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