ocra-recipes
Doxygen documentation for the ocra-recipes repository
CmlQuadraticSolver.cpp
Go to the documentation of this file.
1 #if 0
2 
4 
5 #include "cfl/Timer.h"
6 
7 #include <algorithm>
8 #include <sstream>
9 
10 #include <fstream>
11 #include <stdexcept>
12 
13 using namespace xde;
14 
15 namespace ocra
16 {
17  CmlQuadraticSolver::CmlQuadraticSolver(int type)
18  :QuadraticSolver("CmlQuadraticSolver"), _solverType(type)
19  {
20  switch (type)
21  {
22  case CMLQPSOLVER_LEMKE:
23  _solver = cmlQPSolver::New(cmlQPSolver::LEMKE_SOLVER);
24  break;
25  case CMLQPSOLVER_GAUSS_SEIDEL:
26  _solver = cmlQPSolver::New(cmlQPSolver::GAUSS_SEIDEL_SOLVER);
27  break;
28  default:
29  throw std::runtime_error("[CmlQuadraticSolver::CmlQuadraticSolver] Invalid solver type");
30  }
31  }
32 
33  void CmlQuadraticSolver::setTolerance(double epsilon)
34  {
35  _solver->setTolerance(epsilon);
36  }
37 
38  void CmlQuadraticSolver::setMaxIteration(cfl_size_t maxIter)
39  {
40  switch (_solverType)
41  {
42  case CMLQPSOLVER_LEMKE:
43  _solver->setNumberOfLemkeLoopsMax(maxIter);
44  break;
45  case CMLQPSOLVER_GAUSS_SEIDEL:
46  throw std::runtime_error("[CmlQuadraticSolver::setMaxIteration] There is no method to set the maximum iteration number with this type of solver");
47  }
48  }
49 
50  /* const double CmlQuadraticSolver::getTolerance(void) const
51  {
52  _solver->getTolerance();
53  }*/
54 
55  cfl_size_t CmlQuadraticSolver::getMaxIteration(void) const
56  {
57  switch (_solverType)
58  {
59  case CMLQPSOLVER_LEMKE:
60  return _solver->getNumberOfLemkeLoops();
61  case CMLQPSOLVER_GAUSS_SEIDEL:
62  throw std::runtime_error("[CmlQuadraticSolver::getMaxIteration] There is no method to get the maximum iteration number with this type of solver");
63  }
64  return 0;
65  }
66 
67  const std::string& CmlQuadraticSolver::getMoreInfo(void) const
68  {
69  //TODO [todo]
70  return "";
71  }
72 
73 
74  void CmlQuadraticSolver::addLinearEqualityConstraint(LinearConstraint* constraint)
75  {
76  if (constraint->isInequality())
77  throw std::runtime_error("[CmlQuadraticSolver::addLinearEqualityConstraint] added Constraint is not an equality" );
78 
79  _equalityConstraints.push_back(constraint);
80  _m += constraint->getDimension();
81  constraint->attach(*this);
82  addVariable(constraint->getVariable()); //invalidate _isPrepared
83  }
84 
85  void CmlQuadraticSolver::addLinearInequalityConstraint(LinearConstraint* constraint)
86  {
87  if (constraint->isEquality())
88  throw std::runtime_error("[CmlQuadraticSolver::addLinearEqualityConstraint] added Constraint is not an inequality" );
89 
90  _inequalityConstraints.push_back(constraint);
91  _p += constraint->getDimension();
92  constraint->attach(*this);
93  addVariable(constraint->getVariable()); //invalidate _isPrepared
94  }
95 
96  void CmlQuadraticSolver::removeConstraint(LinearConstraint* constraint)
97  {
98  std::vector<LinearConstraint*>* v;
99  if (constraint->isEquality())
100  v = &_equalityConstraints;
101  else
102  v = &_inequalityConstraints;
103 
104  std::vector<LinearConstraint*>::iterator it = std::find(v->begin(), v->end(), constraint);
105  if (it != v->end())
106  {
107  removeVariable((*it)->getVariable()); //invalidate _isPrepared
108  v->erase(it);
109  constraint->completelyDetach(*this);
110  if (constraint->isEquality())
111  _m -= constraint->getDimension();
112  else
113  _p -= constraint->getDimension();
114  }
115  }
116 
117 
118  void CmlQuadraticSolver::setObjective(QuadraticFunction* obj, real weight)
119  {
120  //TODO [todo] : attach to function
121  if (obj->getDimension() != 1)
122  throw std::runtime_error("[QLDSolver::setObjective] dimension of objective function is not 1. Multidimensionnal objectives are not handled by this solver");
123 
124  _objectives.clear();
125  WeightedObjective wo;
126  wo.objective = obj;
127  wo.weight = weight;
128  _objectives.push_back(wo);
129  obj->attach(*this);
130 
131  addVariable(obj->getVariable());
132  }
133 
134  void CmlQuadraticSolver::addObjective(QuadraticFunction* obj, real weight)
135  {
136  if (obj->getDimension() != 1)
137  throw std::runtime_error("[CmlQuadraticSolver::setObjective] dimension of objective function is not 1. Multidimensionnal objectives are not handled by this solver");
138 
139 
140  if (_objectives.size() == 0)
141  {
142  setObjective(obj, weight);
143  }
144  else
145  {
146  addVariable(obj->getVariable());
147  WeightedObjective wo;
148  wo.objective = obj;
149  wo.weight = weight;
150  _objectives.push_back(wo);
151  obj->attach(*this);
152  }
153  }
154 
155 
156  void CmlQuadraticSolver::removeObjective(QuadraticFunction* obj)
157  {
158  std::vector<WeightedObjective>::iterator it; // = std::find(_objectives.begin(), _objectives.end(), obj);
159 
160  for (it = _objectives.begin(); it != _objectives.end(); ++it)
161  {
162  if (it->objective == obj)
163  break;
164  }
165 
166  if (it != _objectives.end())
167  {
168  obj->completelyDetach(*this);
169  _objectives.erase(it);
170  }
171  }
172 
173 
174  void CmlQuadraticSolver::printValuesAtSolution(void)
175  {
176  _variable->setValue(_result.solution);
177  std::cout << "objective(s):" <<std::endl;
178  for (unsigned int i=0; i<_objectives.size(); ++i)
179  std::cout << _objectives[i].objective->getValues() << std::endl;
180  std::cout << "equalities:" <<std::endl;
181  for (unsigned int i=0; i<_equalityConstraints.size(); ++i)
182  std::cout << _equalityConstraints[i]->getValues() << std::endl;
183  std::cout << "inequalities:" <<std::endl;
184  for (unsigned int i=0; i<_inequalityConstraints.size(); ++i)
185  std::cout << _inequalityConstraints[i]->getValues() << std::endl;
186  }
187 
188 
189  bool CmlQuadraticSolver::checkConstraints(void)
190  {
191  _variable->setValue(_result.solution);
192  bool b = true;
193  for (unsigned int i=0; i<_equalityConstraints.size(); ++i)
194  {
195  const Vector& v =_equalityConstraints[i]->getValues();
196  for (cfl_size_t j=0; j<v.getSize(); ++j)
197  {
198  if (fabs(v[j]) > 1.e-8)
199  {
200  if (b)
201  {
202  std::cout << "equalities : " << std::endl;
203  b=false;
204  }
205  std::cout << "(" << i << "," << j << "): " << v[j] << std::endl;
206  }
207  }
208  }
209  bool c = true;
210  for (unsigned int i=0; i<_inequalityConstraints.size(); ++i)
211  {
212  const Vector& v =_inequalityConstraints[i]->getValues();
213  for (cfl_size_t j=0; j<v.getSize(); ++j)
214  {
215  if (v[j] > 1.e-7)
216  {
217  if (c)
218  {
219  std::cout << "inequalities : " << std::endl;
220  c=false;
221  }
222  std::cout << "(" << i << "," << j << "): " << v[j] << std::endl;
223  }
224  }
225  }
226  return b&&c;
227  }
228 
229 
230 
231  const MatrixBase& CmlQuadraticSolver::getP(void) const
232  {
233  return _Q;
234  }
235 
236  const MatrixBase& CmlQuadraticSolver::getA(void) const
237  {
238  return _H;
239  }
240 
241  const MatrixBase& CmlQuadraticSolver::getC(void) const
242  {
243  _minus_G.resize(_G.get_nrows(), _G.get_ncols());
244  _minus_G.setToZero();
245  CML_axpy(-1,_G, _minus_G);
246  return _minus_G;
247  }
248 
249  const VectorBase& CmlQuadraticSolver::getq(void) const
250  {
251  _minus_k.resize(_k.getSize());
252  _minus_k.copyValuesFrom(_k);
253  _minus_k *= -1;
254  return _minus_k;
255  }
256 
257  const VectorBase& CmlQuadraticSolver::getb(void) const
258  {
259  return _a;
260  }
261 
262  const VectorBase& CmlQuadraticSolver::getd(void) const
263  {
264  _minus_c.resize(_c.getSize());
265  _minus_c.copyValuesFrom(_c);
266  _minus_c *= -1;
267  return _minus_c;
268  }
269 
270  const VectorBase& CmlQuadraticSolver::getu(void) const
271  {
272  _u.resize(_k.getSize());
273  _u.fill(1e30);
274  return _u;
275  }
276 
277  const VectorBase& CmlQuadraticSolver::getl(void) const
278  {
279  _l.resize(_k.getSize());
280  _l.fill(-1e30);
281  return _l;
282  }
283 
284 
285 
286 
287  const Solver::Result& CmlQuadraticSolver::doSolve(void)
288  {
289  static int cpt =0;
290 /* cflTimer t1,t2;
291  t1.reset();
292  t1.start();*/
293  prepare();
294 #ifdef OCRA_REAL_IS_DOUBLE
295  cmlDDenseVector& res = _result.solution;
296 #else
297  cmlDDenseVector r;
298  cmlDDenseVector& res = &r;
299 #endif
300  updateMatrices();
301 // t1.stop();
302  //res.resize(_n);
303  //Debug
304 /* SubMatrix subH(_H);
305  subH.rescope(_m-6, _n, 0, 0);
306  Matrix Debug(_m-6, _n);
307  Debug.copyValuesFrom(subH);
308  SubVector suba(_a);
309  suba.rescope(_m-6, 0);
310  Vector debuga(_m-6);
311  debuga.copyValuesFrom(suba);*/
312 // t2.reset();
313 // t2.start();
314  int info = _solver->solveQP(_Q, _k, /*Debug*/ _H, /*suba*/_a, _G, _c, res);
315 // t2.stop();
316  //TODO [todo] : change _result.inform
317 // std::cout << info << " x_star " << "new " << _result.solution << std::endl;
318  //printSolution(res, *_variable, 10);
319  //printValuesAtSolution();
320 // if (!checkConstraints() && cpt%10 == 0)
321 // {
322 // printEquation(_G, _c, false, 9);
323 // printSolution(res, *_variable, 10);
324 // }
325  //printSolution(res, *_variable, 10);
326 // ++cpt;
327 // bool toto = false;
328 // if(toto)
329  //{
330  //printEquation(_H, _a, false, 9);
331  //printEquation(_G, _c, false, 9);
332  //printEquation(_Q, _k, false, 9);
333  //printSolution(res, *_variable, 15,8);
334  //}
335  //system("pause");
336 // std::cout << "prepare " << t1.getTime() << std::endl;
337 // std::cout << "solve " << t2.getTime() << std::endl;
338  //checkConstraints();
339  _result.inform = info;
340  return _result;
341  }
342 
343 
344  void CmlQuadraticSolver::doPrepare(void)
345  {
346  updateMatrixDimension();
347  }
348 
349 
350  void CmlQuadraticSolver::recomputeVariable(void)
351  {
352  _variable->clear();
353  for (unsigned int i=0; i<_objectives.size(); ++i)
354  {
355  addVariable(_objectives[i].objective->getVariable());
356  }
357  for (unsigned int i=0; i<_equalityConstraints.size(); ++i)
358  {
359  addVariable(_equalityConstraints[i]->getVariable());
360  }
361  for (unsigned int i=0; i<_inequalityConstraints.size(); ++i)
362  {
363  addVariable(_inequalityConstraints[i]->getVariable());
364  }
365  _isPrepared = false;
366  }
367 
368 
369 
370  void CmlQuadraticSolver::updateMatrixDimension(void)
371  {
372  //TODO [todo] : correctly
373  //we assume _n, _m and _p have been correctly updated
374 
375  _Q.resize(_n, _n);
376  _Q.setToZero();
377  _k.resize(_n);
378  _k.setToZero();
379  _H.resize(_m, _n);
380  _H.setToZero();
381  _a.resize(_m);
382  _a.setToZero();
383  _G.resize(_p, _n);
384  _G.setToZero();
385  _c.resize(_p);
386  _c.setToZero();
387  }
388 
389  void CmlQuadraticSolver::updateSize(void)
390  {
391  //TODO [mineur] : be more subtle
392  //this is called when a function change its dimension
393  _m=0;
394  _p=0;
395  for (unsigned int i=0; i<_equalityConstraints.size(); ++i)
396  _m += _equalityConstraints[i]->getDimension();
397  for (unsigned int i=0; i<_inequalityConstraints.size(); ++i)
398  _p += _inequalityConstraints[i]->getDimension();
399 
400  _isPrepared = false;
401  //updateMatrixDimension();
402  }
403 
404  void CmlQuadraticSolver::updateMatrices(void)
405  {
406  //updateSize(); //TODO [???]: should not be needed
407  //std::vector<cfl_size_t> workingMapping(_n);
408 
409  updateEqualityEquations(_workingMapping);
410  updateInequalityEquations(_workingMapping);
411  updateObjectiveEquations(_workingMapping);
412 
413 /* std::ofstream aofA("A.txt");
414  if (aofA.is_open())
415  {
416  for (cfl_size_t i=0; i<_m; ++i)
417  {
418  for (cfl_size_t j=0; j<_n; ++j)
419  aofA << _H(i,j) << " ";
420  aofA << std::endl;
421  }
422  aofA.close();
423  }
424 
425  std::ofstream aofb("b.txt");
426  if (aofb.is_open())
427  {
428  aofb << std::endl;
429  for (cfl_size_t i=0; i<_m; ++i)
430  {
431  aofb << _a[i] << " ";
432  }
433  aofb << std::endl;
434  aofb.close();
435  }
436 
437  std::ofstream aofC("C.txt");
438  if (aofC.is_open())
439  {
440  for (cfl_size_t i=0; i<_p; ++i)
441  {
442  for (cfl_size_t j=0; j<_n; ++j)
443  aofC << _G(i,j) << " ";
444  aofC << std::endl;
445  }
446  aofC << std::endl;
447  aofC.close();
448  }
449 
450  std::ofstream aofd("d.txt");
451  if (aofd.is_open())
452  {
453  for (cfl_size_t i=0; i<_p; ++i)
454  {
455  aofd << _c[i] << " ";
456  }
457  aofd << std::endl;
458  aofd.close();
459  }
460 */
461 /* std::ofstream aofP("P.txt");
462  if (aofP.is_open())
463  {
464  for (cfl_size_t i=0; i<_n; ++i)
465  {
466  for (cfl_size_t j=0; j<_n; ++j)
467  aofP << _Q(i,j) << " ";
468  aofP << std::endl;
469  }
470  aofP << std::endl;
471  aofP.close();
472  }
473 */
474 /* std::ofstream aofq("q.txt");
475  if (aofq.is_open())
476  {
477  for (cfl_size_t i=0; i<_n; ++i)
478  {
479  aofq << _k[i] << " ";
480  }
481  aofq.close();
482  }
483 */
484 // std::cout.precision(3);
485 // std::cout << "A " <<_H << std::endl;
486 // std::cout << "b " <<_a << std::endl;
487 
488 // std::cout << "C " <<_G << std::endl;
489 // std::cout << "d " <<_c << std::endl;
490 
491 // std::cout << "P " <<_Q << std::endl;
492 // std::cout << "q " <<_k << std::endl;
493 
494  bool toto = false;
495  if(toto)
496  {
497  //printEquation(_H, _a, false, 9);
498  printEquation(_G, _c, false, 9);
499  //printEquation(_Q, _k, false, 9);
500  }
501 // system("pause");
502  }
503 
504  void CmlQuadraticSolver::updateEqualityEquations(std::vector<cfl_size_t>& workingMapping)
505  {
506  _H.setToZero(); //TODO [mineur] : be more subtle : elements that will be replaced don't need to be put to 0
507  SubMatrix sA(_H);
508  SubVector sb(_a);
509  cfl_size_t m = 0;
510  for (unsigned int i=0; i<_equalityConstraints.size(); ++i)
511  {
512  Constraint<LinearFunction>* cstr = _equalityConstraints[i];
513  cfl_size_t dim = cstr->getDimension();
514  sA.rescope(dim, _n, m, 0);
515  sb.rescope(dim, m);
516 
517  workingMapping.resize(cstr->getVariable().getSize());
518  uncompressMatrix(*_variable, cstr->getVariable(), cstr->getGradients(), sA, workingMapping);
519 // sb.copyValuesFrom(((LinearFunction)*cstr).getb());
520  sb.copyValuesFrom(cstr->getFunction()->getb());
521 
522  m+=dim;
523  }
524 
525 
526 /* //debug
527  SubMatrix M(_H);
528  M.rescope(6,_n,_m-6,0);
529  Matrix MtM(_n, _n);
530  CML_gemm<'t','n'>(1., M, M, 0., MtM);
531  std::ofstream aofM("MtM.txt");
532  if (aofM.is_open())
533  {
534  for (cfl_size_t i=0; i<_n; ++i)
535  {
536  for (cfl_size_t j=0; j<_n; ++j)
537  aofM << MtM(i,j) << " ";
538  aofM << std::endl;
539  }
540  aofM << std::endl;
541  aofM.close();
542  }
543 
544  SubVector v(_a);
545  v.rescope(6,_m-6);
546  Vector Mtv(_n);
547  CML_gemv<'t'>(1., M, v, 0., Mtv);
548  std::ofstream aofv("Mtv.txt");
549  if (aofv.is_open())
550  {
551  for (cfl_size_t i=0; i<_n; ++i)
552  {
553  aofv << Mtv[i] << " ";
554  }
555  aofv << std::endl;
556  aofv.close();
557  }*/
558  }
559 
560 
561  void CmlQuadraticSolver::updateInequalityEquations(std::vector<cfl_size_t>& workingMapping)
562  {
563  _G.setToZero(); //TODO [mineur] : be more subtle : elements that will be replaced don't need to be put to 0
564  SubMatrix sC(_G);
565  SubVector sd(_c);
566  int m = 0;
567  for (unsigned int i=0; i<_inequalityConstraints.size(); ++i)
568  {
569  Constraint<LinearFunction>* cstr = _inequalityConstraints[i];
570  cfl_size_t dim = cstr->getDimension();
571  sC.rescope(dim, _n, m, 0);
572  sd.rescope(dim, m);
573 
574  workingMapping.resize(cstr->getVariable().getSize());
575  uncompressMatrixWithScaling(*_variable, cstr->getVariable(), cstr->getGradients(), sC, workingMapping, -1);
576  sd.copyValuesFrom(cstr->getFunction()->getb());
577  CML_scal(-1, sd);
578 
579  if (cstr->isSlacked())
580  {
581  //we need to put -1. * -I in front of the slack variable
582  _variable->getRelativeMappingOf(*cstr->getSlackVariable(), workingMapping);
583  for (cfl_size_t j=0; j<dim; ++j)
584  sC(j, workingMapping[j]) = 1;
585  }
586 
587  m+=dim;
588  }
589  }
590 
591 
592  void CmlQuadraticSolver::updateObjectiveEquations(std::vector<cfl_size_t>& workingMapping)
593  {
594  //TODO [mineur] : verify this reset is needed
595  _Q.setToZero();
596  _k.setToZero();
597 
598  int nt = 0;
599  for (unsigned int i=0; i<_objectives.size(); ++i)
600  {
601  /*int ni = (*_variable)(i).getSize();
602  sP.rescope(ni, ni, nt, nt);
603  sq.rescope(ni, nt);
604 
605  sP.setToZero();
606  sP.copyValuesFrom(_objectives[i]->getPi());
607  sq.copyValuesFrom(_objectives[i]->getqi());
608 
609  nt += ni;
610  */
611  Variable& v = _objectives[i].objective->getVariable();
612  workingMapping.resize(v.getSize());
613  addCompressedMatrix(*_variable, v, _objectives[i].objective->getPi(), _Q, workingMapping, _objectives[i].weight);
614  addCompressedVector(_objectives[i].objective->getqi(), _k, workingMapping, _objectives[i].weight);
615  }
616  CML_scal(-1., _k); //to comply with cmlQPSolver definition
617  }
618 
619 }
620 
621 #include "ocra/optim/BaseVariable.h"
622 #include "ocra/optim/CompositeVariable.h"
623 
624 namespace ocra
625 {
626  void testSolveCmlQP(void)
627  {
628  VariableManager m;
629  BaseVariable x("x", 1, m);
630  BaseVariable y("y", 1, m);
631  BaseVariable z("z", 1, m);
632 
633  CompositeVariable xy("xy", m);
634  xy.add(x).add(y);
635  CompositeVariable xz("xz", m);
636  xz.add(x).add(z);
637  CompositeVariable yz("yz", m);
638  yz.add(y).add(z);
639  CompositeVariable X("X", m);
640  X.add(x).add(y).add(z);
641 
642  Matrix A1(1,2);
643  A1(0,0) = 1;
644  A1(0,1) = 1;
645  Vector b1(1);
646  b1[0] = -1;
647  LinearFunction f1(xy, A1, b1);
648  LinearConstraint e(&f1, true);
649 
650  Matrix A2(2,3);
651  A2(0,0) = 1; A2(0,1) = -1; A2(0,2) = 1;
652  A2(1,0) = 2; A2(1,1) = 1; A2(1,2) = 1;
653  Vector b2(2);
654  b2[0] = -1; b2[1] = 2;
655  LinearFunction f2(X, A2, b2);
656  LinearConstraint i(&f2, false);
657 
658  //objectives
659  Matrix P1(1,1);
660  P1(0,0) = 1;
661  Vector q1(1);
662  q1[0] = 0;
663  QuadraticFunction o1(x, P1, q1, 0);
664 
665  Matrix P2(2,2);
666  P2(0,0) = 1; P2(0,1) = 0;
667  P2(1,0) = 0; P2(1,1) = 1;
668  Vector q2(2);
669  q2[0] = 0; q2[1] = 0;
670  QuadraticFunction o2(yz, P2, q2, 0);
671 
672 
673  CmlQuadraticSolver solver;
674  solver.setObjective(&o1);
675  solver.addObjective(&o2);
676  solver.addLinearEqualityConstraint(&e);
677  solver.addLinearInequalityConstraint(&i);
678  std::cout << solver.solve().solution << std::endl;
679  }
680 
682  {
683  VariableManager m;
684  BaseVariable x("x", 1, m);
685 
686  Matrix P1(1,1);
687  P1(0,0) = 1;
688  Vector q1(1);
689  q1[0] = 0;
690  QuadraticFunction o1(x, P1, q1, 0);
691 
692  Matrix A1(2,1);
693  A1(0,0) = 1;
694  A1(1,0) = -1;
695  Vector b1(2);
696  b1[0] = 1;
697  b1[1] = 1;
698  LinearFunction f(x, A1, b1);
699  LinearConstraint inequality(&f, false);
700 
701  CmlQuadraticSolver solver;
702  solver.addObjective(&o1);
703  solver.addLinearInequalityConstraint(&inequality);
704  solver.solve();
705  }
706 }
707 
708 #endif
709 
710 // cmake:sourcegroup=toBeUpdated
void testSolveCmlQPWithNonFeasiblePb(void)
Constraint< LinearFunction > LinearConstraint
Definition: Constraint.h:673
Optimization-based Robot Controller namespace. a library of classes to write and solve optimization p...
Declaration file of the CmlQuadraticSolver class.
double real
Definition: MathTypes.h:27
void testSolveCmlQP(void)