conic.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 "conic_impl.hpp"
27 #include "nlpsol_impl.hpp"
28 #include "filesystem_impl.hpp"
29 
30 namespace casadi {
31 
32  bool has_conic(const std::string& name) {
33  return Conic::has_plugin(name);
34  }
35 
36  void load_conic(const std::string& name) {
37  Conic::load_plugin(name);
38  }
39 
40  std::string doc_conic(const std::string& name) {
41  return Conic::getPlugin(name).doc;
42  }
43 
44  Function conic(const std::string& name, const std::string& solver,
45  const SpDict& qp, const Dict& opts) {
46  return Function::create(Conic::instantiate(name, solver, qp), opts);
47  }
48 
49  void conic_debug(const Function& f, const std::string &filename) {
50  auto file_ptr = Filesystem::ofstream_ptr(filename);
51  conic_debug(f, *file_ptr);
52  }
53 
54  void conic_debug(const Function& f, std::ostream &file) {
55  casadi_assert_dev(!f.is_null());
56  const Conic* n = f.get<Conic>();
57  n->generateNativeCode(file);
58  }
59 
60  std::vector<std::string> conic_in() {
61  std::vector<std::string> ret(conic_n_in());
62  for (size_t i=0; i<ret.size(); ++i) ret[i]=conic_in(i);
63  return ret;
64  }
65 
66  std::vector<std::string> conic_out() {
67  std::vector<std::string> ret(conic_n_out());
68  for (size_t i=0; i<ret.size(); ++i) ret[i]=conic_out(i);
69  return ret;
70  }
71 
72  std::string conic_in(casadi_int ind) {
73  switch (static_cast<ConicInput>(ind)) {
74  case CONIC_H: return "h";
75  case CONIC_G: return "g";
76  case CONIC_A: return "a";
77  case CONIC_Q: return "q";
78  case CONIC_P: return "p";
79  case CONIC_LBA: return "lba";
80  case CONIC_UBA: return "uba";
81  case CONIC_LBX: return "lbx";
82  case CONIC_UBX: return "ubx";
83  case CONIC_X0: return "x0";
84  case CONIC_LAM_X0: return "lam_x0";
85  case CONIC_LAM_A0: return "lam_a0";
86  case CONIC_NUM_IN: break;
87  }
88  return std::string();
89  }
90 
91  std::string conic_out(casadi_int ind) {
92  switch (static_cast<ConicOutput>(ind)) {
93  case CONIC_X: return "x";
94  case CONIC_COST: return "cost";
95  case CONIC_LAM_A: return "lam_a";
96  case CONIC_LAM_X: return "lam_x";
97  case CONIC_NUM_OUT: break;
98  }
99  return std::string();
100  }
101 
102  casadi_int conic_n_in() {
103  return CONIC_NUM_IN;
104  }
105 
106  casadi_int conic_n_out() {
107  return CONIC_NUM_OUT;
108  }
109 
110  template<typename M>
111  Function qpsol_nlp(const std::string& name, const std::string& solver,
112  const std::map<std::string, M>& qp, const Dict& opts) {
113  // We have: minimize f(x) = 1/2 * x' H x + c'x
114  // subject to lbx <= x <= ubx
115  // lbg <= g(x) = A x + b <= ubg
116  // h(x) >=0 (psd)
117 
118  // Extract 'expand' option
119  bool expand = false;
120  Dict opt = opts;
121  extract_from_dict_inplace(opt, "expand", expand);
122  bool postpone_expand = false;
123  extract_from_dict_inplace(opt, "postpone_expand", postpone_expand);
124  bool error_on_fail = get_from_dict(opts, "error_on_fail", true);
125 
126  if (expand && !postpone_expand && M::type_name()=="MX") {
127  Function f = Function("f", qp, {"x", "p"}, {"f", "g", "h"});
128  std::vector<SX> arg = f.sx_in();
129  std::vector<SX> res = f(arg);
130  SXDict qp_mod;
131  for (casadi_int i=0;i<f.n_in();++i) qp_mod[f.name_in(i)] = arg[i];
132  for (casadi_int i=0;i<f.n_out();++i) qp_mod[f.name_out(i)] = res[i];
133  return qpsol_nlp(name, solver, qp_mod, opt);
134  }
135 
136  M x, p, f, g, h;
137  for (auto&& i : qp) {
138  if (i.first=="x") {
139  x = i.second;
140  } else if (i.first=="p") {
141  p = i.second;
142  } else if (i.first=="f") {
143  f = i.second;
144  } else if (i.first=="g") {
145  g = i.second;
146  } else if (i.first=="h") {
147  h = i.second;
148  } else {
149  casadi_error("No such field: " + i.first);
150  }
151  }
152 
153  if (f.is_empty()) f = 0;
154  if (g.is_empty()) g = M(0, 1);
155 
156  // Dimension checks
157  casadi_assert(g.is_dense() && g.is_vector(),
158  "Expected a dense vector 'g', but got " + g.dim() + ".");
159 
160  casadi_assert(f.is_dense() && f.is_scalar(),
161  "Expected a dense scalar 'f', but got " + f.dim() + ".");
162 
163  casadi_assert(x.is_dense() && x.is_vector(),
164  "Expected a dense vector 'x', but got " + x.dim() + ".");
165 
166  casadi_assert(h.is_square(),
167  "Expected a symmetric matrix 'h', but got " + h.dim() + ".");
168 
169  if (g.is_empty(true)) g = M(0, 1); // workaround
170 
171  // Gradient of the objective: gf == Hx + g
172  M gf = M::gradient(f, x);
173 
174  // Identify the linear term in the objective
175  M c = substitute(gf, x, M::zeros(x.sparsity()));
176 
177  // Identify the quadratic term in the objective
178  M H = M::jacobian(gf, x, {{"symmetric", true}});
179 
180  // Identify constant term in the objective
181  Function r("constant_qp", {x, p}, {substitute(f, x, M::zeros(x.sparsity()))});
182 
183  // Identify the constant term in the constraints
184  M b = substitute(g, x, M::zeros(x.sparsity()));
185 
186  // Identify the linear term in the constraints
187  M A = M::jacobian(g, x);
188 
189  // Identify the constant term in the psd constraints
190  M P = substitute(h, x, M::zeros(x.sparsity()));
191 
192  // Identify the linear term in the psd constraints
193  M Q = M::jacobian(h, x);
194 
195  // Create a function for calculating the required matrices vectors
196  Function prob(name + "_qp", {x, p}, {H, c, A, b, Q, P},
197  {"x", "p"}, {"H", "c", "A", "b", "Q", "P"});
198  if (expand && postpone_expand) prob = prob.expand();
199 
200  // Make sure that the problem is sound
201  casadi_assert(!prob.has_free(), "Cannot create '" + prob.name() + "' "
202  "since " + str(prob.get_free()) + " are free.");
203 
204  // Create the QP solver
205  Function conic_f = conic(name + "_qpsol", solver,
206  {{"h", H.sparsity()}, {"a", A.sparsity()},
207  {"p", P.sparsity()}, {"q", Q.sparsity()}}, opt);
208 
209  // Create an MXFunction with the right signature
210  std::vector<MX> ret_in(NLPSOL_NUM_IN);
211  ret_in[NLPSOL_X0] = MX::sym("x0", x.sparsity());
212  ret_in[NLPSOL_P] = MX::sym("p", p.sparsity());
213  ret_in[NLPSOL_LBX] = MX::sym("lbx", x.sparsity());
214  ret_in[NLPSOL_UBX] = MX::sym("ubx", x.sparsity());
215  ret_in[NLPSOL_LBG] = MX::sym("lbg", g.sparsity());
216  ret_in[NLPSOL_UBG] = MX::sym("ubg", g.sparsity());
217  ret_in[NLPSOL_LAM_X0] = MX::sym("lam_x0", x.sparsity());
218  ret_in[NLPSOL_LAM_G0] = MX::sym("lam_g0", g.sparsity());
219  std::vector<MX> ret_out(NLPSOL_NUM_OUT);
220 
221 
222  std::vector<MX> v(NL_NUM_IN);
223  v[NL_X] = ret_in[NLPSOL_X0];
224  v[NL_P] = ret_in[NLPSOL_P];
225  // Evaluate constant part of objective
226  MX rv = r(v)[0];
227  // Get expressions for the QP matrices and vectors
228  v = prob(v);
229 
230  // Call the QP solver
231  std::vector<MX> w(CONIC_NUM_IN);
232  w[CONIC_H] = v.at(0);
233  w[CONIC_G] = v.at(1);
234  w[CONIC_A] = v.at(2);
235  w[CONIC_Q] = v.at(4);
236  w[CONIC_P] = v.at(5);
237  w[CONIC_LBX] = ret_in[NLPSOL_LBX];
238  w[CONIC_UBX] = ret_in[NLPSOL_UBX];
239  w[CONIC_LBA] = ret_in[NLPSOL_LBG] - v.at(3);
240  w[CONIC_UBA] = ret_in[NLPSOL_UBG] - v.at(3);
241  w[CONIC_X0] = ret_in[NLPSOL_X0];
242  w[CONIC_LAM_X0] = ret_in[NLPSOL_LAM_X0];
243  w[CONIC_LAM_A0] = ret_in[NLPSOL_LAM_G0];
244  w = conic_f(w);
245 
246  // Get expressions for the solution
247  ret_out[NLPSOL_X] = reshape(w[CONIC_X], x.size());
248  ret_out[NLPSOL_F] = rv + w[CONIC_COST];
249  ret_out[NLPSOL_G] = reshape(mtimes(v.at(2), w[CONIC_X]), g.size()) + v.at(3);
250  ret_out[NLPSOL_LAM_X] = reshape(w[CONIC_LAM_X], x.size());
251  ret_out[NLPSOL_LAM_G] = reshape(w[CONIC_LAM_A], g.size());
252  ret_out[NLPSOL_LAM_P] = MX::nan(p.sparsity());
253 
254  Dict fun_opts;
255  fun_opts["default_in"] = nlpsol_default_in();
256  fun_opts["error_on_fail"] = error_on_fail;
257 
258  return Function(name, ret_in, ret_out, nlpsol_in(), nlpsol_out(), fun_opts);
259  }
260 
261  Function qpsol(const std::string& name, const std::string& solver,
262  const SXDict& qp, const Dict& opts) {
263  return qpsol_nlp(name, solver, qp, opts);
264  }
265 
266  Function qpsol(const std::string& name, const std::string& solver,
267  const MXDict& qp, const Dict& opts) {
268  return qpsol_nlp(name, solver, qp, opts);
269  }
270 
271  // Constructor
272  Conic::Conic(const std::string& name, const std::map<std::string, Sparsity> &st)
273  : FunctionInternal(name) {
274 
275  // Set default options
276  error_on_fail_ = true;
277 
278  P_ = Sparsity(0, 0);
279  for (auto i=st.begin(); i!=st.end(); ++i) {
280  if (i->first=="a") {
281  A_ = i->second;
282  } else if (i->first=="h") {
283  H_ = i->second;
284  } else if (i->first=="q") {
285  Q_ = i->second;
286  } else if (i->first=="p") {
287  P_ = i->second;
288  } else {
289  casadi_error("Unrecognized field in QP structure: " + str(i->first));
290  }
291  }
292 
293  // We need either A or H
294  casadi_assert(!A_.is_null() || !H_.is_null(),
295  "Cannot determine dimension");
296 
297  // Generate A or H
298  if (A_.is_null()) {
299  A_ = Sparsity(0, H_.size2());
300  } else if (H_.is_null()) {
301  H_ = Sparsity(A_.size2(), A_.size2());
302  } else {
303  // Consistency check
304  casadi_assert(A_.size2()==H_.size2(),
305  "Got incompatible dimensions.\n"
306  "min x'Hx + G'x s.t. LBA <= Ax <= UBA :\n"
307  "H: " + H_.dim() + " - A: " + A_.dim() + "\n"
308  "We need: H.size2()==A.size2()");
309  }
310 
311  casadi_assert(H_.is_symmetric(),
312  "Got incompatible dimensions. min x'Hx + G'x\n"
313  "H: " + H_.dim() +
314  "We need H square & symmetric");
315 
316  nx_ = A_.size2();
317  na_ = A_.size1();
318 
319  // Check psd constraints (linear part)
320  if (Q_.is_null()) {
321  Q_ = Sparsity(0, 0);
322  np_ = 0;
323  } else {
324  casadi_assert(Q_.size2()==nx_,
325  "Got incompatible dimensions.\n"
326  "Q: " + Q_.dim() +
327  "We need the product Qx to exist.");
328  np_ = static_cast<casadi_int>(sqrt(static_cast<double>(Q_.size1())));
329  casadi_assert(np_*np_==Q_.size1(),
330  "Got incompatible dimensions.\n"
331  "Q: " + Q_.dim() +
332  "We need Q.size1() to have an integer square root.");
333 
334  Sparsity qsum = reshape(sum2(Q_), np_, np_);
335 
336  casadi_assert(qsum.is_symmetric(),
337  "Got incompatible dimensions.");
338  }
339 
340  // Check psd constraints (constant part)
341  if (P_.is_null()) P_ = Sparsity(np_, np_);
342 
343  casadi_assert(P_.is_symmetric(),
344  "Got incompatible dimensions.\n"
345  "P: " + P_.dim() +
346  "We need P square & symmetric.");
347 
348  casadi_assert(P_.size1()==np_,
349  "Got incompatible dimensions.\n"
350  "P: " + P_.dim() +
351  "We need P " + str(np_) + "-by-" + str(np_) + ".");
352 
353  }
354 
356  switch (static_cast<ConicInput>(i)) {
357  case CONIC_X0:
358  case CONIC_G:
359  case CONIC_LBX:
360  case CONIC_UBX:
361  case CONIC_LAM_X0:
362  return get_sparsity_out(CONIC_X);
363  case CONIC_Q:
364  return Q_;
365  case CONIC_P:
366  return P_;
367  case CONIC_LBA:
368  case CONIC_UBA:
369  case CONIC_LAM_A0:
371  case CONIC_A:
372  return A_;
373  case CONIC_H:
374  return H_;
375  case CONIC_NUM_IN: break;
376  }
377  return Sparsity();
378  }
379 
381  switch (static_cast<ConicOutput>(i)) {
382  case CONIC_COST:
383  return Sparsity::scalar();
384  case CONIC_X:
385  case CONIC_LAM_X:
386  return Sparsity::dense(nx_, 1);
387  case CONIC_LAM_A:
388  return Sparsity::dense(na_, 1);
389  case CONIC_NUM_OUT: break;
390  }
391  return Sparsity();
392  }
393 
396  {{"discrete",
397  {OT_BOOLVECTOR,
398  "Indicates which of the variables are discrete, i.e. integer-valued"}},
399  {"equality",
400  {OT_BOOLVECTOR,
401  "Indicate an upfront hint which of the constraints are equalities. "
402  "Some solvers may be able to exploit this knowledge. "
403  "When true, the corresponding lower and upper bounds are assumed equal. "
404  "When false, the corresponding bounds may be equal or different."}},
405  {"print_problem",
406  {OT_BOOL,
407  "Print a numeric description of the problem"}},
408  {"solver_version_check",
409  {OT_BOOL,
410  "When the plugin loads an externally supplied solver, "
411  "check that its version is compatible with the plugin [Default: true]"}},
412  {"sens_min_lam",
413  {OT_DOUBLE,
414  "Minimum multiplier value for a constraint to be considered active "
415  "in parametric sensitivities [0]."}},
416  {"sens_force_equality",
417  {OT_BOOL,
418  "Treat constraints with equal bounds as active in parametric sensitivities, "
419  "regardless of the multiplier, see issue #2545 [false]."}},
420  {"sens_linsol",
421  {OT_STRING,
422  "Linear solver used for parametric sensitivities (default 'qr')."}},
423  {"sens_linsol_options",
424  {OT_DICT,
425  "Linear solver options used for parametric sensitivities."}}
426  }
427  };
428 
429  void Conic::init(const Dict& opts) {
430  // Call the init method of the base class
432 
433  print_problem_ = false;
434  solver_version_check_ = true;
435  sens_min_lam_ = 0;
436  sens_force_equality_ = false;
437  sens_linsol_ = "qr";
438 
439  // Read options
440  for (auto&& op : opts) {
441  if (op.first=="discrete") {
442  discrete_ = op.second;
443  } else if (op.first=="equality") {
444  equality_ = op.second;
445  } else if (op.first=="print_problem") {
446  print_problem_ = op.second;
447  } else if (op.first=="solver_version_check") {
448  solver_version_check_ = op.second;
449  } else if (op.first=="sens_min_lam") {
450  sens_min_lam_ = op.second;
451  } else if (op.first=="sens_force_equality") {
452  sens_force_equality_ = op.second;
453  } else if (op.first=="sens_linsol") {
454  sens_linsol_ = op.second.to_string();
455  } else if (op.first=="sens_linsol_options") {
456  sens_linsol_options_ = op.second;
457  }
458  }
459 
461 
462  // Check options
463  if (!discrete_.empty()) {
464  casadi_assert(discrete_.size()==nx_, "\"discrete\" option has wrong length");
465  if (std::find(discrete_.begin(), discrete_.end(), true)!=discrete_.end()) {
466  casadi_assert(integer_support(),
467  "Discrete variables require a solver with integer support");
468  }
469  }
470 
471  if (!equality_.empty()) {
472  casadi_assert(equality_.size()==na_, "\"equality\" option has wrong length. "
473  "Expected " + str(na_) + " elements, but got " +
474  str(equality_.size()) + " instead.");
475  }
476 
477  casadi_assert(np_==0 || psd_support(),
478  "Selected solver does not support psd constraints.");
479 
480  set_qp_prob();
481  }
482 
484  if (solver_version_check_) deps_version_check("finalize");
485 
486  // Recursive call
488  }
489 
491  int Conic::init_mem(void* mem) const {
492  if (ProtoFunction::init_mem(mem)) return 1;
493 
494  return 0;
495  }
496 
498  void Conic::set_work(void* mem, const double**& arg, double**& res,
499  casadi_int*& iw, double*& w) const {
500 
501  auto *m = static_cast<ConicMemory*>(mem);
502 
503  casadi_qp_data<double>& d_qp = m->d_qp;
504  d_qp.h = arg[CONIC_H];
505  d_qp.g = arg[CONIC_G];
506  d_qp.a = arg[CONIC_A];
507  d_qp.lbx = arg[CONIC_LBX];
508  d_qp.ubx = arg[CONIC_UBX];
509  d_qp.uba = arg[CONIC_UBA];
510  d_qp.lba = arg[CONIC_LBA];
511  d_qp.x0 = arg[CONIC_X0];
512  d_qp.lam_x0 = arg[CONIC_LAM_X0];
513  d_qp.lam_a0 = arg[CONIC_LAM_A0];
514  d_qp.x = res[CONIC_X];
515  d_qp.lam_x = res[CONIC_LAM_X];
516  d_qp.lam_a = res[CONIC_LAM_A];
517  d_qp.f = res[CONIC_COST];
518 
519  // Problem has not been solved at this point
520  d_qp.success = false;
522  d_qp.iter_count = -1;
523  }
524 
526  }
527 
528  void Conic::check_inputs(const double* lbx, const double* ubx,
529  const double* lba, const double* uba) const {
530  for (casadi_int i=0; i<nx_; ++i) {
531  double lb = lbx ? lbx[i] : 0., ub = ubx ? ubx[i] : 0.;
532  casadi_assert(lb <= ub && lb!=inf && ub!=-inf,
533  "Ill-posed problem detected: "
534  "LBX[" + str(i) + "] <= UBX[" + str(i) + "] was violated. "
535  "Got LBX[" + str(i) + "]=" + str(lb) + " and UBX[" + str(i) + "] = " + str(ub) + ".");
536  }
537  for (casadi_int i=0; i<na_; ++i) {
538  double lb = lba ? lba[i] : 0., ub = uba ? uba[i] : 0.;
539  casadi_assert(lb <= ub && lb!=inf && ub!=-inf,
540  "Ill-posed problem detected: "
541  "LBA[" + str(i) + "] <= UBA[" + str(i) + "] was violated. "
542  "Got LBA[" + str(i) + "] = " + str(lb) + " and UBA[" + str(i) + "] = " + str(ub) + ".");
543  }
544  }
545 
546  void Conic::generateNativeCode(std::ostream& file) const {
547  casadi_error("generateNativeCode not defined for class " + class_name());
548  }
549 
550  std::map<std::string, Conic::Plugin> Conic::solvers_;
551 
552 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
553  std::mutex Conic::mutex_solvers_;
554 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
555 
556  const std::string Conic::infix_ = "conic";
557 
558  double Conic::get_default_in(casadi_int ind) const {
559  switch (ind) {
560  case CONIC_LBX:
561  case CONIC_LBA:
562  return -std::numeric_limits<double>::infinity();
563  case CONIC_UBX:
564  case CONIC_UBA:
565  return std::numeric_limits<double>::infinity();
566  default:
567  return 0;
568  }
569  }
570 
572  eval(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
573  if (print_problem_) {
574  uout() << "H:";
575  DM::print_dense(uout(), H_, arg[CONIC_H], false);
576  uout() << std::endl;
577  uout() << "G:" << std::vector<double>(arg[CONIC_G], arg[CONIC_G]+nx_) << std::endl;
578  uout() << "A:";
579  DM::print_dense(uout(), A_, arg[CONIC_A], false);
580  uout() << std::endl;
581  uout() << "lba:" << std::vector<double>(arg[CONIC_LBA], arg[CONIC_LBA]+na_) << std::endl;
582  uout() << "uba:" << std::vector<double>(arg[CONIC_UBA], arg[CONIC_UBA]+na_) << std::endl;
583  uout() << "lbx:" << std::vector<double>(arg[CONIC_LBX], arg[CONIC_LBX]+nx_) << std::endl;
584  uout() << "ubx:" << std::vector<double>(arg[CONIC_UBX], arg[CONIC_UBX]+nx_) << std::endl;
585  }
586  auto *m = static_cast<ConicMemory*>(mem);
587 
588  if (inputs_check_) {
589  check_inputs(arg[CONIC_LBX], arg[CONIC_UBX], arg[CONIC_LBA], arg[CONIC_UBA]);
590  }
591 
592  setup(mem, arg, res, iw, w);
593 
594  int ret = solve(arg, res, iw, w, mem);
595 
596  if (m->d_qp.success) m->d_qp.unified_return_status = SOLVER_RET_SUCCESS;
597 
598  if (error_on_fail_ && !m->d_qp.success)
599  casadi_error("conic process failed. "
600  "Set 'error_on_fail' option to false to ignore this error.");
601  return ret;
602  }
603 
604  std::vector<std::string> conic_options(const std::string& name) {
605  return Conic::plugin_options(name).all();
606  }
607 
608  std::string conic_option_type(const std::string& name, const std::string& op) {
609  return Conic::plugin_options(name).type(op);
610  }
611 
612  std::string conic_option_info(const std::string& name, const std::string& op) {
613  return Conic::plugin_options(name).info(op);
614  }
615 
616  bool Conic::is_a(const std::string& type, bool recursive) const {
617  return type=="Conic" || (recursive && FunctionInternal::is_a(type, recursive));
618  }
619 
620  MX Conic::sens_kkt(const MX& H, const MX& A, const MX& lam_x, const MX& lam_a,
621  const MX& lbx, const MX& ubx, const MX& lba, const MX& uba,
622  double min_lam, bool force_equality,
623  MX& lbIx, MX& ubIx, MX& lbIa, MX& ubIa) {
624  ubIx = lam_x > min_lam;
625  lbIx = lam_x < -min_lam;
626  ubIa = lam_a > min_lam;
627  lbIa = lam_a < -min_lam;
628  if (force_equality) {
629  lbIx = if_else(lbx==ubx, 1-ubIx, lbIx);
630  lbIa = if_else(lba==uba, 1-ubIa, lbIa);
631  }
632  MX bIx = ubIx + lbIx, iIx = 1-bIx;
633  MX bIa = ubIa + lbIa, iIa = 1-bIa;
634  MX H_11 = mtimes(diag(iIx), H) + diag(bIx);
635  MX H_12 = mtimes(diag(iIx), A.T());
636  MX H_21 = mtimes(diag(bIa), A);
637  MX H_22 = diag(-iIa);
638  return MX::blockcat({{H_11, H_12}, {H_21, H_22}});
639  }
640 
641  // (x, lam_a, h, g, a) -> (cost, r, ax) with r = -lam_x at a solution
642  static Function conic_kkt_res(const Sparsity& sp_h, const Sparsity& sp_a) {
643  MX x = MX::sym("x", sp_h.size2()), lam_a = MX::sym("lam_a", sp_a.size1());
644  MX h = MX::sym("h", sp_h), g = MX::sym("g", sp_h.size2()), a = MX::sym("a", sp_a);
645  MX cost = 0.5*bilin(h, x, x) + dot(g, x);
646  MX r = mtimes(0.5*(h + h.T()), x) + g + mtimes(a.T(), lam_a);
647  return Function("conic_kkt_res", {x, lam_a, h, g, a}, {cost, r, mtimes(a, x)});
648  }
649 
651  get_forward(casadi_int nfwd, const std::string& name,
652  const std::vector<std::string>& inames,
653  const std::vector<std::string>& onames,
654  const Dict& opts) const {
655  casadi_assert(np_==0, "Derivatives not supported for psd constraints");
656  casadi_assert(std::find(discrete_.begin(), discrete_.end(), true)==discrete_.end(),
657  "Derivatives not supported for discrete variables");
658 
659  // Symbolic expression for the input
660  std::vector<MX> arg = mx_in(), res = mx_out();
661 
662  // Initial guesses not used for derivative calculations
664  std::string name = arg[i].is_symbolic() ? arg[i].name() : "tmp_get_forward";
665  arg[i] = MX::sym(name, Sparsity(arg[i].size()));
666  }
667 
668  // Problem data and optimal solution
669  MX h = arg[CONIC_H], g = arg[CONIC_G], a = arg[CONIC_A];
670  MX x = res[CONIC_X], cost = res[CONIC_COST];
671  MX lam_a = res[CONIC_LAM_A], lam_x = res[CONIC_LAM_X];
672 
673  // KKT matrix, active set given by the multiplier signs
674  MX lbIx, ubIx, lbIa, ubIa;
675  MX H = sens_kkt(h, a, lam_x, lam_a, arg[CONIC_LBX], arg[CONIC_UBX],
677  lbIx, ubIx, lbIa, ubIa);
678 
679  // Sensitivity inputs
680  std::vector<MX> fseed(CONIC_NUM_IN);
681  for (casadi_int i=0; i<CONIC_NUM_IN; ++i) {
682  fseed[i] = MX(repmat(Sparsity(arg[i].size()), 1, nfwd));
683  }
685  fseed[i] = MX::sym("fwd_" + name_in_.at(i), repmat(arg[i].sparsity(), 1, nfwd));
686  }
687 
688  // fwd_res: (x, lam_a, h, g, a, cost, r, ax, fwd_x, fwd_lam_a, fwd_h, fwd_g, fwd_a)
689  // -> (fwd_cost, fwd_r, fwd_ax)
690  Function fwd_res = conic_kkt_res(H_, A_).forward(nfwd);
691  std::vector<MX> nom = {x, lam_a, h, g, a, cost, -lam_x, mtimes(a, x)};
692 
693  // Calculate sensitivities from the problem data
694  std::vector<MX> vv = nom;
695  vv.insert(vv.end(), {0, 0, fseed[CONIC_H], fseed[CONIC_G], fseed[CONIC_A]});
696  vv = fwd_res(vv);
697 
698  // Propagate forward seeds
699  MX fwd_alpha_x = if_else(lbIx, fseed[CONIC_LBX], 0) + if_else(ubIx, fseed[CONIC_UBX], 0)
700  - if_else(1-lbIx-ubIx, vv.at(1), 0);
701  MX fwd_alpha_a = if_else(lbIa, fseed[CONIC_LBA], 0) + if_else(ubIa, fseed[CONIC_UBA], 0)
702  - if_else(lbIa+ubIa, vv.at(2), 0);
703  MX v = MX::solve(H, vertcat(fwd_alpha_x, fwd_alpha_a), sens_linsol_, sens_linsol_options_);
704  std::vector<MX> v_split = vertsplit(v, {0, nx_, nx_+na_});
705 
706  // Calculate sensitivities in cost and lam_x
707  vv = nom;
708  vv.insert(vv.end(), {v_split.at(0), v_split.at(1),
709  fseed[CONIC_H], fseed[CONIC_G], fseed[CONIC_A]});
710  vv = fwd_res(vv);
711 
712  // Forward sensitivities
713  std::vector<MX> fsens(CONIC_NUM_OUT);
714  fsens[CONIC_X] = v_split.at(0);
715  fsens[CONIC_COST] = vv.at(0);
716  fsens[CONIC_LAM_A] = v_split.at(1);
717  fsens[CONIC_LAM_X] = -vv.at(1);
718 
719  // Gather return values
720  arg.insert(arg.end(), res.begin(), res.end());
721  arg.insert(arg.end(), fseed.begin(), fseed.end());
722 
723  Dict options = opts;
724  options["allow_duplicate_io_names"] = true;
725 
726  return Function(name, arg, fsens, inames, onames, options);
727  }
728 
730  get_reverse(casadi_int nadj, const std::string& name,
731  const std::vector<std::string>& inames,
732  const std::vector<std::string>& onames,
733  const Dict& opts) const {
734  casadi_assert(np_==0, "Derivatives not supported for psd constraints");
735  casadi_assert(std::find(discrete_.begin(), discrete_.end(), true)==discrete_.end(),
736  "Derivatives not supported for discrete variables");
737 
738  // Symbolic expression for the input
739  std::vector<MX> arg = mx_in(), res = mx_out();
740 
741  // Initial guesses not used for derivative calculations
743  std::string name = arg[i].is_symbolic() ? arg[i].name() : "tmp_get_reverse";
744  arg[i] = MX::sym(name, Sparsity(arg[i].size()));
745  }
746 
747  // Problem data and optimal solution
748  MX h = arg[CONIC_H], g = arg[CONIC_G], a = arg[CONIC_A];
749  MX x = res[CONIC_X], cost = res[CONIC_COST];
750  MX lam_a = res[CONIC_LAM_A], lam_x = res[CONIC_LAM_X];
751 
752  // KKT matrix, active set given by the multiplier signs
753  MX lbIx, ubIx, lbIa, ubIa;
754  MX H = sens_kkt(h, a, lam_x, lam_a, arg[CONIC_LBX], arg[CONIC_UBX],
756  lbIx, ubIx, lbIa, ubIa);
757 
758  // Sensitivity inputs
759  std::vector<MX> aseed(CONIC_NUM_OUT);
760  for (casadi_int i=0; i<CONIC_NUM_OUT; ++i) {
761  aseed[i] = MX::sym("adj_" + name_out_.at(i), repmat(res[i].sparsity(), 1, nadj));
762  }
763 
764  // rev_res: (x, lam_a, h, g, a, cost, r, ax, adj_cost, adj_r, adj_ax)
765  // -> (adj_x, adj_lam_a, adj_h, adj_g, adj_a)
766  Function rev_res = conic_kkt_res(H_, A_).reverse(nadj);
767  std::vector<MX> nom = {x, lam_a, h, g, a, cost, -lam_x, mtimes(a, x)};
768 
769  // Calculate sensitivities from cost and lam_x
770  std::vector<MX> vv = nom;
771  vv.insert(vv.end(), {aseed[CONIC_COST], -aseed[CONIC_LAM_X], 0});
772  vv = rev_res(vv);
773  std::vector<MX> adj0 = vv;
774 
775  // Solve to get beta_x, beta_a
776  MX v = MX::solve(H.T(), vertcat(aseed[CONIC_X] + adj0.at(0), aseed[CONIC_LAM_A] + adj0.at(1)),
778  std::vector<MX> v_split = vertsplit(v, {0, nx_, nx_+na_});
779  MX beta_x = v_split.at(0), beta_a = v_split.at(1);
780 
781  // Calculate sensitivities in the problem data
782  vv = nom;
783  vv.insert(vv.end(), {0, (1-lbIx-ubIx)*beta_x, (lbIa+ubIa)*beta_a});
784  vv = rev_res(vv);
785 
786  // Reverse sensitivities
787  std::vector<MX> asens(CONIC_NUM_IN);
788  for (casadi_int i=0; i<CONIC_NUM_IN; ++i) {
789  asens[i] = MX(repmat(Sparsity(arg[i].size()), 1, nadj));
790  }
791  asens[CONIC_H] = adj0.at(2) - vv.at(2);
792  asens[CONIC_G] = adj0.at(3) - vv.at(3);
793  asens[CONIC_A] = adj0.at(4) - vv.at(4);
794  asens[CONIC_LBX] = if_else(lbIx, beta_x, 0);
795  asens[CONIC_UBX] = if_else(ubIx, beta_x, 0);
796  asens[CONIC_LBA] = if_else(lbIa, beta_a, 0);
797  asens[CONIC_UBA] = if_else(ubIa, beta_a, 0);
798 
799  // Gather return values
800  arg.insert(arg.end(), res.begin(), res.end());
801  arg.insert(arg.end(), aseed.begin(), aseed.end());
802 
803  Dict options = opts;
804  options["allow_duplicate_io_names"] = true;
805 
806  return Function(name, arg, asens, inames, onames, options);
807  }
808 
810 
811  Sparsity qsum = reshape(sum2(Q_), np_, np_);
812 
813  // Block detection
814  Sparsity aggregate = qsum+P_;
815 
816  std::vector<casadi_int> p;
817  casadi_int nb = aggregate.scc(p, mem.r);
818 
819  std::string pattern_message = "Pattern not recognised";
820 
821  casadi_assert(p==range(p.size()), pattern_message);
822 
823  const casadi_int* row = aggregate.row();
824  const casadi_int* colind = aggregate.colind();
825 
826  // Check fishbone-structure
827  for (casadi_int i=0;i<nb;++i) {
828  casadi_int block_size = mem.r[i+1]-mem.r[i];
829  // number of nonzeros in column mem.r[i+1]-1
830  casadi_int nz = colind[mem.r[i+1]]-colind[mem.r[i+1]-1];
831  // Last column of block should be dense
832  casadi_assert(nz==block_size, pattern_message);
833  for (casadi_int k=0;k<block_size-1;++k) {
834  casadi_assert(colind[mem.r[i]+k+1]-colind[mem.r[i]+k], pattern_message);
835  casadi_assert(*(row++)==k+mem.r[i], pattern_message);
836  casadi_assert(*(row++)==mem.r[i]+block_size-1, pattern_message);
837  }
838 
839  for (casadi_int k=0;k<block_size;++k)
840  casadi_assert(*(row++)==k+mem.r[i], pattern_message);
841  }
842 
862  /*
863 
864  Aggregate pattern:
865 
866  x (x)
867  x(x)
868  xx(x)
869  x (x)
870  x(x)
871  xx(x)
872 
873  We are interested in the parts in parenthesis (target).
874 
875  Find out which rows in Q correspond to those targets
876  */
877 
878  // Lookup vector for target start and end
879  std::vector<casadi_int> target_start(nb), target_stop(nb);
880  for (casadi_int i=0;i<nb;++i) {
881  target_start[i] = (mem.r[i+1]-1)*aggregate.size1()+mem.r[i];
882  target_stop[i] = target_start[i]+mem.r[i+1]-mem.r[i];
883  }
884 
885  // Collect the nonzero indices in Q that that correspond to the target area
886  std::vector<casadi_int> q_nz;
887  // Triplet form for map_Q sparsity
888  std::vector<casadi_int> q_row, q_col;
889 
890  // Loop over Q's columns (decision variables)
891  for (casadi_int j=0; j<Q_.size2(); ++j) {
892  casadi_int block_index = 0;
893  // Loop over Q's rows
894  for (casadi_int k=Q_.colind(j); k<Q_.colind(j+1); ++k) {
895  casadi_int i = Q_.row(k);
896 
897  // Increment block_index if i runs ahead
898  while (i>target_stop[block_index] && block_index<nb-1) block_index++;
899 
900  if (i>=target_start[block_index] && i<target_stop[block_index]) {
901  // Got a nonzero in the target region
902  q_nz.push_back(k);
903  q_row.push_back(mem.r[block_index]+i-target_start[block_index]);
904  q_col.push_back(j);
905  }
906  }
907  }
908 
909  mem.map_Q = IM::triplet(q_row, q_col, q_nz, mem.r[nb], nx_);
910 
911  // Add the [X1;Z1;X2;Z2;...] part
912  mem.map_Q = horzcat(mem.map_Q, -IM::eye(mem.r[nb])).T();
913 
914  // Get maximum nonzero count of any column
915  casadi_int max_nnz = 0;
916  for (casadi_int i=0;i<mem.map_Q.size2();++i) {
917  max_nnz = std::max(max_nnz, mem.map_Q.colind(i+1)-mem.map_Q.colind(i));
918  }
919 
920  // ind/val size needs to cover max nonzero count
921  mem.indval_size = std::max(nx_, max_nnz);
922 
923  // Collect the indices for the P target area
924  mem.map_P.resize(mem.r[nb], -1);
925  for (casadi_int i=0;i<nb;++i) {
926  for (casadi_int k=P_.colind(mem.r[i+1]-1); k<P_.colind(mem.r[i+1]); ++k) {
927  casadi_int r = P_.row(k);
928  mem.map_P[r] = k;
929  }
930  }
931 
932  // ind/val size needs to cover blocksize
933  for (casadi_int i=0;i<nb;++i)
934  mem.indval_size = std::max(mem.indval_size, mem.r[i+1]-mem.r[i]);
935 
936  // Get the transpose and mapping
937  mem.AT = A_.transpose(mem.A_mapping);
938  }
939 
940  Dict Conic::get_stats(void* mem) const {
941  Dict stats = FunctionInternal::get_stats(mem);
942  auto *m = static_cast<ConicMemory*>(mem);
943 
944  stats["success"] = m->d_qp.success;
945  stats["unified_return_status"] = string_from_UnifiedReturnStatus(m->d_qp.unified_return_status);
946  stats["iter_count"] = m->d_qp.iter_count;
947  return stats;
948  }
949 
951  s.pack("Conic::SDPToSOCPMem::r", m.r);
952  s.pack("Conic::SDPToSOCPMem::AT", m.AT);
953  s.pack("Conic::SDPToSOCPMem::A_mapping", m.A_mapping);
954  s.pack("Conic::SDPToSOCPMem::map_Q", m.map_Q);
955  s.pack("Conic::SDPToSOCPMem::map_P", m.map_P);
956  s.pack("Conic::SDPToSOCPMem::indval_size", m.indval_size);
957  }
959  s.unpack("Conic::SDPToSOCPMem::r", m.r);
960  s.unpack("Conic::SDPToSOCPMem::AT", m.AT);
961  s.unpack("Conic::SDPToSOCPMem::A_mapping", m.A_mapping);
962  s.unpack("Conic::SDPToSOCPMem::map_Q", m.map_Q);
963  s.unpack("Conic::SDPToSOCPMem::map_P", m.map_P);
964  s.unpack("Conic::SDPToSOCPMem::indval_size", m.indval_size);
965  }
966 
969 
970  s.version("Conic", 6);
971  s.pack("Conic::discrete", discrete_);
972  s.pack("Conic::equality", equality_);
973  s.pack("Conic::print_problem", print_problem_);
974  s.pack("Conic::solver_version_check", solver_version_check_);
975  s.pack("Conic::sens_min_lam", sens_min_lam_);
976  s.pack("Conic::sens_linsol", sens_linsol_);
977  s.pack("Conic::sens_linsol_options", sens_linsol_options_);
978  s.pack("Conic::sens_force_equality", sens_force_equality_);
979 
980  s.pack("Conic::H", H_);
981  s.pack("Conic::A", A_);
982  s.pack("Conic::Q", Q_);
983  s.pack("Conic::P", P_);
984  s.pack("Conic::nx", nx_);
985  s.pack("Conic::na", na_);
986  s.pack("Conic::np", np_);
987  }
988 
992  }
993 
996  }
997 
999  int version = s.version("Conic", 1, 6);
1000  s.unpack("Conic::discrete", discrete_);
1001  if (version>=3) {
1002  s.unpack("Conic::equality", equality_);
1003  }
1004  s.unpack("Conic::print_problem", print_problem_);
1005  if (version>=4) {
1006  s.unpack("Conic::solver_version_check", solver_version_check_);
1007  } else {
1008  solver_version_check_ = true;
1009  }
1010  if (version>=5) {
1011  s.unpack("Conic::sens_min_lam", sens_min_lam_);
1012  s.unpack("Conic::sens_linsol", sens_linsol_);
1013  s.unpack("Conic::sens_linsol_options", sens_linsol_options_);
1014  } else {
1015  sens_min_lam_ = 0;
1016  sens_linsol_ = "qr";
1017  }
1018  if (version>=6) {
1019  s.unpack("Conic::sens_force_equality", sens_force_equality_);
1020  } else {
1021  sens_force_equality_ = false;
1022  }
1023  if (version==1) {
1024  s.unpack("Conic::error_on_fail", error_on_fail_);
1025  }
1026 
1027  s.unpack("Conic::H", H_);
1028  s.unpack("Conic::A", A_);
1029  set_qp_prob();
1030  s.unpack("Conic::Q", Q_);
1031  s.unpack("Conic::P", P_);
1032  s.unpack("Conic::nx", nx_);
1033  s.unpack("Conic::na", na_);
1034  s.unpack("Conic::np", np_);
1035  }
1036 
1037  void Conic::set_qp_prob() {
1038  p_qp_.sp_a = A_;
1039  p_qp_.sp_h = H_;
1040  casadi_qp_setup(&p_qp_);
1041  }
1042 
1045  g.local("d_qp", "struct casadi_qp_data");
1046  g.local("p_qp", "struct casadi_qp_prob");
1047 
1048  g << "d_qp.prob = &p_qp;\n";
1049  g << "p_qp.sp_a = " << g.sparsity(A_) << ";\n";
1050  g << "p_qp.sp_h = " << g.sparsity(H_) << ";\n";
1051  g << "casadi_qp_setup(&p_qp);\n";
1052  g << "casadi_qp_set_work(&d_qp, &arg, &res, &iw, &w);\n";
1053 
1054 
1055  g << "d_qp.h = arg[" << CONIC_H << "];\n";
1056  g << "d_qp.g = arg[" << CONIC_G << "];\n";
1057  g << "d_qp.a = arg[" << CONIC_A << "];\n";
1058  g << "d_qp.lbx = arg[" << CONIC_LBX << "];\n";
1059  g << "d_qp.ubx = arg[" << CONIC_UBX << "];\n";
1060  g << "d_qp.lba = arg[" << CONIC_LBA << "];\n";
1061  g << "d_qp.uba = arg[" << CONIC_UBA << "];\n";
1062  g << "d_qp.x0 = arg[" << CONIC_X0 << "];\n";
1063  g << "d_qp.lam_x0 = arg[" << CONIC_LAM_X0 << "];\n";
1064  g << "d_qp.lam_a0 = arg[" << CONIC_LAM_A0 << "];\n";
1065 
1066  g << "d_qp.f = res[" << CONIC_COST << "];\n";
1067  g << "d_qp.x = res[" << CONIC_X << "];\n";
1068  g << "d_qp.lam_x = res[" << CONIC_LAM_X << "];\n";
1069  g << "d_qp.lam_a = res[" << CONIC_LAM_A << "];\n";
1070  }
1071 
1072 } // namespace casadi
Helper class for C code generation.
void local(const std::string &name, const std::string &type, const std::string &ref="")
Declare a local variable.
std::string sparsity(const Sparsity &sp, bool canonical=true)
void add_auxiliary(Auxiliary f, const std::vector< std::string > &inst={"casadi_real"})
Add a built-in auxiliary function.
Internal class.
Definition: conic_impl.hpp:44
Dict sens_linsol_options_
Definition: conic_impl.hpp:204
static const Options options_
Options.
Definition: conic_impl.hpp:83
casadi_int nx_
Number of decision variables.
Definition: conic_impl.hpp:210
bool is_a(const std::string &type, bool recursive) const override
Check if the function is of a particular type.
Definition: conic.cpp:616
void finalize() override
Finalize the object creation.
Definition: conic.cpp:483
double get_default_in(casadi_int ind) const override
Get default input value.
Definition: conic.cpp:558
virtual int solve(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const =0
Solve the QP.
int init_mem(void *mem) const override
Initalize memory block.
Definition: conic.cpp:491
casadi_int np_
The shape of psd constraint matrix.
Definition: conic_impl.hpp:216
Sparsity get_sparsity_in(casadi_int i) override
Sparsities of function inputs and outputs.
Definition: conic.cpp:355
casadi_int na_
The number of constraints (counting both equality and inequality) == A.size1()
Definition: conic_impl.hpp:213
static std::map< std::string, Plugin > solvers_
Collection of solvers.
Definition: conic_impl.hpp:126
virtual void generateNativeCode(std::ostream &file) const
Definition: conic.cpp:546
virtual void check_inputs(const double *lbx, const double *ubx, const double *lba, const double *uba) const
Check if the numerical values of the supplied bounds make sense.
Definition: conic.cpp:528
Sparsity H_
Problem structure.
Definition: conic_impl.hpp:207
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: conic.cpp:730
void init(const Dict &opts) override
Initialize.
Definition: conic.cpp:429
void deserialize(DeserializingStream &s, SDPToSOCPMem &m)
Definition: conic.cpp:958
std::vector< bool > discrete_
Options.
Definition: conic_impl.hpp:197
std::vector< bool > equality_
Definition: conic_impl.hpp:198
Conic(const std::string &name, const std::map< std::string, Sparsity > &st)
Definition: conic.cpp:272
Sparsity get_sparsity_out(casadi_int i) override
Sparsities of function inputs and outputs.
Definition: conic.cpp:380
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
~Conic() override=0
Definition: conic.cpp:525
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: conic.cpp:967
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
Definition: conic.cpp:498
virtual bool psd_support() const
Can psd constraints be treated.
Definition: conic_impl.hpp:152
bool sens_force_equality_
Definition: conic_impl.hpp:202
bool solver_version_check_
Definition: conic_impl.hpp:200
double sens_min_lam_
Definition: conic_impl.hpp:201
Dict get_stats(void *mem) const override
Get all statistics.
Definition: conic.cpp:940
std::string sens_linsol_
Definition: conic_impl.hpp:203
static const std::string infix_
Infix.
Definition: conic_impl.hpp:133
casadi_qp_prob< double > p_qp_
Definition: conic_impl.hpp:47
void serialize_type(SerializingStream &s) const override
Serialize type information.
Definition: conic.cpp:989
void qp_codegen_body(CodeGenerator &g) const
Generate code for the function body.
Definition: conic.cpp:1043
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: conic.cpp:651
void sdp_to_socp_init(SDPToSOCPMem &mem) const
SDP to SOCP conversion initialization.
Definition: conic.cpp:809
virtual bool integer_support() const
Can discrete variables be treated.
Definition: conic_impl.hpp:149
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const final
Solve the QP.
Definition: conic.cpp:572
void serialize(SerializingStream &s, const SDPToSOCPMem &m) const
Definition: conic.cpp:950
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
static std::unique_ptr< std::ostream > ofstream_ptr(const std::string &path, std::ios_base::openmode mode=std::ios_base::out)
Definition: filesystem.cpp:115
Internal class for Function.
Dict get_stats(void *mem) const override
Get all statistics.
void init(const Dict &opts) override
Initialize.
void finalize() override
Finalize the object creation.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
virtual const std::vector< MX > mx_in() const
Get function input(s) and output(s)
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.
static const Options options_
Options.
void serialize_type(SerializingStream &s) const override
Serialize type information.
virtual const std::vector< MX > mx_out() const
Get function input(s) and output(s)
void setup(void *mem, const double **arg, double **res, casadi_int *iw, double *w) const
Set the (persistent and temporary) work vectors.
static std::string string_from_UnifiedReturnStatus(UnifiedReturnStatus status)
std::vector< std::string > name_out_
std::vector< std::string > name_in_
Input and output scheme.
Function object.
Definition: function.hpp:126
Function forward(casadi_int nfwd) const
Get a function computing nfwd forward directional derivatives.
Definition: function.cpp:1324
FunctionInternal * get() const
Definition: function.cpp:505
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
Function reverse(casadi_int nadj) const
Get a function computing nadj reverse (adjoint) directional derivatives.
Definition: function.cpp:1332
static Function create(FunctionInternal *node)
Create from node.
Definition: function.cpp:488
const SX sx_in(casadi_int iind) const
Create fresh symbols with the names and sparsity patterns of the inputs.
Definition: function.cpp:1749
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
const std::vector< std::string > & name_out() const
Get the names of all outputs, in order.
Definition: function.cpp:1117
casadi_int size2() const
Get the second dimension (i.e. number of columns)
static MX sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
const casadi_int * colind() const
Get the sparsity pattern. See the Sparsity class for details.
bool is_null() const
Is a null pointer?
MX - Matrix expression.
Definition: mx.hpp:145
static MX blockcat(const std::vector< std::vector< MX > > &v)
Definition: mx.cpp:1254
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 nan(const Sparsity &sp)
Create a constant with all nonzeros NaN.
Definition: mx.cpp:599
Matrix< Scalar > T() const
Transpose the matrix.
static Matrix< casadi_int > triplet(const std::vector< casadi_int > &row, const std::vector< casadi_int > &col, const Matrix< casadi_int > &d)
Construct a sparse matrix from triplet form (row indices, column indices, values)
void print_dense(std::ostream &stream, bool truncate=true) const
Print as a dense matrix, one row per line, structural zeros as 00.
static Matrix< casadi_int > eye(casadi_int n)
Create an n-by-n identity matrix.
static bool has_plugin(const std::string &pname, bool verbose=false)
Check if a plugin is available or can be loaded.
static Conic * 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.
virtual void deps_version_check(const std::string &stage) const
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?
virtual int init_mem(void *mem) const
Initalize memory block.
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
virtual std::string class_name() const =0
Readable name of the internal class.
General sparsity class.
Definition: sparsity.hpp:200
casadi_int size1() const
Number of rows.
Definition: sparsity.cpp:124
casadi_int scc(std::vector< casadi_int > &index, std::vector< casadi_int > &offset) const
Strongly connected components of the directed graph of a square pattern.
Definition: sparsity.cpp:714
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 transpose(std::vector< casadi_int > &mapping, bool invert_mapping=false) const
Transposed pattern together with the reordering of the nonzeros.
Definition: sparsity.cpp:392
casadi_int size2() const
Number of columns.
Definition: sparsity.cpp:128
const casadi_int * row() const
Get a reference to row-vector,.
Definition: sparsity.cpp:166
static Sparsity scalar(bool dense_scalar=true)
Create a 1-by-1 sparsity pattern.
Definition: sparsity.hpp:454
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
Definition: sparsity.cpp:170
bool is_symmetric() const
Check whether the pattern equals its transpose.
Definition: sparsity.cpp:319
Function qpsol(const std::string &name, const std::string &solver, const SXDict &qp, const Dict &opts)
Definition: conic.cpp:261
std::string conic_option_info(const std::string &name, const std::string &op)
Get the documentation string of an option of a QP solver plugin.
Definition: conic.cpp:612
Function conic(const std::string &name, const std::string &solver, const SpDict &qp, const Dict &opts)
Definition: conic.cpp:44
std::string conic_option_type(const std::string &name, const std::string &op)
Get the type of an option of a QP solver plugin.
Definition: conic.cpp:608
bool has_conic(const std::string &name)
Check if a QP solver plugin is available.
Definition: conic.cpp:32
std::string doc_conic(const std::string &name)
Get the documentation string of a QP solver plugin.
Definition: conic.cpp:40
std::vector< std::string > conic_options(const std::string &name)
Get all options of a QP solver plugin.
Definition: conic.cpp:604
std::vector< std::string > conic_out()
Get the output scheme of QP solvers.
Definition: conic.cpp:66
casadi_int conic_n_in()
Get the number of QP solver inputs.
Definition: conic.cpp:102
casadi_int conic_n_out()
Get the number of QP solver outputs.
Definition: conic.cpp:106
void load_conic(const std::string &name)
Explicitly load a QP solver plugin.
Definition: conic.cpp:36
std::vector< std::string > conic_in()
Get the input scheme of QP solvers.
Definition: conic.cpp:60
void conic_debug(const Function &f, const std::string &filename)
Generate native code in the interfaced language for debugging.
Definition: conic.cpp:49
std::vector< std::string > nlpsol_in()
Get the input scheme of NLP solvers.
Definition: nlpsol.cpp:284
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
@ 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
std::vector< casadi_int > range(casadi_int start, casadi_int stop, casadi_int step, casadi_int len)
Range function.
@ 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)
@ 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
ConicInput
Input arguments of a QP problem.
Definition: conic.hpp:807
@ CONIC_UBA
dense, (nc x 1), default +inf
Definition: conic.hpp:818
@ CONIC_X0
dense, (n x 1), initial guess, default 0
Definition: conic.hpp:824
@ CONIC_A
The matrix A: sparse, (nc x n) - product with x must be dense.
Definition: conic.hpp:814
@ CONIC_G
The vector g: dense, (n x 1)
Definition: conic.hpp:812
@ CONIC_Q
The matrix Q: sparse symmetric, (np^2 x n)
Definition: conic.hpp:830
@ CONIC_LBA
dense, (nc x 1), default -inf
Definition: conic.hpp:816
@ CONIC_UBX
dense, (n x 1), default +inf
Definition: conic.hpp:822
@ CONIC_H
Definition: conic.hpp:810
@ CONIC_LAM_A0
dense, (nc x 1), initial guess for the multipliers of the linear constraints, default 0
Definition: conic.hpp:828
@ CONIC_LBX
dense, (n x 1), default -inf
Definition: conic.hpp:820
@ CONIC_NUM_IN
Definition: conic.hpp:833
@ CONIC_LAM_X0
dense, (n x 1), initial guess for the multipliers of the simple bounds, default 0
Definition: conic.hpp:826
@ CONIC_P
The matrix P: sparse symmetric, (np x np)
Definition: conic.hpp:832
double if_else(double x, double y, double z)
Definition: calculus.hpp:296
@ OT_BOOLVECTOR
std::map< std::string, SX > SXDict
Definition: sx_fwd.hpp:40
void extract_from_dict_inplace(Dict &d, const std::string &key, T &value)
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
const double inf
infinity
Definition: calculus.hpp:50
std::map< std::string, Sparsity > SpDict
Definition: sparsity.hpp:6350
T dot(const std::vector< T > &a, const std::vector< T > &b)
static Function conic_kkt_res(const Sparsity &sp_h, const Sparsity &sp_a)
Definition: conic.cpp:642
std::ostream & uout()
Function qpsol_nlp(const std::string &name, const std::string &solver, const std::map< std::string, M > &qp, const Dict &opts)
Definition: conic.cpp:111
std::string filename(const std::string &path)
Definition: ghc.cpp:55
@ SOLVER_RET_SUCCESS
@ SOLVER_RET_UNKNOWN
ConicOutput
Output arguments of an QP Solver.
Definition: conic.hpp:836
@ CONIC_X
The primal solution.
Definition: conic.hpp:838
@ CONIC_LAM_A
Definition: conic.hpp:843
@ CONIC_COST
The optimal cost.
Definition: conic.hpp:840
@ CONIC_LAM_X
The dual solution corresponding to simple bounds; same sign convention.
Definition: conic.hpp:845
@ CONIC_NUM_OUT
Definition: conic.hpp:846
casadi_qp_data< double > d_qp
Definition: conic_impl.hpp:39
SDP to SOCP conversion memory.
Definition: conic_impl.hpp:219
std::vector< casadi_int > r
Definition: conic_impl.hpp:221
std::vector< casadi_int > A_mapping
Definition: conic_impl.hpp:225
std::vector< casadi_int > map_P
Definition: conic_impl.hpp:231
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
const T1 * h
Definition: casadi_qp.hpp:64
const T1 * lba
Definition: casadi_qp.hpp:64
casadi_int iter_count
Definition: casadi_qp.hpp:61
const T1 * lbx
Definition: casadi_qp.hpp:64
const T1 * uba
Definition: casadi_qp.hpp:64
const T1 * ubx
Definition: casadi_qp.hpp:64
const T1 * lam_x0
Definition: casadi_qp.hpp:64
const T1 * x0
Definition: casadi_qp.hpp:64
UnifiedReturnStatus unified_return_status
Definition: casadi_qp.hpp:57
const T1 * g
Definition: casadi_qp.hpp:64
const T1 * lam_a0
Definition: casadi_qp.hpp:64
const T1 * a
Definition: casadi_qp.hpp:64
const casadi_int * sp_h
Definition: casadi_qp.hpp:31
const casadi_int * sp_a
Definition: casadi_qp.hpp:31