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
48 static Scalar sqrt_epsilon()
51 return sqrt(NumTraits<Scalar>::epsilon());
55 LevenbergMarquardt(FunctorType &_functor)
56 : functor(_functor) { nfev = njev = iter = 0; fnorm = gnorm = 0.; useExternalScaling=
false; }
58 typedef DenseIndex
Index;
62 : factor(Scalar(100.))
64 , ftol(sqrt_epsilon())
65 , xtol(sqrt_epsilon())
67 , epsfcn(Scalar(0.)) {}
79 LevenbergMarquardtSpace::Status lmder1(
81 const Scalar tol = sqrt_epsilon()
84 LevenbergMarquardtSpace::Status minimize(FVectorType &x);
85 LevenbergMarquardtSpace::Status minimizeInit(FVectorType &x);
86 LevenbergMarquardtSpace::Status minimizeOneStep(FVectorType &x);
88 static LevenbergMarquardtSpace::Status lmdif1(
92 const Scalar tol = sqrt_epsilon()
95 LevenbergMarquardtSpace::Status lmstr1(
97 const Scalar tol = sqrt_epsilon()
100 LevenbergMarquardtSpace::Status minimizeOptimumStorage(FVectorType &x);
101 LevenbergMarquardtSpace::Status minimizeOptimumStorageInit(FVectorType &x);
102 LevenbergMarquardtSpace::Status minimizeOptimumStorageOneStep(FVectorType &x);
104 void resetParameters(
void) { parameters =
Parameters(); }
107 FVectorType fvec, qtf, diag;
114 bool useExternalScaling;
116 Scalar lm_param(
void) {
return par; }
119 FunctorType &functor;
122 FVectorType wa1, wa2, wa3, wa4;
125 Scalar temp, temp1, temp2;
128 Scalar pnorm, xnorm, fnorm1, actred, dirder, prered;
133 template<
typename FunctorType,
typename Scalar>
134 LevenbergMarquardtSpace::Status
141 m = functor.values();
144 if (n <= 0 || m < n || tol < 0.)
145 return LevenbergMarquardtSpace::ImproperInputParameters;
148 parameters.ftol = tol;
149 parameters.xtol = tol;
150 parameters.maxfev = 100*(n+1);
156 template<
typename FunctorType,
typename Scalar>
157 LevenbergMarquardtSpace::Status
160 LevenbergMarquardtSpace::Status status = minimizeInit(x);
161 if (status==LevenbergMarquardtSpace::ImproperInputParameters)
164 status = minimizeOneStep(x);
165 }
while (status==LevenbergMarquardtSpace::Running);
169 template<
typename FunctorType,
typename Scalar>
170 LevenbergMarquardtSpace::Status
174 m = functor.values();
176 wa1.resize(n); wa2.resize(n); wa3.resize(n);
180 if (!useExternalScaling)
182 eigen_assert( (!useExternalScaling || diag.size()==n) &&
"When useExternalScaling is set, the caller must provide a valid 'diag'");
190 if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.)
191 return LevenbergMarquardtSpace::ImproperInputParameters;
193 if (useExternalScaling)
194 for (Index j = 0; j < n; ++j)
196 return LevenbergMarquardtSpace::ImproperInputParameters;
201 if ( functor(x, fvec) < 0)
202 return LevenbergMarquardtSpace::UserAsked;
203 fnorm = fvec.stableNorm();
209 return LevenbergMarquardtSpace::NotStarted;
212 template<
typename FunctorType,
typename Scalar>
213 LevenbergMarquardtSpace::Status
219 eigen_assert(x.size()==n);
222 Index df_ret = functor.df(x, fjac);
224 return LevenbergMarquardtSpace::UserAsked;
231 wa2 = fjac.colwise().blueNorm();
239 if (!useExternalScaling)
240 for (Index j = 0; j < n; ++j)
241 diag[j] = (wa2[j]==0.)? 1. : wa2[j];
245 xnorm = diag.cwiseProduct(x).stableNorm();
246 delta = parameters.factor * xnorm;
248 delta = parameters.factor;
260 for (Index j = 0; j < n; ++j)
261 if (wa2[permutation.indices()[j]] != 0.)
262 gnorm = (std::max)(gnorm, abs( fjac.col(j).head(j+1).dot(qtf.head(j+1)/fnorm) / wa2[permutation.indices()[j]]));
265 if (gnorm <= parameters.gtol)
266 return LevenbergMarquardtSpace::CosinusTooSmall;
269 if (!useExternalScaling)
270 diag = diag.cwiseMax(wa2);
275 internal::lmpar2<Scalar>(qrfac, diag, qtf, delta, par, wa1);
280 pnorm = diag.cwiseProduct(wa1).stableNorm();
284 delta = (std::min)(delta,pnorm);
287 if ( functor(wa2, wa4) < 0)
288 return LevenbergMarquardtSpace::UserAsked;
290 fnorm1 = wa4.stableNorm();
294 if (Scalar(.1) * fnorm1 < fnorm)
295 actred = 1. - numext::abs2(fnorm1 / fnorm);
299 wa3 = fjac.template triangularView<Upper>() * (qrfac.colsPermutation().inverse() *wa1);
300 temp1 = numext::abs2(wa3.stableNorm() / fnorm);
301 temp2 = numext::abs2(sqrt(par) * pnorm / fnorm);
302 prered = temp1 + temp2 / Scalar(.5);
303 dirder = -(temp1 + temp2);
309 ratio = actred / prered;
312 if (ratio <= Scalar(.25)) {
316 temp = Scalar(.5) * dirder / (dirder + Scalar(.5) * actred);
317 if (Scalar(.1) * fnorm1 >= fnorm || temp < Scalar(.1))
320 delta = temp * (std::min)(delta, pnorm / Scalar(.1));
322 }
else if (!(par != 0. && ratio < Scalar(.75))) {
323 delta = pnorm / Scalar(.5);
324 par = Scalar(.5) * par;
328 if (ratio >= Scalar(1e-4)) {
331 wa2 = diag.cwiseProduct(x);
333 xnorm = wa2.stableNorm();
339 if (abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm)
340 return LevenbergMarquardtSpace::RelativeErrorAndReductionTooSmall;
341 if (abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.)
342 return LevenbergMarquardtSpace::RelativeReductionTooSmall;
343 if (delta <= parameters.xtol * xnorm)
344 return LevenbergMarquardtSpace::RelativeErrorTooSmall;
347 if (nfev >= parameters.maxfev)
348 return LevenbergMarquardtSpace::TooManyFunctionEvaluation;
350 return LevenbergMarquardtSpace::FtolTooSmall;
352 return LevenbergMarquardtSpace::XtolTooSmall;
354 return LevenbergMarquardtSpace::GtolTooSmall;
356 }
while (ratio < Scalar(1e-4));
358 return LevenbergMarquardtSpace::Running;
361 template<
typename FunctorType,
typename Scalar>
362 LevenbergMarquardtSpace::Status
369 m = functor.values();
372 if (n <= 0 || m < n || tol < 0.)
373 return LevenbergMarquardtSpace::ImproperInputParameters;
376 parameters.ftol = tol;
377 parameters.xtol = tol;
378 parameters.maxfev = 100*(n+1);
380 return minimizeOptimumStorage(x);
383 template<
typename FunctorType,
typename Scalar>
384 LevenbergMarquardtSpace::Status
388 m = functor.values();
390 wa1.resize(n); wa2.resize(n); wa3.resize(n);
399 if (!useExternalScaling)
401 eigen_assert( (!useExternalScaling || diag.size()==n) &&
"When useExternalScaling is set, the caller must provide a valid 'diag'");
409 if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.)
410 return LevenbergMarquardtSpace::ImproperInputParameters;
412 if (useExternalScaling)
413 for (Index j = 0; j < n; ++j)
415 return LevenbergMarquardtSpace::ImproperInputParameters;
420 if ( functor(x, fvec) < 0)
421 return LevenbergMarquardtSpace::UserAsked;
422 fnorm = fvec.stableNorm();
428 return LevenbergMarquardtSpace::NotStarted;
432 template<
typename FunctorType,
typename Scalar>
433 LevenbergMarquardtSpace::Status
439 eigen_assert(x.size()==n);
451 for (i = 0; i < m; ++i) {
452 if (functor.df(x, wa3, rownb) < 0)
return LevenbergMarquardtSpace::UserAsked;
453 internal::rwupdt<Scalar>(fjac, wa3, qtf, fvec[i]);
461 for (j = 0; j < n; ++j) {
464 wa2[j] = fjac.col(j).head(j).stableNorm();
466 permutation.setIdentity(n);
468 wa2 = fjac.colwise().blueNorm();
473 wa1 = fjac.diagonal();
474 fjac.diagonal() = qrfac.
hCoeffs();
477 for(Index ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii);
479 for (j = 0; j < n; ++j) {
480 if (fjac(j,j) != 0.) {
482 for (i = j; i < n; ++i)
483 sum += fjac(i,j) * qtf[i];
484 temp = -sum / fjac(j,j);
485 for (i = j; i < n; ++i)
486 qtf[i] += fjac(i,j) * temp;
495 if (!useExternalScaling)
496 for (j = 0; j < n; ++j)
497 diag[j] = (wa2[j]==0.)? 1. : wa2[j];
501 xnorm = diag.cwiseProduct(x).stableNorm();
502 delta = parameters.factor * xnorm;
504 delta = parameters.factor;
510 for (j = 0; j < n; ++j)
511 if (wa2[permutation.indices()[j]] != 0.)
512 gnorm = (std::max)(gnorm, abs( fjac.col(j).head(j+1).dot(qtf.head(j+1)/fnorm) / wa2[permutation.indices()[j]]));
515 if (gnorm <= parameters.gtol)
516 return LevenbergMarquardtSpace::CosinusTooSmall;
519 if (!useExternalScaling)
520 diag = diag.cwiseMax(wa2);
525 internal::lmpar<Scalar>(fjac, permutation.indices(), diag, qtf, delta, par, wa1);
530 pnorm = diag.cwiseProduct(wa1).stableNorm();
534 delta = (std::min)(delta,pnorm);
537 if ( functor(wa2, wa4) < 0)
538 return LevenbergMarquardtSpace::UserAsked;
540 fnorm1 = wa4.stableNorm();
544 if (Scalar(.1) * fnorm1 < fnorm)
545 actred = 1. - numext::abs2(fnorm1 / fnorm);
549 wa3 = fjac.topLeftCorner(n,n).template triangularView<Upper>() * (permutation.inverse() * wa1);
550 temp1 = numext::abs2(wa3.stableNorm() / fnorm);
551 temp2 = numext::abs2(sqrt(par) * pnorm / fnorm);
552 prered = temp1 + temp2 / Scalar(.5);
553 dirder = -(temp1 + temp2);
559 ratio = actred / prered;
562 if (ratio <= Scalar(.25)) {
566 temp = Scalar(.5) * dirder / (dirder + Scalar(.5) * actred);
567 if (Scalar(.1) * fnorm1 >= fnorm || temp < Scalar(.1))
570 delta = temp * (std::min)(delta, pnorm / Scalar(.1));
572 }
else if (!(par != 0. && ratio < Scalar(.75))) {
573 delta = pnorm / Scalar(.5);
574 par = Scalar(.5) * par;
578 if (ratio >= Scalar(1e-4)) {
581 wa2 = diag.cwiseProduct(x);
583 xnorm = wa2.stableNorm();
589 if (abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm)
590 return LevenbergMarquardtSpace::RelativeErrorAndReductionTooSmall;
591 if (abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.)
592 return LevenbergMarquardtSpace::RelativeReductionTooSmall;
593 if (delta <= parameters.xtol * xnorm)
594 return LevenbergMarquardtSpace::RelativeErrorTooSmall;
597 if (nfev >= parameters.maxfev)
598 return LevenbergMarquardtSpace::TooManyFunctionEvaluation;
600 return LevenbergMarquardtSpace::FtolTooSmall;
602 return LevenbergMarquardtSpace::XtolTooSmall;
604 return LevenbergMarquardtSpace::GtolTooSmall;
606 }
while (ratio < Scalar(1e-4));
608 return LevenbergMarquardtSpace::Running;
611 template<
typename FunctorType,
typename Scalar>
612 LevenbergMarquardtSpace::Status
615 LevenbergMarquardtSpace::Status status = minimizeOptimumStorageInit(x);
616 if (status==LevenbergMarquardtSpace::ImproperInputParameters)
619 status = minimizeOptimumStorageOneStep(x);
620 }
while (status==LevenbergMarquardtSpace::Running);
624 template<
typename FunctorType,
typename Scalar>
625 LevenbergMarquardtSpace::Status
627 FunctorType &functor,
634 Index m = functor.values();
637 if (n <= 0 || m < n || tol < 0.)
638 return LevenbergMarquardtSpace::ImproperInputParameters;
643 lm.parameters.ftol = tol;
644 lm.parameters.xtol = tol;
645 lm.parameters.maxfev = 200*(n+1);
647 LevenbergMarquardtSpace::Status info = LevenbergMarquardtSpace::Status(lm.minimize(x));
655 #endif // EIGEN_LEVENBERGMARQUARDT__H Performs non linear optimization over a non-linear function, using a variant of the Levenberg Marquar...
Definition: LevenbergMarquardt.h:110
const HCoeffsType & hCoeffs() const
Definition: ColPivHouseholderQR.h:334
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:85
Holds information about the various numeric (i.e.
Definition: NumTraits.h:150
HouseholderSequenceType householderQ() const
Definition: ColPivHouseholderQR.h:634
Householder rank-revealing QR decomposition of a matrix with column-pivoting.
Definition: ForwardDeclarations.h:255
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:33
Definition: LevenbergMarquardt.h:60
This class allows you to add a method df() to your functor, which will use numerical differentiation ...
Definition: NumericalDiff.h:36
const MatrixType & matrixQR() const
Definition: ColPivHouseholderQR.h:189
const PermutationType & colsPermutation() const
Definition: ColPivHouseholderQR.h:214