25 #include "cbc_interface.hpp"
28 #include "casadi/core/nlp_tools.hpp"
33 int CASADI_CONIC_CBC_EXPORT
38 plugin->version = CASADI_VERSION;
51 const std::map<std::string, Sparsity>& st)
61 "Options to be passed to CBC."
62 "Three sets of options are supported. "
63 "The first can be found in OsiSolverParameters.hpp. "
64 "The second can be found in CbcModel.hpp. "
65 "The third are options that can be passed to CbcMain1."
69 "Definition of SOS groups by indices."}},
72 "Weights corresponding to SOS entries."}},
75 "Specify 1 or 2 for each SOS group."}},
78 "Hot start with x0 [Default false]."}},
85 return "before branchAndBound";
89 return "stopped - on maxnodes, maxsols, maxtime";
91 return "difficulties so run was abandoned";
93 return "stopped by event handler";
99 std::map<std::string, CbcModel::CbcIntParam> CbcInterface::param_map_int = {
100 {
"MaxNumNode", CbcModel::CbcMaxNumNode},
101 {
"MaxNumSol", CbcModel::CbcMaxNumSol},
102 {
"FathomDiscipline", CbcModel::CbcFathomDiscipline},
103 {
"Printing", CbcModel::CbcPrinting},
104 {
"NumberBranches", CbcModel::CbcNumberBranches},
107 std::map<std::string, CbcModel::CbcDblParam> CbcInterface::param_map_double = {
108 {
"IntegerTolerance", CbcModel::CbcIntegerTolerance},
109 {
"InfeasibilityWeight", CbcModel::CbcInfeasibilityWeight},
110 {
"CutoffIncrement", CbcModel::CbcCutoffIncrement},
111 {
"AllowableGap", CbcModel::CbcAllowableGap},
112 {
"AllowableFractionGap", CbcModel::CbcAllowableFractionGap},
113 {
"MaximumSeconds", CbcModel::CbcMaximumSeconds},
114 {
"CurrentCutoff", CbcModel::CbcCurrentCutoff},
115 {
"OptimizationDirection", CbcModel::CbcOptimizationDirection},
116 {
"CurrentObjectiveValue", CbcModel::CbcCurrentObjectiveValue},
117 {
"CurrentMinimizationObjectiveValue", CbcModel::CbcCurrentMinimizationObjectiveValue},
118 {
"StartSeconds", CbcModel::CbcStartSeconds},
119 {
"HeuristicGap", CbcModel::CbcHeuristicGap},
120 {
"HeuristicFractionGap", CbcModel::CbcHeuristicFractionGap},
121 {
"SmallestChange", CbcModel::CbcSmallestChange},
122 {
"SumChange", CbcModel::CbcSumChange},
123 {
"LargestChange", CbcModel::CbcLargestChange},
124 {
"SmallChange", CbcModel::CbcSmallChange}
127 std::map<std::string, OsiIntParam> CbcInterface::osi_param_map_int = {
128 {
"MaxNumIteration", OsiMaxNumIteration},
129 {
"MaxNumIterationHotStart", OsiMaxNumIterationHotStart},
130 {
"NameDiscipline", OsiNameDiscipline}
133 std::map<std::string, OsiDblParam> CbcInterface::osi_param_map_double = {
134 {
"DualObjectiveLimit", OsiDualObjectiveLimit},
135 {
"PrimalObjectiveLimit", OsiPrimalObjectiveLimit},
136 {
"DualTolerance", OsiDualTolerance},
137 {
"PrimalTolerance", OsiPrimalTolerance},
138 {
"ObjOffset", OsiObjOffset}
146 return "search completed with solution";
148 return "linear relaxation not feasible (or worse than cutoff)";
150 return "stopped on gap";
152 return "stopped on nodes";
154 return "stopped on time";
156 return "stopped on user event";
158 return "stopped on solutions";
159 case CbcEventHandler::CbcEvent::node:
161 case CbcEventHandler::CbcEvent::treeStatus:
163 case CbcEventHandler::CbcEvent::solution:
165 case CbcEventHandler::CbcEvent::heuristicSolution:
166 return "heuristicSolution";
167 case CbcEventHandler::CbcEvent::beforeSolution1:
168 return "beforeSolution1";
169 case CbcEventHandler::CbcEvent::beforeSolution2:
170 return "beforeSolution2";
171 case CbcEventHandler::CbcEvent::afterHeuristic:
172 return "afterHeuristic";
173 case CbcEventHandler::CbcEvent::smallBranchAndBound:
174 return "smallBranchAndBound";
175 case CbcEventHandler::CbcEvent::heuristicPass:
176 return "heuristicPass";
177 case CbcEventHandler::CbcEvent::convertToCuts:
178 return "convertToCuts";
179 case CbcEventHandler::CbcEvent::endSearch:
186 class CasadiHandler :
public CoinMessageHandler {
188 virtual int print() ;
191 int CasadiHandler::print() {
192 uout() << messageBuffer() << std::endl;
196 void CbcInterface::copy_cbc_results(
const CbcModel& model,
double** res)
const {
198 const double* x = model.getColSolution();
202 const double* minus_lam_x = model.getReducedCost();
209 const double* minus_lam_a = model.getRowPrice();
216 double f = model.getObjValue();
225 for (
auto&& op : opts) {
226 if (op.first==
"sos_groups") {
227 sos_groups_ =
to_int(op.second.to_int_vector_vector());
228 }
else if (op.first==
"sos_weights") {
229 sos_weights_ = op.second.to_double_vector_vector();
230 }
else if (op.first==
"sos_types") {
231 sos_types_ = op.second.to_int_vector();
232 }
else if (op.first==
"hot_start") {
233 hot_start_ = op.second;
234 }
else if (op.first==
"cbc") {
243 casadi_assert(
H_.
nnz()==0,
"Not an LP");
261 m->add_stat(
"solver");
262 m->add_stat(
"postprocessing");
264 m->colind.resize(
A_.
size2()+1);
265 m->row.resize(
A_.
nnz());
271 solve(
const double** arg,
double** res, casadi_int* iw,
double* w,
void* mem)
const {
276 m->secondary_return_status = -1;
278 m->fstats.at(
"preprocessing").tic();
281 double* g=w; w +=
nx_;
283 double* lbx=w; w +=
nx_;
285 double* ubx=w; w +=
nx_;
287 double* lba=w; w +=
na_;
289 double* uba=w; w +=
na_;
300 OsiClpSolverInterface osi_model;
303 lbx, ubx, g, lba, uba);
307 for (casadi_int i=0; i<
A_.
size2();++i) {
308 if (
discrete_[i]) osi_model.setInteger(i);
312 CbcModel model(osi_model);
315 model.setBestSolution(arg[
CONIC_X0],
nx_, COIN_DBL_MAX,
true);
319 copy_cbc_results(model, res);
323 std::vector<CbcSOS> sos_objects;
324 for (casadi_int i=0;i<sos_groups_.size();++i) {
325 const std::vector<int>& sos_group = sos_groups_[i];
326 sos_objects.emplace_back(&model, sos_group.size(),
get_ptr(sos_group),
327 sos_weights_.empty() ?
nullptr :
get_ptr(sos_weights_[i]), i, sos_types_[i]);
329 std::vector<CbcObject*> sos_objects_ptr;
330 for (casadi_int i=0;i<sos_groups_.size();++i) {
331 sos_objects_ptr.push_back(&sos_objects[i]);
333 if (!sos_objects.empty()) {
334 model.addObjects(sos_objects.size(),
get_ptr(sos_objects_ptr));
340 std::vector<std::string> main1_options(1,
"CbcInterface");
343 for (
auto&& op :
opts_) {
346 auto it = param_map_double.find(op.first);
347 if (it!=param_map_double.end()) {
348 casadi_assert(model.setDblParam(it->second, op.second.to_double()),
349 "Error setting option '" + op.first +
"'.");
355 auto it = param_map_int.find(op.first);
356 if (it!=param_map_int.end()) {
357 casadi_assert(model.setIntParam(it->second, op.second.to_int()),
358 "Error setting option '" + op.first +
"'.");
364 auto it = osi_param_map_double.find(op.first);
365 if (it!=osi_param_map_double.end()) {
366 casadi_assert(model.solver()->setDblParam(it->second, op.second.to_double()),
367 "Error setting option '" + op.first +
"'.");
373 auto it = osi_param_map_int.find(op.first);
374 if (it!=osi_param_map_int.end()) {
375 casadi_assert(model.solver()->setIntParam(it->second, op.second.to_int()),
376 "Error setting option '" + op.first +
"'.");
380 if (op.first==
"startalg") {
381 std::string startalg = op.second.to_string();
382 main1_options.push_back(
"-" + op.second.to_string());
384 main1_options.push_back(
"-" + op.first);
385 main1_options.push_back(
str(op.second));
389 main1_options.push_back(
"-solve");
390 main1_options.push_back(
"-quit");
392 std::vector<const char*> main_options_char;
393 for (
const auto& s : main1_options) main_options_char.push_back(s.c_str());
396 model.passInMessageHandler(&ch);
398 m->fstats.at(
"preprocessing").toc();
399 m->fstats.at(
"solver").tic();
401 CbcMain1(main_options_char.size(),
get_ptr(main_options_char), model);
403 m->fstats.at(
"solver").toc();
404 m->fstats.at(
"postprocessing").tic();
406 if (hot_start_ && model.status() == 0 &&
407 model.isProvenOptimal() && model.secondaryStatus() == 1) {
410 copy_cbc_results(model, res);
413 m->fstats.at(
"postprocessing").toc();
415 m->return_status = model.status();
416 m->d_qp.success = m->return_status==0 &&
417 model.isProvenOptimal() &&
418 model.secondaryStatus() <= 1;
419 m->secondary_return_status = model.secondaryStatus();
420 m->iter_count = model.getIterationCount();
421 m->node_count = model.getNodeCount();
447 stats[
"iter_count"] = m->iter_count;
448 stats[
"node_count"] = m->node_count;
455 s.
unpack(
"CbcInterface::sos_groups", sos_groups_);
456 s.
unpack(
"CbcInterface::sos_weights", sos_weights_);
457 s.
unpack(
"CbcInterface::sos_types", sos_types_);
458 s.
unpack(
"CbcInterface::hot_start", hot_start_);
466 s.
pack(
"CbcInterface::sos_groups", sos_groups_);
467 s.
pack(
"CbcInterface::sos_weights", sos_weights_);
468 s.
pack(
"CbcInterface::sos_types", sos_types_);
469 s.
pack(
"CbcInterface::hot_start", hot_start_);
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
int init_mem(void *mem) const override
Initalize memory block.
static const std::string meta_doc
A documentation string.
static Conic * creator(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new QP Solver.
CbcInterface(const std::string &name, const std::map< std::string, Sparsity > &st)
Constructor using sparsity patterns.
static const Options options_
Options.
void init(const Dict &opts) override
Initialize.
Dict opts_
All CBC options.
int solve(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Solve the QP.
Dict get_stats(void *mem) const override
Get all statistics.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
~CbcInterface() override
Destructor.
static const Options options_
Options.
casadi_int nx_
Number of decision variables.
int init_mem(void *mem) const override
Initalize memory block.
casadi_int na_
The number of constraints (counting both equality and inequality) == A.size1()
Sparsity H_
Problem structure.
void init(const Dict &opts) override
Initialize.
std::vector< bool > discrete_
Options.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Dict get_stats(void *mem) const override
Get all statistics.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
casadi_int nnz_in() const
Number of input/output nonzeros.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
bool verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
casadi_int size1() const
Get the number of rows.
casadi_int nnz() const
Get the number of (structural) non-zeros.
casadi_int size2() const
Get the number of columns.
const casadi_int * row() const
Get a reference to row-vector,.
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
void copy_vector(const std::vector< S > &s, std::vector< D > &d)
@ CONIC_UBA
dense, (nc x 1)
@ CONIC_A
The matrix A: sparse, (nc x n) - product with x must be dense.
@ CONIC_G
The vector g: dense, (n x 1)
@ CONIC_LBA
dense, (nc x 1)
@ CONIC_UBX
dense, (n x 1)
@ CONIC_LBX
dense, (n x 1)
int to_int(casadi_int rhs)
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
const char * return_status_string(Bonmin::TMINLP::SolverReturn status)
std::string str(const T &v)
String representation, any type.
void check_sos(casadi_int nx, const std::vector< std::vector< T > > &groups, std::vector< std::vector< double > > &weights, std::vector< casadi_int > &types)
Check sos structure and generate defaults.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
void CASADI_CONIC_CBC_EXPORT casadi_load_conic_cbc()
void casadi_scal(casadi_int n, T1 alpha, T1 *x)
SCAL: x <- alpha*x.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
int CASADI_CONIC_CBC_EXPORT casadi_register_conic_cbc(Conic::Plugin *plugin)
std::string return_secondary_status_string(int status)
@ CONIC_X
The primal solution.
@ CONIC_LAM_A
The dual solution corresponding to linear bounds.
@ CONIC_COST
The optimal cost.
@ CONIC_LAM_X
The dual solution corresponding to simple bounds.
Options metadata for a class.
void add_stat(const std::string &s)