ocra-recipes
Doxygen documentation for the ocra-recipes repository
QLDSolver.cpp
Go to the documentation of this file.
1 #include "ocra/optim/QLDSolver.h"
2 
3 
4 #define SOLVER_VERBOSE 0
5 #if SOLVER_VERBOSE
6 # define IF_SOLVER_VERBOSE(x) x
7 #else
8 # define IF_SOLVER_VERBOSE(x) ((void)0);
9 #endif
10 
11 
12 namespace ocra
13 {
15  : NamedInstance("QLDSolver")
16  , QuadraticSolver(false)
17  , _pt(0)
18  , _infinity(1.e+10)
19  , _C(0x0,0,0)
20  , _d(0x0,0)
21  , _A(0x0,0,0)
22  , _b(0x0,0)
23  , _xl(0x0,0)
24  , _xu(0x0,0)
25  , _buffer(100)
26  {
27  _solver = new ObjQLD();
28  _eps = _solver->getEps();
29  }
30 
31  void QLDSolver::setTolerance(double epsilon)
32  {
33  _eps = epsilon;
34  _solver->setEps(epsilon);
35  }
36 
37  double QLDSolver::getTolerance(void) const
38  {
39  return _solver->getEps();
40  }
41 
42 
43  const std::string& QLDSolver::getMoreInfo() const
44  {
45  static const std::string info = "";
46  return info;
47  }
48 
49  MatrixXd QLDSolver::getP() const
50  {
51  return _C;
52  }
53 
54  VectorXd QLDSolver::getq() const
55  {
56  return _d;
57  }
58 
59  MatrixXd QLDSolver::getA() const
60  {
61  return _A.topRows(_m);
62  }
63 
64  VectorXd QLDSolver::getb() const
65  {
66  return _b.head(_m);
67  }
68 
69  VectorXd QLDSolver::getbp() const
70  {
71  return VectorXd::Zero(_m);
72  }
73 
74  MatrixXd QLDSolver::getC() const
75  {
76  return _A.bottomRows(_p);
77  }
78 
79  VectorXd QLDSolver::getd() const
80  {
81  return _b.tail(_p);
82  }
83 
84  VectorXd QLDSolver::getl() const
85  {
86  return VectorXd::Zero(_p);
87  }
88 
89  VectorXd QLDSolver::getu() const
90  {
91  return VectorXd::Constant(_p, 1e10);
92  }
93 
94  VectorXd QLDSolver::getxl() const
95  {
96  return _xl;
97  }
98 
99  VectorXd QLDSolver::getxu() const
100  {
101  return _xu;
102  }
103 
104 
106  {
107  resize();
108 
109  updateObjectiveEquations();
110  updateEqualityEquations();
111  updateInequalityEquations();
112  updateBounds();
113 
115  //_variable.printTree(std::cout);
116  std::cout << "obj" << std::endl;
117  std::cout << _C << std::endl << std::endl;
118  std::cout << _d << std::endl << std::endl;
119 
120  std::cout << "cstr" << std::endl;
121  std::cout << _A << std::endl << std::endl;
122  std::cout << _b << std::endl << std::endl;
123 
124  std::cout << "bnd" << std::endl;
125  std::cout << _xl << std::endl << std::endl;
126  std::cout << _xu << std::endl << std::endl;
127  system("pause");
128  )
129  }
130 
132  {
133  Map<VectorXd> x(_result.solution.data(), _result.solution.size());
134  info = _solver->solve(_C, _d, _A, _b, static_cast<int>(_m), x, _xl, _xu);
135  translateReturnInfo(_result.info, info);
136  }
137 
139  {
140  //do nothing
141  }
142 
143  void QLDSolver::resize()
144  {
145  int _n = n();
146  if (_invalidatedMP)
147  recomputeMP();
148 
149  int mp = static_cast<int>(_m+_ps);
150 
151  _buffer.resize(_n*(_n+mp+3)+mp);
152  new (&_C) MatrixMap(_buffer.allocate(_n*_n), _n, _n);
153  new (&_d) VectorMap(_buffer.allocate(_n), _n);
154  new (&_A) MatrixMap(_buffer.allocate(_n*mp), mp, _n);
155  new (&_b) VectorMap(_buffer.allocate(mp), mp);
156  new (&_xl) VectorMap(_buffer.allocate(_n), _n);
157  new (&_xu) VectorMap(_buffer.allocate(_n), _n);
158 
159  _C.setZero();
160  _d.setZero();
161  _A.setZero();
162  _b.setZero();
163  _xl.setConstant(-_infinity);
164  _xu.setConstant(+_infinity);
165  }
166 
167 
168  void QLDSolver::updateEqualityEquations()
169  {
170  int m = 0;
171  for (size_t i=0; i<_equalityConstraints.size(); ++i)
172  {
174  int dim = cstr->getDimension();
175 
176  // XXX http://eigen.tuxfamily.org/api/TopicFunctionTakingEigenTypes.html#TopicPlainFunctionsFailing
177  Eigen::Block<MatrixMap> _A_block = _A.block(m, 0, dim, n());
178  Eigen::DenseBase<VectorMap>::SegmentReturnType _b_segment = _b.segment(m, dim);
179  Eigen::VectorXd v;
180  utils::convert(*cstr, findMapping(cstr->getVariable()), CSTR_PLUS_EQUAL, _A_block, _b_segment, v);
181 
182  m += dim;
183  }
184  }
185 
186  void QLDSolver::updateInequalityEquations()
187  {
188  int p = static_cast<int>(_m);
189  for (size_t i=0; i<_inequalityConstraints.size(); ++i)
190  {
192  int dim = cstr->getDimension();
193 
194  if(cstr->getType() == CSTR_LOWER_AND_GREATER)
195  dim *= 2;
196 
197  // XXX http://eigen.tuxfamily.org/api/TopicFunctionTakingEigenTypes.html#TopicPlainFunctionsFailing
198  Eigen::Block<Eigen::Map<Eigen::MatrixXd> > _A_block = _A.block(p, 0, dim, n());
199  Eigen::VectorBlock<Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, 1> > > _b_segment = _b.segment(p, dim);
200  Eigen::VectorXd v;
201  utils::convert(*cstr, findMapping(cstr->getVariable()), CSTR_PLUS_GREATER, _A_block, _b_segment, v);
202 
203  p += dim;
204  }
205  }
206 
207  void QLDSolver::updateObjectiveEquations()
208  {
209  for (size_t i=0; i<_objectives.size(); ++i)
210  {
211  QuadraticFunction& obj = _objectives[i]->getFunction();
212  utils::addCompressed2d(obj.getPi(), _C, findMapping(obj.getVariable()), _objectives[i]->getWeight());
213  utils::addCompressedByRow(obj.getqi(), _d, findMapping(obj.getVariable()), _objectives[i]->getWeight());
214  }
215  }
216 
217  void QLDSolver::updateBounds()
218  {
219  for (size_t i=0; i<_bounds.size(); ++i)
220  {
222  const std::vector<int>& mapping = findMapping(cstr->getVariable());
223 
224  utils::intersectBounds(*cstr, mapping, _xl, _xu);
225  }
226  }
227 
228 
229  void QLDSolver::translateReturnInfo(eReturnInfo& ocraInfo, int qldInfo)
230  {
231  switch (qldInfo)
232  {
233  case 0: ocraInfo = RETURN_SUCCESS; return;
234  case 1: ocraInfo = RETURN_MAX_ITER_REACHED; return;
235  case 2: ocraInfo = RETURN_NUMERICAL_ERROR; return;
236  case 5: ocraInfo = RETURN_MEMORY_ERROR; return;
237  default:
238  if (qldInfo >10)
239  {ocraInfo = RETURN_INFEASIBLE_PROBLEM; return;}
240  else
241  throw std::runtime_error("[QLDSolver::translateReturnInfo] invalid info number.");
242  }
243  }
244 
245 #undef SOLVER_VERBOSE
246 #undef IF_SOLVER_VERBOSE
247 
248 
249  /*
250  void QLDSolver::updateInequalityEquations(std::vector<cfl_size_t>& workingMapping)
251  {
252  SubMatrix sC(_A);
253  sC.rescope(_p,_n,_m,0);
254  //sC.setToZero(); //TODO [mineur] : be more subtle : elements that will be replaced don't need to be put to 0
255  SubVector sd(_b);
256  int p = 0;
257  _pt = 0;
258  for (unsigned int i=0; i<_inequalityConstraints.size(); ++i)
259  {
260  Constraint<LinearFunction>* cstr = _inequalityConstraints[i];
261  cfl_size_t dim = cstr->getDimension();
262  sC.rescope(dim, _n, p+_m, 0);
263  sC.setToZero();
264  sd.rescope(dim, p+_m);
265 
266  workingMapping.resize(cstr->getVariable().getSize());
267  uncompressMatrixWithScaling(*_variable, cstr->getVariable(), cstr->getGradients(), sC, workingMapping, -1);
268  sd.copyValuesFrom(cstr->getFunction()->getb());
269  CML_scal(-1, sd);
270 
271  if (cstr->isSlacked())
272  {
273  //we need to put -1. * -I in front of the slack variable
274  _variable->getRelativeMappingOf(*cstr->getSlackVariable(), workingMapping);
275  for (cfl_size_t j=0; j<dim; ++j)
276  sC(j, workingMapping[j]) = 1;
277  }
278 
279  //std::cout << sC << std::endl;
280 
281  int k = transferSimpleInequalityToBounds(sC, sd);
282 
283  p+=dim-k;
284  _pt += k;
285  }
286  }
287 
288 
289  void QLDSolver::updateObjectiveEquations(std::vector<cfl_size_t>& workingMapping)
290  {
291  //TODO [mineur] : verify this reset is needed
292  _C.setToZero();
293  _d.setToZero();
294 
295  //SubMatrix sP(_C);
296  //SubVector sq(_d);
297 
298  //int nt = 0;
299  for (unsigned int i=0; i<_objectives.size(); ++i)
300  {
301  //int ni = (*_variable)(i).getSize();
302  Variable& v = _objectives[i].objective->getVariable();
303  //sP.rescope(ni, ni, nt, nt);
304  //sq.rescope(ni, nt);
305 
306  //sP.setToZero();
307  //sP.copyValuesFrom(_objectives[i]->getPi());
308 
309  //sq.copyValuesFrom(_objectives[i]->getqi());
310  workingMapping.resize(v.getSize());
311  addCompressedMatrix(*_variable, v, _objectives[i].objective->getPi(), _C, workingMapping, _objectives[i].weight);
312  addCompressedVector(_objectives[i].objective->getqi(), _d, workingMapping, _objectives[i].weight);
313 
314  //nt += ni;
315  }
316  //CML_scal(.5, _d); //to comply with QLDSolver definition
317  }
318 
319 
320  unsigned int QLDSolver::transferSimpleInequalityToBounds(MatrixBase& C, VectorBase& d)
321  {
322  std::vector<cfl_size_t> linesToBeChanged;
323 
324  // 1 - detect bound-like rows and copy the constraints into the corresponding bounds
325  for (cfl_size_t r=0; r<C.get_nrows(); ++r)
326  {
327  cfl_size_t c;
328  if (isASingleComponentRow(C, r, c))
329  {
330  linesToBeChanged.push_back(r);
331  if (C(r,c)>0) //lower bound
332  {
333  _xl[c] = std::max(-d[r]/C(r,c), _xl[c]);
334  }
335  else //upper bound
336  {
337  _xu[c] = std::min(-d[r]/C(r,c), _xu[c]);
338  }
339  }
340  }
341 
342  // 2 - suppress the rows from C and d by moving up the remaining rows
343  linesToBeChanged.push_back(C.get_nrows());
344  for (unsigned int i=0; i<linesToBeChanged.size()-1; ++i)
345  {
346  for (unsigned int j=linesToBeChanged[i]+1; j<linesToBeChanged[i+1]; ++j)
347  {
348  d[j-i-1] = d[j];
349  for (cfl_size_t c=0; c<C.get_ncols(); ++c)
350  C(j-i-1,c) = C(j,c);
351  }
352  }
353  return (unsigned int)(linesToBeChanged.size()-1);
354  }
355 
356  bool QLDSolver::isASingleComponentRow(const MatrixBase& C, const cfl_size_t rowIndex, cfl_size_t& returnColIndex)
357  {
358  int i=0;
359  for (cfl_size_t c=0; c<C.get_ncols() && i<2; ++c)
360  {
361  if (fabs(C(rowIndex, c))>_eps)
362  {
363  if (i==0)
364  {
365  returnColIndex = c;
366  }
367  ++i;
368  }
369  }
370 
371  if (i==1)
372  return true;
373  else
374  return false;
375  }*/
376 
378  {
379  BaseVariable xy("xy",2);
380  BaseVariable z("z",1);
381  CompositeVariable T("T", xy, z);
382 
383  MatrixXd A1(1,1); A1 << 1;
384  VectorXd b1(1); b1 << -3;
385  LinearFunction lf1(z, A1, b1);
386  LinearConstraint c1(&lf1, true);
387 
388  MatrixXd A2(1,2); A2 << 3,1 ;
389  VectorXd b2(1); b2 << 0;
390  LinearFunction lf2(xy, A2, b2);
391  LinearConstraint c2(&lf2, true);
392 
393  MatrixXd A3(2,2); A3 << 2,1,-0.5,1 ;
394  VectorXd b3(2); b3 << 0, 1;
395  LinearFunction lf3(xy, A3, b3);
396  LinearConstraint c3(&lf3, false);
397 
398  QuadraticFunction objFunc(T, Matrix3d::Identity(), Vector3d::Zero(), 0);
399  QuadraticObjective obj(&objFunc);
400 
401  QLDSolver solver;
402  solver.addConstraint(c1);
403  solver.addConstraint(c2);
404  solver.addConstraint(c3);
405  solver.addObjective(obj);
406 
407  std::cout << "sol = " << std::endl << solver.solve().solution << std::endl << std::endl;
408  ocra_assert(solver.getLastResult().info == 0);
409 
410 
411  solver.removeConstraint(c1);
412  IdentityFunction id(z);
413  VectorXd lz(1); lz << 1;
414  VectorXd uz(1); uz << 2;
415  IdentityConstraint bnd1(&id, lz, uz);
416  solver.addBounds(bnd1);
417  std::cout << "sol = " << std::endl << solver.solve().solution << std::endl << std::endl;
418  ocra_assert(solver.getLastResult().info == 0);
419 
420  BaseVariable t("t", 2);
421  VectorXd ut(2); ut << -4,-1;
423  BoundConstraint bnd2(&bf, false);
424  solver.addBounds(bnd2);
425 
426  QuadraticFunction objFunc2(t, Matrix2d::Identity(), Vector2d::Constant(2.71828),0);
427  QuadraticObjective obj2(&objFunc2);
428  solver.addObjective(obj2);
429  std::cout << "sol = " << std::endl << solver.solve().solution << std::endl << std::endl;
430  ocra_assert(solver.getLastResult().info == 0);
431 
432  Vector2d c3l(-1,-1);
433  c3.setL(c3l);
434  std::cout << "sol = " << std::endl << solver.solve().solution << std::endl << std::endl;
435  ocra_assert(solver.getLastResult().info == 0);
436  }
437 }
438 
439 // cmake:sourcegroup=Solvers
const Variable & getVariable() const
Definition: Function.cpp:46
Objective class.
Definition: Objective.h:44
VectorXd getl() const
Definition: QLDSolver.cpp:84
void setTolerance(double epsilon)
Definition: QLDSolver.cpp:31
void testQLDSolver()
Definition: QLDSolver.cpp:377
VectorXd getxl() const
Definition: QLDSolver.cpp:94
QuadraticSolver class.
void addCompressed2d(const MatrixBase< Derived1 > &in, MatrixBase< Derived2 > const &_out, const std::vector< int > &mapping, double scale, bool reverseMapping)
void setEps(double eps)
Definition: ObjQLD.h:77
std::vector< LinearConstraint * > _equalityConstraints
VectorXd getd() const
Definition: QLDSolver.cpp:79
VectorXd getb() const
Definition: QLDSolver.cpp:64
void removeConstraint(LinearConstraint &constraint)
int solve(Map< MatrixXd > &C, const Map< VectorXd > &d, const Map< MatrixXd > &A, const Map< VectorXd > &b, int me, Map< VectorXd > &x, const Map< VectorXd > &xl, const Map< VectorXd > &xu, bool factorizedC=false)
Definition: ObjQLD.cpp:15
ObjQLD class.
Definition: ObjQLD.h:52
OptimizationResult _result
Definition: Solver.h:215
MatrixXd getA() const
Definition: QLDSolver.cpp:59
const OptimizationResult & solve()
Definition: Solver.cpp:37
void addBounds(BoundConstraint &constraint)
const std::vector< int > & findMapping(Variable &var)
Definition: Solver.cpp:12
void resize(size_t size)
Definition: Buffer.h:40
const std::string & getMoreInfo() const
Definition: QLDSolver.cpp:43
LinearFunction class.
BoundFunction class.
Definition: BoundFunction.h:45
VectorXd getu() const
Definition: QLDSolver.cpp:89
Optimization-based Robot Controller namespace. a library of classes to write and solve optimization p...
Map< MatrixXd > MatrixMap
Definition: QLDSolver.h:41
Declaration file of the QLDSolver class.
VectorXd getq() const
Definition: QLDSolver.cpp:54
Constraint class.
Definition: Constraint.h:100
void addConstraint(LinearConstraint &constraint)
double getTolerance(void) const
Definition: QLDSolver.cpp:37
void convert(const LinearConstraint &cstr, const std::vector< int > &mapping, eConstraintOutput type, MatrixBase< Derived > &A, VectorBase1 &b, VectorBase2 &l, double infinity=0.)
const VectorXd & getqi(int index=0) const
void addCompressedByRow(const MatrixBase< Derived1 > &in, MatrixBase< Derived2 > const &_out, const std::vector< int > &mapping, double scale, bool reverseMapping)
const MatrixXd & getPi(int index=0) const
QLDSolver class.
Definition: QLDSolver.h:37
Map< VectorXd > VectorMap
Definition: QLDSolver.h:42
std::vector< LinearConstraint * > _inequalityConstraints
const OptimizationResult & getLastResult() const
Definition: Solver.cpp:59
void addObjective(QuadraticObjective &obj)
void intersectBounds(const DiagonalLinearConstraint &bounds, const std::vector< int > &mapping, VectorBase1 &bl, VectorBase2 &bu)
std::vector< DiagonalLinearConstraint * > _bounds
std::vector< QuadraticObjective * > _objectives
VectorXd getbp() const
Definition: QLDSolver.cpp:69
A concatenation of base variables and other composite variables.
Definition: Variable.h:357
int n()
Definition: Solver.h:146
double getEps(void) const
Definition: ObjQLD.h:76
#define ocra_assert(ocra_expression)
Definition: ocra_assert.h:45
QuadraticFunction class.
VectorXd getxu() const
Definition: QLDSolver.cpp:99
MatrixXd getP() const
Definition: QLDSolver.cpp:49
MatrixXd getC() const
Definition: QLDSolver.cpp:74
IdentityFunction class.
Implements a basic variable.
Definition: Variable.h:304
#define IF_SOLVER_VERBOSE(x)
Definition: QLDSolver.cpp:8
ptr_type allocate(size_t n)
Definition: Buffer.h:68