ooqp_interface.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "ooqp_interface.hpp"
27 #include "casadi/core/casadi_misc.hpp"
28 
29 // OOQP headers
30 #include <cQpGenSparse.h>
31 #include <Status.h>
32 #include <GondzioSolver.h>
33 
34 // A variable that controls the printlevel of OOQP
35 // This is the only possible way to access it using the C++ interface
36 extern casadi_int gOoqpPrintLevel;
37 
38 namespace casadi {
39 
40  extern "C"
41  int CASADI_CONIC_OOQP_EXPORT
42  casadi_register_conic_ooqp(Conic::Plugin* plugin) {
43  plugin->creator = OoqpInterface::creator;
44  plugin->name = "ooqp";
45  plugin->doc = OoqpInterface::meta_doc.c_str();
46  plugin->version = CASADI_VERSION;
47  plugin->options = &OoqpInterface::options_;
48  plugin->deserialize = &OoqpInterface::deserialize;
49  return 0;
50  }
51 
52  extern "C"
53  void CASADI_CONIC_OOQP_EXPORT casadi_load_conic_ooqp() {
55  }
56 
57  OoqpInterface::OoqpInterface(const std::string& name,
58  const std::map<std::string, Sparsity>& st)
59  : Conic(name, st) {
60  }
61 
63  clear_mem();
64  }
65 
67  = {{&Conic::options_},
68  {{"print_level",
69  {OT_INT,
70  "Print level. OOQP listens to print_level 0, 10 and 100"}},
71  {"mutol",
72  {OT_DOUBLE,
73  "tolerance as provided with setMuTol to OOQP"}},
74  {"artol",
75  {OT_DOUBLE,
76  "tolerance as provided with setArTol to OOQP"}}
77  }
78  };
79 
80  void OoqpInterface::init(const Dict& opts) {
81  // Initialize the base classes
82  Conic::init(opts);
83 
84  // Default options
85  print_level_ = 0;
86  mutol_ = 1e-8;
87  artol_ = 1e-8;
88 
89  // Read options
90  for (auto&& op : opts) {
91  if (op.first=="print_level") {
92  print_level_ = op.second;
93  } else if (op.first=="mutol") {
94  mutol_ = op.second;
95  } else if (op.first=="artol") {
96  artol_ = op.second;
97  }
98  }
99 
100  // Allocate memory for problem
101  nQ_ = H_.nnz_upper();
102  nA_ = nnz_in(CONIC_A);
103  nH_ = nnz_in(CONIC_H);
104  spAT_ = A_.T();
105 
106  // Allocate work vectors
107  alloc_w(nx_, true); // g
108  alloc_w(nx_, true); // lbx
109  alloc_w(nx_, true); // ubx
110  alloc_w(na_, true); // lba
111  alloc_w(na_, true); // uba
112  alloc_w(nH_, true); // H
113  alloc_w(nA_, true); // A
114  alloc_w(nx_, true); // c_
115  alloc_w(na_, true); // bA_
116  alloc_w(nx_, true); // xlow_
117  alloc_w(nx_, true); // xupp_
118  alloc_w(na_, true); // clow_
119  alloc_w(na_, true); // cupp_
120  alloc_w(nx_, true); // x_
121  alloc_w(nx_, true); // gamma_
122  alloc_w(nx_, true); // phi_
123  alloc_w(na_, true); // y_
124  alloc_w(na_, true); // z_
125  alloc_w(na_, true); // lambda_
126  alloc_w(na_, true); // pi_
127  alloc_iw(nx_, true); // ixlow_
128  alloc_iw(nx_, true); // ixupp_
129  alloc_iw(na_, true); // iclow_
130  alloc_iw(na_, true); // icupp_
131  alloc_w(nQ_, true); // dQ_
132  alloc_w(nA_, true); // dA_
133  alloc_w(nA_, true); // dC_
134  alloc_iw(nQ_, true); // irowQ_
135  alloc_iw(nQ_, true); // jcolQ_
136  alloc_iw(nA_, true); // irowA_
137  alloc_iw(nA_, true); // jcolA_
138  alloc_iw(nA_, true); // irowC_
139  alloc_iw(nA_, true); // jcolC_
140  alloc_iw(nx_, true); // x_index_
141  alloc_iw(na_, true); // c_index_
142  alloc_w(nx_, true); // p_
143  alloc_w(nA_, true); // AT
144  alloc_iw(na_); // casadi_trans
145  }
146 
148  solve(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
149  auto m = static_cast<OoqpMemory*>(mem);
150  m->return_status = -1;
151 
152  // Get problem data
153  double* g=w; w += nx_;
154  casadi_copy(arg[CONIC_G], nx_, g);
155  double* lbx=w; w += nx_;
156  casadi_copy(arg[CONIC_LBX], nx_, lbx);
157  double* ubx=w; w += nx_;
158  casadi_copy(arg[CONIC_UBX], nx_, ubx);
159  double* lba=w; w += na_;
160  casadi_copy(arg[CONIC_LBA], na_, lba);
161  double* uba=w; w += na_;
162  casadi_copy(arg[CONIC_UBA], na_, uba);
163  double* H=w; w += nnz_in(CONIC_H);
164  casadi_copy(arg[CONIC_H], nnz_in(CONIC_H), H);
165  double* A=w; w += nnz_in(CONIC_A);
166  casadi_copy(arg[CONIC_A], nnz_in(CONIC_A), A);
167 
168  // Temporary memory
169  double* c_ = w; w += nx_;
170  double* bA_ = w; w += na_;
171  double* xlow_ = w; w += nx_;
172  double* xupp_ = w; w += nx_;
173  double* clow_ = w; w += na_;
174  double* cupp_ = w; w += na_;
175  double* x_ = w; w += nx_;
176  double* gamma_ = w; w += nx_;
177  double* phi_ = w; w += nx_;
178  double* y_ = w; w += na_;
179  double* z_ = w; w += na_;
180  double* lambda_ = w; w += na_;
181  double* pi_ = w; w += na_;
182  char* ixlow_ = reinterpret_cast<char*>(iw); iw += nx_;
183  char* ixupp_ = reinterpret_cast<char*>(iw); iw += nx_;
184  char* iclow_ = reinterpret_cast<char*>(iw); iw += na_;
185  char* icupp_ = reinterpret_cast<char*>(iw); iw += na_;
186  double* dQ_ = w; w += nQ_;
187  double* dA_ = w; w += nA_;
188  double* dC_ = w; w += nA_;
189  int* irowQ_ = reinterpret_cast<int*>(iw); iw += nQ_;
190  int* jcolQ_ = reinterpret_cast<int*>(iw); iw += nQ_;
191  int* irowA_ = reinterpret_cast<int*>(iw); iw += nA_;
192  int* jcolA_ = reinterpret_cast<int*>(iw); iw += nA_;
193  int* irowC_ = reinterpret_cast<int*>(iw); iw += nA_;
194  int* jcolC_ = reinterpret_cast<int*>(iw); iw += nA_;
195  int* x_index_ = reinterpret_cast<int*>(iw); iw += nx_;
196  int* c_index_ = reinterpret_cast<int*>(iw); iw += na_;
197  double* p_ = w; w += nx_;
198  double* AT = w; w += nA_;
199 
200  // Parameter contribution to the objective
201  double objParam = 0;
202 
203  // Get the number of free variables and their types
204  casadi_int nx = 0, np=0;
205  for (casadi_int i=0; i<nx_; ++i) {
206  if (lbx[i]==ubx[i]) {
207  // Save parameter
208  p_[np] = lbx[i];
209 
210  // Add contribution to objective
211  objParam += g[i]*p_[np];
212 
213  // Save index
214  x_index_[i] = -1-np++;
215 
216  } else {
217  // True free variable
218  if (lbx[i]==-std::numeric_limits<double>::infinity()) {
219  xlow_[nx] = 0;
220  ixlow_[nx] = 0;
221  } else {
222  xlow_[nx] = lbx[i];
223  ixlow_[nx] = 1;
224  }
225  if (ubx[i]==std::numeric_limits<double>::infinity()) {
226  xupp_[nx] = 0;
227  ixupp_[nx] = 0;
228  } else {
229  xupp_[nx] = ubx[i];
230  ixupp_[nx] = 1;
231  }
232  c_[nx] = g[i];
233  x_index_[i] = nx++;
234  }
235  }
236 
237  // Get quadratic term
238  const casadi_int* H_colind = H_.colind();
239  const casadi_int* H_row = H_.row();
240  casadi_int nnzQ = 0;
241  // Loop over the columns of the quadratic term
242  for (casadi_int cc=0; cc<nx_; ++cc) {
243 
244  // Loop over nonzero elements of the column
245  for (casadi_int el=H_colind[cc]; el<H_colind[cc+1]; ++el) {
246 
247  // Only upper triangular part
248  casadi_int rr=H_row[el];
249  if (rr>cc) break;
250 
251  // Get variable types
252  casadi_int icc=x_index_[cc];
253  casadi_int irr=x_index_[rr];
254 
255  if (icc<0) {
256  if (irr<0) {
257  // Add contribution to objective
258  objParam += icc==irr ? H[el]*sq(p_[-1-icc])/2 : H[el]*p_[-1-irr]*p_[-1-icc];
259  } else {
260  // Add contribution to gradient term
261  c_[irr] += H[el]*p_[-1-icc];
262  }
263  } else {
264  if (irr<0) {
265  // Add contribution to gradient term
266  c_[icc] += H[el]*p_[-1-irr];
267  } else {
268  // Add to sparsity pattern
269  irowQ_[nnzQ] = icc; // row-major --> indices swapped
270  jcolQ_[nnzQ] = irr; // row-major --> indices swapped
271  dQ_[nnzQ++] = H[el];
272  }
273  }
274  }
275  }
276 
277  // Get the transpose of the sparsity pattern to be able to loop over the constraints
278  casadi_trans(A, A_, AT, spAT_, iw);
279 
280  // Loop over constraints
281  const casadi_int* A_colind = A_.colind();
282  const casadi_int* A_row = A_.row();
283  const casadi_int* AT_colind = spAT_.colind();
284  const casadi_int* AT_row = spAT_.row();
285  casadi_int nA=0, nC=0, /*mz=0, */ nnzA=0, nnzC=0;
286  for (casadi_int j=0; j<na_; ++j) {
287  if (lba[j] == -std::numeric_limits<double>::infinity() &&
288  uba[j] == std::numeric_limits<double>::infinity()) {
289  // Redundant constraint
290  c_index_[j] = 0;
291  } else if (lba[j]==uba[j]) {
292  // Equality constraint
293  bA_[nA] = lba[j];
294 
295  // Add to A
296  for (casadi_int el=AT_colind[j]; el<AT_colind[j+1]; ++el) {
297  casadi_int i=AT_row[el];
298  if (x_index_[i]<0) {
299  // Parameter
300  bA_[nA] -= AT[el]*p_[-x_index_[i]-1];
301  } else {
302  // Free variable
303  irowA_[nnzA] = nA;
304  jcolA_[nnzA] = x_index_[i];
305  dA_[nnzA++] = AT[el];
306  }
307  }
308  c_index_[j] = -1-nA++;
309  } else {
310  // Inequality constraint
311  if (lba[j]==-std::numeric_limits<double>::infinity()) {
312  clow_[nC] = 0;
313  iclow_[nC] = 0;
314  } else {
315  clow_[nC] = lba[j];
316  iclow_[nC] = 1;
317  }
318  if (uba[j]==std::numeric_limits<double>::infinity()) {
319  cupp_[nC] = 0;
320  icupp_[nC] = 0;
321  } else {
322  cupp_[nC] = uba[j];
323  icupp_[nC] = 1;
324  }
325 
326  // Add to C
327  for (casadi_int el=AT_colind[j]; el<AT_colind[j+1]; ++el) {
328  casadi_int i=AT_row[el];
329  if (x_index_[i]<0) {
330  // Parameter
331  if (iclow_[nC]==1) clow_[nC] -= AT[el]*p_[-x_index_[i]-1];
332  if (icupp_[nC]==1) cupp_[nC] -= AT[el]*p_[-x_index_[i]-1];
333  } else {
334  // Free variable
335  irowC_[nnzC] = nC;
336  jcolC_[nnzC] = x_index_[i];
337  dC_[nnzC++] = AT[el];
338  }
339  }
340  c_index_[j] = 1+nC++;
341  }
342  }
343 
344  // Reset the solution
345  casadi_clear(x_, nx_);
346  casadi_clear(gamma_, nx_);
347  casadi_clear(phi_, nx_);
348  casadi_clear(y_, na_);
349  casadi_clear(z_, na_);
350  casadi_clear(lambda_, na_);
351  casadi_clear(pi_, na_);
352 
353  // Solve the QP
354  double objectiveValue;
355 
356  int ierr;
357  if (false) { // Use C interface NOLINT
358  // TODO(jgillis): Change to conicvehb, see OOQP users guide
359  qpsolvesp(c_, nx,
360  irowQ_, nnzQ, jcolQ_, dQ_,
361  xlow_, ixlow_,
362  xupp_, ixupp_,
363  irowA_, nnzA, jcolA_, dA_,
364  bA_, nA,
365  irowC_, nnzC, jcolC_, dC_,
366  clow_, nC, iclow_,
367  cupp_, icupp_,
368  x_, gamma_, phi_,
369  y_,
370  z_, lambda_, pi_,
371  &objectiveValue,
372  print_level_, &ierr);
373  } else { // Use C++ interface
374  ierr=0;
375  // All OOQP related allocations in evaluate
376 
377  std::vector<int> krowQ(nx+1);
378  std::vector<int> krowA(nA+1);
379  std::vector<int> krowC(nC+1);
380 
381  //casadi_int status_code = 0;
382  makehb(irowQ_, nnzQ, get_ptr(krowQ), nx, &ierr);
383  if (ierr == 0) makehb(irowA_, nnzA, get_ptr(krowA), nA, &ierr);
384  if (ierr == 0) makehb(irowC_, nnzC, get_ptr(krowC), nC, &ierr);
385 
386  if (ierr == 0) {
387  QpGenContext ctx;
388 
389  QpGenHbGondzioSetup(c_, nx, get_ptr(krowQ), jcolQ_, dQ_,
390  xlow_, ixlow_, xupp_, ixupp_,
391  get_ptr(krowA), nA, jcolA_, dA_, bA_,
392  get_ptr(krowC), nC, jcolC_, dC_,
393  clow_, iclow_, cupp_, icupp_, &ctx,
394  &ierr);
395  if (ierr == 0) {
396  Solver* solver = static_cast<Solver *>(ctx.solver);
397  gOoqpPrintLevel = print_level_;
398  solver->monitorSelf();
399  solver->setMuTol(mutol_);
400  solver->setMuTol(mutol_);
401 
402  QpGenFinish(&ctx, x_, gamma_, phi_,
403  y_, z_, lambda_, pi_,
404  &objectiveValue, &ierr);
405  }
406 
407  QpGenCleanup(&ctx);
408  }
409  }
410 
411  m->return_status = ierr;
412  m->d_qp.success = ierr==SUCCESSFUL_TERMINATION;
413  if (ierr==MAX_ITS_EXCEEDED) m->d_qp.unified_return_status = SOLVER_RET_LIMITED;
414  if (ierr>0) {
415  casadi_warning("Unable to solve problem: " + str(errFlag(ierr)));
416  } else if (ierr<0) {
417  casadi_error("Fatal error: " + str(errFlag(ierr)));
418  }
419 
420  // Retrieve eliminated decision variables
421  for (casadi_int i=nx_-1; i>=0; --i) {
422  casadi_int ii = x_index_[i];
423  if (ii<0) {
424  x_[i] = p_[-1-ii];
425  } else {
426  x_[i] = x_[ii];
427  }
428  }
429 
430  // Retreive eliminated dual variables (linear bounds)
431  for (casadi_int j=na_-1; j>=0; --j) {
432  casadi_int jj = c_index_[j];
433  if (jj==0) {
434  lambda_[j] = 0;
435  } else if (jj<0) {
436  lambda_[j] = -y_[-1-jj];
437  } else {
438  lambda_[j] = pi_[-1+jj]-lambda_[-1+jj];
439  }
440  }
441 
442  // Retreive eliminated dual variables (simple bounds)
443  for (casadi_int i=nx_-1; i>=0; --i) {
444  casadi_int ii = x_index_[i];
445  if (ii<0) {
446  // The dual solution for the fixed parameters follows from the KKT conditions
447  gamma_[i] = -g[i];
448  for (casadi_int el=H_colind[i]; el<H_colind[i+1]; ++el) {
449  casadi_int j=H_row[el];
450  gamma_[i] -= H[el]*x_[j];
451  }
452  for (casadi_int el=A_colind[i]; el<A_colind[i+1]; ++el) {
453  casadi_int j=A_row[el];
454  gamma_[i] -= A[el]*lambda_[j];
455  }
456  } else {
457  gamma_[i] = phi_[ii]-gamma_[ii];
458  }
459  }
460 
461  // Save optimal cost
462  if (res[CONIC_COST]) *res[CONIC_COST] = objectiveValue + objParam;
463 
464  // Save primal solution
465  casadi_copy(x_, nx_, res[CONIC_X]);
466 
467  // Save dual solution (linear bounds)
468  casadi_copy(lambda_, na_, res[CONIC_LAM_A]);
469 
470  // Save dual solution (simple bounds)
471  casadi_copy(gamma_, nx_, res[CONIC_LAM_X]);
472  return 0;
473  }
474 
475  const char* OoqpInterface::errFlag(int flag) {
476  // Find the error
477  //const char* msg;
478  switch (flag) {
479  case SUCCESSFUL_TERMINATION: return "SUCCESSFUL_TERMINATION";
480  case NOT_FINISHED: return "NOT_FINISHED";
481  case MAX_ITS_EXCEEDED: return "MAX_ITS_EXCEEDED";
482  case INFEASIBLE: return "INFEASIBLE";
483  case UNKNOWN: return "UNKNOWN";
484  default: return "N/A";
485  }
486  }
487 
488  Dict OoqpInterface::get_stats(void* mem) const {
489  Dict stats = Conic::get_stats(mem);
490 
491  auto m = static_cast<OoqpMemory*>(mem);
492  stats["return_status"] = m->return_status;
493  return stats;
494  }
495 
496  std::string OoqpInterface::printBounds(const std::vector<double>& b,
497  const std::vector<char>& ib, casadi_int n, const char *sign) {
498  std::stringstream ss;
499  ss << "[";
500  for (casadi_int i=0; i<n; ++i) {
501  if (i!=0) ss << ", ";
502  if (ib[i]==0) {
503  ss << sign << "inf";
504  } else {
505  ss << b[i];
506  }
507  }
508  ss << "]";
509  return ss.str();
510  }
511 
513  s.version("OoqpInterface", 1);
514  s.unpack("OoqpInterface::spAT", spAT_);
515  s.unpack("OoqpInterface::nQ", nQ_);
516  s.unpack("OoqpInterface::nH", nH_);
517  s.unpack("OoqpInterface::nA", nA_);
518  s.unpack("OoqpInterface::print_level", print_level_);
519  s.unpack("OoqpInterface::mutol", mutol_);
520  s.unpack("OoqpInterface::artol", artol_);
521  }
522 
525  s.version("OoqpInterface", 1);
526  s.pack("OoqpInterface::spAT", spAT_);
527  s.pack("OoqpInterface::nQ", nQ_);
528  s.pack("OoqpInterface::nH", nH_);
529  s.pack("OoqpInterface::nA", nA_);
530  s.pack("OoqpInterface::print_level", print_level_);
531  s.pack("OoqpInterface::mutol", mutol_);
532  s.pack("OoqpInterface::artol", artol_);
533  }
534 
535 } // namespace casadi
Internal class.
Definition: conic_impl.hpp:44
static const Options options_
Options.
Definition: conic_impl.hpp:83
casadi_int nx_
Number of decision variables.
Definition: conic_impl.hpp:169
casadi_int na_
The number of constraints (counting both equality and inequality) == A.size1()
Definition: conic_impl.hpp:172
Sparsity H_
Problem structure.
Definition: conic_impl.hpp:166
void init(const Dict &opts) override
Initialize.
Definition: conic.cpp:412
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: conic.cpp:738
Dict get_stats(void *mem) const override
Get all statistics.
Definition: conic.cpp:711
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.
casadi_int nnz_in() const
Number of input/output nonzeros.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
static const char * errFlag(int flag)
Throw error.
static Conic * creator(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new QP Solver.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize into MX.
Dict get_stats(void *mem) const override
Get all statistics.
static std::string printBounds(const std::vector< double > &b, const std::vector< char > &ib, casadi_int n, const char *sign)
Print an OOQP bounds vector.
~OoqpInterface() override
Destructor.
int solve(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Solve the QP.
static const std::string meta_doc
A documentation string.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
OoqpInterface(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new Solver.
void init(const Dict &opts) override
Initialize.
static const Options options_
Options.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
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.
Sparsity T() const
Transpose the matrix.
Definition: sparsity.cpp:394
casadi_int nnz_upper(bool strictly=false) const
Number of non-zeros in the upper triangular half,.
Definition: sparsity.cpp:356
const casadi_int * row() const
Get a reference to row-vector,.
Definition: sparsity.cpp:164
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
Definition: sparsity.cpp:168
The casadi namespace.
Definition: archiver.cpp:28
T sq(const T &x)
Definition: calculus.hpp:331
@ CONIC_UBA
dense, (nc x 1)
Definition: conic.hpp:181
@ CONIC_A
The matrix A: sparse, (nc x n) - product with x must be dense.
Definition: conic.hpp:177
@ CONIC_G
The vector g: dense, (n x 1)
Definition: conic.hpp:175
@ CONIC_LBA
dense, (nc x 1)
Definition: conic.hpp:179
@ CONIC_UBX
dense, (n x 1)
Definition: conic.hpp:185
@ CONIC_H
Definition: conic.hpp:173
@ CONIC_LBX
dense, (n x 1)
Definition: conic.hpp:183
double sign(double x)
Sign function, note that sign(nan) == nan.
Definition: calculus.hpp:264
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
int CASADI_CONIC_OOQP_EXPORT casadi_register_conic_ooqp(Conic::Plugin *plugin)
void casadi_clear(T1 *x, casadi_int n)
CLEAR: x <- 0.
void casadi_trans(const T1 *x, const casadi_int *sp_x, T1 *y, const casadi_int *sp_y, casadi_int *tmp)
TRANS: y <- trans(x) , w work vector (length >= rows x)
void CASADI_CONIC_OOQP_EXPORT casadi_load_conic_ooqp()
@ SOLVER_RET_LIMITED
@ CONIC_X
The primal solution.
Definition: conic.hpp:201
@ CONIC_LAM_A
The dual solution corresponding to linear bounds.
Definition: conic.hpp:205
@ CONIC_COST
The optimal cost.
Definition: conic.hpp:203
@ CONIC_LAM_X
The dual solution corresponding to simple bounds.
Definition: conic.hpp:207
Options metadata for a class.
Definition: options.hpp:40