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 (*TFunctor)(
00063 const VECTORTYPE &x,
00064 const USERPARAM &y,
00065 VECTORTYPE &out);
00066
00067 struct TResultInfo
00068 {
00069 NUMTYPE final_sqr_err;
00070 size_t iterations_executed;
00071 CMatrixTemplateNumeric<NUMTYPE> path;
00072
00073
00074
00075
00076
00077
00078
00079
00080 };
00081
00082
00083
00084
00085
00086
00087
00088 static void execute(
00089 VECTORTYPE &out_optimal_x,
00090 const VECTORTYPE &x0,
00091 TFunctor functor,
00092 const VECTORTYPE &increments,
00093 const USERPARAM &userParam,
00094 TResultInfo &out_info,
00095 bool verbose = false,
00096 const size_t &maxIter = 200,
00097 const NUMTYPE tau = 1e-3,
00098 const NUMTYPE e1 = 1e-8,
00099 const NUMTYPE e2 = 1e-8,
00100 bool returnPath=true
00101 )
00102 {
00103 using namespace mrpt;
00104 using namespace mrpt::utils;
00105 using namespace mrpt::math;
00106 using namespace std;
00107
00108 MRPT_START;
00109
00110 VECTORTYPE &x=out_optimal_x;
00111
00112
00113 ASSERT_( increments.size() == x0.size() );
00114
00115 x=x0;
00116 VECTORTYPE f_x;
00117 CMatrixTemplateNumeric<NUMTYPE> AUX;
00118 CMatrixTemplateNumeric<NUMTYPE> J;
00119 CMatrixTemplateNumeric<NUMTYPE> H;
00120 VECTORTYPE g;
00121
00122
00123 mrpt::math::estimateJacobian( x, functor, increments, userParam, J);
00124 H.multiply_AtA(J);
00125
00126 const size_t H_len = H.getColCount();
00127
00128
00129 functor(x, userParam ,f_x);
00130 J.multiply_Atb(f_x, g);
00131
00132
00133 bool found = math::norm_inf(g)<=e1;
00134 if (verbose && found) printf_debug("[LM] End condition: math::norm_inf(g)<=e1 :%f\n",math::norm_inf(g));
00135
00136 NUMTYPE lambda = tau * H.maximumDiagonal();
00137 size_t iter = 0;
00138 NUMTYPE v = 2;
00139
00140 VECTORTYPE h_lm;
00141 VECTORTYPE xnew, f_xnew ;
00142 NUMTYPE F_x = pow( math::norm( f_x ), 2);
00143
00144 const size_t N = x.size();
00145
00146 if (returnPath) {
00147 out_info.path.setSize(maxIter,N+1);
00148 out_info.path.insertRow(iter,x);
00149 } else out_info.path.setSize(0,0);
00150
00151 while (!found && ++iter<maxIter)
00152 {
00153
00154 for (size_t k=0;k<H_len;k++)
00155 H(k,k)+= lambda;
00156
00157
00158 H.inv_fast(AUX);
00159 AUX.multiply_Ab(g,h_lm);
00160 h_lm *= NUMTYPE(-1.0);
00161
00162 double h_lm_n2 = math::norm(h_lm);
00163 double x_n2 = math::norm(x);
00164
00165 if (verbose) printf_debug( (format("[LM] Iter: %u x:",(unsigned)iter)+ sprintf_vector(" %f",x) + string("\n")).c_str() );
00166
00167 if (h_lm_n2<e2*(x_n2+e2))
00168 {
00169
00170 found = true;
00171 if (verbose) printf_debug("[LM] End condition: %e < %e\n", h_lm_n2, e2*(x_n2+e2) );
00172 }
00173 else
00174 {
00175
00176 xnew = x;
00177 xnew += h_lm;
00178 functor(xnew, userParam ,f_xnew );
00179 const double F_xnew = pow( math::norm(f_xnew), 2);
00180
00181
00182 VECTORTYPE tmp(h_lm);
00183 tmp *= lambda;
00184 tmp -= g;
00185 tmp*=h_lm;
00186 double denom = math::sum(tmp);
00187 double l = (F_x - F_xnew) / denom;
00188
00189
00190
00191 if (l>0)
00192 {
00193
00194 x = xnew;
00195 f_x = f_xnew;
00196 F_x = F_xnew;
00197
00198 math::estimateJacobian( x, functor, increments, userParam, J);
00199 H.multiply_AtA(J);
00200 J.multiply_Atb(f_x, g);
00201
00202 found = math::norm_inf(g)<=e1;
00203 if (verbose && found) printf_debug("[LM] End condition: math::norm_inf(g)<=e1 : %e\n", math::norm_inf(g) );
00204
00205 lambda *= max(0.33, 1-pow(2*l-1,3) );
00206 v = 2;
00207 }
00208 else
00209 {
00210
00211 lambda *= v;
00212 v*= 2;
00213 }
00214
00215
00216 if (returnPath) {
00217 out_info.path.insertRow(iter,x);
00218 out_info.path(iter,x.size()) = F_x;
00219 }
00220 }
00221 }
00222
00223
00224 out_info.final_sqr_err = F_x;
00225 out_info.iterations_executed = iter;
00226 if (returnPath) out_info.path.setSize(iter,N+1);
00227
00228 MRPT_END;
00229 }
00230
00231 };
00232
00233
00234 typedef CLevenbergMarquardtTempl<vector_double> CLevenbergMarquardt;
00235
00236 }
00237 }
00238 #endif