clarabel_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 "clarabel_interface.hpp"
26 #include "casadi/core/nlp_tools.hpp"
27 #include <clarabel_runtime_str.h> // analogous to highs_runtime_str.h
28 namespace casadi {
29 
30 
31 
32 extern "C"
33 int CASADI_CONIC_CLARABEL_EXPORT
34 casadi_register_conic_clarabel(Conic::Plugin* plugin) {
35  plugin->creator = ClarabelInterface::creator;
36  plugin->name = "clarabel";
37  plugin->doc = ClarabelInterface::meta_doc.c_str();
38  plugin->version = CASADI_VERSION;
39  plugin->options = &ClarabelInterface::options_;
40  plugin->deserialize = &ClarabelInterface::deserialize;
41  return 0;
42 }
43 
44 extern "C"
45 void CASADI_CONIC_CLARABEL_EXPORT casadi_load_conic_clarabel() {
47 }
48 
49 
50 ClarabelInterface::ClarabelInterface(const std::string& name,
51  const std::map<std::string, Sparsity>& st)
52  : Conic(name, st) {
53 }
54 
56  = {{&Conic::options_},
57  {{"clarabel",
58  {OT_DICT,
59  "Options to be passed to Clarabel."}},
60  }
61  };
62 
63 void ClarabelInterface::init(const Dict& opts) {
64  // Call the init method of the base class
65  Conic::init(opts);
66  // Read user options for Clarabel (if provided)
67  for (auto&& op : opts) {
68  if (op.first=="clarabel") {
69  opts_ = op.second;
70  }
71  }
72  // Initialize dependent (read-only) members
75 
76  casadi_warning("This plugin is not implemented yet. "
77  "It's only a stub to check the generation of binaries linked to rust packages.");
78 
79  // Allocate memory for arguments and work vectors; the work sizes are determined
80  // by a call to our clarabel_work routine.
81  casadi_int sz_arg, sz_res, sz_w, sz_iw;
82  casadi_clarabel_work(&p_, &sz_arg, &sz_res, &sz_iw, &sz_w);
83 
84  alloc_arg(sz_arg, true);
85  alloc_res(sz_res, true);
86  alloc_iw(sz_iw, true);
87  alloc_w(sz_w, true);
88 }
89 
91  // For Clarabel we need two CSC representations:
92  // one for the quadratic cost (matrix P, built here from H_) and one for the constraints (A_).
93  // (We assume that H_ and A_ have been set up by the base class.)
94  colindp_.resize(H_.size2()+1);
95  rowp_.resize(H_.nnz());
96  colinda_.resize(A_.size2()+1);
97  rowa_.resize(A_.nnz());
98  copy_vector(H_.colind(), colindp_);
99  copy_vector(H_.row(), rowp_);
100  copy_vector(A_.colind(), colinda_);
101  copy_vector(A_.row(), rowa_);
102  // (We omit integrality because in this example Clarabel does not support integer vars.)
103 }
104 
105 void codegen_local(CodeGenerator& g, const std::string& name, const std::vector<int>& v) {
106  std::string n = name + "[]";
107  g.local(n, "static const int");
108  std::stringstream init;
109  init << "{";
110  for (casadi_int i = 0; i < v.size(); ++i) {
111  init << v[i];
112  if (i < v.size()-1) init << ", ";
113  }
114  if (v.empty()) init << "0"; // ISO C forbids empty initializer braces
115  init << "}";
116  g.init_local(n, init.str());
117 }
118 
120  g << "p.qp = &p_qp;\n";
121  codegen_local(g, "colindp", colindp_);
122  codegen_local(g, "rowp", rowp_);
123  codegen_local(g, "colinda", colinda_);
124  codegen_local(g, "rowa", rowa_);
125  g << "p.colindp = colindp;\n";
126  g << "p.rowp = rowp;\n";
127  g << "p.colinda = colinda;\n";
128  g << "p.rowa = rowa;\n";
129  g << "casadi_clarabel_setup(&p);\n";
130 }
131 
133  p_.qp = &p_qp_;
134  p_.colindp = get_ptr(colindp_);
135  p_.rowp = get_ptr(rowp_);
136  p_.colinda = get_ptr(colinda_);
137  p_.rowa = get_ptr(rowa_);
138 
139  casadi_clarabel_setup(&p_);
140 }
141 
143  g << "clarabel_init_mem(&" + codegen_mem(g) + ");\n";
144  g << "return 0;\n";
145 }
146 
148  g << "clarabel_free_mem(&" + codegen_mem(g) + ");\n";
149 }
150 
151 int ClarabelInterface::init_mem(void* mem) const {
152  if (Conic::init_mem(mem)) return 1;
153  if (!mem) return 1;
154  auto m = static_cast<ClarabelMemory*>(mem);
155  clarabel_init_mem(&m->d);
156  m->add_stat("preprocessing");
157  m->add_stat("solver");
158  m->add_stat("postprocessing");
159  return 0;
160 }
161 
162 void ClarabelInterface::free_mem(void* mem) const {
163  auto m = static_cast<ClarabelMemory*>(mem);
164  clarabel_free_mem(&m->d);
165  delete m;
166 }
167 
168 void ClarabelInterface::set_work(void* mem, const double**& arg, double**& res,
169  casadi_int*& iw, double*& w) const {
170  auto m = static_cast<ClarabelMemory*>(mem);
171  Conic::set_work(mem, arg, res, iw, w);
172  m->d.prob = &p_;
173  m->d.qp = &m->d_qp;
174  casadi_clarabel_init(&m->d, &arg, &res, &iw, &w);
175 }
176 
177 int ClarabelInterface::solve(const double** arg, double** res,
178  casadi_int* iw, double* w, void* mem) const {
179  auto m = static_cast<ClarabelMemory*>(mem);
180  m->fstats.at("solver").tic();
181  casadi_clarabel_solve(&m->d, arg, res, iw, w);
182  m->fstats.at("solver").toc();
183  return 0;
184 }
185 
187  clear_mem();
188 }
189 
191  qp_codegen_body(g);
203  g.add_include("interfaces/clarabel_c_api.h");
204 
205  g.auxiliaries << g.sanitize_source(clarabel_runtime_str, {"casadi_real"});
206 
207  g.local("d", "struct casadi_clarabel_data*");
208  g.init_local("d", "&" + codegen_mem(g));
209  g.local("p", "struct casadi_clarabel_prob");
211 
212  g << "d->prob = &p;\n";
213  g << "d->qp = &d_qp;\n";
214  g << "casadi_clarabel_init(d, &arg, &res, &iw, &w);\n";
215 
216  g << "casadi_clarabel_solve(d, arg, res, iw, w);\n";
217  g << "if (!d_qp.success) {\n";
218  if (error_on_fail_) {
219  g << "return -1000;\n";
220  } else {
221  g << "return -1;\n";
222  }
223  g << "}\n";
224  g << "return 0;\n";
225 }
226 
228  Dict stats = Conic::get_stats(mem);
229  auto m = static_cast<ClarabelMemory*>(mem);
230  stats["return_status"] = m->d.return_status;
231  // (Additional clarabel‐specific stats can be added here.)
232  return stats;
233 }
234 
236  s.version("ClarabelInterface", 1);
237  s.unpack("ClarabelInterface::opts", opts_);
238  init_dependent();
240 }
241 
244  s.version("ClarabelInterface", 1);
245  s.pack("ClarabelInterface::opts", opts_);
246 }
247 
248 } // end namespace casadi
void codegen_free_mem(CodeGenerator &g) const override
Codegen for freeing memory.
void init_dependent()
Initialize dependent (read-only) members.
int solve(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Solve the QP.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Dict opts_
Options passed to Clarabel (distinct from options in the solver)
static Conic * creator(const std::string &name, const std::map< std::string, Sparsity > &st)
Creator function for the plugin.
void free_mem(void *mem) const override
Free the memory block.
ClarabelInterface(const std::string &name, const std::map< std::string, Sparsity > &st)
Constructor using sparsity patterns.
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
void codegen_init_mem(CodeGenerator &g) const override
Codegen for initializing memory.
static const Options options_
Options for Clarabel.
int init_mem(void *mem) const override
Initialize the memory block.
void init(const Dict &opts) override
Initialize the solver.
Dict get_stats(void *mem) const override
Get all statistics.
static const std::string meta_doc
A documentation string.
~ClarabelInterface() override
Destructor.
void codegen_body(CodeGenerator &g) const override
Generate code for the function body.
Helper class for C code generation.
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
int init_mem(void *mem) const override
Initalize memory block.
Definition: conic.cpp:451
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
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:458
Dict get_stats(void *mem) const override
Get all statistics.
Definition: conic.cpp:711
void qp_codegen_body(CodeGenerator &g) const
Generate code for the function body.
Definition: conic.cpp:789
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
void alloc_iw(size_t sz_iw, bool persistent=false)
Ensure required length of iw field.
void alloc_res(size_t sz_res, bool persistent=false)
Ensure required length of res field.
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.
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
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
int CASADI_CONIC_CLARABEL_EXPORT casadi_register_conic_clarabel(Conic::Plugin *plugin)
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.
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)
void CASADI_CONIC_CLARABEL_EXPORT casadi_load_conic_clarabel()
casadi_clarabel_data< double > d
Options metadata for a class.
Definition: options.hpp:40
std::map< std::string, FStats > fstats
const casadi_qp_prob< T1 > * qp