ipopt_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 "ipopt_interface.hpp"
28 #include "ipopt_nlp.hpp"
29 #include "casadi/core/casadi_misc.hpp"
30 #include "../../core/global_options.hpp"
31 #include "../../core/casadi_interrupt.hpp"
32 #include "../../core/convexify.hpp"
33 
34 #include <ctime>
35 #include <stdlib.h>
36 #include <iostream>
37 #include <iomanip>
38 #include <chrono>
39 
40 #include <IpIpoptApplication.hpp>
41 
42 #include <ipopt_runtime_str.h>
43 
44 namespace casadi {
45  extern "C"
46  int CASADI_NLPSOL_IPOPT_EXPORT
47  casadi_register_nlpsol_ipopt(Nlpsol::Plugin* plugin) {
48  plugin->creator = IpoptInterface::creator;
49  plugin->name = "ipopt";
50  plugin->doc = IpoptInterface::meta_doc.c_str();
51  plugin->version = CASADI_VERSION;
52  plugin->options = &IpoptInterface::options_;
53  plugin->deserialize = &IpoptInterface::deserialize;
54  return 0;
55  }
56 
57  extern "C"
58  void CASADI_NLPSOL_IPOPT_EXPORT casadi_load_nlpsol_ipopt() {
60  }
61 
62  IpoptInterface::IpoptInterface(const std::string& name, const Function& nlp)
63  : Nlpsol(name, nlp) {
64  }
65 
67  clear_mem();
68  }
69 
71  = {{&Nlpsol::options_},
72  {{"pass_nonlinear_variables",
73  {OT_BOOL,
74  "Pass list of variables entering nonlinearly to IPOPT"}},
75  {"nonlinear_variables",
77  "Which decision variables enter nonlinearly? (detected automatically by default)"}},
78  {"ipopt",
79  {OT_DICT,
80  "Options to be passed to IPOPT"}},
81  {"var_string_md",
82  {OT_DICT,
83  "String metadata (a dictionary with lists of strings) "
84  "about variables to be passed to IPOPT"}},
85  {"var_integer_md",
86  {OT_DICT,
87  "Integer metadata (a dictionary with lists of integers) "
88  "about variables to be passed to IPOPT"}},
89  {"var_numeric_md",
90  {OT_DICT,
91  "Numeric metadata (a dictionary with lists of reals) about "
92  "variables to be passed to IPOPT"}},
93  {"con_string_md",
94  {OT_DICT,
95  "String metadata (a dictionary with lists of strings) about "
96  "constraints to be passed to IPOPT"}},
97  {"con_integer_md",
98  {OT_DICT,
99  "Integer metadata (a dictionary with lists of integers) "
100  "about constraints to be passed to IPOPT"}},
101  {"con_numeric_md",
102  {OT_DICT,
103  "Numeric metadata (a dictionary with lists of reals) about "
104  "constraints to be passed to IPOPT"}},
105  {"hess_lag",
106  {OT_FUNCTION,
107  "Function for calculating the Hessian of the Lagrangian (autogenerated by default)"}},
108  {"jac_g",
109  {OT_FUNCTION,
110  "Function for calculating the Jacobian of the constraints "
111  "(autogenerated by default)"}},
112  {"grad_f",
113  {OT_FUNCTION,
114  "Function for calculating the gradient of the objective "
115  "(column, autogenerated by default)"}},
116  {"convexify_strategy",
117  {OT_STRING,
118  "NONE|regularize|eigen-reflect|eigen-clip. "
119  "Strategy to convexify the Lagrange Hessian before passing it to the solver."}},
120  {"convexify_margin",
121  {OT_DOUBLE,
122  "When using a convexification strategy, make sure that "
123  "the smallest eigenvalue is at least this (default: 1e-7)."}},
124  {"max_iter_eig",
125  {OT_DOUBLE,
126  "Maximum number of iterations to compute an eigenvalue decomposition (default: 50)."}},
127  {"clip_inactive_lam",
128  {OT_BOOL,
129  "Explicitly set Lagrange multipliers to 0 when bound is deemed inactive "
130  "(default: false)."}},
131  {"inactive_lam_strategy",
132  {OT_STRING,
133  "Strategy to detect if a bound is inactive. "
134  "RELTOL: use solver-defined constraint tolerance * inactive_lam_value|"
135  "abstol: use inactive_lam_value"}},
136  {"inactive_lam_value",
137  {OT_DOUBLE,
138  "Value used in inactive_lam_strategy (default: 10)."}}
139  }
140  };
141 
142  void IpoptInterface::init(const Dict& opts) {
143  // Call the init method of the base class
144  Nlpsol::init(opts);
145 
146  // Default options
148 
149  std::string convexify_strategy = "none";
150  double convexify_margin = 1e-7;
151  casadi_int max_iter_eig = 200;
152 
153  clip_inactive_lam_ = false;
154  inactive_lam_strategy_ = "reltol";
155  inactive_lam_value_ = 10;
156 
157  // Read user options
158  for (auto&& op : opts) {
159  if (op.first=="ipopt") {
160  opts_ = op.second;
161  } else if (op.first=="pass_nonlinear_variables") {
162  pass_nonlinear_variables_ = op.second;
163  } else if (op.first=="nonlinear_variables") {
164  nl_ex_ = op.second;
165  casadi_assert(nl_ex_.empty() || nl_ex_.size()==nx_, "Wrong length ("
166  + str(nl_ex_.size()) + ") for 'nonlinear_variables', expected " + str(nx_));
167  } else if (op.first=="var_string_md") {
168  var_string_md_ = op.second;
169  } else if (op.first=="var_integer_md") {
170  var_integer_md_ = op.second;
171  } else if (op.first=="var_numeric_md") {
172  var_numeric_md_ = op.second;
173  } else if (op.first=="con_string_md") {
174  con_string_md_ = op.second;
175  } else if (op.first=="con_integer_md") {
176  con_integer_md_ = op.second;
177  } else if (op.first=="con_numeric_md") {
178  con_numeric_md_ = op.second;
179  } else if (op.first=="hess_lag") {
180  Function f = op.second;
181  casadi_assert_dev(f.n_in()==4);
182  casadi_assert_dev(f.n_out()==1);
183  set_function(f, "nlp_hess_l");
184  } else if (op.first=="jac_g") {
185  Function f = op.second;
186  casadi_assert_dev(f.n_in()==2);
187  casadi_assert_dev(f.n_out()==2);
188  set_function(f, "nlp_jac_g");
189  } else if (op.first=="grad_f") {
190  Function f = op.second;
191  casadi_assert_dev(f.n_in()==2);
192  casadi_assert_dev(f.n_out()==2);
193  set_function(f, "nlp_grad_f");
194  } else if (op.first=="convexify_strategy") {
195  convexify_strategy = op.second.to_string();
196  } else if (op.first=="convexify_margin") {
197  convexify_margin = op.second;
198  } else if (op.first=="max_iter_eig") {
199  max_iter_eig = op.second;
200  } else if (op.first=="clip_inactive_lam") {
201  clip_inactive_lam_ = op.second;
202  } else if (op.first=="inactive_lam_strategy") {
203  inactive_lam_strategy_ = op.second.to_string();
204  } else if (op.first=="inactive_lam_value") {
205  inactive_lam_value_ = op.second;
206  }
207  }
208 
209  // Do we need second order derivatives?
210  exact_hessian_ = true;
211  auto hessian_approximation = opts_.find("hessian_approximation");
212  if (hessian_approximation!=opts_.end()) {
213  exact_hessian_ = hessian_approximation->second == "exact";
214  }
215 
216  // Setup NLP functions
217  create_function("nlp_f", {"x", "p"}, {"f"});
218  create_function("nlp_g", {"x", "p"}, {"g"});
219  if (!has_function("nlp_grad_f")) {
220  create_function("nlp_grad_f", {"x", "p"}, {"f", "grad:f:x"});
221  }
222  if (!has_function("nlp_jac_g")) {
223  create_function("nlp_jac_g", {"x", "p"}, {"g", "jac:g:x"});
224  }
225  jacg_sp_ = get_function("nlp_jac_g").sparsity_out(1);
226  casadi_assert(jacg_sp_.size1()==ng_, "nlp_jac_g must have " + str(ng_) +
227  " rows, but has " + str(jacg_sp_.size1()) + " instead.");
228  casadi_assert(jacg_sp_.size2()==nx_, "nlp_jac_g must have " + str(nx_) +
229  " columns, but has " + str(jacg_sp_.size2()) + " instead.");
230 
231  convexify_ = false;
232 
233  // Allocate temporary work vectors
234  if (exact_hessian_) {
235  if (!has_function("nlp_hess_l")) {
236  create_function("nlp_hess_l", {"x", "p", "lam:f", "lam:g"},
237  {"triu:hess:gamma:x:x"}, {{"gamma", {"f", "g"}}});
238  }
239  hesslag_sp_ = get_function("nlp_hess_l").sparsity_out(0);
240  casadi_assert(hesslag_sp_.is_triu(), "Hessian must be upper triangular");
241  if (convexify_strategy!="none") {
242  convexify_ = true;
243  Dict opts;
244  opts["strategy"] = convexify_strategy;
245  opts["margin"] = convexify_margin;
246  opts["max_iter_eig"] = max_iter_eig;
247  opts["verbose"] = verbose_;
249  }
250  } else if (pass_nonlinear_variables_ && nl_ex_.empty()) {
251  nl_ex_ = oracle_.which_depends("x", {"f", "g"}, 2, false);
252  }
253 
254  // Allocate work vectors
255  alloc_w(ng_, true); // gk_
256  alloc_w(nx_, true); // grad_fk_
257  alloc_w(jacg_sp_.nnz(), true); // jac_gk_
258  if (exact_hessian_) {
259  alloc_w(hesslag_sp_.nnz(), true); // hess_lk_
260  }
261  if (convexify_) {
264  }
265  }
266 
267  int IpoptInterface::init_mem(void* mem) const {
268  if (Nlpsol::init_mem(mem)) return 1;
269  auto m = static_cast<IpoptMemory*>(mem);
270 
271  // Start an IPOPT application
272  Ipopt::SmartPtr<Ipopt::IpoptApplication> *app = new Ipopt::SmartPtr<Ipopt::IpoptApplication>();
273  m->app = static_cast<void*>(app);
274  *app = new Ipopt::IpoptApplication(false);
275 
276  // Direct output through casadi::uout()
277  StreamJournal* jrnl_raw = new StreamJournal("console", J_ITERSUMMARY);
278  jrnl_raw->SetOutputStream(&casadi::uout());
279  jrnl_raw->SetPrintLevel(J_DBG, J_NONE);
280  SmartPtr<Journal> jrnl = jrnl_raw;
281  (*app)->Jnlst()->AddJournal(jrnl);
282 
283  // Create an Ipopt user class -- need to use Ipopts spart pointer class
284  Ipopt::SmartPtr<Ipopt::TNLP> *userclass = new Ipopt::SmartPtr<Ipopt::TNLP>();
285  m->userclass = static_cast<void*>(userclass);
286  *userclass = new IpoptUserClass(*this, m);
287 
288  if (verbose_) {
289  uout() << "There are " << nx_ << " variables and " << ng_ << " constraints." << std::endl;
290  if (exact_hessian_) uout() << "Using exact Hessian" << std::endl;
291  else uout() << "Using limited memory Hessian approximation" << std::endl;
292  }
293 
294  // Get all options available in (s)IPOPT
295  auto regops = (*app)->RegOptions()->RegisteredOptionsList();
296 
297  Dict options = Options::sanitize(opts_);
298  // Replace resto group with prefixes
299  auto it = options.find("resto");
300  if (it!=options.end()) {
301  Dict resto_options = it->second;
302  options.erase(it);
303  for (auto&& op : resto_options) {
304  options["resto." + op.first] = op.second;
305  }
306  }
307 
308  // Pass all the options to ipopt
309  for (auto&& op : options) {
310 
311  // There might be options with a resto prefix.
312  std::string option_name = op.first;
313  if (startswith(option_name, "resto.")) {
314  option_name = option_name.substr(6);
315  }
316 
317  // Find the option
318  auto regops_it = regops.find(option_name);
319  if (regops_it==regops.end()) {
320  casadi_error("No such IPOPT option: " + op.first);
321  }
322 
323  // Get the type
324  Ipopt::RegisteredOptionType ipopt_type = regops_it->second->Type();
325 
326  // Pass to IPOPT
327  bool ret;
328  switch (ipopt_type) {
329  case Ipopt::OT_Number:
330  ret = (*app)->Options()->SetNumericValue(op.first, op.second.to_double(), false);
331  break;
332  case Ipopt::OT_Integer:
333  ret = (*app)->Options()->SetIntegerValue(op.first, op.second.to_int(), false);
334  break;
335  case Ipopt::OT_String:
336  ret = (*app)->Options()->SetStringValue(op.first, op.second.to_string(), false);
337  break;
338  case Ipopt::OT_Unknown:
339  default:
340  casadi_warning("Cannot handle option \"" + op.first + "\", ignored");
341  continue;
342  }
343  if (!ret) casadi_error("Invalid options were detected by Ipopt.");
344  }
345 
346  // Override IPOPT's default linear solver
347  if (opts_.find("linear_solver") == opts_.end()) {
348  char * default_solver = getenv("IPOPT_DEFAULT_LINEAR_SOLVER");
349  if (default_solver) {
350  bool ret = (*app)->Options()->SetStringValue("linear_solver", default_solver, false);
351  casadi_assert(ret, "Corrupted IPOPT_DEFAULT_LINEAR_SOLVER environmental variable");
352  } else {
353  // Fall back to MUMPS (avoid user issues after SPRAL was added to binaries and
354  // chosen default by Ipopt)
355  bool ret = (*app)->Options()->SetStringValue("linear_solver", "mumps", false);
356  casadi_assert_dev(ret);
357  }
358 
359  }
360 
361  // Intialize the IpoptApplication and process the options
362  Ipopt::ApplicationReturnStatus status = (*app)->Initialize();
363  casadi_assert(status == Solve_Succeeded, "Error during IPOPT initialization");
364 
365  if (convexify_) m->add_stat("convexify");
366  return 0;
367  }
368 
369  void IpoptInterface::set_work(void* mem, const double**& arg, double**& res,
370  casadi_int*& iw, double*& w) const {
371  auto m = static_cast<IpoptMemory*>(mem);
372 
373  // Set work in base classes
374  Nlpsol::set_work(mem, arg, res, iw, w);
375 
376  // Work vectors
377  m->gk = w; w += ng_;
378  m->grad_fk = w; w += nx_;
379  m->jac_gk = w; w += jacg_sp_.nnz();
380  if (exact_hessian_) {
381  m->hess_lk = w; w += hesslag_sp_.nnz();
382  }
383  }
384 
385  inline const char* return_status_string(Ipopt::ApplicationReturnStatus status) {
386  switch (status) {
387  case Solve_Succeeded:
388  return "Solve_Succeeded";
389  case Solved_To_Acceptable_Level:
390  return "Solved_To_Acceptable_Level";
391  case Infeasible_Problem_Detected:
392  return "Infeasible_Problem_Detected";
393  case Search_Direction_Becomes_Too_Small:
394  return "Search_Direction_Becomes_Too_Small";
395  case Diverging_Iterates:
396  return "Diverging_Iterates";
397  case User_Requested_Stop:
398  return "User_Requested_Stop";
399  case Maximum_Iterations_Exceeded:
400  return "Maximum_Iterations_Exceeded";
401  case Restoration_Failed:
402  return "Restoration_Failed";
403  case Error_In_Step_Computation:
404  return "Error_In_Step_Computation";
405  case Not_Enough_Degrees_Of_Freedom:
406  return "Not_Enough_Degrees_Of_Freedom";
407  case Invalid_Problem_Definition:
408  return "Invalid_Problem_Definition";
409  case Invalid_Option:
410  return "Invalid_Option";
411  case Invalid_Number_Detected:
412  return "Invalid_Number_Detected";
413  case Unrecoverable_Exception:
414  return "Unrecoverable_Exception";
415  case NonIpopt_Exception_Thrown:
416  return "NonIpopt_Exception_Thrown";
417  case Insufficient_Memory:
418  return "Insufficient_Memory";
419  case Internal_Error:
420  return "Internal_Error";
421  case Maximum_CpuTime_Exceeded:
422  return "Maximum_CpuTime_Exceeded";
423  case Feasible_Point_Found:
424  return "Feasible_Point_Found";
425 #if (IPOPT_VERSION_MAJOR > 3) || (IPOPT_VERSION_MAJOR == 3 && IPOPT_VERSION_MINOR >= 14)
426  case Maximum_WallTime_Exceeded:
427  return "Maximum_WallTime_Exceeded";
428 #endif
429  }
430  return "Unknown";
431  }
432 
433  int IpoptInterface::solve(void* mem) const {
434  auto m = static_cast<IpoptMemory*>(mem);
435  auto d_nlp = &m->d_nlp;
436 
437  // Reset statistics
438  m->inf_pr.clear();
439  m->inf_du.clear();
440  m->mu.clear();
441  m->d_norm.clear();
442  m->regularization_size.clear();
443  m->alpha_pr.clear();
444  m->alpha_du.clear();
445  m->obj.clear();
446  m->ls_trials.clear();
447 
448  // Reset number of iterations
449  m->n_iter = 0;
450 
451  // Get back the smart pointers
452  Ipopt::SmartPtr<Ipopt::TNLP> *userclass =
453  static_cast<Ipopt::SmartPtr<Ipopt::TNLP>*>(m->userclass);
454  Ipopt::SmartPtr<Ipopt::IpoptApplication> *app =
455  static_cast<Ipopt::SmartPtr<Ipopt::IpoptApplication>*>(m->app);
456 
457  // Ask Ipopt to solve the problem
458  Ipopt::ApplicationReturnStatus status = (*app)->OptimizeTNLP(*userclass);
459  m->return_status = return_status_string(status);
460  m->success = status==Solve_Succeeded || status==Solved_To_Acceptable_Level
461  || status==Feasible_Point_Found;
462  if (status==Maximum_Iterations_Exceeded ||
463  status==Maximum_CpuTime_Exceeded) m->unified_return_status = SOLVER_RET_LIMITED;
464 
465 #if (IPOPT_VERSION_MAJOR > 3) || (IPOPT_VERSION_MAJOR == 3 && IPOPT_VERSION_MINOR >= 14)
466  if (status==Maximum_WallTime_Exceeded) m->unified_return_status = SOLVER_RET_LIMITED;
467 #endif
468 
469  // Save results to outputs
470  casadi_copy(m->gk, ng_, d_nlp->z + nx_);
471 
472  if (clip_inactive_lam_) {
473  // Compute a margin
474  double margin;
475  if (inactive_lam_strategy_=="abstol") {
476  margin = inactive_lam_value_;
477  } else if (inactive_lam_strategy_=="reltol") {
478  double constr_viol_tol;
479  (*app)->Options()->GetNumericValue("constr_viol_tol", constr_viol_tol, "");
480  if (status==Solved_To_Acceptable_Level) {
481  (*app)->Options()->GetNumericValue("acceptable_constr_viol_tol", constr_viol_tol, "");
482  }
483  margin = inactive_lam_value_*constr_viol_tol;
484  } else {
485  casadi_error("inactive_lam_strategy '" + inactive_lam_strategy_ +
486  "' unknown. Use 'abstol' or reltol'.");
487  }
488 
489  for (casadi_int i=0; i<nx_ + ng_; ++i) {
490  // Sufficiently inactive -> make multiplier exactly zero
491  if (d_nlp->lam[i]>0 && d_nlp->ubz[i] - d_nlp->z[i] > margin) d_nlp->lam[i]=0;
492  if (d_nlp->lam[i]<0 && d_nlp->z[i] - d_nlp->lbz[i] > margin) d_nlp->lam[i]=0;
493  }
494  }
495 
496  return 0;
497  }
498 
500  intermediate_callback(IpoptMemory* m, const double* x, const double* z_L, const double* z_U,
501  const double* g, const double* lambda, double obj_value, int iter,
502  double inf_pr, double inf_du, double mu, double d_norm,
503  double regularization_size, double alpha_du, double alpha_pr,
504  int ls_trials, bool full_callback) const {
505  auto d_nlp = &m->d_nlp;
506  m->n_iter += 1;
507  try {
508  m->inf_pr.push_back(inf_pr);
509  m->inf_du.push_back(inf_du);
510  m->mu.push_back(mu);
511  m->d_norm.push_back(d_norm);
512  m->regularization_size.push_back(regularization_size);
513  m->alpha_pr.push_back(alpha_pr);
514  m->alpha_du.push_back(alpha_du);
515  m->ls_trials.push_back(ls_trials);
516  m->obj.push_back(obj_value);
517  if (!fcallback_.is_null()) {
518  ScopedTiming tic(m->fstats.at("callback_fun"));
519  if (full_callback) {
520  casadi_copy(x, nx_, d_nlp->z);
521  for (casadi_int i=0; i<nx_; ++i) {
522  d_nlp->lam[i] = z_U[i]-z_L[i];
523  }
524  casadi_copy(lambda, ng_, d_nlp->lam + nx_);
525  casadi_copy(g, ng_, m->gk);
526  } else {
527  if (iter==0) {
528  uerr()
529  << "Warning: intermediate_callback is disfunctional in your installation. "
530  "You will only be able to use stats(). "
531  "See https://github.com/casadi/casadi/wiki/enableIpoptCallback to enable it."
532  << std::endl;
533  }
534  }
535 
536  // Inputs
537  std::fill_n(m->arg, fcallback_.n_in(), nullptr);
538  if (full_callback) {
539  // The values used below are meaningless
540  // when not doing a full_callback
541  m->arg[NLPSOL_X] = x;
542  m->arg[NLPSOL_F] = &obj_value;
543  m->arg[NLPSOL_G] = g;
544  m->arg[NLPSOL_LAM_P] = nullptr;
545  m->arg[NLPSOL_LAM_X] = d_nlp->lam;
546  m->arg[NLPSOL_LAM_G] = d_nlp->lam + nx_;
547  }
548 
549  // Outputs
550  std::fill_n(m->res, fcallback_.n_out(), nullptr);
551  double ret_double;
552  m->res[0] = &ret_double;
553 
554  fcallback_(m->arg, m->res, m->iw, m->w, 0);
555  casadi_int ret = static_cast<casadi_int>(ret_double);
556 
557  return !ret;
558  } else {
559  return 1;
560  }
561 
562  } catch(KeyboardInterruptException& ex) {
563  return 0;
564  } catch(std::exception& ex) {
565  casadi_warning("intermediate_callback: " + std::string(ex.what()));
566  if (iteration_callback_ignore_errors_) return 1;
567  return 0;
568  }
569  }
570 
572  finalize_solution(IpoptMemory* m, const double* x, const double* z_L, const double* z_U,
573  const double* g, const double* lambda, double obj_value,
574  int iter_count) const {
575  auto d_nlp = &m->d_nlp;
576  try {
577  // Get primal solution
578  casadi_copy(x, nx_, d_nlp->z);
579 
580  // Get optimal cost
581  d_nlp->objective = obj_value;
582 
583  // Get dual solution (simple bounds)
584  for (casadi_int i=0; i<nx_; ++i) {
585  d_nlp->lam[i] = z_U[i]-z_L[i];
586  }
587 
588  // Get dual solution (nonlinear bounds)
589  casadi_copy(lambda, ng_, d_nlp->lam + nx_);
590 
591  // Get the constraints
592  casadi_copy(g, ng_, m->gk);
593 
594  // Get statistics
595  m->iter_count = iter_count;
596 
597  } catch(std::exception& ex) {
598  uerr() << "finalize_solution failed: " << ex.what() << std::endl;
599  }
600  }
601 
603  get_bounds_info(IpoptMemory* m, double* x_l, double* x_u,
604  double* g_l, double* g_u) const {
605  auto d_nlp = &m->d_nlp;
606  try {
607  casadi_copy(d_nlp->lbz, nx_, x_l);
608  casadi_copy(d_nlp->ubz, nx_, x_u);
609  casadi_copy(d_nlp->lbz+nx_, ng_, g_l);
610  casadi_copy(d_nlp->ubz+nx_, ng_, g_u);
611  return true;
612  } catch(std::exception& ex) {
613  uerr() << "get_bounds_info failed: " << ex.what() << std::endl;
614  return false;
615  }
616  }
617 
619  get_starting_point(IpoptMemory* m, bool init_x, double* x,
620  bool init_z, double* z_L, double* z_U,
621  bool init_lambda, double* lambda) const {
622  auto d_nlp = &m->d_nlp;
623  try {
624  // Initialize primal variables
625  if (init_x) {
626  casadi_copy(d_nlp->z, nx_, x);
627  }
628 
629  // Initialize dual variables (simple bounds)
630  if (init_z) {
631  for (casadi_int i=0; i<nx_; ++i) {
632  z_L[i] = std::max(0., -d_nlp->lam[i]);
633  z_U[i] = std::max(0., d_nlp->lam[i]);
634  }
635  }
636 
637  // Initialize dual variables (nonlinear bounds)
638  if (init_lambda) {
639  casadi_copy(d_nlp->lam + nx_, ng_, lambda);
640  }
641 
642  return true;
643  } catch(std::exception& ex) {
644  uerr() << "get_starting_point failed: " << ex.what() << std::endl;
645  return false;
646  }
647  }
648 
649  void IpoptInterface::get_nlp_info(IpoptMemory* m, int& nx, int& ng,
650  int& nnz_jac_g, int& nnz_h_lag) const {
651  try {
652  // Number of variables
653  nx = nx_;
654 
655  // Number of constraints
656  ng = ng_;
657 
658  // Number of Jacobian nonzeros
659  nnz_jac_g = ng_==0 ? 0 : jacg_sp_.nnz();
660 
661  // Number of Hessian nonzeros (only upper triangular half)
662  nnz_h_lag = exact_hessian_ ? hesslag_sp_.nnz() : 0;
663 
664  } catch(std::exception& ex) {
665  uerr() << "get_nlp_info failed: " << ex.what() << std::endl;
666  }
667  }
668 
670  try {
672  // No Hessian has been interfaced
673  return -1;
674  } else {
675  // Number of variables that appear nonlinearily
676  int nv = 0;
677  for (auto&& i : nl_ex_) if (i) nv++;
678  return nv;
679  }
680  } catch(std::exception& ex) {
681  uerr() << "get_number_of_nonlinear_variables failed: " << ex.what() << std::endl;
682  return -1;
683  }
684  }
685 
687  get_list_of_nonlinear_variables(int num_nonlin_vars, int* pos_nonlin_vars) const {
688  try {
689  for (int i=0; i<nl_ex_.size(); ++i) {
690  if (nl_ex_[i]) *pos_nonlin_vars++ = i;
691  }
692  return true;
693  } catch(std::exception& ex) {
694  uerr() << "get_list_of_nonlinear_variables failed: " << ex.what() << std::endl;
695  return false;
696  }
697  }
698 
700  get_var_con_metadata(std::map<std::string, std::vector<std::string> >& var_string_md,
701  std::map<std::string, std::vector<int> >& var_integer_md,
702  std::map<std::string, std::vector<double> >& var_numeric_md,
703  std::map<std::string, std::vector<std::string> >& con_string_md,
704  std::map<std::string, std::vector<int> >& con_integer_md,
705  std::map<std::string, std::vector<double> >& con_numeric_md) const {
706  for (auto&& op : var_string_md_) var_string_md[op.first] = op.second;
707  for (auto&& op : var_integer_md_) var_integer_md[op.first] = op.second;
708  for (auto&& op : var_numeric_md_) var_numeric_md[op.first] = op.second;
709  for (auto&& op : con_string_md_) con_string_md[op.first] = op.second;
710  for (auto&& op : con_integer_md_) con_integer_md[op.first] = op.second;
711  for (auto&& op : con_numeric_md_) con_numeric_md[op.first] = op.second;
712  return true;
713  }
714 
716  this->app = nullptr;
717  this->userclass = nullptr;
718  this->return_status = "Unset";
719  }
720 
722  // Free Ipopt application instance (or rather, the smart pointer holding it)
723  if (this->app != nullptr) {
724  delete static_cast<Ipopt::SmartPtr<Ipopt::IpoptApplication>*>(this->app);
725  }
726 
727  // Free Ipopt user class (or rather, the smart pointer holding it)
728  if (this->userclass != nullptr) {
729  delete static_cast<Ipopt::SmartPtr<Ipopt::TNLP>*>(this->userclass);
730  }
731  }
732 
733  Dict IpoptInterface::get_stats(void* mem) const {
734  Dict stats = Nlpsol::get_stats(mem);
735  auto m = static_cast<IpoptMemory*>(mem);
736  stats["return_status"] = m->return_status;
737  stats["iter_count"] = m->iter_count;
738  if (!m->inf_pr.empty()) {
739  Dict iterations;
740  iterations["inf_pr"] = m->inf_pr;
741  iterations["inf_du"] = m->inf_du;
742  iterations["mu"] = m->mu;
743  iterations["d_norm"] = m->d_norm;
744  iterations["regularization_size"] = m->regularization_size;
745  iterations["obj"] = m->obj;
746  iterations["alpha_pr"] = m->alpha_pr;
747  iterations["alpha_du"] = m->alpha_du;
748  stats["iterations"] = iterations;
749  }
750  return stats;
751  }
752 
754  int version = s.version("IpoptInterface", 1, 3);
755  s.unpack("IpoptInterface::jacg_sp", jacg_sp_);
756  s.unpack("IpoptInterface::hesslag_sp", hesslag_sp_);
757  s.unpack("IpoptInterface::exact_hessian", exact_hessian_);
758  s.unpack("IpoptInterface::opts", opts_);
759  s.unpack("IpoptInterface::pass_nonlinear_variables", pass_nonlinear_variables_);
760  s.unpack("IpoptInterface::nl_ex", nl_ex_);
761  s.unpack("IpoptInterface::var_string_md", var_string_md_);
762  s.unpack("IpoptInterface::var_integer_md", var_integer_md_);
763  s.unpack("IpoptInterface::var_numeric_md", var_numeric_md_);
764  s.unpack("IpoptInterface::con_string_md", con_string_md_);
765  s.unpack("IpoptInterface::con_integer_md", con_integer_md_);
766  s.unpack("IpoptInterface::con_numeric_md", con_numeric_md_);
767  if (version>=2) {
768  s.unpack("IpoptInterface::convexify", convexify_);
769  if (convexify_) Convexify::deserialize(s, "IpoptInterface::", convexify_data_);
770  }
771 
772  if (version>=3) {
773  s.unpack("IpoptInterface::clip_inactive_lam", clip_inactive_lam_);
774  s.unpack("IpoptInterface::inactive_lam_strategy", inactive_lam_strategy_);
775  s.unpack("IpoptInterface::inactive_lam_value", inactive_lam_value_);
776  } else {
777  clip_inactive_lam_ = false;
778  inactive_lam_strategy_ = "reltol";
779  inactive_lam_value_ = 10;
780  }
781  }
782 
785  s.version("IpoptInterface", 3);
786  s.pack("IpoptInterface::jacg_sp", jacg_sp_);
787  s.pack("IpoptInterface::hesslag_sp", hesslag_sp_);
788  s.pack("IpoptInterface::exact_hessian", exact_hessian_);
789  s.pack("IpoptInterface::opts", opts_);
790  s.pack("IpoptInterface::pass_nonlinear_variables", pass_nonlinear_variables_);
791  s.pack("IpoptInterface::nl_ex", nl_ex_);
792  s.pack("IpoptInterface::var_string_md", var_string_md_);
793  s.pack("IpoptInterface::var_integer_md", var_integer_md_);
794  s.pack("IpoptInterface::var_numeric_md", var_numeric_md_);
795  s.pack("IpoptInterface::con_string_md", con_string_md_);
796  s.pack("IpoptInterface::con_integer_md", con_integer_md_);
797  s.pack("IpoptInterface::con_numeric_md", con_numeric_md_);
798  s.pack("IpoptInterface::convexify", convexify_);
799  if (convexify_) Convexify::serialize(s, "IpoptInterface::", convexify_data_);
800 
801  s.pack("IpoptInterface::clip_inactive_lam", clip_inactive_lam_);
802  s.pack("IpoptInterface::inactive_lam_strategy", inactive_lam_strategy_);
803  s.pack("IpoptInterface::inactive_lam_value", inactive_lam_value_);
804 
805  }
806 
808  g << "casadi_ipopt_init_mem(&" + codegen_mem(g) + ");\n";
809  g << "return 0;\n";
810  }
811 
813  g << "casadi_ipopt_free_mem(&" + codegen_mem(g) + ");\n";
814  }
815 
821  g.add_dependency(get_function("nlp_f"));
822  g.add_dependency(get_function("nlp_grad_f"));
823  g.add_dependency(get_function("nlp_g"));
824  g.add_dependency(get_function("nlp_jac_g"));
825  if (exact_hessian_) {
826  g.add_dependency(get_function("nlp_hess_l"));
827  }
828  g.add_include("coin-or/IpStdCInterface.h");
829 
830  std::string name = "nlp_f";
831  std::string f = g.shorthand(g.wrapper(get_function(name), name));
832 
833  g << "bool " << f
834  << "(ipindex n, ipnumber *x, bool new_x, ipnumber *obj_value, UserDataPtr user_data) {\n";
835  g.flush(g.body);
836  g.scope_enter();
837  g << "struct casadi_ipopt_data* d = (struct casadi_ipopt_data*) user_data;\n";
838  g << "d->arg[0] = x;\n";
839  g << "d->arg[1] = d->nlp->p;\n";
840  g << "d->res[0] = obj_value;\n";
841  std::string flag = g(get_function(name), "d->arg", "d->res", "d->iw", "d->w", "false");
842  g << "if (" + flag + ") return false;\n";
843  g << "return true;\n";
844  g.scope_exit();
845  g << "}\n";
846 
847  name = "nlp_g";
848  f = g.shorthand(g.wrapper(get_function(name), name));
849  g << "bool " << f
850  << "(ipindex n, ipnumber *x, bool new_x, ipindex m, ipnumber *g, UserDataPtr user_data) {\n";
851  g.flush(g.body);
852  g.scope_enter();
853  g << "struct casadi_ipopt_data* d = (struct casadi_ipopt_data*) user_data;\n";
854  g << "d->arg[0] = x;\n";
855  g << "d->arg[1] = d->nlp->p;\n";
856  g << "d->res[0] = g;\n";
857  flag = g(get_function(name), "d->arg", "d->res", "d->iw", "d->w", "false");
858  g << "if (" + flag + ") return false;\n";
859  g << "return true;\n";
860  g.scope_exit();
861  g << "}\n";
862 
863  name = "nlp_grad_f";
864  f = g.shorthand(g.wrapper(get_function(name), name));
865  g << "bool " << f
866  << "(ipindex n, ipnumber *x, bool new_x, ipnumber *grad_f, UserDataPtr user_data) {\n";
867  g.flush(g.body);
868  g.scope_enter();
869  g << "struct casadi_ipopt_data* d = (struct casadi_ipopt_data*) user_data;\n";
870  g << "d->arg[0] = x;\n";
871  g << "d->arg[1] = d->nlp->p;\n";
872  g << "d->res[0] = 0;\n";
873  g << "d->res[1] = grad_f;\n";
874  flag = g(get_function(name), "d->arg", "d->res", "d->iw", "d->w", "false");
875  g << "if (" + flag + ") return false;\n";
876  g << "return true;\n";
877  g.scope_exit();
878  g << "}\n";
879 
880  name = "nlp_jac_g";
881  f = g.shorthand(g.wrapper(get_function(name), name));
882  g << "bool " << f
883  << "(ipindex n, ipnumber *x, bool new_x, ipindex m,"
884  << " ipindex nele_jac, ipindex *iRow, ipindex *jCol, "
885  << "ipnumber *values, UserDataPtr user_data) {\n";
886  g.flush(g.body);
887  g.scope_enter();
888  g << "struct casadi_ipopt_data* d = (struct casadi_ipopt_data*) user_data;\n";
889  g << "if (values) {\n";
890  g << "d->arg[0] = x;\n";
891  g << "d->arg[1] = d->nlp->p;\n";
892  g << "d->res[0] = 0;\n";
893  g << "d->res[1] = values;\n";
894  flag = g(get_function(name), "d->arg", "d->res", "d->iw", "d->w", "false");
895  g << "if (" + flag + ") return false;\n";
896  g << "} else {\n";
897  g << "casadi_ipopt_sparsity(d->prob->sp_a, iRow, jCol);\n";
898  g << "}\n";
899  g << "return true;\n";
900  g.scope_exit();
901  g << "}\n";
902 
903  if (exact_hessian_) {
904  name = "nlp_hess_l";
905  f = g.shorthand(g.wrapper(get_function(name), name));
906  g << "bool " << f << "(ipindex n, ipnumber *x, bool new_x, ipnumber obj_factor,"
907  << "ipindex m, ipnumber *lambda, bool new_lambda, ipindex nele_hess, "
908  << "ipindex *iRow, ipindex *jCol, ipnumber *values, UserDataPtr user_data) {\n";
909  g.flush(g.body);
910  g.scope_enter();
911  g << "struct casadi_ipopt_data* d = (struct casadi_ipopt_data*) user_data;\n";
912  g << "if (values) {\n";
913  g << "d->arg[0] = x;\n";
914  g << "d->arg[1] = d->nlp->p;\n";
915  g << "d->arg[2] = &obj_factor;\n";
916  g << "d->arg[3] = lambda;\n";
917  g << "d->res[0] = values;\n";
918  flag = g(get_function(name), "d->arg", "d->res", "d->iw", "d->w", "false");
919  g << "if (" + flag + ") return false;\n";
920  g << "return true;\n";
921  g << "} else {\n";
922  g << "casadi_ipopt_sparsity(d->prob->sp_h, iRow, jCol);\n";
923  g << "}\n";
924  g << "return true;\n";
925  g.scope_exit();
926  g << "}\n";
927  }
928 }
929 
932  g.auxiliaries << g.sanitize_source(ipopt_runtime_str, {"casadi_real"});
933 
934  g.local("d", "struct casadi_ipopt_data*");
935  g.init_local("d", "&" + codegen_mem(g));
936  g.local("p", "struct casadi_ipopt_prob");
937  set_ipopt_prob(g);
938 
939  g << "casadi_ipopt_set_work(d, &arg, &res, &iw, &w);\n";
940  g << "casadi_ipopt_presolve(d);\n";
941 
942  // Start an IPOPT application
943  Ipopt::SmartPtr<Ipopt::IpoptApplication> *app = new Ipopt::SmartPtr<Ipopt::IpoptApplication>();
944  *app = new Ipopt::IpoptApplication(false);
945 
946  // Get all options available in (s)IPOPT
947  auto regops = (*app)->RegOptions()->RegisteredOptionsList();
948 
949  Dict options = Options::sanitize(opts_);
950  // Replace resto group with prefixes
951  auto it = options.find("resto");
952  if (it!=options.end()) {
953  Dict resto_options = it->second;
954  options.erase(it);
955  for (auto&& op : resto_options) {
956  options["resto." + op.first] = op.second;
957  }
958  }
959 
960  // Pass all the options to ipopt
961  for (auto&& op : options) {
962 
963  // There might be options with a resto prefix.
964  std::string option_name = op.first;
965  if (startswith(option_name, "resto.")) {
966  option_name = option_name.substr(6);
967  }
968 
969  // Find the option
970  auto regops_it = regops.find(option_name);
971  if (regops_it==regops.end()) {
972  casadi_error("No such IPOPT option: " + op.first);
973  }
974 
975  // Get the type
976  Ipopt::RegisteredOptionType ipopt_type = regops_it->second->Type();
977 
978  // Pass to IPOPT
979  switch (ipopt_type) {
980  case Ipopt::OT_Number:
981  g << "AddIpoptNumOption(d->ipopt, \"" << op.first << "\""
982  << "," << op.second.to_double() << ");\n";
983  break;
984  case Ipopt::OT_Integer:
985  g << "AddIpoptIntOption(d->ipopt, \"" << op.first << "\""
986  << "," << op.second.to_int() << ");\n";
987  break;
988  case Ipopt::OT_String:
989  g << "AddIpoptStrOption(d->ipopt, \"" << op.first << "\""
990  << ",\"" << op.second.to_string() << "\");\n";
991  break;
992  case Ipopt::OT_Unknown:
993  default:
994  casadi_warning("Cannot handle option \"" + op.first + "\", ignored");
995  continue;
996  }
997  }
998 
999  // Override IPOPT's default linear solver
1000  if (opts_.find("linear_solver") == opts_.end()) {
1001  char * default_solver = getenv("IPOPT_DEFAULT_LINEAR_SOLVER");
1002  if (default_solver) {
1003  g << "AddIpoptStrOption(d->ipopt, \"linear_solver\"" << ",\"" << default_solver << "\");\n";
1004  } else {
1005  // Fall back to MUMPS (avoid user issues after SPRAL was added to binaries and
1006  // chosen default by Ipopt)
1007  g << "AddIpoptStrOption(d->ipopt, \"linear_solver\",\"mumps\");\n";
1008  }
1009 
1010  }
1011 
1012  delete app;
1013 
1014  // Options
1015  g << "casadi_ipopt_solve(d);\n";
1016 
1017  codegen_body_exit(g);
1018 
1019  if (error_on_fail_) {
1020  g << "return d->unified_return_status;\n";
1021  } else {
1022  g << "return 0;\n";
1023  }
1024 }
1025 
1027  if (jacg_sp_.size1()>0 && jacg_sp_.nnz()==0) {
1028  casadi_error("Empty sparsity pattern not supported in IPOPT C interface");
1029  }
1030  g << "d->nlp = &d_nlp;\n";
1031  g << "d->prob = &p;\n";
1032  g << "p.nlp = &p_nlp;\n";
1033  g << "p.sp_a = " << g.sparsity(jacg_sp_) << ";\n";
1034  if (exact_hessian_) {
1035  g << "p.sp_h = " << g.sparsity(hesslag_sp_) << ";\n";
1036  } else {
1037  g << "p.sp_h = 0;\n";
1038  }
1039  g << "casadi_ipopt_setup(&p);\n";
1040 
1041  std::string nlp_f = g.shorthand(g.wrapper(get_function("nlp_f"), "nlp_f"));
1042  g << "p.eval_f = " << nlp_f << ";\n";
1043  std::string nlp_g = g.shorthand(g.wrapper(get_function("nlp_g"), "nlp_g"));
1044  g << "p.eval_g = " << nlp_g << ";\n";
1045  std::string nlp_grad_f = g.shorthand(g.wrapper(get_function("nlp_grad_f"), "nlp_grad_f"));
1046  g << "p.eval_grad_f = " << nlp_grad_f << ";\n";
1047  std::string nlp_jac_g = g.shorthand(g.wrapper(get_function("nlp_jac_g"), "nlp_jac_g"));
1048  g << "p.eval_jac_g = " << nlp_jac_g << ";\n";
1049  if (exact_hessian_) {
1050  std::string nlp_hess_l = g.shorthand(g.wrapper(get_function("nlp_hess_l"), "nlp_hess_l"));
1051  g << "p.eval_h = " << nlp_hess_l << ";\n";
1052  } else {
1053  g << "p.eval_h = casadi_ipopt_hess_l_empty;\n";
1054  }
1055 }
1056 
1057 } // namespace casadi
const char * what() const override
Display error.
Definition: exception.hpp:90
Helper class for C code generation.
std::string add_dependency(const Function &f)
Add a function dependency.
std::string wrapper(const Function &base, const std::string &name)
void scope_enter()
Enter a local scope.
void flush(std::ostream &s)
Flush the buffer to a stream of choice.
void local(const std::string &name, const std::string &type, const std::string &ref="")
Declare a local variable.
void scope_exit()
Exit a local scope.
void init_local(const std::string &name, const std::string &def)
Specify the default value for a local variable.
std::string sanitize_source(const std::string &src, const std::vector< std::string > &inst, bool add_shorthand=true)
Sanitize source files for codegen.
void add_include(const std::string &new_include, bool relative_path=false, const std::string &use_ifdef=std::string())
Add an include file optionally using a relative path "..." instead of an absolute path <....
std::string shorthand(const std::string &name) const
Get a shorthand.
std::stringstream body
std::string sparsity(const Sparsity &sp, bool canonical=true)
std::stringstream auxiliaries
void add_auxiliary(Auxiliary f, const std::vector< std::string > &inst={"casadi_real"})
Add a built-in auxiliary function.
static void serialize(SerializingStream &s, const std::string &prefix, const ConvexifyData &d)
Definition: convexify.cpp:112
static Sparsity setup(ConvexifyData &d, const Sparsity &H, const Dict &opts=Dict(), bool inplace=true)
Definition: convexify.cpp:167
static MXNode * deserialize(DeserializingStream &s)
Deserialize without type information.
Definition: convexify.hpp:105
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_iw(size_t sz_iw, bool persistent=false)
Ensure required length of iw field.
std::string codegen_mem(CodeGenerator &g, const std::string &index="mem") const
Get thread-local memory object.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
Function object.
Definition: function.hpp:60
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
Which variables enter with some order.
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?
void get_nlp_info(IpoptMemory *m, int &nx, int &ng, int &nnz_jac_g, int &nnz_h_lag) const
void finalize_solution(IpoptMemory *m, const double *x, const double *z_L, const double *z_U, const double *g, const double *lambda, double obj_value, int iter_count) const
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
static const std::string meta_doc
A documentation string.
bool get_bounds_info(IpoptMemory *m, double *x_l, double *x_u, double *g_l, double *g_u) const
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
void codegen_init_mem(CodeGenerator &g) const override
Codegen alloc_mem.
void codegen_free_mem(CodeGenerator &g) const override
Codegen free_mem.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
bool exact_hessian_
Exact Hessian?
ConvexifyData convexify_data_
Data for convexification.
int get_number_of_nonlinear_variables() const
bool get_var_con_metadata(std::map< std::string, std::vector< std::string > > &var_string_md, std::map< std::string, std::vector< int > > &var_integer_md, std::map< std::string, std::vector< double > > &var_numeric_md, std::map< std::string, std::vector< std::string > > &con_string_md, std::map< std::string, std::vector< int > > &con_integer_md, std::map< std::string, std::vector< double > > &con_numeric_md) const
std::string inactive_lam_strategy_
Dict get_stats(void *mem) const override
Get all statistics.
void set_ipopt_prob(CodeGenerator &g) const
static const Options options_
Options.
Dict opts_
All IPOPT options.
static Nlpsol * creator(const std::string &name, const Function &nlp)
Create a new NLP Solver.
void codegen_body(CodeGenerator &g) const override
Generate code for the function body.
int init_mem(void *mem) const override
Initalize memory block.
int solve(void *mem) const override
void init(const Dict &opts) override
Initialize.
bool intermediate_callback(IpoptMemory *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_list_of_nonlinear_variables(int num_nonlin_vars, int *pos_nonlin_vars) const
std::vector< bool > nl_ex_
IpoptInterface(const std::string &name, const Function &nlp)
bool get_starting_point(IpoptMemory *m, bool init_x, double *x, bool init_z, double *z_L, double *z_U, bool init_lambda, double *lambda) const
NLP solver storage class.
Definition: nlpsol_impl.hpp:59
bool iteration_callback_ignore_errors_
Options.
Definition: nlpsol_impl.hpp:95
void codegen_body_exit(CodeGenerator &g) const override
Generate code for the function body.
Definition: nlpsol.cpp:1368
Dict get_stats(void *mem) const override
Get all statistics.
Definition: nlpsol.cpp:1251
static const Options options_
Options.
void codegen_body_enter(CodeGenerator &g) const override
Generate code for the function body.
Definition: nlpsol.cpp:1268
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
Definition: nlpsol.cpp:1348
void init(const Dict &opts) override
Initialize.
Definition: nlpsol.cpp:499
casadi_int ng_
Number of constraints.
Definition: nlpsol_impl.hpp:69
int init_mem(void *mem) const override
Initalize memory block.
Definition: nlpsol.cpp:692
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: nlpsol.cpp:1409
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:884
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 error_on_fail_
Throw an exception on failure?
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.
Definition: sparsity.cpp:124
casadi_int nnz() const
Get the number of (structural) non-zeros.
Definition: sparsity.cpp:148
casadi_int size2() const
Get the number of columns.
Definition: sparsity.cpp:128
bool is_triu(bool strictly=false) const
Is upper triangular?
Definition: sparsity.cpp:325
The casadi namespace.
Definition: archiver.cpp:28
@ NLPSOL_G
Constraints function at the optimal solution (ng x 1)
Definition: nlpsol.hpp:221
@ NLPSOL_X
Decision variables at the optimal solution (nx x 1)
Definition: nlpsol.hpp:217
@ NLPSOL_LAM_P
Lagrange multipliers for bounds on P at the solution (np x 1)
Definition: nlpsol.hpp:227
@ NLPSOL_F
Cost function value at the optimal solution (1 x 1)
Definition: nlpsol.hpp:219
@ NLPSOL_LAM_G
Lagrange multipliers for bounds on G at the solution (ng x 1)
Definition: nlpsol.hpp:225
@ NLPSOL_LAM_X
Lagrange multipliers for bounds on X at the solution (nx x 1)
Definition: nlpsol.hpp:223
std::ostream & uerr()
int CASADI_NLPSOL_IPOPT_EXPORT casadi_register_nlpsol_ipopt(Nlpsol::Plugin *plugin)
bool startswith(const std::string &s, const std::string &p)
Checks if s starts with p.
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
void CASADI_NLPSOL_IPOPT_EXPORT casadi_load_nlpsol_ipopt()
const char * return_status_string(Bonmin::TMINLP::SolverReturn status)
@ OT_BOOLVECTOR
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
std::ostream & uout()
@ SOLVER_RET_LIMITED
casadi_int sz_iw
Definition: mx.hpp:62
casadi_int sz_w
Definition: mx.hpp:63
IpoptMemory()
Constructor.
std::vector< double > regularization_size
std::vector< double > alpha_pr
const char * return_status
std::vector< double > obj
std::vector< double > inf_du
std::vector< double > d_norm
std::vector< double > inf_pr
std::vector< double > alpha_du
std::vector< int > ls_trials
std::vector< double > mu
casadi_nlpsol_data< double > d_nlp
Definition: nlpsol_impl.hpp:42
Options metadata for a class.
Definition: options.hpp:40
static Dict sanitize(const Dict &opts, bool top_level=true)
Sanitize a options dictionary.
Definition: options.cpp:173
std::map< std::string, FStats > fstats