bonmin_interface.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 
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"
33 
34 #include <ctime>
35 #include <stdlib.h>
36 #include <iostream>
37 #include <iomanip>
38 #include <chrono>
39 
40 namespace casadi {
41  extern "C"
42  int CASADI_NLPSOL_BONMIN_EXPORT
43  casadi_register_nlpsol_bonmin(Nlpsol::Plugin* plugin) {
44  plugin->creator = BonminInterface::creator;
45  plugin->name = "bonmin";
46  plugin->doc = BonminInterface::meta_doc.c_str();
47  plugin->version = CASADI_VERSION;
48  plugin->options = &BonminInterface::options_;
49  plugin->deserialize = &BonminInterface::deserialize;
50  return 0;
51  }
52 
53  extern "C"
54  void CASADI_NLPSOL_BONMIN_EXPORT casadi_load_nlpsol_bonmin() {
56  }
57 
58  BonminInterface::BonminInterface(const std::string& name, const Function& nlp)
59  : Nlpsol(name, nlp) {
60  }
61 
63  clear_mem();
64  }
65 
67  = {{&Nlpsol::options_},
68  {{"pass_nonlinear_variables",
69  {OT_BOOL,
70  "Pass list of variables entering nonlinearly to BONMIN"}},
71  {"pass_nonlinear_constraints",
72  {OT_BOOL,
73  "Pass list of constraints entering nonlinearly to BONMIN"}},
74  {"bonmin",
75  {OT_DICT,
76  "Options to be passed to BONMIN"}},
77  {"var_string_md",
78  {OT_DICT,
79  "String metadata (a dictionary with lists of strings) "
80  "about variables to be passed to BONMIN"}},
81  {"var_integer_md",
82  {OT_DICT,
83  "Integer metadata (a dictionary with lists of integers) "
84  "about variables to be passed to BONMIN"}},
85  {"var_numeric_md",
86  {OT_DICT,
87  "Numeric metadata (a dictionary with lists of reals) about "
88  "variables to be passed to BONMIN"}},
89  {"con_string_md",
90  {OT_DICT,
91  "String metadata (a dictionary with lists of strings) about "
92  "constraints to be passed to BONMIN"}},
93  {"con_integer_md",
94  {OT_DICT,
95  "Integer metadata (a dictionary with lists of integers) "
96  "about constraints to be passed to BONMIN"}},
97  {"con_numeric_md",
98  {OT_DICT,
99  "Numeric metadata (a dictionary with lists of reals) about "
100  "constraints to be passed to BONMIN"}},
101  {"hess_lag",
102  {OT_FUNCTION,
103  "Function for calculating the Hessian of the Lagrangian (autogenerated by default)"}},
104  {"hess_lag_options",
105  {OT_DICT,
106  "Options for the autogenerated Hessian of the Lagrangian."}},
107  {"jac_g",
108  {OT_FUNCTION,
109  "Function for calculating the Jacobian of the constraints "
110  "(autogenerated by default)"}},
111  {"jac_g_options",
112  {OT_DICT,
113  "Options for the autogenerated Jacobian of the constraints."}},
114  {"grad_f",
115  {OT_FUNCTION,
116  "Function for calculating the gradient of the objective "
117  "(column, autogenerated by default)"}},
118  {"grad_f_options",
119  {OT_DICT,
120  "Options for the autogenerated gradient of the objective."}},
121  {"sos1_groups",
123  "Options for the autogenerated gradient of the objective."}},
124  {"sos1_weights",
126  "Options for the autogenerated gradient of the objective."}},
127  {"sos1_priorities",
128  {OT_INTVECTOR,
129  "Options for the autogenerated gradient of the objective."}},
130  }
131  };
132 
133  void BonminInterface::init(const Dict& opts) {
134  // Call the init method of the base class
135  Nlpsol::init(opts);
136 
137  // Bonmin returns no multipliers (lam is NaN): skip post-solve lam_x/lam_p
138  calc_lam_x_ = calc_lam_p_ = false;
139 
140  // Default options
143  Dict hess_lag_options, jac_g_options, grad_f_options;
144 
145  std::vector< std::vector<int> > sos1_groups;
146  std::vector< std::vector<double> > sos1_weights;
147  // Read user options
148  for (auto&& op : opts) {
149  if (op.first=="bonmin") {
150  opts_ = op.second;
151  } else if (op.first=="pass_nonlinear_variables") {
152  pass_nonlinear_variables_ = op.second;
153  } else if (op.first=="pass_nonlinear_constraints") {
154  pass_nonlinear_constraints_ = op.second;
155  } else if (op.first=="var_string_md") {
156  var_string_md_ = op.second;
157  } else if (op.first=="var_integer_md") {
158  var_integer_md_ = op.second;
159  } else if (op.first=="var_numeric_md") {
160  var_numeric_md_ = op.second;
161  } else if (op.first=="con_string_md") {
162  con_string_md_ = op.second;
163  } else if (op.first=="con_integer_md") {
164  con_integer_md_ = op.second;
165  } else if (op.first=="con_numeric_md") {
166  con_numeric_md_ = op.second;
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") {
174  Function f = op.second;
175  casadi_assert_dev(f.n_in()==4);
176  casadi_assert_dev(f.n_out()==1);
177  set_function(f, "nlp_hess_l");
178  } else if (op.first=="jac_g") {
179  Function f = op.second;
180  casadi_assert_dev(f.n_in()==2);
181  casadi_assert_dev(f.n_out()==2);
182  set_function(f, "nlp_jac_g");
183  } else if (op.first=="grad_f") {
184  Function f = op.second;
185  casadi_assert_dev(f.n_in()==2);
186  casadi_assert_dev(f.n_out()==2);
187  set_function(f, "nlp_grad_f");
188  } else if (op.first=="sos1_groups") {
189  sos1_groups = to_int(op.second.to_int_vector_vector());
190  for (auto & g : sos1_groups) {
191  for (auto & e : g) e-= GlobalOptions::start_index;
192  }
193  } else if (op.first=="sos1_weights") {
194  sos1_weights = op.second.to_double_vector_vector();
195  } else if (op.first=="sos1_priorities") {
196  sos1_priorities_ = to_int(op.second.to_int_vector());
197  }
198  }
199 
200  // Do we need second order derivatives?
201  exact_hessian_ = true;
202  auto hessian_approximation = opts_.find("hessian_approximation");
203  if (hessian_approximation!=opts_.end()) {
204  exact_hessian_ = hessian_approximation->second == "exact";
205  }
206 
207 
208  // Setup NLP functions
209  create_function("nlp_f", {"x", "p"}, {"f"});
210  create_function("nlp_g", {"x", "p"}, {"g"});
211  if (!has_function("nlp_grad_f")) {
212  create_function("nlp_grad_f", {"x", "p"}, {"f", "grad:f:x"});
213  }
214  if (!has_function("nlp_jac_g")) {
215  create_function("nlp_jac_g", {"x", "p"}, {"g", "jac:g:x"});
216  }
217  jacg_sp_ = get_function("nlp_jac_g").sparsity_out(1);
218 
219  // By default, assume all nonlinear
220  nl_ex_.resize(nx_, true);
221  nl_g_.resize(ng_, true);
222 
223  // Allocate temporary work vectors
224  if (exact_hessian_) {
225  if (!has_function("nlp_hess_l")) {
226  create_function("nlp_hess_l", {"x", "p", "lam:f", "lam:g"},
227  {"triu:hess:gamma:x:x"}, {{"gamma", {"f", "g"}}});
228  }
229  hesslag_sp_ = get_function("nlp_hess_l").sparsity_out(0);
230 
232  const casadi_int* col = hesslag_sp_.colind();
233  for (casadi_int i=0;i<nx_;++i) nl_ex_[i] = col[i+1]-col[i];
234  }
235  } else {
237  nl_ex_ = oracle_.which_depends("x", {"f", "g"}, 2, false);
238  }
240  nl_g_ = oracle_.which_depends("x", {"g"}, 2, true);
241 
242  // Create sos info
243 
244  // Declare size
245  sos_num_ = sos1_groups.size();
246  // sos1 type
247  sos1_types_.resize(sos_num_, 1);
248 
249  casadi_assert(sos1_weights.empty() || sos1_weights.size()==sos_num_,
250  "sos1_weights has incorrect size");
251  casadi_assert(sos1_priorities_.empty() || sos1_priorities_.size()==sos_num_,
252  "sos1_priorities has incorrect size");
253  if (sos1_priorities_.empty()) sos1_priorities_.resize(sos_num_, 1);
254 
255  sos_num_nz_ = 0;
256  for (casadi_int i=0;i<sos_num_;++i) {
257  // get local group
258  const std::vector<int>& sos1_group = sos1_groups[i];
259 
260  // Get local weights
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");
266 
267  // Populate lookup vector
268  sos1_starts_.push_back(sos_num_nz_);
269  sos_num_nz_+=sos1_group.size();
270 
271  sos1_weights_.insert(sos1_weights_.end(), sos1_weight.begin(), sos1_weight.end());
272  sos1_indices_.insert(sos1_indices_.end(), sos1_group.begin(), sos1_group.end());
273  }
274 
275  sos1_starts_.push_back(sos_num_nz_);
276 
277  // Allocate work vectors
278  alloc_w(nx_, true); // xk_
279  alloc_w(nx_, true); // lam_xk_
280  alloc_w(ng_, true); // gk_
281  alloc_w(nx_, true); // grad_fk_
282  alloc_w(jacg_sp_.nnz(), true); // jac_gk_
283  if (exact_hessian_) {
284  alloc_w(hesslag_sp_.nnz(), true); // hess_lk_
285  }
286  }
287 
288  int BonminInterface::init_mem(void* mem) const {
289 
290  auto m = static_cast<BonminMemory*>(mem);
291  m->sos_info.num = sos_num_;
292  m->sos_info.numNz = sos_num_nz_;
293  // sos_info takes ownership of passed-in pointers
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];
297  m->sos_info.indices = new int[sos_num_nz_];
298  m->sos_info.weights = new double[sos_num_nz_];
299  casadi_assert_dev(sos_num_==sos1_types_.size());
300  casadi_assert_dev(sos_num_==sos1_priorities_.size());
301  casadi_assert_dev(sos_num_+1==sos1_starts_.size());
302  casadi_assert_dev(sos_num_nz_==sos1_indices_.size());
303  casadi_assert_dev(sos_num_nz_==sos1_weights_.size());
304  std::copy(sos1_types_.begin(), sos1_types_.end(), m->sos_info.types);
305  std::copy(sos1_priorities_.begin(), sos1_priorities_.end(), m->sos_info.priorities);
306  std::copy(sos1_starts_.begin(), sos1_starts_.end(), m->sos_info.starts);
307  std::copy(sos1_indices_.begin(), sos1_indices_.end(), m->sos_info.indices);
308  std::copy(sos1_weights_.begin(), sos1_weights_.end(), m->sos_info.weights);
309 
310  return Nlpsol::init_mem(mem);
311  }
312 
313  void BonminInterface::set_work(void* mem, const double**& arg, double**& res,
314  casadi_int*& iw, double*& w) const {
315  auto m = static_cast<BonminMemory*>(mem);
316 
317  // Set work in base classes
318  Nlpsol::set_work(mem, arg, res, iw, w);
319 
320  // Work vectors
321  m->gk = w; w += ng_;
322  m->grad_fk = w; w += nx_;
323  m->jac_gk = w; w += jacg_sp_.nnz();
324  if (exact_hessian_) {
325  m->hess_lk = w; w += hesslag_sp_.nnz();
326  }
327  }
328 
329  inline const char* return_status_string(Bonmin::TMINLP::SolverReturn status) {
330  switch (status) {
331  case Bonmin::TMINLP::MINLP_ERROR:
332  return "MINLP_ERROR";
333  case Bonmin::TMINLP::SUCCESS:
334  return "SUCCESS";
335  case Bonmin::TMINLP::INFEASIBLE:
336  return "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";
343  }
344  return "Unknown";
345  }
346 
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();
351  } else {
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();
356  }
357  return ss.str();
358  }
359 
360  inline std::string to_str(TNLPSolver::UnsolvedError& e) {
361  std::stringstream ss;
362  e.printError(ss);
363  return ss.str();
364  }
365 
366 
372  class BonMinMessageHandler : public CoinMessageHandler {
373  public:
374  BonMinMessageHandler() { }
376  int print() override {
377  uout() << messageBuffer_ << std::endl;
378  return 0;
379  }
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);
385  return *this;
386  }
387  CoinMessageHandler* clone() const override {
388  return new BonMinMessageHandler(*this);
389  }
390  };
391 
392  int BonminInterface::solve(void* mem) const {
393  auto m = static_cast<BonminMemory*>(mem);
394  auto d_nlp = &m->d_nlp;
395 
396  // Reset statistics
397  m->inf_pr.clear();
398  m->inf_du.clear();
399  m->mu.clear();
400  m->d_norm.clear();
401  m->regularization_size.clear();
402  m->alpha_pr.clear();
403  m->alpha_du.clear();
404  m->obj.clear();
405  m->ls_trials.clear();
406 
407  // Reset number of iterations
408  m->n_iter = 0;
409 
410  // MINLP instance
411  SmartPtr<BonminUserClass> tminlp = new BonminUserClass(*this, m);
412 
413  BonMinMessageHandler mh;
414 
415  // Start an BONMIN application
416  BonminSetup bonmin(&mh);
417 
418  SmartPtr<OptionsList> options = new OptionsList();
419  SmartPtr<Journalist> journalist= new Journalist();
420  SmartPtr<Bonmin::RegisteredOptions> roptions = new Bonmin::RegisteredOptions();
421 
422  {
423  // Direct output through casadi::uout()
424  UoutJournal* jrnl_raw = new UoutJournal("console", J_ITERSUMMARY);
425  jrnl_raw->SetPrintLevel(J_DBG, J_NONE);
426  SmartPtr<Journal> jrnl = jrnl_raw;
427  journalist->AddJournal(jrnl);
428  }
429 
430  options->SetJournalist(journalist);
431  options->SetRegisteredOptions(roptions);
432  bonmin.setOptionsAndJournalist(roptions, options, journalist);
433  bonmin.registerOptions();
434  // Get all options available in BONMIN
435  auto regops = bonmin.roptions()->RegisteredOptionsList();
436 
437  // Pass all the options to BONMIN
438  for (auto&& op : opts_) {
439  // Find the option
440  auto regops_it = regops.find(op.first);
441  if (regops_it==regops.end()) {
442  casadi_error("No such BONMIN option: " + op.first);
443  }
444 
445  // Get the type
446  Ipopt::RegisteredOptionType ipopt_type = regops_it->second->Type();
447 
448  // Pass to BONMIN
449  bool ret;
450  switch (ipopt_type) {
451  case Ipopt::OT_Number:
452  ret = bonmin.options()->SetNumericValue(op.first, op.second.to_double(), false);
453  break;
454  case Ipopt::OT_Integer:
455  ret = bonmin.options()->SetIntegerValue(op.first, op.second.to_int(), false);
456  break;
457  case Ipopt::OT_String:
458  ret = bonmin.options()->SetStringValue(op.first, op.second.to_string(), false);
459  break;
460  case Ipopt::OT_Unknown:
461  default:
462  casadi_warning("Cannot handle option \"" + op.first + "\", ignored");
463  continue;
464  }
465  if (!ret) casadi_error("Invalid options were detected by BONMIN.");
466  }
467 
468  // Initialize
469  bonmin.initialize(GetRawPtr(tminlp));
470 
471  // Branch-and-bound
472  try {
473  Bab bb;
474  bb(bonmin);
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));
479  } catch (...) {
480  casadi_error("Uncaught error in Bonmin");
481  }
482 
483  // Save results to outputs
484  casadi_copy(m->gk, ng_, d_nlp->z + nx_);
485  return 0;
486  }
487 
489  intermediate_callback(BonminMemory* m, const double* x, const double* z_L, const double* z_U,
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;
495  m->n_iter += 1;
496  try {
497  if (verbose_) casadi_message("intermediate_callback started");
498  m->inf_pr.push_back(inf_pr);
499  m->inf_du.push_back(inf_du);
500  m->mu.push_back(mu);
501  m->d_norm.push_back(d_norm);
502  m->regularization_size.push_back(regularization_size);
503  m->alpha_pr.push_back(alpha_pr);
504  m->alpha_du.push_back(alpha_du);
505  m->ls_trials.push_back(ls_trials);
506  m->obj.push_back(obj_value);
507  if (!fcallback_.is_null()) {
508  ScopedTiming tic(m->fstats.at("callback_fun"));
509  if (full_callback) {
510  casadi_copy(x, nx_, d_nlp->z);
511  for (casadi_int i=0; i<nx_; ++i) {
512  d_nlp->lam[i] = z_U[i]-z_L[i];
513  }
514  casadi_copy(lambda, ng_, d_nlp->lam + nx_);
515  casadi_copy(g, ng_, m->gk);
516  } else {
517  if (iter==0) {
518  uerr()
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."
522  << std::endl;
523  }
524  }
525 
526  // Inputs
527  std::fill_n(m->arg, fcallback_.n_in(), nullptr);
528  if (full_callback) {
529  // The values used below are meaningless
530  // when not doing a full_callback
531  m->arg[NLPSOL_X] = x;
532  m->arg[NLPSOL_F] = &obj_value;
533  m->arg[NLPSOL_G] = g;
534  m->arg[NLPSOL_LAM_P] = nullptr;
535  m->arg[NLPSOL_LAM_X] = d_nlp->lam;
536  m->arg[NLPSOL_LAM_G] = d_nlp->lam + nx_;
537  }
538 
539  // Outputs
540  std::fill_n(m->res, fcallback_.n_out(), nullptr);
541  double ret_double;
542  m->res[0] = &ret_double;
543 
544  fcallback_(m->arg, m->res, m->iw, m->w, 0);
545  int ret = static_cast<int>(ret_double);
546 
547  m->fstats.at("callback_fun").toc();
548  return !ret;
549  } else {
550  return 1;
551  }
552  } catch(KeyboardInterruptException& ex) {
553  return 0;
554  } catch(std::exception& ex) {
555  casadi_warning("intermediate_callback: " + std::string(ex.what()));
556  if (iteration_callback_ignore_errors_) return 1;
557  return 0;
558  }
559  }
560 
562  finalize_solution(BonminMemory* m, TMINLP::SolverReturn status,
563  const double* x, double obj_value) const {
564  auto d_nlp = &m->d_nlp;
565  try {
566  // Get primal solution
567  casadi_copy(x, nx_, d_nlp->z);
568 
569  // Get optimal cost
570  d_nlp->objective = obj_value;
571 
572  // Dual solution not calculated
573  casadi_fill(d_nlp->lam, nx_ + ng_, nan);
574 
575  // Get the constraints
576  casadi_fill(m->gk, ng_, nan);
577 
578  // Get statistics
579  m->iter_count = 0;
580 
581  // Interpret return code
582  m->return_status = return_status_string(status);
583  m->success = status==Bonmin::TMINLP::SUCCESS;
584  if (status==Bonmin::TMINLP::LIMIT_EXCEEDED) m->unified_return_status = SOLVER_RET_LIMITED;
585  } catch(std::exception& ex) {
586  uerr() << "finalize_solution failed: " << ex.what() << std::endl;
587  }
588  }
589 
590  const TMINLP::SosInfo& BonminInterface::sosConstraints(BonminMemory* m) const {
591  return m->sos_info;
592  }
593 
595  get_bounds_info(BonminMemory* m, double* x_l, double* x_u,
596  double* g_l, double* g_u) const {
597  auto d_nlp = &m->d_nlp;
598  try {
599  casadi_copy(d_nlp->lbz, nx_, x_l);
600  casadi_copy(d_nlp->ubz, nx_, x_u);
601  casadi_copy(d_nlp->lbz+nx_, ng_, g_l);
602  casadi_copy(d_nlp->ubz+nx_, ng_, g_u);
603  return true;
604  } catch(std::exception& ex) {
605  uerr() << "get_bounds_info failed: " << ex.what() << std::endl;
606  return false;
607  }
608  }
609 
611  get_starting_point(BonminMemory* m, bool init_x, double* x,
612  bool init_z, double* z_L, double* z_U,
613  bool init_lambda, double* lambda) const {
614  auto d_nlp = &m->d_nlp;
615  try {
616  // Initialize primal variables
617  if (init_x) {
618  casadi_copy(d_nlp->z, nx_, x);
619  }
620 
621  // Initialize dual variables (simple bounds)
622  if (init_z) {
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]);
626  }
627  }
628 
629  // Initialize dual variables (nonlinear bounds)
630  if (init_lambda) {
631  casadi_copy(d_nlp->lam + nx_, ng_, lambda);
632  }
633 
634  return true;
635  } catch(std::exception& ex) {
636  uerr() << "get_starting_point failed: " << ex.what() << std::endl;
637  return false;
638  }
639  }
640 
641  void BonminInterface::get_nlp_info(BonminMemory* m, int& nx, int& ng,
642  int& nnz_jac_g, int& nnz_h_lag) const {
643  try {
644  // Number of variables
645  nx = nx_;
646 
647  // Number of constraints
648  ng = ng_;
649 
650  // Number of Jacobian nonzeros
651  nnz_jac_g = ng_==0 ? 0 : jacg_sp_.nnz();
652 
653  // Number of Hessian nonzeros (only upper triangular half)
654  nnz_h_lag = exact_hessian_ ? hesslag_sp_.nnz() : 0;
655 
656  } catch(std::exception& ex) {
657  uerr() << "get_nlp_info failed: " << ex.what() << std::endl;
658  }
659  }
660 
662  try {
664  // No Hessian has been interfaced
665  return -1;
666  } else {
667  // Number of variables that appear nonlinearily
668  int nv = 0;
669  for (auto&& i : nl_ex_) if (i) nv++;
670  return nv;
671  }
672  } catch(std::exception& ex) {
673  uerr() << "get_number_of_nonlinear_variables failed: " << ex.what() << std::endl;
674  return -1;
675  }
676  }
677 
679  get_list_of_nonlinear_variables(int num_nonlin_vars, int* pos_nonlin_vars) const {
680  try {
681  for (casadi_int i=0; i<nl_ex_.size(); ++i) {
682  if (nl_ex_[i]) *pos_nonlin_vars++ = i;
683  }
684  return true;
685  } catch(std::exception& ex) {
686  uerr() << "get_list_of_nonlinear_variables failed: " << ex.what() << std::endl;
687  return false;
688  }
689  }
690 
692  this->return_status = "Unset";
693  }
694 
696  }
697 
698  Dict BonminInterface::get_stats(void* mem) const {
699  Dict stats = Nlpsol::get_stats(mem);
700  auto m = static_cast<BonminMemory*>(mem);
701  stats["return_status"] = m->return_status;
702  stats["iter_count"] = m->iter_count;
703  return stats;
704  }
705 
707  s.version("BonminInterface", 1);
708  s.unpack("BonminInterface::jacg_sp", jacg_sp_);
709  s.unpack("BonminInterface::hesslag_sp", hesslag_sp_);
710  s.unpack("BonminInterface::exact_hessian", exact_hessian_);
711  s.unpack("BonminInterface::opts", opts_);
712 
713  s.unpack("BonminInterface::sos1_weights", sos1_weights_);
714  s.unpack("BonminInterface::sos1_indices", sos1_indices_);
715  s.unpack("BonminInterface::sos1_priorities", sos1_priorities_);
716  s.unpack("BonminInterface::sos1_starts", sos1_starts_);
717  s.unpack("BonminInterface::sos1_types", sos1_types_);
718  s.unpack("BonminInterface::sos1_types", sos1_types_);
719  s.unpack("BonminInterface::sos_num", sos_num_);
720  s.unpack("BonminInterface::sos_num_nz", sos_num_nz_);
721 
722  s.unpack("BonminInterface::pass_nonlinear_variables", pass_nonlinear_variables_);
723  s.unpack("BonminInterface::pass_nonlinear_constraints", pass_nonlinear_constraints_);
724  s.unpack("BonminInterface::nl_ex", nl_ex_);
725  s.unpack("BonminInterface::nl_g", nl_g_);
726  s.unpack("BonminInterface::var_string_md", var_string_md_);
727  s.unpack("BonminInterface::var_integer_md", var_integer_md_);
728  s.unpack("BonminInterface::var_numeric_md", var_numeric_md_);
729  s.unpack("BonminInterface::con_string_md", con_string_md_);
730  s.unpack("BonminInterface::con_integer_md", con_integer_md_);
731  s.unpack("BonminInterface::con_numeric_md", con_numeric_md_);
732  }
733 
736  s.version("BonminInterface", 1);
737  s.pack("BonminInterface::jacg_sp", jacg_sp_);
738  s.pack("BonminInterface::hesslag_sp", hesslag_sp_);
739  s.pack("BonminInterface::exact_hessian", exact_hessian_);
740  s.pack("BonminInterface::opts", opts_);
741 
742  s.pack("BonminInterface::sos1_weights", sos1_weights_);
743  s.pack("BonminInterface::sos1_indices", sos1_indices_);
744  s.pack("BonminInterface::sos1_priorities", sos1_priorities_);
745  s.pack("BonminInterface::sos1_starts", sos1_starts_);
746  s.pack("BonminInterface::sos1_types", sos1_types_);
747  s.pack("BonminInterface::sos1_types", sos1_types_);
748  s.pack("BonminInterface::sos_num", sos_num_);
749  s.pack("BonminInterface::sos_num_nz", sos_num_nz_);
750 
751  s.pack("BonminInterface::pass_nonlinear_variables", pass_nonlinear_variables_);
752  s.pack("BonminInterface::pass_nonlinear_constraints", pass_nonlinear_constraints_);
753  s.pack("BonminInterface::nl_ex", nl_ex_);
754  s.pack("BonminInterface::nl_g", nl_g_);
755  s.pack("BonminInterface::var_string_md", var_string_md_);
756  s.pack("BonminInterface::var_integer_md", var_integer_md_);
757  s.pack("BonminInterface::var_numeric_md", var_numeric_md_);
758  s.pack("BonminInterface::con_string_md", con_string_md_);
759  s.pack("BonminInterface::con_integer_md", con_integer_md_);
760  s.pack("BonminInterface::con_numeric_md", con_numeric_md_);
761  }
762 
763 } // namespace casadi
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_
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_
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.
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.
Definition: exception.hpp:90
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.
Function object.
Definition: function.hpp:126
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.
Definition: function.cpp:2023
casadi_int n_out() const
Get the number of function outputs.
Definition: function.cpp:975
casadi_int n_in() const
Get the number of function inputs.
Definition: function.cpp:971
bool is_null() const
Is a null pointer?
static casadi_int start_index
NLP solver storage class.
Definition: nlpsol_impl.hpp:59
bool iteration_callback_ignore_errors_
Options.
Definition: nlpsol_impl.hpp:95
bool calc_lam_p_
Options.
Definition: nlpsol_impl.hpp:97
Dict get_stats(void *mem) const override
Get all statistics.
Definition: nlpsol.cpp:1241
static const Options options_
Options.
void init(const Dict &opts) override
Initialize.
Definition: nlpsol.cpp:509
casadi_int ng_
Number of constraints.
Definition: nlpsol_impl.hpp:69
int init_mem(void *mem) const override
Initalize memory block.
Definition: nlpsol.cpp:704
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: nlpsol.cpp:1399
bool calc_lam_x_
Options.
Definition: nlpsol_impl.hpp:97
casadi_int nx_
Number of variables.
Definition: nlpsol_impl.hpp:66
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
Definition: nlpsol.cpp:896
Function fcallback_
callback function, executed at each iteration
Definition: nlpsol_impl.hpp:75
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.
Definition: sparsity.cpp:150
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
Definition: sparsity.cpp:170
Ipopt journal printing through casadi::uout()
The casadi namespace.
Definition: archiver.cpp:28
@ NLPSOL_G
Constraints function at the optimal solution (ng x 1)
Definition: nlpsol.hpp:858
@ NLPSOL_X
Decision variables at the optimal solution (nx x 1)
Definition: nlpsol.hpp:854
@ NLPSOL_LAM_P
Definition: nlpsol.hpp:866
@ NLPSOL_F
Cost function value at the optimal solution (1 x 1)
Definition: nlpsol.hpp:856
@ NLPSOL_LAM_G
Lagrange multipliers for bounds on G at the solution (ng x 1); same sign convention.
Definition: nlpsol.hpp:863
@ NLPSOL_LAM_X
Definition: nlpsol.hpp:861
std::string to_str(const CoinError &e)
std::ostream & uerr()
int to_int(casadi_int rhs)
Definition: casadi_misc.cpp:60
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)
@ OT_INTVECTOR
@ OT_DOUBLEVECTORVECTOR
@ OT_INTVECTORVECTOR
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
const double nan
Not a number.
Definition: calculus.hpp:53
void CASADI_NLPSOL_BONMIN_EXPORT casadi_load_nlpsol_bonmin()
std::ostream & uout()
@ SOLVER_RET_LIMITED
std::vector< double > mu
std::vector< double > obj
std::vector< double > inf_pr
std::vector< double > alpha_du
std::vector< double > d_norm
std::vector< double > alpha_pr
Bonmin::TMINLP::SosInfo sos_info
std::vector< double > regularization_size
std::vector< casadi_int > ls_trials
std::vector< double > inf_du
UnifiedReturnStatus unified_return_status
Definition: nlpsol_impl.hpp:48
casadi_nlpsol_data< double > d_nlp
Definition: nlpsol_impl.hpp:42
Options metadata for a class.
Definition: options.hpp:40
std::map< std::string, FStats > fstats