blob: ea5d8bc2749bb0ff97bff31cff6b941a0a069348 [file] [log] [blame]
Thomas Capricelliac8f7d82009-11-09 03:32:40 +01001// -*- coding: utf-8
2// vim: set fileencoding=utf-8
3
Thomas Capricelli206b5e32009-09-28 02:43:07 +02004// This file is part of Eigen, a lightweight C++ template library
5// for linear algebra.
6//
7// Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org>
8//
Benoit Jacob69124cf2012-07-13 14:42:47 -04009// This Source Code Form is subject to the terms of the Mozilla
10// Public License v. 2.0. If a copy of the MPL was not distributed
11// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
Thomas Capricelli206b5e32009-09-28 02:43:07 +020012
13#ifndef EIGEN_NUMERICAL_DIFF_H
14#define EIGEN_NUMERICAL_DIFF_H
15
Jitse Niesen3c412182012-04-15 11:06:28 +010016namespace Eigen {
17
Thomas Capricelli87be19d2009-09-28 02:55:30 +020018enum NumericalDiffMode {
19 Forward,
20 Central
21};
22
23
Thomas Capricelli09cb27c2009-11-09 03:25:21 +010024/**
Thomas Capricelli09cb27c2009-11-09 03:25:21 +010025 * This class allows you to add a method df() to your functor, which will
26 * use numerical differentiation to compute an approximate of the
27 * derivative for the functor. Of course, if you have an analytical form
Thomas Capricellide195e02009-11-09 04:21:45 +010028 * for the derivative, you should rather implement df() by yourself.
Thomas Capricelli09cb27c2009-11-09 03:25:21 +010029 *
30 * More information on
31 * http://en.wikipedia.org/wiki/Numerical_differentiation
32 *
Thomas Capricellide195e02009-11-09 04:21:45 +010033 * Currently only "Forward" and "Central" scheme are implemented.
Thomas Capricelli09cb27c2009-11-09 03:25:21 +010034 */
bjornpiltzaf177702009-12-03 09:27:15 +010035template<typename _Functor, NumericalDiffMode mode=Forward>
36class NumericalDiff : public _Functor
Thomas Capricelli206b5e32009-09-28 02:43:07 +020037{
38public:
bjornpiltzaf177702009-12-03 09:27:15 +010039 typedef _Functor Functor;
Thomas Capricelli206b5e32009-09-28 02:43:07 +020040 typedef typename Functor::Scalar Scalar;
41 typedef typename Functor::InputType InputType;
42 typedef typename Functor::ValueType ValueType;
43 typedef typename Functor::JacobianType JacobianType;
44
45 NumericalDiff(Scalar _epsfcn=0.) : Functor(), epsfcn(_epsfcn) {}
46 NumericalDiff(const Functor& f, Scalar _epsfcn=0.) : Functor(f), epsfcn(_epsfcn) {}
47
48 // forward constructors
49 template<typename T0>
50 NumericalDiff(const T0& a0) : Functor(a0), epsfcn(0) {}
51 template<typename T0, typename T1>
52 NumericalDiff(const T0& a0, const T1& a1) : Functor(a0, a1), epsfcn(0) {}
53 template<typename T0, typename T1, typename T2>
Gael Guennebaud37d367a2012-06-15 07:56:55 +020054 NumericalDiff(const T0& a0, const T1& a1, const T2& a2) : Functor(a0, a1, a2), epsfcn(0) {}
Thomas Capricelli206b5e32009-09-28 02:43:07 +020055
56 enum {
57 InputsAtCompileTime = Functor::InputsAtCompileTime,
58 ValuesAtCompileTime = Functor::ValuesAtCompileTime
59 };
60
61 /**
62 * return the number of evaluation of functor
63 */
64 int df(const InputType& _x, JacobianType &jac) const
65 {
Gael Guennebauda76fbbf2012-11-06 15:25:50 +010066 using std::sqrt;
67 using std::abs;
Thomas Capricelli206b5e32009-09-28 02:43:07 +020068 /* Local variables */
69 Scalar h;
70 int nfev=0;
Hauke Heibele402d342010-06-20 15:52:34 +020071 const typename InputType::Index n = _x.size();
Gael Guennebauda76fbbf2012-11-06 15:25:50 +010072 const Scalar eps = sqrt(((std::max)(epsfcn,NumTraits<Scalar>::epsilon() )));
Thomas Capricelli87be19d2009-09-28 02:55:30 +020073 ValueType val1, val2;
Thomas Capricelli206b5e32009-09-28 02:43:07 +020074 InputType x = _x;
75 // TODO : we should do this only if the size is not already known
Thomas Capricelli87be19d2009-09-28 02:55:30 +020076 val1.resize(Functor::values());
77 val2.resize(Functor::values());
Thomas Capricelli206b5e32009-09-28 02:43:07 +020078
Thomas Capricelli79687372009-09-28 04:13:57 +020079 // initialization
Thomas Capricelli87be19d2009-09-28 02:55:30 +020080 switch(mode) {
81 case Forward:
82 // compute f(x)
83 Functor::operator()(x, val1); nfev++;
84 break;
85 case Central:
86 // do nothing
87 break;
88 default:
Jitse Niesen14e2ab02013-02-02 22:04:42 +000089 eigen_assert(false);
Thomas Capricelli87be19d2009-09-28 02:55:30 +020090 };
Thomas Capricelli206b5e32009-09-28 02:43:07 +020091
Thomas Capricelli79687372009-09-28 04:13:57 +020092 // Function Body
Thomas Capricelli206b5e32009-09-28 02:43:07 +020093 for (int j = 0; j < n; ++j) {
Gael Guennebauda76fbbf2012-11-06 15:25:50 +010094 h = eps * abs(x[j]);
Thomas Capricelli206b5e32009-09-28 02:43:07 +020095 if (h == 0.) {
96 h = eps;
97 }
Thomas Capricelli87be19d2009-09-28 02:55:30 +020098 switch(mode) {
99 case Forward:
100 x[j] += h;
101 Functor::operator()(x, val2);
102 nfev++;
103 x[j] = _x[j];
104 jac.col(j) = (val2-val1)/h;
105 break;
106 case Central:
107 x[j] += h;
108 Functor::operator()(x, val2); nfev++;
109 x[j] -= 2*h;
110 Functor::operator()(x, val1); nfev++;
111 x[j] = _x[j];
112 jac.col(j) = (val2-val1)/(2*h);
113 break;
114 default:
Jitse Niesen14e2ab02013-02-02 22:04:42 +0000115 eigen_assert(false);
Thomas Capricelli87be19d2009-09-28 02:55:30 +0200116 };
Thomas Capricelli206b5e32009-09-28 02:43:07 +0200117 }
118 return nfev;
119 }
120private:
121 Scalar epsfcn;
Hauke Heibel45d3b402010-06-09 09:30:22 +0200122
123 NumericalDiff& operator=(const NumericalDiff&);
Thomas Capricelli206b5e32009-09-28 02:43:07 +0200124};
125
Jitse Niesen3c412182012-04-15 11:06:28 +0100126} // end namespace Eigen
127
Thomas Capricelliac8f7d82009-11-09 03:32:40 +0100128//vim: ai ts=4 sts=4 et sw=4
Thomas Capricelli206b5e32009-09-28 02:43:07 +0200129#endif // EIGEN_NUMERICAL_DIFF_H
Thomas Capricelliac8f7d82009-11-09 03:32:40 +0100130