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