piqp_interface.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2014 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * K.U. 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 "piqp_interface.hpp"
27 #include "casadi/core/casadi_misc.hpp"
28 
29 
30 using namespace std;
31 namespace casadi {
32 
33  extern "C"
34  int CASADI_CONIC_PIQP_EXPORT
35  casadi_register_conic_piqp(Conic::Plugin* plugin) {
36  plugin->creator = PiqpInterface::creator;
37  plugin->name = "piqp";
38  plugin->doc = PiqpInterface::meta_doc.c_str();
39  plugin->version = CASADI_VERSION;
40  plugin->options = &PiqpInterface::options_;
41  plugin->deserialize = &PiqpInterface::deserialize;
42  return 0;
43  }
44 
45  extern "C"
46  void CASADI_CONIC_PIQP_EXPORT casadi_load_conic_piqp() {
47  Conic::registerPlugin(casadi_register_conic_piqp);
48  }
49 
50  // Map a kkt_solver option string to the PIQP enum
51  inline piqp::KKTSolver kkt_solver_from_string(const std::string& s) {
52  if (s == "dense_cholesky") return piqp::KKTSolver::dense_cholesky;
53  if (s == "sparse_ldlt") return piqp::KKTSolver::sparse_ldlt;
54  if (s == "sparse_ldlt_eq_cond") return piqp::KKTSolver::sparse_ldlt_eq_cond;
55  if (s == "sparse_ldlt_ineq_cond") return piqp::KKTSolver::sparse_ldlt_ineq_cond;
56  if (s == "sparse_ldlt_cond") return piqp::KKTSolver::sparse_ldlt_cond;
57  if (s == "sparse_multistage") return piqp::KKTSolver::sparse_multistage;
58  casadi_error("Unknown kkt_solver '" + s + "'. Choose one of: dense_cholesky, "
59  "sparse_ldlt, sparse_ldlt_eq_cond, sparse_ldlt_ineq_cond, sparse_ldlt_cond, "
60  "sparse_multistage.");
61  return piqp::KKTSolver::sparse_ldlt;
62  }
63 
64  PiqpInterface::PiqpInterface(const std::string& name,
65  const std::map<std::string, Sparsity>& st)
66  : Conic(name, st) {
67  // Default to the sparse backend (PIQP's struct default is dense_cholesky)
68  settings_.kkt_solver = piqp::KKTSolver::sparse_ldlt;
69  }
70 
72  clear_mem();
73  }
74 
76  = {{&Conic::options_},
77  {{"piqp",
78  {OT_DICT,
79  "const Options to be passed to piqp."}},
80  }
81  };
82 
83  void PiqpInterface::init(const Dict& opts) {
84  // Initialize the base classes
85  Conic::init(opts);
86 
87  // Read options
88  for (auto&& op : opts) {
89  if (op.first=="piqp") {
90  const Dict& opts = op.second;
91  for (auto&& op : opts) {
92  if (op.first == "rho_init") {
93  settings_.rho_init = op.second;
94  } else if (op.first == "delta_init") {
95  settings_.delta_init = op.second;
96  } else if (op.first == "eps_abs") {
97  settings_.eps_abs = op.second;
98  } else if (op.first == "eps_rel") {
99  settings_.eps_rel = op.second;
100  } else if (op.first == "check_duality_gap") {
101  settings_.check_duality_gap = op.second;
102  } else if (op.first == "eps_duality_gap_abs") {
103  settings_.eps_duality_gap_abs = op.second;
104  } else if (op.first == "eps_duality_gap_rel") {
105  settings_.eps_duality_gap_rel = op.second;
106  } else if (op.first == "reg_lower_limit") {
107  settings_.reg_lower_limit = op.second;
108  } else if (op.first == "reg_finetune_lower_limit") {
109  settings_.reg_finetune_lower_limit = op.second;
110  } else if (op.first == "reg_finetune_primal_update_threshold") {
111  settings_.reg_finetune_primal_update_threshold = static_cast<piqp::isize>(
112  op.second.to_int());
113  } else if (op.first == "reg_finetune_dual_update_threshold") {
114  settings_.reg_finetune_dual_update_threshold = static_cast<piqp::isize>(
115  op.second.to_int());
116  } else if (op.first == "max_iter") {
117  settings_.max_iter = static_cast<piqp::isize>(op.second.to_int());
118  } else if (op.first == "max_factor_retires") {
119  settings_.max_factor_retires = static_cast<piqp::isize>(
120  op.second.to_int());
121  } else if (op.first == "preconditioner_scale_cost") {
122  settings_.preconditioner_scale_cost = op.second;
123  } else if (op.first == "preconditioner_iter") {
124  settings_.preconditioner_iter = static_cast<piqp::isize>(
125  op.second.to_int());
126  } else if (op.first == "tau") {
127  settings_.tau = op.second;
128  } else if (op.first == "iterative_refinement_always_enabled") {
129  settings_.iterative_refinement_always_enabled = op.second;
130  } else if (op.first == "iterative_refinement_eps_abs") {
131  settings_.iterative_refinement_eps_abs = op.second;
132  } else if (op.first == "iterative_refinement_eps_rel") {
133  settings_.iterative_refinement_eps_rel = op.second;
134  } else if (op.first == "iterative_refinement_max_iter") {
135  settings_.iterative_refinement_max_iter = static_cast<piqp::isize>(
136  op.second.to_int());
137  } else if (op.first == "iterative_refinement_min_improvement_rate") {
138  settings_.iterative_refinement_min_improvement_rate = op.second;
139  } else if (op.first == "iterative_refinement_static_regularization_eps") {
140  settings_.iterative_refinement_static_regularization_eps = op.second;
141  } else if (op.first == "iterative_refinement_static_regularization_rel") {
142  settings_.iterative_refinement_static_regularization_rel = op.second;
143  } else if (op.first == "verbose") {
144  settings_.verbose = op.second;
145  } else if (op.first == "compute_timings") {
146  settings_.compute_timings = op.second;
147  } else if (op.first == "kkt_solver") {
148  settings_.kkt_solver = kkt_solver_from_string(op.second.to_string());
149  } else {
150  casadi_error("Unrecognised PIQP option '" + op.first + "'.");
151  }
152  }
153  }
154  }
155 
156  nnzH_ = H_.nnz();
157  nnzA_ = A_.nnz()+nx_;
158 
159  alloc_w(nx_, true); // g
160  alloc_w(nx_, true); // lbx
161  alloc_w(nx_, true); // ubx
162  alloc_w(na_, true); // lba
163  alloc_w(na_, true); // uba
164  alloc_w(nnzH_, true); // H
165  alloc_w(nnzA_, true); // A
166  }
167 
169  // dense_cholesky uses the dense backend; all sparse_* solvers use the sparse one
170  sparse_backend_ = settings_.kkt_solver != piqp::KKTSolver::dense_cholesky;
171  Conic::finalize();
172  }
173 
174  int PiqpInterface::init_mem(void* mem) const {
175  if (Conic::init_mem(mem)) return 1;
176  auto m = static_cast<PiqpMemory*>(mem);
177 
178  m->tripletList.reserve(2 * H_.nnz());
179  m->tripletListEq.reserve(na_);
180 
181  m->g_vector.resize(nx_);
182  m->uba_vector.resize(na_);
183  m->lba_vector.resize(na_);
184  m->ubx_vector.resize(nx_);
185  m->lbx_vector.resize(nx_);
186  m->eq_b_vector.resize(na_);
187 
188  m->add_stat("preprocessing");
189  m->add_stat("solver");
190  m->add_stat("postprocessing");
191  return 0;
192  }
193 
195  solve(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
196  typedef Eigen::Triplet<double> TripletT;
197 
198  auto m = static_cast<PiqpMemory*>(mem);
199  m->fstats.at("preprocessing").tic();
200 
201  // Get problem data
202  double* g=w; w += nx_;
203  casadi_copy(arg[CONIC_G], nx_, g);
204  double* lbx=w; w += nx_;
205  casadi_copy(arg[CONIC_LBX], nx_, lbx);
206  double* ubx=w; w += nx_;
207  casadi_copy(arg[CONIC_UBX], nx_, ubx);
208  double* lba=w; w += na_;
209  casadi_copy(arg[CONIC_LBA], na_, lba);
210  double* uba=w; w += na_;
211  casadi_copy(arg[CONIC_UBA], na_, uba);
212  double* H=w; w += nnz_in(CONIC_H);
213  casadi_copy(arg[CONIC_H], nnz_in(CONIC_H), H);
214  double* A=w; w += nnz_in(CONIC_A);
215  casadi_copy(arg[CONIC_A], nnz_in(CONIC_A), A);
216 
217  m->g_vector = Eigen::Map<const Eigen::VectorXd>(g, nx_);
218  m->uba_vector = Eigen::Map<Eigen::VectorXd>(uba, na_);
219  m->lba_vector = Eigen::Map<Eigen::VectorXd>(lba, na_);
220  m->ubx_vector = Eigen::Map<Eigen::VectorXd>(ubx, nx_);
221  m->lbx_vector = Eigen::Map<Eigen::VectorXd>(lbx, nx_);
222 
223  // Split constraints into equality (lba == uba) and inequality (lba != uba)
224  // PIQP 0.6.0+ supports double-sided inequality constraints natively: h_l <= Gx <= h_u
225  const Eigen::Array<bool, Eigen::Dynamic, 1>
226  is_equality = (m->uba_vector.array() == m->lba_vector.array()).eval();
227 
228  // Count equalities and inequalities, track mapping from original to new indices
229  std::vector<unsigned int> number_of_prev_equality(na_, 0);
230  std::vector<unsigned int> number_of_prev_inequality(na_, 0);
231  std::vector<double> tmp_eq_vector;
232  std::vector<double> tmp_ineq_lb_vector;
233  std::vector<double> tmp_ineq_ub_vector;
234 
235  for (std::size_t k = 1; k < static_cast<std::size_t>(na_); ++k) {
236  if (is_equality[k-1]) {
237  number_of_prev_equality[k] = number_of_prev_equality[k-1] + 1;
238  number_of_prev_inequality[k] = number_of_prev_inequality[k-1];
239  } else {
240  number_of_prev_equality[k] = number_of_prev_equality[k-1];
241  number_of_prev_inequality[k] = number_of_prev_inequality[k-1] + 1;
242  }
243  }
244 
245  for (casadi_int k = 0; k < na_; ++k) {
246  if (is_equality[k]) {
247  tmp_eq_vector.push_back(m->lba_vector[k]);
248  } else {
249  tmp_ineq_lb_vector.push_back(m->lba_vector[k]);
250  tmp_ineq_ub_vector.push_back(m->uba_vector[k]);
251  }
252  }
253 
254  m->eq_b_vector.resize(tmp_eq_vector.size());
255  if (tmp_eq_vector.size() > 0) {
256  m->eq_b_vector = Eigen::Map<Eigen::VectorXd>(
257  get_ptr(tmp_eq_vector), tmp_eq_vector.size());
258  }
259 
260  // For inequalities, use double-sided bounds directly (PIQP 0.6.0+ feature)
261  Eigen::VectorXd ineq_lb_vector(tmp_ineq_lb_vector.size());
262  Eigen::VectorXd ineq_ub_vector(tmp_ineq_ub_vector.size());
263  if (tmp_ineq_lb_vector.size() > 0) {
264  ineq_lb_vector = Eigen::Map<Eigen::VectorXd>(
265  get_ptr(tmp_ineq_lb_vector), tmp_ineq_lb_vector.size());
266  ineq_ub_vector = Eigen::Map<Eigen::VectorXd>(
267  get_ptr(tmp_ineq_ub_vector), tmp_ineq_ub_vector.size());
268  }
269 
270  std::size_t n_eq = m->eq_b_vector.size();
271  std::size_t n_ineq = tmp_ineq_lb_vector.size();
272 
273  // Convert H_ from casadi::Sparsity to Eigen::SparseMatrix (misuse tripletList)
274  H_.get_triplet(m->row, m->col);
275  for (int k=0; k<H_.nnz(); ++k) {
276  m->tripletList.push_back(PiqpMemory::TripletT(
277  static_cast<double>(m->row[k]),
278  static_cast<double>(m->col[k]),
279  static_cast<double>(H[k])));
280  }
281  Eigen::SparseMatrix<double> H_spa(H_.size1(), H_.size2());
282  H_spa.setFromTriplets(m->tripletList.begin(), m->tripletList.end());
283  m->tripletList.clear();
284 
285  // Convert A_ from casadi Sparsity to Eigen::SparseMatrix and split
286  // in- and equality constraints into different matrices
287  m->tripletList.reserve(A_.nnz());
288  A_.get_triplet(m->row, m->col);
289  for (int k=0; k<A_.nnz(); ++k) {
290  // Detect equality constraint
291  if (is_equality[m->row[k]]) {
292  m->tripletListEq.push_back(TripletT(
293  static_cast<double>(number_of_prev_equality[m->row[k]]),
294  static_cast<double>(m->col[k]),
295  static_cast<double>(A[k])));
296  } else {
297  // Inequality constraint - add to G matrix (PIQP uses h_l <= Gx <= h_u)
298  m->tripletList.push_back(TripletT(
299  static_cast<double>(number_of_prev_inequality[m->row[k]]),
300  static_cast<double>(m->col[k]),
301  static_cast<double>(A[k])));
302  }
303  }
304 
305  // Build equality constraint matrix A
306  Eigen::SparseMatrix<double> A_spa(n_eq, nx_);
307  A_spa.setFromTriplets(m->tripletListEq.begin(), m->tripletListEq.end());
308  m->tripletListEq.clear();
309 
310  // Build inequality constraint matrix G (for h_l <= Gx <= h_u)
311  Eigen::SparseMatrix<double> G_spa(n_ineq, nx_);
312  G_spa.setFromTriplets(m->tripletList.begin(), m->tripletList.end());
313  m->tripletList.clear();
314 
315  m->fstats.at("preprocessing").toc();
316 
317  // Solve Problem using PIQP 0.6.0+ API with double-sided inequality constraints
318  // Problem form: min 0.5*x'*P*x + c'*x s.t. Ax = b, h_l <= Gx <= h_u, x_l <= x <= x_u
319  m->fstats.at("solver").tic();
320  if (sparse_backend_) {
321  piqp::SparseSolver<double> solver;
322  solver.settings() = settings_;
323 
324  solver.setup(
325  H_spa, m->g_vector,
326  A_spa, m->eq_b_vector,
327  G_spa, ineq_lb_vector, ineq_ub_vector,
328  m->lbx_vector, m->ubx_vector);
329  m->status = solver.solve();
330 
331  m->results_x = std::make_unique<Eigen::VectorXd>(solver.result().x);
332  m->results_y = std::make_unique<Eigen::VectorXd>(solver.result().y);
333  // Inequality duals: z_u for upper bounds, z_l for lower bounds
334  // Combined dual for lba <= Ax <= uba is z_u - z_l
335  m->results_z = std::make_unique<Eigen::VectorXd>(
336  solver.result().z_u - solver.result().z_l);
337  // Box constraint duals: z_bu for upper, z_bl for lower
338  m->results_lam_x = std::make_unique<Eigen::VectorXd>(
339  solver.result().z_bu - solver.result().z_bl);
340  m->objValue = solver.result().info.primal_obj;
341  } else {
342  piqp::DenseSolver<double> solver;
343  solver.settings() = settings_;
344  solver.setup(
345  Eigen::MatrixXd(H_spa), m->g_vector,
346  Eigen::MatrixXd(A_spa), m->eq_b_vector,
347  Eigen::MatrixXd(G_spa), ineq_lb_vector, ineq_ub_vector,
348  m->lbx_vector, m->ubx_vector);
349  m->status = solver.solve();
350 
351  m->results_x = std::make_unique<Eigen::VectorXd>(solver.result().x);
352  m->results_y = std::make_unique<Eigen::VectorXd>(solver.result().y);
353  m->results_z = std::make_unique<Eigen::VectorXd>(
354  solver.result().z_u - solver.result().z_l);
355  m->results_lam_x = std::make_unique<Eigen::VectorXd>(
356  solver.result().z_bu - solver.result().z_bl);
357  m->objValue = solver.result().info.primal_obj;
358  }
359  m->fstats.at("solver").toc();
360 
361  // Post-processing to retrieve the results
362  m->fstats.at("postprocessing").tic();
363  casadi_copy(m->results_x->data(), nx_, res[CONIC_X]);
364  casadi_copy(m->results_lam_x->data(), nx_, res[CONIC_LAM_X]);
365 
366  // Copy back the multipliers.
367  // CasADi has LAM_X (multipliers for box constraints on x) and
368  // LAM_A (multipliers for in- and equality constraints Ax).
369  // PIQP returns: results_y (equality multipliers), results_z (inequality multipliers)
370  if (n_ineq + n_eq > 0) {
371  Eigen::VectorXd lam_a(na_);
372 
373  for (casadi_int k = 0; k < na_; ++k) {
374  if (is_equality[k]) {
375  lam_a[k] = m->results_y->coeff(number_of_prev_equality[k]);
376  } else {
377  lam_a[k] = m->results_z->coeff(number_of_prev_inequality[k]);
378  }
379  }
380  casadi_copy(lam_a.data(), na_, res[CONIC_LAM_A]);
381  }
382 
383  if (res[CONIC_COST]) {
384  *res[CONIC_COST] = m->objValue;
385  }
386 
387  m->d_qp.success = m->status == piqp::Status::PIQP_SOLVED;
388  if (m->d_qp.success) {
389  m->d_qp.unified_return_status = SOLVER_RET_SUCCESS;
390  } else {
391  if (m->status == piqp::Status::PIQP_MAX_ITER_REACHED) {
392  m->d_qp.unified_return_status = SOLVER_RET_LIMITED;
393  } else { // primal or dual infeasibility
394  m->d_qp.unified_return_status = SOLVER_RET_UNKNOWN;
395  }
396  }
397  m->fstats.at("postprocessing").toc();
398 
399  return 0;
400  }
401 
402  Dict PiqpInterface::get_stats(void* mem) const {
403  Dict stats = Conic::get_stats(mem);
404  auto m = static_cast<PiqpMemory*>(mem);
405 
406  stats["return_status"] = piqp::status_to_string(m->status);
407  return stats;
408  }
409 
411  }
412 
414  }
415 
417  std::size_t tmp;
418  s.version("PiqpInterface", 1);
419  s.unpack("PiqpInterface::nnzH", nnzH_);
420  s.unpack("PiqpInterface::nnzA", nnzA_);
421  s.unpack("PiqpInterface::settings::rho_init", settings_.rho_init);
422  s.unpack("PiqpInterface::settings::delta_init", settings_.delta_init);
423  s.unpack("PiqpInterface::settings::eps_abs", settings_.eps_abs);
424  s.unpack("PiqpInterface::settings::eps_rel", settings_.eps_rel);
425  s.unpack("PiqpInterface::settings::check_duality_gap", settings_.check_duality_gap);
426  s.unpack("PiqpInterface::settings::eps_duality_gap_abs", settings_.eps_duality_gap_abs);
427  s.unpack("PiqpInterface::settings::eps_duality_gap_rel", settings_.eps_duality_gap_rel);
428  s.unpack("PiqpInterface::settings::reg_lower_limit", settings_.reg_lower_limit);
429  s.unpack("PiqpInterface::settings::reg_finetune_lower_limit",
430  settings_.reg_finetune_lower_limit);
431  s.unpack("PiqpInterface::settings::reg_finetune_primal_update_threshold", tmp);
432  settings_.reg_finetune_primal_update_threshold = tmp;
433  s.unpack("PiqpInterface::settings::reg_finetune_dual_update_threshold", tmp);
434  settings_.reg_finetune_dual_update_threshold = tmp;
435  s.unpack("PiqpInterface::settings::max_iter", tmp);
436  settings_.max_iter = tmp;
437  s.unpack("PiqpInterface::settings::max_factor_retires", tmp);
438  settings_.max_factor_retires = tmp;
439  s.unpack("PiqpInterface::settings::preconditioner_scale_cost",
440  settings_.preconditioner_scale_cost);
441  s.unpack("PiqpInterface::settings::preconditioner_iter", tmp);
442  settings_.preconditioner_iter = tmp;
443  s.unpack("PiqpInterface::settings::tau", settings_.tau);
444  s.unpack("PiqpInterface::settings::iterative_refinement_always_enabled",
445  settings_.iterative_refinement_always_enabled);
446  s.unpack("PiqpInterface::settings::iterative_refinement_eps_abs",
447  settings_.iterative_refinement_eps_abs);
448  s.unpack("PiqpInterface::settings::iterative_refinement_eps_rel",
449  settings_.iterative_refinement_eps_rel);
450  s.unpack("PiqpInterface::settings::iterative_refinement_max_iter", tmp);
451  settings_.iterative_refinement_max_iter = tmp;
452  s.unpack("PiqpInterface::settings::iterative_refinement_min_improvement_rate",
453  settings_.iterative_refinement_min_improvement_rate);
454  s.unpack("PiqpInterface::settings::iterative_refinement_static_regularization_eps",
455  settings_.iterative_refinement_static_regularization_eps);
456  s.unpack("PiqpInterface::settings::iterative_refinement_static_regularization_rel",
457  settings_.iterative_refinement_static_regularization_rel);
458  s.unpack("PiqpInterface::settings::verbose", settings_.verbose);
459  s.unpack("PiqpInterface::settings::compute_timings", settings_.compute_timings);
460  std::string kkt_solver;
461  s.unpack("PiqpInterface::settings::kkt_solver", kkt_solver);
462  settings_.kkt_solver = kkt_solver_from_string(kkt_solver);
463  }
464 
466  std::size_t tmp;
467 
469  s.version("PiqpInterface", 1);
470  s.pack("PiqpInterface::nnzH", nnzH_);
471  s.pack("PiqpInterface::nnzA", nnzA_);
472  s.pack("PiqpInterface::settings::rho_init", settings_.rho_init);
473  s.pack("PiqpInterface::settings::delta_init", settings_.delta_init);
474  s.pack("PiqpInterface::settings::eps_abs", settings_.eps_abs);
475  s.pack("PiqpInterface::settings::eps_rel", settings_.eps_rel);
476  s.pack("PiqpInterface::settings::check_duality_gap", settings_.check_duality_gap);
477  s.pack("PiqpInterface::settings::eps_duality_gap_abs", settings_.eps_duality_gap_abs);
478  s.pack("PiqpInterface::settings::eps_duality_gap_rel", settings_.eps_duality_gap_rel);
479  s.pack("PiqpInterface::settings::reg_lower_limit", settings_.reg_lower_limit);
480  s.pack("PiqpInterface::settings::reg_finetune_lower_limit",
481  settings_.reg_finetune_lower_limit);
482  tmp = settings_.reg_finetune_primal_update_threshold;
483  s.pack("PiqpInterface::settings::reg_finetune_primal_update_threshold", tmp);
484  tmp = settings_.reg_finetune_dual_update_threshold;
485  s.pack("PiqpInterface::settings::reg_finetune_dual_update_threshold", tmp);
486  tmp = settings_.max_iter;
487  s.pack("PiqpInterface::settings::max_iter", tmp);
488  tmp = settings_.max_factor_retires;
489  s.pack("PiqpInterface::settings::max_factor_retires", tmp);
490  s.pack("PiqpInterface::settings::preconditioner_scale_cost",
491  settings_.preconditioner_scale_cost);
492  tmp = settings_.preconditioner_iter;
493  s.pack("PiqpInterface::settings::preconditioner_iter", tmp);
494  s.pack("PiqpInterface::settings::tau", settings_.tau);
495  s.pack("PiqpInterface::settings::iterative_refinement_always_enabled",
496  settings_.iterative_refinement_always_enabled);
497  s.pack("PiqpInterface::settings::iterative_refinement_eps_abs",
498  settings_.iterative_refinement_eps_abs);
499  s.pack("PiqpInterface::settings::iterative_refinement_eps_rel",
500  settings_.iterative_refinement_eps_rel);
501  tmp = settings_.iterative_refinement_max_iter;
502  s.pack("PiqpInterface::settings::iterative_refinement_max_iter", tmp);
503  s.pack("PiqpInterface::settings::iterative_refinement_min_improvement_rate",
504  settings_.iterative_refinement_min_improvement_rate);
505  s.pack("PiqpInterface::settings::iterative_refinement_static_regularization_eps",
506  settings_.iterative_refinement_static_regularization_eps);
507  s.pack("PiqpInterface::settings::iterative_refinement_static_regularization_rel",
508  settings_.iterative_refinement_static_regularization_rel);
509  s.pack("PiqpInterface::settings::verbose", settings_.verbose);
510  s.pack("PiqpInterface::settings::compute_timings", settings_.compute_timings);
511  s.pack("PiqpInterface::settings::kkt_solver",
512  std::string(piqp::kkt_solver_to_string(settings_.kkt_solver)));
513  }
514 
515 } // 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:173
void finalize() override
Finalize the object creation.
Definition: conic.cpp:458
int init_mem(void *mem) const override
Initalize memory block.
Definition: conic.cpp:466
casadi_int na_
The number of constraints (counting both equality and inequality) == A.size1()
Definition: conic_impl.hpp:176
Sparsity H_
Problem structure.
Definition: conic_impl.hpp:170
void init(const Dict &opts) override
Initialize.
Definition: conic.cpp:415
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: conic.cpp:753
Dict get_stats(void *mem) const override
Get all statistics.
Definition: conic.cpp:726
int eval(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const final
Solve the QP.
Definition: conic.cpp:547
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
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.
~PiqpInterface() override
Destructor.
piqp::Settings< double > settings_
static const Options options_
const Options
int solve(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Solve the QP.
PiqpInterface(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new Solver.
void init(const Dict &opts) override
Initialize.
Dict get_stats(void *mem) const override
Get all statistics.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
int init_mem(void *mem) const override
Initalize memory block.
void finalize() override
Finalize.
void clear_mem()
Clear all memory (called from destructor)
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
casadi_int size1() const
Get the number of rows.
Definition: sparsity.cpp:124
casadi_int nnz() const
Get the number of (structural) non-zeros.
Definition: sparsity.cpp:148
casadi_int size2() const
Get the number of columns.
Definition: sparsity.cpp:128
void get_triplet(std::vector< casadi_int > &row, std::vector< casadi_int > &col) const
Get the sparsity in sparse triplet format.
Definition: sparsity.cpp:385
The casadi namespace.
Definition: archiver.cpp:28
@ 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
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
piqp::KKTSolver kkt_solver_from_string(const std::string &s)
void CASADI_CONIC_PIQP_EXPORT casadi_load_conic_piqp()
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_PIQP_EXPORT casadi_register_conic_piqp(Conic::Plugin *plugin)
@ SOLVER_RET_LIMITED
@ SOLVER_RET_SUCCESS
@ SOLVER_RET_UNKNOWN
@ 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
Definition: sx_elem.cpp:508
Options metadata for a class.
Definition: options.hpp:40
PiqpMemory()
Constructor.
std::vector< TripletT > tripletList
Eigen::Triplet< double > TripletT
~PiqpMemory()
Destructor.
std::map< std::string, FStats > fstats