![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
quadprog++ and Eigen library test
Dependencies: mbed Eigen FastPWM
quadprog.cpp@2:e843c1b0b25c, 2019-09-24 (annotated)
- Committer:
- jsoh91
- Date:
- Tue Sep 24 00:20:12 2019 +0000
- Revision:
- 2:e843c1b0b25c
QP and Eigen library test project;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
jsoh91 | 2:e843c1b0b25c | 1 | /* |
jsoh91 | 2:e843c1b0b25c | 2 | File $Id: QuadProg++.cc 232 2007-06-21 12:29:00Z digasper $ |
jsoh91 | 2:e843c1b0b25c | 3 | |
jsoh91 | 2:e843c1b0b25c | 4 | Author: Luca Di Gaspero |
jsoh91 | 2:e843c1b0b25c | 5 | DIEGM - University of Udine, Italy |
jsoh91 | 2:e843c1b0b25c | 6 | luca.digaspero@uniud.it |
jsoh91 | 2:e843c1b0b25c | 7 | http://www.diegm.uniud.it/digaspero/ |
jsoh91 | 2:e843c1b0b25c | 8 | |
jsoh91 | 2:e843c1b0b25c | 9 | This software may be modified and distributed under the terms |
jsoh91 | 2:e843c1b0b25c | 10 | of the MIT license. See the LICENSE file for details. |
jsoh91 | 2:e843c1b0b25c | 11 | |
jsoh91 | 2:e843c1b0b25c | 12 | */ |
jsoh91 | 2:e843c1b0b25c | 13 | |
jsoh91 | 2:e843c1b0b25c | 14 | #include <iostream> |
jsoh91 | 2:e843c1b0b25c | 15 | #include <algorithm> |
jsoh91 | 2:e843c1b0b25c | 16 | #include <cmath> |
jsoh91 | 2:e843c1b0b25c | 17 | #include <limits> |
jsoh91 | 2:e843c1b0b25c | 18 | #include <sstream> |
jsoh91 | 2:e843c1b0b25c | 19 | #include <stdexcept> |
jsoh91 | 2:e843c1b0b25c | 20 | #include "quadprog.h" |
jsoh91 | 2:e843c1b0b25c | 21 | #include "math.h" |
jsoh91 | 2:e843c1b0b25c | 22 | |
jsoh91 | 2:e843c1b0b25c | 23 | //#define TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 24 | |
jsoh91 | 2:e843c1b0b25c | 25 | namespace quadprogpp |
jsoh91 | 2:e843c1b0b25c | 26 | { |
jsoh91 | 2:e843c1b0b25c | 27 | |
jsoh91 | 2:e843c1b0b25c | 28 | // Utility functions for updating some data needed by the solution method |
jsoh91 | 2:e843c1b0b25c | 29 | void compute_d(Vector<double>& d, const Matrix<double>& J, const Vector<double>& np); |
jsoh91 | 2:e843c1b0b25c | 30 | void update_z(Vector<double>& z, const Matrix<double>& J, const Vector<double>& d, int iq); |
jsoh91 | 2:e843c1b0b25c | 31 | void update_r(const Matrix<double>& R, Vector<double>& r, const Vector<double>& d, int iq); |
jsoh91 | 2:e843c1b0b25c | 32 | bool add_constraint(Matrix<double>& R, Matrix<double>& J, Vector<double>& d, int& iq, double& rnorm); |
jsoh91 | 2:e843c1b0b25c | 33 | void delete_constraint(Matrix<double>& R, Matrix<double>& J, Vector<int>& A, Vector<double>& u, int n, int p, int& iq, int l); |
jsoh91 | 2:e843c1b0b25c | 34 | |
jsoh91 | 2:e843c1b0b25c | 35 | // Utility functions for computing the Cholesky decomposition and solving |
jsoh91 | 2:e843c1b0b25c | 36 | // linear systems |
jsoh91 | 2:e843c1b0b25c | 37 | void cholesky_decomposition(Matrix<double>& A); |
jsoh91 | 2:e843c1b0b25c | 38 | void cholesky_solve(const Matrix<double>& L, Vector<double>& x, const Vector<double>& b); |
jsoh91 | 2:e843c1b0b25c | 39 | void forward_elimination(const Matrix<double>& L, Vector<double>& y, const Vector<double>& b); |
jsoh91 | 2:e843c1b0b25c | 40 | void backward_elimination(const Matrix<double>& U, Vector<double>& x, const Vector<double>& y); |
jsoh91 | 2:e843c1b0b25c | 41 | |
jsoh91 | 2:e843c1b0b25c | 42 | // Utility functions for computing the scalar product and the euclidean |
jsoh91 | 2:e843c1b0b25c | 43 | // distance between two numbers |
jsoh91 | 2:e843c1b0b25c | 44 | double scalar_product(const Vector<double>& x, const Vector<double>& y); |
jsoh91 | 2:e843c1b0b25c | 45 | double distance(double a, double b); |
jsoh91 | 2:e843c1b0b25c | 46 | |
jsoh91 | 2:e843c1b0b25c | 47 | // Utility functions for printing vectors and matrices |
jsoh91 | 2:e843c1b0b25c | 48 | void print_matrix(char* name, const Matrix<double>& A, int n = -1, int m = -1); |
jsoh91 | 2:e843c1b0b25c | 49 | |
jsoh91 | 2:e843c1b0b25c | 50 | template<typename T> |
jsoh91 | 2:e843c1b0b25c | 51 | void print_vector(char* name, const Vector<T>& v, int n = -1); |
jsoh91 | 2:e843c1b0b25c | 52 | |
jsoh91 | 2:e843c1b0b25c | 53 | // The Solving function, implementing the Goldfarb-Idnani method |
jsoh91 | 2:e843c1b0b25c | 54 | |
jsoh91 | 2:e843c1b0b25c | 55 | double solve_quadprog(Matrix<double>& G, Vector<double>& g0, |
jsoh91 | 2:e843c1b0b25c | 56 | const Matrix<double>& CE, const Vector<double>& ce0, |
jsoh91 | 2:e843c1b0b25c | 57 | const Matrix<double>& CI, const Vector<double>& ci0, |
jsoh91 | 2:e843c1b0b25c | 58 | Vector<double>& x) |
jsoh91 | 2:e843c1b0b25c | 59 | { |
jsoh91 | 2:e843c1b0b25c | 60 | std::ostringstream msg; |
jsoh91 | 2:e843c1b0b25c | 61 | int n = G.ncols(), p = CE.ncols(), m = CI.ncols(); |
jsoh91 | 2:e843c1b0b25c | 62 | if (G.nrows() != n) { |
jsoh91 | 2:e843c1b0b25c | 63 | msg << "The matrix G is not a squared matrix (" << G.nrows() << " x " << G.ncols() << ")"; |
jsoh91 | 2:e843c1b0b25c | 64 | // throw std::logic_error(msg.str()); |
jsoh91 | 2:e843c1b0b25c | 65 | } |
jsoh91 | 2:e843c1b0b25c | 66 | if (CE.nrows() != n) { |
jsoh91 | 2:e843c1b0b25c | 67 | msg << "The matrix CE is incompatible (incorrect number of rows " << CE.nrows() << " , expecting " << n << ")"; |
jsoh91 | 2:e843c1b0b25c | 68 | // throw std::logic_error(msg.str()); |
jsoh91 | 2:e843c1b0b25c | 69 | } |
jsoh91 | 2:e843c1b0b25c | 70 | if (ce0.size() != p) { |
jsoh91 | 2:e843c1b0b25c | 71 | msg << "The vector ce0 is incompatible (incorrect dimension " << ce0.size() << ", expecting " << p << ")"; |
jsoh91 | 2:e843c1b0b25c | 72 | // throw std::logic_error(msg.str()); |
jsoh91 | 2:e843c1b0b25c | 73 | } |
jsoh91 | 2:e843c1b0b25c | 74 | if (CI.nrows() != n) { |
jsoh91 | 2:e843c1b0b25c | 75 | msg << "The matrix CI is incompatible (incorrect number of rows " << CI.nrows() << " , expecting " << n << ")"; |
jsoh91 | 2:e843c1b0b25c | 76 | // throw std::logic_error(msg.str()); |
jsoh91 | 2:e843c1b0b25c | 77 | } |
jsoh91 | 2:e843c1b0b25c | 78 | if (ci0.size() != m) { |
jsoh91 | 2:e843c1b0b25c | 79 | msg << "The vector ci0 is incompatible (incorrect dimension " << ci0.size() << ", expecting " << m << ")"; |
jsoh91 | 2:e843c1b0b25c | 80 | // throw std::logic_error(msg.str()); |
jsoh91 | 2:e843c1b0b25c | 81 | } |
jsoh91 | 2:e843c1b0b25c | 82 | x.resize(n); |
jsoh91 | 2:e843c1b0b25c | 83 | register int i, j, k, l; /* indices */ |
jsoh91 | 2:e843c1b0b25c | 84 | int ip; // this is the index of the constraint to be added to the active set |
jsoh91 | 2:e843c1b0b25c | 85 | Matrix<double> R(n, n), J(n, n); |
jsoh91 | 2:e843c1b0b25c | 86 | Vector<double> s(m + p), z(n), r(m + p), d(n), np(n), u(m + p), x_old(n), u_old(m + p); |
jsoh91 | 2:e843c1b0b25c | 87 | double f_value, psi, c1, c2, sum, ss, R_norm; |
jsoh91 | 2:e843c1b0b25c | 88 | double inf; |
jsoh91 | 2:e843c1b0b25c | 89 | if (std::numeric_limits<double>::has_infinity) |
jsoh91 | 2:e843c1b0b25c | 90 | inf = std::numeric_limits<double>::infinity(); |
jsoh91 | 2:e843c1b0b25c | 91 | else |
jsoh91 | 2:e843c1b0b25c | 92 | inf = 1.0E300; |
jsoh91 | 2:e843c1b0b25c | 93 | double t, t1, t2; /* t is the step lenght, which is the minimum of the partial step length t1 |
jsoh91 | 2:e843c1b0b25c | 94 | * and the full step length t2 */ |
jsoh91 | 2:e843c1b0b25c | 95 | Vector<int> A(m + p), A_old(m + p), iai(m + p); |
jsoh91 | 2:e843c1b0b25c | 96 | int q, iq, iter = 0; |
jsoh91 | 2:e843c1b0b25c | 97 | Vector<bool> iaexcl(m + p); |
jsoh91 | 2:e843c1b0b25c | 98 | |
jsoh91 | 2:e843c1b0b25c | 99 | /* p is the number of equality constraints */ |
jsoh91 | 2:e843c1b0b25c | 100 | /* m is the number of inequality constraints */ |
jsoh91 | 2:e843c1b0b25c | 101 | q = 0; /* size of the active set A (containing the indices of the active constraints) */ |
jsoh91 | 2:e843c1b0b25c | 102 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 103 | std::cout << std::endl << "Starting solve_quadprog" << std::endl; |
jsoh91 | 2:e843c1b0b25c | 104 | print_matrix("G", G); |
jsoh91 | 2:e843c1b0b25c | 105 | print_vector("g0", g0); |
jsoh91 | 2:e843c1b0b25c | 106 | print_matrix("CE", CE); |
jsoh91 | 2:e843c1b0b25c | 107 | print_vector("ce0", ce0); |
jsoh91 | 2:e843c1b0b25c | 108 | print_matrix("CI", CI); |
jsoh91 | 2:e843c1b0b25c | 109 | print_vector("ci0", ci0); |
jsoh91 | 2:e843c1b0b25c | 110 | #endif |
jsoh91 | 2:e843c1b0b25c | 111 | |
jsoh91 | 2:e843c1b0b25c | 112 | /* |
jsoh91 | 2:e843c1b0b25c | 113 | * Preprocessing phase |
jsoh91 | 2:e843c1b0b25c | 114 | */ |
jsoh91 | 2:e843c1b0b25c | 115 | |
jsoh91 | 2:e843c1b0b25c | 116 | /* compute the trace of the original matrix G */ |
jsoh91 | 2:e843c1b0b25c | 117 | c1 = 0.0; |
jsoh91 | 2:e843c1b0b25c | 118 | for (i = 0; i < n; i++) { |
jsoh91 | 2:e843c1b0b25c | 119 | c1 += G[i][i]; |
jsoh91 | 2:e843c1b0b25c | 120 | } |
jsoh91 | 2:e843c1b0b25c | 121 | /* decompose the matrix G in the form L^T L */ |
jsoh91 | 2:e843c1b0b25c | 122 | cholesky_decomposition(G); |
jsoh91 | 2:e843c1b0b25c | 123 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 124 | print_matrix("G", G); |
jsoh91 | 2:e843c1b0b25c | 125 | #endif |
jsoh91 | 2:e843c1b0b25c | 126 | /* initialize the matrix R */ |
jsoh91 | 2:e843c1b0b25c | 127 | for (i = 0; i < n; i++) { |
jsoh91 | 2:e843c1b0b25c | 128 | d[i] = 0.0; |
jsoh91 | 2:e843c1b0b25c | 129 | for (j = 0; j < n; j++) |
jsoh91 | 2:e843c1b0b25c | 130 | R[i][j] = 0.0; |
jsoh91 | 2:e843c1b0b25c | 131 | } |
jsoh91 | 2:e843c1b0b25c | 132 | R_norm = 1.0; /* this variable will hold the norm of the matrix R */ |
jsoh91 | 2:e843c1b0b25c | 133 | |
jsoh91 | 2:e843c1b0b25c | 134 | /* compute the inverse of the factorized matrix G^-1, this is the initial value for H */ |
jsoh91 | 2:e843c1b0b25c | 135 | c2 = 0.0; |
jsoh91 | 2:e843c1b0b25c | 136 | for (i = 0; i < n; i++) { |
jsoh91 | 2:e843c1b0b25c | 137 | d[i] = 1.0; |
jsoh91 | 2:e843c1b0b25c | 138 | forward_elimination(G, z, d); |
jsoh91 | 2:e843c1b0b25c | 139 | for (j = 0; j < n; j++) |
jsoh91 | 2:e843c1b0b25c | 140 | J[i][j] = z[j]; |
jsoh91 | 2:e843c1b0b25c | 141 | c2 += z[i]; |
jsoh91 | 2:e843c1b0b25c | 142 | d[i] = 0.0; |
jsoh91 | 2:e843c1b0b25c | 143 | } |
jsoh91 | 2:e843c1b0b25c | 144 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 145 | print_matrix("J", J); |
jsoh91 | 2:e843c1b0b25c | 146 | #endif |
jsoh91 | 2:e843c1b0b25c | 147 | |
jsoh91 | 2:e843c1b0b25c | 148 | /* c1 * c2 is an estimate for cond(G) */ |
jsoh91 | 2:e843c1b0b25c | 149 | |
jsoh91 | 2:e843c1b0b25c | 150 | /* |
jsoh91 | 2:e843c1b0b25c | 151 | * Find the unconstrained minimizer of the quadratic form 0.5 * x G x + g0 x |
jsoh91 | 2:e843c1b0b25c | 152 | * this is a feasible point in the dual space |
jsoh91 | 2:e843c1b0b25c | 153 | * x = G^-1 * g0 |
jsoh91 | 2:e843c1b0b25c | 154 | */ |
jsoh91 | 2:e843c1b0b25c | 155 | cholesky_solve(G, x, g0); |
jsoh91 | 2:e843c1b0b25c | 156 | for (i = 0; i < n; i++) |
jsoh91 | 2:e843c1b0b25c | 157 | x[i] = -x[i]; |
jsoh91 | 2:e843c1b0b25c | 158 | /* and compute the current solution value */ |
jsoh91 | 2:e843c1b0b25c | 159 | f_value = 0.5 * scalar_product(g0, x); |
jsoh91 | 2:e843c1b0b25c | 160 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 161 | std::cout << "Unconstrained solution: " << f_value << std::endl; |
jsoh91 | 2:e843c1b0b25c | 162 | print_vector("x", x); |
jsoh91 | 2:e843c1b0b25c | 163 | #endif |
jsoh91 | 2:e843c1b0b25c | 164 | |
jsoh91 | 2:e843c1b0b25c | 165 | /* Add equality constraints to the working set A */ |
jsoh91 | 2:e843c1b0b25c | 166 | iq = 0; |
jsoh91 | 2:e843c1b0b25c | 167 | for (i = 0; i < p; i++) { |
jsoh91 | 2:e843c1b0b25c | 168 | for (j = 0; j < n; j++) |
jsoh91 | 2:e843c1b0b25c | 169 | np[j] = CE[j][i]; |
jsoh91 | 2:e843c1b0b25c | 170 | compute_d(d, J, np); |
jsoh91 | 2:e843c1b0b25c | 171 | update_z(z, J, d, iq); |
jsoh91 | 2:e843c1b0b25c | 172 | update_r(R, r, d, iq); |
jsoh91 | 2:e843c1b0b25c | 173 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 174 | print_matrix("R", R, n, iq); |
jsoh91 | 2:e843c1b0b25c | 175 | print_vector("z", z); |
jsoh91 | 2:e843c1b0b25c | 176 | print_vector("r", r, iq); |
jsoh91 | 2:e843c1b0b25c | 177 | print_vector("d", d); |
jsoh91 | 2:e843c1b0b25c | 178 | #endif |
jsoh91 | 2:e843c1b0b25c | 179 | |
jsoh91 | 2:e843c1b0b25c | 180 | /* compute full step length t2: i.e., the minimum step in primal space s.t. the contraint |
jsoh91 | 2:e843c1b0b25c | 181 | becomes feasible */ |
jsoh91 | 2:e843c1b0b25c | 182 | t2 = 0.0; |
jsoh91 | 2:e843c1b0b25c | 183 | if (fabs(scalar_product(z, z)) > std::numeric_limits<double>::epsilon()) // i.e. z != 0 |
jsoh91 | 2:e843c1b0b25c | 184 | t2 = (-scalar_product(np, x) - ce0[i]) / scalar_product(z, np); |
jsoh91 | 2:e843c1b0b25c | 185 | |
jsoh91 | 2:e843c1b0b25c | 186 | /* set x = x + t2 * z */ |
jsoh91 | 2:e843c1b0b25c | 187 | for (k = 0; k < n; k++) |
jsoh91 | 2:e843c1b0b25c | 188 | x[k] += t2 * z[k]; |
jsoh91 | 2:e843c1b0b25c | 189 | |
jsoh91 | 2:e843c1b0b25c | 190 | /* set u = u+ */ |
jsoh91 | 2:e843c1b0b25c | 191 | u[iq] = t2; |
jsoh91 | 2:e843c1b0b25c | 192 | for (k = 0; k < iq; k++) |
jsoh91 | 2:e843c1b0b25c | 193 | u[k] -= t2 * r[k]; |
jsoh91 | 2:e843c1b0b25c | 194 | |
jsoh91 | 2:e843c1b0b25c | 195 | /* compute the new solution value */ |
jsoh91 | 2:e843c1b0b25c | 196 | f_value += 0.5 * (t2 * t2) * scalar_product(z, np); |
jsoh91 | 2:e843c1b0b25c | 197 | A[i] = -i - 1; |
jsoh91 | 2:e843c1b0b25c | 198 | |
jsoh91 | 2:e843c1b0b25c | 199 | if (!add_constraint(R, J, d, iq, R_norm)) { |
jsoh91 | 2:e843c1b0b25c | 200 | // Equality constraints are linearly dependent |
jsoh91 | 2:e843c1b0b25c | 201 | // throw std::runtime_error("Constraints are linearly dependent"); |
jsoh91 | 2:e843c1b0b25c | 202 | return f_value; |
jsoh91 | 2:e843c1b0b25c | 203 | } |
jsoh91 | 2:e843c1b0b25c | 204 | } |
jsoh91 | 2:e843c1b0b25c | 205 | |
jsoh91 | 2:e843c1b0b25c | 206 | /* set iai = K \ A */ |
jsoh91 | 2:e843c1b0b25c | 207 | for (i = 0; i < m; i++) |
jsoh91 | 2:e843c1b0b25c | 208 | iai[i] = i; |
jsoh91 | 2:e843c1b0b25c | 209 | |
jsoh91 | 2:e843c1b0b25c | 210 | l1: |
jsoh91 | 2:e843c1b0b25c | 211 | iter++; |
jsoh91 | 2:e843c1b0b25c | 212 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 213 | print_vector("x", x); |
jsoh91 | 2:e843c1b0b25c | 214 | #endif |
jsoh91 | 2:e843c1b0b25c | 215 | /* step 1: choose a violated constraint */ |
jsoh91 | 2:e843c1b0b25c | 216 | for (i = p; i < iq; i++) { |
jsoh91 | 2:e843c1b0b25c | 217 | ip = A[i]; |
jsoh91 | 2:e843c1b0b25c | 218 | iai[ip] = -1; |
jsoh91 | 2:e843c1b0b25c | 219 | } |
jsoh91 | 2:e843c1b0b25c | 220 | |
jsoh91 | 2:e843c1b0b25c | 221 | /* compute s[x] = ci^T * x + ci0 for all elements of K \ A */ |
jsoh91 | 2:e843c1b0b25c | 222 | ss = 0.0; |
jsoh91 | 2:e843c1b0b25c | 223 | psi = 0.0; /* this value will contain the sum of all infeasibilities */ |
jsoh91 | 2:e843c1b0b25c | 224 | ip = 0; /* ip will be the index of the chosen violated constraint */ |
jsoh91 | 2:e843c1b0b25c | 225 | for (i = 0; i < m; i++) { |
jsoh91 | 2:e843c1b0b25c | 226 | iaexcl[i] = true; |
jsoh91 | 2:e843c1b0b25c | 227 | sum = 0.0; |
jsoh91 | 2:e843c1b0b25c | 228 | for (j = 0; j < n; j++) |
jsoh91 | 2:e843c1b0b25c | 229 | sum += CI[j][i] * x[j]; |
jsoh91 | 2:e843c1b0b25c | 230 | sum += ci0[i]; |
jsoh91 | 2:e843c1b0b25c | 231 | s[i] = sum; |
jsoh91 | 2:e843c1b0b25c | 232 | psi += std::min(0.0, sum); |
jsoh91 | 2:e843c1b0b25c | 233 | } |
jsoh91 | 2:e843c1b0b25c | 234 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 235 | print_vector("s", s, m); |
jsoh91 | 2:e843c1b0b25c | 236 | #endif |
jsoh91 | 2:e843c1b0b25c | 237 | |
jsoh91 | 2:e843c1b0b25c | 238 | |
jsoh91 | 2:e843c1b0b25c | 239 | if (fabs(psi) <= m * std::numeric_limits<double>::epsilon() * c1 * c2* 100.0) { |
jsoh91 | 2:e843c1b0b25c | 240 | /* numerically there are not infeasibilities anymore */ |
jsoh91 | 2:e843c1b0b25c | 241 | q = iq; |
jsoh91 | 2:e843c1b0b25c | 242 | |
jsoh91 | 2:e843c1b0b25c | 243 | return f_value; |
jsoh91 | 2:e843c1b0b25c | 244 | } |
jsoh91 | 2:e843c1b0b25c | 245 | |
jsoh91 | 2:e843c1b0b25c | 246 | /* save old values for u and A */ |
jsoh91 | 2:e843c1b0b25c | 247 | for (i = 0; i < iq; i++) { |
jsoh91 | 2:e843c1b0b25c | 248 | u_old[i] = u[i]; |
jsoh91 | 2:e843c1b0b25c | 249 | A_old[i] = A[i]; |
jsoh91 | 2:e843c1b0b25c | 250 | } |
jsoh91 | 2:e843c1b0b25c | 251 | /* and for x */ |
jsoh91 | 2:e843c1b0b25c | 252 | for (i = 0; i < n; i++) |
jsoh91 | 2:e843c1b0b25c | 253 | x_old[i] = x[i]; |
jsoh91 | 2:e843c1b0b25c | 254 | |
jsoh91 | 2:e843c1b0b25c | 255 | l2: /* Step 2: check for feasibility and determine a new S-pair */ |
jsoh91 | 2:e843c1b0b25c | 256 | for (i = 0; i < m; i++) { |
jsoh91 | 2:e843c1b0b25c | 257 | if (s[i] < ss && iai[i] != -1 && iaexcl[i]) { |
jsoh91 | 2:e843c1b0b25c | 258 | ss = s[i]; |
jsoh91 | 2:e843c1b0b25c | 259 | ip = i; |
jsoh91 | 2:e843c1b0b25c | 260 | } |
jsoh91 | 2:e843c1b0b25c | 261 | } |
jsoh91 | 2:e843c1b0b25c | 262 | if (ss >= 0.0) { |
jsoh91 | 2:e843c1b0b25c | 263 | q = iq; |
jsoh91 | 2:e843c1b0b25c | 264 | |
jsoh91 | 2:e843c1b0b25c | 265 | return f_value; |
jsoh91 | 2:e843c1b0b25c | 266 | } |
jsoh91 | 2:e843c1b0b25c | 267 | |
jsoh91 | 2:e843c1b0b25c | 268 | /* set np = n[ip] */ |
jsoh91 | 2:e843c1b0b25c | 269 | for (i = 0; i < n; i++) |
jsoh91 | 2:e843c1b0b25c | 270 | np[i] = CI[i][ip]; |
jsoh91 | 2:e843c1b0b25c | 271 | /* set u = [u 0]^T */ |
jsoh91 | 2:e843c1b0b25c | 272 | u[iq] = 0.0; |
jsoh91 | 2:e843c1b0b25c | 273 | /* add ip to the active set A */ |
jsoh91 | 2:e843c1b0b25c | 274 | A[iq] = ip; |
jsoh91 | 2:e843c1b0b25c | 275 | |
jsoh91 | 2:e843c1b0b25c | 276 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 277 | std::cout << "Trying with constraint " << ip << std::endl; |
jsoh91 | 2:e843c1b0b25c | 278 | print_vector("np", np); |
jsoh91 | 2:e843c1b0b25c | 279 | #endif |
jsoh91 | 2:e843c1b0b25c | 280 | |
jsoh91 | 2:e843c1b0b25c | 281 | l2a:/* Step 2a: determine step direction */ |
jsoh91 | 2:e843c1b0b25c | 282 | /* compute z = H np: the step direction in the primal space (through J, see the paper) */ |
jsoh91 | 2:e843c1b0b25c | 283 | compute_d(d, J, np); |
jsoh91 | 2:e843c1b0b25c | 284 | update_z(z, J, d, iq); |
jsoh91 | 2:e843c1b0b25c | 285 | /* compute N* np (if q > 0): the negative of the step direction in the dual space */ |
jsoh91 | 2:e843c1b0b25c | 286 | update_r(R, r, d, iq); |
jsoh91 | 2:e843c1b0b25c | 287 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 288 | std::cout << "Step direction z" << std::endl; |
jsoh91 | 2:e843c1b0b25c | 289 | print_vector("z", z); |
jsoh91 | 2:e843c1b0b25c | 290 | print_vector("r", r, iq + 1); |
jsoh91 | 2:e843c1b0b25c | 291 | print_vector("u", u, iq + 1); |
jsoh91 | 2:e843c1b0b25c | 292 | print_vector("d", d); |
jsoh91 | 2:e843c1b0b25c | 293 | print_vector("A", A, iq + 1); |
jsoh91 | 2:e843c1b0b25c | 294 | #endif |
jsoh91 | 2:e843c1b0b25c | 295 | |
jsoh91 | 2:e843c1b0b25c | 296 | /* Step 2b: compute step length */ |
jsoh91 | 2:e843c1b0b25c | 297 | l = 0; |
jsoh91 | 2:e843c1b0b25c | 298 | /* Compute t1: partial step length (maximum step in dual space without violating dual feasibility */ |
jsoh91 | 2:e843c1b0b25c | 299 | t1 = inf; /* +inf */ |
jsoh91 | 2:e843c1b0b25c | 300 | /* find the index l s.t. it reaches the minimum of u+[x] / r */ |
jsoh91 | 2:e843c1b0b25c | 301 | for (k = p; k < iq; k++) { |
jsoh91 | 2:e843c1b0b25c | 302 | if (r[k] > 0.0) { |
jsoh91 | 2:e843c1b0b25c | 303 | if (u[k] / r[k] < t1) { |
jsoh91 | 2:e843c1b0b25c | 304 | t1 = u[k] / r[k]; |
jsoh91 | 2:e843c1b0b25c | 305 | l = A[k]; |
jsoh91 | 2:e843c1b0b25c | 306 | } |
jsoh91 | 2:e843c1b0b25c | 307 | } |
jsoh91 | 2:e843c1b0b25c | 308 | } |
jsoh91 | 2:e843c1b0b25c | 309 | /* Compute t2: full step length (minimum step in primal space such that the constraint ip becomes feasible */ |
jsoh91 | 2:e843c1b0b25c | 310 | if (fabs(scalar_product(z, z)) > std::numeric_limits<double>::epsilon()) { // i.e. z != 0 |
jsoh91 | 2:e843c1b0b25c | 311 | t2 = -s[ip] / scalar_product(z, np); |
jsoh91 | 2:e843c1b0b25c | 312 | if (t2 < 0) // patch suggested by Takano Akio for handling numerical inconsistencies |
jsoh91 | 2:e843c1b0b25c | 313 | t2 = inf; |
jsoh91 | 2:e843c1b0b25c | 314 | } else |
jsoh91 | 2:e843c1b0b25c | 315 | t2 = inf; /* +inf */ |
jsoh91 | 2:e843c1b0b25c | 316 | |
jsoh91 | 2:e843c1b0b25c | 317 | /* the step is chosen as the minimum of t1 and t2 */ |
jsoh91 | 2:e843c1b0b25c | 318 | t = std::min(t1, t2); |
jsoh91 | 2:e843c1b0b25c | 319 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 320 | std::cout << "Step sizes: " << t << " (t1 = " << t1 << ", t2 = " << t2 << ") "; |
jsoh91 | 2:e843c1b0b25c | 321 | #endif |
jsoh91 | 2:e843c1b0b25c | 322 | |
jsoh91 | 2:e843c1b0b25c | 323 | /* Step 2c: determine new S-pair and take step: */ |
jsoh91 | 2:e843c1b0b25c | 324 | |
jsoh91 | 2:e843c1b0b25c | 325 | /* case (i): no step in primal or dual space */ |
jsoh91 | 2:e843c1b0b25c | 326 | if (t >= inf) { |
jsoh91 | 2:e843c1b0b25c | 327 | /* QPP is infeasible */ |
jsoh91 | 2:e843c1b0b25c | 328 | // FIXME: unbounded to raise |
jsoh91 | 2:e843c1b0b25c | 329 | q = iq; |
jsoh91 | 2:e843c1b0b25c | 330 | return inf; |
jsoh91 | 2:e843c1b0b25c | 331 | } |
jsoh91 | 2:e843c1b0b25c | 332 | /* case (ii): step in dual space */ |
jsoh91 | 2:e843c1b0b25c | 333 | if (t2 >= inf) { |
jsoh91 | 2:e843c1b0b25c | 334 | /* set u = u + t * [-r 1] and drop constraint l from the active set A */ |
jsoh91 | 2:e843c1b0b25c | 335 | for (k = 0; k < iq; k++) |
jsoh91 | 2:e843c1b0b25c | 336 | u[k] -= t * r[k]; |
jsoh91 | 2:e843c1b0b25c | 337 | u[iq] += t; |
jsoh91 | 2:e843c1b0b25c | 338 | iai[l] = l; |
jsoh91 | 2:e843c1b0b25c | 339 | delete_constraint(R, J, A, u, n, p, iq, l); |
jsoh91 | 2:e843c1b0b25c | 340 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 341 | std::cout << " in dual space: " |
jsoh91 | 2:e843c1b0b25c | 342 | << f_value << std::endl; |
jsoh91 | 2:e843c1b0b25c | 343 | print_vector("x", x); |
jsoh91 | 2:e843c1b0b25c | 344 | print_vector("z", z); |
jsoh91 | 2:e843c1b0b25c | 345 | print_vector("A", A, iq + 1); |
jsoh91 | 2:e843c1b0b25c | 346 | #endif |
jsoh91 | 2:e843c1b0b25c | 347 | goto l2a; |
jsoh91 | 2:e843c1b0b25c | 348 | } |
jsoh91 | 2:e843c1b0b25c | 349 | |
jsoh91 | 2:e843c1b0b25c | 350 | /* case (iii): step in primal and dual space */ |
jsoh91 | 2:e843c1b0b25c | 351 | |
jsoh91 | 2:e843c1b0b25c | 352 | /* set x = x + t * z */ |
jsoh91 | 2:e843c1b0b25c | 353 | for (k = 0; k < n; k++) |
jsoh91 | 2:e843c1b0b25c | 354 | x[k] += t * z[k]; |
jsoh91 | 2:e843c1b0b25c | 355 | /* update the solution value */ |
jsoh91 | 2:e843c1b0b25c | 356 | f_value += t * scalar_product(z, np) * (0.5 * t + u[iq]); |
jsoh91 | 2:e843c1b0b25c | 357 | /* u = u + t * [-r 1] */ |
jsoh91 | 2:e843c1b0b25c | 358 | for (k = 0; k < iq; k++) |
jsoh91 | 2:e843c1b0b25c | 359 | u[k] -= t * r[k]; |
jsoh91 | 2:e843c1b0b25c | 360 | u[iq] += t; |
jsoh91 | 2:e843c1b0b25c | 361 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 362 | std::cout << " in both spaces: " |
jsoh91 | 2:e843c1b0b25c | 363 | << f_value << std::endl; |
jsoh91 | 2:e843c1b0b25c | 364 | print_vector("x", x); |
jsoh91 | 2:e843c1b0b25c | 365 | print_vector("u", u, iq + 1); |
jsoh91 | 2:e843c1b0b25c | 366 | print_vector("r", r, iq + 1); |
jsoh91 | 2:e843c1b0b25c | 367 | print_vector("A", A, iq + 1); |
jsoh91 | 2:e843c1b0b25c | 368 | #endif |
jsoh91 | 2:e843c1b0b25c | 369 | |
jsoh91 | 2:e843c1b0b25c | 370 | if (fabs(t - t2) < std::numeric_limits<double>::epsilon()) { |
jsoh91 | 2:e843c1b0b25c | 371 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 372 | std::cout << "Full step has taken " << t << std::endl; |
jsoh91 | 2:e843c1b0b25c | 373 | print_vector("x", x); |
jsoh91 | 2:e843c1b0b25c | 374 | #endif |
jsoh91 | 2:e843c1b0b25c | 375 | /* full step has taken */ |
jsoh91 | 2:e843c1b0b25c | 376 | /* add constraint ip to the active set*/ |
jsoh91 | 2:e843c1b0b25c | 377 | if (!add_constraint(R, J, d, iq, R_norm)) { |
jsoh91 | 2:e843c1b0b25c | 378 | iaexcl[ip] = false; |
jsoh91 | 2:e843c1b0b25c | 379 | delete_constraint(R, J, A, u, n, p, iq, ip); |
jsoh91 | 2:e843c1b0b25c | 380 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 381 | print_matrix("R", R); |
jsoh91 | 2:e843c1b0b25c | 382 | print_vector("A", A, iq); |
jsoh91 | 2:e843c1b0b25c | 383 | print_vector("iai", iai); |
jsoh91 | 2:e843c1b0b25c | 384 | #endif |
jsoh91 | 2:e843c1b0b25c | 385 | for (i = 0; i < m; i++) |
jsoh91 | 2:e843c1b0b25c | 386 | iai[i] = i; |
jsoh91 | 2:e843c1b0b25c | 387 | for (i = p; i < iq; i++) { |
jsoh91 | 2:e843c1b0b25c | 388 | A[i] = A_old[i]; |
jsoh91 | 2:e843c1b0b25c | 389 | u[i] = u_old[i]; |
jsoh91 | 2:e843c1b0b25c | 390 | iai[A[i]] = -1; |
jsoh91 | 2:e843c1b0b25c | 391 | } |
jsoh91 | 2:e843c1b0b25c | 392 | for (i = 0; i < n; i++) |
jsoh91 | 2:e843c1b0b25c | 393 | x[i] = x_old[i]; |
jsoh91 | 2:e843c1b0b25c | 394 | goto l2; /* go to step 2 */ |
jsoh91 | 2:e843c1b0b25c | 395 | } else |
jsoh91 | 2:e843c1b0b25c | 396 | iai[ip] = -1; |
jsoh91 | 2:e843c1b0b25c | 397 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 398 | print_matrix("R", R); |
jsoh91 | 2:e843c1b0b25c | 399 | print_vector("A", A, iq); |
jsoh91 | 2:e843c1b0b25c | 400 | print_vector("iai", iai); |
jsoh91 | 2:e843c1b0b25c | 401 | #endif |
jsoh91 | 2:e843c1b0b25c | 402 | goto l1; |
jsoh91 | 2:e843c1b0b25c | 403 | } |
jsoh91 | 2:e843c1b0b25c | 404 | |
jsoh91 | 2:e843c1b0b25c | 405 | /* a patial step has taken */ |
jsoh91 | 2:e843c1b0b25c | 406 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 407 | std::cout << "Partial step has taken " << t << std::endl; |
jsoh91 | 2:e843c1b0b25c | 408 | print_vector("x", x); |
jsoh91 | 2:e843c1b0b25c | 409 | #endif |
jsoh91 | 2:e843c1b0b25c | 410 | /* drop constraint l */ |
jsoh91 | 2:e843c1b0b25c | 411 | iai[l] = l; |
jsoh91 | 2:e843c1b0b25c | 412 | delete_constraint(R, J, A, u, n, p, iq, l); |
jsoh91 | 2:e843c1b0b25c | 413 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 414 | print_matrix("R", R); |
jsoh91 | 2:e843c1b0b25c | 415 | print_vector("A", A, iq); |
jsoh91 | 2:e843c1b0b25c | 416 | #endif |
jsoh91 | 2:e843c1b0b25c | 417 | |
jsoh91 | 2:e843c1b0b25c | 418 | /* update s[ip] = CI * x + ci0 */ |
jsoh91 | 2:e843c1b0b25c | 419 | sum = 0.0; |
jsoh91 | 2:e843c1b0b25c | 420 | for (k = 0; k < n; k++) |
jsoh91 | 2:e843c1b0b25c | 421 | sum += CI[k][ip] * x[k]; |
jsoh91 | 2:e843c1b0b25c | 422 | s[ip] = sum + ci0[ip]; |
jsoh91 | 2:e843c1b0b25c | 423 | |
jsoh91 | 2:e843c1b0b25c | 424 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 425 | print_vector("s", s, m); |
jsoh91 | 2:e843c1b0b25c | 426 | #endif |
jsoh91 | 2:e843c1b0b25c | 427 | goto l2a; |
jsoh91 | 2:e843c1b0b25c | 428 | } |
jsoh91 | 2:e843c1b0b25c | 429 | |
jsoh91 | 2:e843c1b0b25c | 430 | inline void compute_d(Vector<double>& d, const Matrix<double>& J, const Vector<double>& np) |
jsoh91 | 2:e843c1b0b25c | 431 | { |
jsoh91 | 2:e843c1b0b25c | 432 | register int i, j, n = d.size(); |
jsoh91 | 2:e843c1b0b25c | 433 | register double sum; |
jsoh91 | 2:e843c1b0b25c | 434 | |
jsoh91 | 2:e843c1b0b25c | 435 | /* compute d = H^T * np */ |
jsoh91 | 2:e843c1b0b25c | 436 | for (i = 0; i < n; i++) { |
jsoh91 | 2:e843c1b0b25c | 437 | sum = 0.0; |
jsoh91 | 2:e843c1b0b25c | 438 | for (j = 0; j < n; j++) |
jsoh91 | 2:e843c1b0b25c | 439 | sum += J[j][i] * np[j]; |
jsoh91 | 2:e843c1b0b25c | 440 | d[i] = sum; |
jsoh91 | 2:e843c1b0b25c | 441 | } |
jsoh91 | 2:e843c1b0b25c | 442 | } |
jsoh91 | 2:e843c1b0b25c | 443 | |
jsoh91 | 2:e843c1b0b25c | 444 | inline void update_z(Vector<double>& z, const Matrix<double>& J, const Vector<double>& d, int iq) |
jsoh91 | 2:e843c1b0b25c | 445 | { |
jsoh91 | 2:e843c1b0b25c | 446 | register int i, j, n = z.size(); |
jsoh91 | 2:e843c1b0b25c | 447 | |
jsoh91 | 2:e843c1b0b25c | 448 | /* setting of z = H * d */ |
jsoh91 | 2:e843c1b0b25c | 449 | for (i = 0; i < n; i++) { |
jsoh91 | 2:e843c1b0b25c | 450 | z[i] = 0.0; |
jsoh91 | 2:e843c1b0b25c | 451 | for (j = iq; j < n; j++) |
jsoh91 | 2:e843c1b0b25c | 452 | z[i] += J[i][j] * d[j]; |
jsoh91 | 2:e843c1b0b25c | 453 | } |
jsoh91 | 2:e843c1b0b25c | 454 | } |
jsoh91 | 2:e843c1b0b25c | 455 | |
jsoh91 | 2:e843c1b0b25c | 456 | inline void update_r(const Matrix<double>& R, Vector<double>& r, const Vector<double>& d, int iq) |
jsoh91 | 2:e843c1b0b25c | 457 | { |
jsoh91 | 2:e843c1b0b25c | 458 | register int i, j, n = d.size(); |
jsoh91 | 2:e843c1b0b25c | 459 | register double sum; |
jsoh91 | 2:e843c1b0b25c | 460 | |
jsoh91 | 2:e843c1b0b25c | 461 | /* setting of r = R^-1 d */ |
jsoh91 | 2:e843c1b0b25c | 462 | for (i = iq - 1; i >= 0; i--) { |
jsoh91 | 2:e843c1b0b25c | 463 | sum = 0.0; |
jsoh91 | 2:e843c1b0b25c | 464 | for (j = i + 1; j < iq; j++) |
jsoh91 | 2:e843c1b0b25c | 465 | sum += R[i][j] * r[j]; |
jsoh91 | 2:e843c1b0b25c | 466 | r[i] = (d[i] - sum) / R[i][i]; |
jsoh91 | 2:e843c1b0b25c | 467 | } |
jsoh91 | 2:e843c1b0b25c | 468 | } |
jsoh91 | 2:e843c1b0b25c | 469 | |
jsoh91 | 2:e843c1b0b25c | 470 | bool add_constraint(Matrix<double>& R, Matrix<double>& J, Vector<double>& d, int& iq, double& R_norm) |
jsoh91 | 2:e843c1b0b25c | 471 | { |
jsoh91 | 2:e843c1b0b25c | 472 | int n = d.size(); |
jsoh91 | 2:e843c1b0b25c | 473 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 474 | std::cout << "Add constraint " << iq << '/'; |
jsoh91 | 2:e843c1b0b25c | 475 | #endif |
jsoh91 | 2:e843c1b0b25c | 476 | register int i, j, k; |
jsoh91 | 2:e843c1b0b25c | 477 | double cc, ss, h, t1, t2, xny; |
jsoh91 | 2:e843c1b0b25c | 478 | |
jsoh91 | 2:e843c1b0b25c | 479 | /* we have to find the Givens rotation which will reduce the element |
jsoh91 | 2:e843c1b0b25c | 480 | d[j] to zero. |
jsoh91 | 2:e843c1b0b25c | 481 | if it is already zero we don't have to do anything, except of |
jsoh91 | 2:e843c1b0b25c | 482 | decreasing j */ |
jsoh91 | 2:e843c1b0b25c | 483 | for (j = n - 1; j >= iq + 1; j--) { |
jsoh91 | 2:e843c1b0b25c | 484 | /* The Givens rotation is done with the matrix (cc cs, cs -cc). |
jsoh91 | 2:e843c1b0b25c | 485 | If cc is one, then element (j) of d is zero compared with element |
jsoh91 | 2:e843c1b0b25c | 486 | (j - 1). Hence we don't have to do anything. |
jsoh91 | 2:e843c1b0b25c | 487 | If cc is zero, then we just have to switch column (j) and column (j - 1) |
jsoh91 | 2:e843c1b0b25c | 488 | of J. Since we only switch columns in J, we have to be careful how we |
jsoh91 | 2:e843c1b0b25c | 489 | update d depending on the sign of gs. |
jsoh91 | 2:e843c1b0b25c | 490 | Otherwise we have to apply the Givens rotation to these columns. |
jsoh91 | 2:e843c1b0b25c | 491 | The i - 1 element of d has to be updated to h. */ |
jsoh91 | 2:e843c1b0b25c | 492 | cc = d[j - 1]; |
jsoh91 | 2:e843c1b0b25c | 493 | ss = d[j]; |
jsoh91 | 2:e843c1b0b25c | 494 | h = distance(cc, ss); |
jsoh91 | 2:e843c1b0b25c | 495 | if (fabs(h) < std::numeric_limits<double>::epsilon()) // h == 0 |
jsoh91 | 2:e843c1b0b25c | 496 | continue; |
jsoh91 | 2:e843c1b0b25c | 497 | d[j] = 0.0; |
jsoh91 | 2:e843c1b0b25c | 498 | ss = ss / h; |
jsoh91 | 2:e843c1b0b25c | 499 | cc = cc / h; |
jsoh91 | 2:e843c1b0b25c | 500 | if (cc < 0.0) { |
jsoh91 | 2:e843c1b0b25c | 501 | cc = -cc; |
jsoh91 | 2:e843c1b0b25c | 502 | ss = -ss; |
jsoh91 | 2:e843c1b0b25c | 503 | d[j - 1] = -h; |
jsoh91 | 2:e843c1b0b25c | 504 | } else |
jsoh91 | 2:e843c1b0b25c | 505 | d[j - 1] = h; |
jsoh91 | 2:e843c1b0b25c | 506 | xny = ss / (1.0 + cc); |
jsoh91 | 2:e843c1b0b25c | 507 | for (k = 0; k < n; k++) { |
jsoh91 | 2:e843c1b0b25c | 508 | t1 = J[k][j - 1]; |
jsoh91 | 2:e843c1b0b25c | 509 | t2 = J[k][j]; |
jsoh91 | 2:e843c1b0b25c | 510 | J[k][j - 1] = t1 * cc + t2 * ss; |
jsoh91 | 2:e843c1b0b25c | 511 | J[k][j] = xny * (t1 + J[k][j - 1]) - t2; |
jsoh91 | 2:e843c1b0b25c | 512 | } |
jsoh91 | 2:e843c1b0b25c | 513 | } |
jsoh91 | 2:e843c1b0b25c | 514 | /* update the number of constraints added*/ |
jsoh91 | 2:e843c1b0b25c | 515 | iq++; |
jsoh91 | 2:e843c1b0b25c | 516 | /* To update R we have to put the iq components of the d vector |
jsoh91 | 2:e843c1b0b25c | 517 | into column iq - 1 of R |
jsoh91 | 2:e843c1b0b25c | 518 | */ |
jsoh91 | 2:e843c1b0b25c | 519 | for (i = 0; i < iq; i++) |
jsoh91 | 2:e843c1b0b25c | 520 | R[i][iq - 1] = d[i]; |
jsoh91 | 2:e843c1b0b25c | 521 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 522 | std::cout << iq << std::endl; |
jsoh91 | 2:e843c1b0b25c | 523 | print_matrix("R", R, iq, iq); |
jsoh91 | 2:e843c1b0b25c | 524 | print_matrix("J", J); |
jsoh91 | 2:e843c1b0b25c | 525 | print_vector("d", d, iq); |
jsoh91 | 2:e843c1b0b25c | 526 | #endif |
jsoh91 | 2:e843c1b0b25c | 527 | |
jsoh91 | 2:e843c1b0b25c | 528 | if (fabs(d[iq - 1]) <= std::numeric_limits<double>::epsilon() * R_norm) { |
jsoh91 | 2:e843c1b0b25c | 529 | // problem degenerate |
jsoh91 | 2:e843c1b0b25c | 530 | return false; |
jsoh91 | 2:e843c1b0b25c | 531 | } |
jsoh91 | 2:e843c1b0b25c | 532 | R_norm = std::max<double>(R_norm, fabs(d[iq - 1])); |
jsoh91 | 2:e843c1b0b25c | 533 | return true; |
jsoh91 | 2:e843c1b0b25c | 534 | } |
jsoh91 | 2:e843c1b0b25c | 535 | |
jsoh91 | 2:e843c1b0b25c | 536 | void delete_constraint(Matrix<double>& R, Matrix<double>& J, Vector<int>& A, Vector<double>& u, int n, int p, int& iq, int l) |
jsoh91 | 2:e843c1b0b25c | 537 | { |
jsoh91 | 2:e843c1b0b25c | 538 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 539 | std::cout << "Delete constraint " << l << ' ' << iq; |
jsoh91 | 2:e843c1b0b25c | 540 | #endif |
jsoh91 | 2:e843c1b0b25c | 541 | register int i, j, k, qq = -1; // just to prevent warnings from smart compilers |
jsoh91 | 2:e843c1b0b25c | 542 | double cc, ss, h, xny, t1, t2; |
jsoh91 | 2:e843c1b0b25c | 543 | |
jsoh91 | 2:e843c1b0b25c | 544 | /* Find the index qq for active constraint l to be removed */ |
jsoh91 | 2:e843c1b0b25c | 545 | for (i = p; i < iq; i++) |
jsoh91 | 2:e843c1b0b25c | 546 | if (A[i] == l) { |
jsoh91 | 2:e843c1b0b25c | 547 | qq = i; |
jsoh91 | 2:e843c1b0b25c | 548 | break; |
jsoh91 | 2:e843c1b0b25c | 549 | } |
jsoh91 | 2:e843c1b0b25c | 550 | |
jsoh91 | 2:e843c1b0b25c | 551 | /* remove the constraint from the active set and the duals */ |
jsoh91 | 2:e843c1b0b25c | 552 | for (i = qq; i < iq - 1; i++) { |
jsoh91 | 2:e843c1b0b25c | 553 | A[i] = A[i + 1]; |
jsoh91 | 2:e843c1b0b25c | 554 | u[i] = u[i + 1]; |
jsoh91 | 2:e843c1b0b25c | 555 | for (j = 0; j < n; j++) |
jsoh91 | 2:e843c1b0b25c | 556 | R[j][i] = R[j][i + 1]; |
jsoh91 | 2:e843c1b0b25c | 557 | } |
jsoh91 | 2:e843c1b0b25c | 558 | |
jsoh91 | 2:e843c1b0b25c | 559 | A[iq - 1] = A[iq]; |
jsoh91 | 2:e843c1b0b25c | 560 | u[iq - 1] = u[iq]; |
jsoh91 | 2:e843c1b0b25c | 561 | A[iq] = 0; |
jsoh91 | 2:e843c1b0b25c | 562 | u[iq] = 0.0; |
jsoh91 | 2:e843c1b0b25c | 563 | for (j = 0; j < iq; j++) |
jsoh91 | 2:e843c1b0b25c | 564 | R[j][iq - 1] = 0.0; |
jsoh91 | 2:e843c1b0b25c | 565 | /* constraint has been fully removed */ |
jsoh91 | 2:e843c1b0b25c | 566 | iq--; |
jsoh91 | 2:e843c1b0b25c | 567 | #ifdef TRACE_SOLVER |
jsoh91 | 2:e843c1b0b25c | 568 | std::cout << '/' << iq << std::endl; |
jsoh91 | 2:e843c1b0b25c | 569 | #endif |
jsoh91 | 2:e843c1b0b25c | 570 | |
jsoh91 | 2:e843c1b0b25c | 571 | if (iq == 0) |
jsoh91 | 2:e843c1b0b25c | 572 | return; |
jsoh91 | 2:e843c1b0b25c | 573 | |
jsoh91 | 2:e843c1b0b25c | 574 | for (j = qq; j < iq; j++) { |
jsoh91 | 2:e843c1b0b25c | 575 | cc = R[j][j]; |
jsoh91 | 2:e843c1b0b25c | 576 | ss = R[j + 1][j]; |
jsoh91 | 2:e843c1b0b25c | 577 | h = distance(cc, ss); |
jsoh91 | 2:e843c1b0b25c | 578 | if (fabs(h) < std::numeric_limits<double>::epsilon()) // h == 0 |
jsoh91 | 2:e843c1b0b25c | 579 | continue; |
jsoh91 | 2:e843c1b0b25c | 580 | cc = cc / h; |
jsoh91 | 2:e843c1b0b25c | 581 | ss = ss / h; |
jsoh91 | 2:e843c1b0b25c | 582 | R[j + 1][j] = 0.0; |
jsoh91 | 2:e843c1b0b25c | 583 | if (cc < 0.0) { |
jsoh91 | 2:e843c1b0b25c | 584 | R[j][j] = -h; |
jsoh91 | 2:e843c1b0b25c | 585 | cc = -cc; |
jsoh91 | 2:e843c1b0b25c | 586 | ss = -ss; |
jsoh91 | 2:e843c1b0b25c | 587 | } else |
jsoh91 | 2:e843c1b0b25c | 588 | R[j][j] = h; |
jsoh91 | 2:e843c1b0b25c | 589 | |
jsoh91 | 2:e843c1b0b25c | 590 | xny = ss / (1.0 + cc); |
jsoh91 | 2:e843c1b0b25c | 591 | for (k = j + 1; k < iq; k++) { |
jsoh91 | 2:e843c1b0b25c | 592 | t1 = R[j][k]; |
jsoh91 | 2:e843c1b0b25c | 593 | t2 = R[j + 1][k]; |
jsoh91 | 2:e843c1b0b25c | 594 | R[j][k] = t1 * cc + t2 * ss; |
jsoh91 | 2:e843c1b0b25c | 595 | R[j + 1][k] = xny * (t1 + R[j][k]) - t2; |
jsoh91 | 2:e843c1b0b25c | 596 | } |
jsoh91 | 2:e843c1b0b25c | 597 | for (k = 0; k < n; k++) { |
jsoh91 | 2:e843c1b0b25c | 598 | t1 = J[k][j]; |
jsoh91 | 2:e843c1b0b25c | 599 | t2 = J[k][j + 1]; |
jsoh91 | 2:e843c1b0b25c | 600 | J[k][j] = t1 * cc + t2 * ss; |
jsoh91 | 2:e843c1b0b25c | 601 | J[k][j + 1] = xny * (J[k][j] + t1) - t2; |
jsoh91 | 2:e843c1b0b25c | 602 | } |
jsoh91 | 2:e843c1b0b25c | 603 | } |
jsoh91 | 2:e843c1b0b25c | 604 | } |
jsoh91 | 2:e843c1b0b25c | 605 | |
jsoh91 | 2:e843c1b0b25c | 606 | inline double distance(double a, double b) |
jsoh91 | 2:e843c1b0b25c | 607 | { |
jsoh91 | 2:e843c1b0b25c | 608 | register double a1, b1, t; |
jsoh91 | 2:e843c1b0b25c | 609 | a1 = fabs(a); |
jsoh91 | 2:e843c1b0b25c | 610 | b1 = fabs(b); |
jsoh91 | 2:e843c1b0b25c | 611 | if (a1 > b1) { |
jsoh91 | 2:e843c1b0b25c | 612 | t = (b1 / a1); |
jsoh91 | 2:e843c1b0b25c | 613 | return a1 * sqrt(1.0 + t * t); |
jsoh91 | 2:e843c1b0b25c | 614 | } else if (b1 > a1) { |
jsoh91 | 2:e843c1b0b25c | 615 | t = (a1 / b1); |
jsoh91 | 2:e843c1b0b25c | 616 | return b1 * sqrt(1.0 + t * t); |
jsoh91 | 2:e843c1b0b25c | 617 | } |
jsoh91 | 2:e843c1b0b25c | 618 | return a1 * sqrt(2.0); |
jsoh91 | 2:e843c1b0b25c | 619 | } |
jsoh91 | 2:e843c1b0b25c | 620 | |
jsoh91 | 2:e843c1b0b25c | 621 | |
jsoh91 | 2:e843c1b0b25c | 622 | inline double scalar_product(const Vector<double>& x, const Vector<double>& y) |
jsoh91 | 2:e843c1b0b25c | 623 | { |
jsoh91 | 2:e843c1b0b25c | 624 | register int i, n = x.size(); |
jsoh91 | 2:e843c1b0b25c | 625 | register double sum; |
jsoh91 | 2:e843c1b0b25c | 626 | |
jsoh91 | 2:e843c1b0b25c | 627 | sum = 0.0; |
jsoh91 | 2:e843c1b0b25c | 628 | for (i = 0; i < n; i++) |
jsoh91 | 2:e843c1b0b25c | 629 | sum += x[i] * y[i]; |
jsoh91 | 2:e843c1b0b25c | 630 | return sum; |
jsoh91 | 2:e843c1b0b25c | 631 | } |
jsoh91 | 2:e843c1b0b25c | 632 | |
jsoh91 | 2:e843c1b0b25c | 633 | void cholesky_decomposition(Matrix<double>& A) |
jsoh91 | 2:e843c1b0b25c | 634 | { |
jsoh91 | 2:e843c1b0b25c | 635 | register int i, j, k, n = A.nrows(); |
jsoh91 | 2:e843c1b0b25c | 636 | register double sum; |
jsoh91 | 2:e843c1b0b25c | 637 | |
jsoh91 | 2:e843c1b0b25c | 638 | for (i = 0; i < n; i++) { |
jsoh91 | 2:e843c1b0b25c | 639 | for (j = i; j < n; j++) { |
jsoh91 | 2:e843c1b0b25c | 640 | sum = A[i][j]; |
jsoh91 | 2:e843c1b0b25c | 641 | for (k = i - 1; k >= 0; k--) |
jsoh91 | 2:e843c1b0b25c | 642 | sum -= A[i][k]*A[j][k]; |
jsoh91 | 2:e843c1b0b25c | 643 | if (i == j) { |
jsoh91 | 2:e843c1b0b25c | 644 | if (sum <= 0.0) { |
jsoh91 | 2:e843c1b0b25c | 645 | std::ostringstream os; |
jsoh91 | 2:e843c1b0b25c | 646 | // raise error |
jsoh91 | 2:e843c1b0b25c | 647 | print_matrix("A", A); |
jsoh91 | 2:e843c1b0b25c | 648 | os << "Error in cholesky decomposition, sum: " << sum; |
jsoh91 | 2:e843c1b0b25c | 649 | // throw std::logic_error(os.str()); |
jsoh91 | 2:e843c1b0b25c | 650 | // exit(-1); |
jsoh91 | 2:e843c1b0b25c | 651 | } |
jsoh91 | 2:e843c1b0b25c | 652 | A[i][i] = sqrt(sum); |
jsoh91 | 2:e843c1b0b25c | 653 | } else |
jsoh91 | 2:e843c1b0b25c | 654 | A[j][i] = sum / A[i][i]; |
jsoh91 | 2:e843c1b0b25c | 655 | } |
jsoh91 | 2:e843c1b0b25c | 656 | for (k = i + 1; k < n; k++) |
jsoh91 | 2:e843c1b0b25c | 657 | A[i][k] = A[k][i]; |
jsoh91 | 2:e843c1b0b25c | 658 | } |
jsoh91 | 2:e843c1b0b25c | 659 | } |
jsoh91 | 2:e843c1b0b25c | 660 | |
jsoh91 | 2:e843c1b0b25c | 661 | void cholesky_solve(const Matrix<double>& L, Vector<double>& x, const Vector<double>& b) |
jsoh91 | 2:e843c1b0b25c | 662 | { |
jsoh91 | 2:e843c1b0b25c | 663 | int n = L.nrows(); |
jsoh91 | 2:e843c1b0b25c | 664 | Vector<double> y(n); |
jsoh91 | 2:e843c1b0b25c | 665 | |
jsoh91 | 2:e843c1b0b25c | 666 | /* Solve L * y = b */ |
jsoh91 | 2:e843c1b0b25c | 667 | forward_elimination(L, y, b); |
jsoh91 | 2:e843c1b0b25c | 668 | /* Solve L^T * x = y */ |
jsoh91 | 2:e843c1b0b25c | 669 | backward_elimination(L, x, y); |
jsoh91 | 2:e843c1b0b25c | 670 | } |
jsoh91 | 2:e843c1b0b25c | 671 | |
jsoh91 | 2:e843c1b0b25c | 672 | inline void forward_elimination(const Matrix<double>& L, Vector<double>& y, const Vector<double>& b) |
jsoh91 | 2:e843c1b0b25c | 673 | { |
jsoh91 | 2:e843c1b0b25c | 674 | register int i, j, n = L.nrows(); |
jsoh91 | 2:e843c1b0b25c | 675 | |
jsoh91 | 2:e843c1b0b25c | 676 | y[0] = b[0] / L[0][0]; |
jsoh91 | 2:e843c1b0b25c | 677 | for (i = 1; i < n; i++) { |
jsoh91 | 2:e843c1b0b25c | 678 | y[i] = b[i]; |
jsoh91 | 2:e843c1b0b25c | 679 | for (j = 0; j < i; j++) |
jsoh91 | 2:e843c1b0b25c | 680 | y[i] -= L[i][j] * y[j]; |
jsoh91 | 2:e843c1b0b25c | 681 | y[i] = y[i] / L[i][i]; |
jsoh91 | 2:e843c1b0b25c | 682 | } |
jsoh91 | 2:e843c1b0b25c | 683 | } |
jsoh91 | 2:e843c1b0b25c | 684 | |
jsoh91 | 2:e843c1b0b25c | 685 | inline void backward_elimination(const Matrix<double>& U, Vector<double>& x, const Vector<double>& y) |
jsoh91 | 2:e843c1b0b25c | 686 | { |
jsoh91 | 2:e843c1b0b25c | 687 | register int i, j, n = U.nrows(); |
jsoh91 | 2:e843c1b0b25c | 688 | |
jsoh91 | 2:e843c1b0b25c | 689 | x[n - 1] = y[n - 1] / U[n - 1][n - 1]; |
jsoh91 | 2:e843c1b0b25c | 690 | for (i = n - 2; i >= 0; i--) { |
jsoh91 | 2:e843c1b0b25c | 691 | x[i] = y[i]; |
jsoh91 | 2:e843c1b0b25c | 692 | for (j = i + 1; j < n; j++) |
jsoh91 | 2:e843c1b0b25c | 693 | x[i] -= U[i][j] * x[j]; |
jsoh91 | 2:e843c1b0b25c | 694 | x[i] = x[i] / U[i][i]; |
jsoh91 | 2:e843c1b0b25c | 695 | } |
jsoh91 | 2:e843c1b0b25c | 696 | } |
jsoh91 | 2:e843c1b0b25c | 697 | |
jsoh91 | 2:e843c1b0b25c | 698 | void print_matrix(char* name, const Matrix<double>& A, int n, int m) |
jsoh91 | 2:e843c1b0b25c | 699 | { |
jsoh91 | 2:e843c1b0b25c | 700 | std::ostringstream s; |
jsoh91 | 2:e843c1b0b25c | 701 | std::string t; |
jsoh91 | 2:e843c1b0b25c | 702 | if (n == -1) |
jsoh91 | 2:e843c1b0b25c | 703 | n = A.nrows(); |
jsoh91 | 2:e843c1b0b25c | 704 | if (m == -1) |
jsoh91 | 2:e843c1b0b25c | 705 | m = A.ncols(); |
jsoh91 | 2:e843c1b0b25c | 706 | |
jsoh91 | 2:e843c1b0b25c | 707 | s << name << ": " << std::endl; |
jsoh91 | 2:e843c1b0b25c | 708 | for (int i = 0; i < n; i++) { |
jsoh91 | 2:e843c1b0b25c | 709 | s << " "; |
jsoh91 | 2:e843c1b0b25c | 710 | for (int j = 0; j < m; j++) |
jsoh91 | 2:e843c1b0b25c | 711 | s << A[i][j] << ", "; |
jsoh91 | 2:e843c1b0b25c | 712 | s << std::endl; |
jsoh91 | 2:e843c1b0b25c | 713 | } |
jsoh91 | 2:e843c1b0b25c | 714 | t = s.str(); |
jsoh91 | 2:e843c1b0b25c | 715 | t = t.substr(0, t.size() - 3); // To remove the trailing space, comma and newline |
jsoh91 | 2:e843c1b0b25c | 716 | |
jsoh91 | 2:e843c1b0b25c | 717 | std::cout << t << std::endl; |
jsoh91 | 2:e843c1b0b25c | 718 | } |
jsoh91 | 2:e843c1b0b25c | 719 | |
jsoh91 | 2:e843c1b0b25c | 720 | template<typename T> |
jsoh91 | 2:e843c1b0b25c | 721 | void print_vector(char* name, const Vector<T>& v, int n) |
jsoh91 | 2:e843c1b0b25c | 722 | { |
jsoh91 | 2:e843c1b0b25c | 723 | std::ostringstream s; |
jsoh91 | 2:e843c1b0b25c | 724 | std::string t; |
jsoh91 | 2:e843c1b0b25c | 725 | if (n == -1) |
jsoh91 | 2:e843c1b0b25c | 726 | n = v.size(); |
jsoh91 | 2:e843c1b0b25c | 727 | |
jsoh91 | 2:e843c1b0b25c | 728 | s << name << ": " << std::endl << " "; |
jsoh91 | 2:e843c1b0b25c | 729 | for (int i = 0; i < n; i++) { |
jsoh91 | 2:e843c1b0b25c | 730 | s << v[i] << ", "; |
jsoh91 | 2:e843c1b0b25c | 731 | } |
jsoh91 | 2:e843c1b0b25c | 732 | t = s.str(); |
jsoh91 | 2:e843c1b0b25c | 733 | t = t.substr(0, t.size() - 2); // To remove the trailing space and comma |
jsoh91 | 2:e843c1b0b25c | 734 | |
jsoh91 | 2:e843c1b0b25c | 735 | std::cout << t << std::endl; |
jsoh91 | 2:e843c1b0b25c | 736 | } |
jsoh91 | 2:e843c1b0b25c | 737 | |
jsoh91 | 2:e843c1b0b25c | 738 | } // namespace quadprogpp |