Directory: | ./ |
---|---|
File: | src/eiquadprog.cpp |
Date: | 2024-08-26 22:54:11 |
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 |