casadi_qrqp.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 
27 // C-REPLACE "casadi_qp_prob<T1>" "struct casadi_qp_prob"
28 // C-REPLACE "casadi_qp_data<T1>" "struct casadi_qp_data"
29 
30 // SYMBOL "qrqp_prob"
31 template<typename T1>
34  // Sparsity patterns
35  const casadi_int *sp_at, *sp_kkt;
36  // Symbolic QR factorization
37  const casadi_int *prinv, *pc, *sp_v, *sp_r;
38  // Smallest nonzero number
39  T1 dmin;
40  // Infinity
41  T1 inf;
42  // Smallest multiplier treated as inactive for the initial active set
43  T1 min_lam;
44  // Maximum number of iterations
45  casadi_int max_iter;
46  // Primal and dual error tolerance
48 };
49 // C-REPLACE "casadi_qrqp_prob<T1>" "struct casadi_qrqp_prob"
50 
51 // SYMBOL "qrqp_setup"
52 template<typename T1>
53 void casadi_qrqp_setup(casadi_qrqp_prob<T1>* p) {
54  p->dmin = std::numeric_limits<T1>::min();
55  p->inf = std::numeric_limits<T1>::infinity();
56  p->min_lam = 0;
57  p->max_iter = 1000;
58  p->constr_viol_tol = 1e-8;
59  p->dual_inf_tol = 1e-8;
60 }
61 
62 // SYMBOL "qrqp_flag_t"
63 typedef enum {
64  QP_SUCCESS,
65  QP_MAX_ITER,
66  QP_NO_SEARCH_DIR,
67  QP_PRINTING_ERROR
68 } casadi_qrqp_flag_t;
69 
70 // SYMBOL "qrqp_data"
71 template<typename T1>
73  // Problem structure
75  // Problem structure
77  // Cost
78  T1 f;
79  // Solver status
80  casadi_qrqp_flag_t status;
81  // Vectors
82  T1 *lbz, *ubz, *z, *infeas, *tinfeas, *sens, *lam, *w, *dz, *dlam;
83  casadi_int *iw, *neverzero, *neverlower, *neverupper, *lincomb;
84  // Numeric QR factorization
85  T1 *nz_at, *nz_kkt, *beta, *nz_v, *nz_r;
86  // Message buffer
87  const char *msg;
88  // Message index
89  casadi_int msg_ind;
90  // Stepsize
91  T1 tau;
92  // Singularity
93  casadi_int sing;
94  // Do we already have a search direction?
96  // Smallest diagonal value for the QR factorization
97  T1 mina;
98  casadi_int imina;
99  // Primal and dual error, corresponding index
100  T1 pr, du, epr, edu;
101  casadi_int ipr, idu;
102  // Pending active-set change
103  casadi_int index, sign;
104  // Feasibility restoration active-set change
105  casadi_int r_index, r_sign;
106  // Iteration
107  casadi_int iter;
108 };
109 // C-REPLACE "casadi_qrqp_data<T1>" "struct casadi_qrqp_data"
110 
111 
112 // SYMBOL "qrqp_work"
113 template<typename T1>
114 void casadi_qrqp_work(const casadi_qrqp_prob<T1>* p, casadi_int* sz_arg, casadi_int* sz_res,
115  casadi_int* sz_iw, casadi_int* sz_w) {
116  // Local variables
117  casadi_int nnz_a, nnz_kkt, nnz_v, nnz_r;
118  casadi_qp_work(p->qp, sz_arg, sz_res, sz_iw, sz_w);
119  // Get matrix number of nonzeros
120  nnz_a = p->qp->sp_a[2+p->qp->sp_a[1]];
121  nnz_kkt = p->sp_kkt[2+p->sp_kkt[1]];
122  nnz_v = p->sp_v[2+p->sp_v[1]];
123  nnz_r = p->sp_r[2+p->sp_r[1]];
124  // Temporary work vectors
125  *sz_w = casadi_max(*sz_w, p->qp->nz); // casadi_project, tau memory
126  *sz_iw = casadi_max(*sz_iw, p->qp->nz); // casadi_trans, tau type, allzero
127  *sz_w = casadi_max(*sz_w, 2*p->qp->nz); // casadi_qr
128  // Persistent work vectors
129  *sz_w += nnz_kkt; // kkt
130  *sz_w += p->qp->nz; // z=[xk,gk]
131  *sz_w += p->qp->nz; // lbz
132  *sz_w += p->qp->nz; // ubz
133  *sz_w += p->qp->nz; // lam
134  *sz_w += p->qp->nz; // dz
135  *sz_w += p->qp->nz; // dlam
136  *sz_w += casadi_max(nnz_v+nnz_r, nnz_kkt); // [v,r] or trans(kkt)
137  *sz_w += p->qp->nz; // beta
138  *sz_w += nnz_a; // trans(a)
139  *sz_w += p->qp->nx; // infeas
140  *sz_w += p->qp->nx; // tinfeas
141  *sz_w += p->qp->nz; // sens
142  *sz_iw += p->qp->nz; // neverzero
143  *sz_iw += p->qp->nz; // neverupper
144  *sz_iw += p->qp->nz; // neverlower
145  *sz_iw += p->qp->nz; // lincomb
146 }
147 
148 // SYMBOL "qrqp_init"
149 template<typename T1>
150 void casadi_qrqp_init(casadi_qrqp_data<T1>* d, casadi_int** iw, T1** w) {
151  // Local variables
152  casadi_int nnz_a, nnz_kkt, nnz_v, nnz_r;
153  const casadi_qrqp_prob<T1>* p = d->prob;
154  // Get matrix number of nonzeros
155  nnz_a = p->qp->sp_a[2+p->qp->sp_a[1]];
156  nnz_kkt = p->sp_kkt[2+p->sp_kkt[1]];
157  nnz_v = p->sp_v[2+p->sp_v[1]];
158  nnz_r = p->sp_r[2+p->sp_r[1]];
159  d->nz_kkt = *w; *w += nnz_kkt;
160  d->z = *w; *w += p->qp->nz;
161  d->lbz = *w; *w += p->qp->nz;
162  d->ubz = *w; *w += p->qp->nz;
163  d->lam = *w; *w += p->qp->nz;
164  d->dz = *w; *w += p->qp->nz;
165  d->dlam = *w; *w += p->qp->nz;
166  d->nz_v = *w; *w += casadi_max(nnz_v+nnz_r, nnz_kkt);
167  d->beta = *w; *w += p->qp->nz;
168  d->nz_at = *w; *w += nnz_a;
169  d->infeas = *w; *w += p->qp->nx;
170  d->tinfeas = *w; *w += p->qp->nx;
171  d->sens = *w; *w += p->qp->nz;
172  d->neverzero = *iw; *iw += p->qp->nz;
173  d->neverupper = *iw; *iw += p->qp->nz;
174  d->neverlower = *iw; *iw += p->qp->nz;
175  d->lincomb = *iw; *iw += p->qp->nz;
176  d->w = *w;
177  d->iw = *iw;
178 
179  d->nz_r = d->nz_v + nnz_v;
180 }
181 
182 // SYMBOL "qrqp_reset"
183 template<typename T1>
184 int casadi_qrqp_reset(casadi_qrqp_data<T1>* d) {
185  // Local variables
186  casadi_int i;
187  const casadi_qrqp_prob<T1>* p = d->prob;
188  // Reset variables corresponding to previous iteration
189  d->msg = 0;
190  d->tau = 0.;
191  d->sing = 0;
192  // Correct lam if needed, determine permitted signs
193  for (i=0; i<p->qp->nz; ++i) {
194  // Permitted signs for lam
195  d->neverzero[i] = d->lbz[i] == d->ubz[i];
196  d->neverupper[i] = d->ubz[i] == p->inf;
197  d->neverlower[i] = d->lbz[i] == -p->inf;
198  if (d->neverzero[i] && d->neverupper[i] && d->neverlower[i]) return 1;
199  // Small enough lambdas are treated as inactive
200  if (!d->neverzero[i] && fabs(d->lam[i]) < p->min_lam) d->lam[i] = 0.;
201  // Prevent illegal active sets
202  if (d->neverzero[i] && d->lam[i] == 0.) {
203  d->lam[i] = d->neverupper[i]
204  || d->z[i]-d->lbz[i] <= d->ubz[i]-d->z[i] ? -p->dmin : p->dmin;
205  } else if (d->neverupper[i] && d->lam[i]>0.) {
206  d->lam[i] = d->neverzero[i] ? -p->dmin : 0.;
207  } else if (d->neverlower[i] && d->lam[i]<0.) {
208  d->lam[i] = d->neverzero[i] ? p->dmin : 0.;
209  }
210  }
211  // Transpose A
212  casadi_trans(d->qp->a, p->qp->sp_a, d->nz_at, p->sp_at, d->iw);
213  // No pending active-set change
214  d->index = -2;
215  d->sign = 0;
216  // No restoration index
217  d->r_index = -2;
218  d->r_sign = 0;
219  // Reset iteration counter
220  d->iter = 0;
221  return 0;
222 }
223 
224 // SYMBOL "qrqp_pr"
225 template<typename T1>
226 void casadi_qrqp_pr(casadi_qrqp_data<T1>* d) {
227  // Calculate largest constraint violation
228  casadi_int i;
229  const casadi_qrqp_prob<T1>* p = d->prob;
230  d->pr = 0;
231  d->ipr = -1;
232  for (i=0; i<p->qp->nz; ++i) {
233  if (d->z[i] > d->ubz[i]+d->pr) {
234  d->pr = d->z[i]-d->ubz[i];
235  d->ipr = i;
236  } else if (d->z[i] < d->lbz[i]-d->pr) {
237  d->pr = d->lbz[i]-d->z[i];
238  d->ipr = i;
239  }
240  }
241 }
242 
243 // SYMBOL "qrqp_du"
244 template<typename T1>
245 void casadi_qrqp_du(casadi_qrqp_data<T1>* d) {
246  // Calculate largest constraint violation
247  casadi_int i;
248  const casadi_qrqp_prob<T1>* p = d->prob;
249  d->du = 0;
250  d->idu = -1;
251  for (i=0; i<p->qp->nx; ++i) {
252  if (d->infeas[i] > d->du) {
253  d->du = d->infeas[i];
254  d->idu = i;
255  } else if (d->infeas[i] < -d->du) {
256  d->du = -d->infeas[i];
257  d->idu = i;
258  }
259  }
260 }
261 
262 // SYMBOL "qrqp_du_check"
263 template<typename T1>
264 int casadi_qrqp_du_check(casadi_qrqp_data<T1>* d, casadi_int i) {
265  // Local variables
266  casadi_int k;
267  T1 new_du;
268  const casadi_int *at_colind, *at_row;
269  const casadi_qrqp_prob<T1>* p = d->prob;
270  // AT sparsity
271  at_colind = p->sp_at + 2;
272  at_row = at_colind + p->qp->na + 1;
273  // Maximum infeasibility from setting from setting lam[i]=0
274  if (i<p->qp->nx) {
275  new_du = fabs(d->infeas[i]-d->lam[i]);
276  } else {
277  new_du = 0.;
278  for (k=at_colind[i-p->qp->nx]; k<at_colind[i-p->qp->nx+1]; ++k) {
279  new_du = fmax(new_du, fabs(d->infeas[at_row[k]]-d->nz_at[k]*d->lam[i]));
280  }
281  }
282  return new_du <= d->du;
283 }
284 
285 // SYMBOL "qrqp_du_index"
286 template<typename T1>
287 void casadi_qrqp_du_index(casadi_qrqp_data<T1>* d) {
288  // Try to improve dual feasibility by removing a constraint
289  // Local variables
290  casadi_int i, s;
291  T1 best_sens;
292  const casadi_qrqp_prob<T1>* p = d->prob;
293  // Find the best lam[i] to make zero
294  d->index = -1;
295  best_sens = -1;
296  for (i = 0; i < p->qp->nz; ++i) {
297  // Skip if no dual infeasibility sensitivity
298  if (d->sens[i] == 0.) continue;
299  // Is the constraint enforced?
300  if (d->lam[i] == 0) {
301  // We're enforcing constraints
302  s = d->sens[i] > 0 ? 1 : -1;
303  // Make sure that enforcing the constraint is possible
304  if (s > 0 ? d->neverupper[i] : d->neverlower[i]) continue;
305  } else {
306  // We're removing constraints
307  s = 0;
308  // Make sure that it's a constraint that can be removed
309  if (d->neverzero[i]) continue;
310  // If variable influences du, make sure sign is right
311  if (d->lam[i] > 0. ? d->sens[i] > 0. : d->sens[i] < 0.) continue;
312  // Skip if maximum infeasibility increases
313  if (!casadi_qrqp_du_check(d, i)) continue;
314  }
315  // Check if best so far
316  if (fabs(d->sens[i]) > best_sens) {
317  best_sens = fabs(d->sens[i]);
318  d->index = i;
319  d->sign = s;
320  }
321  }
322  // Accept, if any
323  if (d->index >= 0) {
324  if (d->sign > 0) {
325  d->msg = "Enforced ubz to reduce |du|";
326  } else if (d->sign < 0) {
327  d->msg = "Enforced lbz to reduce |du|";
328  } else if (d->lam[d->index] > 0) {
329  d->msg = "Dropped ubz to reduce |du|";
330  } else {
331  d->msg = "Dropped lbz to reduce |du|";
332  }
333  d->msg_ind = d->index;
334  }
335 }
336 
337 // SYMBOL "qrqp_pr_index"
338 template<typename T1>
339 void casadi_qrqp_pr_index(casadi_qrqp_data<T1>* d) {
340  // Try to improve primal feasibility by adding a constraint
341  if (d->lam[d->ipr] == 0.) {
342  // Add the most violating constraint
343  if (d->z[d->ipr] < d->lbz[d->ipr]) {
344  d->sign = -1;
345  d->msg = "Added lbz to reduce |pr|";
346  } else {
347  d->sign = 1;
348  d->msg = "Added ubz to reduce |pr|";
349  }
350  d->msg_ind = d->ipr;
351  d->index = d->ipr;
352  } else {
353  // No improvement possible
354  d->index = -1;
355  }
356 }
357 
358 // SYMBOL "qrqp_kkt"
359 template<typename T1>
360 void casadi_qrqp_kkt(casadi_qrqp_data<T1>* d) {
361  // Local variables
362  casadi_int i, k;
363  const casadi_int *h_colind, *h_row, *a_colind, *a_row, *at_colind, *at_row,
364  *kkt_colind, *kkt_row;
365  const casadi_qrqp_prob<T1>* p = d->prob;
366  // Extract sparsities
367  a_row = (a_colind = p->qp->sp_a+2) + p->qp->nx + 1;
368  at_row = (at_colind = p->sp_at+2) + p->qp->na + 1;
369  h_row = (h_colind = p->qp->sp_h+2) + p->qp->nx + 1;
370  kkt_row = (kkt_colind = p->sp_kkt+2) + p->qp->nz + 1;
371  // Reset w to zero
372  casadi_clear(d->w, p->qp->nz);
373  // Loop over rows of the (transposed) KKT
374  for (i=0; i<p->qp->nz; ++i) {
375  // Copy row of KKT to w
376  if (i<p->qp->nx) {
377  if (d->lam[i]==0) {
378  for (k=h_colind[i]; k<h_colind[i+1]; ++k) d->w[h_row[k]] = d->qp->h[k];
379  for (k=a_colind[i]; k<a_colind[i+1]; ++k) d->w[p->qp->nx+a_row[k]] = d->qp->a[k];
380  } else {
381  d->w[i] = 1.;
382  }
383  } else {
384  if (d->lam[i]==0) {
385  d->w[i] = -1.;
386  } else {
387  for (k=at_colind[i-p->qp->nx]; k<at_colind[i-p->qp->nx+1]; ++k) {
388  d->w[at_row[k]] = d->nz_at[k];
389  }
390  }
391  }
392  // Copy row to KKT, zero out w
393  for (k=kkt_colind[i]; k<kkt_colind[i+1]; ++k) {
394  d->nz_kkt[k] = d->w[kkt_row[k]];
395  d->w[kkt_row[k]] = 0;
396  }
397  }
398 }
399 
400 // SYMBOL "qrqp_kkt_vector"
401 template<typename T1>
402 void casadi_qrqp_kkt_vector(casadi_qrqp_data<T1>* d, T1* kkt_i, casadi_int i) {
403  // Local variables
404  casadi_int k;
405  const casadi_int *h_colind, *h_row, *a_colind, *a_row, *at_colind, *at_row;
406  const casadi_qrqp_prob<T1>* p = d->prob;
407  // Extract sparsities
408  a_row = (a_colind = p->qp->sp_a+2) + p->qp->nx + 1;
409  at_row = (at_colind = p->sp_at+2) + p->qp->na + 1;
410  h_row = (h_colind = p->qp->sp_h+2) + p->qp->nx + 1;
411  // Reset kkt_i to zero
412  casadi_clear(kkt_i, p->qp->nz);
413  // Copy sparse entries
414  if (i<p->qp->nx) {
415  for (k=h_colind[i]; k<h_colind[i+1]; ++k) kkt_i[h_row[k]] = d->qp->h[k];
416  for (k=a_colind[i]; k<a_colind[i+1]; ++k) kkt_i[p->qp->nx+a_row[k]] = d->qp->a[k];
417  } else {
418  for (k=at_colind[i-p->qp->nx]; k<at_colind[i-p->qp->nx+1]; ++k) {
419  kkt_i[at_row[k]] = -d->nz_at[k];
420  }
421  }
422  // Add diagonal entry
423  kkt_i[i] -= 1.;
424 }
425 
426 // SYMBOL "qrqp_kkt_dot"
427 template<typename T1>
428 T1 casadi_qrqp_kkt_dot(casadi_qrqp_data<T1>* d, const T1* v, casadi_int i) {
429  // Local variables
430  casadi_int k;
431  const casadi_int *h_colind, *h_row, *a_colind, *a_row, *at_colind, *at_row;
432  T1 r;
433  const casadi_qrqp_prob<T1>* p = d->prob;
434  // Extract sparsities
435  a_row = (a_colind = p->qp->sp_a + 2) + p->qp->nx + 1;
436  at_row = (at_colind = p->sp_at + 2) + p->qp->na + 1;
437  h_row = (h_colind = p->qp->sp_h + 2) + p->qp->nx + 1;
438  // Scalar product with the diagonal
439  r = v[i];
440  // Scalar product with the sparse entries
441  if (i < p->qp->nx) {
442  for (k=h_colind[i]; k<h_colind[i+1]; ++k) r -= v[h_row[k]] * d->qp->h[k];
443  for (k=a_colind[i]; k<a_colind[i+1]; ++k) r -= v[p->qp->nx+a_row[k]] * d->qp->a[k];
444  } else {
445  for (k=at_colind[i-p->qp->nx]; k<at_colind[i-p->qp->nx+1]; ++k) {
446  r += v[at_row[k]] * d->nz_at[k];
447  }
448  }
449  return r;
450 }
451 
452 // SYMBOL "qrqp_kkt_residual"
453 template<typename T1>
454 void casadi_qrqp_kkt_residual(casadi_qrqp_data<T1>* d, T1* r) {
455  casadi_int i;
456  const casadi_qrqp_prob<T1>* p = d->prob;
457  for (i=0; i<p->qp->nz; ++i) {
458  if (d->lam[i]>0.) {
459  r[i] = d->ubz[i]-d->z[i];
460  } else if (d->lam[i]<0.) {
461  r[i] = d->lbz[i]-d->z[i];
462  } else if (i<p->qp->nx) {
463  r[i] = d->lam[i]-d->infeas[i];
464  } else {
465  r[i] = d->lam[i];
466  }
467  }
468 }
469 
470 // SYMBOL "qrqp_zero_blocking"
471 template<typename T1>
472 int casadi_qrqp_zero_blocking(casadi_qrqp_data<T1>* d) {
473  // Local variables
474  casadi_int i;
475  T1 dz_max = 0;
476  const casadi_qrqp_prob<T1>* p = d->prob;
477  // Look for violated constraints that are not improving
478  for (i = 0; i < p->qp->nz; ++i) {
479  if (d->dz[i] < -dz_max && d->lbz[i] - d->z[i] >= d->epr) {
480  dz_max = -d->dz[i];
481  d->index = i;
482  d->sign = -1;
483  d->msg = "lbz violated with zero step";
484  d->msg_ind = d->index;
485  } else if (d->dz[i] > dz_max && d->z[i] - d->ubz[i] >= d->epr) {
486  dz_max = d->dz[i];
487  d->index = i;
488  d->sign = 1;
489  d->msg = "ubz violated with zero step";
490  d->msg_ind = d->index;
491  }
492  }
493  return dz_max > 0;
494 }
495 
496 // SYMBOL "qrqp_primal_blocking"
497 template<typename T1>
498 void casadi_qrqp_primal_blocking(casadi_qrqp_data<T1>* d) {
499  // Local variables
500  casadi_int i;
501  T1 trial_z;
502  const casadi_qrqp_prob<T1>* p = d->prob;
503  // Check if violation with tau=0 and not improving
504  if (casadi_qrqp_zero_blocking(d)) {
505  d->tau = 0.;
506  return;
507  }
508  // Loop over all primal variables
509  for (i = 0; i < p->qp->nz; ++i) {
510  if (d->dz[i] == 0.) continue; // Skip zero steps
511  // Trial primal step
512  trial_z = d->z[i] + d->tau * d->dz[i];
513  if (d->dz[i] < 0 && trial_z < d->lbz[i] - d->epr) {
514  // Trial would increase maximum infeasibility
515  d->tau = (d->lbz[i] - d->epr - d->z[i]) / d->dz[i];
516  d->index = d->lam[i] < 0. ? -1 : i;
517  d->sign = -1;
518  d->msg = "Enforcing lbz";
519  d->msg_ind = i;
520  } else if (d->dz[i] > 0 && trial_z > d->ubz[i] + d->epr) {
521  // Trial would increase maximum infeasibility
522  d->tau = (d->ubz[i] + d->epr - d->z[i]) / d->dz[i];
523  d->index = d->lam[i] > 0. ? -1 : i;
524  d->sign = 1;
525  d->msg = "Enforcing ubz";
526  d->msg_ind = i;
527  }
528  if (d->tau <= 0) return;
529  }
530 }
531 
532 // SYMBOL "qrqp_dual_breakpoints"
533 template<typename T1>
534 casadi_int casadi_qrqp_dual_breakpoints(casadi_qrqp_data<T1>* d, T1* tau_list,
535  casadi_int* ind_list, T1 tau) {
536  // Local variables
537  casadi_int i, n_tau, loc, next_ind, tmp_ind, j;
538  T1 trial_lam, new_tau, next_tau, tmp_tau;
539  const casadi_qrqp_prob<T1>* p = d->prob;
540  // Dual feasibility is piecewise linear. Start with one interval [0,tau]:
541  tau_list[0] = tau;
542  ind_list[0] = -1; // no associated index
543  n_tau = 1;
544  // Find the taus corresponding to lam crossing zero and insert into list
545  for (i=0; i<p->qp->nz; ++i) {
546  if (d->dlam[i]==0.) continue; // Skip zero steps
547  if (d->lam[i]==0.) continue; // Skip inactive constraints
548  // Trial dual step
549  trial_lam = d->lam[i] + tau*d->dlam[i];
550  // Skip if no sign change
551  if (d->lam[i]>0 ? trial_lam>=0 : trial_lam<=0) continue;
552  // Location of the sign change
553  new_tau = -d->lam[i]/d->dlam[i];
554  // Where to insert the w[i]
555  for (loc=0; loc<n_tau-1; ++loc) {
556  if (new_tau<tau_list[loc]) break;
557  }
558  // Insert element
559  n_tau++;
560  next_tau=new_tau;
561  next_ind=i;
562  for (j=loc; j<n_tau; ++j) {
563  tmp_tau = tau_list[j];
564  tau_list[j] = next_tau;
565  next_tau = tmp_tau;
566  tmp_ind = ind_list[j];
567  ind_list[j] = next_ind;
568  next_ind = tmp_ind;
569  }
570  }
571  return n_tau;
572 }
573 
574 // SYMBOL "qrqp_dual_blocking"
575 template<typename T1>
576 casadi_int casadi_qrqp_dual_blocking(casadi_qrqp_data<T1>* d) {
577  // Local variables
578  casadi_int i, n_tau, j, k, du_index;
579  T1 tau_k, dtau, new_infeas, tau1, infeas, tinfeas;
580  const casadi_int *at_colind, *at_row;
581  const casadi_qrqp_prob<T1>* p = d->prob;
582  // Extract sparsities
583  at_row = (at_colind = p->sp_at+2) + p->qp->na + 1;
584  // Dual feasibility is piecewise linear in tau. Get the intervals:
585  n_tau = casadi_qrqp_dual_breakpoints(d, d->w, d->iw, d->tau);
586  // No dual blocking yet
587  du_index = -1;
588  // How long step can we take without exceeding e?
589  tau_k = 0.;
590  for (j=0; j<n_tau; ++j) {
591  // Distance to the next tau (may be zero)
592  dtau = d->w[j] - tau_k;
593  // Check if maximum dual infeasibility gets exceeded
594  for (k=0; k<p->qp->nx; ++k) {
595  // Get infeasibility and infeasibility tangent
596  infeas = d->infeas[k];
597  tinfeas = d->tinfeas[k];
598  // Make sure tinfeas>0
599  if (fabs(tinfeas)<1e-14) {
600  // Skip
601  continue;
602  } else if (tinfeas<0) {
603  // Switch signs
604  infeas *= -1;
605  tinfeas *= -1;
606  }
607  // Tentative new infeasibility
608  new_infeas = infeas + dtau*tinfeas;
609  // Does infeasibility get exceeded
610  if (new_infeas > d->edu) {
611  // Sign change and exceeded
612  tau1 = fmax(tau_k, tau_k + (d->edu - infeas)/tinfeas);
613  if (tau1 < d->tau) {
614  // Enforce dual blocking constraint
615  d->tau = tau1;
616  du_index = k;
617  }
618  }
619  }
620  // Update infeasibility
621  casadi_axpy(p->qp->nx, fmin(d->tau - tau_k, dtau), d->tinfeas, d->infeas);
622  // Stop here if dual blocking constraint
623  if (du_index>=0) return du_index;
624  // Continue to the next tau
625  tau_k = d->w[j];
626  // Get component, break if last
627  i = d->iw[j];
628  if (i<0) break;
629  // Update sign or tinfeas
630  if (!d->neverzero[i]) {
631  // lam becomes zero, update the infeasibility tangent
632  if (i<p->qp->nx) {
633  // Set a lam_x to zero
634  d->tinfeas[i] -= d->dlam[i];
635  } else {
636  // Set a lam_a to zero
637  for (k=at_colind[i-p->qp->nx]; k<at_colind[i-p->qp->nx+1]; ++k) {
638  d->tinfeas[at_row[k]] -= d->nz_at[k]*d->dlam[i];
639  }
640  }
641  }
642  }
643  return du_index;
644 }
645 
646 // SYMBOL "qrqp_take_step"
647 template<typename T1>
648 void casadi_qrqp_take_step(casadi_qrqp_data<T1>* d) {
649  // Local variables
650  casadi_int i;
651  const casadi_qrqp_prob<T1>* p = d->prob;
652  // Get current sign
653  for (i=0; i<p->qp->nz; ++i) d->iw[i] = d->lam[i]>0. ? 1 : d->lam[i]<0 ? -1 : 0;
654  // Take primal-dual step
655  casadi_axpy(p->qp->nz, d->tau, d->dz, d->z);
656  casadi_axpy(p->qp->nz, d->tau, d->dlam, d->lam);
657  // Update sign
658  for (i=0; i<p->qp->nz; ++i) {
659  // Allow sign changes for certain components
660  if (d->neverzero[i] && (d->iw[i]<0 ? d->lam[i]>0 : d->lam[i]<0)) {
661  d->iw[i]=-d->iw[i];
662  }
663  // Ensure correct sign
664  switch (d->iw[i]) {
665  case -1: d->lam[i] = fmin(d->lam[i], -p->dmin); break;
666  case 1: d->lam[i] = fmax(d->lam[i], p->dmin); break;
667  case 0: d->lam[i] = 0.; break;
668  }
669  }
670 }
671 
672 // SYMBOL "qrqp_flip_check"
673 template<typename T1>
674 int casadi_qrqp_flip_check(casadi_qrqp_data<T1>* d) {
675  const casadi_qrqp_prob<T1>* p = d->prob;
676  // Calculate the difference between unenforced and enforced column index
677  casadi_qrqp_kkt_vector(d, d->dlam, d->index);
678  // Calculate the difference between old and new column index
679  if (d->sign == 0) casadi_scal(p->qp->nz, -1., d->dlam);
680  // Try to find a linear combination of the new columns
681  casadi_qr_solve(d->dlam, 1, 0, p->sp_v, d->nz_v, p->sp_r, d->nz_r, d->beta,
682  p->prinv, p->pc, d->w);
683  // If dlam[index]!=1, new columns must be linearly independent
684  if (fabs(d->dlam[d->index]-1.) >= 1e-12) return 0;
685  // Next, find a linear combination of the new rows
686  casadi_clear(d->dz, p->qp->nz);
687  d->dz[d->index] = 1;
688  casadi_qr_solve(d->dz, 1, 1, p->sp_v, d->nz_v, p->sp_r, d->nz_r, d->beta,
689  p->prinv, p->pc, d->w);
690  // Normalize dlam, dz
691  casadi_scal(p->qp->nz, 1./sqrt(casadi_dot(p->qp->nz, d->dlam, d->dlam)), d->dlam);
692  casadi_scal(p->qp->nz, 1./sqrt(casadi_dot(p->qp->nz, d->dz, d->dz)), d->dz);
693  // KKT system will be singular
694  return 1;
695 }
696 
697 // SYMBOL "qrqp_factorize"
698 template<typename T1>
699 void casadi_qrqp_factorize(casadi_qrqp_data<T1>* d) {
700  const casadi_qrqp_prob<T1>* p = d->prob;
701  // Do we already have a search direction due to lost singularity?
702  if (d->has_search_dir) {
703  d->sing = 1;
704  return;
705  }
706  // Construct the KKT matrix
707  casadi_qrqp_kkt(d);
708  // QR factorization
709  casadi_qr(p->sp_kkt, d->nz_kkt, d->w, p->sp_v, d->nz_v, p->sp_r,
710  d->nz_r, d->beta, p->prinv, p->pc);
711  // Check singularity
712  d->sing = casadi_qr_singular(&d->mina, &d->imina, d->nz_r, p->sp_r, p->pc, 1e-12);
713 }
714 
715 // SYMBOL "qrqp_expand_step"
716 template<typename T1>
717 void casadi_qrqp_expand_step(casadi_qrqp_data<T1>* d) {
718  // Local variables
719  casadi_int i;
720  const casadi_qrqp_prob<T1>* p = d->prob;
721  // Calculate change in Lagrangian gradient
722  casadi_clear(d->dlam, p->qp->nx);
723  casadi_mv(d->qp->h, p->qp->sp_h, d->dz, d->dlam, 0); // gradient of the objective
724  casadi_mv(d->qp->a, p->qp->sp_a, d->dz + p->qp->nx, d->dlam, 1); // gradient of the Lagrangian
725  // Step in lam[:nx]
726  casadi_scal(p->qp->nx, -1., d->dlam);
727  // For inactive constraints, lam(x) step is zero
728  for (i = 0; i < p->qp->nx; ++i) if (d->lam[i] == 0.) d->dlam[i] = 0.;
729  // Step in lam[nx:]
730  casadi_copy(d->dz+p->qp->nx, p->qp->na, d->dlam + p->qp->nx);
731  // Step in z[nx:]
732  casadi_clear(d->dz + p->qp->nx, p->qp->na);
733  casadi_mv(d->qp->a, p->qp->sp_a, d->dz, d->dz + p->qp->nx, 0);
734  // Avoid steps that are nonzero due to numerics
735  for (i = 0; i < p->qp->nz; ++i) if (fabs(d->dz[i]) < 1e-14) d->dz[i] = 0.;
736  // Tangent of the dual infeasibility at tau=0
737  casadi_clear(d->tinfeas, p->qp->nx);
738  casadi_mv(d->qp->h, p->qp->sp_h, d->dz, d->tinfeas, 0);
739  casadi_mv(d->qp->a, p->qp->sp_a, d->dlam + p->qp->nx, d->tinfeas, 1);
740  casadi_axpy(p->qp->nx, 1., d->dlam, d->tinfeas);
741 }
742 
743 // SYMBOL "casadi_qrqp_pr_direction"
744 template<typename T1>
745 int casadi_qrqp_pr_direction(casadi_qrqp_data<T1>* d) {
746  casadi_int i;
747  const casadi_qrqp_prob<T1>* p = d->prob;
748  for (i=0; i<p->qp->nz; ++i) {
749  if (d->lbz[i] - d->z[i] >= d->epr) {
750  // Prevent further violation of lower bound
751  if (d->dz[i] < 0 || d->dlam[i] > 0) return 1;
752  } else if (d->z[i] - d->ubz[i] >= d->epr) {
753  // Prevent further violation of upper bound
754  if (d->dz[i] > 0 || d->dlam[i] < 0) return 1;
755  }
756  }
757  return 0;
758 }
759 
760 // SYMBOL "casadi_qrqp_du_direction"
761 template<typename T1>
762 int casadi_qrqp_du_direction(casadi_qrqp_data<T1>* d) {
763  casadi_int i;
764  const casadi_qrqp_prob<T1>* p = d->prob;
765  for (i=0; i<p->qp->nx; ++i) {
766  // Prevent further increase in dual infeasibility
767  if (d->infeas[i] <= -d->edu && d->tinfeas[i] < -1e-12) {
768  return 1;
769  } else if (d->infeas[i] >= d->edu && d->tinfeas[i] > 1e-12) {
770  return 1;
771  }
772  }
773  return 0;
774 }
775 
776 // SYMBOL "qrqp_enforceable"
777 template<typename T1>
778 int casadi_qrqp_enforceable(casadi_qrqp_data<T1>* d, casadi_int i, casadi_int s) {
779  // Local variables
780  casadi_int k;
781  const casadi_int *at_colind, *at_row;
782  const casadi_qrqp_prob<T1>* p = d->prob;
783  // Can always enforce if not at bound
784  if (fabs(d->infeas[i]) < d->edu) return 1;
785  // AT sparsity
786  at_colind = p->sp_at + 2;
787  at_row = at_colind + p->qp->na + 1;
788  // Can we set lam[i] := s*DMIN without exceeding edu?
789  if (i<p->qp->nx) {
790  return (s < 0) == (d->infeas[i] > 0);
791  } else {
792  for (k=at_colind[i-p->qp->nx]; k<at_colind[i-p->qp->nx+1]; ++k) {
793  if (d->nz_at[k] > 0) {
794  if ((s > 0) == (d->infeas[at_row[k]] > 0)) return 0;
795  } else if (d->nz_at[k] < 0) {
796  if ((s < 0) == (d->infeas[at_row[k]] > 0)) return 0;
797  }
798  }
799  return 1;
800  }
801 }
802 
803 // SYMBOL "qrqp_singular_step"
804 // C-REPLACE "static_cast<T1*>(0)" "0"
805 template<typename T1>
806 int casadi_qrqp_singular_step(casadi_qrqp_data<T1>* d) {
807  // Local variables
808  T1 tau_test, tau;
809  casadi_int nnz_kkt, nk, k, i, best_k, best_neg, neg;
810  const casadi_qrqp_prob<T1>* p = d->prob;
811  // Find the columns that take part in any linear combination
812  for (i = 0; i < p->qp->nz; ++i) d->lincomb[i] = 0;
813  for (k = 0; k < d->sing; ++k) {
814  if (!d->has_search_dir) {
815  casadi_qr_colcomb(d->dlam, d->nz_r, p->sp_r, p->pc, 1e-12, k);
816  }
817  for (i = 0; i < p->qp->nz; ++i) if (fabs(d->dlam[i]) >= 1e-12) d->lincomb[i]++;
818  }
819 
820  if (d->has_search_dir) {
821  // One, given search direction
822  nk = 1;
823  } else {
824  // QR factorization of the transpose
825  casadi_trans(d->nz_kkt, p->sp_kkt, d->nz_v, p->sp_kkt, d->iw);
826  nnz_kkt = p->sp_kkt[2+p->qp->nz]; // kkt_colind[nz]
827  casadi_copy(d->nz_v, nnz_kkt, d->nz_kkt);
828  casadi_qr(p->sp_kkt, d->nz_kkt, d->w, p->sp_v, d->nz_v, p->sp_r, d->nz_r,
829  d->beta, p->prinv, p->pc);
830  // For all nullspace vectors
831  nk = casadi_qr_singular(static_cast<T1*>(0), 0, d->nz_r, p->sp_r, p->pc, 1e-12);
832  }
833  // Best flip
834  best_k = best_neg = -1;
835  tau = p->inf;
836  for (k=0; k<nk; ++k) {
837  if (!d->has_search_dir) {
838  // Get a linear combination of the rows in kkt
839  casadi_qr_colcomb(d->dz, d->nz_r, p->sp_r, p->pc, 1e-12, k);
840  }
841  // Which constraints can be flipped in order to increase rank?
842  for (i=0; i<p->qp->nz; ++i) {
843  d->iw[i] = d->lincomb[i] && fabs(casadi_qrqp_kkt_dot(d, d->dz, i)) > 1e-12;
844  }
845  // Calculate step, dz and dlam
846  casadi_qrqp_expand_step(d);
847  // Try both positive and negative direction
848  for (neg = 0; neg < 2; ++neg) {
849  // Negate direction
850  if (neg) {
851  casadi_scal(p->qp->nz, -1., d->dz);
852  casadi_scal(p->qp->nz, -1., d->dlam);
853  casadi_scal(p->qp->nx, -1., d->tinfeas);
854  }
855  // Make sure primal infeasibility doesn't exceed limits
856  if (casadi_qrqp_pr_direction(d)) continue;
857  // Make sure dual infeasibility doesn't exceed limits
858  if (casadi_qrqp_du_direction(d)) continue;
859  // Loop over potential active set changes
860  for (i=0; i<p->qp->nz; ++i) {
861  // Skip if no rank increase
862  if (!d->iw[i]) continue;
863  // Enforced or not?
864  if (d->lam[i]==0.) {
865  if (d->z[i] <= d->ubz[i] && (d->z[i] >= d->lbz[i] ?
866  d->dz[i] < -1e-12 : d->dz[i] > 1e-12)) {
867  // Enforce lower bound?
868  if (!d->neverlower[i]
869  && (tau_test = (d->lbz[i] - d->z[i]) / d->dz[i]) < tau
870  && casadi_qrqp_enforceable(d, i, -1)) {
871  tau = tau_test;
872  d->r_index = i;
873  d->r_sign = -1;
874  best_k = k;
875  best_neg = neg;
876  }
877  } else if (d->z[i] >= d->lbz[i] && (d->z[i] <= d->ubz[i] ?
878  d->dz[i] > 1e-12 : d->dz[i] < -1e-12)) {
879  // Enforce upper bound?
880  if (!d->neverupper[i]
881  && (tau_test = (d->ubz[i] - d->z[i]) / d->dz[i]) < tau
882  && casadi_qrqp_enforceable(d, i, 1)) {
883  tau = tau_test;
884  d->r_index = i;
885  d->r_sign = 1;
886  best_k = k;
887  best_neg = neg;
888  }
889  }
890  } else if (!d->neverzero[i]) {
891  // Drop a constraint?
892  if (d->lam[i] > 0 ? d->dlam[i] < -1e-12 : d->dlam[i] > 1e-12) {
893  if ((tau_test = -d->lam[i] / d->dlam[i]) < tau) {
894  tau = tau_test;
895  d->r_index = i;
896  d->r_sign = 0;
897  best_k = k;
898  best_neg = neg;
899  }
900  }
901  }
902  }
903  }
904  }
905  // Can we restore feasibility?
906  if (d->r_index < 0) return 1;
907  // Recalculate direction, if needed
908  if (--k != best_k) {
909  // Need to recalculate direction
910  casadi_qr_colcomb(d->dz, d->nz_r, p->sp_r, p->pc, 1e-12, best_k);
911  casadi_qrqp_expand_step(d);
912  if (best_neg) tau *= -1;
913  } else if (--neg != best_neg) {
914  // No need to recalculate, but opposite direction
915  tau *= -1;
916  }
917  // Scale step so that that tau=1 corresponds to a full step
918  casadi_scal(p->qp->nz, tau, d->dz);
919  casadi_scal(p->qp->nz, tau, d->dlam);
920  casadi_scal(p->qp->nx, tau, d->tinfeas);
921  return 0;
922 }
923 
924 // SYMBOL "qrqp_calc_step"
925 template<typename T1>
926 int casadi_qrqp_calc_step(casadi_qrqp_data<T1>* d) {
927  // Local variables
928  const casadi_qrqp_prob<T1>* p = d->prob;
929  // Reset returns
930  d->r_index = -1;
931  d->r_sign = 0;
932  // Handle singularity
933  if (d->sing) return casadi_qrqp_singular_step(d);
934  // Negative KKT residual
935  casadi_qrqp_kkt_residual(d, d->dz);
936  // Solve to get step in z[:nx] and lam[nx:]
937  casadi_qr_solve(d->dz, 1, 1, p->sp_v, d->nz_v, p->sp_r, d->nz_r, d->beta,
938  p->prinv, p->pc, d->w);
939  // Have step in dz[:nx] and dlam[nx:]. Calculate complete dz and dlam
940  casadi_qrqp_expand_step(d);
941  // Successful return
942  return 0;
943 }
944 
945 // SYMBOL "qrqp_calc_sens"
946 template<typename T1>
947 void casadi_qrqp_calc_sens(casadi_qrqp_data<T1>* d, casadi_int i) {
948  // Local variables
949  const casadi_qrqp_prob<T1>* p = d->prob;
950  // Calculate sensitivities in decreasing dual infeasibility index i
951  casadi_clear(d->sens, p->qp->nz);
952  if (i >= 0) {
953  d->sens[i] = d->infeas[i] > 0 ? -1. : 1.;
954  casadi_mv(d->qp->a, p->qp->sp_a, d->sens, d->sens + p->qp->nx, 0);
955  }
956 }
957 
958 // SYMBOL "qrqp_calc_dependent"
959 template<typename T1>
960 void casadi_qrqp_calc_dependent(casadi_qrqp_data<T1>* d) {
961  // Local variables
962  casadi_int i;
963  T1 r;
964  const casadi_qrqp_prob<T1>* p = d->prob;
965  // Calculate f
966  d->f = casadi_bilin(d->qp->h, p->qp->sp_h, d->z, d->z)/2.
967  + casadi_dot(p->qp->nx, d->z, d->qp->g);
968  // Calculate z[nx:]
969  casadi_clear(d->z+p->qp->nx, p->qp->na);
970  casadi_mv(d->qp->a, p->qp->sp_a, d->z, d->z+p->qp->nx, 0);
971  // Calculate gradient of the Lagrangian
972  casadi_copy(d->qp->g, p->qp->nx, d->infeas);
973  casadi_mv(d->qp->h, p->qp->sp_h, d->z, d->infeas, 0);
974  casadi_mv(d->qp->a, p->qp->sp_a, d->lam+p->qp->nx, d->infeas, 1);
975  // Calculate lam[:nx] without changing the sign accidentally, dual infeasibility
976  for (i=0; i<p->qp->nx; ++i) {
977  // No change if zero
978  if (d->lam[i]==0) continue;
979  // lam[i] with no sign restrictions
980  r = -d->infeas[i];
981  if (d->lam[i]>0) {
982  if (d->neverzero[i] && !d->neverlower[i]) {
983  d->lam[i] = r==0 ? p->dmin : r; // keep sign if r==0
984  } else {
985  d->lam[i] = fmax(r, p->dmin); // no sign change
986  }
987  } else {
988  if (d->neverzero[i] && !d->neverupper[i]) {
989  d->lam[i] = r==0 ? -p->dmin : r; // keep sign if r==0
990  } else {
991  d->lam[i] = fmin(r, -p->dmin); // no sign change
992  }
993  }
994  // Update dual infeasibility
995  d->infeas[i] += d->lam[i];
996  }
997  // Calculate primal and dual error
998  casadi_qrqp_pr(d);
999  casadi_qrqp_du(d);
1000  // Acceptable primal and dual error
1001  d->epr = fmax(d->pr, (0.5 * p->constr_viol_tol / p->dual_inf_tol) * d->du);
1002  d->edu = fmax(d->du, (0.5 * p->dual_inf_tol / p->constr_viol_tol) * d->pr);
1003  // Sensitivity in decreasing |du|
1004  casadi_qrqp_calc_sens(d, d->idu);
1005 }
1006 
1007 // SYMBOL "qrqp_linesearch"
1008 template<typename T1>
1009 void casadi_qrqp_linesearch(casadi_qrqp_data<T1>* d) {
1010  // Local variables
1011  casadi_int du_index;
1012  // Start with a full step and no active set change
1013  d->sign = 0;
1014  d->index = -1;
1015  d->tau = 1.;
1016  // Find largest possible step without exceeding acceptable |pr|
1017  casadi_qrqp_primal_blocking(d);
1018  // Find largest possible step without exceeding acceptable |du|
1019  du_index = casadi_qrqp_dual_blocking(d);
1020  // Take primal-dual step, avoiding accidental sign changes for lam
1021  casadi_qrqp_take_step(d);
1022  // Handle dual blocking constraints
1023  if (du_index >= 0) {
1024  // Sensititivity in decreasing du_index
1025  casadi_qrqp_calc_sens(d, du_index);
1026  // Find corresponding index
1027  casadi_qrqp_du_index(d);
1028  }
1029 }
1030 
1031 // SYMBOL "qrqp_flip"
1032 template<typename T1>
1033 void casadi_qrqp_flip(casadi_qrqp_data<T1>* d) {
1034  // Local variables
1035  const casadi_qrqp_prob<T1>* p = d->prob;
1036  // Try to restore regularity if possible
1037  if (d->index == -1 && d->r_index >= 0) {
1038  if (d->r_sign != 0 || casadi_qrqp_du_check(d, d->r_index)) {
1039  d->index = d->r_index;
1040  d->sign = d->r_sign;
1041  if (d->sign > 0) {
1042  d->msg = "Enforced ubz for regularity";
1043  } else if (d->sign < 0) {
1044  d->msg = "Enforced lbz for regularity";
1045  } else if (d->lam[d->index] > 0) {
1046  d->msg = "Dropped ubz for regularity";
1047  } else {
1048  d->msg = "Dropped lbz for regularity";
1049  }
1050  d->msg_ind = d->index;
1051  }
1052  }
1053  // If nonsingular and nonzero error, try to flip a constraint
1054  if (!d->sing && d->index == -1) {
1055  if (d->pr * p->dual_inf_tol >= p->constr_viol_tol * d->du) {
1056  // Improve primal feasibility if dominating
1057  if (d->pr >= p->constr_viol_tol) casadi_qrqp_pr_index(d);
1058  } else {
1059  // Improve dual feasibility if dominating
1060  if (d->du >= p->dual_inf_tol) casadi_qrqp_du_index(d);
1061  }
1062  }
1063  // No search direction given by default
1064  d->has_search_dir = 0;
1065  // If a constraint was added
1066  if (d->index >= 0) {
1067  // Detect singularity before it happens and get nullspace vectors
1068  if (!d->sing) d->has_search_dir = casadi_qrqp_flip_check(d);
1069  // Perform the active-set change
1070  d->lam[d->index] = d->sign==0 ? 0 : d->sign > 0 ? p->dmin : -p->dmin;
1071  // Recalculate primal and dual infeasibility
1072  casadi_qrqp_calc_dependent(d);
1073  }
1074 }
1075 
1076 // SYMBOL "qrqp_prepare"
1077 template<typename T1>
1078 int casadi_qrqp_prepare(casadi_qrqp_data<T1>* d) {
1079  // Local variables
1080  const casadi_qrqp_prob<T1>* p = d->prob;
1081  // Calculate dependent quantities
1082  casadi_qrqp_calc_dependent(d);
1083  // Make an active set change
1084  casadi_qrqp_flip(d);
1085  // Form and factorize the KKT system
1086  casadi_qrqp_factorize(d);
1087  // Termination message
1088  if (!d->sing && d->index == -1) {
1089  d->status = QP_SUCCESS;
1090  d->msg = "Converged";
1091  d->msg_ind = -2;
1092  return 1;
1093  } else if (d->iter >= p->max_iter) {
1094  d->status = QP_MAX_ITER;
1095  d->msg = "Max iter";
1096  d->msg_ind = -2;
1097  return 1;
1098  } else if (!d->sing && d->ipr < 0 && d->idu < 0) {
1099  d->status = QP_SUCCESS;
1100  d->msg = "No primal or dual error";
1101  d->msg_ind = -2;
1102  return 1;
1103  } else {
1104  // Keep iterating
1105  return 0;
1106  }
1107 }
1108 
1109 // SYMBOL "qrqp_iterate"
1110 template<typename T1>
1111 int casadi_qrqp_iterate(casadi_qrqp_data<T1>* d) {
1112  // Reset message flag
1113  d->msg = 0;
1114  // Start a new iteration
1115  d->iter++;
1116  // Calculate search direction
1117  if (casadi_qrqp_calc_step(d)) {
1118  d->status = QP_NO_SEARCH_DIR;
1119  return 1;
1120  }
1121  // Line search in the calculated direction
1122  casadi_qrqp_linesearch(d);
1123  // Keep iterating
1124  return 0;
1125 }
1126 
1127 // SYMBOL "qrqp_print_header"
1128 template<typename T1>
1129 int casadi_qrqp_print_header(casadi_qrqp_data<T1>* d, char* buf, size_t buf_sz) {
1130 #ifdef CASADI_SNPRINTF
1131  int flag;
1132  // Print to string
1133  flag = CASADI_SNPRINTF(buf, buf_sz, "%5s %5s %9s %9s %5s %9s %5s %9s %5s %9s %4s",
1134  "Iter", "Sing", "fk", "|pr|", "con", "|du|", "var",
1135  "min_R", "con", "last_tau", "Note");
1136  // Check if error
1137  if (flag < 0) {
1138  d->status = QP_PRINTING_ERROR;
1139  return 1;
1140  }
1141 #else
1142  if (buf_sz) buf[0] = '\0';
1143 #endif
1144  // Successful return
1145  return 0;
1146 }
1147 
1148 // SYMBOL "qrqp_print_colcomb"
1149 template<typename T1>
1150 int casadi_qrqp_print_colcomb(casadi_qrqp_data<T1>* d, char* buf, size_t buf_sz, casadi_int j) {
1151 #ifdef CASADI_SNPRINTF
1152  casadi_int num_size, n_print, i, k, buf_offset, val;
1153  size_t b;
1154  const casadi_qrqp_prob<T1>* p = d->prob;
1155  casadi_qr_colcomb(d->dlam, d->nz_r, p->sp_r, p->pc, 1e-12, j);
1156 
1157  // Determine max printing size
1158  num_size = 1;
1159  val = p->qp->nz-1;
1160  while (val) {
1161  val/=10;
1162  num_size++;
1163  }
1164 
1165  if (buf_sz<=4) return 1;
1166 
1167  // How many numbers can be printed?
1168  // Need some extra space for '...'
1169  // and null
1170  n_print = (buf_sz-4)/num_size;
1171 
1172  // Clear buffer
1173  for (b=0;b<buf_sz;++b) buf[b]=' ';
1174 
1175  buf_offset = 0;
1176  for (i=0;i<p->qp->nz;++i) {
1177  if (fabs(d->dlam[i]) >= 1e-12) {
1178  if (n_print==0) {
1179  buf[buf_sz-4] = '.';
1180  buf[buf_sz-3] = '.';
1181  buf[buf_sz-2] = '.';
1182  buf[buf_sz-1] = '\0';
1183  return 1;
1184  }
1185  n_print--;
1186  CASADI_SNPRINTF(buf+buf_offset, num_size, "%d", static_cast<int>(i));
1187  // Clear null chars
1188  for (k=0;k<num_size;++k) {
1189  if (buf[buf_offset+k]=='\0') buf[buf_offset+k] = ' ';
1190  }
1191  buf_offset += num_size;
1192  }
1193  }
1194  buf[buf_sz-1] = '\0';
1195 #else
1196  if (buf_sz) buf[0] = '\0';
1197 #endif
1198  // Successful return
1199  return 0;
1200 }
1201 
1202 // SYMBOL "qrqp_print_iteration"
1203 template<typename T1>
1204 int casadi_qrqp_print_iteration(casadi_qrqp_data<T1>* d, char* buf, int buf_sz) {
1205 #ifdef CASADI_SNPRINTF
1206  int flag;
1207  // Print iteration data without note to string
1208  flag = CASADI_SNPRINTF(buf, buf_sz,
1209  "%5d %5d %9.2g %9.2g %5d %9.2g %5d %9.2g %5d %9.2g ",
1210  static_cast<int>(d->iter), static_cast<int>(d->sing), d->f, d->pr,
1211  static_cast<int>(d->ipr), d->du, static_cast<int>(d->idu),
1212  d->mina, static_cast<int>(d->imina), d->tau);
1213  // Check if error
1214  if (flag < 0) {
1215  d->status = QP_PRINTING_ERROR;
1216  return 1;
1217  }
1218  // Rest of buffer reserved for iteration note
1219  buf += flag;
1220  buf_sz -= flag;
1221  // Print iteration note, if any
1222  if (d->msg) {
1223  if (d->msg_ind > -2) {
1224  flag = CASADI_SNPRINTF(buf, buf_sz, "%s, i=%d", d->msg, static_cast<int>(d->msg_ind));
1225  } else {
1226  flag = CASADI_SNPRINTF(buf, buf_sz, "%s", d->msg);
1227  }
1228  // Check if error
1229  if (flag < 0) {
1230  d->status = QP_PRINTING_ERROR;
1231  return 1;
1232  }
1233  }
1234 #else
1235  if (buf_sz) buf[0] = '\0';
1236 #endif
1237  // Successful return
1238  return 0;
1239 }
casadi_int index
casadi_qp_data< T1 > * qp
Definition: casadi_qrqp.hpp:76
casadi_int * neverlower
Definition: casadi_qrqp.hpp:83
const char * msg
Definition: casadi_qrqp.hpp:87
casadi_int imina
Definition: casadi_qrqp.hpp:98
casadi_int r_sign
casadi_int r_index
casadi_int * neverzero
Definition: casadi_qrqp.hpp:83
casadi_int * iw
Definition: casadi_qrqp.hpp:83
casadi_int * neverupper
Definition: casadi_qrqp.hpp:83
casadi_int sing
Definition: casadi_qrqp.hpp:93
casadi_qrqp_flag_t status
Definition: casadi_qrqp.hpp:80
casadi_int * lincomb
Definition: casadi_qrqp.hpp:83
casadi_int msg_ind
Definition: casadi_qrqp.hpp:89
const casadi_qrqp_prob< T1 > * prob
Definition: casadi_qrqp.hpp:74
const casadi_qp_prob< T1 > * qp
Definition: casadi_qrqp.hpp:33
casadi_int max_iter
Definition: casadi_qrqp.hpp:45
const casadi_int * sp_at
Definition: casadi_qrqp.hpp:35
const casadi_int * sp_r
Definition: casadi_qrqp.hpp:37
const casadi_int * prinv
Definition: casadi_qrqp.hpp:37
const casadi_int * sp_v
Definition: casadi_qrqp.hpp:37
const casadi_int * sp_kkt
Definition: casadi_qrqp.hpp:35
const casadi_int * pc
Definition: casadi_qrqp.hpp:37