daqp_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 #include "daqp_interface.hpp"
26 #include "casadi/core/nlp_tools.hpp"
27 
28 #include <daqp_runtime_str.h>
29 namespace casadi {
30 
31  extern "C"
32  int CASADI_CONIC_DAQP_EXPORT
33  casadi_register_conic_daqp(Conic::Plugin* plugin) {
34  plugin->creator = DaqpInterface::creator;
35  plugin->name = "daqp";
36  plugin->doc = DaqpInterface::meta_doc.c_str();
37  plugin->version = CASADI_VERSION;
38  plugin->options = &DaqpInterface::options_;
39  plugin->deserialize = &DaqpInterface::deserialize;
40  return 0;
41  }
42 
43  extern "C"
44  void CASADI_CONIC_DAQP_EXPORT casadi_load_conic_daqp() {
46  }
47 
48 
49  DaqpInterface::DaqpInterface(const std::string& name,
50  const std::map<std::string, Sparsity>& st)
51  : Conic(name, st) {
52 
53  has_refcount_ = true;
54  }
55 
57  = {{&Conic::options_},
58  {{"daqp",
59  {OT_DICT,
60  "Options to be passed to Daqp."
61  }},
62  }
63  };
64 
65  void DaqpInterface::init(const Dict& opts) {
66  // Call the init method of the base class
67  Conic::init(opts);
68 
69  // Read user options
70  for (auto&& op : opts) {
71  if (op.first=="daqp") {
72  opts_ = op.second;
73  }
74  }
75 
76  // Initialize read-only members of class that don't require saving
77  // since they can be derived from other read-only members
78  if (!discrete_.empty()) {
79  integrality_.resize(nx_);
80  copy_vector(discrete_, integrality_);
81  } else {
82  integrality_.clear();
83  }
84 
85  set_daqp_prob();
86 
87  // Allocate memory
88  casadi_int sz_arg, sz_res, sz_w, sz_iw;
89  casadi_daqp_work(&p_, &sz_arg, &sz_res, &sz_iw, &sz_w);
90 
91  alloc_arg(sz_arg, true);
92  alloc_res(sz_res, true);
93  alloc_iw(sz_iw, true);
94  alloc_w(sz_w, true);
95  }
96 
97  void codegen_local(CodeGenerator& g, const std::string& name, const std::vector<int>& v) {
98  std::string n = name + "[]";
99  g.local(n, "static const int");
100  std::stringstream init;
101  init << "{";
102  for (casadi_int i=0;i<v.size();++i) {
103  init << v[i];
104  if (i<v.size()-1) init << ", ";
105  }
106  // ISO C forbids empty initializer braces
107  if (v.empty()) init << "0";
108  init << "}";
109  g.init_local(n, init.str());
110  }
111 
112 
114  g << "p.qp = &p_qp;\n";
115  g << "daqp_default_settings(&p.settings);\n";
116  if (!discrete_.empty()) {
117  codegen_local(g, "integrality", integrality_);
118  }
119  if (discrete_.empty()) {
120  g << "p.integrality = 0;\n";
121  } else {
122  g << "p.integrality = integrality;\n";
123  }
124 
125  for (auto&& op : opts_) {
126  if (op.first=="primal_tol") {
127  g << "p.settings.primal_tol = " << g.constant(op.second.to_double()) << ";\n";
128  } else if (op.first=="dual_tol") {
129  g << "p.settings.dual_tol = " << g.constant(op.second.to_double()) << ";\n";
130  } else if (op.first=="zero_tol") {
131  g << "p.settings.zero_tol = " << g.constant(op.second.to_double()) << ";\n";
132  } else if (op.first=="pivot_tol") {
133  g << "p.settings.pivot_tol = " << g.constant(op.second.to_double()) << ";\n";
134  } else if (op.first=="progress_tol") {
135  g << "p.settings.progress_tol = " << g.constant(op.second.to_double()) << ";\n";
136  } else if (op.first=="cycle_tol") {
137  g << "p.settings.cycle_tol = " << op.second.to_int() << ";\n";
138  } else if (op.first=="iter_limit") {
139  g << "p.settings.iter_limit = " << op.second.to_int() << ";\n";
140  } else if (op.first=="fval_bound") {
141  g << "p.settings.fval_bound = " << g.constant(op.second.to_double()) << ";\n";
142  } else if (op.first=="eps_prox") {
143  g << "p.settings.eps_prox = " << g.constant(op.second.to_double()) << ";\n";
144  } else if (op.first=="eta_prox") {
145  g << "p.settings.eta_prox = " << g.constant(op.second.to_double()) << ";\n";
146  } else if (op.first=="rho_soft") {
147  g << "p.settings.rho_soft = " << g.constant(op.second.to_double()) << ";\n";
148  } else if (op.first=="rel_subopt") {
149  g << "p.settings.rel_subopt = " << g.constant(op.second.to_double()) << ";\n";
150  } else if (op.first=="abs_subopt") {
151  g << "p.settings.abs_subopt = " << g.constant(op.second.to_double()) << ";\n";
152  } else {
153  casadi_error("Unknown option '" + op.first + "'.");
154  }
155  }
156 
157  g << "casadi_daqp_setup(&p);\n";
158  }
159 
161  g << "casadi_daqp_init_mem(&" + codegen_mem(g) + ");\n";
162  g << "return 0;\n";
163  }
164 
166  g << "casadi_daqp_free_mem(&" + codegen_mem(g) + ");\n";
167  }
168 
170  p_.qp = &p_qp_;
171 
172  DAQPSettings* settings = &p_.settings;
173 
174  daqp_default_settings(settings);
175 
176  for (auto&& op : opts_) {
177  if (op.first=="primal_tol") {
178  settings->primal_tol = op.second.to_double();
179  } else if (op.first=="dual_tol") {
180  settings->dual_tol = op.second.to_double();
181  } else if (op.first=="zero_tol") {
182  settings->zero_tol = op.second.to_double();
183  } else if (op.first=="pivot_tol") {
184  settings->pivot_tol = op.second.to_double();
185  } else if (op.first=="progress_tol") {
186  settings->progress_tol = op.second.to_double();
187  } else if (op.first=="cycle_tol") {
188  settings->cycle_tol = op.second.to_int();
189  } else if (op.first=="iter_limit") {
190  settings->iter_limit = op.second.to_int();
191  } else if (op.first=="fval_bound") {
192  settings->fval_bound = op.second.to_double();
193  } else if (op.first=="eps_prox") {
194  settings->eps_prox = op.second.to_double();
195  } else if (op.first=="eta_prox") {
196  settings->eta_prox = op.second.to_double();
197  } else if (op.first=="rho_soft") {
198  settings->rho_soft = op.second.to_double();
199  } else if (op.first=="rel_subopt") {
200  settings->rel_subopt = op.second.to_double();
201  } else if (op.first=="abs_subopt") {
202  settings->abs_subopt = op.second.to_double();
203  } else {
204  casadi_error("Unknown option '" + op.first + "'.");
205  }
206  }
207  p_.integrality = get_ptr(integrality_);
208 
209  casadi_daqp_setup(&p_);
210  }
211 
212  int DaqpInterface::init_mem(void* mem) const {
213  if (Conic::init_mem(mem)) return 1;
214  if (!mem) return 1;
215  auto m = static_cast<DaqpMemory*>(mem);
216  casadi_daqp_init_mem(&m->d);
217 
218  m->add_stat("preprocessing");
219  m->add_stat("solver");
220  m->add_stat("postprocessing");
221 
222  return 0;
223  }
224 
225  void DaqpInterface::free_mem(void* mem) const {
226  auto m = static_cast<DaqpMemory*>(mem);
227  casadi_daqp_free_mem(&m->d);
228  delete static_cast<DaqpMemory*>(mem);
229  }
230 
232  void DaqpInterface::set_work(void* mem, const double**& arg, double**& res,
233  casadi_int*& iw, double*& w) const {
234 
235  auto m = static_cast<DaqpMemory*>(mem);
236 
237  Conic::set_work(mem, arg, res, iw, w);
238 
239  m->d.prob = &p_;
240  m->d.qp = &m->d_qp;
241 
242  casadi_daqp_set_work(&m->d, &arg, &res, &iw, &w);
243 
244  }
245 
247  solve(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
248  auto m = static_cast<DaqpMemory*>(mem);
249 
250  // Statistics
251  m->fstats.at("solver").tic();
252 
253  casadi_daqp_solve(&m->d, arg, res, iw, w);
254  m->fstats.at("solver").toc();
255 
256  return 0;
257  }
258 
260  clear_mem();
261  }
262 
264  qp_codegen_body(g);
268  g.add_include("daqp/api.h");
269  g.add_include("stdio.h");
270 
271  g.auxiliaries << g.sanitize_source(daqp_runtime_str, {"casadi_real"});
272 
273  g.local("d", "struct casadi_daqp_data*");
274  g.init_local("d", "&" + codegen_mem(g));
275  g.local("p", "struct casadi_daqp_prob");
276  set_daqp_prob(g);
277 
278  // Setup data structure (corresponds to set_work)
279  g << "d->prob = &p;\n";
280  g << "d->qp = &d_qp;\n";
281  g << "casadi_daqp_set_work(d, &arg, &res, &iw, &w);\n";
282 
283  g << "casadi_daqp_solve(d, arg, res, iw, w);\n";
284 
285  g << "if (!d_qp.success) {\n";
286  if (error_on_fail_) {
287  g << "return -1000;\n";
288  } else {
289  g << "return -1;\n";
290  }
291  g << "}\n";
292  g << "return 0;\n";
293  }
294 
295  Dict DaqpInterface::get_stats(void* mem) const {
296  Dict stats = Conic::get_stats(mem);
297  auto m = static_cast<DaqpMemory*>(mem);
298  stats["return_status"] = m->d.return_status;
299  stats["bnb_nodecount"] = m->d.nodecount;
300  stats["bnb_itercount"] = m->d.bnb_itercount;
301  return stats;
302  }
303 
305  s.version("DaqpInterface", 1);
306  s.unpack("DaqpInterface::opts", opts_);
307  set_daqp_prob();
308  }
309 
312 
313  s.version("DaqpInterface", 1);
314  s.pack("DaqpInterface::opts", opts_);
315  }
316 
317 } // end namespace casadi
Helper class for C code generation.
std::string constant(const std::vector< casadi_int > &v)
Represent an array constant; adding it when new.
void local(const std::string &name, const std::string &type, const std::string &ref="")
Declare a local variable.
void init_local(const std::string &name, const std::string &def)
Specify the default value for a local variable.
std::string sanitize_source(const std::string &src, const std::vector< std::string > &inst, bool add_shorthand=true)
Sanitize source files for codegen.
void add_include(const std::string &new_include, bool relative_path=false, const std::string &use_ifdef=std::string())
Add an include file optionally using a relative path "..." instead of an absolute path <....
std::stringstream auxiliaries
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
static const Options options_
Options.
Definition: conic_impl.hpp:83
casadi_int nx_
Number of decision variables.
Definition: conic_impl.hpp:173
int init_mem(void *mem) const override
Initalize memory block.
Definition: conic.cpp:466
void init(const Dict &opts) override
Initialize.
Definition: conic.cpp:415
std::vector< bool > discrete_
Options.
Definition: conic_impl.hpp:164
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Definition: conic.cpp:753
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:473
Dict get_stats(void *mem) const override
Get all statistics.
Definition: conic.cpp:726
casadi_qp_prob< double > p_qp_
Definition: conic_impl.hpp:47
void qp_codegen_body(CodeGenerator &g) const
Generate code for the function body.
Definition: conic.cpp:812
static Conic * creator(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new QP Solver.
void codegen_body(CodeGenerator &g) const override
Generate code for the function body.
void init(const Dict &opts) override
Initialize.
Dict get_stats(void *mem) const override
Get all statistics.
void codegen_init_mem(CodeGenerator &g) const override
Codegen decref for init_mem.
Dict opts_
All Daqp options.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
static const Options options_
Options.
~DaqpInterface() override
Destructor.
static const std::string meta_doc
A documentation string.
void codegen_free_mem(CodeGenerator &g) const override
Codegen for free_mem.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
void free_mem(void *mem) const override
Free memory block.
int solve(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Solve the QP.
DaqpInterface(const std::string &name, const std::map< std::string, Sparsity > &st)
Constructor using sparsity patterns.
int init_mem(void *mem) const override
Initalize memory block.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
bool has_refcount_
Reference counting in codegen?
void alloc_iw(size_t sz_iw, bool persistent=false)
Ensure required length of iw field.
void alloc_res(size_t sz_res, bool persistent=false)
Ensure required length of res field.
void alloc_arg(size_t sz_arg, bool persistent=false)
Ensure required length of arg field.
std::string codegen_mem(CodeGenerator &g, const std::string &index="mem") const
Get thread-local memory object.
size_t sz_res() const
Get required length of res field.
size_t sz_w() const
Get required length of w field.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
size_t sz_arg() const
Get required length of arg field.
size_t sz_iw() const
Get required length of iw field.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
bool error_on_fail_
Throw an exception on failure?
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.
The casadi namespace.
Definition: archiver.cpp:28
void copy_vector(const std::vector< S > &s, std::vector< D > &d)
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
void CASADI_CONIC_DAQP_EXPORT casadi_load_conic_daqp()
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
void codegen_local(CodeGenerator &g, const std::string &name, const std::vector< int > &v)
int CASADI_CONIC_DAQP_EXPORT casadi_register_conic_daqp(Conic::Plugin *plugin)
casadi_daqp_data< double > d
Options metadata for a class.
Definition: options.hpp:40
std::map< std::string, FStats > fstats
const int * integrality
DAQPSettings settings
const casadi_qp_prob< T1 > * qp