Eigen-Contrib  5.0.1
 
Loading...
Searching...
No Matches
NumericalDiff.h
1// -*- coding: utf-8
2// vim: set fileencoding=utf-8
3// SPDX-License-Identifier: MPL-2.0
4
5// This file is part of Eigen, a lightweight C++ template library
6// for linear algebra.
7//
8// Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org>
9//
10// This Source Code Form is subject to the terms of the Mozilla
11// Public License v. 2.0. If a copy of the MPL was not distributed
12// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
13
14#ifndef EIGEN_NUMERICAL_DIFF_H
15#define EIGEN_NUMERICAL_DIFF_H
16
17// IWYU pragma: private
18#include "./InternalHeaderCheck.h"
19
20namespace Eigen {
21
22namespace internal {
23
24// Keeps -ffast-math from folding the rounded evaluation points back into x and h, e.g. (x + h) - x
25// into h. EIGEN_OPTIMIZATION_BARRIER is an asm operand constraint restricted to plain types (see
26// Macros.h), so class-type scalars go unguarded.
27template <typename Scalar, std::enable_if_t<std::is_floating_point<Scalar>::value, int> = 0>
28EIGEN_STRONG_INLINE void numerical_diff_barrier(Scalar& x) {
29 EIGEN_UNUSED_VARIABLE(x);
30 EIGEN_OPTIMIZATION_BARRIER(x)
31}
32template <typename Scalar, std::enable_if_t<!std::is_floating_point<Scalar>::value, int> = 0>
33EIGEN_STRONG_INLINE void numerical_diff_barrier(Scalar&) {}
34
35} // namespace internal
36
37enum NumericalDiffMode { Forward, Central };
38
50template <typename Functor_, NumericalDiffMode mode = Forward>
51class NumericalDiff : public Functor_ {
52 public:
53 typedef Functor_ Functor;
54 typedef typename Functor::Scalar Scalar;
55 typedef typename Functor::InputType InputType;
56 typedef typename Functor::ValueType ValueType;
57 typedef typename Functor::JacobianType JacobianType;
58
59 NumericalDiff(Scalar _epsfcn = 0.) : Functor(), epsfcn(_epsfcn) {}
60 NumericalDiff(const Functor& f, Scalar _epsfcn = 0.) : Functor(f), epsfcn(_epsfcn) {}
61
62 // forward constructors
63 template <typename T0>
64 NumericalDiff(const T0& a0) : Functor(a0), epsfcn(0) {}
65 template <typename T0, typename T1>
66 NumericalDiff(const T0& a0, const T1& a1) : Functor(a0, a1), epsfcn(0) {}
67 template <typename T0, typename T1, typename T2>
68 NumericalDiff(const T0& a0, const T1& a1, const T2& a2) : Functor(a0, a1, a2), epsfcn(0) {}
69
70 enum { InputsAtCompileTime = Functor::InputsAtCompileTime, ValuesAtCompileTime = Functor::ValuesAtCompileTime };
71
79 int df(const InputType& _x, JacobianType& jac) const {
80 using std::abs;
81 using std::sqrt;
82 /* Local variables */
83 Scalar h;
84 int nfev = 0;
85 const typename InputType::Index n = _x.size();
86 const Scalar eps = sqrt(((std::max)(epsfcn, NumTraits<Scalar>::epsilon())));
87 ValueType val1, val2;
88 InputType x = _x;
89 // TODO: We should do this only if the size is not already known.
90 val1.resize(Functor::values());
91 val2.resize(Functor::values());
92
93 // initialization
94 switch (mode) {
95 case Forward:
96 // compute f(x)
97 Functor::operator()(x, val1);
98 nfev++;
99 break;
100 case Central:
101 // do nothing
102 break;
103 default:
104 eigen_assert(false);
105 }
106
107 // Function Body
108 for (int j = 0; j < n; ++j) {
109 const Scalar x_abs = abs(x[j]);
110 h = numext::maxi(x_abs, Scalar(1)) * eps;
111 // The functor is evaluated at fl(x[j] + h), so divide by that representable step: the rounding
112 // of x[j] + h perturbs h by up to ulp(x[j]) <= epsilon/eps * h <= sqrt(epsilon) * h, comparable
113 // to the error of the difference quotient itself.
114 Scalar x_plus = _x[j] + h;
115 internal::numerical_diff_barrier(x_plus);
116 h = x_plus - _x[j];
117 switch (mode) {
118 case Forward:
119 x[j] = x_plus;
120 Functor::operator()(x, val2);
121 nfev++;
122 x[j] = _x[j];
123 jac.col(j) = (val2 - val1) / h;
124 break;
125 case Central: {
126 x[j] = x_plus;
127 Functor::operator()(x, val2);
128 nfev++;
129 // x[j] - h can round (a tie when x[j] < 0 has |x[j]| within h above a power of two), so
130 // divide by the separation of the two evaluation points rather than by 2*h.
131 Scalar x_minus = _x[j] - h;
132 internal::numerical_diff_barrier(x_minus);
133 x[j] = x_minus;
134 Functor::operator()(x, val1);
135 nfev++;
136 x[j] = _x[j];
137 jac.col(j) = (val2 - val1) / (x_plus - x_minus);
138 break;
139 }
140 default:
141 eigen_assert(false);
142 }
143 }
144 return nfev;
145 }
146
147 private:
148 Scalar epsfcn;
149
150 NumericalDiff& operator=(const NumericalDiff&) = delete;
151};
152
153} // end namespace Eigen
154
155// vim: ai ts=4 sts=4 et sw=4
156#endif // EIGEN_NUMERICAL_DIFF_H
Definition NumericalDiff.h:51
int df(const InputType &_x, JacobianType &jac) const
Definition NumericalDiff.h:79
Namespace containing all symbols from the Eigen library.