ocra-recipes
Doxygen documentation for the ocra-recipes repository
NewtonSolver.cpp
Go to the documentation of this file.
2 #include <limits>
3 
4 namespace ocra
5 {
6  NewtonSolver::NewtonSolver(bool fullNewton)
7  : NamedInstance("NewtonSolver")
8  , _adaptativeAlpha(true)
9  , _completeMethod(fullNewton)
10  , _maxIter(100)
11  , _alpha(1)
12  , _epsilonSqr(1e-12)
13  , _x(0x0,0)
14  , _H(0x0,0,0)
15  , _g(0x0,0)
16  , _p(0x0,0)
17  , _buffer(1000)
18  , _ldlt(10)
19  {
20  }
21 
23  {
24  _adaptativeAlpha = adapt;
25  }
26 
28  {
29  return _adaptativeAlpha;
30  }
31 
32  void NewtonSolver::setEpsilon(double eps)
33  {
34  ocra_assert(eps > 0);
35  _epsilonSqr = eps*eps;
36  }
37 
38  double NewtonSolver::getEpsilon() const
39  {
40  return std::sqrt(_epsilonSqr);
41  }
42 
43  void NewtonSolver::setMaxIter(int maxIter)
44  {
45  ocra_assert(maxIter>0);
46  _maxIter = maxIter;
47  }
48 
50  {
51  return _maxIter;
52  }
53 
54  void NewtonSolver::set_x0(const VectorXd& x0)
55  {
56  _x0 = x0;
57  }
58 
59  const VectorXd& NewtonSolver::get_x0() const
60  {
61  return _x0;
62  }
63 
65  {
68  _objectives.push_back(&obj);
69  }
70 
72  {
73  for(size_t i = 0; i < _objectives.size(); ++i)
74  {
75  if(&_objectives[i]->getFunction() == &obj)
76  {
77  removeObjective(*_objectives[i]);
78  break;
79  }
80  }
81  }
82 
84  {
86  _objectives.erase(std::find(_objectives.begin(), _objectives.end(), &obj));
87  }
88 
90  {
91  std::cout << "objective(s):" <<std::endl;
92  for (unsigned int i=0; i<_objectives.size(); ++i)
93  std::cout << _objectives[i]->getValue() << std::endl;
94  }
95 
96  std::string NewtonSolver::toString()
97  {
98  return "non implemented yet";
99  }
100 
102  {
103  const int s=n();
104  if (s!=_H.rows())
105  {
106  _buffer.resize(s*(2*s+3));
107  new (&_H) MatrixMap(_buffer.allocate(s*s), s, s);
108  _tmpHbuf = _buffer.allocate(s*s);
109  new (&_g) VectorMap(_buffer.allocate(s), s);
110  _tmpgbuf = _buffer.allocate(s);
111  new (&_p) VectorMap(_buffer.allocate(s), s);
112  new (&_ldlt) LDLT<MatrixXd>(s);
113  }
114  }
115 
117  {
118  initInfo();
119  _alpha = 1;
120  new (&_x) VectorMap(_result.solution.data(), _result.solution.size());
121  if (_x0.size() != _x.size())
122  {
123  _x0 = VectorXd::Zero(_x.size());
124  _info.usedDefaultGuess = false;
125  }
126  newtonSolve();
127  _info.residual = std::sqrt(_info.residual);
128  translateReturnInfo(_result.info);
129  }
130 
132  {
133  }
134 
135  void NewtonSolver::initInfo()
136  {
137  _info.iter = 1;
138  _info.residual = std::numeric_limits<double>::max();
139  _info.usedDefaultGuess = true;
140  _info.nonPositiveH = false;
141  _info.smallAlpha = false;
142  }
143 
144 
145  void NewtonSolver::newtonSolve()
146  {
147  _x=_x0;
148  for (; _info.iter<=_maxIter; ++_info.iter)
149  {
150  setVariableValue(_x);
151  compute_H();
152  _ldlt.compute(_H); //[TODO] this line create a temporary, see eigen's mailing list thread "Accepting different matrix type in the decompositions"
153  if (!_ldlt.isPositive())
154  {
155  _info.nonPositiveH = true;
156  _info.success = false;
157  return;
158  }
159  compute_g();
160  _p = _ldlt.solve(_g);
161  _x -= compute_alpha()*_p;
162 
163  if (_info.residual < _epsilonSqr)
164  break;
165  }
166  //std::cout << "nb iteration: " << i << std::endl;
167  _info.success = _info.iter <= _maxIter;
168  _info.smallAlpha = _alpha < std::sqrt(getEpsilon());
169  _x0 = _x;
170  }
171 
172  double NewtonSolver::compute_alpha()
173  {
174  if (_adaptativeAlpha)
175  {
176  double ri = _alpha*_alpha*_p.squaredNorm();
177  if (ri >= _info.residual)
178  {
179  _alpha /=2;
180  _info.residual = ri/4;
181  return _alpha;
182  }
183  else
184  {
185  double newAlpha = _alpha;
186  _info.residual = ri;
187  _alpha = std::min<double> (_alpha * 1.1, 1.0);
188  return newAlpha;
189  }
190  }
191  else
192  {
193  _info.residual = _alpha*_alpha*_p.squaredNorm();
194  return _alpha;
195  }
196  }
197 
198  void NewtonSolver::compute_H()
199  {
200  _H.setZero();
201  for (size_t i=0; i<_objectives.size(); ++i)
202  {
203  Function& obj = _objectives[i]->getFunction();
204  if (obj.canCompute<PARTIAL_XX>() && _completeMethod)
205  {
206  ocra_assert(false && "non implemented yet");
207  }
208  else
209  {
210  const int s = obj.getVariable().getSize();
211  MatrixMap _tmpH(_tmpHbuf, s, s);
212  const MatrixXd& J = obj.getJacobian();
213  _tmpH = J.transpose()*J;
214  utils::addCompressed2d(_tmpH, _H, findMapping(obj.getVariable()), _objectives[i]->getWeight());
215  }
216  }
217  }
218 
219  void NewtonSolver::compute_g()
220  {
221  _g.setZero();
222  for (size_t i=0; i<_objectives.size(); ++i)
223  {
224  Function& obj = _objectives[i]->getFunction();
225  const int s = obj.getVariable().getSize();
226  VectorMap _tmpg(_tmpgbuf, s);
227  _tmpg = obj.getJacobian().transpose()*obj.getValue();
228  utils::addCompressedByRow(_tmpg, _g, findMapping(obj.getVariable()), _objectives[i]->getWeight());
229  }
230  }
231 
232  void NewtonSolver::translateReturnInfo(eReturnInfo& ocraInfo)
233  {
234  if (_info.success)
235  ocraInfo = RETURN_SUCCESS;
236  else if (_info.iter>_maxIter)
237  ocraInfo = RETURN_MAX_ITER_REACHED;
238  else if (_info.nonPositiveH)
239  ocraInfo = RETURN_INCONSISTENT_PROBLEM;
240  else
241  ocraInfo = RETURN_ERROR;
242  }
243 
244 }
245 
246 
249 #include "ocra/optim/QLDSolver.h"
250 
251 namespace ocra
252 {
254  {
255  NewtonSolver solver;
256  //solver.setAdaptativeAlpha(false);
257  //solver.setMaxIter(10);
258 
259  const int n1 = 15;
260  const int n2 = 5;
261  BaseVariable x("x", n1);
262  BaseVariable y("y", n2);
263  CompositeVariable xy("xy", x, y);
264 
265  MatrixXd A1 = MatrixXd::Random(n1,n1);
266  VectorXd b1 = VectorXd::Random(n1);
267  MatrixXd A2 = 100*MatrixXd::Random(n2,n2);
268  VectorXd b2 = 100*VectorXd::Random(n2);
269  LinearFunction* fx = new LinearFunction(x, A1, b1);
270  LinearFunction* fy = new LinearFunction(y, A2, b2);
271 
274 
275  solver.addObjective(obj_x);
276  solver.addObjective(obj_y);
277  std::cout << solver.solve().solution.transpose() << std::endl;
278 
281  QLDSolver solverQP;
282  solverQP.addObjective(obj_x2);
283  solverQP.addObjective(obj_y2);
284  std::cout << solverQP.solve().solution.transpose() << std::endl;
285 
286  if ((solver.getLastResult().solution-solverQP.getLastResult().solution).isZero())
287  std::cout << "It works !" << std::endl;
288  else
289  std::cout << "It doesn't work !" << std::endl;
290  }
291 
292 
294  {
295  NewtonSolver solver;
296  //solver.setAdaptativeAlpha(false);
297  //solver.setMaxIter(10);
298 
299  const int n1 = 15;
300  const int n2 = 5;
301  const double a=0.01;
302  BaseVariable x("x", n1);
303  BaseVariable y("y", n2);
304  CompositeVariable xy("xy", x, y);
305 
306  MatrixXd A1 = MatrixXd::Random(n1,n1);
307  VectorXd b1 = VectorXd::Random(n1);
308  MatrixXd A2 = 100*MatrixXd::Random(n2,n2);
309  VectorXd b2 = 100*VectorXd::Random(n2);
310  LinearFunction* fx = new LinearFunction(x, A1, b1);
311  LinearFunction* fy = new LinearFunction(y, A2, b2);
312 
315 
316  solver.addObjective(obj_x);
317  solver.addObjective(obj_y);
318 
319  for (int i=0; i<100; ++i)
320  {
321  std::cout << solver.solve().solution.transpose() << std::endl;
322  A1 += a*MatrixXd::Random(n1,n1);
323  b1 += a*VectorXd::Random(n1);
324  A2 += a*MatrixXd::Random(n2,n2);
325  b2 += a*VectorXd::Random(n2);
326  fx->changeA(A1);
327  fx->changeb(b1);
328  fy->changeA(A2);
329  fy->changeb(b2);
330  }
331  }
332 }
333 
334 // cmake:sourcegroup=Solvers
const Variable & getVariable() const
Definition: Function.cpp:46
const VectorXd & get_x0() const
void setVariableValue(const VectorXd &value)
Definition: Solver.h:150
NewtonSolver class.
Definition: NewtonSolver.h:51
void changeA(const MatrixXd &A)
void printValuesAtSolution()
void testNewtonSolver01()
void internalAddObjective(const GenericObjective &objective)
Definition: Solver.cpp:77
void addCompressed2d(const MatrixBase< Derived1 > &in, MatrixBase< Derived2 > const &_out, const std::vector< int > &mapping, double scale, bool reverseMapping)
Eigen::Map< MatrixXd > MatrixMap
Definition: NewtonSolver.h:55
Declaration file of the SquaredLinearFunction class.
void set_x0(const VectorXd &x0)
OptimizationResult _result
Definition: Solver.h:215
const OptimizationResult & solve()
Definition: Solver.cpp:37
const std::vector< int > & findMapping(Variable &var)
Definition: Solver.cpp:12
std::string toString()
void resize(size_t size)
Definition: Buffer.h:40
void setAdaptativeAlpha(bool adapt)
void changeb(const VectorXd &b)
LinearFunction class.
void internalRemoveObjective(const GenericObjective &objective)
Definition: Solver.cpp:106
Declaration file of the NewtonSolver class.
Optimization-based Robot Controller namespace. a library of classes to write and solve optimization p...
Function class.
Definition: Function.h:77
Declaration file of the QLDSolver class.
void setEpsilon(double eps)
const MatrixXd & getJacobian() const
Definition: Function.h:375
bool canCompute() const
Definition: Function.h:347
Eigen::Map< VectorXd > VectorMap
Definition: NewtonSolver.h:56
int getSize() const
Definition: Variable.cpp:81
bool getAdaptativeAlpha() const
void addCompressedByRow(const MatrixBase< Derived1 > &in, MatrixBase< Derived2 > const &_out, const std::vector< int > &mapping, double scale, bool reverseMapping)
SquaredLinearFunction class.
const VectorXd & getValue() const
Definition: Function.h:365
QLDSolver class.
Definition: QLDSolver.h:37
const OptimizationResult & getLastResult() const
Definition: Solver.cpp:59
int getMaxIter() const
void addObjective(QuadraticObjective &obj)
virtual Function & getFunction()
Definition: Objective.h:97
void addObjective(GenericObjective &obj)
A concatenation of base variables and other composite variables.
Definition: Variable.h:357
int n()
Definition: Solver.h:146
void testNewtonSolver02()
void setMaxIter(int maxIter)
#define ocra_assert(ocra_expression)
Definition: ocra_assert.h:45
void removeObjective(Function &obj)
double getEpsilon() const
Implements a basic variable.
Definition: Variable.h:304
ptr_type allocate(size_t n)
Definition: Buffer.h:68