GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/eiquadprog-fast.cpp Lines: 151 222 68.0 %
Date: 2023-11-29 12:38:05 Branches: 163 386 42.2 %

Line Branch Exec Source
1
#include "eiquadprog/eiquadprog-fast.hpp"
2
3
#include <iostream>
4
5
namespace eiquadprog {
6
namespace solvers {
7
8







12
EiquadprogFast::EiquadprogFast() {
9
12
  m_maxIter = DEFAULT_MAX_ITER;
10
12
  q = 0;  // size of the active set A (containing the indices
11
  // of the active constraints)
12
12
  is_inverse_provided_ = false;
13
12
  m_nVars = 0;
14
12
  m_nEqCon = 0;
15
12
  m_nIneqCon = 0;
16
12
}
17
18
24
EiquadprogFast::~EiquadprogFast() {}
19
20
12
void EiquadprogFast::reset(size_t nVars, size_t nEqCon, size_t nIneqCon) {
21
12
  m_nVars = nVars;
22
12
  m_nEqCon = nEqCon;
23
12
  m_nIneqCon = nIneqCon;
24
12
  m_J.setZero(nVars, nVars);
25
12
  chol_.compute(m_J);
26
12
  R.resize(nVars, nVars);
27
12
  s.resize(nIneqCon);
28
12
  r.resize(nIneqCon + nEqCon);
29
12
  u.resize(nIneqCon + nEqCon);
30
12
  z.resize(nVars);
31
12
  d.resize(nVars);
32
12
  np.resize(nVars);
33
12
  A.resize(nIneqCon + nEqCon);
34
12
  iai.resize(nIneqCon);
35
12
  iaexcl.resize(nIneqCon);
36
12
  x_old.resize(nVars);
37
12
  u_old.resize(nIneqCon + nEqCon);
38
12
  A_old.resize(nIneqCon + nEqCon);
39
40
#ifdef OPTIMIZE_ADD_CONSTRAINT
41
  T1.resize(nVars);
42
#endif
43
12
}
44
45
10
bool EiquadprogFast::add_constraint(MatrixXd &R, MatrixXd &J, VectorXd &d,
46
                                    size_t &iq, double &R_norm) {
47
10
  size_t nVars = J.rows();
48
#ifdef EIQGUADPROG_TRACE_SOLVER
49
  std::cerr << "Add constraint " << iq << '/';
50
#endif
51
  size_t j, k;
52
  double cc, ss, h, t1, t2, xny;
53
54
#ifdef OPTIMIZE_ADD_CONSTRAINT
55
  Eigen::Vector2d cc_ss;
56
#endif
57
58
  /* we have to find the Givens rotation which will reduce the element
59
           d(j) to zero.
60
           if it is already zero we don't have to do anything, except of
61
           decreasing j */
62
16
  for (j = d.size() - 1; j >= iq + 1; j--) {
63
    /* The Givens rotation is done with the matrix (cc cs, cs -cc).
64
                    If cc is one, then element (j) of d is zero compared with
65
       element (j - 1). Hence we don't have to do anything. If cc is zero, then
66
       we just have to switch column (j) and column (j - 1) of J. Since we only
67
       switch columns in J, we have to be careful how we update d depending on
68
       the sign of gs. Otherwise we have to apply the Givens rotation to these
69
       columns. The i - 1 element of d has to be updated to h. */
70
6
    cc = d(j - 1);
71
6
    ss = d(j);
72
6
    h = utils::distance(cc, ss);
73
6
    if (h == 0.0) continue;
74
6
    d(j) = 0.0;
75
6
    ss = ss / h;
76
6
    cc = cc / h;
77
6
    if (cc < 0.0) {
78
      cc = -cc;
79
      ss = -ss;
80
      d(j - 1) = -h;
81
    } else
82
6
      d(j - 1) = h;
83
6
    xny = ss / (1.0 + cc);
84
85
// #define OPTIMIZE_ADD_CONSTRAINT
86
#ifdef OPTIMIZE_ADD_CONSTRAINT  // the optimized code is actually slower than
87
                                // the original
88
    T1 = J.col(j - 1);
89
    cc_ss(0) = cc;
90
    cc_ss(1) = ss;
91
    J.col(j - 1).noalias() = J.middleCols<2>(j - 1) * cc_ss;
92
    J.col(j) = xny * (T1 + J.col(j - 1)) - J.col(j);
93
#else
94
    // J.col(j-1) = J[:,j-1:j] * [cc; ss]
95
18
    for (k = 0; k < nVars; k++) {
96
12
      t1 = J(k, j - 1);
97
12
      t2 = J(k, j);
98
12
      J(k, j - 1) = t1 * cc + t2 * ss;
99
12
      J(k, j) = xny * (t1 + J(k, j - 1)) - t2;
100
    }
101
#endif
102
  }
103
  /* update the number of constraints added*/
104
10
  iq++;
105
  /* To update R we have to put the iq components of the d vector
106
into column iq - 1 of R
107
*/
108

10
  R.col(iq - 1).head(iq) = d.head(iq);
109
#ifdef EIQGUADPROG_TRACE_SOLVER
110
  std::cerr << iq << std::endl;
111
#endif
112
113
10
  if (std::abs(d(iq - 1)) <= std::numeric_limits<double>::epsilon() * R_norm)
114
    // problem degenerate
115
1
    return false;
116
9
  R_norm = std::max<double>(R_norm, std::abs(d(iq - 1)));
117
9
  return true;
118
}
119
120
void EiquadprogFast::delete_constraint(MatrixXd &R, MatrixXd &J, VectorXi &A,
121
                                       VectorXd &u, size_t nEqCon, size_t &iq,
122
                                       size_t l) {
123
  size_t nVars = R.rows();
124
#ifdef EIQGUADPROG_TRACE_SOLVER
125
  std::cerr << "Delete constraint " << l << ' ' << iq;
126
#endif
127
  size_t i, j, k;
128
  size_t qq = 0;
129
  double cc, ss, h, xny, t1, t2;
130
131
  /* Find the index qq for active constraint l to be removed */
132
  for (i = nEqCon; i < iq; i++)
133
    if (A(i) == static_cast<VectorXi::Scalar>(l)) {
134
      qq = i;
135
      break;
136
    }
137
138
  /* remove the constraint from the active set and the duals */
139
  for (i = qq; i < iq - 1; i++) {
140
    A(i) = A(i + 1);
141
    u(i) = u(i + 1);
142
    R.col(i) = R.col(i + 1);
143
  }
144
145
  A(iq - 1) = A(iq);
146
  u(iq - 1) = u(iq);
147
  A(iq) = 0;
148
  u(iq) = 0.0;
149
  for (j = 0; j < iq; j++) R(j, iq - 1) = 0.0;
150
  /* constraint has been fully removed */
151
  iq--;
152
#ifdef EIQGUADPROG_TRACE_SOLVER
153
  std::cerr << '/' << iq << std::endl;
154
#endif
155
156
  if (iq == 0) return;
157
158
  for (j = qq; j < iq; j++) {
159
    cc = R(j, j);
160
    ss = R(j + 1, j);
161
    h = utils::distance(cc, ss);
162
    if (h == 0.0) continue;
163
    cc = cc / h;
164
    ss = ss / h;
165
    R(j + 1, j) = 0.0;
166
    if (cc < 0.0) {
167
      R(j, j) = -h;
168
      cc = -cc;
169
      ss = -ss;
170
    } else
171
      R(j, j) = h;
172
173
    xny = ss / (1.0 + cc);
174
    for (k = j + 1; k < iq; k++) {
175
      t1 = R(j, k);
176
      t2 = R(j + 1, k);
177
      R(j, k) = t1 * cc + t2 * ss;
178
      R(j + 1, k) = xny * (t1 + R(j, k)) - t2;
179
    }
180
    for (k = 0; k < nVars; k++) {
181
      t1 = J(k, j);
182
      t2 = J(k, j + 1);
183
      J(k, j) = t1 * cc + t2 * ss;
184
      J(k, j + 1) = xny * (J(k, j) + t1) - t2;
185
    }
186
  }
187
}
188
189
12
EiquadprogFast_status EiquadprogFast::solve_quadprog(
190
    const MatrixXd &Hess, const VectorXd &g0, const MatrixXd &CE,
191
    const VectorXd &ce0, const MatrixXd &CI, const VectorXd &ci0, VectorXd &x) {
192
12
  const size_t nVars = g0.size();
193
12
  const size_t nEqCon = ce0.size();
194
12
  const size_t nIneqCon = ci0.size();
195
196

12
  if (nVars != m_nVars || nEqCon != m_nEqCon || nIneqCon != m_nIneqCon)
197
    reset(nVars, nEqCon, nIneqCon);
198
199


12
  assert(static_cast<size_t>(Hess.rows()) == m_nVars &&
200
         static_cast<size_t>(Hess.cols()) == m_nVars);
201

12
  assert(static_cast<size_t>(g0.size()) == m_nVars);
202


12
  assert(static_cast<size_t>(CE.rows()) == m_nEqCon &&
203
         static_cast<size_t>(CE.cols()) == m_nVars);
204

12
  assert(static_cast<size_t>(ce0.size()) == m_nEqCon);
205


12
  assert(static_cast<size_t>(CI.rows()) == m_nIneqCon &&
206
         static_cast<size_t>(CI.cols()) == m_nVars);
207

12
  assert(static_cast<size_t>(ci0.size()) == m_nIneqCon);
208
209
  size_t i, k, l;  // indices
210
  size_t ip;       // index of the chosen violated constraint
211
  size_t iq;       // current number of active constraints
212
  double psi;      // current sum of constraint violations
213
  double c1;       // Hessian trace
214
  double c2;       // Hessian Cholesky factor trace
215
  double ss;       // largest constraint violation (negative for violation)
216
  double R_norm;   // norm of matrix R
217
12
  const double inf = std::numeric_limits<double>::infinity();
218
  double t, t1, t2;
219
  /* t is the step length, which is the minimum of the partial step length t1
220
   * and the full step length t2 */
221
222
12
  iter = 0;  // active-set iteration number
223
224
  /*
225
   * Preprocessing phase
226
   */
227
  /* compute the trace of the original matrix Hess */
228
12
  c1 = Hess.trace();
229
230
  /* decompose the matrix Hess in the form LL^T */
231
12
  if (!is_inverse_provided_) {
232
    START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_CHOLESKY_DECOMPOSITION);
233
12
    chol_.compute(Hess);
234
    STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_CHOLESKY_DECOMPOSITION);
235
  }
236
237
  /* initialize the matrix R */
238
12
  d.setZero(nVars);
239
12
  R.setZero(nVars, nVars);
240
12
  R_norm = 1.0;
241
242
  /* compute the inverse of the factorized matrix Hess^-1,
243
     this is the initial value for H */
244
  // m_J = L^-T
245
12
  if (!is_inverse_provided_) {
246
    START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_CHOLESKY_INVERSE);
247
12
    m_J.setIdentity(nVars, nVars);
248
#ifdef OPTIMIZE_HESSIAN_INVERSE
249

12
    chol_.matrixU().solveInPlace(m_J);
250
#else
251
    m_J = chol_.matrixU().solve(m_J);
252
#endif
253
    STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_CHOLESKY_INVERSE);
254
  }
255
256
12
  c2 = m_J.trace();
257
#ifdef EIQGUADPROG_TRACE_SOLVER
258
  utils::print_matrix("m_J", m_J);
259
#endif
260
261
  /* c1 * c2 is an estimate for cond(Hess) */
262
263
  /*
264
   * Find the unconstrained minimizer of the quadratic
265
   * form 0.5 * x Hess x + g0 x
266
   * this is a feasible point in the dual space
267
   * x = Hess^-1 * g0
268
   */
269
  START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_1_UNCONSTR_MINIM);
270
12
  if (is_inverse_provided_) {
271
    x = m_J * (m_J.transpose() * g0);
272
  } else {
273
#ifdef OPTIMIZE_UNCONSTR_MINIM
274

12
    x = -g0;
275
12
    chol_.solveInPlace(x);
276
  }
277
#else
278
    x = chol_.solve(g0);
279
  }
280
  x = -x;
281
#endif
282
  /* and compute the current solution value */
283
12
  f_value = 0.5 * g0.dot(x);
284
#ifdef EIQGUADPROG_TRACE_SOLVER
285
  std::cerr << "Unconstrained solution: " << f_value << std::endl;
286
  utils::print_vector("x", x);
287
#endif
288
  STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_1_UNCONSTR_MINIM);
289
290
  /* Add equality constraints to the working set A */
291
292
  START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_ADD_EQ_CONSTR);
293
12
  iq = 0;
294
16
  for (i = 0; i < nEqCon; i++) {
295
    START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_ADD_EQ_CONSTR_1);
296

5
    np = CE.row(i);
297
5
    compute_d(d, m_J, np);
298
5
    update_z(z, m_J, d, iq);
299
5
    update_r(R, r, d, iq);
300
301
#ifdef EIQGUADPROG_TRACE_SOLVER
302
    utils::print_matrix("R", R);
303
    utils::print_vector("z", z);
304
    utils::print_vector("r", r);
305
    utils::print_vector("d", d);
306
#endif
307
308
    /* compute full step length t2: i.e.,
309
       the minimum step in primal space s.t. the contraint
310
       becomes feasible */
311
5
    t2 = 0.0;
312

5
    if (std::abs(z.dot(z)) > std::numeric_limits<double>::epsilon())
313
      // i.e. z != 0
314

4
      t2 = (-np.dot(x) - ce0(i)) / z.dot(np);
315
316

5
    x += t2 * z;
317
318
    /* set u = u+ */
319
5
    u(iq) = t2;
320


5
    u.head(iq) -= t2 * r.head(iq);
321
322
    /* compute the new solution value */
323
5
    f_value += 0.5 * (t2 * t2) * z.dot(np);
324
5
    A(i) = static_cast<VectorXi::Scalar>(-i - 1);
325
    STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_ADD_EQ_CONSTR_1);
326
327
    START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_ADD_EQ_CONSTR_2);
328

5
    if (!add_constraint(R, m_J, d, iq, R_norm)) {
329
      // Equality constraints are linearly dependent
330
1
      return EIQUADPROG_FAST_REDUNDANT_EQUALITIES;
331
    }
332
    STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_ADD_EQ_CONSTR_2);
333
  }
334
  STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_ADD_EQ_CONSTR);
335
336
  /* set iai = K \ A */
337

22
  for (i = 0; i < nIneqCon; i++) iai(i) = static_cast<VectorXi::Scalar>(i);
338
339
#ifdef USE_WARM_START
340
  //      DEBUG_STREAM("Gonna warm start using previous active
341
  // set:\n"<<A.transpose()<<"\n")
342
  for (i = nEqCon; i < q; i++) {
343
    iai(i - nEqCon) = -1;
344
    ip = A(i);
345
    np = CI.row(ip);
346
    compute_d(d, m_J, np);
347
    update_z(z, m_J, d, iq);
348
    update_r(R, r, d, iq);
349
350
    /* compute full step length t2: i.e.,
351
       the minimum step in primal space s.t. the contraint
352
       becomes feasible */
353
    t2 = 0.0;
354
    if (std::abs(z.dot(z)) >
355
        std::numeric_limits<double>::epsilon())  // i.e. z != 0
356
      t2 = (-np.dot(x) - ci0(ip)) / z.dot(np);
357
    else
358
      DEBUG_STREAM("[WARM START] z=0\n")
359
360
    x += t2 * z;
361
362
    /* set u = u+ */
363
    u(iq) = t2;
364
    u.head(iq) -= t2 * r.head(iq);
365
366
    /* compute the new solution value */
367
    f_value += 0.5 * (t2 * t2) * z.dot(np);
368
369
    if (!add_constraint(R, m_J, d, iq, R_norm)) {
370
      // constraints are linearly dependent
371
      std::cerr << "[WARM START] Constraints are linearly dependent\n";
372
      return RT_EIQUADPROG_REDUNDANT_EQUALITIES;
373
    }
374
  }
375
#else
376
377
#endif
378
379
11
l1:
380
16
  iter++;
381
16
  if (iter >= m_maxIter) {
382
    q = iq;
383
    return EIQUADPROG_FAST_MAX_ITER_REACHED;
384
  }
385
386
  START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_1);
387
388
#ifdef EIQGUADPROG_TRACE_SOLVER
389
  utils::print_vector("x", x);
390
#endif
391
  /* step 1: choose a violated constraint */
392
22
  for (i = nEqCon; i < iq; i++) {
393
6
    ip = A(i);
394
6
    iai(ip) = -1;
395
  }
396
397
  /* compute s(x) = ci^T * x + ci0 for all elements of K \ A */
398
  START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_1_2);
399
16
  ss = 0.0;
400
16
  ip = 0; /* ip will be the index of the chosen violated constraint */
401
402
#ifdef OPTIMIZE_STEP_1_2
403
16
  s = ci0;
404

16
  s.noalias() += CI * x;
405
16
  iaexcl.setOnes();
406

16
  psi = (s.cwiseMin(VectorXd::Zero(nIneqCon))).sum();
407
#else
408
  psi = 0.0; /* this value will contain the sum of all infeasibilities */
409
  for (i = 0; i < nIneqCon; i++) {
410
    iaexcl(i) = 1;
411
    s(i) = CI.row(i).dot(x) + ci0(i);
412
    psi += std::min(0.0, s(i));
413
  }
414
#endif
415
  STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_1_2);
416
#ifdef EIQGUADPROG_TRACE_SOLVER
417
  utils::print_vector("s", s);
418
#endif
419
420
  STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_1);
421
422
16
  if (std::abs(psi) <= static_cast<double>(nIneqCon) *
423
16
                           std::numeric_limits<double>::epsilon() * c1 * c2 *
424
                           100.0) {
425
    /* numerically there are not infeasibilities anymore */
426
9
    q = iq;
427
    //        DEBUG_STREAM("Optimal active
428
    // set:\n"<<A.head(iq).transpose()<<"\n\n")
429
9
    return EIQUADPROG_FAST_OPTIMAL;
430
  }
431
432
  /* save old values for u, x and A */
433

7
  u_old.head(iq) = u.head(iq);
434

7
  A_old.head(iq) = A.head(iq);
435
7
  x_old = x;
436
437
7
l2: /* Step 2: check for feasibility and determine a new S-pair */
438
  START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2);
439
  // find constraint with highest violation
440
  // (what about normalizing constraints?)
441
20
  for (i = 0; i < nIneqCon; i++) {
442



13
    if (s(i) < ss && iai(i) != -1 && iaexcl(i)) {
443
7
      ss = s(i);
444
7
      ip = i;
445
    }
446
  }
447
7
  if (ss >= 0.0) {
448
    q = iq;
449
    //        DEBUG_STREAM("Optimal active set:\n"<<A.transpose()<<"\n\n")
450
    return EIQUADPROG_FAST_OPTIMAL;
451
  }
452
453
  /* set np = n(ip) */
454

7
  np = CI.row(ip);
455
  /* set u = (u 0)^T */
456
7
  u(iq) = 0.0;
457
  /* add ip to the active set A */
458
7
  A(iq) = static_cast<VectorXi::Scalar>(ip);
459
460
  //      DEBUG_STREAM("Add constraint "<<ip<<" to active set\n")
461
462
#ifdef EIQGUADPROG_TRACE_SOLVER
463
  std::cerr << "Trying with constraint " << ip << std::endl;
464
  utils::print_vector("np", np);
465
#endif
466
  STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2);
467
468
7
l2a: /* Step 2a: determine step direction */
469
  START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2A);
470
  /* compute z = H np: the step direction in the primal space
471
     (through m_J, see the paper) */
472
7
  compute_d(d, m_J, np);
473
  //    update_z(z, m_J, d, iq);
474
7
  if (iq >= nVars) {
475
    //      throw std::runtime_error("iq >= m_J.cols()");
476
1
    z.setZero();
477
  } else {
478
6
    update_z(z, m_J, d, iq);
479
  }
480
  /* compute N* np (if q > 0): the negative of the
481
     step direction in the dual space */
482
7
  update_r(R, r, d, iq);
483
#ifdef EIQGUADPROG_TRACE_SOLVER
484
  std::cerr << "Step direction z" << std::endl;
485
  utils::print_vector("z", z);
486
  utils::print_vector("r", r);
487
  utils::print_vector("u", u);
488
  utils::print_vector("d", d);
489
  utils::print_vector("A", A);
490
#endif
491
  STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2A);
492
493
  /* Step 2b: compute step length */
494
  START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2B);
495
7
  l = 0;
496
  /* Compute t1: partial step length (maximum step in dual
497
     space without violating dual feasibility */
498
7
  t1 = inf; /* +inf */
499
  /* find the index l s.t. it reaches the minimum of u+(x) / r */
500
  // l: index of constraint to drop (maybe)
501
10
  for (k = nEqCon; k < iq; k++) {
502
    double tmp;
503



3
    if (r(k) > 0.0 && ((tmp = u(k) / r(k)) < t1)) {
504
      t1 = tmp;
505
      l = A(k);
506
    }
507
  }
508
  /* Compute t2: full step length (minimum step in primal
509
     space such that the constraint ip becomes feasible */
510

7
  if (std::abs(z.dot(z)) > std::numeric_limits<double>::epsilon())
511
    // i.e. z != 0
512

5
    t2 = -s(ip) / z.dot(np);
513
  else
514
2
    t2 = inf; /* +inf */
515
516
  /* the step is chosen as the minimum of t1 and t2 */
517
7
  t = std::min(t1, t2);
518
#ifdef EIQGUADPROG_TRACE_SOLVER
519
  std::cerr << "Step sizes: " << t << " (t1 = " << t1 << ", t2 = " << t2
520
            << ") ";
521
#endif
522
  STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2B);
523
524
  /* Step 2c: determine new S-pair and take step: */
525
  START_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2C);
526
  /* case (i): no step in primal or dual space */
527
7
  if (t >= inf) {
528
    /* QPP is infeasible */
529
2
    q = iq;
530
    STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2C);
531
2
    return EIQUADPROG_FAST_UNBOUNDED;
532
  }
533
  /* case (ii): step in dual space */
534
5
  if (t2 >= inf) {
535
    /* set u = u +  t * [-r 1) and drop constraint l from the active set A */
536
    u.head(iq) -= t * r.head(iq);
537
    u(iq) += t;
538
    iai(l) = static_cast<VectorXi::Scalar>(l);
539
    delete_constraint(R, m_J, A, u, nEqCon, iq, l);
540
#ifdef EIQGUADPROG_TRACE_SOLVER
541
    std::cerr << " in dual space: " << f_value << std::endl;
542
    utils::print_vector("x", x);
543
    utils::print_vector("z", z);
544
    utils::print_vector("A", A);
545
#endif
546
    STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2C);
547
    goto l2a;
548
  }
549
550
  /* case (iii): step in primal and dual space */
551

5
  x += t * z;
552
  /* update the solution value */
553

5
  f_value += t * z.dot(np) * (0.5 * t + u(iq));
554
555


5
  u.head(iq) -= t * r.head(iq);
556
5
  u(iq) += t;
557
558
#ifdef EIQGUADPROG_TRACE_SOLVER
559
  std::cerr << " in both spaces: " << f_value << std::endl;
560
  utils::print_vector("x", x);
561
  utils::print_vector("u", u);
562
  utils::print_vector("r", r);
563
  utils::print_vector("A", A);
564
#endif
565
566
5
  if (t == t2) {
567
#ifdef EIQGUADPROG_TRACE_SOLVER
568
    std::cerr << "Full step has taken " << t << std::endl;
569
    utils::print_vector("x", x);
570
#endif
571
    /* full step has taken */
572
    /* add constraint ip to the active set*/
573

5
    if (!add_constraint(R, m_J, d, iq, R_norm)) {
574
      iaexcl(ip) = 0;
575
      delete_constraint(R, m_J, A, u, nEqCon, iq, ip);
576
#ifdef EIQGUADPROG_TRACE_SOLVER
577
      utils::print_matrix("R", R);
578
      utils::print_vector("A", A);
579
#endif
580
      for (i = 0; i < nIneqCon; i++) iai(i) = static_cast<VectorXi::Scalar>(i);
581
      for (i = 0; i < iq; i++) {
582
        A(i) = A_old(i);
583
        iai(A(i)) = -1;
584
        u(i) = u_old(i);
585
      }
586
      x = x_old;
587
      STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2C);
588
      goto l2; /* go to step 2 */
589
    } else
590
5
      iai(ip) = -1;
591
#ifdef EIQGUADPROG_TRACE_SOLVER
592
    utils::print_matrix("R", R);
593
    utils::print_vector("A", A);
594
#endif
595
    STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2C);
596
5
    goto l1;
597
  }
598
599
  /* a partial step has been taken => drop constraint l */
600
  iai(l) = static_cast<VectorXi::Scalar>(l);
601
  delete_constraint(R, m_J, A, u, nEqCon, iq, l);
602
  s(ip) = CI.row(ip).dot(x) + ci0(ip);
603
604
#ifdef EIQGUADPROG_TRACE_SOLVER
605
  std::cerr << "Partial step has taken " << t << std::endl;
606
  utils::print_vector("x", x);
607
  utils::print_matrix("R", R);
608
  utils::print_vector("A", A);
609
  utils::print_vector("s", s);
610
#endif
611
  STOP_PROFILER_EIQUADPROG_FAST(EIQUADPROG_FAST_STEP_2C);
612
613
  goto l2a;
614
}
615
616
} /* namespace solvers */
617
} /* namespace eiquadprog */