fatrop_conic_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 "fatrop_conic_interface.hpp"
26 #include <numeric>
27 #include <cstring>
28 
29 #include <fatrop_conic_runtime_str.h>
30 
31 
32 namespace casadi {
33 
34  extern "C"
35  int CASADI_CONIC_FATROP_EXPORT
36  casadi_register_conic_fatrop(Conic::Plugin* plugin) {
37  plugin->creator = FatropConicInterface::creator;
38  plugin->name = "fatrop";
39  plugin->doc = FatropConicInterface::meta_doc.c_str();
40  plugin->version = CASADI_VERSION;
41  plugin->options = &FatropConicInterface::options_;
42  return 0;
43  }
44 
45  extern "C"
46  void CASADI_CONIC_FATROP_EXPORT casadi_load_conic_fatrop() {
48  }
49 
51  const std::map<std::string, Sparsity>& st)
52  : Conic(name, st) {
53  }
54 
56  clear_mem();
57  }
58 
60  = {{&Conic::options_},
61  {{"N",
62  {OT_INT,
63  "OCP horizon"}},
64  {"nx",
65  {OT_INTVECTOR,
66  "Number of states, length N+1"}},
67  {"nu",
68  {OT_INTVECTOR,
69  "Number of controls, length N"}},
70  {"ng",
71  {OT_INTVECTOR,
72  "Number of non-dynamic constraints, length N+1"}},
73  {"structure_detection",
74  {OT_STRING,
75  "NONE | auto | manual"}},
76  {"fatrop",
77  {OT_DICT,
78  "Options to be passed to fatrop"}}}
79  };
80 
81  void FatropConicInterface::init(const Dict& opts) {
82  Conic::init(opts);
83 
84  casadi_int struct_cnt=0;
86 
87  // Read options
88  for (auto&& op : opts) {
89  if (op.first=="N") {
90  N_ = op.second;
91  struct_cnt++;
92  } else if (op.first=="nx") {
93  nxs_ = op.second;
94  struct_cnt++;
95  } else if (op.first=="nu") {
96  nus_ = op.second;
97  struct_cnt++;
98  } else if (op.first=="ng") {
99  ngs_ = op.second;
100  struct_cnt++;
101  } else if (op.first=="structure_detection") {
102  std::string v = op.second;
103  if (v=="auto") {
105  } else if (v=="manual") {
107  } else if (v=="none") {
109  } else {
110  casadi_error("Unknown option for structure_detection: '" + v + "'.");
111  }
112  }
113  }
114 
116  casadi_assert(struct_cnt==4,
117  "You must set all of N, nx, nu, ng.");
118  } else if (structure_detection_==STRUCTURE_NONE) {
119  N_ = 0;
120  nxs_ = {static_cast<int>(nx_)};
121  nus_ = {0};
122  ngs_ = {static_cast<int>(na_)};
123  }
124 
125  if (struct_cnt>0) {
126  casadi_assert(structure_detection_ == STRUCTURE_MANUAL,
127  "You must set structure_detection to 'manual' if you set N, nx, nu, ng.");
128  }
129 
130 
131  const std::vector<int>& nx = nxs_;
132  const std::vector<int>& ng = ngs_;
133  const std::vector<int>& nu = nus_;
134 
135  Sparsity lamg_csp_, lam_ulsp_, lam_uusp_, lam_xlsp_, lam_xusp_, lam_clsp_;
136 
138  /* General strategy: look for the xk+1 diagonal part in A
139  */
140 
141  // Find the right-most column for each row in A -> A_skyline
142  // Find the second-to-right-most column -> A_skyline2
143  // Find the left-most column -> A_bottomline
144  Sparsity AT = A_.T();
145  std::vector<casadi_int> A_skyline;
146  std::vector<casadi_int> A_skyline2;
147  std::vector<casadi_int> A_bottomline;
148  for (casadi_int i=0;i<AT.size2();++i) {
149  casadi_int pivot = AT.colind()[i+1];
150  A_bottomline.push_back(AT.row()[AT.colind()[i]]);
151  if (pivot>AT.colind()[i]) {
152  A_skyline.push_back(AT.row()[pivot-1]);
153  if (pivot>AT.colind()[i]+1) {
154  A_skyline2.push_back(AT.row()[pivot-2]);
155  } else {
156  A_skyline2.push_back(-1);
157  }
158  } else {
159  A_skyline.push_back(-1);
160  A_skyline2.push_back(-1);
161  }
162  }
163 
164  /*
165  Loop over the right-most columns of A:
166  they form the diagonal part due to xk+1 in gap constraints.
167  detect when the diagonal pattern is broken -> new stage
168  */
169  casadi_int pivot = 0; // Current right-most element
170  casadi_int start_pivot = pivot; // First right-most element that started the stage
171  casadi_int cg = 0; // Counter for non-gap-closing constraints
172  for (casadi_int i=0;i<na_;++i) { // Loop over all rows
173  bool commit = false; // Set true to jump to the stage
174  if (A_skyline[i]>pivot+1) { // Jump to a diagonal in the future
175  nus_.push_back(A_skyline[i]-pivot-1); // Size of jump equals number of states
176  commit = true;
177  } else if (A_skyline[i]==pivot+1) { // Walking the diagonal
178  if (A_skyline2[i]<start_pivot) { // Free of below-diagonal entries?
179  pivot++;
180  } else {
181  nus_.push_back(0); // We cannot but conclude that we arrived at a new stage
182  commit = true;
183  }
184  } else { // non-gap-closing constraint detected
185  cg++;
186  }
187 
188  if (commit) {
189  nxs_.push_back(pivot-start_pivot+1);
190  ngs_.push_back(cg); cg=0;
191  start_pivot = A_skyline[i];
192  pivot = A_skyline[i];
193  }
194  }
195  nxs_.push_back(pivot-start_pivot+1);
196 
197  // Correction for k==0
198  nxs_[0] = A_skyline[0];
199  nus_[0] = 0;
200  ngs_.erase(ngs_.begin());
201  casadi_int cN=0;
202  for (casadi_int i=na_-1;i>=0;--i) {
203  if (A_bottomline[i]<start_pivot) break;
204  cN++;
205  }
206  ngs_.push_back(cg-cN);
207  ngs_.push_back(cN);
208 
209  N_ = nus_.size();
210  uout() << "nus" << nus_.size() << "nxs" << nxs_.size() << std::endl;
211  nus_.push_back(0);
212 
213  if (N_>1) {
214  if (nus_[0]==0 && nxs_[1]+nus_[1]==nxs_[0]) {
215  nxs_[0] = nxs_[1];
216  nus_[0] = nus_[1];
217  }
218  }
219  }
220 
221  if (verbose_) {
222  casadi_message("Using structure: N " + str(N_) + ", nx " + str(nx) + ", "
223  "nu " + str(nu) + ", ng " + str(ng) + ".");
224  }
225 
226  /* Disassemble A input into:
227  A B I
228  C D
229  A B I
230  C D
231  C
232  */
233  casadi_int offset_r = 0, offset_c = 0;
234  for (casadi_int k=0;k<N_;++k) { // Loop over blocks
235  AB_blocks.push_back({offset_r, offset_c, nx[k+1], nx[k]+nu[k]});
236  CD_blocks.push_back({offset_r+nx[k+1], offset_c, ng[k], nx[k]+nu[k]});
237  offset_c+= nx[k]+nu[k];
238  if (k+1<N_)
239  I_blocks.push_back({offset_r, offset_c, nx[k+1], nx[k+1]});
240  // TODO(jgillis) actually use these
241  // test5.py versus tesst6.py
242  // test5 changes behaviour when piping stdout to file -> memory corruption
243  // logs are ever so slightly different
244  else
245  I_blocks.push_back({offset_r, offset_c, nx[k+1], nx[k+1]});
246  offset_r+= nx[k+1]+ng[k];
247  }
248  CD_blocks.push_back({offset_r, offset_c, ng[N_], nx[N_]});
249 
250  casadi_int offset = 0;
251  AB_offsets_.push_back(0);
252  for (auto e : AB_blocks) {
253  offset += e.rows*e.cols;
254  AB_offsets_.push_back(offset);
255  }
256  offset = 0;
257  CD_offsets_.push_back(0);
258  for (auto e : CD_blocks) {
259  offset += e.rows*e.cols;
260  CD_offsets_.push_back(offset);
261  }
262 
265  Isp_ = blocksparsity(na_, nx_, I_blocks, true);
266 
267  Sparsity total = ABsp_ + CDsp_ + Isp_;
268 
269  casadi_assert((A_ + total).nnz() == total.nnz(),
270  "HPIPM: specified structure of A does not correspond to what the interface can handle. "
271  "Structure is: N " + str(N_) + ", nx " + str(nx) + ", nu " + str(nu) + ", "
272  "ng " + str(ng) + ".");
273  casadi_assert_dev(total.nnz() == ABsp_.nnz() + CDsp_.nnz() + Isp_.nnz());
274 
275  /* Disassemble H input into:
276  Q S'
277  S R
278  Q S'
279  S R
280 
281  Multiply by 2
282  */
283  offset = 0;
284  for (casadi_int k=0;k<N_+1;++k) { // Loop over blocks
285  RSQ_blocks.push_back({offset, offset, nx[k]+nu[k], nx[k]+nu[k]});
286  offset+= nx[k]+nu[k];
287  }
289 
290  offset = 0;
291  RSQ_offsets_.push_back(0);
292  for (auto e : RSQ_blocks) {
293  offset += e.rows*e.cols;
294  RSQ_offsets_.push_back(offset);
295  }
297 
298  // Allocate memory
299  casadi_int sz_arg, sz_res, sz_w, sz_iw;
300  casadi_fatrop_conic_work(&p_, &sz_arg, &sz_res, &sz_iw, &sz_w);
301 
302  alloc_arg(sz_arg, true);
303  alloc_res(sz_res, true);
304  alloc_iw(sz_iw, true);
305  alloc_w(sz_w, true);
306  }
307 
308  void FatropConicInterface::set_temp(void* mem, const double** arg, double** res,
309  casadi_int* iw, double* w) const {
310 
311  }
312 
313  std::vector<casadi_int> fatrop_blocks_pack(const std::vector<casadi_ocp_block>& blocks) {
314  size_t N = blocks.size();
315  std::vector<casadi_int> ret(4*N);
316  casadi_int* r = get_ptr(ret);
317  for (casadi_int i=0;i<N;++i) {
318  *r++ = blocks[i].offset_r;
319  *r++ = blocks[i].offset_c;
320  *r++ = blocks[i].rows;
321  *r++ = blocks[i].cols;
322  }
323  return ret;
324  }
325 
327  p_.qp = &p_qp_;
328  p_.nx = get_ptr(nxs_);
329  p_.nu = get_ptr(nus_);
330  p_.ABsp = ABsp_;
332  p_.CDsp = CDsp_;
334  p_.RSQsp = RSQsp_;
336  p_.AB = get_ptr(AB_blocks);
337  p_.CD = get_ptr(CD_blocks);
339  p_.N = N_;
340  casadi_fatrop_conic_setup(&p_);
341  }
342 
343  int FatropConicInterface::init_mem(void* mem) const {
344  if (Conic::init_mem(mem)) return 1;
345  auto m = static_cast<FatropConicMemory*>(mem);
346 
347  m->add_stat("preprocessing");
348  m->add_stat("solver");
349  m->add_stat("postprocessing");
350  return 0;
351  }
352 
354  void FatropConicInterface::set_work(void* mem, const double**& arg, double**& res,
355  casadi_int*& iw, double*& w) const {
356 
357  auto m = static_cast<FatropConicMemory*>(mem);
358 
359  Conic::set_work(mem, arg, res, iw, w);
360 
361  m->d.prob = &p_;
362  m->d.qp = &m->d_qp;
363 
364  //casadi_qp_data<double>* d_qp = m->d.qp;
365 
366  casadi_fatrop_conic_set_work(&m->d, &arg, &res, &iw, &w);
367  }
368 
369 
371  Dict stats = Conic::get_stats(mem);
372  auto m = static_cast<FatropConicMemory*>(mem);
373 
374  stats["return_status"] = m->d.return_status;
375  stats["iter_count"] = m->d.iter_count;
376  return stats;
377  }
378 
380  }
381 
383  }
384 
385  Sparsity FatropConicInterface::blocksparsity(casadi_int rows, casadi_int cols,
386  const std::vector<casadi_ocp_block>& blocks, bool eye) {
387  DM r(rows, cols);
388  for (auto && b : blocks) {
389  if (eye) {
390  r(range(b.offset_r, b.offset_r+b.rows),
391  range(b.offset_c, b.offset_c+b.cols)) = DM::eye(b.rows);
392  casadi_assert_dev(b.rows==b.cols);
393  } else {
394  r(range(b.offset_r, b.offset_r+b.rows),
395  range(b.offset_c, b.offset_c+b.cols)) = DM::zeros(b.rows, b.cols);
396  }
397  }
398  return r.sparsity();
399  }
400  void FatropConicInterface::blockptr(std::vector<double *>& vs, std::vector<double>& v,
401  const std::vector<casadi_ocp_block>& blocks, bool eye) {
402  casadi_int N = blocks.size();
403  vs.resize(N);
404  casadi_int offset=0;
405  for (casadi_int k=0;k<N;++k) {
406  vs[k] = get_ptr(v)+offset;
407  if (eye) {
408  casadi_assert_dev(blocks[k].rows==blocks[k].cols);
409  offset+=blocks[k].rows;
410  } else {
411  offset+=blocks[k].rows*blocks[k].cols;
412  }
413  }
414  }
415 
417  s.version("FatropConicInterface", 1);
418  }
419 
422 
423  s.version("FatropConicInterface", 1);
424  }
425 
426  typedef struct FatropUserData {
427  const FatropConicInterface* solver;
428  FatropConicMemory* mem;
429  } FatropUserData;
430 
431  fatrop_int get_nx(const fatrop_int k, void* user_data) {
432  FatropUserData* data = static_cast<FatropUserData*>(user_data);
433  const auto& solver = *data->solver;
434  if (k==solver.nxs_.size()) return solver.nxs_[k-1];
435  return solver.nxs_[k];
436  }
437 
438  fatrop_int get_nu(const fatrop_int k, void* user_data) {
439  FatropUserData* data = static_cast<FatropUserData*>(user_data);
440  const auto& solver = *data->solver;
441  return solver.nus_[k];
442  }
443 
444  fatrop_int get_ng(const fatrop_int k, void* user_data) {
445  FatropUserData* data = static_cast<FatropUserData*>(user_data);
446  auto d = &data->mem->d;
447  int ret;
448  fatrop_int n_a_eq = d->a_eq_idx[k+1]-d->a_eq_idx[k];
449  fatrop_int n_x_eq = d->x_eq_idx[k+1]-d->x_eq_idx[k];
450 
451  ret = n_a_eq+n_x_eq;
452  return ret;
453  }
454 
455  fatrop_int get_n_stage_params(const fatrop_int k, void* user_data) {
456  return 0;
457  }
458 
459  fatrop_int get_n_global_params(void* user_data) {
460  return 0;
461  }
462 
463  fatrop_int get_default_stage_params(double *stage_params, const fatrop_int k, void* user_data) {
464  return 0;
465  }
466 
467  fatrop_int get_default_global_params(double *global_params, void* user_data) {
468  return 0;
469  }
470 
471  fatrop_int get_ng_ineq(const fatrop_int k, void* user_data) {
472  FatropUserData* data = static_cast<FatropUserData*>(user_data);
473  auto d = &data->mem->d;
474  fatrop_int n_a_ineq = d->a_ineq_idx[k+1]-d->a_ineq_idx[k];
475  fatrop_int n_x_ineq = d->x_ineq_idx[k+1]-d->x_ineq_idx[k];
476  return n_a_ineq+n_x_ineq;
477  }
478 
479  fatrop_int get_horizon_length(void* user_data) {
480  FatropUserData* data = static_cast<FatropUserData*>(user_data);
481  return data->solver->N_+1;
482  }
483 
484  fatrop_int eval_BAbt(const double *states_kp1, const double *inputs_k,
485  const double *states_k, const double *stage_params_k,
486  const double *global_params, MAT *res, const fatrop_int k, void* user_data) {
487  FatropUserData* data = static_cast<FatropUserData*>(user_data);
488  auto m = data->mem;
489  double one = 1.0;
490  auto d = &m->d;
491  auto p = d->prob;
492  casadi_qp_data<double>* d_qp = d->qp;
493  blasfeo_pack_tran_dmat(p->nx[k+1], p->nx[k],
494  d->AB+p->AB_offsets[k], p->nx[k+1], res, p->nu[k], 0);
495  blasfeo_pack_tran_dmat(p->nx[k+1], p->nu[k],
496  d->AB+p->AB_offsets[k]+p->nx[k]*p->nx[k+1], p->nx[k+1], res, 0, 0);
497  blasfeo_pack_dmat(1, p->nx[k+1], const_cast<double*>(d_qp->lba+p->AB[k].offset_r),
498  1, res, p->nx[k]+p->nu[k], 0);
499 
500  blasfeo_dvec v, r;
501  blasfeo_allocate_dvec(p->nx[k]+p->nu[k]+1, &v);
502  blasfeo_allocate_dvec(p->nx[k+1], &r);
503  // Fill v with [u;x;1]
504  blasfeo_pack_dvec(p->nu[k], const_cast<double*>(inputs_k), 1, &v, 0);
505  blasfeo_pack_dvec(p->nx[k], const_cast<double*>(states_k), 1, &v, p->nu[k]);
506  blasfeo_pack_dvec(1, &one, 1, &v, p->nu[k]+p->nx[k]);
507 
508  blasfeo_dgemv_t(p->nx[k]+p->nu[k]+1, p->nx[k+1], 1.0, res, 0, 0,
509  &v, 0,
510  0.0, &r, 0,
511  &r, 0);
512 
513  std::vector<double> mem(p->nx[k+1]);
514  blasfeo_unpack_dvec(p->nx[k+1], &r, 0, get_ptr(mem), 1);
515 
516  if (states_kp1) {
517  for (int i=0;i<p->nx[k+1];++i) {
518  mem[i] -= states_kp1[i];
519  }
520  }
521 
522  blasfeo_pack_dmat(1, p->nx[k+1], get_ptr(mem), 1, res, p->nx[k]+p->nu[k], 0);
523 
524  blasfeo_free_dvec(&v);
525  blasfeo_free_dvec(&r);
526 
527  return 0;
528  }
529 
530 
531  fatrop_int eval_Ggt(
532  const double *inputs_k,
533  const double *states_k,
534  const double *stage_params_k,
535  const double *global_params,
536  MAT *res,
537  const fatrop_int k, void* user_data) {
538  FatropUserData* data = static_cast<FatropUserData*>(user_data);
539  auto m = data->mem;
540 casadi_int i, column;
541  double one = 1;
542  auto d = &m->d;
543  auto p = d->prob;
544  casadi_qp_data<double>* d_qp = d->qp;
545 
546  int n_a_eq = d->a_eq_idx[k+1]-d->a_eq_idx[k];
547  int n_x_eq = d->x_eq_idx[k+1]-d->x_eq_idx[k];
548  int ng_eq = n_a_eq+n_x_eq;
549 
550  blasfeo_dgese(p->nx[k]+p->nu[k]+1, ng_eq, 0.0, res, 0, 0);
551 
552  column = 0;
553  for (i=d->a_eq_idx[k];i<d->a_eq_idx[k+1];++i) {
554  blasfeo_pack_tran_dmat(1, p->nx[k],
555  d->CD+p->CD_offsets[k]+(d->a_eq[i]-p->CD[k].offset_r),
556  p->CD[k].rows, res, p->nu[k], column);
557  blasfeo_pack_tran_dmat(1, p->nu[k],
558  d->CD+p->CD_offsets[k]+(d->a_eq[i]-p->CD[k].offset_r)+p->nx[k]*p->CD[k].rows,
559  p->CD[k].rows, res, 0, column);
560  double v = -d_qp->lba[d->a_eq[i]];
561  blasfeo_pack_tran_dmat(1, 1, &v, 1, res, p->nx[k]+p->nu[k], column);
562  column++;
563  }
564  for (i=d->x_eq_idx[k];i<d->x_eq_idx[k+1];++i) {
565  int j = d->x_eq[i]-p->CD[k].offset_c;
566  if (j>=p->nx[k]) {
567  j -= p->nx[k];
568  } else {
569  j += p->nu[k];
570  }
571  blasfeo_pack_tran_dmat(1, 1, &one, 1, res, j, column);
572  double v = -d_qp->lbx[d->x_eq[i]];
573  blasfeo_pack_tran_dmat(1, 1, &v, 1, res, p->nx[k]+p->nu[k], column);
574  column++;
575  }
576 
577  // Second part
578  blasfeo_dvec v, r;
579  blasfeo_allocate_dvec(p->nx[k]+p->nu[k]+1, &v);
580  blasfeo_allocate_dvec(ng_eq, &r);
581  // Fill v with [u;x;1]
582  blasfeo_pack_dvec(p->nu[k], const_cast<double*>(inputs_k), 1, &v, 0);
583  blasfeo_pack_dvec(p->nx[k], const_cast<double*>(states_k), 1, &v, p->nu[k]);
584  blasfeo_pack_dvec(1, &one, 1, &v, p->nu[k]+p->nx[k]);
585 
586  blasfeo_dgemv_t(p->nx[k]+p->nu[k]+1, ng_eq, 1.0, res, 0, 0,
587  &v, 0,
588  0.0, &r, 0,
589  &r, 0);
590 
591  std::vector<double> mem(ng_eq);
592  blasfeo_unpack_dvec(ng_eq, &r, 0, get_ptr(mem), 1);
593 
594  blasfeo_pack_dmat(1, ng_eq, get_ptr(mem), 1, res, p->nx[k]+p->nu[k], 0);
595 
596  blasfeo_free_dvec(&v);
597  blasfeo_free_dvec(&r);
598 
599  return 0;
600  }
601 
602  fatrop_int eval_Ggt_ineq(
603  const double *inputs_k,
604  const double *states_k,
605  const double *stage_params_k,
606  const double *global_params,
607  MAT *res,
608  const fatrop_int k, void* user_data) {
609  FatropUserData* data = static_cast<FatropUserData*>(user_data);
610  auto m = data->mem;
611  casadi_int i, column;
612  double one = 1;
613  double zero = 0;
614  auto d = &m->d;
615  auto p = d->prob;
616  //casadi_qp_data<double>* d_qp = d->qp;
617 
618  int n_a_ineq = d->a_ineq_idx[k+1]-d->a_ineq_idx[k];
619  int n_x_ineq = d->x_ineq_idx[k+1]-d->x_ineq_idx[k];
620  int ng_ineq = n_a_ineq+n_x_ineq;
621 
622  blasfeo_dgese(p->nx[k]+p->nu[k]+1, ng_ineq, 0.0, res, 0, 0);
623 
624  column = 0;
625  for (i=d->a_ineq_idx[k];i<d->a_ineq_idx[k+1];++i) {
626  blasfeo_pack_tran_dmat(1, p->nx[k],
627  d->CD+p->CD_offsets[k]+(d->a_ineq[i]-p->CD[k].offset_r),
628  p->CD[k].rows, res, p->nu[k], column);
629  blasfeo_pack_tran_dmat(1, p->nu[k],
630  d->CD+p->CD_offsets[k]+(d->a_ineq[i]-p->CD[k].offset_r)+p->nx[k]*p->CD[k].rows,
631  p->CD[k].rows, res, 0, column);
632  blasfeo_pack_tran_dmat(1, 1, &zero, 1, res, p->nx[k]+p->nu[k], column);
633  column++;
634  }
635  for (i=d->x_ineq_idx[k];i<d->x_ineq_idx[k+1];++i) {
636  int j = d->x_ineq[i]-p->CD[k].offset_c;
637  if (j>=p->nx[k]) {
638  j -= p->nx[k];
639  } else {
640  j += p->nu[k];
641  }
642  blasfeo_pack_tran_dmat(1, 1, &one, 1, res, j, column);
643  blasfeo_pack_tran_dmat(1, 1, &zero, 1, res, p->nx[k]+p->nu[k], column);
644  column++;
645  }
646 
647  // Second part
648  blasfeo_dvec v, r;
649  blasfeo_allocate_dvec(p->nx[k]+p->nu[k]+1, &v);
650  blasfeo_allocate_dvec(ng_ineq, &r);
651  // Fill v with [u;x;1]
652  blasfeo_pack_dvec(p->nu[k], const_cast<double*>(inputs_k), 1, &v, 0);
653  blasfeo_pack_dvec(p->nx[k], const_cast<double*>(states_k), 1, &v, p->nu[k]);
654  blasfeo_pack_dvec(1, &zero, 1, &v, p->nu[k]+p->nx[k]);
655 
656  blasfeo_dgemv_t(p->nx[k]+p->nu[k]+1, ng_ineq, 1.0, res, 0, 0,
657  &v, 0,
658  0.0, &r, 0,
659  &r, 0);
660  std::vector<double> mem(ng_ineq);
661  blasfeo_unpack_dvec(ng_ineq, &r, 0, get_ptr(mem), 1);
662 
663  blasfeo_pack_dmat(1, ng_ineq, get_ptr(mem), 1, res, p->nx[k]+p->nu[k], 0);
664 
665  blasfeo_free_dvec(&v);
666  blasfeo_free_dvec(&r);
667 
668  return 0;
669  }
670 
671  fatrop_int eval_RSQrqt(
672  const double *objective_scale,
673  const double *inputs_k,
674  const double *states_k,
675  const double *lam_dyn_k,
676  const double *lam_eq_k,
677  const double *lam_eq_ineq_k,
678  const double *stage_params_k,
679  const double *global_params,
680  MAT *res,
681  const fatrop_int k, void* user_data) {
682  FatropUserData* data = static_cast<FatropUserData*>(user_data);
683  auto m = data->mem;
684  const auto& solver = *data->solver;
685  casadi_assert_dev(*objective_scale==1);
686 
687  auto d = &m->d;
688  auto p = d->prob;
689  casadi_qp_data<double>* d_qp = d->qp;
690  int n = p->nx[k]+p->nu[k];
691  blasfeo_pack_dmat(p->nx[k], p->nx[k],
692  d->RSQ+p->RSQ_offsets[k], n, res, p->nu[k], p->nu[k]);
693  blasfeo_pack_dmat(p->nu[k], p->nu[k],
694  d->RSQ+p->RSQ_offsets[k]+p->nx[k]*n+p->nx[k], n, res, 0, 0);
695  blasfeo_pack_dmat(p->nu[k], p->nx[k],
696  d->RSQ+p->RSQ_offsets[k]+p->nx[k], n, res, 0, p->nu[k]);
697  blasfeo_pack_dmat(p->nx[k], p->nu[k],
698  d->RSQ+p->RSQ_offsets[k]+p->nx[k]*n, n, res, p->nu[k], 0);
699 
700  blasfeo_pack_dmat(1, p->nx[k], const_cast<double*>(d_qp->g+p->RSQ[k].offset_r),
701  1, res, p->nu[k]+p->nx[k], p->nu[k]);
702  blasfeo_pack_dmat(1, p->nu[k], const_cast<double*>(d_qp->g+p->RSQ[k].offset_r+p->nx[k]),
703  1, res, p->nu[k]+p->nx[k], 0);
704 
705  blasfeo_dvec r, v;
706  blasfeo_allocate_dvec(n, &v);
707  blasfeo_allocate_dvec(p->nx[k]+p->nu[k], &r);
708  // Fill v with [u;x]
709  blasfeo_pack_dvec(p->nu[k], const_cast<double*>(inputs_k), 1, &v, 0);
710  blasfeo_pack_dvec(p->nx[k], const_cast<double*>(states_k), 1, &v, p->nu[k]);
711 
712  blasfeo_pack_dvec(p->nx[k], const_cast<double*>(d_qp->g+p->RSQ[k].offset_r),
713  1, &r, p->nu[k]);
714  blasfeo_pack_dvec(p->nu[k], const_cast<double*>(d_qp->g+p->RSQ[k].offset_r+p->nx[k]),
715  1, &r, 0);
716 
717  blasfeo_dgemv_n(n, n, 1.0, res, 0, 0,
718  &v, 0,
719  1.0, &r, 0,
720  &r, 0);
721 
722  int n_a_eq = d->a_eq_idx[k+1]-d->a_eq_idx[k];
723  int n_x_eq = d->x_eq_idx[k+1]-d->x_eq_idx[k];
724  int ng_eq = n_a_eq+n_x_eq;
725  int n_a_ineq = d->a_ineq_idx[k+1]-d->a_ineq_idx[k];
726  int n_x_ineq = d->x_ineq_idx[k+1]-d->x_ineq_idx[k];
727  int ng_ineq = n_a_ineq+n_x_ineq;
728 
729  bool last_k = k==solver.N_;
730 
731  blasfeo_dvec lam_dyn, lam_g, lam_g_ineq;
732  blasfeo_dmat BAbtk, Ggtk, Ggt_ineqk;
733  if (!last_k)
734  blasfeo_allocate_dvec(p->nx[k+1], &lam_dyn);
735  blasfeo_allocate_dvec(ng_eq, &lam_g);
736  blasfeo_allocate_dvec(ng_ineq, &lam_g_ineq);
737  if (!last_k)
738  blasfeo_allocate_dmat(p->nx[k]+p->nu[k]+1, p->nx[k+1], &BAbtk);
739  blasfeo_allocate_dmat(p->nx[k]+p->nu[k]+1, ng_eq, &Ggtk);
740  blasfeo_allocate_dmat(p->nx[k]+p->nu[k]+1, ng_ineq, &Ggt_ineqk);
741 
742  if (!last_k)
743  eval_BAbt(0, inputs_k, states_k, stage_params_k, global_params, &BAbtk, k, user_data);
744  eval_Ggt(inputs_k, states_k, stage_params_k, global_params, &Ggtk, k, user_data);
745  eval_Ggt_ineq(inputs_k, states_k, stage_params_k, global_params, &Ggt_ineqk, k, user_data);
746 
747  if (!last_k)
748  blasfeo_pack_dvec(p->nx[k+1], const_cast<double*>(lam_dyn_k), 1, &lam_dyn, 0);
749  blasfeo_pack_dvec(ng_eq, const_cast<double*>(lam_eq_k), 1, &lam_g, 0);
750  blasfeo_pack_dvec(ng_ineq, const_cast<double*>(lam_eq_ineq_k), 1, &lam_g_ineq, 0);
751 
752  if (!last_k)
753  blasfeo_dgemv_n(p->nx[k]+p->nu[k], p->nx[k+1], 1.0, &BAbtk, 0, 0,
754  &lam_dyn, 0,
755  1.0, &r, 0,
756  &r, 0);
757 
758  blasfeo_dgemv_n(p->nx[k]+p->nu[k], ng_eq, 1.0, &Ggtk, 0, 0,
759  &lam_g, 0,
760  1.0, &r, 0,
761  &r, 0);
762 
763  blasfeo_dgemv_n(p->nx[k]+p->nu[k], ng_ineq, 1.0, &Ggt_ineqk, 0, 0,
764  &lam_g_ineq, 0,
765  1.0, &r, 0,
766  &r, 0);
767 
768  std::vector<double> mem(p->nx[k]+p->nu[k]);
769  blasfeo_unpack_dvec(p->nx[k]+p->nu[k], &r, 0, get_ptr(mem), 1);
770 
771  blasfeo_pack_dmat(1, p->nx[k]+p->nu[k], const_cast<double*>(get_ptr(mem)),
772  1, res, p->nu[k]+p->nx[k], 0);
773 
774 
775  if (!last_k)
776  blasfeo_free_dmat(&BAbtk);
777  blasfeo_free_dmat(&Ggtk);
778  blasfeo_free_dmat(&Ggt_ineqk);
779  blasfeo_free_dvec(&r);
780  if (!last_k)
781  blasfeo_free_dvec(&lam_dyn);
782  blasfeo_free_dvec(&lam_g);
783  blasfeo_free_dvec(&lam_g_ineq);
784  blasfeo_free_dvec(&v);
785 
786  return 0;
787  }
788 
789  fatrop_int eval_b(
790  const double *states_kp1,
791  const double *inputs_k,
792  const double *states_k,
793  const double *stage_params_k,
794  const double *global_params,
795  double *res,
796  const fatrop_int k, void* user_data) {
797  FatropUserData* data = static_cast<FatropUserData*>(user_data);
798  auto m = data->mem;
799  auto d = &m->d;
800  auto p = d->prob;
801 
802  blasfeo_dmat BAbtk;
803  blasfeo_allocate_dmat(p->nx[k]+p->nu[k]+1, p->nx[k+1], &BAbtk);
804  eval_BAbt(states_kp1, inputs_k, states_k, stage_params_k, global_params, &BAbtk, k, user_data);
805  blasfeo_unpack_dmat(1, p->nx[k+1], &BAbtk, p->nx[k]+p->nu[k], 0, res, 1);
806  blasfeo_free_dmat(&BAbtk);
807 
808  return 0;
809 
810  }
811 
812  fatrop_int eval_g(
813  const double *states_k,
814  const double *inputs_k,
815  const double *stage_params_k,
816  const double *global_params,
817  double *res,
818  const fatrop_int k, void* user_data) {
819  FatropUserData* data = static_cast<FatropUserData*>(user_data);
820 
821  auto m = data->mem;
822  auto d = &m->d;
823  auto p = d->prob;
824 
825  int n_a_eq = d->a_eq_idx[k+1]-d->a_eq_idx[k];
826  int n_x_eq = d->x_eq_idx[k+1]-d->x_eq_idx[k];
827  int ng_eq = n_a_eq+n_x_eq;
828 
829  blasfeo_dmat Ggtk;
830  blasfeo_allocate_dmat(p->nx[k]+p->nu[k]+1, ng_eq, &Ggtk);
831  eval_Ggt(states_k, inputs_k, stage_params_k, global_params, &Ggtk, k, user_data);
832  blasfeo_unpack_dmat(1, ng_eq, &Ggtk, p->nx[k]+p->nu[k], 0, res, 1);
833  blasfeo_free_dmat(&Ggtk);
834 
835  return 0;
836  }
837 
838  fatrop_int eval_gineq(
839  const double *states_k,
840  const double *inputs_k,
841  const double *stage_params_k,
842  const double *global_params,
843  double *res,
844  const fatrop_int k, void* user_data) {
845  FatropUserData* data = static_cast<FatropUserData*>(user_data);
846  auto m = data->mem;
847  auto d = &m->d;
848  auto p = d->prob;
849 
850  int n_a_ineq = d->a_ineq_idx[k+1]-d->a_ineq_idx[k];
851  int n_x_ineq = d->x_ineq_idx[k+1]-d->x_ineq_idx[k];
852  int ng_ineq = n_a_ineq+n_x_ineq;
853 
854 
855  blasfeo_dmat Ggtk;
856  blasfeo_allocate_dmat(p->nx[k]+p->nu[k]+1, ng_ineq, &Ggtk);
857  eval_Ggt_ineq(states_k, inputs_k, stage_params_k, global_params, &Ggtk, k, user_data);
858  blasfeo_unpack_dmat(1, ng_ineq, &Ggtk, p->nx[k]+p->nu[k], 0, res, 1);
859  blasfeo_free_dmat(&Ggtk);
860 
861  return 0;
862  }
863 
864  fatrop_int eval_rq(
865  const double *objective_scale,
866  const double *inputs_k,
867  const double *states_k,
868  const double *stage_params_k,
869  const double *global_params,
870  double *res,
871  const fatrop_int k, void* user_data) {
872  FatropUserData* data = static_cast<FatropUserData*>(user_data);
873  auto m = data->mem;
874  *res = 0.0;
875  casadi_assert_dev(*objective_scale==1);
876  auto d = &m->d;
877  auto p = d->prob;
878  casadi_qp_data<double>* d_qp = d->qp;
879  blasfeo_dmat RSQrqtk;
880 
881  int n = p->nx[k]+p->nu[k];
882 
883  blasfeo_dvec v, r;
884  blasfeo_allocate_dmat(n, n, &RSQrqtk);
885  blasfeo_allocate_dvec(n, &v);
886  blasfeo_allocate_dvec(n, &r);
887  blasfeo_pack_dmat(p->nx[k], p->nx[k], d->RSQ+p->RSQ_offsets[k],
888  n, &RSQrqtk, p->nu[k], p->nu[k]);
889  blasfeo_pack_dmat(p->nu[k], p->nu[k], d->RSQ+p->RSQ_offsets[k]+p->nx[k]*n+p->nx[k],
890  n, &RSQrqtk, 0, 0);
891  blasfeo_pack_dmat(p->nu[k], p->nx[k], d->RSQ+p->RSQ_offsets[k]+p->nx[k],
892  n, &RSQrqtk, 0, p->nu[k]);
893  blasfeo_pack_dmat(p->nx[k], p->nu[k], d->RSQ+p->RSQ_offsets[k]+p->nx[k]*n,
894  n, &RSQrqtk, p->nu[k], 0);
895 
896  // Fill v with [u;x]
897  blasfeo_pack_dvec(p->nu[k], const_cast<double*>(inputs_k), 1, &v, 0);
898  blasfeo_pack_dvec(p->nx[k], const_cast<double*>(states_k), 1, &v, p->nu[k]);
899 
900  blasfeo_pack_dvec(p->nx[k], const_cast<double*>(d_qp->g+p->RSQ[k].offset_r), 1, &r, p->nu[k]);
901  blasfeo_pack_dvec(p->nu[k], const_cast<double*>(d_qp->g+p->RSQ[k].offset_r+p->nx[k]), 1, &r, 0);
902 
903  blasfeo_dgemv_n(n, n, 1.0, &RSQrqtk, 0, 0,
904  &v, 0,
905  1.0, &r, 0,
906  &r, 0);
907 
908  blasfeo_unpack_dvec(n, &r, 0, res, 1);
909 
910  blasfeo_free_dmat(&RSQrqtk);
911  blasfeo_free_dvec(&v);
912  blasfeo_free_dvec(&r);
913 
914  return 0;
915  }
916 
917  fatrop_int eval_L(
918  const double *objective_scale,
919  const double *inputs_k,
920  const double *states_k,
921  const double *stage_params_k,
922  const double *global_params,
923  double *res,
924  const fatrop_int k, void* user_data) {
925  FatropUserData* data = static_cast<FatropUserData*>(user_data);
926  auto m = data->mem;
927  *res = 0.0;
928  casadi_assert_dev(*objective_scale==1);
929  auto d = &m->d;
930  auto p = d->prob;
931  casadi_qp_data<double>* d_qp = d->qp;
932  blasfeo_dmat RSQrqtk;
933 
934  int n = p->nx[k]+p->nu[k];
935 
936  blasfeo_dvec v, r;
937  blasfeo_allocate_dmat(n, n, &RSQrqtk);
938  blasfeo_allocate_dvec(n, &v);
939  blasfeo_allocate_dvec(n, &r);
940  blasfeo_pack_dmat(p->nx[k], p->nx[k], d->RSQ+p->RSQ_offsets[k],
941  n, &RSQrqtk, p->nu[k], p->nu[k]);
942  blasfeo_pack_dmat(p->nu[k], p->nu[k], d->RSQ+p->RSQ_offsets[k]+p->nx[k]*n+p->nx[k],
943  n, &RSQrqtk, 0, 0);
944  blasfeo_pack_dmat(p->nu[k], p->nx[k], d->RSQ+p->RSQ_offsets[k]+p->nx[k],
945  n, &RSQrqtk, 0, p->nu[k]);
946  blasfeo_pack_dmat(p->nx[k], p->nu[k], d->RSQ+p->RSQ_offsets[k]+p->nx[k]*n,
947  n, &RSQrqtk, p->nu[k], 0);
948 
949  // Fill v with [u;x]
950  blasfeo_pack_dvec(p->nu[k], const_cast<double*>(inputs_k), 1, &v, 0);
951  blasfeo_pack_dvec(p->nx[k], const_cast<double*>(states_k), 1, &v, p->nu[k]);
952 
953  blasfeo_dgemv_n(n, n, 1.0, &RSQrqtk, 0, 0,
954  &v, 0,
955  0.0, &r, 0,
956  &r, 0);
957 
958  double obj = 0.5*blasfeo_ddot(n, &v, 0, &r, 0);
959 
960  blasfeo_pack_dvec(p->nx[k], const_cast<double*>(d_qp->g+p->RSQ[k].offset_r),
961  1, &r, p->nu[k]);
962  blasfeo_pack_dvec(p->nu[k], const_cast<double*>(d_qp->g+p->RSQ[k].offset_r+p->nx[k]),
963  1, &r, 0);
964 
965  obj += blasfeo_ddot(n, &v, 0, &r, 0);
966 
967  blasfeo_free_dmat(&RSQrqtk);
968  blasfeo_free_dvec(&v);
969  blasfeo_free_dvec(&r);
970  *res = obj;
971 
972  return 0;
973 
974  }
975 
976  fatrop_int get_bounds(double *lower, double *upper, const fatrop_int k, void* user_data) {
977  FatropUserData* data = static_cast<FatropUserData*>(user_data);
978  auto m = data->mem;
979  auto d = &m->d;
980  //auto p = d->prob;
981  casadi_qp_data<double>* d_qp = d->qp;
982  int i=0;
983  int column = 0;
984  for (i=d->a_ineq_idx[k];i<d->a_ineq_idx[k+1];++i) {
985  lower[column] = d_qp->lba[d->a_ineq[i]];
986  upper[column] = d_qp->uba[d->a_ineq[i]];
987  column++;
988  }
989  //int offset = d->a_ineq_idx[k+1]-d->a_ineq_idx[k];
990  for (i=d->x_ineq_idx[k];i<d->x_ineq_idx[k+1];++i) {
991  lower[column] = d_qp->lbx[d->x_ineq[i]];
992  upper[column] = d_qp->ubx[d->x_ineq[i]];
993  column++;
994  }
995 
996  //fatrop_int n_a_ineq = d->a_ineq_idx[k+1]-d->a_ineq_idx[k];
997  //fatrop_int n_x_ineq = d->x_ineq_idx[k+1]-d->x_ineq_idx[k];
998  //fatrop_int ng_ineq = n_a_ineq+n_x_ineq;
999 
1000  return 0;
1001  }
1002 
1003  fatrop_int get_initial_xk(double *xk, const fatrop_int k, void* user_data) {
1004  FatropUserData* data = static_cast<FatropUserData*>(user_data);
1005  auto m = data->mem;
1006  auto d = &m->d;
1007  auto p = d->prob;
1008  casadi_qp_data<double>* d_qp = d->qp;
1009  casadi_copy(d_qp->x0+p->CD[k].offset_c, p->nx[k], xk);
1010 
1011  return 0;
1012  }
1013 
1014  fatrop_int get_initial_uk(double *uk, const fatrop_int k, void* user_data) {
1015  FatropUserData* data = static_cast<FatropUserData*>(user_data);
1016  auto m = data->mem;
1017  auto d = &m->d;
1018  auto p = d->prob;
1019  casadi_qp_data<double>* d_qp = d->qp;
1020  casadi_copy(d_qp->x0+p->CD[k].offset_c+p->nx[k], p->nu[k], uk);
1021  return 0;
1022  }
1023 
1024  void dummy_signal(void* user_data) {
1025 
1026  }
1027 
1028  fatrop_int full_eval_lag_hess(double objective_scale,
1029  const double* primal_data, const double* lam_data,
1030  const double* stageparams_p, const double* globalparams_p,
1031  MAT * RSQrqt_p, const FatropOcpCDims* s, void* user_data) {
1032  return 0;
1033  }
1034 
1035  fatrop_int full_eval_constr_jac(const double* primal_data,
1036  const double* stageparams_p, const double* globalparams_p,
1037  MAT* BAbt_p, MAT* Ggt_p, MAT* Ggt_ineq_p, const FatropOcpCDims* s, void* user_data) {
1038  return 0;
1039  }
1040 
1041  fatrop_int full_eval_contr_viol(const double* primal_data,
1042  const double* stageparams_p, const double* globalparams_p,
1043  double* cv_p, const FatropOcpCDims* s, void* user_data) {
1044  return 0;
1045  }
1046 
1047  fatrop_int full_eval_obj_grad(double objective_scale, const double* primal_data,
1048  const double* stageparams_p, const double* globalparams_p,
1049  double* grad_p, const FatropOcpCDims* s, void* user_data) {
1050  return 0;
1051  }
1052 
1053  fatrop_int full_eval_obj(double objective_scale, const double* primal_data,
1054  const double* stageparams_p, const double* globalparams_p,
1055  double* res, const FatropOcpCDims* s, void* user_data) {
1056  return 0;
1057  }
1058 
1059 
1061  solve(const double** arg, double** res, casadi_int* iw, double* w, void* mem) const {
1062  auto m = static_cast<FatropConicMemory*>(mem);
1063 
1064 
1065  casadi_fatrop_conic_solve(&m->d, arg, res, iw, w);
1066 
1067  // Statistics
1068  m->fstats.at("solver").tic();
1069 
1070  FatropOcpCInterface ocp_interface;
1071  ocp_interface.get_nx = get_nx;
1072  ocp_interface.get_nu = get_nu;
1073  ocp_interface.get_ng = get_ng;
1074  ocp_interface.get_n_stage_params = get_n_stage_params;
1075  ocp_interface.get_n_global_params = get_n_global_params;
1076  ocp_interface.get_default_stage_params = get_default_stage_params;
1077  ocp_interface.get_default_global_params = get_default_global_params;
1078  ocp_interface.get_ng_ineq = get_ng_ineq;
1079  ocp_interface.get_horizon_length = get_horizon_length;
1080  ocp_interface.eval_BAbt = eval_BAbt;
1081  ocp_interface.eval_Ggt = eval_Ggt;
1082  ocp_interface.eval_Ggt_ineq = eval_Ggt_ineq;
1083  ocp_interface.eval_RSQrqt = eval_RSQrqt;
1084  ocp_interface.eval_b = eval_b;
1085  ocp_interface.eval_g = eval_g;
1086  ocp_interface.eval_gineq = eval_gineq;
1087  ocp_interface.eval_rq = eval_rq;
1088  ocp_interface.eval_L = eval_L;
1089  ocp_interface.get_bounds = get_bounds;
1090  ocp_interface.get_initial_xk = get_initial_xk;
1091  ocp_interface.get_initial_uk = get_initial_uk;
1092  ocp_interface.full_eval_lag_hess = full_eval_lag_hess;
1093  ocp_interface.full_eval_constr_jac = full_eval_constr_jac;
1094  ocp_interface.full_eval_contr_viol = full_eval_contr_viol;
1095  ocp_interface.full_eval_obj_grad = full_eval_obj_grad;
1096  ocp_interface.full_eval_obj = full_eval_obj;
1097 
1098  FatropUserData user_data;
1099  user_data.solver = this;
1100  user_data.mem = static_cast<FatropConicMemory*>(mem);
1101 
1102  ocp_interface.user_data = &user_data;
1103 
1104  uout() << "ocp_interface" << ocp_interface.get_horizon_length << std::endl;
1105 
1106 
1107  FatropOcpCSolver* s = fatrop_ocp_c_create(&ocp_interface, 0, 0);
1108 
1109  int ret = fatrop_ocp_c_solve(s);
1110 
1111  uout() << "ret" << ret << std::endl;
1112 
1113  if (ret) {
1114  m->d_qp.success = false;
1115  m->d.return_status = "failed";
1116  return 0;
1117  }
1118 
1119  // u0 x0 u1 u2 ...
1120  const blasfeo_dvec* primal = fatrop_ocp_c_get_primal(s);
1121  // eq, dynamic, ineq
1122  const blasfeo_dvec* dual = fatrop_ocp_c_get_dual(s);
1123 
1124  auto d = &m->d;
1125  auto p = d->prob;
1126  casadi_qp_data<double>* d_qp = d->qp;
1127 
1128  // Unpack primal solution
1129  casadi_int offset_fatrop = 0;
1130  casadi_int offset_casadi = 0;
1131  for (int k=0;k<N_+1;++k) {
1132  blasfeo_unpack_dvec(p->nu[k], const_cast<blasfeo_dvec*>(primal),
1133  offset_fatrop, d_qp->x+offset_casadi+p->nx[k], 1);
1134  offset_fatrop += p->nu[k];
1135  blasfeo_unpack_dvec(p->nx[k], const_cast<blasfeo_dvec*>(primal),
1136  offset_fatrop, d_qp->x+offset_casadi, 1);
1137  offset_fatrop += p->nx[k];
1138  offset_casadi += p->nx[k]+p->nu[k];
1139  }
1140 
1141  blasfeo_print_dvec(offset_casadi, const_cast<blasfeo_dvec*>(primal), 0);
1142 
1143  m->d_qp.success = true;
1144  m->d_qp.unified_return_status = SOLVER_RET_SUCCESS;
1145  m->d.return_status = "solved";
1146 
1147  std::vector<double> dualv(nx_+na_);
1148  blasfeo_unpack_dvec(nx_+na_, const_cast<blasfeo_dvec*>(dual), 0, get_ptr(dualv), 1);
1149 
1150  // Unpack dual solution
1151  offset_fatrop = 0;
1152  // Inequalities
1153  for (int k=0;k<N_+1;++k) {
1154  for (casadi_int i=d->a_eq_idx[k];i<d->a_eq_idx[k+1];++i) {
1155  d_qp->lam_a[d->a_eq[i]] = dualv[offset_fatrop++];
1156  }
1157  for (casadi_int i=d->x_eq_idx[k];i<d->x_eq_idx[k+1];++i) {
1158  d_qp->lam_x[d->x_eq[i]] = dualv[offset_fatrop++];
1159  }
1160  }
1161  // Dynamics
1162  for (int k=0;k<N_;++k) {
1163  for (casadi_int i=0;i<p->nx[k];++i) {
1164  d_qp->lam_a[AB_blocks[k].offset_r+i] = -dualv[offset_fatrop++];
1165  }
1166  }
1167  // Inequalities
1168  for (int k=0;k<N_+1;++k) {
1169  for (casadi_int i=d->a_ineq_idx[k];i<d->a_ineq_idx[k+1];++i) {
1170  d_qp->lam_a[d->a_ineq[i]] = dualv[offset_fatrop++];
1171  }
1172  for (casadi_int i=d->x_ineq_idx[k];i<d->x_ineq_idx[k+1];++i) {
1173  d_qp->lam_x[d->x_ineq[i]] = dualv[offset_fatrop++];
1174  }
1175  }
1176  //const fatrop::FatropVecBF& primal = app.last_solution_primal();
1177  //const fatrop::FatropVecBF& dual = app.last_solution_dual();
1178 
1179  //primal.vec_;
1180 
1181  m->fstats.at("solver").toc();
1182 
1183  //fatrop::FatropStats stats = app.get_stats();
1184 
1185  // success
1186  // fail
1187 
1188  fatrop_ocp_c_destroy(s);
1189 
1190  return 0;
1191  }
1192 
1193 } // namespace casadi
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
casadi_int na_
The number of constraints (counting both equality and inequality) == A.size1()
Definition: conic_impl.hpp:176
void init(const Dict &opts) override
Initialize.
Definition: conic.cpp:415
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
Helper class for Serialization.
void version(const std::string &name, int v)
FatropConicInterface()
Constructor.
static const std::string meta_doc
A documentation string.
std::vector< casadi_ocp_block > CD_blocks
std::vector< casadi_ocp_block > AB_blocks
std::vector< casadi_int > CD_offsets_
int solve(const double **arg, double **res, casadi_int *iw, double *w, void *mem) const override
Evaluate numerically.
casadi_fatrop_conic_prob< double > p_
std::vector< casadi_int > AB_offsets_
void init(const Dict &opts) override
Initialize.
Dict get_stats(void *mem) const override
Get all statistics.
static Sparsity blocksparsity(casadi_int rows, casadi_int cols, const std::vector< casadi_ocp_block > &blocks, bool eye=false)
static const Options options_
Options.
~FatropConicInterface() override
Destructor.
static Conic * creator(const std::string &name, const std::map< std::string, Sparsity > &st)
Create a new QP Solver.
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_ocp_block > RSQ_blocks
static void blockptr(std::vector< double * > &vs, std::vector< double > &v, const std::vector< casadi_ocp_block > &blocks, bool eye=false)
void set_temp(void *mem, const double **arg, double **res, casadi_int *iw, double *w) const override
Set the (temporary) work vectors.
int init_mem(void *mem) const override
Initalize memory block.
void serialize_body(SerializingStream &s) const override
Serialize an object without type information.
std::vector< casadi_int > RSQ_offsets_
std::vector< casadi_ocp_block > I_blocks
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.
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.
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 verbose_
Verbose printout.
void clear_mem()
Clear all memory (called from destructor)
Helper class for Serialization.
void version(const std::string &name, int v)
General sparsity class.
Definition: sparsity.hpp:106
Sparsity T() const
Transpose the matrix.
Definition: sparsity.cpp:394
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
void CASADI_CONIC_FATROP_EXPORT casadi_load_conic_fatrop()
void dummy_signal(void *user_data)
std::vector< casadi_int > range(casadi_int start, casadi_int stop, casadi_int step, casadi_int len)
Range function.
fatrop_int get_initial_uk(double *uk, const fatrop_int k, void *user_data)
fatrop_int get_horizon_length(void *user_data)
std::vector< casadi_int > fatrop_blocks_pack(const std::vector< casadi_ocp_block > &blocks)
fatrop_int full_eval_constr_jac(const double *primal_data, const double *stageparams_p, const double *globalparams_p, MAT *BAbt_p, MAT *Ggt_p, MAT *Ggt_ineq_p, const FatropOcpCDims *s, void *user_data)
fatrop_int get_nu(const fatrop_int k, void *user_data)
fatrop_int get_ng_ineq(const fatrop_int k, void *user_data)
fatrop_int eval_BAbt(const double *states_kp1, const double *inputs_k, const double *states_k, const double *stage_params_k, const double *global_params, MAT *res, const fatrop_int k, void *user_data)
fatrop_int get_n_global_params(void *user_data)
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
fatrop_int full_eval_lag_hess(double objective_scale, const double *primal_data, const double *lam_data, const double *stageparams_p, const double *globalparams_p, MAT *RSQrqt_p, const FatropOcpCDims *s, void *user_data)
fatrop_int eval_RSQrqt(const double *objective_scale, const double *inputs_k, const double *states_k, const double *lam_dyn_k, const double *lam_eq_k, const double *lam_eq_ineq_k, const double *stage_params_k, const double *global_params, MAT *res, const fatrop_int k, void *user_data)
fatrop_int eval_Ggt(const double *inputs_k, const double *states_k, const double *stage_params_k, const double *global_params, MAT *res, const fatrop_int k, void *user_data)
fatrop_int eval_gineq(const double *states_k, const double *inputs_k, const double *stage_params_k, const double *global_params, double *res, const fatrop_int k, void *user_data)
@ OT_INTVECTOR
fatrop_int eval_L(const double *objective_scale, const double *inputs_k, const double *states_k, const double *stage_params_k, const double *global_params, double *res, const fatrop_int k, void *user_data)
std::string str(const T &v)
String representation, any type.
fatrop_int full_eval_obj(double objective_scale, const double *primal_data, const double *stageparams_p, const double *globalparams_p, double *res, const FatropOcpCDims *s, void *user_data)
fatrop_int get_ng(const fatrop_int k, void *user_data)
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
fatrop_int full_eval_contr_viol(const double *primal_data, const double *stageparams_p, const double *globalparams_p, double *cv_p, const FatropOcpCDims *s, void *user_data)
fatrop_int eval_Ggt_ineq(const double *inputs_k, const double *states_k, const double *stage_params_k, const double *global_params, MAT *res, const fatrop_int k, void *user_data)
fatrop_int eval_b(const double *states_kp1, const double *inputs_k, const double *states_k, const double *stage_params_k, const double *global_params, double *res, const fatrop_int k, void *user_data)
fatrop_int full_eval_obj_grad(double objective_scale, const double *primal_data, const double *stageparams_p, const double *globalparams_p, double *grad_p, const FatropOcpCDims *s, void *user_data)
int CASADI_CONIC_FATROP_EXPORT casadi_register_conic_fatrop(Conic::Plugin *plugin)
fatrop_int eval_rq(const double *objective_scale, const double *inputs_k, const double *states_k, const double *stage_params_k, const double *global_params, double *res, const fatrop_int k, void *user_data)
static double blasfeo_ddot(casadi_int n, const double *x, const double *y)
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
fatrop_int get_nx(const fatrop_int k, void *user_data)
fatrop_int eval_g(const double *states_k, const double *inputs_k, const double *stage_params_k, const double *global_params, double *res, const fatrop_int k, void *user_data)
fatrop_int get_default_global_params(double *global_params, void *user_data)
std::ostream & uout()
fatrop_int get_n_stage_params(const fatrop_int k, void *user_data)
@ SOLVER_RET_SUCCESS
fatrop_int get_initial_xk(double *xk, const fatrop_int k, void *user_data)
fatrop_int get_default_stage_params(double *stage_params, const fatrop_int k, void *user_data)
fatrop_int get_bounds(double *lower, double *upper, const fatrop_int k, void *user_data)
casadi_fatrop_conic_data< double > d
Options metadata for a class.
Definition: options.hpp:40
void add_stat(const std::string &s)
const casadi_qp_prob< T1 > * qp
const T1 * lba
Definition: casadi_qp.hpp:64
const T1 * lbx
Definition: casadi_qp.hpp:64
const T1 * uba
Definition: casadi_qp.hpp:64
const T1 * ubx
Definition: casadi_qp.hpp:64
const T1 * x0
Definition: casadi_qp.hpp:64
const T1 * g
Definition: casadi_qp.hpp:64