DirectTrajectoryOptimization  v0.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
CostFunctionAutoDiffDerivativeBase.hpp
1 /***********************************************************************************
2 Copyright (c) 2017, Diego Pardo. All rights reserved.
3 
4 Redistribution and use in source and binary forms, with or without modification,
5 are permitted provided that the following conditions are met:
6  * Redistributions of source code must retain the above copyright notice,
7  this list of conditions and the following disclaimer.
8  * Redistributions in binary form must reproduce the above copyright notice,
9  this list of conditions and the following disclaimer in the documentation
10  and/or other materials provided with the distribution.
11  * Neither the name of ETH ZURICH nor the names of its contributors may be used
12  to endorse or promote products derived from this software without specific
13  prior written permission.
14 
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
16 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
18 SHALL ETH ZURICH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
19 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 ***************************************************************************************/
25 
26 /*
27  * CostFunctionBase.hpp
28  *
29  * created on 06.06.2015
30  *
31  * Based on the original "CostFunctionBase.hpp" version of
32  *
33  * Created on: 26.03.2014
34  * Author: neunertm
35  */
36 #ifndef DOXYGEN_SHOULD_SKIP_THIS
37 
38 #ifndef COSTFUNCTIONAUTODIFFDERIVATIVEBASE_HPP_
39 #define COSTFUNCTIONAUTODIFFDERIVATIVEBASE_HPP_
40 
41 #include <Eigen/Dense>
42 #include <unsupported/Eigen/NonLinearOptimization>
43 #include <unsupported/Eigen/AutoDiff>
44 #include <iostream>
45 
46 template <class DIMENSIONS>
47 class CostFunctionAutoDiffDerivativeBase
48 {
49 public:
50 
51  EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
52 
53  typedef typename DIMENSIONS::state_vector_t state_vector_t;
54  typedef typename DIMENSIONS::state_vector_array_t state_vector_array_t;
55  typedef typename DIMENSIONS::state_matrix_t state_matrix_t;
56  typedef typename DIMENSIONS::control_vector_t control_vector_t;
57  typedef typename DIMENSIONS::control_vector_array_t control_vector_array_t;
58  typedef typename DIMENSIONS::control_matrix_t control_matrix_t;
59  typedef typename DIMENSIONS::control_feedback_t control_feedback_t;
60  typedef typename DIMENSIONS::scalar_t scalar_t;
61 
62  // Generic functor
63  template<typename _Scalar>
64  struct Functor
65  {
66  typedef _Scalar Scalar;
67  enum {
68  InputsAtCompileTime = Eigen::Dynamic,
69  ValuesAtCompileTime = Eigen::Dynamic
70  };
71  typedef Eigen::Matrix<Scalar,InputsAtCompileTime,1> InputType;
72  typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
73  typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
74 
75  const int m_inputs, m_values;
76 
77  Functor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
78  Functor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
79 
80  int inputs() const { return m_inputs; } // number of degree of freedom (= 2*nb_vertices)
81  int values() const { return m_values; } // number of energy terms (= nb_vertices + nb_edges)
82 
83 
84  };
85 
86 
87  // Specialized functor warping the function to be derived
88  struct iklike_functor : Functor<double>
89  {
90  typedef Eigen::AutoDiffScalar<Eigen::Matrix<double,Eigen::Dynamic,1> > ADS;
91  typedef Eigen::Matrix<ADS, Eigen::Dynamic, 1> VectorXad;
92 
93  // pfirst and plast are the two extremities of the curve
94  iklike_functor(const int inputs_size, const int values_size)
95  : Functor<double>(inputs_size,values_size), // and initialize stuff
96  m_targetAngles(targetAngles), m_targetLengths(targetLengths), m_beta(beta),
97  m_pfirst(pfirst), m_plast(plast)
98  {}
99 
100  // input = x = { ..., x_i, y_i, ....}
101  // output = fvec = the value of each term
102  int operator()(const Eigen::VectorXd &inputs, Eigen::VectorXd &val_of_function)
103  {
104  //I don't like this :using namespace Eigen;
105  Eigen::VectorXd curves(this->inputs()+8); //so the curves are larger than the inputs
106 
107  curves.segment(4,this->inputs()) = inputs;
108  //what is with the other values
109 
110  Vector2d d(1,0);
111  curves.segment<2>(0) = m_pfirst - d;
112  curves.segment<2>(2) = m_pfirst;
113  curves.segment<2>(this->inputs()+4) = m_plast;
114  curves.segment<2>(this->inputs()+6) = m_plast + d;
115 
116  ikLikeCosts(curves, m_targetAngles, m_targetLengths, m_beta, fvec);
117  return 0;
118  }
119 
120  // Compute the jacobian into fjac for the current solution x
121  int df(const Eigen::VectorXd &x, Eigen::MatrixXd &fjac)
122  {
123  using namespace Eigen;
124  VectorXad curves(this->inputs()+8);
125 
126  // Compute the derivatives of each degree of freedom
127  // -> grad( x_i ) = (0, ..., 0, 1, 0, ..., 0) ; 1 is in position i
128  for(int i=0; i<this->inputs();++i)
129  curves(4+i) = ADS(x(i), this->inputs(), i);
130 
131  Vector2d d(1,0);
132  curves.segment<2>(0) = (m_pfirst - d).cast<ADS>();
133  curves.segment<2>(2) = (m_pfirst).cast<ADS>();
134  curves.segment<2>(this->inputs()+4) = (m_plast).cast<ADS>();
135  curves.segment<2>(this->inputs()+6) = (m_plast + d).cast<ADS>();
136 
137  VectorXad v(this->values());
138 
139  ikLikeCosts(curves, m_targetAngles, m_targetLengths, m_beta, v);
140 
141  // copy the gradient of each energy term into the Jacobian
142  for(int i=0; i<this->values();++i)
143  fjac.row(i) = v(i).derivatives();
144 
145  return 0;
146  }
147 
148  const Eigen::VectorXd& m_targetAngles;
149  const Eigen::VectorXd& m_targetLengths;
150  double m_beta;
151  Eigen::Vector2d m_pfirst, m_plast;
152  };
153 
154 
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 
165 
166 
167 
168 
169 
170 
171 
172 
173 
174 
175 
176 
177 
178 
179 
180 
181 
182 
183 
184 
185 
186 
187 // END OF FILE
188 
189  // Specialized functor warping the ikLikeCosts function
190  struct iklike_functor : Functor<double>
191  {
192  typedef Eigen::AutoDiffScalar<Eigen::Matrix<Scalar,Eigen::Dynamic,1> > ADS;
193  typedef Eigen::Matrix<ADS, Eigen::Dynamic, 1> VectorXad;
194 
195  // pfirst and plast are the two extremities of the curve
196  iklike_functor(const Eigen::VectorXd& targetAngles, const Eigen::VectorXd& targetLengths, double beta, const Eigen::Vector2d pfirst, const Eigen::Vector2d plast)
197  : Functor<double>(targetAngles.size()*2-4,targetAngles.size()*2-1),
198  m_targetAngles(targetAngles), m_targetLengths(targetLengths), m_beta(beta),
199  m_pfirst(pfirst), m_plast(plast)
200  {}
201 
202  // input = x = { ..., x_i, y_i, ....}
203  // output = fvec = the value of each term
204  int operator()(const Eigen::VectorXd &x, Eigen::VectorXd &fvec)
205  {
206  using namespace Eigen;
207  VectorXd curves(this->inputs()+8);
208 
209  curves.segment(4,this->inputs()) = x;
210 
211  Vector2d d(1,0);
212  curves.segment<2>(0) = m_pfirst - d;
213  curves.segment<2>(2) = m_pfirst;
214  curves.segment<2>(this->inputs()+4) = m_plast;
215  curves.segment<2>(this->inputs()+6) = m_plast + d;
216 
217  ikLikeCosts(curves, m_targetAngles, m_targetLengths, m_beta, fvec);
218  return 0;
219  }
220 
221  // Compute the jacobian into fjac for the current solution x
222  int df(const Eigen::VectorXd &x, Eigen::MatrixXd &fjac)
223  {
224  using namespace Eigen;
225  VectorXad curves(this->inputs()+8);
226 
227  // Compute the derivatives of each degree of freedom
228  // -> grad( x_i ) = (0, ..., 0, 1, 0, ..., 0) ; 1 is in position i
229  for(int i=0; i<this->inputs();++i)
230  curves(4+i) = ADS(x(i), this->inputs(), i);
231 
232  Vector2d d(1,0);
233  curves.segment<2>(0) = (m_pfirst - d).cast<ADS>();
234  curves.segment<2>(2) = (m_pfirst).cast<ADS>();
235  curves.segment<2>(this->inputs()+4) = (m_plast).cast<ADS>();
236  curves.segment<2>(this->inputs()+6) = (m_plast + d).cast<ADS>();
237 
238  VectorXad v(this->values());
239 
240  ikLikeCosts(curves, m_targetAngles, m_targetLengths, m_beta, v);
241 
242  // copy the gradient of each energy term into the Jacobian
243  for(int i=0; i<this->values();++i)
244  fjac.row(i) = v(i).derivatives();
245 
246  return 0;
247  }
248 
249  const Eigen::VectorXd& m_targetAngles;
250  const Eigen::VectorXd& m_targetLengths;
251  double m_beta;
252  Eigen::Vector2d m_pfirst, m_plast;
253  };
254 
255 
256  CostFunctionAutoDiffDerivativeBase() {};
257  virtual ~CostFunctionAutoDiffDerivativeBase() {};
258 
259  virtual void setCurrentStateAndControl(const state_vector_t& x, const control_vector_t& u) {
260  x_ = x;
261  u_ = u;
262  }
263 
264  virtual void setCurrentTrajectory(const state_vector_array_t & x_traj, const control_vector_array_t & u_traj, const Eigen::VectorXd & h_traj)
265  {};
266 
267  virtual double evaluate() = 0;
268 
269  virtual int getNumberOfDependentVariables() = 0 ;
270  /*
271  virtual state_vector_t stateDerivative() = 0;
272  virtual state_matrix_t stateSecondDerivative() = 0;
273  virtual control_vector_t controlDerivative() = 0;
274  virtual control_matrix_t controlSecondDerivative() = 0;
275  */
276 
277  virtual void gradient_xuh(Eigen::VectorXd & f0_gradient) = 0;
278 
279 protected:
280  state_vector_t x_;
281  control_vector_t u_;
282 };
283 
284 
285 // Computes the energy terms into costs. The first part contains termes related to edge length variation,
286 // and the second to angle variations.
287 template<typename Scalar>
288 void ikLikeCosts(const Eigen::Matrix<Scalar,Eigen::Dynamic,1>& curve, const Eigen::VectorXd& targetAngles, const Eigen::VectorXd& targetLengths, double beta,
289  Eigen::Matrix<Scalar,Eigen::Dynamic,1>& costs)
290 {
291  using namespace Eigen;
292  using std::atan2;
293 
294  typedef Matrix<Scalar,2,1> Vec2;
295  int nb = curve.size()/2;
296 
297  costs.setZero();
298  for(int k=1;k<nb-1;++k)
299  {
300  Vec2 pk0 = curve.template segment<2>(2*(k-1));
301  Vec2 pk = curve.template segment<2>(2*k);
302  Vec2 pk1 = curve.template segment<2>(2*(k+1));
303 
304  if(k+1<nb-1) {
305  costs((nb-2)+(k-1)) = (pk1-pk).norm() - targetLengths(k-1);
306  }
307 
308 
309  Vec2 v0 = (pk-pk0).normalized();
310  Vec2 v1 = (pk1-pk).normalized();
311 
312  costs(k-1) = beta * (atan2(-v0.y() * v1.x() + v0.x() * v1.y(), v0.x() * v1.x() + v0.y() * v1.y()) - targetAngles(k-1));
313  }
314 }
315 
316 void draw_vecX(const Eigen::VectorXd& res)
317 {
318  for( int i = 0; i < (res.size()/2) ; i++ )
319  {
320  std::cout << res.segment<2>(2*i).transpose() << "\n";
321  }
322 }
323 
324 
325 
326 int main()
327 {
328  Eigen::Vector2d pfirst(-5., 0.);
329  Eigen::Vector2d plast ( 5., 0.);
330 
331  // rest pose is a straight line starting between first and last point
332  const int nb_points = 30;
333  Eigen::VectorXd targetAngles (nb_points);
334  targetAngles.fill(0);
335 
336  Eigen::VectorXd targetLengths(nb_points-1);
337  double val = (pfirst-plast).norm() / (double)(nb_points-1);
338  targetLengths.fill(val);
339 
340 
341  // get initial solution
342  Eigen::VectorXd x((nb_points-2)*2);
343  for(int i = 1; i < (nb_points - 1); i++)
344  {
345  double s = (double)i / (double)(nb_points-1);
346  x.segment<2>((i-1)*2) = plast * s + pfirst * (1. - s);
347  }
348 
349  // move last point
350  plast = Eigen::Vector2d(4., 1.);
351 
352  // Create the functor object
353  iklike_functor func(targetAngles, targetLengths, 0.1, pfirst, plast);
354 
355  // construct the solver
356  Eigen::LevenbergMarquardt<iklike_functor> lm(func);
357 
358  // adjust tolerance
359  lm.parameters.ftol *= 1e-2;
360  lm.parameters.xtol *= 1e-2;
361  lm.parameters.maxfev = 2000;
362 
363 
364  int a = lm.minimize(x);
365  std::cerr << "info = " << a << " " << lm.nfev << " " << lm.njev << " " << "\n";
366 
367  std::cout << pfirst.transpose() << "\n";
368  draw_vecX( x);
369  std::cout << plast.transpose() << "\n";
370 }
371 
372 
373 #endif /* COSTFUNCTIONAUTODIFFDERIVATIVEBASE_HPP_ */
374 #endif /* DOXYGEN_SHOULD_SKIP_THIS */