Eigen-unsupported  5.0.1-dev+284dcc12
 
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 campaigned 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
19#ifndef EIGEN_LEVENBERGMARQUARDT_H
20#define EIGEN_LEVENBERGMARQUARDT_H
21
22// IWYU pragma: private
23#include "./InternalHeaderCheck.h"
24
25namespace Eigen {
26namespace LevenbergMarquardtSpace {
27enum Status {
28 NotStarted = -2,
29 Running = -1,
30 ImproperInputParameters = 0,
31 RelativeReductionTooSmall = 1,
32 RelativeErrorTooSmall = 2,
33 RelativeErrorAndReductionTooSmall = 3,
34 CosinusTooSmall = 4,
35 TooManyFunctionEvaluation = 5,
36 FtolTooSmall = 6,
37 XtolTooSmall = 7,
38 GtolTooSmall = 8,
39 UserAsked = 9
40};
41}
42
43template <typename Scalar_, int NX = Dynamic, int NY = Dynamic>
44struct DenseFunctor {
45 typedef Scalar_ Scalar;
46 enum { InputsAtCompileTime = NX, ValuesAtCompileTime = NY };
47 typedef Matrix<Scalar, InputsAtCompileTime, 1> InputType;
48 typedef Matrix<Scalar, ValuesAtCompileTime, 1> ValueType;
49 typedef Matrix<Scalar, ValuesAtCompileTime, InputsAtCompileTime> JacobianType;
50 typedef ColPivHouseholderQR<JacobianType> QRSolver;
51 const int m_inputs, m_values;
52
53 DenseFunctor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
54 DenseFunctor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
55
56 int inputs() const { return m_inputs; }
57 int values() const { return m_values; }
58
59 // int operator()(const InputType &x, ValueType& fvec) { }
60 // should be defined in derived classes
61
62 // int df(const InputType &x, JacobianType& fjac) { }
63 // should be defined in derived classes
64};
65
66template <typename Scalar_, typename Index_>
67struct SparseFunctor {
68 typedef Scalar_ Scalar;
69 typedef Index_ Index;
70 typedef Matrix<Scalar, Dynamic, 1> InputType;
71 typedef Matrix<Scalar, Dynamic, 1> ValueType;
72 typedef SparseMatrix<Scalar, ColMajor, Index> JacobianType;
73 typedef SparseQR<JacobianType, COLAMDOrdering<int> > QRSolver;
74 enum { InputsAtCompileTime = Dynamic, ValuesAtCompileTime = Dynamic };
75
76 SparseFunctor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
77
78 int inputs() const { return m_inputs; }
79 int values() const { return m_values; }
80
81 const int m_inputs, m_values;
82 // int operator()(const InputType &x, ValueType& fvec) { }
83 // to be defined in the functor
84
85 // int df(const InputType &x, JacobianType& fjac) { }
86 // to be defined in the functor if no automatic differentiation
87};
88namespace internal {
89template <typename QRSolver, typename VectorType>
90void lmpar2(const QRSolver &qr, const VectorType &diag, const VectorType &qtb, typename VectorType::Scalar m_delta,
91 typename VectorType::Scalar &par, VectorType &x);
92}
101template <typename FunctorType_>
102class LevenbergMarquardt : internal::no_assignment_operator {
103 public:
104 typedef FunctorType_ FunctorType;
105 typedef typename FunctorType::QRSolver QRSolver;
106 typedef typename FunctorType::JacobianType JacobianType;
107 typedef typename JacobianType::Scalar Scalar;
108 typedef typename JacobianType::RealScalar RealScalar;
109 typedef typename QRSolver::StorageIndex PermIndex;
110 typedef Matrix<Scalar, Dynamic, 1> FVectorType;
111 typedef PermutationMatrix<Dynamic, Dynamic, int> PermutationType;
112
113 public:
114 LevenbergMarquardt(FunctorType &functor)
115 : m_functor(functor),
116 m_nfev(0),
117 m_njev(0),
118 m_fnorm(0.0),
119 m_gnorm(0),
120 m_isInitialized(false),
121 m_info(InvalidInput) {
123 m_useExternalScaling = false;
124 }
125
126 LevenbergMarquardtSpace::Status minimize(FVectorType &x);
127 LevenbergMarquardtSpace::Status minimizeInit(FVectorType &x);
128 LevenbergMarquardtSpace::Status minimizeOneStep(FVectorType &x);
129 LevenbergMarquardtSpace::Status lmder1(FVectorType &x, const Scalar tol = std::sqrt(NumTraits<Scalar>::epsilon()));
130 static LevenbergMarquardtSpace::Status lmdif1(FunctorType &functor, FVectorType &x, Index *nfev,
131 const Scalar tol = std::sqrt(NumTraits<Scalar>::epsilon()));
132
135 using std::sqrt;
136
137 m_factor = 100.;
138 m_maxfev = 400;
141 m_gtol = 0.;
142 m_epsfcn = 0.;
143 }
144
146 void setXtol(RealScalar xtol) { m_xtol = xtol; }
147
149 void setFtol(RealScalar ftol) { m_ftol = ftol; }
150
152 void setGtol(RealScalar gtol) { m_gtol = gtol; }
153
155 void setFactor(RealScalar factor) { m_factor = factor; }
156
158 void setEpsilon(RealScalar epsfcn) { m_epsfcn = epsfcn; }
159
161 void setMaxfev(Index maxfev) { m_maxfev = maxfev; }
162
164 void setExternalScaling(bool value) { m_useExternalScaling = value; }
165
167 RealScalar xtol() const { return m_xtol; }
168
170 RealScalar ftol() const { return m_ftol; }
171
173 RealScalar gtol() const { return m_gtol; }
174
176 RealScalar factor() const { return m_factor; }
177
179 RealScalar epsilon() const { return m_epsfcn; }
180
182 Index maxfev() const { return m_maxfev; }
183
185 FVectorType &diag() { return m_diag; }
186
188 Index iterations() { return m_iter; }
189
191 Index nfev() { return m_nfev; }
192
194 Index njev() { return m_njev; }
195
197 RealScalar fnorm() { return m_fnorm; }
198
200 RealScalar gnorm() { return m_gnorm; }
201
203 RealScalar lm_param(void) { return m_par; }
204
207 FVectorType &fvec() { return m_fvec; }
208
211 JacobianType &jacobian() { return m_fjac; }
212
216 JacobianType &matrixR() { return m_rfactor; }
217
220 PermutationType permutation() { return m_permutation; }
221
231 ComputationInfo info() const { return m_info; }
232
233 private:
234 JacobianType m_fjac;
235 JacobianType m_rfactor; // The triangular matrix R from the QR of the jacobian matrix m_fjac
236 FunctorType &m_functor;
237 FVectorType m_fvec, m_qtf, m_diag;
238 Index n;
239 Index m;
240 Index m_nfev;
241 Index m_njev;
242 RealScalar m_fnorm; // Norm of the current vector function
243 RealScalar m_gnorm; // Norm of the gradient of the error
244 RealScalar m_factor; //
245 Index m_maxfev; // Maximum number of function evaluation
246 RealScalar m_ftol; // Tolerance in the norm of the vector function
247 RealScalar m_xtol; //
248 RealScalar m_gtol; // tolerance of the norm of the error gradient
249 RealScalar m_epsfcn; //
250 Index m_iter; // Number of iterations performed
251 RealScalar m_delta;
252 bool m_useExternalScaling;
253 PermutationType m_permutation;
254 FVectorType m_wa1, m_wa2, m_wa3, m_wa4; // Temporary vectors
255 RealScalar m_par;
256 bool m_isInitialized; // Check whether the minimization step has been called
257 ComputationInfo m_info;
258};
259
260template <typename FunctorType>
261LevenbergMarquardtSpace::Status LevenbergMarquardt<FunctorType>::minimize(FVectorType &x) {
262 LevenbergMarquardtSpace::Status status = minimizeInit(x);
263 if (status == LevenbergMarquardtSpace::ImproperInputParameters) {
264 m_isInitialized = true;
265 return status;
266 }
267 do {
268 // std::cout << " uv " << x.transpose() << "\n";
269 status = minimizeOneStep(x);
270 } while (status == LevenbergMarquardtSpace::Running);
271 m_isInitialized = true;
272 return status;
273}
274
275template <typename FunctorType>
276LevenbergMarquardtSpace::Status LevenbergMarquardt<FunctorType>::minimizeInit(FVectorType &x) {
277 n = x.size();
278 m = m_functor.values();
279
280 m_wa1.resize(n);
281 m_wa2.resize(n);
282 m_wa3.resize(n);
283 m_wa4.resize(m);
284 m_fvec.resize(m);
285 // FIXME Sparse Case : Allocate space for the jacobian
286 m_fjac.resize(m, n);
287 // m_fjac.reserve(VectorXi::Constant(n,5)); // FIXME Find a better alternative
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:102
RealScalar epsilon() const
Definition LevenbergMarquardt.h:179
ComputationInfo info() const
Reports whether the minimization was successful.
Definition LevenbergMarquardt.h:231
void setFtol(RealScalar ftol)
Definition LevenbergMarquardt.h:149
RealScalar gtol() const
Definition LevenbergMarquardt.h:173
void resetParameters()
Definition LevenbergMarquardt.h:134
RealScalar ftol() const
Definition LevenbergMarquardt.h:170
FVectorType & diag()
Definition LevenbergMarquardt.h:185
Index maxfev() const
Definition LevenbergMarquardt.h:182
void setExternalScaling(bool value)
Definition LevenbergMarquardt.h:164
RealScalar xtol() const
Definition LevenbergMarquardt.h:167
RealScalar gnorm()
Definition LevenbergMarquardt.h:200
Index iterations()
Definition LevenbergMarquardt.h:188
JacobianType & matrixR()
Definition LevenbergMarquardt.h:216
Index njev()
Definition LevenbergMarquardt.h:194
void setGtol(RealScalar gtol)
Definition LevenbergMarquardt.h:152
RealScalar lm_param(void)
Definition LevenbergMarquardt.h:203
RealScalar fnorm()
Definition LevenbergMarquardt.h:197
void setEpsilon(RealScalar epsfcn)
Definition LevenbergMarquardt.h:158
void setXtol(RealScalar xtol)
Definition LevenbergMarquardt.h:146
FVectorType & fvec()
Definition LevenbergMarquardt.h:207
void setFactor(RealScalar factor)
Definition LevenbergMarquardt.h:155
Index nfev()
Definition LevenbergMarquardt.h:191
PermutationType permutation()
Definition LevenbergMarquardt.h:220
RealScalar factor() const
Definition LevenbergMarquardt.h:176
void setMaxfev(Index maxfev)
Definition LevenbergMarquardt.h:161
JacobianType & jacobian()
Definition LevenbergMarquardt.h:211
Definition NumericalDiff.h:35
ComputationInfo
Namespace containing all symbols from the Eigen library.
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sqrt_op< typename Derived::Scalar >, const Derived > sqrt(const Eigen::ArrayBase< Derived > &x)
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
const int Dynamic