13 #ifndef EIGEN_LEVENBERGMARQUARDT__H
14 #define EIGEN_LEVENBERGMARQUARDT__H
18 namespace LevenbergMarquardtSpace {
22 ImproperInputParameters = 0,
23 RelativeReductionTooSmall = 1,
24 RelativeErrorTooSmall = 2,
25 RelativeErrorAndReductionTooSmall = 3,
27 TooManyFunctionEvaluation = 5,
45 template<
typename FunctorType,
typename Scalar=
double>
46 class LevenbergMarquardt
49 LevenbergMarquardt(FunctorType &_functor)
50 : functor(_functor) {
nfev =
njev = iter = 0;
fnorm =
gnorm = 0.; useExternalScaling=
false; }
52 typedef DenseIndex Index;
56 : factor(Scalar(100.))
58 , ftol(std::sqrt(NumTraits<Scalar>::epsilon()))
59 , xtol(std::sqrt(NumTraits<Scalar>::epsilon()))
61 , epsfcn(Scalar(0.)) {}
70 typedef Matrix< Scalar, Dynamic, 1 > FVectorType;
71 typedef Matrix< Scalar, Dynamic, Dynamic > JacobianType;
73 LevenbergMarquardtSpace::Status lmder1(
75 const Scalar tol = std::sqrt(NumTraits<Scalar>::epsilon())
78 LevenbergMarquardtSpace::Status minimize(FVectorType &x);
79 LevenbergMarquardtSpace::Status minimizeInit(FVectorType &x);
80 LevenbergMarquardtSpace::Status minimizeOneStep(FVectorType &x);
82 static LevenbergMarquardtSpace::Status lmdif1(
86 const Scalar tol = std::sqrt(NumTraits<Scalar>::epsilon())
89 LevenbergMarquardtSpace::Status lmstr1(
91 const Scalar tol = std::sqrt(NumTraits<Scalar>::epsilon())
94 LevenbergMarquardtSpace::Status minimizeOptimumStorage(FVectorType &x);
95 LevenbergMarquardtSpace::Status minimizeOptimumStorageInit(FVectorType &x);
96 LevenbergMarquardtSpace::Status minimizeOptimumStorageOneStep(FVectorType &x);
100 Parameters parameters;
108 bool useExternalScaling;
110 Scalar
lm_param(
void) {
return par; }
112 FunctorType &functor;
115 FVectorType wa1, wa2, wa3, wa4;
118 Scalar temp, temp1, temp2;
121 Scalar pnorm, xnorm, fnorm1, actred, dirder, prered;
123 LevenbergMarquardt& operator=(
const LevenbergMarquardt&);
126 template<
typename FunctorType,
typename Scalar>
127 LevenbergMarquardtSpace::Status
128 LevenbergMarquardt<FunctorType,Scalar>::lmder1(
134 m = functor.values();
137 if (n <= 0 || m < n || tol < 0.)
138 return LevenbergMarquardtSpace::ImproperInputParameters;
141 parameters.ftol = tol;
142 parameters.xtol = tol;
143 parameters.maxfev = 100*(n+1);
149 template<
typename FunctorType,
typename Scalar>
150 LevenbergMarquardtSpace::Status
151 LevenbergMarquardt<FunctorType,Scalar>::minimize(FVectorType &x)
153 LevenbergMarquardtSpace::Status status = minimizeInit(x);
154 if (status==LevenbergMarquardtSpace::ImproperInputParameters)
157 status = minimizeOneStep(x);
158 }
while (status==LevenbergMarquardtSpace::Running);
162 template<
typename FunctorType,
typename Scalar>
163 LevenbergMarquardtSpace::Status
164 LevenbergMarquardt<FunctorType,Scalar>::minimizeInit(FVectorType &x)
167 m = functor.values();
169 wa1.resize(n); wa2.resize(n); wa3.resize(n);
173 if (!useExternalScaling)
175 eigen_assert( (!useExternalScaling || diag.size()==n) ||
"When useExternalScaling is set, the caller must provide a valid 'diag'");
183 if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.)
184 return LevenbergMarquardtSpace::ImproperInputParameters;
186 if (useExternalScaling)
187 for (Index j = 0; j < n; ++j)
189 return LevenbergMarquardtSpace::ImproperInputParameters;
194 if ( functor(x, fvec) < 0)
195 return LevenbergMarquardtSpace::UserAsked;
196 fnorm = fvec.stableNorm();
202 return LevenbergMarquardtSpace::NotStarted;
205 template<
typename FunctorType,
typename Scalar>
206 LevenbergMarquardtSpace::Status
207 LevenbergMarquardt<FunctorType,Scalar>::minimizeOneStep(FVectorType &x)
212 eigen_assert(x.size()==n);
215 Index df_ret = functor.df(x, fjac);
217 return LevenbergMarquardtSpace::UserAsked;
224 wa2 = fjac.colwise().blueNorm();
225 ColPivHouseholderQR<JacobianType> qrfac(fjac);
226 fjac = qrfac.matrixQR();
227 permutation = qrfac.colsPermutation();
232 if (!useExternalScaling)
233 for (Index j = 0; j < n; ++j)
234 diag[j] = (wa2[j]==0.)? 1. : wa2[j];
238 xnorm = diag.cwiseProduct(x).stableNorm();
239 delta = parameters.factor * xnorm;
241 delta = parameters.factor;
247 wa4.applyOnTheLeft(qrfac.householderQ().adjoint());
253 for (Index j = 0; j < n; ++j)
254 if (wa2[permutation.indices()[j]] != 0.)
255 gnorm = (std::max)(gnorm, abs( fjac.col(j).head(j+1).dot(qtf.head(j+1)/fnorm) / wa2[permutation.indices()[j]]));
258 if (gnorm <= parameters.gtol)
259 return LevenbergMarquardtSpace::CosinusTooSmall;
262 if (!useExternalScaling)
263 diag = diag.cwiseMax(wa2);
268 internal::lmpar2<Scalar>(qrfac, diag, qtf, delta, par, wa1);
273 pnorm = diag.cwiseProduct(wa1).stableNorm();
277 delta = (std::min)(delta,pnorm);
280 if ( functor(wa2, wa4) < 0)
281 return LevenbergMarquardtSpace::UserAsked;
283 fnorm1 = wa4.stableNorm();
287 if (Scalar(.1) * fnorm1 < fnorm)
288 actred = 1. - numext::abs2(fnorm1 / fnorm);
292 wa3 = fjac.template triangularView<Upper>() * (qrfac.colsPermutation().inverse() *wa1);
293 temp1 = numext::abs2(wa3.stableNorm() / fnorm);
294 temp2 = numext::abs2(sqrt(par) * pnorm / fnorm);
295 prered = temp1 + temp2 / Scalar(.5);
296 dirder = -(temp1 + temp2);
302 ratio = actred / prered;
305 if (ratio <= Scalar(.25)) {
309 temp = Scalar(.5) * dirder / (dirder + Scalar(.5) * actred);
310 if (Scalar(.1) * fnorm1 >= fnorm || temp < Scalar(.1))
313 delta = temp * (std::min)(delta, pnorm / Scalar(.1));
315 }
else if (!(par != 0. && ratio < Scalar(.75))) {
316 delta = pnorm / Scalar(.5);
317 par = Scalar(.5) * par;
321 if (ratio >= Scalar(1e-4)) {
324 wa2 = diag.cwiseProduct(x);
326 xnorm = wa2.stableNorm();
332 if (abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm)
333 return LevenbergMarquardtSpace::RelativeErrorAndReductionTooSmall;
334 if (abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.)
335 return LevenbergMarquardtSpace::RelativeReductionTooSmall;
336 if (delta <= parameters.xtol * xnorm)
337 return LevenbergMarquardtSpace::RelativeErrorTooSmall;
340 if (nfev >= parameters.maxfev)
341 return LevenbergMarquardtSpace::TooManyFunctionEvaluation;
342 if (abs(actred) <= NumTraits<Scalar>::epsilon() && prered <= NumTraits<Scalar>::epsilon() && Scalar(.5) * ratio <= 1.)
343 return LevenbergMarquardtSpace::FtolTooSmall;
344 if (delta <= NumTraits<Scalar>::epsilon() * xnorm)
345 return LevenbergMarquardtSpace::XtolTooSmall;
346 if (gnorm <= NumTraits<Scalar>::epsilon())
347 return LevenbergMarquardtSpace::GtolTooSmall;
349 }
while (ratio < Scalar(1e-4));
351 return LevenbergMarquardtSpace::Running;
354 template<
typename FunctorType,
typename Scalar>
355 LevenbergMarquardtSpace::Status
356 LevenbergMarquardt<FunctorType,Scalar>::lmstr1(
362 m = functor.values();
365 if (n <= 0 || m < n || tol < 0.)
366 return LevenbergMarquardtSpace::ImproperInputParameters;
369 parameters.ftol = tol;
370 parameters.xtol = tol;
371 parameters.maxfev = 100*(n+1);
373 return minimizeOptimumStorage(x);
376 template<
typename FunctorType,
typename Scalar>
377 LevenbergMarquardtSpace::Status
378 LevenbergMarquardt<FunctorType,Scalar>::minimizeOptimumStorageInit(FVectorType &x)
381 m = functor.values();
383 wa1.resize(n); wa2.resize(n); wa3.resize(n);
392 if (!useExternalScaling)
394 eigen_assert( (!useExternalScaling || diag.size()==n) ||
"When useExternalScaling is set, the caller must provide a valid 'diag'");
402 if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.)
403 return LevenbergMarquardtSpace::ImproperInputParameters;
405 if (useExternalScaling)
406 for (Index j = 0; j < n; ++j)
408 return LevenbergMarquardtSpace::ImproperInputParameters;
413 if ( functor(x, fvec) < 0)
414 return LevenbergMarquardtSpace::UserAsked;
415 fnorm = fvec.stableNorm();
421 return LevenbergMarquardtSpace::NotStarted;
425 template<
typename FunctorType,
typename Scalar>
426 LevenbergMarquardtSpace::Status
427 LevenbergMarquardt<FunctorType,Scalar>::minimizeOptimumStorageOneStep(FVectorType &x)
432 eigen_assert(x.size()==n);
444 for (i = 0; i < m; ++i) {
445 if (functor.df(x, wa3, rownb) < 0)
return LevenbergMarquardtSpace::UserAsked;
446 internal::rwupdt<Scalar>(fjac, wa3, qtf, fvec[i]);
454 for (j = 0; j < n; ++j) {
457 wa2[j] = fjac.col(j).head(j).stableNorm();
459 permutation.setIdentity(n);
461 wa2 = fjac.colwise().blueNorm();
464 ColPivHouseholderQR<JacobianType> qrfac(fjac);
465 fjac = qrfac.matrixQR();
466 wa1 = fjac.diagonal();
467 fjac.diagonal() = qrfac.hCoeffs();
468 permutation = qrfac.colsPermutation();
470 for(Index ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii);
472 for (j = 0; j < n; ++j) {
473 if (fjac(j,j) != 0.) {
475 for (i = j; i < n; ++i)
476 sum += fjac(i,j) * qtf[i];
477 temp = -sum / fjac(j,j);
478 for (i = j; i < n; ++i)
479 qtf[i] += fjac(i,j) * temp;
488 if (!useExternalScaling)
489 for (j = 0; j < n; ++j)
490 diag[j] = (wa2[j]==0.)? 1. : wa2[j];
494 xnorm = diag.cwiseProduct(x).stableNorm();
495 delta = parameters.factor * xnorm;
497 delta = parameters.factor;
503 for (j = 0; j < n; ++j)
504 if (wa2[permutation.indices()[j]] != 0.)
505 gnorm = (std::max)(gnorm, abs( fjac.col(j).head(j+1).dot(qtf.head(j+1)/fnorm) / wa2[permutation.indices()[j]]));
508 if (gnorm <= parameters.gtol)
509 return LevenbergMarquardtSpace::CosinusTooSmall;
512 if (!useExternalScaling)
513 diag = diag.cwiseMax(wa2);
518 internal::lmpar<Scalar>(fjac, permutation.indices(), diag, qtf, delta, par, wa1);
523 pnorm = diag.cwiseProduct(wa1).stableNorm();
527 delta = (std::min)(delta,pnorm);
530 if ( functor(wa2, wa4) < 0)
531 return LevenbergMarquardtSpace::UserAsked;
533 fnorm1 = wa4.stableNorm();
537 if (Scalar(.1) * fnorm1 < fnorm)
538 actred = 1. - numext::abs2(fnorm1 / fnorm);
542 wa3 = fjac.topLeftCorner(n,n).template triangularView<Upper>() * (permutation.inverse() * wa1);
543 temp1 = numext::abs2(wa3.stableNorm() / fnorm);
544 temp2 = numext::abs2(sqrt(par) * pnorm / fnorm);
545 prered = temp1 + temp2 / Scalar(.5);
546 dirder = -(temp1 + temp2);
552 ratio = actred / prered;
555 if (ratio <= Scalar(.25)) {
559 temp = Scalar(.5) * dirder / (dirder + Scalar(.5) * actred);
560 if (Scalar(.1) * fnorm1 >= fnorm || temp < Scalar(.1))
563 delta = temp * (std::min)(delta, pnorm / Scalar(.1));
565 }
else if (!(par != 0. && ratio < Scalar(.75))) {
566 delta = pnorm / Scalar(.5);
567 par = Scalar(.5) * par;
571 if (ratio >= Scalar(1e-4)) {
574 wa2 = diag.cwiseProduct(x);
576 xnorm = wa2.stableNorm();
582 if (abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm)
583 return LevenbergMarquardtSpace::RelativeErrorAndReductionTooSmall;
584 if (abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.)
585 return LevenbergMarquardtSpace::RelativeReductionTooSmall;
586 if (delta <= parameters.xtol * xnorm)
587 return LevenbergMarquardtSpace::RelativeErrorTooSmall;
590 if (nfev >= parameters.maxfev)
591 return LevenbergMarquardtSpace::TooManyFunctionEvaluation;
592 if (abs(actred) <= NumTraits<Scalar>::epsilon() && prered <= NumTraits<Scalar>::epsilon() && Scalar(.5) * ratio <= 1.)
593 return LevenbergMarquardtSpace::FtolTooSmall;
594 if (delta <= NumTraits<Scalar>::epsilon() * xnorm)
595 return LevenbergMarquardtSpace::XtolTooSmall;
596 if (gnorm <= NumTraits<Scalar>::epsilon())
597 return LevenbergMarquardtSpace::GtolTooSmall;
599 }
while (ratio < Scalar(1e-4));
601 return LevenbergMarquardtSpace::Running;
604 template<
typename FunctorType,
typename Scalar>
605 LevenbergMarquardtSpace::Status
606 LevenbergMarquardt<FunctorType,Scalar>::minimizeOptimumStorage(FVectorType &x)
608 LevenbergMarquardtSpace::Status status = minimizeOptimumStorageInit(x);
609 if (status==LevenbergMarquardtSpace::ImproperInputParameters)
612 status = minimizeOptimumStorageOneStep(x);
613 }
while (status==LevenbergMarquardtSpace::Running);
617 template<
typename FunctorType,
typename Scalar>
618 LevenbergMarquardtSpace::Status
619 LevenbergMarquardt<FunctorType,Scalar>::lmdif1(
620 FunctorType &functor,
627 Index m = functor.values();
630 if (n <= 0 || m < n || tol < 0.)
631 return LevenbergMarquardtSpace::ImproperInputParameters;
633 NumericalDiff<FunctorType> numDiff(functor);
635 LevenbergMarquardt<NumericalDiff<FunctorType>, Scalar > lm(numDiff);
636 lm.parameters.ftol = tol;
637 lm.parameters.xtol = tol;
638 lm.parameters.maxfev = 200*(n+1);
640 LevenbergMarquardtSpace::Status info = LevenbergMarquardtSpace::Status(lm.minimize(x));
648 #endif // EIGEN_LEVENBERGMARQUARDT__H
FVectorType & fvec()
Definition: LevenbergMarquardt/LevenbergMarquardt.h:200
Index nfev()
Definition: LevenbergMarquardt/LevenbergMarquardt.h:184
FVectorType & diag()
Definition: LevenbergMarquardt/LevenbergMarquardt.h:178
RealScalar lm_param(void)
Definition: LevenbergMarquardt/LevenbergMarquardt.h:196
void resetParameters()
Definition: LevenbergMarquardt/LevenbergMarquardt.h:146
RealScalar fnorm()
Definition: LevenbergMarquardt/LevenbergMarquardt.h:190
RealScalar gnorm()
Definition: LevenbergMarquardt/LevenbergMarquardt.h:193
Index njev()
Definition: LevenbergMarquardt/LevenbergMarquardt.h:187
PermutationType permutation()
Definition: LevenbergMarquardt/LevenbergMarquardt.h:213