QuadProg++.cpp 22 KB

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