| Directory: | ./ |
|---|---|
| File: | src/eiquadprog.cpp |
| Date: | 2024-12-04 10:05:36 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 134 | 207 | 64.7% |
| Branches: | 134 | 324 | 41.4% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include <eiquadprog/eiquadprog.hpp> | ||
| 2 | namespace eiquadprog { | ||
| 3 | namespace solvers { | ||
| 4 | |||
| 5 | using namespace Eigen; | ||
| 6 | |||
| 7 | /* solve_quadprog is used for on-demand QP solving */ | ||
| 8 | |||
| 9 | 10 | double solve_quadprog(MatrixXd &G, VectorXd &g0, const MatrixXd &CE, | |
| 10 | const VectorXd &ce0, const MatrixXd &CI, | ||
| 11 | const VectorXd &ci0, VectorXd &x, VectorXi &activeSet, | ||
| 12 | size_t &activeSetSize) { | ||
| 13 | 10 | Eigen::DenseIndex p = CE.cols(); | |
| 14 | 10 | Eigen::DenseIndex m = CI.cols(); | |
| 15 | |||
| 16 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | VectorXd y(p + m); |
| 17 | |||
| 18 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | return solve_quadprog(G, g0, CE, ce0, CI, ci0, x, y, activeSet, |
| 19 | 20 | activeSetSize); | |
| 20 | 10 | } | |
| 21 | |||
| 22 | 10 | double solve_quadprog(MatrixXd &G, VectorXd &g0, const MatrixXd &CE, | |
| 23 | const VectorXd &ce0, const MatrixXd &CI, | ||
| 24 | const VectorXd &ci0, VectorXd &x, VectorXd &y, | ||
| 25 | VectorXi &activeSet, size_t &activeSetSize) { | ||
| 26 |
1/2✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | LLT<MatrixXd, Lower> chol(G.cols()); |
| 27 | double c1; | ||
| 28 | /* compute the trace of the original matrix G */ | ||
| 29 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | c1 = G.trace(); |
| 30 | |||
| 31 | /* decompose the matrix G in the form LL^T */ | ||
| 32 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | chol.compute(G); |
| 33 | |||
| 34 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | return solve_quadprog(chol, c1, g0, CE, ce0, CI, ci0, x, y, activeSet, |
| 35 | 20 | activeSetSize); | |
| 36 | 10 | } | |
| 37 | |||
| 38 | ✗ | double solve_quadprog(LLT<MatrixXd, Lower> &chol, double c1, VectorXd &g0, | |
| 39 | const MatrixXd &CE, const VectorXd &ce0, | ||
| 40 | const MatrixXd &CI, const VectorXd &ci0, VectorXd &x, | ||
| 41 | VectorXi &activeSet, size_t &activeSetSize) { | ||
| 42 | ✗ | Eigen::DenseIndex p = CE.cols(); | |
| 43 | ✗ | Eigen::DenseIndex m = CI.cols(); | |
| 44 | |||
| 45 | ✗ | VectorXd y(p + m); | |
| 46 | |||
| 47 | ✗ | return solve_quadprog(chol, c1, g0, CE, ce0, CI, ci0, x, y, activeSet, | |
| 48 | ✗ | activeSetSize); | |
| 49 | } | ||
| 50 | |||
| 51 | /* solve_quadprog2 is used for when the Cholesky decomposition of G is | ||
| 52 | * pre-computed | ||
| 53 | * @param A Output vector containing the indexes of the active constraints. | ||
| 54 | * @param q Output value representing the size of the active set. | ||
| 55 | */ | ||
| 56 | 10 | double solve_quadprog(LLT<MatrixXd, Lower> &chol, double c1, VectorXd &g0, | |
| 57 | const MatrixXd &CE, const VectorXd &ce0, | ||
| 58 | const MatrixXd &CI, const VectorXd &ci0, VectorXd &x, | ||
| 59 | VectorXd &u, VectorXi &A, size_t &q) { | ||
| 60 | size_t i, k, l; /* indices */ | ||
| 61 | size_t ip, me, mi; | ||
| 62 | 10 | size_t n = g0.size(); | |
| 63 | 10 | size_t p = CE.cols(); | |
| 64 | 10 | size_t m = CI.cols(); | |
| 65 |
2/4✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✓ Branch 8 taken 10 times.
✗ Branch 9 not taken.
|
10 | MatrixXd R(g0.size(), g0.size()), J(g0.size(), g0.size()); |
| 66 | |||
| 67 |
5/10✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 10 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 10 times.
✗ Branch 14 not taken.
|
10 | VectorXd s(m + p), z(n), r(m + p), d(n), np(n); |
| 68 |
2/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
10 | VectorXd x_old(n), u_old(m + p); |
| 69 | double f_value, psi, c2, sum, ss, R_norm; | ||
| 70 | 10 | const double inf = std::numeric_limits<double>::infinity(); | |
| 71 | double t, t1, t2; /* t is the step length, which is the minimum of the partial | ||
| 72 | * step length t1 and the full step length t2 */ | ||
| 73 | // VectorXi A(m + p); // Del Prete: active set is now an output | ||
| 74 | // parameter | ||
| 75 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
10 | if (static_cast<size_t>(A.size()) != m + p) A.resize(m + p); |
| 76 |
3/6✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 10 times.
✗ Branch 8 not taken.
|
10 | VectorXi A_old(m + p), iai(m + p), iaexcl(m + p); |
| 77 | // int q; | ||
| 78 | 10 | size_t iq, iter = 0; | |
| 79 | |||
| 80 | 10 | me = p; /* number of equality constraints */ | |
| 81 | 10 | mi = m; /* number of inequality constraints */ | |
| 82 | 10 | q = 0; /* size of the active set A (containing the indices of the active | |
| 83 | constraints) */ | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Preprocessing phase | ||
| 87 | */ | ||
| 88 | |||
| 89 | /* initialize the matrix R */ | ||
| 90 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | d.setZero(); |
| 91 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | R.setZero(); |
| 92 | 10 | R_norm = 1.0; /* this variable will hold the norm of the matrix R */ | |
| 93 | |||
| 94 | /* compute the inverse of the factorized matrix G^-1, this is the initial | ||
| 95 | * value for H */ | ||
| 96 | // J = L^-T | ||
| 97 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | J.setIdentity(); |
| 98 |
2/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
10 | chol.matrixU().solveInPlace(J); |
| 99 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | c2 = J.trace(); |
| 100 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 101 | utils::print_matrix("J", J); | ||
| 102 | #endif | ||
| 103 | |||
| 104 | /* c1 * c2 is an estimate for cond(G) */ | ||
| 105 | |||
| 106 | /* | ||
| 107 | * Find the unconstrained minimizer of the quadratic form 0.5 * x G x + g0 x | ||
| 108 | * this is a feasible point in the dual space | ||
| 109 | * x = G^-1 * g0 | ||
| 110 | */ | ||
| 111 |
2/4✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
|
10 | x = -g0; |
| 112 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | chol.solveInPlace(x); |
| 113 | /* and compute the current solution value */ | ||
| 114 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | f_value = 0.5 * g0.dot(x); |
| 115 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 116 | std::cerr << "Unconstrained solution: " << f_value << std::endl; | ||
| 117 | utils::print_vector("x", x); | ||
| 118 | #endif | ||
| 119 | |||
| 120 | /* Add equality constraints to the working set A */ | ||
| 121 | 10 | iq = 0; | |
| 122 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 9 times.
|
14 | for (i = 0; i < me; i++) { |
| 123 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | np = CE.col(i); |
| 124 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | compute_d(d, J, np); |
| 125 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | update_z(z, J, d, iq); |
| 126 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | update_r(R, r, d, iq); |
| 127 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 128 | utils::print_matrix("R", R); | ||
| 129 | utils::print_vector("z", z); | ||
| 130 | utils::print_vector("r", r); | ||
| 131 | utils::print_vector("d", d); | ||
| 132 | #endif | ||
| 133 | |||
| 134 | /* compute full step length t2: i.e., the minimum step in primal space s.t. | ||
| 135 | the contraint becomes feasible */ | ||
| 136 | 5 | t2 = 0.0; | |
| 137 |
3/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
|
10 | if (std::abs(z.dot(z)) > |
| 138 | 5 | std::numeric_limits<double>::epsilon()) // i.e. z != 0 | |
| 139 |
3/6✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
|
4 | t2 = (-np.dot(x) - ce0(i)) / z.dot(np); |
| 140 | |||
| 141 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | x += t2 * z; |
| 142 | |||
| 143 | /* set u = u+ */ | ||
| 144 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | u(iq) = t2; |
| 145 |
4/8✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
|
5 | u.head(iq) -= t2 * r.head(iq); |
| 146 | |||
| 147 | /* compute the new solution value */ | ||
| 148 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | f_value += 0.5 * (t2 * t2) * z.dot(np); |
| 149 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | A(i) = static_cast<VectorXi::Scalar>(-i - 1); |
| 150 | |||
| 151 |
3/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 4 times.
|
5 | if (!add_constraint(R, J, d, iq, R_norm)) { |
| 152 | // FIXME: it should raise an error | ||
| 153 | // Equality constraints are linearly dependent | ||
| 154 | 1 | return f_value; | |
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | /* set iai = K \ A */ | ||
| 159 |
3/4✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 9 times.
|
20 | for (i = 0; i < mi; i++) iai(i) = static_cast<VectorXi::Scalar>(i); |
| 160 | |||
| 161 | 9 | l1: | |
| 162 | 14 | iter++; | |
| 163 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 164 | utils::print_vector("x", x); | ||
| 165 | #endif | ||
| 166 | /* step 1: choose a violated constraint */ | ||
| 167 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 14 times.
|
20 | for (i = me; i < iq; i++) { |
| 168 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | ip = A(i); |
| 169 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | iai(ip) = -1; |
| 170 | } | ||
| 171 | |||
| 172 | /* compute s(x) = ci^T * x + ci0 for all elements of K \ A */ | ||
| 173 | 14 | ss = 0.0; | |
| 174 | 14 | psi = 0.0; /* this value will contain the sum of all infeasibilities */ | |
| 175 | 14 | ip = 0; /* ip will be the index of the chosen violated constraint */ | |
| 176 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 14 times.
|
34 | for (i = 0; i < mi; i++) { |
| 177 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | iaexcl(i) = 1; |
| 178 |
3/6✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20 times.
✗ Branch 8 not taken.
|
20 | sum = CI.col(i).dot(x) + ci0(i); |
| 179 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | s(i) = sum; |
| 180 | 20 | psi += std::min(0.0, sum); | |
| 181 | } | ||
| 182 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 183 | utils::print_vector("s", s); | ||
| 184 | #endif | ||
| 185 | |||
| 186 | 14 | if (std::abs(psi) <= static_cast<double>(mi) * | |
| 187 |
2/2✓ Branch 1 taken 7 times.
✓ Branch 2 taken 7 times.
|
14 | std::numeric_limits<double>::epsilon() * c1 * c2 * |
| 188 | 100.0) { | ||
| 189 | /* numerically there are not infeasibilities anymore */ | ||
| 190 | 7 | q = iq; | |
| 191 | 7 | return f_value; | |
| 192 | } | ||
| 193 | |||
| 194 | /* save old values for u, x and A */ | ||
| 195 |
3/6✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
|
7 | u_old.head(iq) = u.head(iq); |
| 196 |
3/6✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
|
7 | A_old.head(iq) = A.head(iq); |
| 197 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | x_old = x; |
| 198 | |||
| 199 | 7 | l2: /* Step 2: check for feasibility and determine a new S-pair */ | |
| 200 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
|
20 | for (i = 0; i < mi; i++) { |
| 201 |
9/14✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 6 times.
✓ Branch 6 taken 7 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 7 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 7 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 7 times.
✓ Branch 16 taken 6 times.
|
13 | if (s(i) < ss && iai(i) != -1 && iaexcl(i)) { |
| 202 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | ss = s(i); |
| 203 | 7 | ip = i; | |
| 204 | } | ||
| 205 | } | ||
| 206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (ss >= 0.0) { |
| 207 | ✗ | q = iq; | |
| 208 | ✗ | return f_value; | |
| 209 | } | ||
| 210 | |||
| 211 | /* set np = n(ip) */ | ||
| 212 |
2/4✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
|
7 | np = CI.col(ip); |
| 213 | /* set u = (u 0)^T */ | ||
| 214 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | u(iq) = 0.0; |
| 215 | /* add ip to the active set A */ | ||
| 216 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | A(iq) = static_cast<VectorXi::Scalar>(ip); |
| 217 | |||
| 218 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 219 | std::cerr << "Trying with constraint " << ip << std::endl; | ||
| 220 | utils::print_vector("np", np); | ||
| 221 | #endif | ||
| 222 | |||
| 223 | 7 | l2a: /* Step 2a: determine step direction */ | |
| 224 | /* compute z = H np: the step direction in the primal space (through J, see | ||
| 225 | * the paper) */ | ||
| 226 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | compute_d(d, J, np); |
| 227 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | update_z(z, J, d, iq); |
| 228 | /* compute N* np (if q > 0): the negative of the step direction in the dual | ||
| 229 | * space */ | ||
| 230 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | update_r(R, r, d, iq); |
| 231 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 232 | std::cerr << "Step direction z" << std::endl; | ||
| 233 | utils::print_vector("z", z); | ||
| 234 | utils::print_vector("r", r); | ||
| 235 | utils::print_vector("u", u); | ||
| 236 | utils::print_vector("d", d); | ||
| 237 | utils::print_vector("A", A); | ||
| 238 | #endif | ||
| 239 | |||
| 240 | /* Step 2b: compute step length */ | ||
| 241 | 7 | l = 0; | |
| 242 | /* Compute t1: partial step length (maximum step in dual space without | ||
| 243 | * violating dual feasibility */ | ||
| 244 | 7 | t1 = inf; /* +inf */ | |
| 245 | /* find the index l s.t. it reaches the minimum of u+(x) / r */ | ||
| 246 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7 times.
|
10 | for (k = me; k < iq; k++) { |
| 247 | double tmp; | ||
| 248 |
3/12✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
|
3 | if (r(k) > 0.0 && ((tmp = u(k) / r(k)) < t1)) { |
| 249 | ✗ | t1 = tmp; | |
| 250 | ✗ | l = A(k); | |
| 251 | } | ||
| 252 | } | ||
| 253 | /* Compute t2: full step length (minimum step in primal space such that the | ||
| 254 | * constraint ip becomes feasible */ | ||
| 255 |
3/4✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 2 times.
|
14 | if (std::abs(z.dot(z)) > |
| 256 | 7 | std::numeric_limits<double>::epsilon()) // i.e. z != 0 | |
| 257 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | t2 = -s(ip) / z.dot(np); |
| 258 | else | ||
| 259 | 2 | t2 = inf; /* +inf */ | |
| 260 | |||
| 261 | /* the step is chosen as the minimum of t1 and t2 */ | ||
| 262 | 7 | t = std::min(t1, t2); | |
| 263 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 264 | std::cerr << "Step sizes: " << t << " (t1 = " << t1 << ", t2 = " << t2 | ||
| 265 | << ") "; | ||
| 266 | #endif | ||
| 267 | |||
| 268 | /* Step 2c: determine new S-pair and take step: */ | ||
| 269 | |||
| 270 | /* case (i): no step in primal or dual space */ | ||
| 271 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
|
7 | if (t >= inf) { |
| 272 | /* QPP is infeasible */ | ||
| 273 | // FIXME: unbounded to raise | ||
| 274 | 2 | q = iq; | |
| 275 | 2 | return inf; | |
| 276 | } | ||
| 277 | /* case (ii): step in dual space */ | ||
| 278 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (t2 >= inf) { |
| 279 | /* set u = u + t * [-r 1) and drop constraint l from the active set A */ | ||
| 280 | ✗ | u.head(iq) -= t * r.head(iq); | |
| 281 | ✗ | u(iq) += t; | |
| 282 | ✗ | iai(l) = static_cast<VectorXi::Scalar>(l); | |
| 283 | ✗ | delete_constraint(R, J, A, u, p, iq, l); | |
| 284 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 285 | std::cerr << " in dual space: " << f_value << std::endl; | ||
| 286 | utils::print_vector("x", x); | ||
| 287 | utils::print_vector("z", z); | ||
| 288 | utils::print_vector("A", A); | ||
| 289 | #endif | ||
| 290 | ✗ | goto l2a; | |
| 291 | } | ||
| 292 | |||
| 293 | /* case (iii): step in primal and dual space */ | ||
| 294 | |||
| 295 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | x += t * z; |
| 296 | /* update the solution value */ | ||
| 297 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | f_value += t * z.dot(np) * (0.5 * t + u(iq)); |
| 298 | |||
| 299 |
4/8✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
|
5 | u.head(iq) -= t * r.head(iq); |
| 300 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | u(iq) += t; |
| 301 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 302 | std::cerr << " in both spaces: " << f_value << std::endl; | ||
| 303 | utils::print_vector("x", x); | ||
| 304 | utils::print_vector("u", u); | ||
| 305 | utils::print_vector("r", r); | ||
| 306 | utils::print_vector("A", A); | ||
| 307 | #endif | ||
| 308 | |||
| 309 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (t == t2) { |
| 310 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 311 | std::cerr << "Full step has taken " << t << std::endl; | ||
| 312 | utils::print_vector("x", x); | ||
| 313 | #endif | ||
| 314 | /* full step has taken */ | ||
| 315 | /* add constraint ip to the active set*/ | ||
| 316 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
|
5 | if (!add_constraint(R, J, d, iq, R_norm)) { |
| 317 | ✗ | iaexcl(ip) = 0; | |
| 318 | ✗ | delete_constraint(R, J, A, u, p, iq, ip); | |
| 319 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 320 | utils::print_matrix("R", R); | ||
| 321 | utils::print_vector("A", A); | ||
| 322 | #endif | ||
| 323 | ✗ | for (i = 0; i < m; i++) iai(i) = static_cast<VectorXi::Scalar>(i); | |
| 324 | ✗ | for (i = 0; i < iq; i++) { | |
| 325 | ✗ | A(i) = A_old(i); | |
| 326 | ✗ | iai(A(i)) = -1; | |
| 327 | ✗ | u(i) = u_old(i); | |
| 328 | } | ||
| 329 | ✗ | x = x_old; | |
| 330 | ✗ | goto l2; /* go to step 2 */ | |
| 331 | } else | ||
| 332 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | iai(ip) = -1; |
| 333 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 334 | utils::print_matrix("R", R); | ||
| 335 | utils::print_vector("A", A); | ||
| 336 | #endif | ||
| 337 | 5 | goto l1; | |
| 338 | } | ||
| 339 | |||
| 340 | /* a patial step has taken */ | ||
| 341 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 342 | std::cerr << "Partial step has taken " << t << std::endl; | ||
| 343 | utils::print_vector("x", x); | ||
| 344 | #endif | ||
| 345 | /* drop constraint l */ | ||
| 346 | ✗ | iai(l) = static_cast<VectorXi::Scalar>(l); | |
| 347 | ✗ | delete_constraint(R, J, A, u, p, iq, l); | |
| 348 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 349 | utils::print_matrix("R", R); | ||
| 350 | utils::print_vector("A", A); | ||
| 351 | #endif | ||
| 352 | |||
| 353 | ✗ | s(ip) = CI.col(ip).dot(x) + ci0(ip); | |
| 354 | |||
| 355 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 356 | utils::print_vector("s", s); | ||
| 357 | #endif | ||
| 358 | ✗ | goto l2a; | |
| 359 | 10 | } | |
| 360 | |||
| 361 | 10 | bool add_constraint(MatrixXd &R, MatrixXd &J, VectorXd &d, size_t &iq, | |
| 362 | double &R_norm) { | ||
| 363 | 10 | size_t n = J.rows(); | |
| 364 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 365 | std::cerr << "Add constraint " << iq << '/'; | ||
| 366 | #endif | ||
| 367 | size_t j, k; | ||
| 368 | double cc, ss, h, t1, t2, xny; | ||
| 369 | |||
| 370 | /* we have to find the Givens rotation which will reduce the element | ||
| 371 | d(j) to zero. | ||
| 372 | if it is already zero we don't have to do anything, except of | ||
| 373 | decreasing j */ | ||
| 374 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
|
16 | for (j = n - 1; j >= iq + 1; j--) { |
| 375 | /* The Givens rotation is done with the matrix (cc cs, cs -cc). | ||
| 376 | If cc is one, then element (j) of d is zero compared with element | ||
| 377 | (j - 1). Hence we don't have to do anything. | ||
| 378 | If cc is zero, then we just have to switch column (j) and column (j - 1) | ||
| 379 | of J. Since we only switch columns in J, we have to be careful how we | ||
| 380 | update d depending on the sign of gs. | ||
| 381 | Otherwise we have to apply the Givens rotation to these columns. | ||
| 382 | The i - 1 element of d has to be updated to h. */ | ||
| 383 | 6 | cc = d(j - 1); | |
| 384 | 6 | ss = d(j); | |
| 385 | 6 | h = utils::distance(cc, ss); | |
| 386 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (h == 0.0) continue; |
| 387 | 6 | d(j) = 0.0; | |
| 388 | 6 | ss = ss / h; | |
| 389 | 6 | cc = cc / h; | |
| 390 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (cc < 0.0) { |
| 391 | ✗ | cc = -cc; | |
| 392 | ✗ | ss = -ss; | |
| 393 | ✗ | d(j - 1) = -h; | |
| 394 | } else | ||
| 395 | 6 | d(j - 1) = h; | |
| 396 | 6 | xny = ss / (1.0 + cc); | |
| 397 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
|
18 | for (k = 0; k < n; k++) { |
| 398 | 12 | t1 = J(k, j - 1); | |
| 399 | 12 | t2 = J(k, j); | |
| 400 | 12 | J(k, j - 1) = t1 * cc + t2 * ss; | |
| 401 | 12 | J(k, j) = xny * (t1 + J(k, j - 1)) - t2; | |
| 402 | } | ||
| 403 | } | ||
| 404 | /* update the number of constraints added*/ | ||
| 405 | 10 | iq++; | |
| 406 | /* To update R we have to put the iq components of the d vector | ||
| 407 | into column iq - 1 of R | ||
| 408 | */ | ||
| 409 |
3/6✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 10 times.
✗ Branch 9 not taken.
|
10 | R.col(iq - 1).head(iq) = d.head(iq); |
| 410 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 411 | std::cerr << iq << std::endl; | ||
| 412 | #endif | ||
| 413 | |||
| 414 |
2/2✓ Branch 3 taken 1 times.
✓ Branch 4 taken 9 times.
|
10 | if (std::abs(d(iq - 1)) <= std::numeric_limits<double>::epsilon() * R_norm) |
| 415 | // problem degenerate | ||
| 416 | 1 | return false; | |
| 417 | 9 | R_norm = std::max<double>(R_norm, std::abs(d(iq - 1))); | |
| 418 | 9 | return true; | |
| 419 | } | ||
| 420 | |||
| 421 | ✗ | void delete_constraint(MatrixXd &R, MatrixXd &J, VectorXi &A, VectorXd &u, | |
| 422 | size_t p, size_t &iq, size_t l) { | ||
| 423 | ✗ | size_t n = R.rows(); | |
| 424 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 425 | std::cerr << "Delete constraint " << l << ' ' << iq; | ||
| 426 | #endif | ||
| 427 | ✗ | size_t i, j, k, qq = 0; | |
| 428 | double cc, ss, h, xny, t1, t2; | ||
| 429 | |||
| 430 | /* Find the index qq for active constraint l to be removed */ | ||
| 431 | ✗ | for (i = p; i < iq; i++) | |
| 432 | ✗ | if (static_cast<size_t>(A(i)) == l) { | |
| 433 | ✗ | qq = i; | |
| 434 | ✗ | break; | |
| 435 | } | ||
| 436 | |||
| 437 | /* remove the constraint from the active set and the duals */ | ||
| 438 | ✗ | for (i = qq; i < iq - 1; i++) { | |
| 439 | ✗ | A(i) = A(i + 1); | |
| 440 | ✗ | u(i) = u(i + 1); | |
| 441 | ✗ | R.col(i) = R.col(i + 1); | |
| 442 | } | ||
| 443 | |||
| 444 | ✗ | A(iq - 1) = A(iq); | |
| 445 | ✗ | u(iq - 1) = u(iq); | |
| 446 | ✗ | A(iq) = 0; | |
| 447 | ✗ | u(iq) = 0.0; | |
| 448 | ✗ | for (j = 0; j < iq; j++) R(j, iq - 1) = 0.0; | |
| 449 | /* constraint has been fully removed */ | ||
| 450 | ✗ | iq--; | |
| 451 | #ifdef EIQGUADPROG_TRACE_SOLVER | ||
| 452 | std::cerr << '/' << iq << std::endl; | ||
| 453 | #endif | ||
| 454 | |||
| 455 | ✗ | if (iq == 0) return; | |
| 456 | |||
| 457 | ✗ | for (j = qq; j < iq; j++) { | |
| 458 | ✗ | cc = R(j, j); | |
| 459 | ✗ | ss = R(j + 1, j); | |
| 460 | ✗ | h = utils::distance(cc, ss); | |
| 461 | ✗ | if (h == 0.0) continue; | |
| 462 | ✗ | cc = cc / h; | |
| 463 | ✗ | ss = ss / h; | |
| 464 | ✗ | R(j + 1, j) = 0.0; | |
| 465 | ✗ | if (cc < 0.0) { | |
| 466 | ✗ | R(j, j) = -h; | |
| 467 | ✗ | cc = -cc; | |
| 468 | ✗ | ss = -ss; | |
| 469 | } else | ||
| 470 | ✗ | R(j, j) = h; | |
| 471 | |||
| 472 | ✗ | xny = ss / (1.0 + cc); | |
| 473 | ✗ | for (k = j + 1; k < iq; k++) { | |
| 474 | ✗ | t1 = R(j, k); | |
| 475 | ✗ | t2 = R(j + 1, k); | |
| 476 | ✗ | R(j, k) = t1 * cc + t2 * ss; | |
| 477 | ✗ | R(j + 1, k) = xny * (t1 + R(j, k)) - t2; | |
| 478 | } | ||
| 479 | ✗ | for (k = 0; k < n; k++) { | |
| 480 | ✗ | t1 = J(k, j); | |
| 481 | ✗ | t2 = J(k, j + 1); | |
| 482 | ✗ | J(k, j) = t1 * cc + t2 * ss; | |
| 483 | ✗ | J(k, j + 1) = xny * (J(k, j) + t1) - t2; | |
| 484 | } | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | } // namespace solvers | ||
| 489 | } // namespace eiquadprog | ||
| 490 |