EigenOpt 1.0.0
Loading...
Searching...
No Matches
quadratic_programming.hxx
Go to the documentation of this file.
1#pragma once
2
6
7
8namespace EigenOpt {
9
10namespace quadratic_programming {
11
12
13template<class Scalar>
14Solver<Scalar>::Solver(int xdim, int rdim, const Scalar& tolerance)
15: nx(xdim)
16, ny(xdim)
17, nr(rdim)
18, mi(0)
19, me(0)
20, tol(tolerance)
21{
22 EigenOpt_QUADPROG_DBG("Calling constructor with sizes " << xdim << " and " << rdim);
23 eigen_assert(nx>0 && "AT LEAST ONE DECISION VARIABLE IS REQUIRED");
24 eigen_assert(nr>0 && "AT LEAST ONE OBJECTIVE ROW IS REQUIRED");
25 Qy = Q = MatrixXs::Zero(nr, nx);
26 ry = r = VectorXs::Zero(nr);
27 Cy = MatrixXs::Zero(0, nx);
28 dy = VectorXs::Zero(0);
29 Z = MatrixXs::Identity(nx, nx);
30 yk = yu = xeq = VectorXs::Zero(nx);
32}
33
34
35template<class Scalar>
36template<class D1, class D2>
38 const Eigen::EigenBase<D1>& Q,
39 const Eigen::EigenBase<D2>& r,
40 const Scalar& tolerance
41)
42: Solver<Scalar>(Q.cols(), Q.rows(), tolerance)
43{
44 EigenOpt_QUADPROG_DBG("Calling constructor with Q and r");
46}
47
48
49template<class Scalar>
50template<class D1, class D2>
52 const Eigen::EigenBase<D1>& Q,
53 const Eigen::EigenBase<D2>& r
54)
55{
56 EigenOpt_QUADPROG_DBG("Updating objective");
57 eigen_assert(Q.rows()==nr && "Q MATRIX HAS WRONG NUMBER OF ROWS");
58 eigen_assert(Q.cols()==nx && "Q MATRIX HAS WRONG NUMBER OF COLUMNS");
59 eigen_assert(r.rows()==nr && "R VECTOR HAS WRONG NUMBER OF ROWS");
60 this->Q = Q;
61 this->r = r;
62 EigenOpt_QUADPROG_DBG("Q=" << std::endl << this->Q << std::endl << "and vector r=" << std::endl << this->r);
63
64 // If equality constraints have been set, reduce the problem.
65 if(me > 0) {
66 if(ny > 0) {
67 Qy = this->Q * Z;
68 ry = this->r - this->Q * xeq;
69 }
70 else {
71 Qy = MatrixXs::Zero(nr, 0);
72 ry = VectorXs::Zero(nr);
73 }
74 }
75 else {
76 Qy = Q;
77 ry = r;
78 }
79
80 EigenOpt_QUADPROG_DBG("Qy=" << std::endl << Qy << std::endl << "ry=" << std::endl << ry);
81
82 if(ny > 0) {
83 #ifdef USE_QR_INSTEAD_OF_SVD
84 yu = Qy.fullPivHouseholderQr().solve(ry);
85 #else
86 // yu = Qy.bdcSvd(Eigen::ComputeThinU|Eigen::ComputeThinV).solve(ry);
87 yu = Qy.jacobiSvd(Eigen::ComputeThinU|Eigen::ComputeThinV).solve(ry);
88 #endif
89 }
90 else {
91 yu = VectorXs::Zero(0);
92 }
93 EigenOpt_QUADPROG_DBG("Unconstrained minimum:" << std::endl << "y: " << yu.transpose() << std::endl << "x: " << (xeq+Z*yu).transpose());
94}
95
96
97template<class Scalar>
99{
100 EigenOpt_QUADPROG_DBG("Resetting active set");
101 Ca.resize(0, ny);
102 da.resize(0);
103 active.clear();
104 active.reserve(mi);
105 inactive.resize(mi);
106 for(int i=0; i<mi; i++)
107 inactive[i] = i;
108}
109
110
111template<class Scalar>
113{
114 Z = MatrixXs::Identity(nx, nx);
115 xeq = VectorXs::Zero(nx);
116 Cy = MatrixXs::Zero(0,ny);
117 dy = VectorXs::Zero(0);
118 mi = 0;
119 me = 0;
120 ny = nx;
121 resetActiveSet();
122 updateObjective(Q, r);
123}
124
125
126template<class Scalar>
127template<class D1, class D2>
129 const Eigen::EigenBase<D1>& C,
130 const Eigen::EigenBase<D2>& d
131)
132{
133 return setConstraints(MatrixXs(0, nx), VectorXs(0), C, d);
134}
135
136
137template<class Scalar>
138template<class D1, class D2, class D3, class D4>
140 const Eigen::MatrixBase<D1>& A,
141 const Eigen::MatrixBase<D2>& b,
142 const Eigen::EigenBase<D3>& C,
143 const Eigen::EigenBase<D4>& d
144)
145{
146 EigenOpt_QUADPROG_DBG("Processing equality constraints");
147 eigen_assert(A.cols()==nx && "A MATRIX HAS WRONG NUMBER OF COLUMNS");
148 eigen_assert(A.rows()==b.rows() && "A MATRIX AND b VECTOR HAVE DIFFERENT NUMBER OF ROWS");
149
150 if(A.rows() == 0) {
151 if(me > 0) {
152 EigenOpt_QUADPROG_DBG("Removing pre-existing equality constraints");
153 Z = MatrixXs::Identity(nx, nx);
154 xeq = VectorXs::Zero(nx);
155 me = 0;
156 ny = nx;
157 // Set Qy=Q, ry=r and yu = pinv(Q)*r.
158 updateObjective(Q, r);
159 }
160 }
161 else {
162 EigenOpt_QUADPROG_DBG("Adding equality constraints via kernel projection");
163
164 // Solve the equality constraints right away.
165 #ifdef USE_QR_INSTEAD_OF_SVD
166 EigenOpt_QUADPROG_DBG("Using QR decomposition for kernel projection");
167 qr_projection(A, b, Z, xeq);
168 #else
169 EigenOpt_QUADPROG_DBG("Using SVD for kernel projection");
170 svd_projection(A, b, Z, xeq);
171 #endif
172
173 // Check if the solution is exact.
174 if(!(A*xeq-b).isZero(tol)) {
175 EigenOpt_QUADPROG_DBG("Equality constraints are infeasible");
176 clearConstraints();
177 return false;
178 }
179
180 EigenOpt_QUADPROG_DBG("Projection matrix for equality constraints: Z=" << std::endl << Z);
181
182 // Update information that depends on the equalities.
183 me = A.rows();
184 ny = Z.cols();
185 // Set Qy, ry and calculate yu.
186 updateObjective(Q, r);
187 }
188
189 // Setting mi = 0 forces to reset all data related to the constraints.
190 mi = 0;
191 return updateInequalities(C, d);
192}
193
194
195template<class Scalar>
196template<class D1, class D2>
198 const Eigen::EigenBase<D1>& C,
199 const Eigen::EigenBase<D2>& d
200)
201{
202 EigenOpt_QUADPROG_DBG("Setting inequality constraints");
203 eigen_assert(C.cols()==nx && "C MATRIX HAS WRONG NUMBER OF COLUMNS");
204 eigen_assert(C.rows()==d.rows() && "C MATRIX AND D VECTOR HAVE DIFFERENT NUMBER OF ROWS");
205
206 Cy = C;
207 dy = d;
208 EigenOpt_QUADPROG_DBG("The constraints are C=" << std::endl << Cy << std::endl << "and d=" << std::endl << dy);
209
210 if(me > 0) {
211 if(C.rows() > 0) {
212 if(ny > 0) {
213 // The order matters, since Cy after running the second line is not the
214 // same as Cy during the first line!
215 dy = dy - Cy*xeq;
216 Cy = Cy * Z;
217 }
218 else {
219 Cy = MatrixXs::Zero(C.rows(), 0);
220 dy = VectorXs::Zero(C.rows());
221 }
222 }
223 else {
224 Cy = MatrixXs::Zero(0, ny);
225 dy = VectorXs::Zero(0);
226 }
227 EigenOpt_QUADPROG_DBG("The constraints in y are Cy=" << std::endl << Cy << std::endl << "and dy=" << std::endl << dy);
228 }
229
230 // If constraints have changed dimension, warm start is not an option.
231 if(C.rows() != mi) {
232 if(C.rows() > 0) {
233 // Check if the inequality constraints are feasible using the simplex method.
234 EigenOpt_QUADPROG_DBG("Checking feasibility of inequality constraints");
235 if(ny > 0) {
236 EigenOpt_QUADPROG_DBG("Using simplex to determine feasibility");
237 std::string simplex_error;
238 if(!simplex::minimize(VectorXs::Zero(ny), Cy, dy, yk, simplex_error, tol)) {
239 EigenOpt_QUADPROG_DBG("Simplex failed: " << simplex_error);
240 clearConstraints();
241 return false;
242 }
243 if((Cy*yk-dy).maxCoeff() > tol) {
244 // This should not be happening, but better safe than sorry.
245 EigenOpt_QUADPROG_DBG("Simplex solution is invalid: Cy*yk-dy = " << (Cy*yk-dy).transpose());
246 clearConstraints();
247 return false;
248 }
249 }
250 else {
251 // This is a fully constrained problem: either xeq is a solution for the
252 // original inequalities, or the constraint set as a whole is not
253 // feasible.
254 if((MatrixXs(C)*xeq-VectorXs(d)).maxCoeff() > tol) {
255 EigenOpt_QUADPROG_DBG("Equalities fully constrain the decision vector, but xeq is not feasible for the inequalities: C*xeq-d = " << (MatrixXs(C)*xeq-VectorXs(d)).transpose());
256 clearConstraints();
257 return false;
258 }
259 }
260 }
261
262 // Store the new nuber of inequalities and reset the active set.
263 mi = C.rows();
264 resetActiveSet();
265 }
266
267 return true;
268}
269
270
271template<class Scalar>
272template<class D>
273bool Solver<Scalar>::solve(Eigen::MatrixBase<D>& x) {
274 // If the problem is fully constrained by equalities, there is really nothing
275 // to be done here. Just return the solution to A*X=b.
276 if(ny == 0) {
277 x = xeq;
278 return true;
279 }
280
281 // Try to solve the problem in the Y-space.
282 if(!solveY(x))
283 return false;
284
285 // Project from Y to X, if needed.
286 if(me > 0) {
287 x = Z * VectorXs(x) + xeq;
288 }
289
290 // Success!
291 return true;
292}
293
294
295template<class Scalar>
296template<class D>
297bool Solver<Scalar>::guess(Eigen::MatrixBase<D>& y) {
298 // Check if the active set determines a feasble point.
299 if(Ca.rows() > 0) {
300 // While the active set may have not changed, we still need to ensure that
301 // the matrix Ca and the vector da correspond to the current (probably
302 // changed) values of the constraints.
303 for(unsigned int i=0; i<active.size(); i++) {
304 Ca.row(i) = Cy.row(active[i]);
305 da(i) = dy(active[i]);
306 }
307 #ifdef USE_QR_INSTEAD_OF_SVD
308 VectorXd ya = Ca.fullPivHouseholderQr().solve(da);
309 #else
310 // yk = Ca.bdcSvd(Eigen::ComputeThinU|Eigen::ComputeThinV).solve(da);
311 VectorXs ya = Ca.jacobiSvd(Eigen::ComputeThinU|Eigen::ComputeThinV).solve(da);
312 #endif
313 if((Cy*ya - dy).maxCoeff() <= 0) {
314 yk = ya;
315 EigenOpt_QUADPROG_DBG("Active-set solution (yk=pinv(Ca)*da) is a feasible start");
316 return true;
317 }
318
319 // Tough luck, we need to start all over again.
320 resetActiveSet();
321 }
322
323 // Check if the current point is already feasible
324 if((Cy*yk - dy).maxCoeff() <= 0) {
325 EigenOpt_QUADPROG_DBG("Current value of yk is a feasible start");
326 return initActiveSet();
327 }
328
329 // Check if the user-supplied value is feasible.
330 if(y.rows() == ny && (Cy*y - dy).maxCoeff() <= 0) {
331 EigenOpt_QUADPROG_DBG("User-supplied x is a feasible start");
332 yk = y;
333 return initActiveSet();
334 }
335
336 // Last resort: use the Simplex to find a feasible starting point.
337 EigenOpt_QUADPROG_DBG("Using Simplex to find a feasible start");
338 std::string simplex_error;
339 if(!simplex::minimize(VectorXs::Zero(ny), Cy, dy, yk, simplex_error, tol)) {
340 // Impossible to find a valid point.
341 EigenOpt_QUADPROG_DBG("Simplex failed: " << simplex_error);
342 return false;
343 }
344
345 // Initial point found!
346 return initActiveSet();
347}
348
349
350template<class Scalar>
352 eigen_assert(active.size() == 0 && "IF YOU CALLED initActiveSet(), THE ACTIVE SET SHOULD'VE BEEN EMPTY");
353 // Calulate constraints "violations".
354 VectorXs e = Cy*yk - dy;
355
356 // Both active and inactive will be filled in the next loop.
357 inactive.clear();
358 inactive.reserve(ny);
359
360 // Check which constraints are active at the current solution.
361 for(unsigned int i=0; i<e.rows(); i++) {
362 if(e(i) > tol) {
363 // The constraint has been violated.
364 return false;
365 }
366 else if(e(i) <= -tol) {
367 // Inactive constraint.
368 inactive.push_back(i);
369 }
370 else {
371 // Found an active constraint!
372 active.push_back(i);
373 }
374 }
375
376 // Copy the constraints in the active set.
377 Ca.resize(active.size(), ny);
378 da.resize(active.size());
379 for(unsigned int i=0; i<active.size(); i++) {
380 Ca.row(i) = Cy.row(active[i]);
381 da(i) = dy(active[i]);
382 }
383 return true;
384}
385
386
387template<class Scalar>
388template<class D>
389bool Solver<Scalar>::solveY(Eigen::MatrixBase<D>& y) {
390
391 // if no constraints are given, just perform least squares minimization
392 if(mi == 0) {
393 y = yu;
394 return true;
395 }
396
397 // Make sure yk is initialized, no matter what.
398 if(yk.rows() != ny)
399 EigenOpt_QUADPROG_DBG("Starting optimization");
400 yk = VectorXs::Zero(ny);
401
402 // We need an initial feasible start.
403 if(!guess(y)) {
404 EigenOpt_SIMPLEX_DBG("Failed to determine feasible start for the optimization");
405 return false;
406 }
407 EigenOpt_QUADPROG_DBG("Initial point set to yk = " << yk.transpose());
408
409 // Number of currently active constraints.
410 int na = active.size();
411 EigenOpt_QUADPROG_DBG("Starting with " << na << " active constraints");
412
413#ifdef USE_QR_INSTEAD_OF_SVD
414 // Use QR factorization to find the kernel of a matrix. Given the matrix A,
415 // the QR decomposition allows to write A^T = Q*R with Q orthogonal and R
416 // upper triangular. Note that if the rank of A is r, then the last (mi-r)
417 // columns of Q are a basis of the kernel of A (with mi being the number of
418 // columns in A).
419 // This can also be used to get the solutions of Ca^T * mu = g
420 Eigen::ColPivHouseholderQR<MatrixXs> CaT_qr(nx, na);
421#else
422 // SVD can be used to find the kernel of Ca similarly to what would be done
423 // with a QR factorization.
424 Eigen::JacobiSVD<MatrixXs> Ca_svd(na, nx, Eigen::ComputeFullV);
425 // The following is instead needed to evaluate solutions of Ca^T * mu = g
426 Eigen::JacobiSVD<MatrixXs> CaT_svd(nx, na, Eigen::ComputeThinU|Eigen::ComputeThinV);
427#endif
428 // Step vector (a new iterate is formed as y' = y + alpha*p) and Lagrange
429 // multipliers of the active constraints.
430 VectorXs p, mu;
431 double alpha;
432
433 for(unsigned int iter=0; iter<1e6; iter++) {
434 EigenOpt_QUADPROG_DBG("++++++++++ Beginning iteration ++++++++++");
435 EigenOpt_QUADPROG_DBG("Active set: " << internal::vec2str(active));
436 EigenOpt_QUADPROG_DBG("Inactive set: " << internal::vec2str(inactive));
437
438 if(na > 0) {
439 EigenOpt_QUADPROG_DBG("Perform constrained minimization to find p");
440
441 // solve the EQ.constrained problem
442 // min |Qy*(yk+p)-ry|^2 s.t. Ca*p = 0
443 // which is equal to:
444 // min |Qy*p-(ry-Qy*yk)|^2 s.t. Ca*p = 0
445 // To to that, use a basis W of the kernel of Ca (s.t. Ca*W=0).
446 // In this way, p=W*u is compatible with the constraint.
447 // Furthermore, the problem reduces to
448 // min |Qy*W*u-(ry-Qy*yk)|^2
449 // The solution is thus
450 // p = W * (Qy*W)^+ * (ry-Qy*yk)
451 #ifdef USE_QR_INSTEAD_OF_SVD
452 if(na == ny) {
453 // The kernel is empty, ie, Ca*p=0 iff p=0
454 EigenOpt_QUADPROG_DBG("The kernel of Ca is empty, forcefully selecting p = 0");
455 p = VectorXs::Zero(ny);
456 }
457 else {
458 CaT_qr.compute(Ca.transpose());
459 auto W = MatrixXs(CaT_qr.householderQ()).rightCols(ny-na); // reduced basis of the kernel of Ca, such that Ca*W = 0.
460 p = W * (Qy*W).colPivHouseholderQr().solve(ry-Qy*yk);
461 EigenOpt_QUADPROG_DBG("Computed step p; the constraint equation is s.t. Ca*p = " << (Ca*p).transpose() << " (expecting zeros everywhere)");
462 }
463 #else
464 Ca_svd.compute(Ca); // this will compute the matrix V
465 if(Ca_svd.cols() == Ca_svd.rank()) {
466 EigenOpt_QUADPROG_DBG("The kernel of Ca is empty, forcefully selecting p = 0");
467 // The kernel is empty, ie, Ca*p=0 iff p=0
468 p = VectorXs::Zero(ny);
469 // NOTE: I am almost sure that this step could be avoided...
470 // Meaning that if there are na>=ny active constraints, they should fully
471 // constrain the problem without even needing to check it. However, I
472 // am not sure if this holds ALWAYS: perhaps inserting redundant
473 // constraints makes everything fail...
474 }
475 else {
476 auto W = Ca_svd.matrixV().rightCols(Ca_svd.cols()-Ca_svd.rank()); // reduced basis of the kernel of Ca, such that Ca*W = 0.
477 p = W * (Qy*W).bdcSvd(Eigen::ComputeThinU|Eigen::ComputeThinV).solve(ry-Qy*yk);
478 EigenOpt_QUADPROG_DBG("Computed step p; the constraint equation is s.t. Ca*p = " << (Ca*p).transpose() << " (expecting zeros everywhere)");
479 }
480 #endif
481 }
482 else {
483 EigenOpt_QUADPROG_DBG("Using unconstrained minimum to define p");
484 // No inequality constraints are active: the current solution
485 // would be to step of a value p such that
486 // yk + p = yu
487 // where yu is the unconstrained minimum of the QP problem,
488 // which is computed already in updateObjective.
489 // Thus, the step p is simply:
490 p = yu - yk;
491 }
492
493 // check if p is now zero? This would mean that ny (independent)
494 // constraints are active at the same time... However, this is also a
495 // special case of alpha=1 (or not?)
496 // TODO
497
498 EigenOpt_QUADPROG_DBG("Step direction: " << p.transpose() << "; evaluating step size (alpha)");
499
500 // We have to perform the step p. However, some currently
501 // inactive constraints might be unhappy with that. Thus,
502 // check if the step should be reduced by a factor
503 // 0 <= alpha <= 1.
504 alpha = 1.;
505 int idxact = -1;
506 for(int i=0; i<inactive.size(); i++) {
507 auto& idx = inactive[i];
508 auto ci = Cy.row(idx);
509 double cp = p.dot(ci);
510 if(cp > 0) {
511 double ai = (dy(idx)-yk.dot(ci))/cp;
512 EigenOpt_QUADPROG_DBG("Constraint " << idx << " would be invalidated with alpha > " << ai);
513 if(ai < alpha) {
514 alpha = ai;
515 idxact = i;
516 EigenOpt_QUADPROG_DBG("Constraint " << idx << " is the current candidate constraint");
517 }
518 }
519 }
520
521 if(idxact != -1) {
522 EigenOpt_QUADPROG_DBG("Activating constraint " << inactive[idxact]);
523 // update the current iterate
524 yk.noalias() += alpha*p;
525 // activate the new constraint
526 Ca.conservativeResize(na+1,Cy.cols());
527 Ca.row(na) = Cy.row(inactive[idxact]);
528 da.conservativeResize(na+1);
529 da(na) = dy(inactive[idxact]);
530 // make sure to updated auxiliary structures as well
531 na++;
532 active.push_back(inactive[idxact]);
533 inactive.erase(inactive.begin()+idxact);
534 }
535 else {
536 // check the iterate (note that we can perform a "full" step)
537 yk.noalias() += p;
538
539 if(na == 0) {
540 EigenOpt_QUADPROG_DBG("No constraints are active, and alpha is 1: found global minimum");
541 // we are able to perform the full step and no constraints
542 // were active: this should be the unconstrained minimum
543 y = yk;
544 return true;
545 }
546
547 // Check if any constraint has to be deactivated.
548 // For this, find the most negative Lagrange multiplier (if any).
549 #ifdef USE_QR_INSTEAD_OF_SVD
550 CaT_qr.compute(Ca.transpose());
551 VectorXs half_mu = CaT_qr.solve(Qy.transpose() * (ry-Qy*yk));
552 #else
553 CaT_svd.compute(Ca.transpose());
554 VectorXs half_mu = CaT_svd.solve(Qy.transpose() * (ry-Qy*yk));
555 #endif
556 EigenOpt_QUADPROG_DBG("Lagrange multipliers: " << 2*half_mu.transpose());
557 int idx = -1;
558 double mumin = -tol;
559 for(unsigned i=0; i<na; i++) {
560 if(half_mu(i) < mumin) {
561 mumin = half_mu(i);
562 idx = i;
563 }
564 }
565
566 if(idx != -1) {
567 EigenOpt_QUADPROG_DBG("Deactivating " << active[idx] << " (Ca's row " << idx << ")");
568 // deactivate one constraint
569 // NOTE: the two block operations might lead to aliasing (behavior is
570 // actually undefined in this sense). For this reason, for the moment
571 // I am using the (rather inefficient) solution below, which exploits
572 // the eval() method.
573 int nc = na-idx-1; // how many constraints come after the one to be deactivated
574 if(nc > 0) {
575 // shift up by one row the constraints that come after the one to be removed
576 Ca.block(idx,0,nc,Ca.cols()) = Ca.bottomRows(nc).eval();
577 da.segment(idx,nc) = da.tail(nc).eval();
578 }
579 // reduce the actual size for the constraints (thus removing the last
580 // row, which is not used anymore)
581 na--;
582 Ca.conservativeResize(na,Ca.cols());
583 da.conservativeResize(na);
584 // make sure to updated auxiliary structures as well
585 inactive.push_back(active[idx]);
586 active.erase(active.begin()+idx);
587 }
588 else {
589 EigenOpt_QUADPROG_DBG("Lagrange multipliers are positive: found optimal solution");
590 // All multipliers are non-negative: optimal solution has been reached
591 EigenOpt_QUADPROG_DBG("Active constraints violations (positive = violated):" << std::endl << (Ca*yk-da).transpose());
592 EigenOpt_QUADPROG_DBG("All constraints violations (positive = violated):" << std::endl << (Cy*yk-dy).transpose());
593 y = yk;
594 return true;
595 }
596 }
597
598 EigenOpt_QUADPROG_DBG("Current Active Matrix Ca:" << std::endl << Ca);
599 EigenOpt_QUADPROG_DBG("Active constraints violations (positive = violated):" << std::endl << (Ca*yk-da).transpose());
600 EigenOpt_QUADPROG_DBG("All constraints violations (positive = violated):" << std::endl << (Cy*yk-dy).transpose());
602 }
603
604 throw std::runtime_error("Could not find a solution within maximum number of iterations");
605 return false;
606}
607
608
609} // namespace quadratic_programming
610
611} // namespace EigenOpt
612
613#undef EigenOpt_QUADPROG_DBG
614#undef EigenOpt_QUADPROG_BREAK
Quadratic Programming solver using active set and null-space projections.
bool solve(Eigen::MatrixBase< D > &x)
Solve the optimization problem.
MatrixXs Qy
Modified matrix of coefficients for the objective function.
bool guess(Eigen::MatrixBase< D > &y)
Find an initial solution to start the active-set algorithm.
const int nr
Number of rows in the objective.
VectorXs xeq
A particular solution to the equality constraints.
VectorXs ry
Modified vector of coefficients for the objective function.
VectorXs r
Vector of coefficients for the objective function.
VectorXs yu
Unconstrained minimum of the objective.
MatrixXs Cy
Modified inequality constraints matrix.
bool updateInequalities(const Eigen::EigenBase< D1 > &C, const Eigen::EigenBase< D2 > &d)
Update inequality constraints to the problem.
void resetActiveSet()
Clear the current active set, preventing warm starts.
VectorXs dy
Modified inequality constraints vector.
VectorXs yk
Current guess of the decision variables.
MatrixXs Z
Matrix that projects into the kernel of the equality constraints matrix.
const int nx
Number of decision variables.
void clearConstraints()
Removes constraints and clear the active set.
bool setConstraints(const Eigen::EigenBase< D1 > &C, const Eigen::EigenBase< D2 > &d)
Add inequality constraints to the problem.
Solver(int xdim, int rdim, const Scalar &tolerance)
Give dimensions for x, Q and r explicitly.
bool solveY(Eigen::MatrixBase< D > &y)
Solve the problem in the y variable.
bool initActiveSet()
Initialize the active-set from the current solution.
void updateObjective(const Eigen::EigenBase< D1 > &Q, const Eigen::EigenBase< D2 > &r)
Updates the objective matrix.
MatrixXs Q
Matrix of coefficients for the objective function.
bool minimize(const Eigen::MatrixBase< D1 > &f, const Eigen::MatrixBase< D2 > &A, const Eigen::MatrixBase< D3 > &b, const Eigen::MatrixBase< D4 > &C, const Eigen::MatrixBase< D5 > &d, Eigen::DenseBase< D6 > &x, std::string &halt_reason, const Scalar &small_number, const Scalar &large_number=-1)
Solve a constrained linear optimization problem.
Definition simplex.hxx:152
Main namespace of this project, containing all utilities.
void svd_projection(const Eigen::MatrixBase< D1 > &A, const Eigen::MatrixBase< D2 > &b, Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > &Z, Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > &xeq)
Return all solutions to a linear system, using a kernel-based parameterization.
void qr_projection(const Eigen::MatrixBase< D1 > &A, const Eigen::MatrixBase< D2 > &b, Eigen::Matrix< Scalar, Eigen::Dynamic, Eigen::Dynamic > &Z, Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > &xeq)
Return all solutions to a linear system, using a kernel-based parameterization.
#define EigenOpt_QUADPROG_DBG(x)
#define EigenOpt_QUADPROG_BREAK
#define EigenOpt_SIMPLEX_DBG(x)