Eigen-Contrib  5.0.1
 
Loading...
Searching...
No Matches
LevenbergMarquardt.h
1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org>
5// Copyright (C) 2012 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
6//
7// The algorithm of this class initially comes from MINPACK whose original authors are:
8// Copyright Jorge More - Argonne National Laboratory
9// Copyright Burt Garbow - Argonne National Laboratory
10// Copyright Ken Hillstrom - Argonne National Laboratory
11//
12// This Source Code Form is subject to the terms of the Minpack license
13// (a BSD-like license) described in the accompanying CopyrightMINPACK.txt file.
14//
15// This Source Code Form is subject to the terms of the Mozilla
16// Public License v. 2.0. If a copy of the MPL was not distributed
17// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
18// SPDX-License-Identifier: MPL-2.0 AND LicenseRef-MINPACK
19
20#ifndef EIGEN_LEVENBERGMARQUARDT_H
21#define EIGEN_LEVENBERGMARQUARDT_H
22
23// IWYU pragma: private
24#include "./InternalHeaderCheck.h"
25
26namespace Eigen {
27namespace LevenbergMarquardtSpace {
28enum Status {
29 NotStarted = -2,
30 Running = -1,
31 ImproperInputParameters = 0,
32 RelativeReductionTooSmall = 1,
33 RelativeErrorTooSmall = 2,
34 RelativeErrorAndReductionTooSmall = 3,
35 CosinusTooSmall = 4,
36 TooManyFunctionEvaluation = 5,
37 FtolTooSmall = 6,
38 XtolTooSmall = 7,
39 GtolTooSmall = 8,
40 UserAsked = 9
41};
42}
43
44template <typename Scalar_, int NX = Dynamic, int NY = Dynamic>
45struct DenseFunctor {
46 typedef Scalar_ Scalar;
47 enum { InputsAtCompileTime = NX, ValuesAtCompileTime = NY };
48 typedef Matrix<Scalar, InputsAtCompileTime, 1> InputType;
49 typedef Matrix<Scalar, ValuesAtCompileTime, 1> ValueType;
50 typedef Matrix<Scalar, ValuesAtCompileTime, InputsAtCompileTime> JacobianType;
51 typedef ColPivHouseholderQR<JacobianType> QRSolver;
52 const int m_inputs = InputsAtCompileTime;
53 const int m_values = ValuesAtCompileTime;
54
55 DenseFunctor() = default;
56 DenseFunctor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
57
58 int inputs() const { return m_inputs; }
59 int values() const { return m_values; }
60
61 // int operator()(const InputType &x, ValueType& fvec) { }
62 // should be defined in derived classes
63
64 // int df(const InputType &x, JacobianType& fjac) { }
65 // should be defined in derived classes
66};
67
68template <typename Scalar_, typename Index_>
69struct SparseFunctor {
70 typedef Scalar_ Scalar;
71 typedef Index_ Index;
72 typedef Matrix<Scalar, Dynamic, 1> InputType;
73 typedef Matrix<Scalar, Dynamic, 1> ValueType;
74 typedef SparseMatrix<Scalar, ColMajor, Index> JacobianType;
75 typedef SparseQR<JacobianType, COLAMDOrdering<int> > QRSolver;
76 enum { InputsAtCompileTime = Dynamic, ValuesAtCompileTime = Dynamic };
77
78 SparseFunctor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
79
80 int inputs() const { return m_inputs; }
81 int values() const { return m_values; }
82
83 const int m_inputs, m_values;
84 // int operator()(const InputType &x, ValueType& fvec) { }
85 // to be defined in the functor
86
87 // int df(const InputType &x, JacobianType& fjac) { }
88 // to be defined in the functor if no automatic differentiation
89};
90namespace internal {
91template <typename QRSolver, typename VectorType>
92void lmpar2(const QRSolver &qr, const VectorType &diag, const VectorType &qtb, typename VectorType::Scalar m_delta,
93 typename VectorType::Scalar &par, VectorType &x);
94}
103template <typename FunctorType_>
104class LevenbergMarquardt : internal::no_assignment_operator {
105 public:
106 typedef FunctorType_ FunctorType;
107 typedef typename FunctorType::QRSolver QRSolver;
108 typedef typename FunctorType::JacobianType JacobianType;
109 typedef typename JacobianType::Scalar Scalar;
110 typedef typename JacobianType::RealScalar RealScalar;
111 typedef typename QRSolver::StorageIndex PermIndex;
112 typedef Matrix<Scalar, Dynamic, 1> FVectorType;
113 typedef PermutationMatrix<Dynamic, Dynamic, int> PermutationType;
114
115 public:
116 LevenbergMarquardt(FunctorType &functor)
117 : m_functor(functor),
118 m_nfev(0),
119 m_njev(0),
120 m_fnorm(0.0),
121 m_gnorm(0),
122 m_isInitialized(false),
123 m_info(InvalidInput) {
125 m_useExternalScaling = false;
126 }
127
128 LevenbergMarquardtSpace::Status minimize(FVectorType &x);
129 LevenbergMarquardtSpace::Status minimizeInit(FVectorType &x);
130 LevenbergMarquardtSpace::Status minimizeOneStep(FVectorType &x);
131 LevenbergMarquardtSpace::Status lmder1(FVectorType &x, const Scalar tol = numext::sqrt(NumTraits<Scalar>::epsilon()));
132 static LevenbergMarquardtSpace::Status lmdif1(FunctorType &functor, FVectorType &x, Index *nfev,
133 const Scalar tol = numext::sqrt(NumTraits<Scalar>::epsilon()));
134
137 using std::sqrt;
138
139 m_factor = 100.;
140 m_maxfev = 400;
141 m_ftol = sqrt(NumTraits<RealScalar>::epsilon());
142 m_xtol = sqrt(NumTraits<RealScalar>::epsilon());
143 m_gtol = 0.;
144 m_epsfcn = 0.;
145 }
146
148 void setXtol(RealScalar xtol) { m_xtol = xtol; }
149
151 void setFtol(RealScalar ftol) { m_ftol = ftol; }
152
154 void setGtol(RealScalar gtol) { m_gtol = gtol; }
155
157 void setFactor(RealScalar factor) { m_factor = factor; }
158
160 void setEpsilon(RealScalar epsfcn) { m_epsfcn = epsfcn; }
161
163 void setMaxfev(Index maxfev) { m_maxfev = maxfev; }
164
166 void setExternalScaling(bool value) { m_useExternalScaling = value; }
167
169 RealScalar xtol() const { return m_xtol; }
170
172 RealScalar ftol() const { return m_ftol; }
173
175 RealScalar gtol() const { return m_gtol; }
176
178 RealScalar factor() const { return m_factor; }
179
181 RealScalar epsilon() const { return m_epsfcn; }
182
184 Index maxfev() const { return m_maxfev; }
185
187 FVectorType &diag() { return m_diag; }
188
190 Index iterations() const { return m_iter; }
191
193 Index nfev() const { return m_nfev; }
194
196 Index njev() const { return m_njev; }
197
199 RealScalar fnorm() const { return m_fnorm; }
200
202 RealScalar gnorm() const { return m_gnorm; }
203
205 RealScalar lm_param(void) const { return m_par; }
206
209 FVectorType &fvec() { return m_fvec; }
210
213 JacobianType &jacobian() { return m_fjac; }
214
218 JacobianType &matrixR() { return m_rfactor; }
219
222 PermutationType permutation() const { return m_permutation; }
223
233 ComputationInfo info() const { return m_info; }
234
235 private:
236 JacobianType m_fjac;
237 JacobianType m_rfactor; // The triangular matrix R from the QR of the jacobian matrix m_fjac
238 FunctorType &m_functor;
239 FVectorType m_fvec, m_qtf, m_diag;
240 Index n;
241 Index m;
242 Index m_nfev;
243 Index m_njev;
244 RealScalar m_fnorm; // Norm of the current vector function
245 RealScalar m_gnorm; // Norm of the gradient of the error
246 RealScalar m_factor; //
247 Index m_maxfev; // Maximum number of function evaluation
248 RealScalar m_ftol; // Tolerance in the norm of the vector function
249 RealScalar m_xtol; //
250 RealScalar m_gtol; // tolerance of the norm of the error gradient
251 RealScalar m_epsfcn; //
252 Index m_iter; // Number of iterations performed
253 RealScalar m_delta;
254 bool m_useExternalScaling;
255 PermutationType m_permutation;
256 FVectorType m_wa1, m_wa2, m_wa3, m_wa4; // Temporary vectors
257 RealScalar m_par;
258 bool m_isInitialized; // Check whether the minimization step has been called
259 ComputationInfo m_info;
260};
261
262template <typename FunctorType>
263LevenbergMarquardtSpace::Status LevenbergMarquardt<FunctorType>::minimize(FVectorType &x) {
264 LevenbergMarquardtSpace::Status status = minimizeInit(x);
265 if (status == LevenbergMarquardtSpace::ImproperInputParameters) {
266 m_isInitialized = true;
267 return status;
268 }
269 do {
270 status = minimizeOneStep(x);
271 } while (status == LevenbergMarquardtSpace::Running);
272 m_isInitialized = true;
273 return status;
274}
275
276template <typename FunctorType>
277LevenbergMarquardtSpace::Status LevenbergMarquardt<FunctorType>::minimizeInit(FVectorType &x) {
278 n = x.size();
279 m = m_functor.values();
280
281 m_wa1.resize(n);
282 m_wa2.resize(n);
283 m_wa3.resize(n);
284 m_wa4.resize(m);
285 m_fvec.resize(m);
286 // FIXME: Sparse case: allocate space for the Jacobian.
287 m_fjac.resize(m, n);
288 if (!m_useExternalScaling) m_diag.resize(n);
289 eigen_assert((!m_useExternalScaling || m_diag.size() == n) &&
290 "When m_useExternalScaling is set, the caller must provide a valid 'm_diag'");
291 m_qtf.resize(n);
292
293 /* Function Body */
294 m_nfev = 0;
295 m_njev = 0;
296
297 /* check the input parameters for errors. */
298 if (n <= 0 || m < n || m_ftol < 0. || m_xtol < 0. || m_gtol < 0. || m_maxfev <= 0 || m_factor <= 0.) {
299 m_info = InvalidInput;
300 return LevenbergMarquardtSpace::ImproperInputParameters;
301 }
302
303 if (m_useExternalScaling)
304 for (Index j = 0; j < n; ++j)
305 if (m_diag[j] <= 0.) {
306 m_info = InvalidInput;
307 return LevenbergMarquardtSpace::ImproperInputParameters;
308 }
309
310 /* evaluate the function at the starting point */
311 /* and calculate its norm. */
312 m_nfev = 1;
313 if (m_functor(x, m_fvec) < 0) return LevenbergMarquardtSpace::UserAsked;
314 m_fnorm = m_fvec.stableNorm();
315
316 /* initialize levenberg-marquardt parameter and iteration counter. */
317 m_par = 0.;
318 m_iter = 1;
319
320 return LevenbergMarquardtSpace::NotStarted;
321}
322
323template <typename FunctorType>
324LevenbergMarquardtSpace::Status LevenbergMarquardt<FunctorType>::lmder1(FVectorType &x, const Scalar tol) {
325 n = x.size();
326 m = m_functor.values();
327
328 /* check the input parameters for errors. */
329 if (n <= 0 || m < n || tol < 0.) return LevenbergMarquardtSpace::ImproperInputParameters;
330
331 resetParameters();
332 m_ftol = tol;
333 m_xtol = tol;
334 m_maxfev = 100 * (n + 1);
335
336 return minimize(x);
337}
338
339template <typename FunctorType>
340LevenbergMarquardtSpace::Status LevenbergMarquardt<FunctorType>::lmdif1(FunctorType &functor, FVectorType &x,
341 Index *nfev, const Scalar tol) {
342 Index n = x.size();
343 Index m = functor.values();
344
345 /* check the input parameters for errors. */
346 if (n <= 0 || m < n || tol < 0.) return LevenbergMarquardtSpace::ImproperInputParameters;
347
348 NumericalDiff<FunctorType> numDiff(functor);
349 // embedded LevenbergMarquardt
351 lm.setFtol(tol);
352 lm.setXtol(tol);
353 lm.setMaxfev(200 * (n + 1));
354
355 LevenbergMarquardtSpace::Status info = LevenbergMarquardtSpace::Status(lm.minimize(x));
356 if (nfev) *nfev = lm.nfev();
357 return info;
358}
359
360} // end namespace Eigen
361
362#endif // EIGEN_LEVENBERGMARQUARDT_H
Performs non linear optimization over a non-linear function, using a variant of the Levenberg Marquar...
Definition LevenbergMarquardt.h:104
RealScalar epsilon() const
Definition LevenbergMarquardt.h:181
ComputationInfo info() const
Reports whether the minimization was successful.
Definition LevenbergMarquardt.h:233
void setFtol(RealScalar ftol)
Definition LevenbergMarquardt.h:151
RealScalar gtol() const
Definition LevenbergMarquardt.h:175
void resetParameters()
Definition LevenbergMarquardt.h:136
RealScalar ftol() const
Definition LevenbergMarquardt.h:172
FVectorType & diag()
Definition LevenbergMarquardt.h:187
RealScalar gnorm() const
Definition LevenbergMarquardt.h:202
RealScalar fnorm() const
Definition LevenbergMarquardt.h:199
Index maxfev() const
Definition LevenbergMarquardt.h:184
void setExternalScaling(bool value)
Definition LevenbergMarquardt.h:166
RealScalar xtol() const
Definition LevenbergMarquardt.h:169
RealScalar lm_param(void) const
Definition LevenbergMarquardt.h:205
JacobianType & matrixR()
Definition LevenbergMarquardt.h:218
PermutationType permutation() const
Definition LevenbergMarquardt.h:222
void setGtol(RealScalar gtol)
Definition LevenbergMarquardt.h:154
void setEpsilon(RealScalar epsfcn)
Definition LevenbergMarquardt.h:160
void setXtol(RealScalar xtol)
Definition LevenbergMarquardt.h:148
FVectorType & fvec()
Definition LevenbergMarquardt.h:209
void setFactor(RealScalar factor)
Definition LevenbergMarquardt.h:157
RealScalar factor() const
Definition LevenbergMarquardt.h:178
Index nfev() const
Definition LevenbergMarquardt.h:193
void setMaxfev(Index maxfev)
Definition LevenbergMarquardt.h:163
Index njev() const
Definition LevenbergMarquardt.h:196
Index iterations() const
Definition LevenbergMarquardt.h:190
JacobianType & jacobian()
Definition LevenbergMarquardt.h:213
Definition NumericalDiff.h:51
ComputationInfo
Namespace containing all symbols from the Eigen library.