madnlp_runtime.hpp
1 //
2 // MIT No Attribution
3 //
4 // Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl, KU Leuven.
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy of this
7 // software and associated documentation files (the "Software"), to deal in the Software
8 // without restriction, including without limitation the rights to use, copy, modify,
9 // merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
10 // permit persons to whom the Software is furnished to do so.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13 // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
14 // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
15 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
16 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
17 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 //
19 
20 // C-REPLACE "SOLVER_RET_SUCCESS" "0"
21 // C-REPLACE "SOLVER_RET_UNKNOWN" "1"
22 // C-REPLACE "SOLVER_RET_LIMITED" "2"
23 // C-REPLACE "SOLVER_RET_NAN" "3"
24 // C-REPLACE "SOLVER_RET_INFEASIBLE" "4"
25 // C-REPLACE "SOLVER_RET_EXCEPTION" "5"
26 
27 // C-REPLACE "casadi_nlpsol_prob<T1>" "struct casadi_nlpsol_prob"
28 // C-REPLACE "casadi_nlpsol_data<T1>" "struct casadi_nlpsol_data"
29 
30 // C-REPLACE "reinterpret_cast<int**>" "(int**) "
31 // C-REPLACE "reinterpret_cast<int*>" "(int*) "
32 // C-REPLACE "const_cast<int*>" "(int*) "
33 
34 // C-REPLACE "OracleCallback" "struct casadi_oracle_callback"
35 
36 // SYMBOL "madnlp_prob"
37 template<typename T1>
40 
41  // Sparsity patterns
42  const casadi_int *sp_h, *sp_a;
43 
44  casadi_int nnz_hess_l, nnz_jac_g;
45 
46  OracleCallback nlp_hess_l;
47  OracleCallback nlp_jac_g;
48  OracleCallback nlp_grad_f;
49  OracleCallback nlp_f;
50  OracleCallback nlp_g;
51 };
52 // C-REPLACE "casadi_madnlp_prob<T1>" "struct casadi_madnlp_prob"
53 
54 // SYMBOL "madnlp_data"
55 template<typename T1>
57  // Problem structure
59  // Problem structure
61 
62  const T1** arg;
63  T1** res;
64  casadi_int* iw;
65  T1 *w;
66 
67  // temporary data
68  T1 *x, *lam_g, *g, *f, *jac_g, *grad_f, *hess_l, *grad_l;
69 
71  int success;
72 
73  //struct blasfeo_dvec v, r;
74  //struct blasfeo_dmat R;
75 
76  CNLPModel* cnlp_model;
77  OptsDict* libmad_opts;
78  MadNLPExecutionStats* stats;
79  MadNLPSolver* solver;
80 };
81 // C-REPLACE "casadi_madnlp_data<T1>" "struct casadi_madnlp_data"
82 
83 // SYMBOL "madnlp_setup"
84 template<typename T1>
85 void casadi_madnlp_setup(casadi_madnlp_prob<T1>* p) {
86  if (p->sp_h) {
87  p->nnz_hess_l = p->sp_h[2+p->sp_h[1]];
88  } else {
89  p->nnz_hess_l = 0;
90  }
91  p->nnz_jac_g = p->sp_a[2+p->sp_a[1]];
92 }
93 
94 // C-REPLACE "static_cast< casadi_madnlp_data<T1>* >" "(struct casadi_madnlp_data*)"
95 // C-REPLACE "casadi_oracle_data<T1>" "struct casadi_oracle_data"
96 // C-REPLACE "calc_function" "casadi_oracle_call"
97 // C-REPLACE "casadi_error" "//casadi_error"
98 
99 // SYMBOL "madnlp_constr_jac_structure"
100 template<typename T1>
101 int casadi_madnlp_constr_jac_structure(libmad_int* I, libmad_int* J, void* user_data)
102 {
103  casadi_int cc, el;
104  const casadi_int *colind, *row;
105  casadi_madnlp_data<T1>* d = static_cast< casadi_madnlp_data<T1>* >(user_data);
106  const casadi_madnlp_prob<T1>* p = d->prob;
107 
108  // convert ccs to cco
109  casadi_int ncol = p->sp_a[1];
110  colind = p->sp_a+2;
111  row = colind+ncol+1;
112 
113  for (cc=0; cc<ncol; ++cc) {
114  for (el=colind[cc]; el<colind[cc+1]; ++el) {
115  *I++ = row[el]+1;
116  *J++ = cc+1;
117  }
118  }
119  return 0;
120 }
121 // C-REPLACE "casadi_madnlp_constr_jac_structure<T1>" "casadi_madnlp_constr_jac_structure"
122 
123 // SYMBOL "madnlp_lag_hess_structure"
124 template<typename T1>
125 int casadi_madnlp_lag_hess_structure(libmad_int* I, libmad_int* J, void* user_data)
126 {
127  casadi_int cc, el;
128  const casadi_int *colind, *row;
129  casadi_madnlp_data<T1>* d = static_cast< casadi_madnlp_data<T1>* >(user_data);
130  const casadi_madnlp_prob<T1>* p = d->prob;
131 
132  // convert ccs to cco
133  casadi_int ncol = p->sp_h[1];
134  colind = p->sp_h+2;
135  row = colind+ncol+1;
136 
137  for (cc=0; cc<ncol; ++cc) {
138  for (el=colind[cc]; el<colind[cc+1]; ++el) {
139  *I++ = row[el]+1;
140  *J++ = cc+1;
141  }
142  }
143  return 0;
144 }
145 // C-REPLACE "casadi_madnlp_lag_hess_structure<T1>" "casadi_madnlp_lag_hess_structure"
146 
147 // SYMBOL "madnlp_eval_constr_jac"
148 template<typename T1>
149 int casadi_madnlp_eval_constr_jac(const T1* w, T1* res, void* user_data) {
150  casadi_madnlp_data<T1>* d = static_cast< casadi_madnlp_data<T1>* >(user_data);
151  casadi_nlpsol_data<T1>* d_nlp = d->nlp;
152  casadi_oracle_data<T1>* d_oracle = d_nlp->oracle;
153 
154  d_oracle->arg[0] = w;
155  d_oracle->arg[1] = d_nlp->p;
156  d_oracle->res[0] = res;
157 
158  return calc_function(&d->prob->nlp_jac_g, d_oracle);
159 }
160 
161 // SYMBOL "madnlp_eval_constr"
162 template<typename T1>
163 int casadi_madnlp_eval_constr(const T1* w, T1* res, void* user_data) {
164  casadi_madnlp_data<T1>* d = static_cast< casadi_madnlp_data<T1>* >(user_data);
165  casadi_nlpsol_data<T1>* d_nlp = d->nlp;
166  casadi_oracle_data<T1>* d_oracle = d_nlp->oracle;
167 
168  d_oracle->arg[0] = w;
169  d_oracle->arg[1] = d_nlp->p;
170  d_oracle->res[0] = res;
171 
172  return calc_function(&d->prob->nlp_g, d_oracle);
173 }
174 
175 // SYMBOL "madnlp_eval_obj_grad"
176 template<typename T1>
177 int casadi_madnlp_eval_obj_grad(const T1* w, T1* res, void* user_data) {
178  casadi_madnlp_data<T1>* d = static_cast< casadi_madnlp_data<T1>* >(user_data);
179  casadi_nlpsol_data<T1>* d_nlp = d->nlp;
180  casadi_oracle_data<T1>* d_oracle = d_nlp->oracle;
181 
182  // TODO add argument
183  //T1 objective_scale = 1.0;
184 
185  d_oracle->arg[0] = w;
186  d_oracle->arg[1] = d_nlp->p;
187  d_oracle->res[0] = res;
188  return calc_function(&d->prob->nlp_grad_f, d_oracle);
189 }
190 
191 // SYMBOL "madnlp_eval_obj"
192 template<typename T1>
193 int casadi_madnlp_eval_obj(const T1* w, T1* res, void* user_data) {
194  casadi_madnlp_data<T1>* d = static_cast< casadi_madnlp_data<T1>* >(user_data);
195  casadi_nlpsol_data<T1>* d_nlp = d->nlp;
196  casadi_oracle_data<T1>* d_oracle = d_nlp->oracle;
197 
198  // TODO add argument
199  //T1 objective_scale = 1.0;
200 
201  d_oracle->arg[0] = w;
202  d_oracle->arg[1] = d_nlp->p;
203  d_oracle->res[0] = res;
204  return calc_function(&d->prob->nlp_f, d_oracle);
205 }
206 
207 // SYMBOL "madnlp_eval_lag_hess"
208 template<typename T1>
209 int casadi_madnlp_eval_lag_hess(T1 objective_scale, const T1* w, const T1* lam,
210  T1* res, void* user_data){
211  casadi_madnlp_data<T1>* d = static_cast< casadi_madnlp_data<T1>* >(user_data);
212  casadi_nlpsol_data<T1>* d_nlp = d->nlp;
213  casadi_oracle_data<T1>* d_oracle = d_nlp->oracle;
214 
215  // evaluate hessian with given parameters / inputs
216  d_oracle->arg[0] = w;
217  d_oracle->arg[1] = d_nlp->p;
218  d_oracle->arg[2] = &objective_scale;
219  d_oracle->arg[3] = lam;
220  d_oracle->res[0] = res;
221 
222  return calc_function(&d->prob->nlp_hess_l, d_oracle);
223 }
224 
225 // C-REPLACE "const_cast<T1*>" "(T1*)"
226 
227 // C-REPLACE "casadi_madnlp_eval_constr_jac<T1>" "casadi_madnlp_eval_constr_jac"
228 // C-REPLACE "casadi_madnlp_eval_obj_grad<T1>" "casadi_madnlp_eval_obj_grad"
229 // C-REPLACE "casadi_madnlp_eval_obj<T1>" "casadi_madnlp_eval_obj"
230 // C-REPLACE "casadi_madnlp_eval_constr<T1>" "casadi_madnlp_eval_constr"
231 // C-REPLACE "casadi_madnlp_eval_lag_hess<T1>" "casadi_madnlp_eval_lag_hess"
232 // C-REPLACE "std::numeric_limits<T1>::infinity()" "casadi_inf"
233 
234 // SYMBOL "madnlp_init_mem"
235 template<typename T1>
236 int casadi_madnlp_init_mem(casadi_madnlp_data<T1>* d) {
237  // Problem structure
238 
239  return 0;
240 }
241 
242 // SYMBOL "madnlp_free_mem"
243 template<typename T1>
244 void casadi_madnlp_free_mem(casadi_madnlp_data<T1>* d) {
245  madnlp_delete_solver(d->solver);
246  d->solver = 0;
247  madnlp_delete_stats(d->stats);
248  d->stats = 0;
249  libmad_delete_options_dict(d->libmad_opts);
250 }
251 
252 // SYMBOL "madnlp_work"
253 template<typename T1>
254 void casadi_madnlp_work(const casadi_madnlp_prob<T1>* p, casadi_int* sz_arg, casadi_int* sz_res, casadi_int* sz_iw, casadi_int* sz_w) {
255  casadi_nlpsol_work(p->nlp, sz_arg, sz_res, sz_iw, sz_w);
256 
257  // Temporary work vectors
258  *sz_w = casadi_max(*sz_w, 2*(p->nlp->nx+p->nlp->ng)); // pv
259 }
260 
261 // SYMBOL "madnlp_set_work"
262 template<typename T1>
263 void casadi_madnlp_set_work(casadi_madnlp_data<T1>* d, const T1*** arg, T1*** res, casadi_int** iw, T1** w) {
264  // Problem structure
265  d->arg = *arg;
266  d->res = *res;
267  d->iw = *iw;
268  d->w = *w;
269 }
270 
271 // SYMBOL "madnlp_presolve"
272 template<typename T1>
273 int casadi_madnlp_presolve(casadi_madnlp_data<T1>* d) {
274  int ret;
275  const casadi_madnlp_prob<T1>* p = d->prob;
276  const casadi_nlpsol_prob<T1>* p_nlp = p->nlp;
277  casadi_nlpsol_data<T1>* d_nlp = d->nlp;
278 
280  d->success = 0;
281  ret = libmad_nlpmodel_create(&(d->cnlp_model),
282  "MadNLP",
283  p_nlp->nx, p_nlp->ng,
284  p->nnz_jac_g, p->nnz_hess_l,
285  casadi_madnlp_constr_jac_structure<T1>,
286  casadi_madnlp_lag_hess_structure<T1>,
287  casadi_madnlp_eval_obj<T1>,
288  casadi_madnlp_eval_constr<T1>,
289  casadi_madnlp_eval_obj_grad<T1>,
290  casadi_madnlp_eval_constr_jac<T1>,
291  casadi_madnlp_eval_lag_hess<T1>,
292  d
293  );
294  if (ret != 0) return -1; // Failed to create model
295  // set initial guess
296  ret = libmad_nlpmodel_set_numerics(d->cnlp_model,
297  d_nlp->z, d_nlp->lam + p_nlp->nx,
298  d_nlp->lbx, d_nlp->ubx,
299  d_nlp->lbg, d_nlp->ubg);
300  if (ret != 0) return -2; // Failed to set numerics
301  ret = madnlp_create_solver(&(d->solver), d->cnlp_model, d->libmad_opts);
302  if (ret != 0) return -3; // Failed to create solver
303 
304  return 0;
305 }
306 
307 // SYMBOL "madnlp_solve"
308 template<typename T1>
309 int casadi_madnlp_solve(casadi_madnlp_data<T1>* d) {
310  // Problem structure
311  casadi_nlpsol_data<T1>* d_nlp = d->nlp;
312  const casadi_madnlp_prob<T1>* p = d->prob;
313  const casadi_nlpsol_prob<T1>* p_nlp = p->nlp;
314  int ret = madnlp_solve(d->solver, d->libmad_opts, &(d->stats));
315  madnlp_delete_solver(d->solver);
316  if (ret!=0) return -1; // cleanup done in free_mem
317 
318  // get objective
319  ret = madnlp_get_obj(d->stats, &(d_nlp->objective)); if (ret != 0) return -2;
320  // get primal solution for x
321  ret = madnlp_get_solution(d->stats, d_nlp->z); if (ret != 0) return -2;
322  // get the bound multipliers
323  ret = madnlp_get_bound_multipliers(d->stats, d_nlp->lam); if (ret != 0) return -2;
324  // get the nonlinear constraint function values
325  ret = madnlp_get_constraints(d->stats, d_nlp->z + p_nlp->nx); if (ret != 0) return -2;
326  // get the nonlinear constraint multipliers
327  ret = madnlp_get_multipliers(d->stats, d_nlp->lam + p_nlp->nx); if (ret != 0) return -2;
328 
329  bool success_b;
330  ret = madnlp_get_success(d->stats, &(success_b)); if (ret != 0) return -2;
331 
332  libmad_int status;
333  ret = madnlp_get_status(d->stats, &status); if (ret != 0) return -2;
334  if(success_b){
335  d->success = 1;
337  }
338 
339  if (status == 5) d->unified_return_status = SOLVER_RET_INFEASIBLE;
340  if (status == -2 || (status <= -7 && status >=1 -11)) d->unified_return_status = SOLVER_RET_NAN;
341 
342  return 0;
343 }
@ SOLVER_RET_NAN
@ SOLVER_RET_INFEASIBLE
@ SOLVER_RET_SUCCESS
@ SOLVER_RET_UNKNOWN
MadNLPSolver * solver
CNLPModel * cnlp_model
casadi_nlpsol_data< T1 > * nlp
MadNLPExecutionStats * stats
const casadi_madnlp_prob< T1 > * prob
OracleCallback nlp_f
const casadi_int * sp_a
OracleCallback nlp_g
OracleCallback nlp_jac_g
OracleCallback nlp_hess_l
const casadi_nlpsol_prob< T1 > * nlp
const casadi_int * sp_h
OracleCallback nlp_grad_f