25 #include "hpipm_interface.hpp"
29 #include <hpipm_runtime_str.h>
34 int CASADI_CONIC_HPIPM_EXPORT
37 plugin->name =
"hpipm";
39 plugin->version = CASADI_VERSION;
50 const std::map<std::string, Sparsity>& st)
65 "Number of states, length N+1"}},
68 "Number of controls, length N"}},
71 "Number of non-dynamic constraints, length N+1"}},
74 "Replace infinities by this amount [default: 1e8]"}},
77 "Options to be passed to hpipm"}}}
83 hpipm_mode mode = ROBUST;
84 casadi_int struct_cnt=0;
91 for (
auto&& op : opts) {
95 }
else if (op.first==
"nx") {
98 }
else if (op.first==
"nu") {
101 }
else if (op.first==
"ng") {
104 }
else if (op.first==
"inf") {
106 }
else if (op.first==
"hpipm") {
107 Dict hopts = op.second;
108 auto it = hopts.find(
"mode");
109 if (it!=hopts.end()) {
110 if (it->second==
"speed_abs") {
112 }
else if (it->second==
"speed") {
114 }
else if (it->second==
"balance") {
116 }
else if (it->second==
"robust") {
119 casadi_error(
"Unknown mode. Choose from speed_abs, speedm balance, robust.");
125 for (
auto&& op : hopts) {
126 if (op.first==
"mu0") {
128 }
else if (op.first==
"alpha_min") {
130 }
else if (op.first==
"res_g_max") {
132 }
else if (op.first==
"res_b_max") {
134 }
else if (op.first==
"res_d_max") {
136 }
else if (op.first==
"res_m_max") {
138 }
else if (op.first==
"iter_max") {
140 }
else if (op.first==
"stat_max") {
142 }
else if (op.first==
"pred_corr") {
144 }
else if (op.first==
"cond_pred_corr") {
146 }
else if (op.first==
"itref_pred_max") {
148 }
else if (op.first==
"itref_corr_max") {
150 }
else if (op.first==
"reg_prim") {
152 }
else if (op.first==
"lq_fact") {
154 }
else if (op.first==
"lam_min") {
156 }
else if (op.first==
"t_min") {
158 }
else if (op.first==
"warm_start") {
160 }
else if (op.first==
"abs_form") {
162 }
else if (op.first==
"comp_dual_sol_eq") {
164 }
else if (op.first==
"comp_res_exit") {
166 }
else if (op.first==
"mode") {
169 casadi_error(
"Unknown option.");
175 bool detect_structure = struct_cnt==0;
176 casadi_assert(struct_cnt==0 || struct_cnt==4,
177 "You must either set all of N, nx, nu, ng; "
178 "or set none at all (automatic detection).");
180 const std::vector<int>& nx =
nxs_;
181 const std::vector<int>& ng =
ngs_;
182 const std::vector<int>& nu =
nus_;
184 Sparsity lamg_csp_, lam_ulsp_, lam_uusp_, lam_xlsp_, lam_xusp_, lam_clsp_;
186 if (detect_structure) {
194 std::vector<casadi_int> A_skyline;
195 std::vector<casadi_int> A_skyline2;
196 std::vector<casadi_int> A_bottomline;
198 std::vector<casadi_int> AT_colind = AT.
get_colind();
199 std::vector<casadi_int> AT_row = AT.
get_row();
200 for (casadi_int i=0;i<AT.
size2();++i) {
201 casadi_int pivot = AT.
colind()[i+1];
202 if (pivot>AT_colind.at(i)) {
203 A_bottomline.push_back(AT_row.at(AT_colind.at(i)));
205 A_bottomline.push_back(-1);
207 if (pivot>AT.
colind()[i]) {
208 A_skyline.push_back(AT.
row()[pivot-1]);
209 if (pivot>AT.
colind()[i]+1) {
210 A_skyline2.push_back(AT.
row()[pivot-2]);
212 A_skyline2.push_back(-1);
215 A_skyline.push_back(-1);
216 A_skyline2.push_back(-1);
225 casadi_int pivot = 0;
226 casadi_int start_pivot = pivot;
228 for (casadi_int i=0;i<
na_;++i) {
230 if (A_skyline[i]>pivot+1) {
231 nus_.push_back(A_skyline[i]-pivot-1);
233 }
else if (A_skyline[i]==pivot+1) {
234 if (A_skyline2[i]<start_pivot) {
245 nxs_.push_back(pivot-start_pivot+1);
246 ngs_.push_back(cg); cg=0;
247 start_pivot = A_skyline[i];
248 pivot = A_skyline[i];
251 nxs_.push_back(pivot-start_pivot+1);
254 nxs_[0] = A_skyline[0];
258 for (casadi_int i=
na_-1;i>=0;--i) {
259 if (A_bottomline[i]<start_pivot)
break;
262 ngs_.push_back(cg-cN);
275 casadi_message(
"Using structure: N " +
str(
N_) +
", nx " +
str(nx) +
", "
276 "nu " +
str(nu) +
", ng " +
str(ng) +
".");
279 casadi_assert_dev(nx.size()==
N_+1);
280 casadi_assert_dev(nu.size()==
N_+1);
281 casadi_assert_dev(ng.size()==
N_+1);
283 casadi_assert(
nx_ == std::accumulate(nx.begin(), nx.end(), 0) +
284 std::accumulate(nu.begin(), nu.end(), 0),
285 "sum(nx)+sum(nu) = must equal total size of variables (" +
str(
nx_) +
"). "
286 "Structure is: N " +
str(
N_) +
", nx " +
str(nx) +
", "
287 "nu " +
str(nu) +
", ng " +
str(ng) +
".");
288 casadi_assert(
na_ == std::accumulate(nx.begin()+1, nx.end(), 0) +
289 std::accumulate(ng.begin(), ng.end(), 0),
290 "sum(nx+1)+sum(ng) = must equal total size of constraints (" +
str(
na_) +
"). "
291 "Structure is: N " +
str(
N_) +
", nx " +
str(nx) +
", "
292 "nu " +
str(nu) +
", ng " +
str(ng) +
".");
294 std::string searchpath;
302 casadi_int offset_r = 0, offset_c = 0;
303 for (casadi_int k=0;k<
N_;++k) {
304 A_blocks.push_back({offset_r, offset_c, nx[k+1], nx[k]});
305 B_blocks.push_back({offset_r, offset_c+nx[k], nx[k+1], nu[k]});
306 C_blocks.push_back({offset_r+nx[k+1], offset_c, ng[k], nx[k]});
307 D_blocks.push_back({offset_r+nx[k+1], offset_c+nx[k], ng[k], nu[k]});
309 offset_c+= nx[k]+nu[k];
311 I_blocks.push_back({offset_r, offset_c, nx[k+1], nx[k+1]});
313 I_blocks.push_back({offset_r, offset_c, nx[k+1], nx[k+1]});
314 offset_r+= nx[k+1]+ng[k];
317 C_blocks.push_back({offset_r, offset_c, ng[
N_], nx[
N_]});
328 casadi_assert((
A_ + total).nnz() == total.
nnz(),
329 "HPIPM: specified structure of A does not correspond to what the interface can handle. "
330 "Structure is: N " +
str(
N_) +
", nx " +
str(nx) +
", nu " +
str(nu) +
", "
331 "ng " +
str(ng) +
".");
343 casadi_int offset = 0;
344 for (casadi_int k=0;k<
N_+1;++k) {
345 R_blocks.push_back({offset+nx[k], offset+nx[k], nu[k], nu[k]});
346 S_blocks.push_back({offset+nx[k], offset, nu[k], nx[k]});
347 Q_blocks.push_back({offset, offset, nx[k], nx[k]});
348 offset+= nx[k]+nu[k];
356 casadi_assert((
H_ + total).nnz() == total.
nnz(),
357 "HPIPM: specified structure of H does not correspond to what the interface can handle. "
358 "Structure is: N " +
str(
N_) +
", nx " +
str(nx) +
", nu " +
str(nu) +
", "
359 "ng " +
str(ng) +
".");
371 for (casadi_int k=0;k<
N_;++k) {
372 b_blocks.push_back({offset, 0, nx[k+1], 1}); offset+= nx[k+1];
373 lug_blocks.push_back({offset, 0, ng[k], 1}); offset+= ng[k];
381 casadi_assert_dev(total.
nnz() ==
na_);
392 for (casadi_int k=0;k<
N_+1;++k) {
393 x_blocks.push_back({offset, 0, nx[k], 1}); offset+= nx[k];
394 u_blocks.push_back({offset, 0, nu[k], 1}); offset+= nu[k];
401 casadi_assert_dev(total.
nnz() ==
nx_);
403 std::vector< casadi_hpipm_block > theirs_u_blocks, theirs_x_blocks;
406 for (casadi_int k=0;k<
N_;++k) {
407 theirs_u_blocks.push_back({offset, 0, nu[k], 1}); offset+= nu[k];
408 theirs_x_blocks.push_back({offset, 0, nx[k], 1}); offset+= nx[k];
410 theirs_x_blocks.push_back({offset, 0, nx[
N_], 1});
416 casadi_assert_dev(total.
nnz() ==
nx_);
419 std::vector< casadi_hpipm_block > lamg_gap_blocks;
420 for (casadi_int k=0;k<
N_;++k) {
421 lamg_gap_blocks.push_back({offset, 0, nx[k+1], 1});offset+= nx[k+1] + ng[k];
428 for (casadi_int k=0;k<
N_;++k) {
429 lam_ul_blocks.push_back({offset, 0, nu[k], 1}); offset+= nu[k];
430 lam_xl_blocks.push_back({offset, 0, nx[k], 1}); offset+= nx[k];
431 lam_uu_blocks.push_back({offset, 0, nu[k], 1}); offset+= nu[k];
432 lam_xu_blocks.push_back({offset, 0, nx[k], 1}); offset+= nx[k];
433 lam_cl_blocks.push_back({offset, 0, ng[k], 1}); offset+= ng[k];
434 lam_cu_blocks.push_back({offset, 0, ng[k], 1}); offset+= ng[k];
450 total = lam_ulsp_ + lam_uusp_ + lam_xlsp_ + lam_xusp_ + lam_clsp_ +
lam_cusp_;
451 casadi_assert_dev(total.
nnz() == lam_ulsp_.
nnz() + lam_uusp_.
nnz() + lam_xlsp_.
nnz() +
453 casadi_assert_dev(total.
nnz() == offset);
477 size_t N = blocks.size();
478 std::vector<casadi_int> ret(4*N);
480 for (casadi_int i=0;i<N;++i) {
481 *r++ = blocks[i].offset_r;
482 *r++ = blocks[i].offset_c;
483 *r++ = blocks[i].rows;
484 *r++ = blocks[i].cols;
491 const std::vector<casadi_hpipm_block>& blocks) {
492 std::string n =
"block_" + name +
"[" +
str(blocks.size()) +
"]";
493 g.
local(n,
"static struct casadi_hpipm_block");
494 g <<
"p." << name <<
" = block_" + name +
";\n";
495 g <<
"casadi_hpipm_unpack_blocks(" << blocks.size()
500 void codegen_local(CodeGenerator& g,
const std::string& name,
const std::vector<int>& v) {
501 std::string n = name +
"[]";
502 g.local(n,
"static const int");
503 std::stringstream init;
505 for (casadi_int i=0;i<v.size();++i) {
507 if (i<v.size()-1) init <<
", ";
510 g.init_local(n, init.str());
514 g <<
"p.qp = &p_qp;\n";
523 g <<
"p.nbx = nx;\n";
524 g <<
"p.nbu = nu;\n";
525 g <<
"p.ns = zeros;\n";
526 g <<
"p.nsbx = zeros;\n";
527 g <<
"p.nsbu = zeros;\n";
528 g <<
"p.nsg = zeros;\n";
557 g <<
"p.N = " <<
N_ <<
";\n";
560 g <<
"p.hpipm_options.alpha_min = " <<
hpipm_options_.alpha_min <<
";\n";
561 g <<
"p.hpipm_options.res_g_max = " <<
hpipm_options_.res_g_max <<
";\n";
562 g <<
"p.hpipm_options.res_b_max = " <<
hpipm_options_.res_b_max <<
";\n";
563 g <<
"p.hpipm_options.res_d_max = " <<
hpipm_options_.res_d_max <<
";\n";
564 g <<
"p.hpipm_options.res_m_max = " <<
hpipm_options_.res_m_max <<
";\n";
565 g <<
"p.hpipm_options.reg_prim = " <<
hpipm_options_.reg_prim <<
";\n";
566 g <<
"p.hpipm_options.lam_min = " <<
hpipm_options_.lam_min <<
";\n";
568 g <<
"p.hpipm_options.tau_min = " <<
hpipm_options_.tau_min <<
";\n";
569 g <<
"p.hpipm_options.iter_max = " <<
hpipm_options_.iter_max <<
";\n";
570 g <<
"p.hpipm_options.stat_max = " <<
hpipm_options_.stat_max <<
";\n";
571 g <<
"p.hpipm_options.pred_corr = " <<
hpipm_options_.pred_corr <<
";\n";
572 g <<
"p.hpipm_options.cond_pred_corr = " <<
hpipm_options_.cond_pred_corr <<
";\n";
573 g <<
"p.hpipm_options.itref_pred_max = " <<
hpipm_options_.itref_pred_max <<
";\n";
574 g <<
"p.hpipm_options.itref_corr_max = " <<
hpipm_options_.itref_corr_max <<
";\n";
575 g <<
"p.hpipm_options.warm_start = " <<
hpipm_options_.warm_start <<
";\n";
576 g <<
"p.hpipm_options.square_root_alg = " <<
hpipm_options_.square_root_alg <<
";\n";
577 g <<
"p.hpipm_options.lq_fact = " <<
hpipm_options_.lq_fact <<
";\n";
578 g <<
"p.hpipm_options.abs_form = " <<
hpipm_options_.abs_form <<
";\n";
579 g <<
"p.hpipm_options.comp_dual_sol_eq = " <<
hpipm_options_.comp_dual_sol_eq <<
";\n";
580 g <<
"p.hpipm_options.comp_res_exit = " <<
hpipm_options_.comp_res_exit <<
";\n";
581 g <<
"p.hpipm_options.comp_res_pred = " <<
hpipm_options_.comp_res_pred <<
";\n";
582 g <<
"p.hpipm_options.split_step = " <<
hpipm_options_.split_step <<
";\n";
583 g <<
"p.hpipm_options.var_init_scheme = " <<
hpipm_options_.var_init_scheme <<
";\n";
584 g <<
"p.hpipm_options.t_lam_min = " <<
hpipm_options_.t_lam_min <<
";\n";
586 g <<
"p.hpipm_options.memsize = 0;\n";
589 g <<
"p.inf = " <<
inf_ <<
";\n";
614 g <<
"casadi_hpipm_setup(&p);\n";
686 casadi_hpipm_setup(&
p_);
694 m->add_stat(
"solver");
695 m->add_stat(
"postprocessing");
701 casadi_int*& iw,
double*& w)
const {
709 casadi_hpipm_set_work(&m->d, &arg, &res, &iw, &w);
713 solve(
const double** arg,
double** res, casadi_int* iw,
double* w,
void* mem)
const {
717 m->
fstats.at(
"solver").tic();
719 casadi_hpipm_solve(&m->d, arg, res, iw, w);
721 m->fstats.at(
"solver").toc();
723 m->d_qp.success = m->d.return_status==0;
726 uout() <<
"HPIPM finished after " << m->d.iter_count <<
" iterations." << std::endl;
727 uout() <<
"return status: " << m->d.return_status << std::endl;
728 uout() <<
"HPIPM residuals: " << m->d.res_stat <<
", " <<
729 m->d.res_eq <<
", " << m->d.res_ineq <<
", " <<
730 m->d.res_comp << std::endl;
741 stats[
"iter_count"] = m->d.iter_count;
752 const std::vector<casadi_hpipm_block>& blocks,
bool eye) {
754 for (
auto && b : blocks) {
756 r(
range(b.offset_r, b.offset_r+b.rows),
757 range(b.offset_c, b.offset_c+b.cols)) =
DM::eye(b.rows);
758 casadi_assert_dev(b.rows==b.cols);
760 r(
range(b.offset_r, b.offset_r+b.rows),
761 range(b.offset_c, b.offset_c+b.cols)) =
DM::zeros(b.rows, b.cols);
767 const std::vector<casadi_hpipm_block>& blocks,
bool eye) {
768 casadi_int N = blocks.size();
771 for (casadi_int k=0;k<N;++k) {
774 casadi_assert_dev(blocks[k].rows==blocks[k].cols);
775 offset+=blocks[k].rows;
777 offset+=blocks[k].rows*blocks[k].cols;
808 g.
local(
"d",
"struct casadi_hpipm_data");
809 g.
local(
"p",
"struct casadi_hpipm_prob");
814 g <<
"d.prob = &p;\n";
815 g <<
"d.qp = &d_qp;\n";
816 g <<
"casadi_hpipm_set_work(&d, &arg, &res, &iw, &w);\n";
818 g <<
"casadi_hpipm_solve(&d, arg, res, iw, w);\n";
820 g <<
"if (d.return_status!=0) {\n";
822 g <<
"return -1000;\n";
831 s.
version(
"HpipmInterface", 1);
837 s.
version(
"HpipmInterface", 1);
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.
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::string sparsity(const Sparsity &sp, bool canonical=true)
std::stringstream auxiliaries
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.
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
Dict get_stats(void *mem) const override
Get all statistics.
casadi_qp_prob< double > p_qp_
void qp_codegen_body(CodeGenerator &g) const
Generate code for the function body.
Helper class for Serialization.
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.
const Sparsity & sparsity_in(casadi_int ind) const
Input/output sparsity.
void alloc_arg(size_t sz_arg, bool persistent=false)
Ensure required length of arg field.
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 MatType zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
static Sparsity blocksparsity(casadi_int rows, casadi_int cols, const std::vector< casadi_hpipm_block > &blocks, bool eye=false)
std::vector< casadi_hpipm_block > D_blocks
Dict get_stats(void *mem) const override
Get all statistics.
HpipmInterface()
Constructor.
std::vector< casadi_hpipm_block > lam_cl_blocks
std::vector< casadi_hpipm_block > C_blocks
static void blockptr(std::vector< double * > &vs, std::vector< double > &v, const std::vector< casadi_hpipm_block > &blocks, bool eye=false)
void codegen_body(CodeGenerator &g) const override
Generate code for the function body.
static const std::string meta_doc
A documentation string.
std::vector< casadi_hpipm_block > I_blocks
std::vector< casadi_hpipm_block > lam_uu_blocks
~HpipmInterface() override
Destructor.
std::vector< casadi_hpipm_block > u_blocks
void set_work(void *mem, const double **&arg, double **&res, casadi_int *&iw, double *&w) const override
Set the (persistent) work vectors.
std::vector< casadi_hpipm_block > Q_blocks
std::vector< casadi_hpipm_block > lam_ul_blocks
static const Options options_
Options.
std::vector< casadi_hpipm_block > lam_cu_blocks
casadi_hpipm_prob< double > p_
int solve(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate numerically.
std::vector< casadi_hpipm_block > lug_blocks
std::vector< casadi_hpipm_block > B_blocks
static Conic * creator(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new QP Solver.
std::vector< casadi_hpipm_block > b_blocks
std::vector< int > zeros_
std::vector< casadi_hpipm_block > lam_xu_blocks
std::vector< casadi_hpipm_block > x_blocks
std::vector< casadi_hpipm_block > lam_xl_blocks
std::vector< casadi_hpipm_block > S_blocks
std::vector< casadi_hpipm_block > R_blocks
int init_mem(void *mem) const override
Initalize memory block.
d_ocp_qp_ipm_arg hpipm_options_
void init(const Dict &opts) override
Initialize.
std::vector< casadi_hpipm_block > A_blocks
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
const Sparsity & sparsity() const
Const access the sparsity - reference to data member.
static Matrix< double > eye(casadi_int n)
create an n-by-n identity matrix
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?
bool verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
Helper class for Serialization.
void version(const std::string &name, int v)
Sparsity pattern_inverse() const
Take the inverse of a sparsity pattern; flip zeros and non-zeros.
static Sparsity dense(casadi_int nrow, casadi_int ncol=1)
Create a dense rectangular sparsity pattern *.
Sparsity T() const
Transpose the matrix.
casadi_int nnz() const
Get the number of (structural) non-zeros.
casadi_int size2() const
Get the number of columns.
const casadi_int * row() const
Get a reference to row-vector,.
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)
std::vector< casadi_int > range(casadi_int start, casadi_int stop, casadi_int step, casadi_int len)
Range function.
void CASADI_CONIC_HPIPM_EXPORT casadi_load_conic_hpipm()
@ CONIC_LBA
dense, (nc x 1)
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.
std::vector< casadi_int > hpipm_blocks_pack(const std::vector< casadi_hpipm_block > &blocks)
int CASADI_CONIC_HPIPM_EXPORT casadi_register_conic_hpipm(Conic::Plugin *plugin)
void codegen_local(CodeGenerator &g, const std::string &name, const std::vector< int > &v)
void codegen_unpack_block(CodeGenerator &g, const std::string &name, const std::vector< casadi_ocp_block > &blocks)
casadi_hpipm_data< double > d
~HpipmMemory()
Destructor.
HpipmMemory()
Constructor.
Options metadata for a class.
std::map< std::string, FStats > fstats
void add_stat(const std::string &s)
const casadi_int * theirs_Usp
casadi_hpipm_block * lam_xu
casadi_hpipm_block * lam_ul
casadi_hpipm_block * lam_uu
const casadi_int * theirs_xsp
const casadi_int * theirs_Xsp
const casadi_int * lamg_gapsp
casadi_hpipm_block * lam_cl
casadi_hpipm_block * lam_cu
const casadi_int * theirs_usp
struct d_ocp_qp_ipm_arg hpipm_options
casadi_hpipm_block * lam_xl
const casadi_qp_prob< T1 > * qp