nlpsol.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 #include "nlpsol_impl.hpp"
27 #include "conic_impl.hpp"
28 #include "external.hpp"
29 #include "casadi/core/timing.hpp"
30 #include "nlp_builder.hpp"
31 #include "nlp_tools.hpp"
32 #include <cctype>
33 
34 namespace casadi {
35 
36  bool has_nlpsol(const std::string& name) {
37  return Nlpsol::has_plugin(name);
38  }
39 
40  void load_nlpsol(const std::string& name) {
41  Nlpsol::load_plugin(name);
42  }
43 
44  std::string doc_nlpsol(const std::string& name) {
45  return Nlpsol::getPlugin(name).doc;
46  }
47 
48  bool name_has_g(const std::string& name) {
49  size_t pos = name.find("g");
50 
51  // 'g' does not occur
52  if (pos == std::string::npos) return false;
53 
54  // Check if 'g' has a word boundary on the left
55  bool left = pos==0 || !isalnum(name[pos-1]);
56 
57  // Check if 'g' has a word boundary on the right
58  bool right = pos+1 == name.size() || !isalnum(name[pos+1]);
59 
60  return left && right;
61  }
62 
63  template<class X>
64  Function construct_nlpsol(const std::string& name, const std::string& solver,
65  const std::map<std::string, X>& nlp, const Dict& opts) {
66 
67  if (get_from_dict(opts, "detect_simple_bounds", false)) {
68  X x = get_from_dict(nlp, "x", X(0, 1));
69  X p = get_from_dict(nlp, "p", X(0, 1));
70  X f = get_from_dict(nlp, "f", X(0));
71  X g = get_from_dict(nlp, "g", X(0, 1));
72 
73  if (g.size1()>0 || g.size2()>0) {
74  // Dimension checks
75  casadi_assert(g.is_dense() && g.is_vector(),
76  "Expected a dense vector 'g', but got " + g.dim(true) + ".");
77  }
78 
79  // Read dimensions
80  casadi_int ng = g.size1();
81  casadi_int nx = x.size1();
82 
83  // Get constraint Jacobian sparsity
84  Sparsity sp = jacobian_sparsity(g, x).T();
85 
86  // Reset result vector
87  std::vector<bool> is_simple(ng, true);
88 
89  // Check nonlinearity
90  std::vector<bool> is_nonlin = which_depends(g, x, 2, true);
91 
92  const casadi_int* row = sp.colind();
93  for (casadi_int i=0;i<ng;++i) {
94  // Check if each row of jac_g_x only depends on one column
95  bool single_dependency = row[i+1]-row[i]==1;
96  is_simple[i] = single_dependency && !is_nonlin[i];
97  }
98 
99  // Full-indices of all simple constraints
100  std::vector<casadi_int> sgi = boolvec_to_index(is_simple);
101  std::vector<casadi_int> gi = boolvec_to_index(boolvec_not(is_simple));
102  X g_bounds = g(sgi);
103 
104  // Detect f2(p)x+f1(p)==0
105  Function gf = Function("gf", std::vector<X>{x, p},
106  std::vector<X>{jtimes(g_bounds, x, X::ones(nx, 1)), g_bounds});
107  casadi_assert_dev(!gf.has_free());
108 
109  std::vector<casadi_int> target_x;
110  // Loop over all constraints
111  for (casadi_int i=0;i<ng;++i) {
112  // Only treat simple ones
113  if (!is_simple[i]) continue;
114  target_x.push_back(sp.row()[row[i]]);
115  }
116 
117  Dict nlpsol_opts = opts;
118  nlpsol_opts["detect_simple_bounds_is_simple"] = is_simple;
119  nlpsol_opts["detect_simple_bounds_parts"] = gf;
120  nlpsol_opts["detect_simple_bounds_target_x"] = target_x;
121 
122  // Check for cache entries
123  Dict cache = get_from_dict(opts, "cache", Dict());
124  for (auto&& e : cache) {
125  const Function& f = e.second;
126 
127  // Check for cached Functions where g appears in in/out
128  bool needs_update = false;
129  for (casadi_int i=0;i<f.n_in();++i) {
130  // Does name contain 'g'?
131  if (name_has_g(f.name_in(i))) {
132  // Already has compated size
133  if (f.size1_in(i)==gi.size()) continue;
134  // Needs to be compacted
135  if (f.size1_in(i)==ng) needs_update = true;
136  // Structure not understood, fallback to higher-level sanity checking
137  }
138  }
139  for (casadi_int i=0;i<f.n_out();++i) {
140  if (name_has_g(f.name_out(i))) {
141  if (f.size1_out(i)==gi.size()) continue;
142  // Needs to be compacted
143  if (f.size1_out(i)==ng) needs_update = true;
144  // Structure not understood, fallback to higher-level sanity checking
145  }
146  }
147 
148  if (!needs_update) continue;
149 
150  // Arguments to create a wrapper
151  std::vector<X> args = f.sym_in<X>();
152  // Arguments to pass to the cached function
153  std::vector<X> f_args = args;
154 
155  for (casadi_int i=0;i<f.n_in();++i) {
156  if (name_has_g(f.name_in(i))) {
157  // Needs a compacted symbol
158  args[i] = X::sym(f.name_in(i), gi.size());
159 
160  // Perform projects
161  f_args[i] = X::zeros(ng);
162  f_args[i](gi) = args[i];
163  }
164  }
165 
166  // Peform call
167  std::vector<X> res;
168  f.call(f_args, res, false, false);
169 
170  for (casadi_int i=0;i<f.n_out();++i) {
171  if (name_has_g(f.name_out(i))) {
172  // Select compacted rows out of result
173  res[i] = res[i](gi, casadi::Slice());
174  }
175  }
176 
177  // Create wrapper
178  cache[e.first] = Function(f.name(), args, res, f.name_in(), f.name_out());
179  }
180  // Pass along potentially updated cache
181  nlpsol_opts["cache"] = cache;
182 
183  if (opts.find("equality")!=opts.end()) {
184  std::vector<bool> equality = opts.find("equality")->second;
185  nlpsol_opts["equality"] = vector_select(equality, is_simple, true);
186  }
187 
188  std::map<std::string, X> nlpsol_nlp = nlp;
189  nlpsol_nlp["g"] = g(gi);
190  return nlpsol(name, solver, Nlpsol::create_oracle(nlpsol_nlp, opts), nlpsol_opts);
191  } else {
192  return nlpsol(name, solver, Nlpsol::create_oracle(nlp, opts), opts);
193  }
194  }
195 
196  Function nlpsol(const std::string& name, const std::string& solver,
197  const SXDict& nlp, const Dict& opts) {
198  return construct_nlpsol(name, solver, nlp, opts);
199  }
200 
201  Function nlpsol(const std::string& name, const std::string& solver,
202  const MXDict& nlp, const Dict& opts) {
203  return construct_nlpsol(name, solver, nlp, opts);
204  }
205 
206  template<typename XType>
207  Function Nlpsol::create_oracle(const std::map<std::string, XType>& d,
208  const Dict& opts) {
209  std::vector<XType> nl_in(NL_NUM_IN), nl_out(NL_NUM_OUT);
210  for (auto&& i : d) {
211  if (i.first=="x") {
212  nl_in[NL_X]=i.second;
213  } else if (i.first=="p") {
214  nl_in[NL_P]=i.second;
215  } else if (i.first=="f") {
216  nl_out[NL_F]=i.second;
217  } else if (i.first=="g") {
218  nl_out[NL_G]=i.second;
219  } else {
220  casadi_error("No such field: " + i.first);
221  }
222  }
223  if (nl_out[NL_F].is_empty()) nl_out[NL_F] = 0;
224  if (nl_out[NL_G].is_empty()) nl_out[NL_G] = XType(0, 1);
225 
226  // Options for the oracle
227  Dict oracle_options;
228  Dict::const_iterator it = opts.find("oracle_options");
229  if (it != opts.end()) {
230  // "oracle_options" has been set
231  oracle_options = it->second;
232  } else {
233  // Propagate selected options from Nlpsol to oracle by default
234  for (const char* op : {"verbose", "regularity_check"}) {
235  it = opts.find(op);
236  if (it != opts.end()) {
237  oracle_options[op] = it->second;
238  }
239  }
240  }
241 
242  // Create oracle
243  return Function("nlp", nl_in, nl_out, NL_INPUTS, NL_OUTPUTS, oracle_options);
244  }
245 
246  Function nlpsol(const std::string& name, const std::string& solver,
247  const NlpBuilder& nl, const Dict& opts) {
248  MXDict nlp;
249  nlp["x"] = vertcat(nl.x);
250  nlp["f"] = nl.f;
251  nlp["g"] = vertcat(nl.g);
252  return nlpsol(name, solver, nlp, opts);
253  }
254 
255  Function nlpsol(const std::string& name, const std::string& solver,
256  const std::string& fname, const Dict& opts) {
257  // If fname ends with .c, JIT
258  if (fname.size()>2 && fname.compare(fname.size()-2, fname.size(), ".c")==0) {
259  Importer compiler(fname, "clang");
260  return nlpsol(name, solver, compiler, opts);
261  } else {
262  return nlpsol(name, solver, external("nlp", fname), opts);
263  }
264  }
265 
266  Function nlpsol(const std::string& name, const std::string& solver,
267  const Importer& compiler, const Dict& opts) {
268  return nlpsol(name, solver, external("nlp", compiler), opts);
269  }
270 
271  Function nlpsol(const std::string& name, const std::string& solver,
272  const Function& nlp, const Dict& opts) {
273  // Make sure that nlp is sound
274  casadi_assert(nlp.name_in()==std::vector<std::string>({"x", "p"})
275  && nlp.name_out()==std::vector<std::string>({"f", "g"}),
276  "Cannot create '" + name + "': the NLP function must have inputs (x, p) and outputs "
277  "(f, g), got " + str(nlp.name_in()) + " and " + str(nlp.name_out()) + ".");
278  if (nlp.has_free()) {
279  casadi_error("Cannot create '" + name + "' since " + str(nlp.get_free()) + " are free.");
280  }
281  return Function::create(Nlpsol::instantiate(name, solver, nlp), opts);
282  }
283 
284  std::vector<std::string> nlpsol_in() {
285  std::vector<std::string> ret(nlpsol_n_in());
286  for (size_t i=0; i<ret.size(); ++i) ret[i]=nlpsol_in(i);
287  return ret;
288  }
289 
290  std::vector<std::string> nlpsol_out() {
291  std::vector<std::string> ret(nlpsol_n_out());
292  for (size_t i=0; i<ret.size(); ++i) ret[i]=nlpsol_out(i);
293  return ret;
294  }
295 
296  double nlpsol_default_in(casadi_int ind) {
297  switch (ind) {
298  case NLPSOL_LBX:
299  case NLPSOL_LBG:
300  return -std::numeric_limits<double>::infinity();
301  case NLPSOL_UBX:
302  case NLPSOL_UBG:
303  return std::numeric_limits<double>::infinity();
304  default:
305  return 0;
306  }
307  }
308 
309  std::vector<double> nlpsol_default_in() {
310  std::vector<double> ret(nlpsol_n_in());
311  for (size_t i=0; i<ret.size(); ++i) ret[i]=nlpsol_default_in(i);
312  return ret;
313  }
314 
315  std::string nlpsol_in(casadi_int ind) {
316  switch (static_cast<NlpsolInput>(ind)) {
317  case NLPSOL_X0: return "x0";
318  case NLPSOL_P: return "p";
319  case NLPSOL_LBX: return "lbx";
320  case NLPSOL_UBX: return "ubx";
321  case NLPSOL_LBG: return "lbg";
322  case NLPSOL_UBG: return "ubg";
323  case NLPSOL_LAM_X0: return "lam_x0";
324  case NLPSOL_LAM_G0: return "lam_g0";
325  case NLPSOL_NUM_IN: break;
326  }
327  return std::string();
328  }
329 
330  std::string nlpsol_out(casadi_int ind) {
331  switch (static_cast<NlpsolOutput>(ind)) {
332  case NLPSOL_X: return "x";
333  case NLPSOL_F: return "f";
334  case NLPSOL_G: return "g";
335  case NLPSOL_LAM_X: return "lam_x";
336  case NLPSOL_LAM_G: return "lam_g";
337  case NLPSOL_LAM_P: return "lam_p";
338  case NLPSOL_NUM_OUT: break;
339  }
340  return std::string();
341  }
342 
343  casadi_int nlpsol_n_in() {
344  return NLPSOL_NUM_IN;
345  }
346 
347  casadi_int nlpsol_n_out() {
348  return NLPSOL_NUM_OUT;
349  }
350 
351  Nlpsol::Nlpsol(const std::string& name, const Function& oracle)
352  : OracleFunction(name, oracle) {
353 
354  // Set default options
355  callback_step_ = 1;
356  eval_errors_fatal_ = false;
357  warn_initial_bounds_ = false;
359  print_time_ = true;
360  calc_multipliers_ = false;
361  bound_consistency_ = false;
362  min_lam_ = 0;
363  sens_force_equality_ = false;
364  calc_lam_x_ = calc_f_ = calc_g_ = false;
365  calc_lam_p_ = true;
366  no_nlp_grad_ = false;
367  error_on_fail_ = false;
368  sens_linsol_ = "qr";
369  }
370 
372  clear_mem();
373  }
374 
375  bool Nlpsol::is_a(const std::string& type, bool recursive) const {
376  return type=="Nlpsol" || (recursive && OracleFunction::is_a(type, recursive));
377  }
378 
380  switch (static_cast<NlpsolInput>(i)) {
381  case NLPSOL_X0:
382  case NLPSOL_LBX:
383  case NLPSOL_UBX:
384  case NLPSOL_LAM_X0:
385  return get_sparsity_out(NLPSOL_X);
386  case NLPSOL_LBG:
387  case NLPSOL_UBG:
388  case NLPSOL_LAM_G0:
389  return get_sparsity_out(NLPSOL_G);
390  case NLPSOL_P:
391  return oracle_.sparsity_in(NL_P);
392  case NLPSOL_NUM_IN: break;
393  }
394  return Sparsity();
395  }
396 
398  switch (static_cast<NlpsolOutput>(i)) {
399  case NLPSOL_F:
400  return oracle_.sparsity_out(NL_F);
401  case NLPSOL_X:
402  case NLPSOL_LAM_X:
403  return oracle_.sparsity_in(NL_X);
404  case NLPSOL_LAM_G:
405  case NLPSOL_G:
406  if (detect_simple_bounds_is_simple_.empty()) {
407  return oracle_.sparsity_out(NL_G);
408  } else {
410  }
411  case NLPSOL_LAM_P:
412  return get_sparsity_in(NLPSOL_P);
413  case NLPSOL_NUM_OUT: break;
414  }
415  return Sparsity();
416  }
417 
420  {{"iteration_callback",
421  {OT_FUNCTION,
422  "A function that will be called at each iteration with the solver as input. "
423  "Check documentation of Callback."}},
424  {"iteration_callback_step",
425  {OT_INT,
426  "Only call the callback function every few iterations."}},
427  {"iteration_callback_ignore_errors",
428  {OT_BOOL,
429  "If set to true, errors thrown by iteration_callback will be ignored."}},
430  {"ignore_check_vec",
431  {OT_BOOL,
432  "If set to true, the input shape of F will not be checked."}},
433  {"warn_initial_bounds",
434  {OT_BOOL,
435  "Warn if the initial guess does not satisfy LBX and UBX"}},
436  {"eval_errors_fatal",
437  {OT_BOOL,
438  "When errors occur during evaluation of f,g,...,"
439  "stop the iterations"}},
440  {"verbose_init",
441  {OT_BOOL,
442  "Print out timing information about "
443  "the different stages of initialization"}},
444  {"discrete",
445  {OT_BOOLVECTOR,
446  "Indicates which of the variables are discrete, i.e. integer-valued"}},
447  {"equality",
448  {OT_BOOLVECTOR,
449  "Indicate an upfront hint which of the constraints are equalities. "
450  "Some solvers may be able to exploit this knowledge. "
451  "When true, the corresponding lower and upper bounds are assumed equal. "
452  "When false, the corresponding bounds may be equal or different."}},
453  {"calc_multipliers",
454  {OT_BOOL,
455  "Calculate Lagrange multipliers in the Nlpsol base class"}},
456  {"calc_lam_x",
457  {OT_BOOL,
458  "Calculate 'lam_x' in the Nlpsol base class"}},
459  {"calc_lam_p",
460  {OT_BOOL,
461  "Calculate 'lam_p' in the Nlpsol base class"}},
462  {"calc_f",
463  {OT_BOOL,
464  "Calculate 'f' in the Nlpsol base class"}},
465  {"calc_g",
466  {OT_BOOL,
467  "Calculate 'g' in the Nlpsol base class"}},
468  {"no_nlp_grad",
469  {OT_BOOL,
470  "Prevent the creation of the 'nlp_grad' function"}},
471  {"bound_consistency",
472  {OT_BOOL,
473  "Ensure that primal-dual solution is consistent with the bounds"}},
474  {"min_lam",
475  {OT_DOUBLE,
476  "Minimum allowed multiplier value"}},
477  {"oracle_options",
478  {OT_DICT,
479  "Options to be passed to the oracle function"}},
480  {"sens_linsol",
481  {OT_STRING,
482  "Linear solver used for parametric sensitivities (default 'qr')."}},
483  {"sens_linsol_options",
484  {OT_DICT,
485  "Linear solver options used for parametric sensitivities."}},
486  {"sens_force_equality",
487  {OT_BOOL,
488  "Treat constraints with equal bounds as active in parametric sensitivities, "
489  "regardless of the multiplier, see issue #2545 [false]."}},
490  {"detect_simple_bounds",
491  {OT_BOOL,
492  "Automatically detect simple bounds (lbx/ubx) (default false). "
493  "This is hopefully beneficial to speed and robustness but may also have adverse affects: "
494  "1) Subtleties in heuristics and stopping criteria may change the solution, "
495  "2) IPOPT may lie about multipliers of simple equality bounds unless "
496  "'fixed_variable_treatment' is set to 'relax_bounds'."}},
497  {"detect_simple_bounds_is_simple",
498  {OT_BOOLVECTOR,
499  "For internal use only."}},
500  {"detect_simple_bounds_parts",
501  {OT_FUNCTION,
502  "For internal use only."}},
503  {"detect_simple_bounds_target_x",
504  {OT_INTVECTOR,
505  "For internal use only."}}
506  }
507  };
508 
509  void Nlpsol::init(const Dict& opts) {
510  // Default options
511  bool expand = false;
512 
513  // Read options
514  for (auto&& op : opts) {
515  if (op.first=="expand") {
516  expand = op.second;
517  } else if (op.first=="detect_simple_bounds_is_simple") {
518  assign_vector(op.second.to_bool_vector(), detect_simple_bounds_is_simple_);
519  //detect_simple_bounds_is_simple_ = op.second.to_bool_vector();
520  } else if (op.first=="detect_simple_bounds_parts") {
521  detect_simple_bounds_parts_ = op.second;
522  } else if (op.first=="detect_simple_bounds_target_x") {
523  detect_simple_bounds_target_x_ = op.second;
524  }
525  }
526 
527  for (casadi_int i=0;i<detect_simple_bounds_is_simple_.size();++i) {
529  detect_simple_bounds_target_g_.push_back(i);
530  }
531  }
532 
533  // Not covered by oracle expansion
536  }
537 
538  // Call the initialization method of the base class
539  OracleFunction::init(opts);
540 
541  // Read options
542  for (auto&& op : opts) {
543  if (op.first=="iteration_callback") {
544  fcallback_ = op.second;
545  } else if (op.first=="iteration_callback_step") {
546  callback_step_ = op.second;
547  } else if (op.first=="eval_errors_fatal") {
548  eval_errors_fatal_ = op.second;
549  } else if (op.first=="warn_initial_bounds") {
550  warn_initial_bounds_ = op.second;
551  } else if (op.first=="iteration_callback_ignore_errors") {
553  } else if (op.first=="discrete") {
554  discrete_ = op.second;
555  } else if (op.first=="equality") {
556  equality_ = op.second;
557  } else if (op.first=="calc_multipliers") {
558  calc_multipliers_ = op.second;
559  } else if (op.first=="calc_lam_x") {
560  calc_lam_x_ = op.second;
561  } else if (op.first=="calc_lam_p") {
562  calc_lam_p_ = op.second;
563  } else if (op.first=="calc_f") {
564  calc_f_ = op.second;
565  } else if (op.first=="calc_g") {
566  calc_g_ = op.second;
567  } else if (op.first=="no_nlp_grad") {
568  no_nlp_grad_ = op.second;
569  } else if (op.first=="bound_consistency") {
570  bound_consistency_ = op.second;
571  } else if (op.first=="min_lam") {
572  min_lam_ = op.second;
573  } else if (op.first=="sens_linsol") {
574  sens_linsol_ = op.second.to_string();
575  } else if (op.first=="sens_linsol_options") {
576  sens_linsol_options_ = op.second;
577  } else if (op.first=="sens_force_equality") {
578  sens_force_equality_ = op.second;
579  }
580  }
581 
582  // Deprecated option
583  if (calc_multipliers_) {
584  calc_lam_x_ = true;
585  calc_lam_p_ = true;
586  }
587 
588  // Get dimensions
589  nx_ = nnz_out(NLPSOL_X);
590  np_ = nnz_in(NLPSOL_P);
592 
593  // No need to calculate non-existant quantities
594  if (np_==0) calc_lam_p_ = false;
595  if (ng_==0) calc_g_ = false;
596 
597  // Consistency check
598  if (no_nlp_grad_) {
599  casadi_assert(!calc_lam_p_, "Options 'no_nlp_grad' and 'calc_lam_p' inconsistent");
600  casadi_assert(!calc_lam_x_, "Options 'no_nlp_grad' and 'calc_lam_x' inconsistent");
601  casadi_assert(!calc_f_, "Options 'no_nlp_grad' and 'calc_f' inconsistent");
602  casadi_assert(!calc_g_, "Options 'no_nlp_grad' and 'calc_g' inconsistent");
603  }
604 
605  // Dimension checks
606  casadi_assert(sparsity_out_.at(NLPSOL_G).is_dense()
607  && sparsity_out_.at(NLPSOL_G).is_vector(),
608  "Expected a dense vector 'g', but got " + sparsity_out_.at(NLPSOL_G).dim(true) + ".");
609 
610  casadi_assert(sparsity_out_.at(NLPSOL_F).is_dense(),
611  "Expected a dense 'f', but got " + sparsity_out_.at(NLPSOL_F).dim(true) + ".");
612 
613  casadi_assert(sparsity_out_.at(NLPSOL_X).is_dense()
614  && sparsity_out_.at(NLPSOL_X).is_vector(),
615  "Expected a dense vector 'x', but got " + sparsity_out_.at(NLPSOL_X).dim(true) + ".");
616 
617  // Discrete marker
618  mi_ = false;
619  if (!discrete_.empty()) {
620  casadi_assert(discrete_.size()==nx_, "\"discrete\" option has wrong length");
621  if (std::find(discrete_.begin(), discrete_.end(), true)!=discrete_.end()) {
622  casadi_assert(integer_support(),
623  "Discrete variables require a solver with integer support");
624  mi_ = true;
625  }
626  }
627  if (!equality_.empty()) {
628  casadi_assert(equality_.size()==ng_, "\"equality\" option has wrong length. "
629  "Expected " + str(ng_) + " elements, but got " +
630  str(equality_.size()) + " instead.");
631  }
632 
633  set_nlpsol_prob();
634 
635  // Allocate memory
636  casadi_int sz_arg, sz_res, sz_w, sz_iw;
637  casadi_nlpsol_work(&p_nlp_, &sz_arg, &sz_res, &sz_iw, &sz_w);
638  alloc_arg(sz_arg, true);
639  alloc_res(sz_res, true);
640  alloc_iw(sz_iw, true);
641  alloc_w(sz_w, true);
642 
643  if (!fcallback_.is_null()) {
644  // Consistency checks
645  casadi_assert_dev(!fcallback_.is_null());
646  casadi_assert(fcallback_.n_out()==1 && fcallback_.numel_out()==1,
647  "Callback function must return a scalar.");
648  casadi_assert(fcallback_.n_in()==n_out_,
649  "Callback input signature must match the NLP solver output signature");
650  for (casadi_int i=0; i<n_out_; ++i) {
651  // Ignore empty arguments
652  if (fcallback_.sparsity_in(i).is_empty()) continue;
653  casadi_assert(fcallback_.size_in(i)==size_out(i),
654  "Callback function input size mismatch. For argument '" + nlpsol_out(i) + "', "
655  "callback has shape " + fcallback_.sparsity_in(i).dim() + " while NLP has " +
656  sparsity_out_.at(i).dim() + ".");
657  // TODO(@jaeandersson): Wrap fcallback_ in a function with correct sparsity
658  casadi_assert(fcallback_.sparsity_in(i)==sparsity_out_.at(i),
659  "Callback function input size mismatch. "
660  "For argument " + nlpsol_out(i) + "', callback has shape " +
661  fcallback_.sparsity_in(i).dim() + " while NLP has " +
662  sparsity_out_.at(i).dim() + ".");
663  }
664 
665  // Allocate temporary memory
666  alloc(fcallback_);
667  }
668 
669  // Function calculating f, g and the gradient of the Lagrangian w.r.t. x and p
670  if (!no_nlp_grad_) {
671  create_function("nlp_grad", {"x", "p", "lam:f", "lam:g"},
672  {"f", "g", "grad:gamma:x", "grad:gamma:p"},
673  {{"gamma", {"f", "g"}}});
674  }
675  }
676 
677  int detect_bounds_callback(const double** arg, double** res,
678  casadi_int* iw, double* w, void* callback_data) {
679  Function* f = static_cast<Function*>(callback_data);
680  return f->operator()(arg, res, iw, w);
681  }
682 
683  void Nlpsol::set_nlpsol_prob() {
684  p_nlp_.nx = nx_;
685  p_nlp_.ng = ng_;
686  p_nlp_.np = np_;
687 
691 
692  if (p_nlp_.detect_bounds.ng) {
701  }
702  }
703 
704  int Nlpsol::init_mem(void* mem) const {
705  if (OracleFunction::init_mem(mem)) return 1;
706  auto *m = static_cast<NlpsolMemory*>(mem);
707  m->add_stat("callback_fun");
708  m->success = false;
709  m->d_nlp.prob = nullptr;
710  m->unified_return_status = SOLVER_RET_UNKNOWN;
711  return 0;
712  }
713 
714  void Nlpsol::check_inputs(void* mem) const {
715  auto *m = static_cast<NlpsolMemory*>(mem);
716  auto *d_nlp = &m->d_nlp;
717 
718  // Skip check?
719  if (!inputs_check_) return;
720 
721  const double inf = std::numeric_limits<double>::infinity();
722 
723  // Number of equality constraints
724  casadi_int n_eq = 0;
725 
726  // Detect ill-posed problems (simple bounds)
727  for (casadi_int i=0; i<nx_; ++i) {
728  double lb = d_nlp->lbx ? d_nlp->lbx[i] : get_default_in(NLPSOL_LBX);
729  double ub = d_nlp->ubx ? d_nlp->ubx[i] : get_default_in(NLPSOL_UBX);
730  double x0 = d_nlp->x0 ? d_nlp->x0[i] : get_default_in(NLPSOL_X0);
731  casadi_assert(lb <= ub && lb!=inf && ub!=-inf,
732  "Ill-posed problem detected: "
733  "LBX[" + str(i) + "] <= UBX[" + str(i) + "] was violated. "
734  "Got LBX[" + str(i) + "]=" + str(lb) + " and UBX[" + str(i) + "] = " + str(ub) + ".");
735  if (warn_initial_bounds_ && (x0>ub || x0<lb)) {
736  casadi_warning("Nlpsol: The initial guess does not satisfy LBX and UBX. "
737  "Option 'warn_initial_bounds' controls this warning.");
738  break;
739  }
740  if (lb==ub) n_eq++;
741  }
742 
743  // Detect ill-posed problems (nonlinear bounds)
744  for (casadi_int i=0; i<nnz_out(NLPSOL_G); ++i) {
745  double lb = d_nlp->lbg ? d_nlp->lbg[i] : get_default_in(NLPSOL_LBG);
746  double ub = d_nlp->ubg ? d_nlp->ubg[i] : get_default_in(NLPSOL_UBG);
747  casadi_assert(lb <= ub && lb!=inf && ub!=-inf,
748  "Ill-posed problem detected: "
749  "LBG[" + str(i) + "] <= UBG[" + str(i) + "] was violated. "
750  "Got LBG[" + str(i) + "] = " + str(lb) + " and UBG[" + str(i) + "] = " + str(ub) + ".");
751  if (lb==ub) n_eq++;
752  }
753 
754  // Make sure enough degrees of freedom
755  using casadi::str; // Workaround, MingGW bug, cf. CasADi issue #890
756  if (n_eq> nx_) {
757  casadi_warning("NLP is overconstrained: There are " + str(n_eq) +
758  " equality constraints but only " + str(nx_) + " variables.");
759  }
760  }
761 
762  std::map<std::string, Nlpsol::Plugin> Nlpsol::solvers_;
763 
764 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
765  std::mutex Nlpsol::mutex_solvers_;
766 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
767 
768  const std::string Nlpsol::infix_ = "nlpsol";
769 
771  casadi_error("getReducedHessian not defined for class " + class_name());
772  return DM();
773  }
774 
775  void Nlpsol::setOptionsFromFile(const std::string & file) {
776  casadi_error("setOptionsFromFile not defined for class " + class_name());
777  }
778 
779  void Nlpsol::bound_consistency(casadi_int n, double* z, double* lam,
780  const double* lbz, const double* ubz) {
781  casadi_assert_dev(z!=nullptr);
782  casadi_assert_dev(lam!=nullptr);
783  casadi_assert_dev(lbz!=nullptr);
784  casadi_assert_dev(ubz!=nullptr);
785  // Local variables
786  casadi_int i;
787  // Loop over variables
788  for (i=0; i<n; ++i) {
789  // Make sure bounds are respected
790  z[i] = std::fmin(std::fmax(z[i], lbz[i]), ubz[i]);
791  // Adjust multipliers
792  if (std::isinf(lbz[i]) && std::isinf(ubz[i])) {
793  // Both multipliers are infinite
794  lam[i] = 0.;
795  } else if (std::isinf(lbz[i]) || z[i] - lbz[i] > ubz[i] - z[i]) {
796  // Infinite lower bound or closer to upper bound than lower bound
797  lam[i] = std::fmax(0., lam[i]);
798  } else if (std::isinf(ubz[i]) || z[i] - lbz[i] < ubz[i] - z[i]) {
799  // Infinite upper bound or closer to lower bound than upper bound
800  lam[i] = std::fmin(0., lam[i]);
801  }
802  }
803  }
804 
805  int Nlpsol::eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
806  auto *m = static_cast<NlpsolMemory*>(mem);
807 
808  auto *d_nlp = &m->d_nlp;
809 
810  // Reset the solver, prepare for solution
811  setup(m, arg, res, iw, w);
812  const auto *p_nlp = d_nlp->prob;
813 
814  // Set initial guess
815  casadi_copy(d_nlp->x0, nx_, d_nlp->z);
816 
817  // Read simple bounds and multiplier guesses
818  casadi_copy(d_nlp->lbx, nx_, d_nlp->lbz);
819  casadi_copy(d_nlp->ubx, nx_, d_nlp->ubz);
820  casadi_copy(d_nlp->lam_x0, nx_, d_nlp->lam);
821 
822  if (p_nlp->detect_bounds.ng==0) {
823  // Read constraint bounds and multiplier guesses
824  casadi_copy(d_nlp->lbg, ng_, d_nlp->lbz+nx_);
825  casadi_copy(d_nlp->ubg, ng_, d_nlp->ubz+nx_);
826  casadi_copy(d_nlp->lam_g0, ng_, d_nlp->lam+nx_);
827  } else {
828  if (casadi_nlpsol_detect_bounds_before(d_nlp)) return 1;
829  }
830 
831  // Set multipliers to nan
832  casadi_fill(d_nlp->lam_p, np_, nan);
833 
834  // Reset f, g
835  d_nlp->objective = nan;
836  casadi_fill(d_nlp->z + nx_, ng_, nan);
837 
838  // Check the provided inputs
839  check_inputs(m);
840 
841  // Solve the NLP
842  int flag = solve(m);
843 
844  // Join statistics (introduced for parallel oracle facilities)
845  join_results(m);
846 
847  // Calculate multiplers
848  if ((calc_f_ || calc_g_ || calc_lam_x_ || calc_lam_p_) && !flag) {
849  const double lam_f = 1.;
850  m->arg[0] = d_nlp->z;
851  m->arg[1] = d_nlp->p;
852  m->arg[2] = &lam_f;
853  m->arg[3] = d_nlp->lam + nx_;
854  m->res[0] = calc_f_ ? &d_nlp->objective : nullptr;
855  m->res[1] = calc_g_ ? d_nlp->z + nx_ : nullptr;
856  m->res[2] = calc_lam_x_ ? d_nlp->lam : nullptr;
857  m->res[3] = calc_lam_p_ ? d_nlp->lam_p : nullptr;
858  if (calc_function(m, "nlp_grad")) {
859  casadi_warning("Failed to calculate multipliers");
860  }
861  if (calc_lam_x_) casadi_scal(nx_, -1., d_nlp->lam);
862  if (calc_lam_p_) casadi_scal(np_, -1., d_nlp->lam_p);
863  }
864 
865  // Make sure that an optimal solution is consistant with bounds
866  if (bound_consistency_ && !flag) {
867  bound_consistency(nx_+ng_, d_nlp->z, d_nlp->lam, d_nlp->lbz, d_nlp->ubz);
868  }
869 
870  // Get optimal solution
871  casadi_copy(d_nlp->z, nx_, d_nlp->x);
872 
873  if (p_nlp->detect_bounds.ng==0) {
874  casadi_copy(d_nlp->z + nx_, ng_, d_nlp->g);
875  casadi_copy(d_nlp->lam, nx_, d_nlp->lam_x);
876  casadi_copy(d_nlp->lam + nx_, ng_, d_nlp->lam_g);
877  } else {
878  if (casadi_nlpsol_detect_bounds_after(d_nlp)) return 1;
879  }
880 
881  casadi_copy(d_nlp->lam_p, np_, d_nlp->lam_p);
882  casadi_copy(&d_nlp->objective, 1, d_nlp->f);
883 
884  if (m->success) m->unified_return_status = SOLVER_RET_SUCCESS;
885 
886  if (error_on_fail_ && !m->success)
887  casadi_error("nlpsol process failed. "
888  "Set 'error_on_fail' option to false to ignore this error.");
889 
890  if (m->unified_return_status==SOLVER_RET_EXCEPTION) {
891  casadi_error("An exception was raised in the solver.");
892  }
893  return flag;
894  }
895 
896  void Nlpsol::set_work(void* mem, const double**& arg, double**& res,
897  casadi_int*& iw, double*& w) const {
898  auto *m = static_cast<NlpsolMemory*>(mem);
899 
900  // Problem has not been solved at this point
901  m->success = false;
902  m->unified_return_status = SOLVER_RET_UNKNOWN;
903 
904  m->d_nlp.prob = &p_nlp_;
905  m->d_nlp.oracle = &m->d_oracle;
906 
907  casadi_nlpsol_data<double>& d_nlp = m->d_nlp;
908  d_nlp.p = arg[NLPSOL_P];
909  d_nlp.lbx = arg[NLPSOL_LBX];
910  d_nlp.ubx = arg[NLPSOL_UBX];
911  d_nlp.lbg = arg[NLPSOL_LBG];
912  d_nlp.ubg = arg[NLPSOL_UBG];
913  d_nlp.x0 = arg[NLPSOL_X0];
914  d_nlp.lam_x0 = arg[NLPSOL_LAM_X0];
915  d_nlp.lam_g0 = arg[NLPSOL_LAM_G0];
916 
917  d_nlp.x = res[NLPSOL_X];
918  d_nlp.f = res[NLPSOL_F];
919  d_nlp.g = res[NLPSOL_G];
920  d_nlp.lam_x = res[NLPSOL_LAM_X];
921  d_nlp.lam_g = res[NLPSOL_LAM_G];
922  d_nlp.lam_p = res[NLPSOL_LAM_P];
923 
924 
925  arg += NLPSOL_NUM_IN;
926  res += NLPSOL_NUM_OUT;
927 
928  casadi_nlpsol_set_work(&m->d_nlp, &arg, &res, &iw, &w);
929  }
930 
931  std::vector<std::string> nlpsol_options(const std::string& name) {
932  return Nlpsol::plugin_options(name).all();
933  }
934 
935  std::string nlpsol_option_type(const std::string& name, const std::string& op) {
936  return Nlpsol::plugin_options(name).type(op);
937  }
938 
939  std::string nlpsol_option_info(const std::string& name, const std::string& op) {
940  return Nlpsol::plugin_options(name).info(op);
941  }
942 
943  void Nlpsol::disp_more(std::ostream& stream) const {
944  stream << "minimize f(x;p) subject to lbx<=x<=ubx, lbg<=g(x;p)<=ubg defined by:\n";
945  oracle_.disp(stream, true);
946  }
947 
949 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
950  // Safe access to kkt_
951  std::lock_guard<std::mutex> lock(kkt_mtx_);
952 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
953  // Quick return if cached
954  SharedObject temp;
955  if (kkt_.shared_if_alive(temp)) {
956  return shared_cast<Function>(temp);
957  }
958 
959  // Generate KKT function
960  Function ret = oracle_.factory("kkt", {"x", "p", "lam:f", "lam:g"},
961  {"jac:g:x", "hess:gamma:x:x"}, {{"gamma", {"f", "g"}}});
962 
963  // Cache and return
964  kkt_ = ret;
965  return ret;
966  }
967 
968 
970  get_forward(casadi_int nfwd, const std::string& name,
971  const std::vector<std::string>& inames,
972  const std::vector<std::string>& onames,
973  const Dict& opts) const {
974  casadi_assert(detect_simple_bounds_is_simple_.empty(),
975  "Simple bound detection not compatible with get_forward");
976 
977  // Symbolic expression for the input
978  std::vector<MX> arg = mx_in(), res = mx_out();
979 
980  // Initial guesses not used for derivative calculations
982  std::string name = arg[i].is_symbolic() ? arg[i].name() : "tmp_get_forward";
983  arg[i] = MX::sym(name, Sparsity(arg[i].size()));
984  }
985 
986  // Optimal solution
987  MX x = res[NLPSOL_X];
988  MX lam_g = res[NLPSOL_LAM_G];
989  MX lam_x = res[NLPSOL_LAM_X];
990  MX lam_p = res[NLPSOL_LAM_P];
991  MX f = res[NLPSOL_F];
992  MX g = res[NLPSOL_G];
993 
994  // Inputs used
995  MX lbx = arg[NLPSOL_LBX];
996  MX ubx = arg[NLPSOL_UBX];
997  MX lbg = arg[NLPSOL_LBG];
998  MX ubg = arg[NLPSOL_UBG];
999  MX p = arg[NLPSOL_P];
1000 
1001  // Get KKT function
1002  Function kkt = this->kkt();
1003 
1004  // Hessian of the Lagrangian, Jacobian of the constraints
1005  std::vector<MX> HJ_res = kkt({x, p, 1, lam_g});
1006  MX JG = HJ_res.at(0);
1007  MX HL = HJ_res.at(1);
1008 
1009  // KKT matrix, active set given by the multiplier signs
1010  MX lbIx, ubIx, lbIg, ubIg;
1011  MX H = Conic::sens_kkt(HL, JG, lam_x, lam_g, lbx, ubx, lbg, ubg, min_lam_,
1012  sens_force_equality_, lbIx, ubIx, lbIg, ubIg);
1013  MX iIx = 1-ubIx-lbIx, bIg = ubIg+lbIg;
1014 
1015  // Sensitivity inputs
1016  std::vector<MX> fseed(NLPSOL_NUM_IN);
1017  MX fwd_lbx = fseed[NLPSOL_LBX] = MX::sym("fwd_lbx", repmat(x.sparsity(), 1, nfwd));
1018  MX fwd_ubx = fseed[NLPSOL_UBX] = MX::sym("fwd_ubx", repmat(x.sparsity(), 1, nfwd));
1019  MX fwd_lbg = fseed[NLPSOL_LBG] = MX::sym("fwd_lbg", repmat(g.sparsity(), 1, nfwd));
1020  MX fwd_ubg = fseed[NLPSOL_UBG] = MX::sym("fwd_ubg", repmat(g.sparsity(), 1, nfwd));
1021  MX fwd_p = fseed[NLPSOL_P] = MX::sym("fwd_p", repmat(p.sparsity(), 1, nfwd));
1022 
1023  // Guesses are unused
1025  fseed[i] = MX(repmat(Sparsity(arg[i].size()), 1, nfwd));
1026  }
1027 
1028  // nlp_grad has the signature
1029  // (x, p, lam_f, lam_g) -> (f, g, grad_x, grad_p)
1030  // with lam_f=1 and lam_g=lam_g, grad_x = -lam_x, grad_p=-lam_p
1031  Function nlp_grad = get_function("nlp_grad");
1032 
1033  // fwd_nlp_grad has the signature
1034  // (x, p, lam_f, lam_g, f, g, grad_x, grad_p,
1035  // fwd_x, fwd_p, fwd_lam_f, fwd_lam_g)
1036  // -> (fwd_f, fwd_g, fwd_grad_x, fwd_grad_p)
1037  Function fwd_nlp_grad = nlp_grad.forward(nfwd);
1038 
1039  // Calculate sensitivities from fwd_p
1040  std::vector<MX> vv = {x, p, 1, lam_g, f, g, -lam_x, -lam_p, 0., fwd_p, 0., 0.};
1041  vv = fwd_nlp_grad(vv);
1042  MX fwd_g_p = vv.at(1);
1043  MX fwd_gL_p = vv.at(2);
1044 
1045  // Propagate forward seeds
1046  MX fwd_alpha_x = (if_else(lbIx, fwd_lbx, 0) + if_else(ubIx, fwd_ubx, 0))
1047  - if_else(iIx, fwd_gL_p, 0);
1048  MX fwd_alpha_g = (if_else(ubIg, fwd_ubg, 0) + if_else(lbIg, fwd_lbg, 0))
1049  - if_else(bIg, fwd_g_p, 0);
1050  MX v = MX::vertcat({fwd_alpha_x, fwd_alpha_g});
1051 
1052  // Solve
1054 
1055  // Extract sensitivities in x, lam_x and lam_g
1056  std::vector<MX> v_split = vertsplit(v, {0, nx_, nx_+ng_});
1057  MX fwd_x = v_split.at(0);
1058  MX fwd_lam_g = v_split.at(1);
1059 
1060  // Calculate sensitivities in lam_x, lam_g
1061  vv = {x, p, 1, lam_g, f, g, -lam_x, -lam_p,
1062  fwd_x, fwd_p, 0, fwd_lam_g};
1063  vv = fwd_nlp_grad(vv);
1064  MX fwd_f = vv.at(0);
1065  MX fwd_g = vv.at(1);
1066  MX fwd_lam_x = -vv.at(2);
1067  MX fwd_lam_p = -vv.at(3);
1068 
1069  // Forward sensitivities
1070  std::vector<MX> fsens(NLPSOL_NUM_OUT);
1071  fsens[NLPSOL_X] = fwd_x;
1072  fsens[NLPSOL_F] = fwd_f;
1073  fsens[NLPSOL_G] = fwd_g;
1074  fsens[NLPSOL_LAM_X] = fwd_lam_x;
1075  fsens[NLPSOL_LAM_G] = fwd_lam_g;
1076  fsens[NLPSOL_LAM_P] = fwd_lam_p;
1077 
1078  // Gather return values
1079  arg.insert(arg.end(), res.begin(), res.end());
1080  arg.insert(arg.end(), fseed.begin(), fseed.end());
1081  res = fsens;
1082 
1083  Dict options = opts;
1084  options["allow_duplicate_io_names"] = true;
1085 
1086  return Function(name, arg, res, inames, onames, options);
1087  }
1088 
1090  get_reverse(casadi_int nadj, const std::string& name,
1091  const std::vector<std::string>& inames,
1092  const std::vector<std::string>& onames,
1093  const Dict& opts) const {
1094  casadi_assert(detect_simple_bounds_is_simple_.empty(),
1095  "Simple bound detection not compatible with get_reverse");
1096 
1097  // Symbolic expression for the input
1098  std::vector<MX> arg = mx_in(), res = mx_out();
1099 
1100  // Initial guesses not used for derivative calculations
1102  std::string name = arg[i].is_symbolic() ? arg[i].name() : "tmp_get_reverse";
1103  arg[i] = MX::sym(name, Sparsity(arg[i].size()));
1104  }
1105 
1106  // Optimal solution
1107  MX x = res[NLPSOL_X];
1108  MX lam_g = res[NLPSOL_LAM_G];
1109  MX lam_x = res[NLPSOL_LAM_X];
1110  MX lam_p = res[NLPSOL_LAM_P];
1111  MX f = res[NLPSOL_F];
1112  MX g = res[NLPSOL_G];
1113 
1114  // Inputs used
1115  MX lbx = arg[NLPSOL_LBX];
1116  MX ubx = arg[NLPSOL_UBX];
1117  MX lbg = arg[NLPSOL_LBG];
1118  MX ubg = arg[NLPSOL_UBG];
1119  MX p = arg[NLPSOL_P];
1120 
1121  // Get KKT function
1122  Function kkt = this->kkt();
1123 
1124  // Hessian of the Lagrangian, Jacobian of the constraints
1125  std::vector<MX> HJ_res = kkt({x, p, 1, lam_g});
1126  MX JG = HJ_res.at(0);
1127  MX HL = HJ_res.at(1);
1128 
1129  // KKT matrix, active set given by the multiplier signs
1130  MX lbIx, ubIx, lbIg, ubIg;
1131  MX H = Conic::sens_kkt(HL, JG, lam_x, lam_g, lbx, ubx, lbg, ubg, min_lam_,
1132  sens_force_equality_, lbIx, ubIx, lbIg, ubIg);
1133  MX iIx = 1-ubIx-lbIx, bIg = ubIg+lbIg;
1134 
1135  // Sensitivity inputs
1136  std::vector<MX> aseed(NLPSOL_NUM_OUT);
1137  MX adj_x = aseed[NLPSOL_X] = MX::sym("adj_x", repmat(x.sparsity(), 1, nadj));
1138  MX adj_lam_g = aseed[NLPSOL_LAM_G] = MX::sym("adj_lam_g", repmat(g.sparsity(), 1, nadj));
1139  MX adj_lam_x = aseed[NLPSOL_LAM_X] = MX::sym("adj_lam_x", repmat(x.sparsity(), 1, nadj));
1140  MX adj_lam_p = aseed[NLPSOL_LAM_P] = MX::sym("adj_lam_p", repmat(p.sparsity(), 1, nadj));
1141  MX adj_f = aseed[NLPSOL_F] = MX::sym("adj_f", Sparsity::dense(1, nadj));
1142  MX adj_g = aseed[NLPSOL_G] = MX::sym("adj_g", repmat(g.sparsity(), 1, nadj));
1143 
1144  // nlp_grad has the signature
1145  // (x, p, lam_f, lam_g) -> (f, g, grad_x, grad_p)
1146  // with lam_f=1 and lam_g=lam_g, grad_x = -lam_x, grad_p=-lam_p
1147  Function nlp_grad = get_function("nlp_grad");
1148 
1149  // rev_nlp_grad has the signature
1150  // (x, p, lam_f, lam_g, f, g, grad_x, grad_p,
1151  // adj_f, adj_g, adj_grad_x, adj_grad_p)
1152  // -> (adj_x, adj_p, adj_lam_f, adj_lam_g)
1153  Function rev_nlp_grad = nlp_grad.reverse(nadj);
1154 
1155  // Calculate sensitivities from f, g and lam_x
1156  std::vector<MX> vv = {x, p, 1, lam_g, f, g, -lam_x, -lam_p,
1157  adj_f, adj_g, -adj_lam_x, -adj_lam_p};
1158  vv = rev_nlp_grad(vv);
1159  MX adj_x0 = vv.at(0);
1160  MX adj_p0 = vv.at(1);
1161  MX adj_lam_g0 = vv.at(3);
1162 
1163  // Solve to get beta_x_bar, beta_g_bar
1164  MX v = MX::vertcat({adj_x + adj_x0, adj_lam_g + adj_lam_g0});
1166  std::vector<MX> v_split = vertsplit(v, {0, nx_, nx_+ng_});
1167  MX beta_x_bar = v_split.at(0);
1168  MX beta_g_bar = v_split.at(1);
1169 
1170  // Calculate sensitivities in p
1171  vv = {x, p, 1, lam_g, f, g, -lam_x, -lam_p,
1172  0, bIg*beta_g_bar, iIx*beta_x_bar, 0};
1173  vv = rev_nlp_grad(vv);
1174  MX adj_p = vv.at(1);
1175 
1176  // Reverse sensitivities
1177  std::vector<MX> asens(NLPSOL_NUM_IN);
1178  asens[NLPSOL_UBX] = if_else(ubIx, beta_x_bar, 0);
1179  asens[NLPSOL_LBX] = if_else(lbIx, beta_x_bar, 0);
1180  asens[NLPSOL_UBG] = if_else(ubIg, beta_g_bar, 0);
1181  asens[NLPSOL_LBG] = if_else(lbIg, beta_g_bar, 0);
1182  asens[NLPSOL_P] = adj_p0 - adj_p;
1183 
1184  // Guesses are unused
1186  asens[i] = MX(repmat(Sparsity(arg[i].size()), 1, nadj));
1187  }
1188 
1189  // Gather return values
1190  arg.insert(arg.end(), res.begin(), res.end());
1191  arg.insert(arg.end(), aseed.begin(), aseed.end());
1192  res = asens;
1193 
1194  Dict options = opts;
1195  options["allow_duplicate_io_names"] = true;
1196 
1197  return Function(name, arg, res, inames, onames, options);
1198  }
1199 
1201  // Quick return if no callback function
1202  if (fcallback_.is_null()) return 0;
1203  // Callback inputs
1204  std::fill_n(m->arg, fcallback_.n_in(), nullptr);
1205 
1206  auto *d_nlp = &m->d_nlp;
1207 
1208  m->arg[NLPSOL_X] = d_nlp->z;
1209  m->arg[NLPSOL_F] = &d_nlp->objective;
1210  m->arg[NLPSOL_G] = d_nlp->z + nx_;
1211  m->arg[NLPSOL_LAM_G] = d_nlp->lam + nx_;
1212  m->arg[NLPSOL_LAM_X] = d_nlp->lam;
1213 
1214  // Callback outputs
1215  std::fill_n(m->res, fcallback_.n_out(), nullptr);
1216  double ret = 0;
1217  m->res[0] = &ret;
1218 
1219  // Start timer
1220  m->fstats.at("callback_fun").tic();
1221  try {
1222  // Evaluate
1223  fcallback_(m->arg, m->res, m->iw, m->w, 0);
1224  } catch(KeyboardInterruptException& ex) {
1225  (void)ex; // unused
1226  throw;
1227  } catch(std::exception& ex) {
1228  print("WARNING: intermediate_callback error: %s\n", ex.what());
1230  }
1231 
1232  // User user interruption?
1233  if (static_cast<casadi_int>(ret)) return 1;
1234 
1235  // Stop timer
1236  m->fstats.at("callback_fun").toc();
1237 
1238  return 0;
1239  }
1240 
1241  Dict Nlpsol::get_stats(void* mem) const {
1242  Dict stats = OracleFunction::get_stats(mem);
1243  auto *m = static_cast<NlpsolMemory*>(mem);
1244  casadi_assert(m->d_nlp.prob,
1245  "No stats available: nlp Solver instance has not yet been called with numerical arguments.");
1246  auto *d_nlp = &m->d_nlp;
1247  stats["success"] = m->success;
1248  stats["unified_return_status"] = string_from_UnifiedReturnStatus(m->unified_return_status);
1249  if (d_nlp->prob && d_nlp->prob->detect_bounds.ng) {
1250  std::vector<bool> is_simple;
1252  stats["detect_simple_bounds_is_simple"] = is_simple;
1253  stats["detect_simple_bounds_target_x"] = detect_simple_bounds_target_x_;
1254  }
1255  return stats;
1256  }
1257 
1260  g.local("d_nlp", "struct casadi_nlpsol_data");
1261  g.local("p_nlp", "struct casadi_nlpsol_prob");
1262  codegen_setup_constants(g, "d_nlp", "p_nlp", "d_oracle");
1263  codegen_setup_per_call(g, "d_nlp");
1264  }
1265 
1266  // Per-Function-instance constants: nx/ng/np, detect_bounds descriptors, and
1267  // the prob/oracle pointer wiring that doesn't change between calls.
1268  // Plugins that own the storage (uno) call this from codegen_init_mem; the
1269  // default-name call from codegen_body_enter preserves the historical
1270  // emission order for plugins that don't opt in.
1272  const std::string& d_nlp, const std::string& p_nlp,
1273  const std::string& d_oracle) const {
1274  g << d_nlp << ".oracle = &" << d_oracle << ";\n";
1275  g << d_nlp << ".prob = &" << p_nlp << ";\n";
1276  g << p_nlp << ".nx = " << nx_ << ";\n";
1277  g << p_nlp << ".ng = " << ng_ << ";\n";
1278  g << p_nlp << ".np = " << np_ << ";\n";
1279  g << p_nlp << ".detect_bounds.ng = " << detect_simple_bounds_is_simple_.size() << ";\n";
1280  if (detect_simple_bounds_is_simple_.size()) {
1281  g << p_nlp << ".detect_bounds.sz_arg = " << detect_simple_bounds_parts_.sz_arg() << ";\n";
1282  g << p_nlp << ".detect_bounds.sz_res = " << detect_simple_bounds_parts_.sz_res() << ";\n";
1283  g << p_nlp << ".detect_bounds.sz_iw = " << detect_simple_bounds_parts_.sz_iw() << ";\n";
1284  g << p_nlp << ".detect_bounds.sz_w = " << detect_simple_bounds_parts_.sz_w() << ";\n";
1285 
1286  g << p_nlp << ".detect_bounds.nb = " << detect_simple_bounds_target_x_.size() << ";\n";
1287  g << p_nlp << ".detect_bounds.target_x = "
1289  g << p_nlp << ".detect_bounds.target_g = "
1291  g << p_nlp << ".detect_bounds.is_simple = "
1293  std::string w =
1294  g.shorthand(g.wrapper(detect_simple_bounds_parts_, "detect_simple_bounds_wrapper"));
1295  g << p_nlp << ".detect_bounds.callback = " << w << ";\n";
1296  g << p_nlp << ".detect_bounds.callback_data = 0;\n";
1297  }
1298  }
1299 
1300  // Per-call wiring: arg/res slot bindings, casadi_nlpsol_set_work's workspace
1301  // claim, and the copy_default's that populate z/lbz/ubz/lam from the
1302  // user inputs. Always runs every call.
1303  void Nlpsol::codegen_setup_per_call(CodeGenerator& g, const std::string& d_nlp) const {
1304  g << d_nlp << ".p = arg[" << NLPSOL_P << "];\n";
1305  g << d_nlp << ".lbx = arg[" << NLPSOL_LBX << "];\n";
1306  g << d_nlp << ".ubx = arg[" << NLPSOL_UBX << "];\n";
1307  g << d_nlp << ".lbg = arg[" << NLPSOL_LBG << "];\n";
1308  g << d_nlp << ".ubg = arg[" << NLPSOL_UBG << "];\n";
1309  g << d_nlp << ".x0 = arg[" << NLPSOL_X0 << "];\n";
1310  g << d_nlp << ".lam_x0 = arg[" << NLPSOL_LAM_X0 << "];\n";
1311  g << d_nlp << ".lam_g0 = arg[" << NLPSOL_LAM_G0 << "];\n";
1312  g << "arg += " << NLPSOL_NUM_IN << ";\n";
1313 
1314  g << d_nlp << ".x = res[" << NLPSOL_X << "];\n";
1315  g << d_nlp << ".f = res[" << NLPSOL_F << "];\n";
1316  g << d_nlp << ".g = res[" << NLPSOL_G << "];\n";
1317  g << d_nlp << ".lam_x = res[" << NLPSOL_LAM_X << "];\n";
1318  g << d_nlp << ".lam_g = res[" << NLPSOL_LAM_G << "];\n";
1319  g << d_nlp << ".lam_p = res[" << NLPSOL_LAM_P << "];\n";
1320  g << "res += " << NLPSOL_NUM_OUT << ";\n";
1321 
1322  g << "casadi_nlpsol_set_work(&" << d_nlp << ", &arg, &res, &iw, &w);\n";
1323 
1324  g.copy_default(d_nlp + ".x0", nx_, d_nlp + ".z", "0", false);
1325  g.copy_default(d_nlp + ".lbx", nx_, d_nlp + ".lbz", "-casadi_inf", false);
1326  g.copy_default(d_nlp + ".ubx", nx_, d_nlp + ".ubz", "casadi_inf", false);
1327  g.copy_default(d_nlp + ".lam_x0", nx_, d_nlp + ".lam", "0", false);
1328 
1329  if (detect_simple_bounds_is_simple_.empty()) {
1330  g.copy_default(d_nlp + ".lbg", ng_, d_nlp + ".lbz+" + str(nx_), "-casadi_inf", false);
1331  g.copy_default(d_nlp + ".ubg", ng_, d_nlp + ".ubz+" + str(nx_), "casadi_inf", false);
1332  g.copy_default(d_nlp + ".lam_g0", ng_, d_nlp + ".lam+" + str(nx_), "0", false);
1333  } else {
1334  g << "if (casadi_nlpsol_detect_bounds_before(&" << d_nlp << ")) return 1;\n";
1335  }
1336  }
1337 
1341  if (calc_f_ || calc_g_ || calc_lam_x_ || calc_lam_p_)
1342  g.add_dependency(get_function("nlp_grad"));
1343 
1344  if (detect_simple_bounds_is_simple_.size()) {
1346  std::string w =
1347  g.shorthand(g.wrapper(detect_simple_bounds_parts_, "detect_simple_bounds_wrapper"));
1348 
1349  g << "int " << w
1350  << "(const casadi_real** arg, casadi_real** res, "
1351  << "casadi_int* iw, casadi_real* w, void* callback_data) {\n";
1352  std::string flag = g(detect_simple_bounds_parts_, "arg", "res", "iw", "w");
1353  g << "return " + flag + ";\n";
1354  g << "}\n";
1355  }
1356  }
1357 
1359  codegen_post_solve(g, "d_nlp");
1361  }
1362 
1363  void Nlpsol::codegen_post_solve(CodeGenerator& g, const std::string& d_nlp) const {
1364  if (calc_f_ || calc_g_ || calc_lam_x_ || calc_lam_p_) {
1365  g.local("one", "const casadi_real");
1366  g.init_local("one", "1");
1367  g << "d->arg[0] = " << d_nlp << ".z;\n";
1368  g << "d->arg[1] = " << d_nlp << ".p;\n";
1369  g << "d->arg[2] = &one;\n";
1370  g << "d->arg[3] = " << d_nlp << ".lam+" << str(nx_) << ";\n";
1371  g << "d->res[0] = " << (calc_f_ ? "&" + d_nlp + ".objective" : "0") << ";\n";
1372  g << "d->res[1] = " << (calc_g_ ? d_nlp + ".z+" + str(nx_) : "0") << ";\n";
1373  g << "d->res[2] = " << (calc_lam_x_ ? d_nlp + ".lam+" + str(nx_) : "0") << ";\n";
1374  g << "d->res[3] = " << (calc_lam_p_ ? d_nlp + ".lam_p" : "0") << ";\n";
1375  std::string nlp_grad = g(get_function("nlp_grad"), "d->arg", "d->res", "d->iw", "d->w");
1376  g << "if (" << nlp_grad << ") return 1;\n";
1377  if (calc_lam_x_) g << g.scal(nx_, "-1.0", d_nlp + ".lam") << "\n";
1378  if (calc_lam_p_) g << g.scal(np_, "-1.0", d_nlp + ".lam_p") << "\n";
1379  }
1380  if (bound_consistency_) {
1381  g << g.bound_consistency(nx_+ng_, d_nlp + ".z", d_nlp + ".lam",
1382  d_nlp + ".lbz", d_nlp + ".ubz") << ";\n";
1383  }
1384 
1385  g << g.copy(d_nlp + ".z", nx_, d_nlp + ".x") << "\n";
1386 
1387  if (detect_simple_bounds_is_simple_.empty()) {
1388  g << g.copy(d_nlp + ".z + " + str(nx_), ng_, d_nlp + ".g") << "\n";
1389  g << g.copy(d_nlp + ".lam", nx_, d_nlp + ".lam_x") << "\n";
1390  g << g.copy(d_nlp + ".lam + " + str(nx_), ng_, d_nlp + ".lam_g") << "\n";
1391  } else {
1392  g << "if (casadi_nlpsol_detect_bounds_after(&" << d_nlp << ")) return 1;\n";
1393  }
1394 
1395  g.copy_check("&" + d_nlp + ".objective", 1, d_nlp + ".f", false, true);
1396  g.copy_check(d_nlp + ".lam_p", np_, d_nlp + ".lam_p", false, true);
1397  }
1398 
1401 
1402  s.version("Nlpsol", 6);
1403  s.pack("Nlpsol::nx", nx_);
1404  s.pack("Nlpsol::ng", ng_);
1405  s.pack("Nlpsol::np", np_);
1406  s.pack("Nlpsol::fcallback", fcallback_);
1407  s.pack("Nlpsol::callback_step", callback_step_);
1408  s.pack("Nlpsol::eval_errors_fatal", eval_errors_fatal_);
1409  s.pack("Nlpsol::warn_initial_bounds", warn_initial_bounds_);
1410  s.pack("Nlpsol::iteration_callback_ignore_errors", iteration_callback_ignore_errors_);
1411  s.pack("Nlpsol::calc_multipliers", calc_multipliers_);
1412  s.pack("Nlpsol::calc_lam_x", calc_lam_x_);
1413  s.pack("Nlpsol::calc_lam_p", calc_lam_p_);
1414  s.pack("Nlpsol::calc_f", calc_f_);
1415  s.pack("Nlpsol::calc_g", calc_g_);
1416  s.pack("Nlpsol::min_lam", min_lam_);
1417  s.pack("Nlpsol::bound_consistency", bound_consistency_);
1418  s.pack("Nlpsol::no_nlp_grad", no_nlp_grad_);
1419  s.pack("Nlpsol::discrete", discrete_);
1420  s.pack("Nlpsol::equality", equality_);
1421  s.pack("Nlpsol::mi", mi_);
1422  s.pack("Nlpsol::sens_linsol", sens_linsol_);
1423  s.pack("Nlpsol::sens_linsol_options", sens_linsol_options_);
1424  s.pack("Nlpsol::sens_force_equality", sens_force_equality_);
1425  s.pack("Nlpsol::detect_simple_bounds_is_simple", detect_simple_bounds_is_simple_);
1426  s.pack("Nlpsol::detect_simple_bounds_parts", detect_simple_bounds_parts_);
1427  s.pack("Nlpsol::detect_simple_bounds_target_x", detect_simple_bounds_target_x_);
1428  }
1429 
1433  }
1434 
1437  }
1438 
1440  int version = s.version("Nlpsol", 1, 6);
1441  s.unpack("Nlpsol::nx", nx_);
1442  s.unpack("Nlpsol::ng", ng_);
1443  s.unpack("Nlpsol::np", np_);
1444  s.unpack("Nlpsol::fcallback", fcallback_);
1445  s.unpack("Nlpsol::callback_step", callback_step_);
1446  if (version<=2) {
1447  s.unpack("Nlpsol::error_on_fail", error_on_fail_);
1448  }
1449  s.unpack("Nlpsol::eval_errors_fatal", eval_errors_fatal_);
1450  s.unpack("Nlpsol::warn_initial_bounds", warn_initial_bounds_);
1451  s.unpack("Nlpsol::iteration_callback_ignore_errors", iteration_callback_ignore_errors_);
1452  s.unpack("Nlpsol::calc_multipliers", calc_multipliers_);
1453  s.unpack("Nlpsol::calc_lam_x", calc_lam_x_);
1454  s.unpack("Nlpsol::calc_lam_p", calc_lam_p_);
1455  s.unpack("Nlpsol::calc_f", calc_f_);
1456  s.unpack("Nlpsol::calc_g", calc_g_);
1457  s.unpack("Nlpsol::min_lam", min_lam_);
1458  s.unpack("Nlpsol::bound_consistency", bound_consistency_);
1459  s.unpack("Nlpsol::no_nlp_grad", no_nlp_grad_);
1460  s.unpack("Nlpsol::discrete", discrete_);
1461  if (version>=4) {
1462  s.unpack("Nlpsol::equality", equality_);
1463  }
1464  s.unpack("Nlpsol::mi", mi_);
1465  if (version>=2) {
1466  s.unpack("Nlpsol::sens_linsol", sens_linsol_);
1467  s.unpack("Nlpsol::sens_linsol_options", sens_linsol_options_);
1468  } else {
1469  sens_linsol_ = "qr";
1470  }
1471  if (version>=6) {
1472  s.unpack("Nlpsol::sens_force_equality", sens_force_equality_);
1473  } else {
1474  sens_force_equality_ = false;
1475  }
1476 
1477  if (version>=3) {
1478  s.unpack("Nlpsol::detect_simple_bounds_is_simple", detect_simple_bounds_is_simple_);
1479  s.unpack("Nlpsol::detect_simple_bounds_parts", detect_simple_bounds_parts_);
1480  if (version==4) {
1481  casadi_error("Saved detect_simple_bounds_parts changed signature");
1482  }
1483  s.unpack("Nlpsol::detect_simple_bounds_target_x", detect_simple_bounds_target_x_);
1484  }
1485  for (casadi_int i=0;i<detect_simple_bounds_is_simple_.size();++i) {
1487  detect_simple_bounds_target_g_.push_back(i);
1488  }
1489  }
1490  set_nlpsol_prob();
1491  }
1492 
1493 } // 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)
std::string copy(const std::string &arg, std::size_t n, const std::string &res)
Create a copy operation.
std::string constant(const std::vector< casadi_int > &v)
Represent an array constant; adding it when new.
std::string scal(casadi_int n, const std::string &alpha, const std::string &x)
What does scal do??
std::string bound_consistency(casadi_int n, const std::string &x, const std::string &lam, const std::string &lbx, const std::string &ubx)
bound_consistency
void local(const std::string &name, const std::string &type, const std::string &ref="")
Declare a local variable.
void init_local(const std::string &name, const std::string &def)
Specify the default value for a local variable.
std::string shorthand(const std::string &name) const
Get a shorthand.
void copy_check(const std::string &arg, std::size_t n, const std::string &res, bool check_lhs=true, bool check_rhs=true)
void copy_default(const std::string &arg, std::size_t n, const std::string &res, const std::string &def, bool check_rhs=true)
void add_auxiliary(Auxiliary f, const std::vector< std::string > &inst={"casadi_real"})
Add a built-in auxiliary function.
static MX sens_kkt(const MX &H, const MX &A, const MX &lam_x, const MX &lam_a, const MX &lbx, const MX &ubx, const MX &lba, const MX &uba, double min_lam, bool force_equality, MX &lbIx, MX &ubIx, MX &lbIa, MX &ubIa)
Definition: conic.cpp:620
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.
void alloc_res(size_t sz_res, bool persistent=false)
Ensure required length of res field.
virtual const std::vector< MX > mx_in() const
Get function input(s) and output(s)
void alloc_arg(size_t sz_arg, bool persistent=false)
Ensure required length of arg field.
virtual bool is_a(const std::string &type, bool recursive) const
Check if the function is of a particular type.
bool inputs_check_
Errors are thrown if numerical values of inputs look bad.
size_t sz_res() const
Get required length of res field.
std::pair< casadi_int, casadi_int > size_out(casadi_int ind) const
Input/output dimensions.
casadi_int nnz_in() const
Number of input/output nonzeros.
std::vector< Sparsity > sparsity_out_
void serialize_type(SerializingStream &s) const override
Serialize type information.
size_t sz_w() const
Get required length of w field.
virtual const std::vector< MX > mx_out() const
Get function input(s) and output(s)
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
casadi_int nnz_out() const
Number of input/output nonzeros.
size_t sz_arg() const
Get required length of arg field.
void setup(void *mem, const double **arg, double **res, casadi_int *iw, double *w) const
Set the (persistent and temporary) work vectors.
void alloc(const Function &f, bool persistent=false, int num_threads=1)
Ensure work vectors long enough to evaluate function.
size_t sz_iw() const
Get required length of iw field.
static std::string string_from_UnifiedReturnStatus(UnifiedReturnStatus status)
Function object.
Definition: function.hpp:126
Function forward(casadi_int nfwd) const
Get a function computing nfwd forward directional derivatives.
Definition: function.cpp:1324
size_t sz_res() const
Get the length of the output pointer array needed to evaluate (at least.
Definition: function.cpp:1237
const Sparsity & sparsity_out(casadi_int ind) const
Get the sparsity pattern of an output, by index or name.
Definition: function.cpp:1183
casadi_int size1_in(casadi_int ind) const
Get the shape of an input: rows, columns or both.
Definition: function.cpp:979
Function expand() const
Convert an MXFunction into an equivalent SXFunction.
Definition: function.cpp:312
const std::vector< std::string > & name_in() const
Get the names of all inputs, in order.
Definition: function.cpp:1113
const std::string & name() const
Get the name given at construction ("null" for a null object)
Definition: function.cpp:1504
casadi_int numel_out() const
Get the number of elements (rows times columns) of one output, or of all.
Definition: function.cpp:1015
Function reverse(casadi_int nadj) const
Get a function computing nadj reverse (adjoint) directional derivatives.
Definition: function.cpp:1332
const T sym_in(casadi_int iind) const
Create fresh symbols with the names and sparsity patterns of the inputs.
static Function create(FunctionInternal *node)
Create from node.
Definition: function.cpp:488
const Sparsity & sparsity_in(casadi_int ind) const
Get the sparsity pattern of an input, by index or name.
Definition: function.cpp:1167
size_t sz_iw() const
Get the length of the integer work vector needed to evaluate.
Definition: function.cpp:1239
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
std::vector< std::string > get_free() const
Get the names of the free variables; empty when there are none.
Definition: function.cpp:1382
size_t sz_w() const
Get the length of the real work vector needed to evaluate.
Definition: function.cpp:1241
size_t sz_arg() const
Get the length of the input pointer array needed to evaluate (at least n_in)
Definition: function.cpp:1235
bool has_free() const
Check whether the outputs contain symbols that are not inputs.
Definition: function.cpp:1894
casadi_int size1_out(casadi_int ind) const
Get the shape of an output: rows, columns or both.
Definition: function.cpp:987
std::pair< casadi_int, casadi_int > size_in(casadi_int ind) const
Get the shape of an input: rows, columns or both.
Definition: function.cpp:995
void call(const std::vector< DM > &arg, std::vector< DM > &res, bool always_inline=false, bool never_inline=false) const
Evaluate with a list or a dict of arguments; the result has the same form.
Definition: function.cpp:509
Function factory(const std::string &name, const std::vector< std::string > &s_in, const std::vector< std::string > &s_out, const AuxOut &aux=AuxOut(), const Dict &opts=Dict()) const
Build a function computing derivatives by naming inputs and outputs.
Definition: function.cpp:2009
const std::vector< std::string > & name_out() const
Get the names of all outputs, in order.
Definition: function.cpp:1117
static MX sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
bool is_null() const
Is a null pointer?
bool shared_if_alive(Shared &shared) const
Thread-safe alternative to alive()/shared()
Importer.
Definition: importer.hpp:86
MX - Matrix expression.
Definition: mx.hpp:145
const Sparsity & sparsity() const
Get the sparsity pattern.
Definition: mx.cpp:615
MX T() const
Transpose the matrix.
Definition: mx.cpp:1098
static MX solve(const MX &a, const MX &b)
Definition: mx.cpp:2108
static MX vertcat(const std::vector< MX > &x)
Definition: mx.cpp:1168
A symbolic NLP representation.
Definition: nlp_builder.hpp:41
std::vector< MX > x
Variables.
Definition: nlp_builder.hpp:50
std::vector< MX > g
Constraints.
Definition: nlp_builder.hpp:56
MX f
Objective.
Definition: nlp_builder.hpp:53
void serialize_type(SerializingStream &s) const override
Serialize type information.
Definition: nlpsol.cpp:1430
Nlpsol(const std::string &name, const Function &oracle)
Constructor.
Definition: nlpsol.cpp:351
bool iteration_callback_ignore_errors_
Options.
Definition: nlpsol_impl.hpp:95
void codegen_post_solve(CodeGenerator &g, const std::string &d_nlp) const
Definition: nlpsol.cpp:1363
WeakRef kkt_
Cache for KKT function.
void codegen_body_exit(CodeGenerator &g) const override
Generate code for the function body.
Definition: nlpsol.cpp:1358
bool calc_lam_p_
Options.
Definition: nlpsol_impl.hpp:97
Sparsity get_sparsity_out(casadi_int i) override
Sparsities of function inputs and outputs.
Definition: nlpsol.cpp:397
virtual DM getReducedHessian()
Definition: nlpsol.cpp:770
Dict get_stats(void *mem) const override
Get all statistics.
Definition: nlpsol.cpp:1241
Function get_forward(casadi_int nfwd, const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const override
Generate a function that calculates forward mode derivatives.
Definition: nlpsol.cpp:970
static const Options options_
Options.
void codegen_body_enter(CodeGenerator &g) const override
Generate code for the function body.
Definition: nlpsol.cpp:1258
void codegen_declarations(CodeGenerator &g) const override
Generate code for the declarations of the C function.
Definition: nlpsol.cpp:1338
void init(const Dict &opts) override
Initialize.
Definition: nlpsol.cpp:509
casadi_int ng_
Number of constraints.
Definition: nlpsol_impl.hpp:69
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const final
Evaluate numerically.
Definition: nlpsol.cpp:805
Function kkt() const
Definition: nlpsol.cpp:948
virtual void check_inputs(void *mem) const
Check if the inputs correspond to a well-posed problem.
Definition: nlpsol.cpp:714
void codegen_setup_per_call(CodeGenerator &g, const std::string &d_nlp) const
Definition: nlpsol.cpp:1303
bool eval_errors_fatal_
Options.
Definition: nlpsol_impl.hpp:93
int init_mem(void *mem) const override
Initalize memory block.
Definition: nlpsol.cpp:704
void codegen_setup_constants(CodeGenerator &g, const std::string &d_nlp, const std::string &p_nlp, const std::string &d_oracle) const
Definition: nlpsol.cpp:1271
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
Definition: nlpsol.cpp:1435
Function detect_simple_bounds_parts_
Definition: nlpsol_impl.hpp:85
bool calc_multipliers_
Options.
Definition: nlpsol_impl.hpp:96
static void bound_consistency(casadi_int n, double *z, double *lam, const double *lbz, const double *ubz)
Definition: nlpsol.cpp:779
std::vector< bool > equality_
Options.
bool warn_initial_bounds_
Options.
Definition: nlpsol_impl.hpp:94
static const std::string infix_
Infix.
Dict sens_linsol_options_
Definition: nlpsol_impl.hpp:82
casadi_nlpsol_prob< double > p_nlp_
Definition: nlpsol_impl.hpp:63
void disp_more(std::ostream &stream) const override
Print description.
Definition: nlpsol.cpp:943
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: nlpsol.cpp:1399
static std::map< std::string, Plugin > solvers_
Collection of solvers.
bool calc_f_
Options.
Definition: nlpsol_impl.hpp:97
bool calc_g_
Options.
Definition: nlpsol_impl.hpp:97
Function get_reverse(casadi_int nadj, const std::string &name, const std::vector< std::string > &inames, const std::vector< std::string > &onames, const Dict &opts) const override
Generate a function that calculates reverse mode derivatives.
Definition: nlpsol.cpp:1090
std::string class_name() const override
Get type name.
std::vector< char > detect_simple_bounds_is_simple_
Definition: nlpsol_impl.hpp:84
casadi_int np_
Number of parameters.
Definition: nlpsol_impl.hpp:72
double min_lam_
Options.
Definition: nlpsol_impl.hpp:99
Sparsity get_sparsity_in(casadi_int i) override
Sparsities of function inputs and outputs.
Definition: nlpsol.cpp:379
static Function create_oracle(const std::map< std::string, XType > &d, const Dict &opts)
Convert dictionary to Problem.
Definition: nlpsol.cpp:207
bool calc_lam_x_
Options.
Definition: nlpsol_impl.hpp:97
std::vector< casadi_int > detect_simple_bounds_target_g_
Definition: nlpsol_impl.hpp:87
bool sens_force_equality_
Options.
casadi_int callback_step_
Execute the callback function only after this amount of iterations.
Definition: nlpsol_impl.hpp:78
virtual void setOptionsFromFile(const std::string &file)
Read options from parameter xml.
Definition: nlpsol.cpp:775
std::vector< casadi_int > detect_simple_bounds_target_x_
Definition: nlpsol_impl.hpp:86
int callback(NlpsolMemory *m) const
Definition: nlpsol.cpp:1200
~Nlpsol() override=0
Destructor.
Definition: nlpsol.cpp:371
std::vector< bool > discrete_
Options.
casadi_int nx_
Number of variables.
Definition: nlpsol_impl.hpp:66
virtual bool integer_support() const
Can discrete variables be treated.
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
bool bound_consistency_
Options.
Definition: nlpsol_impl.hpp:98
bool no_nlp_grad_
Options.
std::string sens_linsol_
Linear solver and options.
Definition: nlpsol_impl.hpp:81
virtual int solve(void *mem) const =0
Function fcallback_
callback function, executed at each iteration
Definition: nlpsol_impl.hpp:75
bool is_a(const std::string &type, bool recursive) const override
Check if the function is of a particular type.
Definition: nlpsol.cpp:375
double get_default_in(casadi_int ind) const override
Get default input value.
Base class for functions that perform calculation with an oracle.
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())
void join_results(OracleMemory *m) const
Combine results from different threads.
void init(const Dict &opts) override
int init_mem(void *mem) const override
Initalize memory block.
virtual void codegen_body_enter(CodeGenerator &g) const
Generate code for the function body.
int calc_function(OracleMemory *m, const std::string &fcn, const double *const *arg=nullptr, int thread_id=0) const
std::vector< std::string > get_function() const override
Get list of dependency functions.
static const Options options_
Options.
Dict get_stats(void *mem) const override
Get all statistics.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
virtual void codegen_body_exit(CodeGenerator &g) const
Generate code for the function body.
static bool has_plugin(const std::string &pname, bool verbose=false)
Check if a plugin is available or can be loaded.
static Nlpsol * instantiate(const std::string &fname, const std::string &pname, Problem problem)
void serialize_type(SerializingStream &s) const
Serialize type information.
static const Options & plugin_options(const std::string &pname)
Get the plugin options.
static Plugin & getPlugin(const std::string &pname)
Load and get the creator function.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
static Plugin load_plugin(const std::string &pname, bool register_plugin=true, bool needs_lock=true)
Load a plugin dynamically.
Base class for FunctionInternal and LinsolInternal.
bool error_on_fail_
Throw an exception on failure?
void print(const char *fmt,...) const
C-style formatted printing during evaluation.
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.
GenericShared implements a reference counting framework similar for efficient and.
void disp(std::ostream &stream, bool more=false) const
Print a description of the object.
Class representing a Slice.
Definition: slice.hpp:48
General sparsity class.
Definition: sparsity.hpp:200
casadi_int numel() const
Total number of entries, structural zeros included, i.e. size1()*size2()
Definition: sparsity.cpp:132
std::string dim(bool with_nz=false) const
Dimensions as a string "nrow x ncol", optionally with the number of nonzeros.
Definition: sparsity.cpp:595
static Sparsity dense(casadi_int nrow, casadi_int ncol=1)
Create a dense rectangular sparsity pattern.
Definition: sparsity.cpp:1041
Sparsity T() const
Transposed pattern.
Definition: sparsity.cpp:396
const casadi_int * row() const
Get a reference to row-vector,.
Definition: sparsity.cpp:166
bool is_empty(bool both=false) const
Check whether the pattern has a zero dimension.
Definition: sparsity.cpp:146
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
Definition: sparsity.cpp:170
std::string doc_nlpsol(const std::string &name)
Get the documentation string of an NLP solver plugin.
Definition: nlpsol.cpp:44
bool has_nlpsol(const std::string &name)
Check if an NLP solver plugin is available.
Definition: nlpsol.cpp:36
void load_nlpsol(const std::string &name)
Explicitly load an NLP solver plugin.
Definition: nlpsol.cpp:40
std::string nlpsol_option_info(const std::string &name, const std::string &op)
Get the documentation string of an option of an NLP solver plugin.
Definition: nlpsol.cpp:939
casadi_int nlpsol_n_in()
Number of NLP solver inputs.
Definition: nlpsol.cpp:343
std::string nlpsol_option_type(const std::string &name, const std::string &op)
Get the type of an option of an NLP solver plugin.
Definition: nlpsol.cpp:935
std::vector< std::string > nlpsol_options(const std::string &name)
Get all options of an NLP solver plugin.
Definition: nlpsol.cpp:931
std::vector< std::string > nlpsol_in()
Get the input scheme of NLP solvers.
Definition: nlpsol.cpp:284
Function nlpsol(const std::string &name, const std::string &solver, const SXDict &nlp, const Dict &opts)
Definition: nlpsol.cpp:196
casadi_int nlpsol_n_out()
Number of NLP solver outputs.
Definition: nlpsol.cpp:347
std::vector< std::string > nlpsol_out()
Get the output scheme of NLP solvers.
Definition: nlpsol.cpp:290
double nlpsol_default_in(casadi_int ind)
Default value of an NLP solver input.
Definition: nlpsol.cpp:296
The casadi namespace.
Definition: archiver.cpp:28
NlpsolInput
Input arguments of an NLP Solver.
Definition: nlpsol.hpp:831
@ NLPSOL_P
Value of fixed parameters (np x 1), default 0.
Definition: nlpsol.hpp:835
@ NLPSOL_UBX
Decision variables upper bound (nx x 1), default +inf.
Definition: nlpsol.hpp:839
@ NLPSOL_X0
Decision variables, initial guess (nx x 1), default 0.
Definition: nlpsol.hpp:833
@ NLPSOL_LAM_G0
Lagrange multipliers for bounds on G, initial guess (ng x 1), default 0.
Definition: nlpsol.hpp:847
@ NLPSOL_UBG
Constraints upper bound (ng x 1), default +inf.
Definition: nlpsol.hpp:843
@ NLPSOL_LAM_X0
Lagrange multipliers for bounds on X, initial guess (nx x 1), default 0.
Definition: nlpsol.hpp:845
@ NLPSOL_NUM_IN
Definition: nlpsol.hpp:848
@ NLPSOL_LBG
Constraints lower bound (ng x 1), default -inf.
Definition: nlpsol.hpp:841
@ NLPSOL_LBX
Decision variables lower bound (nx x 1), default -inf.
Definition: nlpsol.hpp:837
std::map< std::string, MX > MXDict
Definition: mx.hpp:5151
bool name_has_g(const std::string &name)
Definition: nlpsol.cpp:48
NlpsolOutput
Output arguments of an NLP Solver.
Definition: nlpsol.hpp:852
@ 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_NUM_OUT
Definition: nlpsol.hpp:867
@ 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
T get_from_dict(const std::map< std::string, T > &d, const std::string &key, const T &default_value)
void assign_vector(const std::vector< S > &s, std::vector< D > &d)
@ NL_X
Decision variable.
Definition: nlpsol.hpp:807
@ NL_P
Fixed parameter.
Definition: nlpsol.hpp:809
@ NL_NUM_IN
Number of NLP inputs.
Definition: nlpsol.hpp:811
double if_else(double x, double y, double z)
Definition: calculus.hpp:296
@ NL_F
Objective function.
Definition: nlpsol.hpp:820
@ NL_G
Constraint function.
Definition: nlpsol.hpp:822
@ NL_NUM_OUT
Number of NLP outputs.
Definition: nlpsol.hpp:824
int detect_bounds_callback(const double **arg, double **res, casadi_int *iw, double *w, void *callback_data)
Definition: nlpsol.cpp:677
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.
@ OT_BOOLVECTOR
@ OT_INTVECTOR
std::map< std::string, SX > SXDict
Definition: sx_fwd.hpp:40
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
std::vector< bool > boolvec_not(const std::vector< bool > &v)
Invert all entries.
const double inf
infinity
Definition: calculus.hpp:50
const std::vector< std::string > NL_INPUTS
Shortname for onput arguments of an NLP function.
Definition: nlpsol.hpp:815
const double nan
Not a number.
Definition: calculus.hpp:53
void casadi_scal(casadi_int n, T1 alpha, T1 *x)
SCAL: x <- alpha*x.
std::vector< T > vector_select(const std::vector< T > &v, const std::vector< bool > &s, bool invert=false)
Select subset of vector.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
Function construct_nlpsol(const std::string &name, const std::string &solver, const std::map< std::string, X > &nlp, const Dict &opts)
Definition: nlpsol.cpp:64
Matrix< double > DM
Definition: dm_fwd.hpp:33
Function external(const std::string &name, const Importer &li, const Dict &opts)
Load a just-in-time compiled external function.
Definition: external.cpp:42
@ SOLVER_RET_SUCCESS
@ SOLVER_RET_UNKNOWN
@ SOLVER_RET_EXCEPTION
std::vector< casadi_int > boolvec_to_index(const std::vector< bool > &v)
const std::vector< std::string > NL_OUTPUTS
Shortname for output arguments of an NLP function.
Definition: nlpsol.hpp:828
Integrator memory.
Definition: nlpsol_impl.hpp:40
casadi_nlpsol_data< double > d_nlp
Definition: nlpsol_impl.hpp:42
Options metadata for a class.
Definition: options.hpp:40
std::string type(const std::string &name) const
Definition: options.cpp:289
std::vector< std::string > all() const
Definition: options.cpp:283
std::string info(const std::string &name) const
Definition: options.cpp:295
std::map< std::string, FStats > fstats
void add_stat(const std::string &s)
const T1 * lam_g0
Definition: casadi_nlp.hpp:87
const T1 * lam_x0
Definition: casadi_nlp.hpp:87
casadi_nlpsol_detect_bounds_prob< T1 > detect_bounds
Definition: casadi_nlp.hpp:46