levmarq.h
Go to the documentation of this file.
1 #ifndef ARUCO_MM__LevMarq_H
2 #define ARUCO_MM__LevMarq_H
3 #include <Eigen/Core>
4 #include <Eigen/Cholesky>
5 #include <functional>
6 #include <iostream>
7 #include <cmath>
8 #include "ar_omp.h"
9 #include <ctime>
10 #include <cstring>
11 #include <vector>
12 #include <chrono>
13 #include <iomanip>
14 namespace aruco{
15 // Levenberg-Marquardt method for general problems Inspired in
16 //@MISC\{IMM2004-03215,
17 // author = "K. Madsen and H. B. Nielsen and O. Tingleff",
18 // title = "Methods for Non-Linear Least Squares Problems (2nd ed.)",
19 // year = "2004",
20 // pages = "60",
21 // publisher = "Informatics and Mathematical Modelling, Technical University of Denmark, {DTU}",
22 // address = "Richard Petersens Plads, Building 321, {DK-}2800 Kgs. Lyngby",
23 // url = "http://www.ltu.se/cms_fs/1.51590!/nonlinear_least_squares.pdf"
24 //}
25 template<typename T>
26 class LevMarq{
27 public:
28 
29 
31  typedef std::function<void(const eVector &, eVector &)> F_z_x;
32  typedef std::function<void(const eVector &, Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> &)> F_z_J;
33  LevMarq();
43  LevMarq(int maxIters,double minError,double min_step_error_diff=0,double tau=1 ,double der_epsilon=1e-3);
44 
54  void setParams(int maxIters,double minError,double min_step_error_diff=0,double tau=1 ,double der_epsilon=1e-3);
55 
67  double solve( eVector &z, F_z_x , F_z_J)throw (std::exception);
69 
70 
75  void init(eVector &z, F_z_x )throw (std::exception);
82  bool step( F_z_x f_z_x , F_z_J f_z_J)throw (std::exception);
83  bool step( F_z_x f_z_x)throw (std::exception);
89  double getCurrentSolution(eVector &z)throw (std::exception);
95  double getBestSolution(eVector &z)throw (std::exception);
96 
105  double solve( eVector &z, F_z_x )throw (std::exception);
106  //to enable verbose mode
107  bool & verbose(){return _verbose;}
108 
109  //sets a callback func call at each step
110  void setStepCallBackFunc(std::function<void(const eVector &)> callback){_step_callback=callback;}
111  //sets a function that indicates when the algorithm must be stop. returns true if must stop and false otherwise
112  void setStopFunction( std::function<bool(const eVector &)> stop_function){_stopFunction=stop_function;}
113 
114  void calcDerivates(const eVector & z , Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> &, F_z_x);
115 private:
118  bool _verbose;
119  //--------
120  eVector curr_z,x64;
123  double mu,v;
124  std::function<void(const eVector &)> _step_callback;
125  std::function<bool(const eVector &)> _stopFunction;
126 
127 
128 };
129 
130 
131 
132 template<typename T>
135 }
145 template<typename T>
146 LevMarq<T>::LevMarq(int maxIters,double minError,double min_step_error_diff,double tau ,double der_epsilon ){
147  _maxIters=maxIters;_minErrorAllowed=minError;_der_epsilon=der_epsilon;_verbose=false;_tau=tau;v=5;_min_step_error_diff=min_step_error_diff;
148 }
149 
159 template<typename T>
160 void LevMarq<T>::setParams(int maxIters,double minError,double min_step_error_diff,double tau ,double der_epsilon){
161  _maxIters=maxIters;
162  _minErrorAllowed=minError;
163  _der_epsilon=der_epsilon;
164  _tau=tau;
165  _min_step_error_diff=min_step_error_diff;
166 
167 }
168 
169 
170 template<typename T>
172 {
173 #pragma omp parallel for
174  for (int i=0;i<z.rows();i++) {
175  eVector zp(z),zm(z);
176  zp(i)+=_der_epsilon;
177  zm(i)-=_der_epsilon;
178  eVector xp,xm;
179  f_z_x( zp,xp);
180  f_z_x( zm,xm);
181  eVector dif=(xp-xm)/(2.f*_der_epsilon);
182  J.middleCols(i,1)=dif;
183  }
184 }
185 
186 template<typename T>
187 double LevMarq<T>:: solve( eVector &z, F_z_x f_z_x)throw (std::exception){
188  return solve(z,f_z_x,std::bind(&LevMarq::calcDerivates,this,std::placeholders::_1,std::placeholders::_2,f_z_x));
189 }
190 template<typename T>
191 bool LevMarq<T>:: step( F_z_x f_z_x)throw (std::exception){
192  return step(f_z_x,std::bind(&LevMarq::calcDerivates,this,std::placeholders::_1,std::placeholders::_2,f_z_x));
193 }
194 
195 template<typename T>
196 void LevMarq<T>::init(eVector &z, F_z_x f_z_x )throw (std::exception){
197  curr_z=z;
198  I.resize(z.rows(),z.rows());
199  I.setIdentity();
200  f_z_x(curr_z,x64);
201  minErr=currErr=prevErr=x64.cwiseProduct(x64).sum();
202  J.resize(x64.rows(),z.rows());
203  mu=-1;
204 
205 
206 }
207 
208 
209 #define splm_get_time(a,b) std::chrono::duration_cast<std::chrono::duration<double>>(a-b).count()
210 
211 
212 template<typename T>
213 bool LevMarq<T>::step( F_z_x f_z_x, F_z_J f_J)throw (std::exception){
214 
215  f_J(curr_z,J);
218 
219  eVector B=-Jt*x64;
220  if(mu<0){//first time only
221  int max=0;
222  for(int j=1;j<JtJ.cols();j++) if (JtJ(j,j)>JtJ(max,max)) max=j;
223  mu=JtJ(max,max)*_tau;
224  }
225 
226  double gain=0,prev_mu=0;
227  int ntries=0;
228  bool isStepAccepted=false;
229  do{
230  //add/update dumping factor to JtJ.
231  //very efficient in any case, but particularly if initial dump does not produce improvement and must reenter
232  for(int j=0;j<JtJ.cols();j++) JtJ(j,j) += mu-prev_mu;//update mu
233  prev_mu=mu;
234  eVector delta= JtJ.ldlt().solve(B);
235  eVector estimated_z=curr_z+delta;
236  //compute error
237  f_z_x(estimated_z,x64);
238  auto err=x64.cwiseProduct(x64).sum();
239  auto L=0.5*delta.transpose()*((mu*delta) - B);
240  gain= (err-prevErr)/ L(0,0) ;
241  //get gain
242  if (gain>0){
243  mu=mu*std::max(double(0.33),1.-pow(2*gain-1,3));
244  v=5.f;
245  currErr=err;
246  curr_z=estimated_z;
247  isStepAccepted=true;
248  }
249  else{ mu=mu*v; v=v*5;}
250 
251  }while(gain<=0 && ntries++<5);
252 
253  if (_verbose) std::cout<<std::setprecision(5) <<"Curr Error="<<currErr<<" AErr(prev-curr)="<<prevErr-currErr<<" gain="<<gain<<" dumping factor="<<mu<<std::endl;
254  // //check if we must move to the new position or exit
255  if ( currErr<prevErr)
256  std::swap ( currErr,prevErr );
257 
258  return isStepAccepted;
259 
260 }
261 
262 
263 template<typename T>
264 double LevMarq<T>:: getCurrentSolution(eVector &z)throw (std::exception){
265 
266  z=curr_z;
267  return currErr;
268 }
269 template<typename T>
270 double LevMarq<T>::solve( eVector &z, F_z_x f_z_x, F_z_J f_J)throw (std::exception){
271 
272  init(z,f_z_x);
273 
274  if( _stopFunction){
275  do{
276  step(f_z_x,f_J);
278  }while(!_stopFunction(curr_z));
279 
280  }
281  else{
282  //intial error estimation
283  int mustExit=0;
284  for ( int i = 0; i < _maxIters && !mustExit; i++ ) {
285  if (_verbose)std::cerr<<"iteration "<<i<<"/"<<_maxIters<< " ";
286  bool isStepAccepted=step(f_z_x,f_J);
287  //check if we must exit
288  if ( currErr<_minErrorAllowed ) mustExit=1;
289  if( fabs( prevErr -currErr)<=_min_step_error_diff || !isStepAccepted) mustExit=2;
290  //exit if error increment
291  if (currErr<prevErr )mustExit=3;
292  // if ( (prevErr-currErr) < 1e-5 ) mustExit=true;
294  }
295 
296 // std::cout<<"Exit code="<<mustExit<<std::endl;
297  }
298  z=curr_z;
299  return currErr;
300 
301 }
302 
303 }
304 
305 #endif
bool step(F_z_x f_z_x, F_z_J f_z_J)
step gives a step of the search
Definition: levmarq.h:213
double _der_epsilon
Definition: levmarq.h:117
Eigen::Matrix< T, Eigen::Dynamic, 1 > eVector
Definition: levmarq.h:30
f
double currErr
Definition: levmarq.h:121
double _min_step_error_diff
Definition: levmarq.h:117
const CwiseUnaryOp< internal::scalar_pow_op< Scalar >, const Derived > pow(const Scalar &exponent) const
eVector x64
Definition: levmarq.h:120
double _tau
Definition: levmarq.h:117
void init(eVector &z, F_z_x)
Step by step solve mode.
Definition: levmarq.h:196
void setParams(int maxIters, double minError, double min_step_error_diff=0, double tau=1, double der_epsilon=1e-3)
setParams
Definition: levmarq.h:160
EIGEN_STRONG_INLINE Index rows() const
double minErr
Definition: levmarq.h:121
double prevErr
Definition: levmarq.h:121
EIGEN_STRONG_INLINE void resize(Index nbRows, Index nbCols)
std::function< void(const eVector &, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &)> F_z_J
Definition: levmarq.h:32
void setStopFunction(std::function< bool(const eVector &)> stop_function)
Definition: levmarq.h:112
eVector curr_z
Definition: levmarq.h:120
double mu
Definition: levmarq.h:123
double _minErrorAllowed
Definition: levmarq.h:117
TFSIMD_FORCE_INLINE const tfScalar & z() const
std::function< bool(const eVector &)> _stopFunction
Definition: levmarq.h:125
double v
Definition: levmarq.h:123
void setStepCallBackFunc(std::function< void(const eVector &)> callback)
Definition: levmarq.h:110
double getCurrentSolution(eVector &z)
getCurrentSolution returns the current solution
Definition: levmarq.h:264
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > I
Definition: levmarq.h:122
double getBestSolution(eVector &z)
getBestSolution sets in z the best solution up to this moment
std::function< void(const eVector &, eVector &)> F_z_x
Definition: levmarq.h:31
bool & verbose()
Definition: levmarq.h:107
void calcDerivates(const eVector &z, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &, F_z_x)
Definition: levmarq.h:171
EIGEN_STRONG_INLINE Index cols() const
double solve(eVector &z, F_z_x, F_z_J)
solve non linear minimization problem ||F(z)||, where F(z)=f(z) f(z)^t
Definition: levmarq.h:270
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > J
Definition: levmarq.h:122
std::function< void(const eVector &)> _step_callback
Definition: levmarq.h:124
bool _verbose
Definition: levmarq.h:118


tuw_aruco
Author(s): Lukas Pfeifhofer
autogenerated on Mon Jun 10 2019 15:40:52