27 #include "bonmin_interface.hpp"
28 #include "bonmin_nlp.hpp"
29 #include "../ipopt/ipopt_uout_journal.hpp"
30 #include "casadi/core/casadi_misc.hpp"
31 #include "../../core/global_options.hpp"
32 #include "../../core/casadi_interrupt.hpp"
42 int CASADI_NLPSOL_BONMIN_EXPORT
45 plugin->name =
"bonmin";
47 plugin->version = CASADI_VERSION;
68 {{
"pass_nonlinear_variables",
70 "Pass list of variables entering nonlinearly to BONMIN"}},
71 {
"pass_nonlinear_constraints",
73 "Pass list of constraints entering nonlinearly to BONMIN"}},
76 "Options to be passed to BONMIN"}},
79 "String metadata (a dictionary with lists of strings) "
80 "about variables to be passed to BONMIN"}},
83 "Integer metadata (a dictionary with lists of integers) "
84 "about variables to be passed to BONMIN"}},
87 "Numeric metadata (a dictionary with lists of reals) about "
88 "variables to be passed to BONMIN"}},
91 "String metadata (a dictionary with lists of strings) about "
92 "constraints to be passed to BONMIN"}},
95 "Integer metadata (a dictionary with lists of integers) "
96 "about constraints to be passed to BONMIN"}},
99 "Numeric metadata (a dictionary with lists of reals) about "
100 "constraints to be passed to BONMIN"}},
103 "Function for calculating the Hessian of the Lagrangian (autogenerated by default)"}},
106 "Options for the autogenerated Hessian of the Lagrangian."}},
109 "Function for calculating the Jacobian of the constraints "
110 "(autogenerated by default)"}},
113 "Options for the autogenerated Jacobian of the constraints."}},
116 "Function for calculating the gradient of the objective "
117 "(column, autogenerated by default)"}},
120 "Options for the autogenerated gradient of the objective."}},
123 "Options for the autogenerated gradient of the objective."}},
126 "Options for the autogenerated gradient of the objective."}},
129 "Options for the autogenerated gradient of the objective."}},
143 Dict hess_lag_options, jac_g_options, grad_f_options;
145 std::vector< std::vector<int> > sos1_groups;
146 std::vector< std::vector<double> > sos1_weights;
148 for (
auto&& op : opts) {
149 if (op.first==
"bonmin") {
151 }
else if (op.first==
"pass_nonlinear_variables") {
153 }
else if (op.first==
"pass_nonlinear_constraints") {
155 }
else if (op.first==
"var_string_md") {
157 }
else if (op.first==
"var_integer_md") {
159 }
else if (op.first==
"var_numeric_md") {
161 }
else if (op.first==
"con_string_md") {
163 }
else if (op.first==
"con_integer_md") {
165 }
else if (op.first==
"con_numeric_md") {
167 }
else if (op.first==
"hess_lag_options") {
168 hess_lag_options = op.second;
169 }
else if (op.first==
"jac_g_options") {
170 jac_g_options = op.second;
171 }
else if (op.first==
"grad_f_options") {
172 grad_f_options = op.second;
173 }
else if (op.first==
"hess_lag") {
175 casadi_assert_dev(f.
n_in()==4);
176 casadi_assert_dev(f.
n_out()==1);
178 }
else if (op.first==
"jac_g") {
180 casadi_assert_dev(f.
n_in()==2);
181 casadi_assert_dev(f.
n_out()==2);
183 }
else if (op.first==
"grad_f") {
185 casadi_assert_dev(f.
n_in()==2);
186 casadi_assert_dev(f.
n_out()==2);
188 }
else if (op.first==
"sos1_groups") {
189 sos1_groups =
to_int(op.second.to_int_vector_vector());
190 for (
auto & g : sos1_groups) {
193 }
else if (op.first==
"sos1_weights") {
194 sos1_weights = op.second.to_double_vector_vector();
195 }
else if (op.first==
"sos1_priorities") {
202 auto hessian_approximation =
opts_.find(
"hessian_approximation");
203 if (hessian_approximation!=
opts_.end()) {
227 {
"triu:hess:gamma:x:x"}, {{
"gamma", {
"f",
"g"}}});
233 for (casadi_int i=0;i<
nx_;++i)
nl_ex_[i] = col[i+1]-col[i];
249 casadi_assert(sos1_weights.empty() || sos1_weights.size()==
sos_num_,
250 "sos1_weights has incorrect size");
252 "sos1_priorities has incorrect size");
256 for (casadi_int i=0;i<
sos_num_;++i) {
258 const std::vector<int>& sos1_group = sos1_groups[i];
261 std::vector<double> default_weights(sos1_group.size(), 1.0);
262 const std::vector<double>& sos1_weight =
263 sos1_weights.empty() ? default_weights : sos1_weights[i];
264 casadi_assert(sos1_weight.size()==sos1_group.size(),
265 "sos1_weights has incorrect size");
294 m->sos_info.types =
new char[
sos_num_];
295 m->sos_info.priorities =
new int[
sos_num_];
296 m->sos_info.starts =
new int[
sos_num_ + 1];
314 casadi_int*& iw,
double*& w)
const {
322 m->grad_fk = w; w +=
nx_;
331 case Bonmin::TMINLP::MINLP_ERROR:
332 return "MINLP_ERROR";
333 case Bonmin::TMINLP::SUCCESS:
335 case Bonmin::TMINLP::INFEASIBLE:
337 case Bonmin::TMINLP::CONTINUOUS_UNBOUNDED:
338 return "CONTINUOUS_UNBOUNDED";
339 case Bonmin::TMINLP::LIMIT_EXCEEDED:
340 return "LIMIT_EXCEEDED";
341 case Bonmin::TMINLP::USER_INTERRUPT:
342 return "USER_INTERRUPT";
347 inline std::string
to_str(
const CoinError& e) {
348 std::stringstream ss;
349 if (e.lineNumber()<0) {
350 ss << e.message()<<
" in "<< e.className()<<
"::" << e.methodName();
352 ss << e.fileName() <<
":" << e.lineNumber() <<
" method " << e.methodName()
353 <<
" : assertion \'" << e.message() <<
"\' failed.";
354 if (!e.className().empty())
355 ss <<
"Possible reason: "<< e.className();
360 inline std::string
to_str(TNLPSolver::UnsolvedError& e) {
361 std::stringstream ss;
372 class BonMinMessageHandler :
public CoinMessageHandler {
374 BonMinMessageHandler() { }
376 int print()
override {
377 uout() << messageBuffer_ << std::endl;
380 ~BonMinMessageHandler()
override { }
381 BonMinMessageHandler(
const BonMinMessageHandler &other): CoinMessageHandler(other) {}
382 BonMinMessageHandler(
const CoinMessageHandler &other): CoinMessageHandler(other) {}
383 BonMinMessageHandler & operator=(
const BonMinMessageHandler &rhs) {
384 CoinMessageHandler::operator=(rhs);
387 CoinMessageHandler* clone()
const override {
388 return new BonMinMessageHandler(*
this);
394 auto d_nlp = &m->
d_nlp;
401 m->regularization_size.clear();
405 m->ls_trials.clear();
413 BonMinMessageHandler mh;
416 BonminSetup bonmin(&mh);
418 SmartPtr<OptionsList> options =
new OptionsList();
419 SmartPtr<Journalist> journalist=
new Journalist();
420 SmartPtr<Bonmin::RegisteredOptions> roptions =
new Bonmin::RegisteredOptions();
425 jrnl_raw->SetPrintLevel(J_DBG, J_NONE);
426 SmartPtr<Journal> jrnl = jrnl_raw;
427 journalist->AddJournal(jrnl);
430 options->SetJournalist(journalist);
431 options->SetRegisteredOptions(roptions);
432 bonmin.setOptionsAndJournalist(roptions, options, journalist);
433 bonmin.registerOptions();
435 auto regops = bonmin.roptions()->RegisteredOptionsList();
438 for (
auto&& op :
opts_) {
440 auto regops_it = regops.find(op.first);
441 if (regops_it==regops.end()) {
442 casadi_error(
"No such BONMIN option: " + op.first);
446 Ipopt::RegisteredOptionType ipopt_type = regops_it->second->Type();
450 switch (ipopt_type) {
451 case Ipopt::OT_Number:
452 ret = bonmin.options()->SetNumericValue(op.first, op.second.to_double(),
false);
454 case Ipopt::OT_Integer:
455 ret = bonmin.options()->SetIntegerValue(op.first, op.second.to_int(),
false);
457 case Ipopt::OT_String:
458 ret = bonmin.options()->SetStringValue(op.first, op.second.to_string(),
false);
460 case Ipopt::OT_Unknown:
462 casadi_warning(
"Cannot handle option \"" + op.first +
"\", ignored");
465 if (!ret) casadi_error(
"Invalid options were detected by BONMIN.");
469 bonmin.initialize(GetRawPtr(tminlp));
475 }
catch (CoinError& e) {
476 casadi_error(
"CoinError occured: " +
to_str(e));
477 }
catch (TNLPSolver::UnsolvedError& e) {
478 casadi_error(
"TNLPSolver::UnsolvedError occured" +
to_str(e));
480 casadi_error(
"Uncaught error in Bonmin");
490 const double* g,
const double* lambda,
double obj_value,
int iter,
491 double inf_pr,
double inf_du,
double mu,
double d_norm,
492 double regularization_size,
double alpha_du,
double alpha_pr,
493 int ls_trials,
bool full_callback)
const {
494 auto d_nlp = &m->
d_nlp;
497 if (
verbose_) casadi_message(
"intermediate_callback started");
498 m->
inf_pr.push_back(inf_pr);
499 m->
inf_du.push_back(inf_du);
501 m->
d_norm.push_back(d_norm);
506 m->
obj.push_back(obj_value);
511 for (casadi_int i=0; i<
nx_; ++i) {
512 d_nlp->lam[i] = z_U[i]-z_L[i];
519 <<
"Warning: intermediate_callback is disfunctional in your installation. "
520 "You will only be able to use stats(). "
521 "See https://github.com/casadi/casadi/wiki/enableBonminCallback to enable it."
542 m->
res[0] = &ret_double;
545 int ret =
static_cast<int>(ret_double);
547 m->
fstats.at(
"callback_fun").toc();
554 }
catch(std::exception& ex) {
555 casadi_warning(
"intermediate_callback: " + std::string(ex.
what()));
563 const double* x,
double obj_value)
const {
564 auto d_nlp = &m->
d_nlp;
570 d_nlp->objective = obj_value;
583 m->
success = status==Bonmin::TMINLP::SUCCESS;
585 }
catch(std::exception& ex) {
586 uerr() <<
"finalize_solution failed: " << ex.what() << std::endl;
596 double* g_l,
double* g_u)
const {
597 auto d_nlp = &m->
d_nlp;
604 }
catch(std::exception& ex) {
605 uerr() <<
"get_bounds_info failed: " << ex.what() << std::endl;
612 bool init_z,
double* z_L,
double* z_U,
613 bool init_lambda,
double* lambda)
const {
614 auto d_nlp = &m->
d_nlp;
623 for (casadi_int i=0; i<
nx_; ++i) {
624 z_L[i] = std::max(0., -d_nlp->lam[i]);
625 z_U[i] = std::max(0., d_nlp->lam[i]);
635 }
catch(std::exception& ex) {
636 uerr() <<
"get_starting_point failed: " << ex.what() << std::endl;
642 int& nnz_jac_g,
int& nnz_h_lag)
const {
656 }
catch(std::exception& ex) {
657 uerr() <<
"get_nlp_info failed: " << ex.what() << std::endl;
669 for (
auto&& i :
nl_ex_)
if (i) nv++;
672 }
catch(std::exception& ex) {
673 uerr() <<
"get_number_of_nonlinear_variables failed: " << ex.what() << std::endl;
681 for (casadi_int i=0; i<
nl_ex_.size(); ++i) {
682 if (
nl_ex_[i]) *pos_nonlin_vars++ = i;
685 }
catch(std::exception& ex) {
686 uerr() <<
"get_list_of_nonlinear_variables failed: " << ex.what() << std::endl;
702 stats[
"iter_count"] = m->iter_count;
707 s.
version(
"BonminInterface", 1);
736 s.
version(
"BonminInterface", 1);
BonminInterface(const std::string &name, const Function &nlp)
std::vector< int > sos1_starts_
std::vector< char > sos1_types_
int init_mem(void *mem) const override
Initalize memory block.
std::vector< double > sos1_weights_
Sos constraints information.
int solve(void *mem) const override
bool exact_hessian_
Exact Hessian?
Dict opts_
All BONMIN options.
std::vector< bool > nl_g_
bool pass_nonlinear_variables_
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
static Nlpsol * creator(const std::string &name, const Function &nlp)
Create a new NLP Solver.
bool get_list_of_nonlinear_variables(int num_nonlin_vars, int *pos_nonlin_vars) const
void finalize_solution(BonminMemory *m, Bonmin::TMINLP::SolverReturn status, const double *x, double obj_value) const
static const Options options_
Options.
Dict get_stats(void *mem) const override
Get all statistics.
void init(const Dict &opts) override
Initialize.
const Bonmin::TMINLP::SosInfo & sosConstraints(BonminMemory *m) const
std::vector< int > sos1_indices_
bool get_starting_point(BonminMemory *m, bool init_x, double *x, bool init_z, double *z_L, double *z_U, bool init_lambda, double *lambda) const
int get_number_of_nonlinear_variables() const
std::vector< bool > nl_ex_
std::vector< int > sos1_priorities_
bool pass_nonlinear_constraints_
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
friend class BonminUserClass
~BonminInterface() override
void get_nlp_info(BonminMemory *m, int &nx, int &ng, int &nnz_jac_g, int &nnz_h_lag) const
bool intermediate_callback(BonminMemory *m, const double *x, const double *z_L, const double *z_U, const double *g, const double *lambda, double obj_value, int iter, double inf_pr, double inf_du, double mu, double d_norm, double regularization_size, double alpha_du, double alpha_pr, int ls_trials, bool full_callback) const
bool get_bounds_info(BonminMemory *m, double *x_l, double *x_u, double *g_l, double *g_u) const
static const std::string meta_doc
A documentation string.
const char * what() const override
Display error.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
std::vector< bool > which_depends(const std::string &s_in, const std::vector< std::string > &s_out, casadi_int order=1, bool tr=false) const
Find which entries of an input the outputs depend on, linearly or not.
casadi_int n_out() const
Get the number of function outputs.
casadi_int n_in() const
Get the number of function inputs.
bool is_null() const
Is a null pointer?
static casadi_int start_index
NLP solver storage class.
bool iteration_callback_ignore_errors_
Options.
Dict get_stats(void *mem) const override
Get all statistics.
static const Options options_
Options.
void init(const Dict &opts) override
Initialize.
casadi_int ng_
Number of constraints.
int init_mem(void *mem) const override
Initalize memory block.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
casadi_int nx_
Number of variables.
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
Function fcallback_
callback function, executed at each iteration
void set_function(const Function &fcn, const std::string &fname, bool jit=false)
Function oracle_
Oracle: Used to generate other functions.
Function create_function(const Function &oracle, const std::string &fname, const std::vector< std::string > &s_in, const std::vector< std::string > &s_out, const Function::AuxOut &aux=Function::AuxOut(), const Dict &opts=Dict())
std::vector< std::string > get_function() const override
Get list of dependency functions.
bool has_function(const std::string &fname) const override
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 nnz() const
Number of structural nonzeros.
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
Ipopt journal printing through casadi::uout()
@ NLPSOL_G
Constraints function at the optimal solution (ng x 1)
@ NLPSOL_X
Decision variables at the optimal solution (nx x 1)
@ NLPSOL_F
Cost function value at the optimal solution (1 x 1)
@ NLPSOL_LAM_G
Lagrange multipliers for bounds on G at the solution (ng x 1); same sign convention.
std::string to_str(const CoinError &e)
int to_int(casadi_int rhs)
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
void casadi_fill(T1 *x, casadi_int n, T1 alpha)
FILL: x <- alpha.
const char * return_status_string(Bonmin::TMINLP::SolverReturn status)
int CASADI_NLPSOL_BONMIN_EXPORT casadi_register_nlpsol_bonmin(Nlpsol::Plugin *plugin)
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
const double nan
Not a number.
void CASADI_NLPSOL_BONMIN_EXPORT casadi_load_nlpsol_bonmin()
std::vector< double > obj
std::vector< double > inf_pr
~BonminMemory()
Destructor.
std::vector< double > alpha_du
const char * return_status
std::vector< double > d_norm
std::vector< double > alpha_pr
Bonmin::TMINLP::SosInfo sos_info
BonminMemory()
Constructor.
std::vector< double > regularization_size
std::vector< casadi_int > ls_trials
std::vector< double > inf_du
UnifiedReturnStatus unified_return_status
casadi_nlpsol_data< double > d_nlp
Options metadata for a class.
std::map< std::string, FStats > fstats