26 #include "osqp_interface.hpp"
27 #include "casadi/core/casadi_misc.hpp"
32 int CASADI_CONIC_OSQP_EXPORT
35 plugin->name =
"osqp";
37 plugin->version = CASADI_VERSION;
49 const std::map<std::string, Sparsity>& st)
63 "const Options to be passed to osqp."}},
66 "Use x0 input to warmstart [Default: true]."}},
69 "Use lam_a0 and lam_x0 input to warmstart [Default: truw]."}}
84 for (
auto&& op : opts) {
85 if (op.first==
"warm_start_primal") {
87 }
else if (op.first==
"warm_start_dual") {
89 }
else if (op.first==
"osqp") {
90 const Dict& opts = op.second;
91 for (
auto&& op : opts) {
92 if (op.first==
"rho") {
94 }
else if (op.first==
"sigma") {
96 }
else if (op.first==
"scaling") {
98 }
else if (op.first==
"adaptive_rho") {
100 }
else if (op.first==
"adaptive_rho_interval") {
101 settings_.adaptive_rho_interval = op.second;
102 }
else if (op.first==
"adaptive_rho_tolerance") {
103 settings_.adaptive_rho_tolerance = op.second;
106 }
else if (op.first==
"max_iter") {
108 }
else if (op.first==
"eps_abs") {
110 }
else if (op.first==
"eps_rel") {
112 }
else if (op.first==
"eps_prim_inf") {
114 }
else if (op.first==
"eps_dual_inf") {
116 }
else if (op.first==
"alpha") {
118 }
else if (op.first==
"delta") {
120 }
else if (op.first==
"polish") {
122 }
else if (op.first==
"polish_refine_iter") {
123 settings_.polish_refine_iter = op.second;
124 }
else if (op.first==
"verbose") {
126 }
else if (op.first==
"scaled_termination") {
127 settings_.scaled_termination = op.second;
128 }
else if (op.first==
"check_termination") {
130 }
else if (op.first==
"warm_start") {
131 casadi_error(
"OSQP's warm_start option is impure and therefore disabled. "
132 "Use CasADi options 'warm_start_primal' and 'warm_start_dual' instead.");
136 casadi_error(
"Not recognised");
157 std::vector<double> dummy(std::max(
nx_+
na_, std::max(Asp.
nnz(),
H_.
nnz())));
159 std::vector<c_int> A_row = vector_static_cast<c_int>(Asp.
get_row());
160 std::vector<c_int> A_colind = vector_static_cast<c_int>(Asp.
get_colind());
161 std::vector<c_int> H_row = vector_static_cast<c_int>(H_triu.
get_row());
162 std::vector<c_int> H_colind = vector_static_cast<c_int>(H_triu.
get_colind());
194 if (osqp_setup(&m->work, &data, &
settings_))
return 1;
197 m->fstats[
"preprocessing"] =
FStats();
198 m->fstats[
"solver"] =
FStats();
199 m->fstats[
"postprocessing"] =
FStats();
208 solve(
const double** arg,
double** res, casadi_int* iw,
double* w,
void* mem)
const {
225 ret = osqp_update_lin_cost(m->work, arg[
CONIC_G]);
226 casadi_assert(ret==0,
"Problem in osqp_update_lin_cost");
235 ret = osqp_update_bounds(m->work, w, w+
nx_+
na_);
236 casadi_assert(ret==0,
"Problem in osqp_update_bounds");
239 casadi_tri_project(arg[
CONIC_H],
H_, w,
false);
242 const casadi_int* colind =
A_.
colind();
245 casadi_int offset = 0;
247 for (casadi_int i=0; i<
nx_; ++i) {
250 casadi_int n = colind[i+1]-colind[i];
256 ret = osqp_update_P_A(m->work, w,
nullptr,
nnzHupp_, A,
nullptr,
nnzA_);
257 casadi_assert(ret==0,
"Problem in osqp_update_P_A");
261 ret = osqp_warm_start_x(m->work, arg[
CONIC_X0]);
262 casadi_assert(ret==0,
"Problem in osqp_warm_start_x");
268 ret = osqp_warm_start_y(m->work, w);
269 casadi_assert(ret==0,
"Problem in osqp_warm_start_y");
273 ret = osqp_solve(m->work);
274 casadi_assert(ret==0,
"Problem in osqp_solve");
281 m->d_qp.success = m->work->info->status_val == OSQP_SOLVED;
282 if (m->d_qp.success) {
284 }
else if (m->work->info->status_val == OSQP_PRIMAL_INFEASIBLE ||
285 m->work->info->status_val == OSQP_MAX_ITER_REACHED ||
286 m->work->info->status_val == OSQP_DUAL_INFEASIBLE ||
287 m->work->info->status_val == OSQP_NON_CVX ||
288 m->work->info->status_val == OSQP_PRIMAL_INFEASIBLE_INACCURATE ||
289 m->work->info->status_val == OSQP_DUAL_INFEASIBLE_INACCURATE) {
304 casadi_int dummy_size = std::max(
nx_+
na_, std::max(Asp.
nnz(),
H_.
nnz()));
307 g.
local(
"dummy[" +
str(dummy_size) +
"]",
"casadi_real");
308 g << g.
clear(
"dummy", dummy_size) <<
"\n";
320 g <<
"A.m = " <<
nx_ +
na_ <<
";\n";
321 g <<
"A.n = " <<
nx_ <<
";\n";
322 g <<
"A.nz = " <<
nnzA_ <<
";\n";
323 g <<
"A.nzmax = " <<
nnzA_ <<
";\n";
324 g <<
"A.x = dummy;\n";
325 g <<
"A.i = A_row;\n";
326 g <<
"A.p = A_colind;\n";
329 g <<
"H.m = " <<
nx_ <<
";\n";
330 g <<
"H.n = " <<
nx_ <<
";\n";
333 g <<
"H.x = dummy;\n";
334 g <<
"H.i = H_row;\n";
335 g <<
"H.p = H_colind;\n";
337 g.
local(
"data",
"OSQPData");
338 g <<
"data.n = " <<
nx_ <<
";\n";
339 g <<
"data.m = " <<
nx_ +
na_ <<
";\n";
340 g <<
"data.P = &H;\n";
341 g <<
"data.q = dummy;\n";
342 g <<
"data.A = &A;\n";
343 g <<
"data.l = dummy;\n";
344 g <<
"data.u = dummy;\n";
346 g.
local(
"settings",
"OSQPSettings");
347 g <<
"osqp_set_default_settings(&settings);\n";
348 g <<
"settings.rho = " <<
settings_.rho <<
";\n";
349 g <<
"settings.sigma = " <<
settings_.sigma <<
";\n";
350 g <<
"settings.scaling = " <<
settings_.scaling <<
";\n";
351 g <<
"settings.adaptive_rho = " <<
settings_.adaptive_rho <<
";\n";
352 g <<
"settings.adaptive_rho_interval = " <<
settings_.adaptive_rho_interval <<
";\n";
353 g <<
"settings.adaptive_rho_tolerance = " <<
settings_.adaptive_rho_tolerance <<
";\n";
355 g <<
"settings.max_iter = " <<
settings_.max_iter <<
";\n";
356 g <<
"settings.eps_abs = " <<
settings_.eps_abs <<
";\n";
357 g <<
"settings.eps_rel = " <<
settings_.eps_rel <<
";\n";
358 g <<
"settings.eps_prim_inf = " <<
settings_.eps_prim_inf <<
";\n";
359 g <<
"settings.eps_dual_inf = " <<
settings_.eps_dual_inf <<
";\n";
360 g <<
"settings.alpha = " <<
settings_.alpha <<
";\n";
361 g <<
"settings.delta = " <<
settings_.delta <<
";\n";
362 g <<
"settings.polish = " <<
settings_.polish <<
";\n";
363 g <<
"settings.polish_refine_iter = " <<
settings_.polish_refine_iter <<
";\n";
364 g <<
"settings.verbose = " <<
settings_.verbose <<
";\n";
365 g <<
"settings.scaled_termination = " <<
settings_.scaled_termination <<
";\n";
366 g <<
"settings.check_termination = " <<
settings_.check_termination <<
";\n";
367 g <<
"settings.warm_start = " <<
settings_.warm_start <<
";\n";
370 g <<
"return osqp_setup(&" +
codegen_mem(g) +
", &data, &settings)!=0;\n";
377 g.
local(
"work",
"OSQPWorkspace",
"*");
382 g <<
"if (osqp_update_lin_cost(work, w)) return 1;\n";
389 g <<
"if (osqp_update_bounds(work, w, w+" +
str(
nx_+
na_)+
")) return 1;\n";
394 g.
comment(
"Get constraint matrix");
396 g.
local(
"offset",
"casadi_int");
397 g.
local(
"n",
"casadi_int");
398 g.
local(
"i",
"casadi_int");
399 g <<
"offset = 0;\n";
400 g <<
"for (i=0; i< " <<
nx_ <<
"; ++i) {\n";
403 g <<
"n = " + A_colind +
"[i+1]-" + A_colind +
"[i];\n";
404 g <<
"casadi_copy(" << g.
arg(
CONIC_A) <<
"+" + A_colind +
"[i], n, "
406 g <<
"offset+= n;\n";
409 g.
comment(
"Pass Hessian and constraint matrices");
411 ", 0, " +
str(
nnzA_) +
")) return 1;\n";
413 g <<
"if (osqp_warm_start_x(work, " + g.
arg(
CONIC_X0) +
")) return 1;\n";
416 g <<
"if (osqp_warm_start_y(work, w)) return 1;\n";
418 g <<
"if (osqp_solve(work)) return 1;\n";
425 g <<
"if (work->info->status_val != OSQP_SOLVED) {\n";
427 g <<
"return -1000;\n";
429 g <<
"if (work->info->status_val == OSQP_PRIMAL_INFEASIBLE || ";
430 g <<
"work->info->status_val == OSQP_MAX_ITER_REACHED || ";
431 g <<
"work->info->status_val == OSQP_DUAL_INFEASIBLE || ";
432 g <<
"work->info->status_val == OSQP_PRIMAL_INFEASIBLE_INACCURATE || ";
433 g <<
"work->info->status_val == OSQP_DUAL_INFEASIBLE_INACCURATE || ";
434 g <<
"work->info->status_val == OSQP_NON_CVX) {\n";
448 stats[
"return_status"] = m->
work->info->status;
470 s.
unpack(
"OsqpInterface::settings::adaptive_rho",
settings_.adaptive_rho);
471 s.
unpack(
"OsqpInterface::settings::adaptive_rho_interval",
settings_.adaptive_rho_interval);
472 s.
unpack(
"OsqpInterface::settings::adaptive_rho_tolerance",
settings_.adaptive_rho_tolerance);
477 s.
unpack(
"OsqpInterface::settings::eps_prim_inf",
settings_.eps_prim_inf);
478 s.
unpack(
"OsqpInterface::settings::eps_dual_inf",
settings_.eps_dual_inf);
482 s.
unpack(
"OsqpInterface::settings::polish_refine_iter",
settings_.polish_refine_iter);
484 s.
unpack(
"OsqpInterface::settings::scaled_termination",
settings_.scaled_termination);
485 s.
unpack(
"OsqpInterface::settings::check_termination",
settings_.check_termination);
499 s.
pack(
"OsqpInterface::settings::scaling",
settings_.scaling);
500 s.
pack(
"OsqpInterface::settings::adaptive_rho",
settings_.adaptive_rho);
501 s.
pack(
"OsqpInterface::settings::adaptive_rho_interval",
settings_.adaptive_rho_interval);
502 s.
pack(
"OsqpInterface::settings::adaptive_rho_tolerance",
settings_.adaptive_rho_tolerance);
504 s.
pack(
"OsqpInterface::settings::max_iter",
settings_.max_iter);
505 s.
pack(
"OsqpInterface::settings::eps_abs",
settings_.eps_abs);
506 s.
pack(
"OsqpInterface::settings::eps_rel",
settings_.eps_rel);
507 s.
pack(
"OsqpInterface::settings::eps_prim_inf",
settings_.eps_prim_inf);
508 s.
pack(
"OsqpInterface::settings::eps_dual_inf",
settings_.eps_dual_inf);
512 s.
pack(
"OsqpInterface::settings::polish_refine_iter",
settings_.polish_refine_iter);
513 s.
pack(
"OsqpInterface::settings::verbose",
settings_.verbose);
514 s.
pack(
"OsqpInterface::settings::scaled_termination",
settings_.scaled_termination);
515 s.
pack(
"OsqpInterface::settings::check_termination",
settings_.check_termination);
516 s.
pack(
"OsqpInterface::settings::warm_start",
settings_.warm_start);
Helper class for C code generation.
std::string arg(casadi_int i) const
Refer to argument.
void comment(const std::string &s)
Write a comment line (ignored if not verbose)
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.
std::string res(casadi_int i) const
Refer to resuly.
void init_local(const std::string &name, const std::string &def)
Specify the default value for a local variable.
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 <....
void constant_copy(const std::string &var_name, const std::vector< casadi_int > &v, const std::string &type="casadi_int")
Represent an array constant; adding it when new.
void copy_check(const std::string &arg, std::size_t n, const std::string &res, bool check_lhs=true, bool check_rhs=true)
std::string tri_project(const std::string &arg, const Sparsity &sp_arg, const std::string &res, bool lower)
Project triangular part.
void copy_default(const std::string &arg, std::size_t n, const std::string &res, const std::string &def, bool check_rhs=true)
std::string clear(const std::string &res, std::size_t n)
Create a fill operation.
void add_auxiliary(Auxiliary f, const std::vector< std::string > &inst={"casadi_real"})
Add a built-in auxiliary function.
static const Options options_
Options.
casadi_int nx_
Number of decision variables.
int init_mem(void *mem) const override
Initalize memory block.
casadi_int na_
The number of constraints (counting both equality and inequality) == A.size1()
Sparsity H_
Problem structure.
void init(const Dict &opts) override
Initialize.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Dict get_stats(void *mem) const override
Get all statistics.
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?
std::string codegen_mem(CodeGenerator &g, const std::string &index="mem") const
Get thread-local memory object.
void alloc_w(size_t sz_w, bool persistent=false)
Ensure required length of w field.
void codegen_free_mem(CodeGenerator &g) const override
Codegen free_mem.
void codegen_init_mem(CodeGenerator &g) const override
Codegen alloc_mem.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
Dict get_stats(void *mem) const override
Get all statistics.
void codegen_body(CodeGenerator &g) const override
Generate code for the function body.
~OsqpInterface() override
Destructor.
static ProtoFunction * deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
int init_mem(void *mem) const override
Initalize memory block.
static Conic * creator(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new QP Solver.
OsqpInterface(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new Solver.
void init(const Dict &opts) override
Initialize.
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.
static const Options options_
const Options
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.
static Sparsity diag(casadi_int nrow)
Create diagonal sparsity pattern *.
static Sparsity triu(const Sparsity &x, bool includeDiagonal=true)
Enlarge matrix.
casadi_int nnz_upper(bool strictly=false) const
Number of non-zeros in the upper triangular half,.
casadi_int nnz() const
Get the number of (structural) non-zeros.
std::vector< casadi_int > get_colind() const
Get the column index for each column.
std::vector< casadi_int > get_row() const
Get the row for each non-zero entry.
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
@ CONIC_UBA
dense, (nc x 1)
@ CONIC_A
The matrix A: sparse, (nc x n) - product with x must be dense.
@ CONIC_G
The vector g: dense, (n x 1)
@ CONIC_LBA
dense, (nc x 1)
@ CONIC_UBX
dense, (n x 1)
@ CONIC_LBX
dense, (n x 1)
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
const char * return_status_string(Bonmin::TMINLP::SolverReturn status)
int CASADI_CONIC_OSQP_EXPORT casadi_register_conic_osqp(Conic::Plugin *plugin)
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.
void CASADI_CONIC_OSQP_EXPORT casadi_load_conic_osqp()
@ CONIC_X
The primal solution.
@ CONIC_LAM_A
The dual solution corresponding to linear bounds.
@ CONIC_COST
The optimal cost.
@ CONIC_LAM_X
The dual solution corresponding to simple bounds.
Options metadata for a class.