25 #include "hpmpc_interface.hpp"
31 int CASADI_CONIC_HPMPC_EXPORT
34 plugin->name =
"hpmpc";
36 plugin->version = CASADI_VERSION;
47 const std::map<std::string, Sparsity>& st)
62 "Number of states, length N+1"}},
65 "Number of controls, length N"}},
68 "Number of non-dynamic constraints, length N+1"}},
71 "Max element in cost function as estimate of max multiplier"}},
74 "Max number of iterations"}},
77 "Tolerance in the duality measure"}},
80 "Use warm-starting"}},
83 "HPMPC cannot handle infinities. Infinities will be replaced by this option's value."}},
86 "Amount of diagnostic printing [Default: 1]."}},
107 casadi_int struct_cnt=0;
109 for (
auto&& op : opts) {
113 }
else if (op.first==
"nx") {
116 }
else if (op.first==
"nu") {
119 }
else if (op.first==
"ng") {
122 }
else if (op.first==
"mu0") {
124 }
else if (op.first==
"max_iter") {
126 }
else if (op.first==
"tol") {
128 }
else if (op.first==
"warm_start") {
130 }
else if (op.first==
"target") {
131 target_ =
static_cast<std::string
>(op.second);
132 }
else if (op.first==
"blasfeo_target") {
134 }
else if (op.first==
"print_level") {
136 }
else if (op.first==
"inf") {
141 bool detect_structure = struct_cnt==0;
142 casadi_assert(struct_cnt==0 || struct_cnt==4,
143 "You must either set all of N, nx, nu, ng; "
144 "or set none at all (automatic detection).");
146 const std::vector<casadi_int>& nx =
nxs_;
147 const std::vector<casadi_int>& ng =
ngs_;
148 const std::vector<casadi_int>& nu =
nus_;
150 if (detect_structure) {
158 std::vector<casadi_int> A_skyline;
159 std::vector<casadi_int> A_skyline2;
160 std::vector<casadi_int> A_bottomline;
161 for (casadi_int i=0;i<AT.
size2();++i) {
162 casadi_int pivot = AT.
colind()[i+1];
163 A_bottomline.push_back(AT.
row()[AT.
colind()[i]]);
164 if (pivot>AT.
colind()[i]) {
165 A_skyline.push_back(AT.
row()[pivot-1]);
166 if (pivot>AT.
colind()[i]+1) {
167 A_skyline2.push_back(AT.
row()[pivot-2]);
169 A_skyline2.push_back(-1);
172 A_skyline.push_back(-1);
173 A_skyline2.push_back(-1);
182 casadi_int pivot = 0;
183 casadi_int start_pivot = pivot;
185 for (casadi_int i=0;i<
na_;++i) {
187 if (A_skyline[i]>pivot+1) {
188 nus_.push_back(A_skyline[i]-pivot-1);
190 }
else if (A_skyline[i]==pivot+1) {
191 if (A_skyline2[i]<start_pivot) {
202 nxs_.push_back(pivot-start_pivot+1);
203 ngs_.push_back(cg); cg=0;
204 start_pivot = A_skyline[i];
205 pivot = A_skyline[i];
208 nxs_.push_back(pivot-start_pivot+1);
211 nxs_[0] = A_skyline[0];
215 for (casadi_int i=
na_-1;i>=0;--i) {
216 if (A_bottomline[i]<start_pivot)
break;
219 ngs_.push_back(cg-cN);
224 casadi_message(
"Detected structure: N " +
str(
N_) +
", nx " +
str(nx) +
", "
225 "nu " +
str(nu) +
", ng " +
str(ng) +
".");
229 casadi_assert_dev(nx.size()==
N_+1);
230 casadi_assert_dev(nu.size()==
N_);
231 casadi_assert_dev(ng.size()==
N_+1);
233 casadi_assert(
nx_ == std::accumulate(nx.begin(), nx.end(), 0) +
234 std::accumulate(nu.begin(), nu.end(), 0),
235 "sum(nx)+sum(nu) = must equal total size of variables (" +
str(
nx_) +
"). "
236 "Structure is: N " +
str(
N_) +
", nx " +
str(nx) +
", "
237 "nu " +
str(nu) +
", ng " +
str(ng) +
".");
238 casadi_assert(
na_ == std::accumulate(nx.begin()+1, nx.end(), 0) +
239 std::accumulate(ng.begin(), ng.end(), 0),
240 "sum(nx+1)+sum(ng) = must equal total size of constraints (" +
str(
na_) +
"). "
241 "Structure is: N " +
str(
N_) +
", nx " +
str(nx) +
", "
242 "nu " +
str(nu) +
", ng " +
str(ng) +
".");
244 std::string searchpath;
249 DL_HANDLE_TYPE handle =
load_library(libname, searchpath,
true);
251 std::string work_size_name =
"hpmpc_d_ip_ocp_hard_tv_work_space_size_bytes";
254 hpmpc_d_ip_ocp_hard_tv_work_space_size_bytes =
255 (Work_size)GetProcAddress(handle, TEXT(work_size_name.c_str()));
261 hpmpc_d_ip_ocp_hard_tv_work_space_size_bytes = (Work_size)dlsym(handle, work_size_name.c_str());
264 casadi_assert(hpmpc_d_ip_ocp_hard_tv_work_space_size_bytes!=
nullptr,
265 "HPMPC interface: symbol \"" + work_size_name +
"\" found in " + searchpath +
".");
267 std::string ocp_solve_name =
"fortran_order_d_ip_ocp_hard_tv";
270 fortran_order_d_ip_ocp_hard_tv =
271 (Ocp_solve)GetProcAddress(handle, TEXT(ocp_solve_name.c_str()));
277 fortran_order_d_ip_ocp_hard_tv = (Ocp_solve)dlsym(handle, ocp_solve_name.c_str());
280 casadi_assert(fortran_order_d_ip_ocp_hard_tv!=
nullptr,
281 "HPMPC interface: symbol \"" + ocp_solve_name +
"\" found in " + searchpath +
".");
290 casadi_int offset_r = 0, offset_c = 0;
291 for (casadi_int k=0;k<
N_;++k) {
292 A_blocks.push_back({offset_r, offset_c, nx[k+1], nx[k]});
293 B_blocks.push_back({offset_r, offset_c+nx[k], nx[k+1], nu[k]});
294 C_blocks.push_back({offset_r+nx[k+1], offset_c, ng[k], nx[k]});
295 D_blocks.push_back({offset_r+nx[k+1], offset_c+nx[k], ng[k], nu[k]});
297 offset_c+= nx[k]+nu[k];
299 I_blocks.push_back({offset_r, offset_c, nx[k+1], nx[k+1]});
301 I_blocks.push_back({offset_r, offset_c, nx[k+1], nx[k+1]});
302 offset_r+= nx[k+1]+ng[k];
305 C_blocks.push_back({offset_r, offset_c, ng[
N_], nx[
N_]});
314 casadi_assert((
A_ + total).nnz() == total.
nnz(),
315 "HPMPC: specified structure of A does not correspond to what the interface can handle. "
316 "Structure is: N " +
str(
N_) +
", nx " +
str(nx) +
", nu " +
str(nu) +
", "
317 "ng " +
str(ng) +
".");
329 casadi_int offset = 0;
330 for (casadi_int k=0;k<
N_;++k) {
331 R_blocks.push_back({offset+nx[k], offset+nx[k], nu[k], nu[k]});
332 S_blocks.push_back({offset+nx[k], offset, nu[k], nx[k]});
333 Q_blocks.push_back({offset, offset, nx[k], nx[k]});
334 offset+= nx[k]+nu[k];
343 casadi_assert((
H_ + total).nnz() == total.
nnz(),
344 "HPMPC: specified structure of H does not correspond to what the interface can handle. "
345 "Structure is: N " +
str(
N_) +
", nx " +
str(nx) +
", nu " +
str(nu) +
", "
346 "ng " +
str(ng) +
".");
358 for (casadi_int k=0;k<
N_;++k) {
359 b_blocks.push_back({offset, 0, nx[k+1], 1}); offset+= nx[k+1];
360 lug_blocks.push_back({offset, 0, ng[k], 1}); offset+= ng[k];
368 casadi_assert_dev(total.
nnz() ==
na_);
379 for (casadi_int k=0;k<
N_;++k) {
380 x_blocks.push_back({offset, 0, nx[k], 1}); offset+= nx[k];
381 u_blocks.push_back({offset, 0, nu[k], 1}); offset+= nu[k];
389 casadi_assert_dev(total.
nnz() ==
nx_);
391 std::vector< Block > theirs_u_blocks, theirs_x_blocks;
394 for (casadi_int k=0;k<
N_;++k) {
395 theirs_u_blocks.push_back({offset, 0, nu[k], 1}); offset+= nu[k];
396 theirs_x_blocks.push_back({offset, 0, nx[k], 1}); offset+= nx[k];
398 theirs_x_blocks.push_back({offset, 0, nx[
N_], 1});
404 casadi_assert_dev(total.
nnz() ==
nx_);
407 std::vector< Block > lamg_gap_blocks;
408 for (casadi_int k=0;k<
N_;++k) {
409 lamg_gap_blocks.push_back({offset, 0, nx[k+1], 1});offset+= nx[k+1] + ng[k];
416 for (casadi_int k=0;k<
N_;++k) {
417 lam_ul_blocks.push_back({offset, 0, nu[k], 1}); offset+= nu[k];
418 lam_xl_blocks.push_back({offset, 0, nx[k], 1}); offset+= nx[k];
419 lam_uu_blocks.push_back({offset, 0, nu[k], 1}); offset+= nu[k];
420 lam_xu_blocks.push_back({offset, 0, nx[k], 1}); offset+= nx[k];
421 lam_cl_blocks.push_back({offset, 0, ng[k], 1}); offset+= ng[k];
422 lam_cu_blocks.push_back({offset, 0, ng[k], 1}); offset+= ng[k];
441 casadi_assert_dev(total.
nnz() == offset);
457 const std::vector<int>& nx = m->nx;
458 const std::vector<int>& nu = m->nu;
459 const std::vector<int>& ng = m->ng;
460 const std::vector<int>& nb = m->nb;
463 casadi_int offset = 0;
464 for (casadi_int k=0;k<
N_;++k) m->nb[k] = nx[k]+nu[k];
481 m->lb.resize(
nx_);m->ub.resize(
nx_);
485 for (casadi_int k=0;k<
N_+1;++k) offset+=m->nx[k]+nu[k];
486 m->hidxb.resize(offset);
489 for (casadi_int k=0;k<
N_;++k) offset+=ng[k]+nx[k]+nu[k];
490 offset+=ng[
N_]+nx[
N_];
491 m->lam.resize(2*offset);
512 for (casadi_int k=0;k<
N_;++k) {
513 m->pis[k] =
get_ptr(m->pi)+offset;
520 for (casadi_int k=0;k<
N_+1;++k) {
521 m->lbs[k] =
get_ptr(m->lb)+offset;
522 m->ubs[k] =
get_ptr(m->ub)+offset;
526 m->lams.resize(
N_+1);
528 for (casadi_int k=0;k<
N_+1;++k) {
529 m->lams[k] =
get_ptr(m->lam)+offset;
530 offset+=2*(ng[k]+nb[k]);
533 m->hidxbs.resize(
N_+1);
535 for (casadi_int k=0;k<
N_+1;++k) {
536 m->hidxbs[k] =
get_ptr(m->hidxb)+offset;
537 for (casadi_int i=0;i<m->nb[k];++i) m->hidxbs[k][i] = i;
542 int workspace_size = hpmpc_d_ip_ocp_hard_tv_work_space_size_bytes(
544 m->workspace.resize(workspace_size);
547 m->pv.resize(2*(
nx_+
na_));
551 m->add_stat(
"preprocessing");
552 m->add_stat(
"solver");
553 m->add_stat(
"postprocessing");
558 double* y,
const casadi_int* sp_y,
double* w) {
559 casadi_int ncol_y = sp_y[1];
560 const casadi_int *colind_y = sp_y+2;
566 const casadi_int* sp_x,
double* y,
567 const casadi_int* sp_y,
double* w) {
568 CASADI_PREFIX(sparsify)(x, w, sp_x,
false);
569 casadi_int nrow_y = sp_y[0];
570 casadi_int ncol_y = sp_y[1];
571 const casadi_int *colind_y = sp_y+2, *row_y = sp_y + 2 + ncol_y+1;
574 for (i=0; i<ncol_y; ++i) {
575 for (el=colind_y[i]; el<colind_y[i+1]; ++el) y[nrow_y*i + row_y[el]] += factor*(*w++);
580 solve(
const double** arg,
double** res, casadi_int* iw,
double* w,
void* mem)
const {
582 m->
fstats.at(
"preprocessing").tic();
601 casadi_assert_dev(std::equal(m->b.begin(), m->b.end(), m->b2.begin()));
606 std::fill(m->lb.begin(), m->lb.end(), 0);
607 std::fill(m->ub.begin(), m->ub.end(), 0);
625 for (casadi_int k=0;k<
N_;++k) {
626 casadi_int n_row = m->nx[k+1];
627 for (casadi_int i=0;i<n_row;++i) {
628 double f = -1/m->Is[k][i];
630 for (casadi_int j=0;j<m->nx[k];++j) m->As[k][i+j*n_row]*=f;
631 for (casadi_int j=0;j<m->nu[k];++j) m->Bs[k][i+j*n_row]*=f;
636 for (casadi_int i=0;i<m->lb.size();++i) {
637 if (m->lb[i]==-std::numeric_limits<double>::infinity()) m->lb[i] = -
inf_;
639 for (casadi_int i=0;i<m->ub.size();++i) {
640 if (m->ub[i]==std::numeric_limits<double>::infinity()) m->ub[i] =
inf_;
642 for (casadi_int i=0;i<m->lg.size();++i) {
643 if (m->lg[i]==-std::numeric_limits<double>::infinity()) m->lg[i] = -
inf_;
645 for (casadi_int i=0;i<m->ug.size();++i) {
646 if (m->ug[i]==std::numeric_limits<double>::infinity()) m->ug[i] =
inf_;
649 m->fstats.at(
"preprocessing").toc();
650 m->fstats.at(
"solver").tic();
653 std::fill(m->pi.begin(), m->pi.end(), 0);
654 std::fill(m->lam.begin(), m->lam.end(), 0);
659 for (casadi_int k=0;k<
N_;++k) {
660 casadi_int n_row = m->nx[k+1];
661 for (casadi_int i=0;i<n_row;++i) {
662 double f = -m->Is[k][i];
684 m->fstats.at(
"solver").toc();
685 m->fstats.at(
"postprocessing").tic();
687 uout() <<
"HPMPC finished after " << m->iter_count <<
" iterations." << std::endl;
688 uout() <<
"return status: " << m->return_status << std::endl;
689 uout() <<
"residuals: " << m->res << std::endl;
691 m->d_qp.success = m->return_status==0;
701 for (casadi_int k=0;k<
N_;++k) {
702 casadi_int n_row = m->nx[k+1];
703 for (casadi_int i=0;i<n_row;++i) {
704 double f = -1/m->Is[k][i];
724 m->fstats.at(
"postprocessing").toc();
733 stats[
"iter_count"] = m->iter_count;
734 stats[
"res"] = m->res;
746 const std::vector<Block>& blocks,
bool eye) {
748 for (
auto && b : blocks) {
750 r(
range(b.offset_r, b.offset_r+b.rows),
751 range(b.offset_c, b.offset_c+b.cols)) =
DM::eye(b.rows);
752 casadi_assert_dev(b.rows==b.cols);
754 r(
range(b.offset_r, b.offset_r+b.rows),
755 range(b.offset_c, b.offset_c+b.cols)) =
DM::zeros(b.rows, b.cols);
761 const std::vector<Block>& blocks,
bool eye) {
762 casadi_int N = blocks.size();
765 for (casadi_int k=0;k<N;++k) {
768 casadi_assert_dev(blocks[k].rows==blocks[k].cols);
769 offset+=blocks[k].rows;
771 offset+=blocks[k].rows*blocks[k].cols;
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.
Dict get_stats(void *mem) const override
Get all statistics.
std::vector< Sparsity > sparsity_in_
Input and output sparsity.
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.
HpmpcInterface()
Constructor.
static const Options options_
Options.
std::vector< Block > Q_blocks
std::vector< Block > lam_ul_blocks
std::vector< Block > R_blocks
std::vector< Block > A_blocks
static void mproject(double factor, const double *x, const casadi_int *sp_x, double *y, const casadi_int *sp_y, double *w)
Helper function.
std::vector< Block > I_blocks
static const std::string meta_doc
A documentation string.
Dict get_stats(void *mem) const override
Get all statistics.
std::vector< Block > b_blocks
std::vector< casadi_int > nxs_
std::vector< Block > lam_cl_blocks
std::vector< Block > C_blocks
std::vector< Block > u_blocks
std::string blasfeo_target_
~HpmpcInterface() override
Destructor.
std::vector< Block > lug_blocks
std::vector< Block > lam_uu_blocks
static void dense_transfer(double factor, const double *x, const casadi_int *sp_x, double *y, const casadi_int *sp_y, double *w)
std::vector< Block > lam_cu_blocks
int solve(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate numerically.
static Sparsity blocksparsity(casadi_int rows, casadi_int cols, const std::vector< Block > &blocks, bool eye=false)
static Conic * creator(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new QP Solver.
std::vector< Block > B_blocks
std::vector< casadi_int > nus_
std::vector< Block > lam_xu_blocks
std::vector< Block > S_blocks
std::vector< casadi_int > ngs_
void init(const Dict &opts) override
Initialize.
std::vector< Block > D_blocks
std::vector< Block > lam_xl_blocks
std::vector< Block > x_blocks
int init_mem(void *mem) const override
Initalize memory block.
static void blockptr(std::vector< double * > &vs, std::vector< double > &v, const std::vector< Block > &blocks, bool eye=false)
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 handle_t load_library(const std::string &libname, std::string &resultpath, bool global)
Load a library dynamically.
static void registerPlugin(const Plugin &plugin, bool needs_lock=true)
Register an integrator in the factory.
bool verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
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,.
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.
int CASADI_CONIC_HPMPC_EXPORT casadi_register_conic_hpmpc(Conic::Plugin *plugin)
void init_vector(std::vector< S > &d, const std::vector< D > &s)
@ 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)
T1 casadi_bilin(const T1 *A, const casadi_int *sp_A, const T1 *x, const T1 *y)
void casadi_project(const T1 *x, const casadi_int *sp_x, T1 *y, const casadi_int *sp_y, T1 *w)
Sparse copy: y <- x, w work vector (length >= number of rows)
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
T1 casadi_dot(casadi_int n, const T1 *x, const T1 *y)
Inner product.
void casadi_scal(casadi_int n, T1 alpha, T1 *x)
SCAL: x <- alpha*x.
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
void CASADI_CONIC_HPMPC_EXPORT casadi_load_conic_hpmpc()
@ 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.
HpmpcMemory()
Constructor.
~HpmpcMemory()
Destructor.
Options metadata for a class.
std::map< std::string, FStats > fstats