00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifndef CLevenbergMarquardt_H
00029 #define CLevenbergMarquardt_H
00030
00031 #include <mrpt/utils/CDebugOutputCapable.h>
00032 #include <mrpt/math/CMatrixD.h>
00033 #include <mrpt/math/utils.h>
00034
00035
00036
00037
00038 namespace mrpt
00039 {
00040 namespace math
00041 {
00042
00043
00044
00045
00046
00047
00048
00049
00050 template <typename VECTORTYPE = mrpt::vector_double, class USERPARAM = VECTORTYPE >
00051 class CLevenbergMarquardtTempl : public mrpt::utils::CDebugOutputCapable
00052 {
00053 public:
00054 typedef typename VECTORTYPE::value_type NUMTYPE;
00055
00056
00057
00058
00059
00060
00061
00062 typedef void (*TFunctorEval)(
00063 const VECTORTYPE &x,
00064 const USERPARAM &y,
00065 VECTORTYPE &out);
00066
00067
00068
00069 typedef void (*TFunctorIncrement)(
00070 VECTORTYPE &x_new,
00071 const VECTORTYPE &x_old,
00072 const VECTORTYPE &x_incr,
00073 const USERPARAM &user_param);
00074
00075 struct TResultInfo
00076 {
00077 NUMTYPE final_sqr_err;
00078 size_t iterations_executed;
00079 VECTORTYPE last_err_vector;
00080 CMatrixTemplateNumeric<NUMTYPE> path;
00081
00082
00083
00084
00085
00086
00087 };
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 static void execute(
00099 VECTORTYPE &out_optimal_x,
00100 const VECTORTYPE &x0,
00101 TFunctorEval functor,
00102 const VECTORTYPE &increments,
00103 const USERPARAM &userParam,
00104 TResultInfo &out_info,
00105 bool verbose = false,
00106 const size_t maxIter = 200,
00107 const NUMTYPE tau = 1e-3,
00108 const NUMTYPE e1 = 1e-8,
00109 const NUMTYPE e2 = 1e-8,
00110 bool returnPath =true,
00111 TFunctorIncrement x_increment_adder = NULL
00112 )
00113 {
00114 using namespace mrpt;
00115 using namespace mrpt::utils;
00116 using namespace mrpt::math;
00117 using namespace std;
00118
00119 MRPT_START
00120
00121 VECTORTYPE &x=out_optimal_x;
00122
00123
00124 ASSERT_( increments.size() == x0.size() );
00125
00126 x=x0;
00127 VECTORTYPE f_x;
00128 CMatrixTemplateNumeric<NUMTYPE> AUX;
00129 CMatrixTemplateNumeric<NUMTYPE> J;
00130 CMatrixTemplateNumeric<NUMTYPE> H;
00131 VECTORTYPE g;
00132
00133
00134 mrpt::math::estimateJacobian( x, functor, increments, userParam, J);
00135 H.multiply_AtA(J);
00136
00137 const size_t H_len = H.getColCount();
00138
00139
00140 functor(x, userParam ,f_x);
00141 J.multiply_Atb(f_x, g);
00142
00143
00144 bool found = math::norm_inf(g)<=e1;
00145 if (verbose && found) printf_debug("[LM] End condition: math::norm_inf(g)<=e1 :%f\n",math::norm_inf(g));
00146
00147 NUMTYPE lambda = tau * H.maximumDiagonal();
00148 size_t iter = 0;
00149 NUMTYPE v = 2;
00150
00151 VECTORTYPE h_lm;
00152 VECTORTYPE xnew, f_xnew ;
00153 NUMTYPE F_x = pow( math::norm( f_x ), 2);
00154
00155 const size_t N = x.size();
00156
00157 if (returnPath) {
00158 out_info.path.setSize(maxIter,N+1);
00159 out_info.path.block(iter,0,1,N) = x.transpose();
00160 } else out_info.path = Eigen::Matrix<NUMTYPE,Eigen::Dynamic,Eigen::Dynamic>();
00161
00162 while (!found && ++iter<maxIter)
00163 {
00164
00165 for (size_t k=0;k<H_len;k++)
00166 H(k,k)+= lambda;
00167
00168
00169 H.inv_fast(AUX);
00170 AUX.multiply_Ab(g,h_lm);
00171 h_lm *= NUMTYPE(-1.0);
00172
00173 double h_lm_n2 = math::norm(h_lm);
00174 double x_n2 = math::norm(x);
00175
00176 if (verbose) printf_debug( (format("[LM] Iter: %u x:",(unsigned)iter)+ sprintf_vector(" %f",x) + string("\n")).c_str() );
00177
00178 if (h_lm_n2<e2*(x_n2+e2))
00179 {
00180
00181 found = true;
00182 if (verbose) printf_debug("[LM] End condition: %e < %e\n", h_lm_n2, e2*(x_n2+e2) );
00183 }
00184 else
00185 {
00186
00187 if (!x_increment_adder)
00188 xnew = x + h_lm;
00189 else x_increment_adder(xnew, x, h_lm, userParam);
00190
00191 functor(xnew, userParam ,f_xnew );
00192 const double F_xnew = pow( math::norm(f_xnew), 2);
00193
00194
00195 VECTORTYPE tmp(h_lm);
00196 tmp *= lambda;
00197 tmp -= g;
00198 tmp.array() *=h_lm.array();
00199 double denom = tmp.sum();
00200 double l = (F_x - F_xnew) / denom;
00201
00202 if (l>0)
00203 {
00204
00205 x = xnew;
00206 f_x = f_xnew;
00207 F_x = F_xnew;
00208
00209 math::estimateJacobian( x, functor, increments, userParam, J);
00210 H.multiply_AtA(J);
00211 J.multiply_Atb(f_x, g);
00212
00213 found = math::norm_inf(g)<=e1;
00214 if (verbose && found) printf_debug("[LM] End condition: math::norm_inf(g)<=e1 : %e\n", math::norm_inf(g) );
00215
00216 lambda *= max(0.33, 1-pow(2*l-1,3) );
00217 v = 2;
00218 }
00219 else
00220 {
00221
00222 lambda *= v;
00223 v*= 2;
00224 }
00225
00226
00227 if (returnPath) {
00228 out_info.path.block(iter,0,1,x.size()) = x.transpose();
00229 out_info.path(iter,x.size()) = F_x;
00230 }
00231 }
00232 }
00233
00234
00235 out_info.final_sqr_err = F_x;
00236 out_info.iterations_executed = iter;
00237 out_info.last_err_vector = f_x;
00238 if (returnPath) out_info.path.setSize(iter,N+1);
00239
00240 MRPT_END
00241 }
00242
00243 };
00244
00245
00246 typedef CLevenbergMarquardtTempl<vector_double> CLevenbergMarquardt;
00247
00248 }
00249 }
00250 #endif