$darkmode
Eigen-unsupported  5.0.1-dev
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 
25 namespace Eigen {
26 namespace LevenbergMarquardtSpace {
27 enum 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 
43 template <typename Scalar_, int NX = Dynamic, int NY = Dynamic>
44 struct 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 
66 template <typename Scalar_, typename Index_>
67 struct 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 };
88 namespace internal {
89 template <typename QRSolver, typename VectorType>
90 void lmpar2(const QRSolver &qr, const VectorType &diag, const VectorType &qtb, typename VectorType::Scalar m_delta,
91  typename VectorType::Scalar &par, VectorType &x);
92 }
101 template <typename FunctorType_>
102 class 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;
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) {
122  resetParameters();
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 
260 template <typename FunctorType>
261 LevenbergMarquardtSpace::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 
275 template <typename FunctorType>
276 LevenbergMarquardtSpace::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 
323 template <typename FunctorType>
324 LevenbergMarquardtSpace::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 
339 template <typename FunctorType>
340 LevenbergMarquardtSpace::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
350  LevenbergMarquardt<NumericalDiff<FunctorType> > lm(numDiff);
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
void setMaxfev(Index maxfev)
Definition: LevenbergMarquardt.h:161
RealScalar epsilon() const
Definition: LevenbergMarquardt.h:179
Index iterations()
Definition: LevenbergMarquardt.h:188
void setGtol(RealScalar gtol)
Definition: LevenbergMarquardt.h:152
RealScalar xtol() const
Definition: LevenbergMarquardt.h:167
void setFactor(RealScalar factor)
Definition: LevenbergMarquardt.h:155
Performs non linear optimization over a non-linear function, using a variant of the Levenberg Marquar...
Definition: LevenbergMarquardt.h:102
RealScalar fnorm()
Definition: LevenbergMarquardt.h:197
Index nfev()
Definition: LevenbergMarquardt.h:191
const Eigen::CwiseUnaryOp< Eigen::internal::scalar_sqrt_op< typename Derived::Scalar >, const Derived > sqrt(const Eigen::ArrayBase< Derived > &x)
Namespace containing all symbols from the Eigen library.
RealScalar factor() const
Definition: LevenbergMarquardt.h:176
Index maxfev() const
Definition: LevenbergMarquardt.h:182
void resetParameters()
Definition: LevenbergMarquardt.h:134
RealScalar ftol() const
Definition: LevenbergMarquardt.h:170
void setExternalScaling(bool value)
Definition: LevenbergMarquardt.h:164
JacobianType & matrixR()
Definition: LevenbergMarquardt.h:216
Index njev()
Definition: LevenbergMarquardt.h:194
RealScalar gnorm()
Definition: LevenbergMarquardt.h:200
FVectorType & fvec()
Definition: LevenbergMarquardt.h:207
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
void setXtol(RealScalar xtol)
Definition: LevenbergMarquardt.h:146
PermutationType permutation()
Definition: LevenbergMarquardt.h:220
FVectorType & diag()
Definition: LevenbergMarquardt.h:185
RealScalar lm_param(void)
Definition: LevenbergMarquardt.h:203
JacobianType & jacobian()
Definition: LevenbergMarquardt.h:211
ComputationInfo info() const
Reports whether the minimization was successful.
Definition: LevenbergMarquardt.h:231
RealScalar gtol() const
Definition: LevenbergMarquardt.h:173
const int Dynamic
ComputationInfo
void setFtol(RealScalar ftol)
Definition: LevenbergMarquardt.h:149
void setEpsilon(RealScalar epsfcn)
Definition: LevenbergMarquardt.h:158