casadi_ipqp.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 
21 // C-REPLACE "fmin" "casadi_fmin"
22 // C-REPLACE "fmax" "casadi_fmax"
23 // C-REPLACE "std::numeric_limits<T1>::min()" "casadi_real_min"
24 // C-REPLACE "std::numeric_limits<T1>::infinity()" "casadi_inf"
25 // C-REPLACE "static_cast<int>" "(int) "
26 // SYMBOL "ipqp_prob"
27 template<typename T1>
29  // Dimensions
30  casadi_int nx, na, nz;
31  // Smallest nonzero number
32  T1 dmin;
33  // Infinity
34  T1 inf;
35  // Maximum number of iterations
36  casadi_int max_iter;
37  // Error tolerance
39 };
40 // C-REPLACE "casadi_ipqp_prob<T1>" "struct casadi_ipqp_prob"
41 
42 // SYMBOL "ipqp_setup"
43 template<typename T1>
44 void casadi_ipqp_setup(casadi_ipqp_prob<T1>* p, casadi_int nx, casadi_int na) {
45  p->nx = nx;
46  p->na = na;
47  p->nz = nx + na;
48  p->dmin = std::numeric_limits<T1>::min();
49  p->inf = std::numeric_limits<T1>::infinity();
50  p->max_iter = 100;
51  p->pr_tol = 1e-8;
52  p->du_tol = 1e-8;
53  p->co_tol = 1e-8;
54  p->mu_tol = 1e-8;
55 }
56 
57 // SYMBOL "ipqp_flag_t"
58 typedef enum {
59  IPQP_SUCCESS,
60  IPQP_MAX_ITER,
61  IPQP_NO_SEARCH_DIR,
62  IPQP_MV_ERROR,
63  IPQP_FACTOR_ERROR,
64  IPQP_SOLVE_ERROR,
65  IPQP_PROGRESS_ERROR
66 } casadi_ipqp_flag_t;
67 
68 // SYMBOL "ipqp_task_t"
69 typedef enum {
70  IPQP_MV,
71  IPQP_PROGRESS,
72  IPQP_FACTOR,
73  IPQP_SOLVE} casadi_ipqp_task_t;
74 
75 // SYMBOL "ipqp_task_t"
76 typedef enum {
77  IPQP_RESET,
78  IPQP_RESIDUAL,
79  IPQP_NEWITER,
80  IPQP_PREPARE,
81  IPQP_PREDICTOR,
82  IPQP_CORRECTOR} casadi_ipqp_next_t;
83 
84 // SYMBOL "ipqp_blocker_t"
85 typedef enum {
86  IPQP_NONE = 0x0,
87  IPQP_UPPER = 0x1,
88  IPQP_LOWER = 0x2,
89  IPQP_PRIMAL = 0x4,
90  IPQP_DUAL = 0x8
91 } casadi_blocker_t;
92 
93 // SYMBOL "ipqp_data"
94 template<typename T1>
96  // Problem structure
98  // QP data
99  const T1 *g;
100  // Number of finite constraints
101  casadi_int n_con;
102  // Solver status
103  casadi_ipqp_flag_t status;
104  // User task
105  casadi_ipqp_task_t task;
106  // Next step
107  casadi_ipqp_next_t next;
108  // Linear system
109  T1* linsys;
110  // Message buffer
111  const char *msg;
112  // Complementarity measure
113  T1 mu;
114  // Stepsize
115  T1 tau;
116  // Primal and dual error, complementarity error, corresponding index
117  T1 pr, du, co;
118  casadi_int ipr, idu, ico;
119  // Iteration
120  casadi_int iter;
121  // Bounds
122  T1 *lbz, *ubz;
123  // Current solution
124  T1 *z, *lam, *lam_lbz, *lam_ubz;
125  // Step
127  // Residual
129  // Diagonal entries
130  T1* D;
131  // Scaling factor
132  T1* S;
133  // Inverse of margin to bounds (0 if no bound)
135 };
136 // C-REPLACE "casadi_ipqp_data<T1>" "struct casadi_ipqp_data"
137 
138 // SYMBOL "ipqp_sz_w"
139 template<typename T1>
140 casadi_int casadi_ipqp_sz_w(const casadi_ipqp_prob<T1>* p) {
141  // Return value
142  casadi_int sz_w = 0;
143  // Persistent work vectors
144  sz_w += p->nz; // lbz
145  sz_w += p->nz; // ubz
146  sz_w += p->nz; // z
147  sz_w += p->nz; // lam
148  sz_w += p->nz; // lam_lbz
149  sz_w += p->nz; // lam_ubz
150  sz_w += p->nz; // dz
151  sz_w += p->nz; // dlam
152  sz_w += p->nz; // dlam_lbz
153  sz_w += p->nz; // dlam_ubz
154  sz_w += p->nz; // rz
155  sz_w += p->nz; // rlam
156  sz_w += p->nz; // rlam_lbz
157  sz_w += p->nz; // rlam_ubz
158  sz_w += p->nz; // D
159  sz_w += p->nz; // S
160  sz_w += p->nz; // dinv_lbz
161  sz_w += p->nz; // dinv_ubz
162  return sz_w;
163 }
164 
165 // SYMBOL "ipqp_init"
166 template<typename T1>
167 void casadi_ipqp_init(casadi_ipqp_data<T1>* d, casadi_int** iw, T1** w) {
168  const casadi_ipqp_prob<T1>* p = d->prob;
169  // Assign memory
170  d->lbz = *w; *w += p->nz;
171  d->ubz = *w; *w += p->nz;
172  d->z = *w; *w += p->nz;
173  d->lam = *w; *w += p->nz;
174  d->lam_lbz = *w; *w += p->nz;
175  d->lam_ubz = *w; *w += p->nz;
176  d->dz = *w; *w += p->nz;
177  d->dlam = *w; *w += p->nz;
178  d->dlam_lbz = *w; *w += p->nz;
179  d->dlam_ubz = *w; *w += p->nz;
180  d->rz = *w; *w += p->nz;
181  d->rlam = *w; *w += p->nz;
182  d->rlam_lbz = *w; *w += p->nz;
183  d->rlam_ubz = *w; *w += p->nz;
184  d->D = *w; *w += p->nz;
185  d->S = *w; *w += p->nz;
186  d->dinv_lbz = *w; *w += p->nz;
187  d->dinv_ubz = *w; *w += p->nz;
188  // New QP
189  d->next = IPQP_RESET;
190 }
191 
192 // SYMBOL "ipqp_bounds"
193 template<typename T1>
194 void casadi_ipqp_bounds(casadi_ipqp_data<T1>* d, const T1* g,
195  const T1* lbx, const T1* ubx, const T1* lba, const T1* uba) {
196  // Local variables
197  const casadi_ipqp_prob<T1>* p = d->prob;
198  // Pass pointer to linear term in objective
199  d->g = g;
200  // Pass bounds on z
201  casadi_copy(lbx, p->nx, d->lbz);
202  casadi_copy(lba, p->na, d->lbz + p->nx);
203  casadi_copy(ubx, p->nx, d->ubz);
204  casadi_copy(uba, p->na, d->ubz + p->nx);
205 }
206 
207 // SYMBOL "ipqp_guess"
208 template<typename T1>
209 void casadi_ipqp_guess(casadi_ipqp_data<T1>* d,
210  const T1* x0, const T1* lam_x0, const T1* lam_a0) {
211  // Local variables
212  const casadi_ipqp_prob<T1>* p = d->prob;
213  // Pass initial guess
214  casadi_copy(x0, p->nx, d->z);
215  casadi_fill(d->z + p->nx, p->na, 0.);
216  casadi_copy(lam_x0, p->nx, d->lam);
217  casadi_copy(lam_a0, p->na, d->lam + p->nx);
218  casadi_fill(d->lam_lbz, p->nz, 0.);
219  casadi_fill(d->lam_ubz, p->nz, 0.);
220 }
221 
222 // SYMBOL "ipqp_reset"
223 template<typename T1>
224 void casadi_ipqp_reset(casadi_ipqp_data<T1>* d) {
225  // Local variables
226  casadi_int k;
227  T1 margin, mid;
228  const casadi_ipqp_prob<T1>* p = d->prob;
229  // Required margin to constraints
230  margin = .1;
231  // Reset constraint count
232  d->n_con = 0;
233  // Initialize constraints to zero
234  for (k = p->nx; k < p->nz; ++k) d->z[k] = 0;
235  // Find interior point
236  for (k = 0; k < p->nz; ++k) {
237  if (d->lbz[k] > -p->inf) {
238  if (d->ubz[k] < p->inf) {
239  // Both upper and lower bounds
240  mid = .5 * (d->lbz[k] + d->ubz[k]);
241  // Ensure margin to boundary, without crossing midpoint
242  if (d->z[k] < mid) {
243  d->z[k] = fmin(fmax(d->z[k], d->lbz[k] + margin), mid);
244  } else if (d->z[k] > mid) {
245  d->z[k] = fmax(fmin(d->z[k], d->ubz[k] - margin), mid);
246  }
247  if (d->ubz[k] > d->lbz[k] + p->dmin) {
248  d->lam_lbz[k] = 1;
249  d->lam_ubz[k] = 1;
250  d->n_con += 2;
251  }
252  } else {
253  // Only lower bound
254  d->z[k] = fmax(d->z[k], d->lbz[k] + margin);
255  d->lam_lbz[k] = 1;
256  d->n_con++;
257  }
258  } else {
259  if (d->ubz[k] < p->inf) {
260  // Only upper bound
261  d->z[k] = fmin(d->z[k], d->ubz[k] - margin);
262  d->lam_ubz[k] = 1;
263  d->n_con++;
264  }
265  }
266  }
267  // Clear residual
268  casadi_clear(d->rz, p->nz);
269  // Reset iteration counter
270  d->iter = 0;
271  // Reset iteration variables
272  d->msg = 0;
273  d->tau = -1;
274 }
275 
276 // SYMBOL "ipqp_diag"
277 template<typename T1>
278 void casadi_ipqp_diag(casadi_ipqp_data<T1>* d) {
279  // Local variables
280  casadi_int k;
281  const casadi_ipqp_prob<T1>* p = d->prob;
282  // Diagonal entries corresponding to variables
283  for (k = 0; k < p->nx; ++k) {
284  if (d->ubz[k] <= d->lbz[k] + p->dmin) {
285  // Fixed variable (eliminate)
286  d->D[k] = -1;
287  } else {
288  d->D[k] = d->lam_lbz[k] * d->dinv_lbz[k]
289  + d->lam_ubz[k] * d->dinv_ubz[k];
290  }
291  }
292  // Diagonal entries corresponding to constraints
293  for (; k < p->nz; ++k) {
294  if (d->lbz[k] <= -p->inf && d->ubz[k] >= p->inf) {
295  // Unconstrained (eliminate)
296  d->D[k] = -1;
297  } else if (d->ubz[k] <= d->lbz[k] + p->dmin) {
298  // Equality constrained
299  d->D[k] = 0;
300  } else {
301  d->D[k] = 1. / (d->lam_lbz[k] * d->dinv_lbz[k]
302  + d->lam_ubz[k] * d->dinv_ubz[k]);
303  }
304  }
305  // Scale diagonal entries
306  for (k = 0; k < p->nz; ++k) {
307  if (d->D[k] < 0) {
308  // Eliminate
309  d->S[k] = 0;
310  d->D[k] = 1;
311  } else {
312  // Scale
313  d->S[k] = fmin(1., std::sqrt(1. / d->D[k]));
314  d->D[k] = fmin(1., d->D[k]);
315  }
316  }
317 }
318 
319 // SYMBOL "ipqp_newiter"
320 template<typename T1>
321 int casadi_ipqp_newiter(casadi_ipqp_data<T1>* d) {
322  // Local variables
323  const casadi_ipqp_prob<T1>* p = d->prob;
324  // Converged?
325  if (d->pr < p->pr_tol && d->du < p->du_tol && d->co < p->co_tol
326  && d->mu < p->mu_tol) {
327  d->status = IPQP_SUCCESS;
328  return 1;
329  }
330  // Max number of iterations reached
331  if (d->iter >= p->max_iter) {
332  d->status = IPQP_MAX_ITER;
333  return 1;
334  }
335  // Start new iteration
336  d->iter++;
337  // Calculate diagonal entries and scaling factors
338  casadi_ipqp_diag(d);
339  // Success
340  return 0;
341 }
342 
343 // SYMBOL "ipqp_residual"
344 template<typename T1>
345 void casadi_ipqp_residual(casadi_ipqp_data<T1>* d) {
346  // Local variables
347  casadi_int k;
348  T1 bdiff, viol;
349  const casadi_ipqp_prob<T1>* p = d->prob;
350  // Gradient of the Lagrangian
351  casadi_axpy(p->nx, 1., d->g, d->rz);
352  for (k = 0; k < p->nx; ++k) {
353  if (d->ubz[k] <= d->lbz[k] + p->dmin) {
354  // Fixed variable: Solve to get multiplier explicitly
355  d->lam[k] = -d->rz[k];
356  d->rz[k] = 0;
357  } else {
358  // Residual
359  d->rz[k] += d->lam[k];
360  }
361  }
362  // Constraint violation (only possible for linear constraints)
363  d->ipr = -1;
364  d->pr = 0;
365  for (k = p->nx; k < p->nz; ++k) {
366  if (d->lbz[k] <= -p->inf && d->ubz[k] >= p->inf) {
367  // Unconstrained: Solve to get g explicitly
368  d->z[k] = d->rz[k];
369  d->lam[k] = 0;
370  } else {
371  // Check constraint violation
372  if (d->rz[k] + d->pr < d->lbz[k]) {
373  d->pr = d->lbz[k] - d->rz[k];
374  d->ipr = k;
375  } else if (d->rz[k] - d->pr > d->ubz[k]) {
376  d->pr = d->rz[k] - d->ubz[k];
377  d->ipr = k;
378  }
379  }
380  }
381  // Dual infeasibility
382  d->idu = -1;
383  d->du = 0;
384  for (k = 0; k < p->nx; ++k) {
385  if (fabs(d->rz[k]) > d->du) {
386  d->du = fabs(d->rz[k]);
387  d->idu = k;
388  }
389  }
390  // Linear constraint
391  casadi_axpy(p->na, -1., d->z + p->nx, d->rz + p->nx);
392  // Multiplier consistency
393  for (k = 0; k < p->nz; ++k) {
394  if (d->ubz[k] <= d->lbz[k] + p->dmin) {
395  // Fixed variable: Solve to get lam_lbz, lam_ubz
396  d->lam_ubz[k] = fmax(d->lam[k], 0.);
397  d->lam_lbz[k] = fmax(-d->lam[k], 0.);
398  d->rlam[k] = 0;
399  } else {
400  // Residual
401  d->rlam[k] = d->lam_ubz[k] - d->lam_lbz[k] - d->lam[k];
402  }
403  }
404  // Complementarity conditions, mu
405  d->mu = 0;
406  d->ico = -1;
407  d->co = 0;
408  for (k = 0; k < p->nz; ++k) {
409  // Lower bound
410  if (d->lbz[k] > -p->inf && d->ubz[k] > d->lbz[k] + p->dmin) {
411  // Inequality constraint
412  bdiff = d->z[k] - d->lbz[k];
413  d->mu += d->rlam_lbz[k] = d->lam_lbz[k] * bdiff;
414  d->dinv_lbz[k] = 1. / bdiff;
415  // Constraint violation
416  viol = bdiff * fmax(-d->lam[k], 0.);
417  if (viol > d->co) {
418  d->co = viol;
419  d->ico = k;
420  }
421  } else {
422  // No bound or equality constraint
423  d->rlam_lbz[k] = 0;
424  d->dinv_lbz[k] = 0;
425  }
426  // Upper bound
427  if (d->ubz[k] < p->inf && d->ubz[k] > d->lbz[k] + p->dmin) {
428  // Inequality constraint
429  bdiff = d->ubz[k] - d->z[k];
430  d->mu += d->rlam_ubz[k] = d->lam_ubz[k] * bdiff;
431  d->dinv_ubz[k] = 1. / bdiff;
432  // Constraint violation
433  viol = bdiff * fmax(d->lam[k], 0.);
434  if (viol > d->co) {
435  d->co = viol;
436  d->ico = k;
437  }
438  } else {
439  // No bound or equality constraint
440  d->rlam_ubz[k] = 0;
441  d->dinv_ubz[k] = 0;
442  }
443  }
444  // Divide mu by total number of finite constraints
445  if (d->n_con > 0) d->mu /= d->n_con;
446 }
447 
448 // SYMBOL "ipqp_predictor_prepare"
449 template<typename T1>
450 void casadi_ipqp_predictor_prepare(casadi_ipqp_data<T1>* d) {
451  // Local variables
452  casadi_int k;
453  const casadi_ipqp_prob<T1>* p = d->prob;
454  // Store r_lam - dinv_lbz * rlam_lbz + dinv_ubz * rlam_ubz in dz
455  casadi_copy(d->rlam, p->nz, d->dz);
456  for (k=0; k<p->nz; ++k) d->dz[k] += d->dinv_lbz[k] * d->rlam_lbz[k];
457  for (k=0; k<p->nz; ++k) d->dz[k] -= d->dinv_ubz[k] * d->rlam_ubz[k];
458  // Finish calculating x-component of right-hand-side and store in dz[:nx]
459  for (k=0; k<p->nx; ++k) d->dz[k] += d->rz[k];
460  // Copy tilde{r}_lam to dlam[nx:] (needed to calculate step in g later)
461  for (k=p->nx; k<p->nz; ++k) d->dlam[k] = d->dz[k];
462  // Finish calculating g-component of right-hand-side and store in dz[nx:]
463  for (k=p->nx; k<p->nz; ++k) {
464  if (d->S[k] == 0.) {
465  // Eliminate
466  d->dz[k] = 0;
467  } else {
468  d->dz[k] *= d->D[k] / (d->S[k] * d->S[k]);
469  d->dz[k] += d->rz[k];
470  }
471  }
472  // Scale and negate right-hand-side
473  for (k=0; k<p->nz; ++k) d->dz[k] *= -d->S[k];
474  // dlam_lbz := -rlam_lbz, dlam_ubz := -rlam_ubz
475  for (k=0; k<p->nz; ++k) d->dlam_lbz[k] = -d->rlam_lbz[k];
476  for (k=0; k<p->nz; ++k) d->dlam_ubz[k] = -d->rlam_ubz[k];
477  // dlam_x := rlam_x
478  for (k=0; k<p->nx; ++k) d->dlam[k] = d->rlam[k];
479  // Solve to get step
480  d->linsys = d->dz;
481 }
482 
483 // SYMBOL "ipqp_maxstep"
484 template<typename T1>
485 int casadi_ipqp_maxstep(casadi_ipqp_data<T1>* d, T1* alpha, casadi_int* ind) {
486  // Local variables
487  T1 test;
488  casadi_int k, blocking_k;
489  int flag;
490  const casadi_ipqp_prob<T1>* p = d->prob;
491  // Reset variables
492  blocking_k = -1;
493  flag = IPQP_NONE;
494  // Maximum step size is 1
495  *alpha = 1.;
496  // Primal step
497  for (k=0; k<p->nz; ++k) {
498  if (d->dz[k] < 0 && d->lbz[k] > -p->inf) {
499  if ((test = (d->lbz[k] - d->z[k]) / d->dz[k]) < *alpha) {
500  *alpha = test;
501  blocking_k = k;
502  flag = IPQP_PRIMAL | IPQP_LOWER;
503  }
504  }
505  if (d->dz[k] > 0 && d->ubz[k] < p->inf) {
506  if ((test = (d->ubz[k] - d->z[k]) / d->dz[k]) < *alpha) {
507  *alpha = test;
508  blocking_k = k;
509  flag = IPQP_PRIMAL | IPQP_UPPER;
510  }
511  }
512  }
513  // Dual step
514  for (k=0; k<p->nz; ++k) {
515  if (d->dlam_lbz[k] < 0.) {
516  if ((test = -d->lam_lbz[k] / d->dlam_lbz[k]) < *alpha) {
517  *alpha = test;
518  blocking_k = k;
519  flag = IPQP_DUAL | IPQP_LOWER;
520  }
521  }
522  if (d->dlam_ubz[k] < 0.) {
523  if ((test = -d->lam_ubz[k] / d->dlam_ubz[k]) < *alpha) {
524  *alpha = test;
525  blocking_k = k;
526  flag = IPQP_DUAL | IPQP_UPPER;
527  }
528  }
529  }
530  // Return information about blocking constraints
531  if (ind) *ind = blocking_k;
532  return flag;
533 }
534 
535 // SYMBOL "ipqp_predictor"
536 template<typename T1>
537 void casadi_ipqp_predictor(casadi_ipqp_data<T1>* d) {
538  // Local variables
539  casadi_int k;
540  T1 t, alpha, sigma;
541  const casadi_ipqp_prob<T1>* p = d->prob;
542  // Scale results
543  for (k=0; k<p->nz; ++k) d->dz[k] *= d->S[k];
544  // Calculate step in z(g), lam(g)
545  for (k=p->nx; k<p->nz; ++k) {
546  if (d->S[k] == 0.) {
547  // Eliminate
548  d->dlam[k] = d->dz[k] = 0;
549  } else {
550  t = d->D[k] / (d->S[k] * d->S[k]) * (d->dz[k] - d->dlam[k]);
551  d->dlam[k] = d->dz[k];
552  d->dz[k] = t;
553  }
554  }
555  // Finish calculation in dlam_lbz, dlam_ubz
556  for (k=0; k<p->nz; ++k) {
557  d->dlam_lbz[k] -= d->lam_lbz[k] * d->dz[k];
558  d->dlam_lbz[k] *= d->dinv_lbz[k];
559  }
560  for (k=0; k<p->nz; ++k) {
561  d->dlam_ubz[k] += d->lam_ubz[k] * d->dz[k];
562  d->dlam_ubz[k] *= d->dinv_ubz[k];
563  }
564  // Finish calculation of dlam(x)
565  for (k=0; k<p->nx; ++k) d->dlam[k] += d->dlam_ubz[k] - d->dlam_lbz[k];
566  // Maximum primal and dual step
567  (void)casadi_ipqp_maxstep(d, &alpha, 0);
568  // Calculate sigma
569  sigma = casadi_ipqp_sigma(d, alpha);
570  // Prepare corrector step
571  casadi_ipqp_corrector_prepare(d, -sigma * d->mu);
572  // Solve to get step
573  d->linsys = d->rz;
574 }
575 
576 // SYMBOL "ipqp_step"
577 template<typename T1>
578 void casadi_ipqp_step(casadi_ipqp_data<T1>* d, T1 alpha_pr, T1 alpha_du) {
579  // Local variables
580  casadi_int k;
581  const casadi_ipqp_prob<T1>* p = d->prob;
582  // Primal step
583  for (k=0; k<p->nz; ++k) d->z[k] += alpha_pr * d->dz[k];
584  // Dual step
585  for (k=0; k<p->nz; ++k) d->lam[k] += alpha_du * d->dlam[k];
586  for (k=0; k<p->nz; ++k) d->lam_lbz[k] += alpha_du * d->dlam_lbz[k];
587  for (k=0; k<p->nz; ++k) d->lam_ubz[k] += alpha_du * d->dlam_ubz[k];
588 }
589 
590 // SYMBOL "ipqp_mu"
591 template<typename T1>
592 T1 casadi_ipqp_mu(casadi_ipqp_data<T1>* d, T1 alpha) {
593  // Local variables
594  T1 mu;
595  casadi_int k;
596  const casadi_ipqp_prob<T1>* p = d->prob;
597  // Quick return if no inequalities
598  if (d->n_con == 0) return 0;
599  // Calculate projected mu (and save to sigma variable)
600  mu = 0;
601  for (k = 0; k < p->nz; ++k) {
602  // Lower bound
603  if (d->lbz[k] > -p->inf && d->ubz[k] > d->lbz[k] + p->dmin) {
604  mu += (d->lam_lbz[k] + alpha * d->dlam_lbz[k])
605  * (d->z[k] - d->lbz[k] + alpha * d->dz[k]);
606  }
607  // Upper bound
608  if (d->ubz[k] < p->inf && d->ubz[k] > d->lbz[k] + p->dmin) {
609  mu += (d->lam_ubz[k] + alpha * d->dlam_ubz[k])
610  * (d->ubz[k] - d->z[k] - alpha * d->dz[k]);
611  }
612  }
613  // Divide mu by total number of finite constraints
614  mu /= d->n_con;
615  return mu;
616 }
617 
618 // SYMBOL "ipqp_sigma"
619 template<typename T1>
620 T1 casadi_ipqp_sigma(casadi_ipqp_data<T1>* d, T1 alpha) {
621  // Local variables
622  T1 sigma;
623  // Quick return if no inequalities
624  if (d->n_con == 0) return 0;
625  // Calculate projected mu (and save to sigma variable)
626  sigma = casadi_ipqp_mu(d, alpha);
627  // Finish calculation of sigma := (mu_aff / mu)^3
628  sigma /= d->mu;
629  sigma *= sigma * sigma;
630  return sigma;
631 }
632 
633 // SYMBOL "ipqp_corrector_prepare"
634 template<typename T1>
635 void casadi_ipqp_corrector_prepare(casadi_ipqp_data<T1>* d, T1 shift) {
636  // Local variables
637  casadi_int k;
638  const casadi_ipqp_prob<T1>* p = d->prob;
639  // Modified residual in lam_lbz, lam_ubz
640  for (k=0; k<p->nz; ++k) d->rlam_lbz[k] = d->dlam_lbz[k] * d->dz[k] + shift;
641  for (k=0; k<p->nz; ++k) d->rlam_ubz[k] = -d->dlam_ubz[k] * d->dz[k] + shift;
642  // Difference in tilde(r)_x, tilde(r)_lamg
643  for (k=0; k<p->nz; ++k)
644  d->rz[k] = d->dinv_lbz[k] * d->rlam_lbz[k]
645  - d->dinv_ubz[k] * d->rlam_ubz[k];
646  // Difference in tilde(r)_g
647  for (k=p->nx; k<p->nz; ++k) {
648  if (d->S[k] == 0.) {
649  // Eliminate
650  d->rlam[k] = d->rz[k] = 0;
651  } else {
652  d->rlam[k] = d->rz[k];
653  d->rz[k] *= d->D[k] / (d->S[k] * d->S[k]);
654  }
655  }
656  // Scale and negate right-hand-side
657  for (k=0; k<p->nz; ++k) d->rz[k] *= -d->S[k];
658 }
659 
660 // SYMBOL "ipqp_corrector"
661 template<typename T1>
662 void casadi_ipqp_corrector(casadi_ipqp_data<T1>* d) {
663  // Local variables
664  T1 t, mu_test, primal_slack, primal_step, dual_slack, dual_step, max_tau;
665  casadi_int k;
666  int flag;
667  const casadi_ipqp_prob<T1>* p = d->prob;
668  // Scale results
669  for (k=0; k<p->nz; ++k) d->rz[k] *= d->S[k];
670  // Calculate step in z(g), lam(g)
671  for (k=p->nx; k<p->nz; ++k) {
672  if (d->S[k] == 0.) {
673  // Eliminate
674  d->rlam[k] = d->rz[k] = 0;
675  } else {
676  t = d->D[k] / (d->S[k] * d->S[k]) * (d->rz[k] - d->rlam[k]);
677  d->rlam[k] = d->rz[k];
678  d->rz[k] = t;
679  }
680  }
681  // Update step in dz, dlam
682  for (k=0; k<p->nz; ++k) d->dz[k] += d->rz[k];
683  for (k=p->nx; k<p->nz; ++k) d->dlam[k] += d->rlam[k];
684  // Update step in lam_lbz
685  for (k=0; k<p->nz; ++k) {
686  t = d->dinv_lbz[k] * (-d->rlam_lbz[k] - d->lam_lbz[k] * d->rz[k]);
687  d->dlam_lbz[k] += t;
688  if (k<p->nx) d->dlam[k] -= t;
689  }
690  // Update step in lam_ubz
691  for (k=0; k<p->nz; ++k) {
692  t = d->dinv_ubz[k] * (-d->rlam_ubz[k] + d->lam_ubz[k] * d->rz[k]);
693  d->dlam_ubz[k] += t;
694  if (k<p->nx) d->dlam[k] += t;
695  }
696  // Find the largest step size, keeping track of blocking constraints
697  flag = casadi_ipqp_maxstep(d, &max_tau, &k);
698  // Handle blocking constraints using Mehrotra's heuristic
699  if (flag == IPQP_NONE) {
700  // No blocking constraints
701  d->tau = 1;
702  } else {
703  // Calculate mu for maximum step
704  mu_test = casadi_ipqp_mu(d, max_tau);
705  // Get distance to constraints for blocking variable
706  if (flag & IPQP_UPPER) {
707  primal_slack = d->ubz[k] - d->z[k];
708  primal_step = -d->dz[k];
709  dual_slack = d->lam_ubz[k];
710  dual_step = d->dlam_ubz[k];
711  } else {
712  primal_slack = d->z[k] - d->lbz[k];
713  primal_step = d->dz[k];
714  dual_slack = d->lam_lbz[k];
715  dual_step = d->dlam_lbz[k];
716  }
717  // Mehrotra's heuristic as in in OOQP per communication with S. Wright
718  if (flag & IPQP_PRIMAL) {
719  d->tau = (0.01 * mu_test / (dual_slack + max_tau * dual_step)
720  - primal_slack) / primal_step;
721  } else {
722  d->tau = (0.01 * mu_test / (primal_slack + max_tau * primal_step)
723  - dual_slack) / dual_step;
724  }
725  d->tau = fmax(d->tau, 0.99 * max_tau);
726  }
727  // Take step
728  casadi_ipqp_step(d, d->tau, d->tau);
729  // Clear residual
730  casadi_clear(d->rz, p->nz);
731 }
732 
733 // SYMBOL "ipqp"
734 template<typename T1>
735 int casadi_ipqp(casadi_ipqp_data<T1>* d) {
736  switch (d->next) {
737  case IPQP_RESET:
738  casadi_ipqp_reset(d);
739  d->task = IPQP_MV;
740  d->next = IPQP_RESIDUAL;
741  return 1;
742  case IPQP_RESIDUAL:
743  // Calculate residual
744  if (d->status == IPQP_MV_ERROR) break;
745  casadi_ipqp_residual(d);
746  d->task = IPQP_PROGRESS;
747  d->next = IPQP_NEWITER;
748  return 1;
749  case IPQP_NEWITER:
750  // New iteration
751  if (d->status == IPQP_PROGRESS_ERROR) break;
752  if (casadi_ipqp_newiter(d)) break;
753  d->task = IPQP_FACTOR;
754  d->next = IPQP_PREPARE;
755  return 1;
756  case IPQP_PREPARE:
757  // Prepare predictor step
758  if (d->status == IPQP_FACTOR_ERROR) break;
759  casadi_ipqp_predictor_prepare(d);
760  d->task = IPQP_SOLVE;
761  d->next = IPQP_PREDICTOR;
762  return 1;
763  case IPQP_PREDICTOR:
764  // Complete predictor step
765  if (d->status == IPQP_SOLVE_ERROR) break;
766  casadi_ipqp_predictor(d);
767  d->task = IPQP_SOLVE;
768  d->next = IPQP_CORRECTOR;
769  return 1;
770  case IPQP_CORRECTOR:
771  // Complete predictor step
772  if (d->status == IPQP_SOLVE_ERROR) break;
773  casadi_ipqp_corrector(d);
774  d->task = IPQP_MV;
775  d->next = IPQP_RESIDUAL;
776  return 1;
777  default:
778  break;
779  }
780  // Done iterating
781  d->next = IPQP_RESET;
782  return 0;
783 }
784 
785 // SYMBOL "ipqp_return_status"
786 inline
787 const char* casadi_ipqp_return_status(casadi_ipqp_flag_t status) {
788  switch (status) {
789  case IPQP_SUCCESS: return "success";
790  case IPQP_MAX_ITER: return "Maximum number of iterations reached";
791  case IPQP_NO_SEARCH_DIR: return "Failed to calculate search direction";
792  case IPQP_MV_ERROR: return "Matrix-vector evaluation error";
793  case IPQP_FACTOR_ERROR: return "Linear solver factorization error";
794  case IPQP_SOLVE_ERROR: return "Linear solver solution error";
795  case IPQP_PROGRESS_ERROR: return "Printing error";
796  }
797  return 0;
798 }
799 
800 // SYMBOL "ipqp_solution"
801 template<typename T1>
802 void casadi_ipqp_solution(casadi_ipqp_data<T1>* d, T1* x, T1* lam_x, T1* lam_a) {
803  // Local variables
804  const casadi_ipqp_prob<T1>* p = d->prob;
805  // Copy solution
806  casadi_copy(d->z, p->nx, x);
807  casadi_copy(d->lam, p->nx, lam_x);
808  casadi_copy(d->lam + p->nx, p->na, lam_a);
809 }
810 
811 // SYMBOL "ipqp_print_header"
812 template<typename T1>
813 int casadi_ipqp_print_header(casadi_ipqp_data<T1>* d, char* buf, size_t buf_sz) {
814 #ifdef CASADI_SNPRINTF
815  int flag;
816  // Print to string
817  flag = CASADI_SNPRINTF(buf, buf_sz, "%5s %9s %9s %5s %9s %5s "
818  "%9s %5s %9s %4s",
819  "Iter", "mu", "|pr|", "con", "|du|", "var", "|co|", "con",
820  "last_tau", "Note");
821  // Check if error
822  if (flag < 0) {
823  d->status = IPQP_PROGRESS_ERROR;
824  return 1;
825  }
826 #else
827  if (buf_sz) buf[0] = '\0';
828 #endif
829  // Successful return
830  return 0;
831 }
832 
833 // SYMBOL "ipqp_print_iteration"
834 template<typename T1>
835 int casadi_ipqp_print_iteration(casadi_ipqp_data<T1>* d, char* buf, int buf_sz) {
836 #ifdef CASADI_SNPRINTF
837  int flag;
838  // Print iteration data without note to string
839  flag = CASADI_SNPRINTF(buf, buf_sz,
840  "%5d %9.2g %9.2g %5d %9.2g %5d %9.2g %5d %9.2g ",
841  static_cast<int>(d->iter), d->mu,
842  d->pr, static_cast<int>(d->ipr),
843  d->du, static_cast<int>(d->idu),
844  d->co, static_cast<int>(d->ico),
845  d->tau);
846  // Check if error
847  if (flag < 0) {
848  d->status = IPQP_PROGRESS_ERROR;
849  return 1;
850  }
851  // Rest of buffer reserved for iteration note
852  buf += flag;
853  buf_sz -= flag;
854  // Print iteration note, if any
855  if (d->msg) {
856  flag = CASADI_SNPRINTF(buf, buf_sz, "%s", d->msg);
857  // Check if error
858  if (flag < 0) {
859  d->status = IPQP_PROGRESS_ERROR;
860  return 1;
861  }
862  }
863 #else
864  if (buf_sz) buf[0] = '\0';
865 #endif
866  // Successful return
867  return 0;
868 }
casadi_int n_con
const casadi_ipqp_prob< T1 > * prob
Definition: casadi_ipqp.hpp:97
casadi_ipqp_flag_t status
casadi_ipqp_next_t next
const char * msg
casadi_ipqp_task_t task
casadi_int max_iter
Definition: casadi_ipqp.hpp:36