flexiblesusy is hosted by Hepforge, IPPP Durham
FlexibleSUSY
derivative.hpp
Go to the documentation of this file.
1// ====================================================================
2// This file is part of FlexibleSUSY.
3//
4// FlexibleSUSY is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published
6// by the Free Software Foundation, either version 3 of the License,
7// or (at your option) any later version.
8//
9// FlexibleSUSY is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with FlexibleSUSY. If not, see
16// <http://www.gnu.org/licenses/>.
17// ====================================================================
18
24#ifndef DERIVATIVE_H
25#define DERIVATIVE_H
26
27#include <cmath>
28#include <limits>
29#include <vector>
30
31namespace flexiblesusy {
32
48template <class F, class A>
49auto derivative_forward_fx(const F& f, A x, decltype(f(x)) fx, A eps = std::numeric_limits<A>::epsilon())
50 -> decltype(f(x))
51{
52 const A h = std::fabs(x) < eps ? eps : std::sqrt(eps) * x;
53 volatile const A xph = x + h; // avoid away optimization
54 const A dx = xph - x;
55 return (f(xph) - fx) / dx;
56}
57
73template <class F, class A>
74auto derivative_backward_fx(const F& f, A x, decltype(f(x)) fx, A eps = std::numeric_limits<A>::epsilon())
75 -> decltype(f(x))
76{
77 const A h = std::fabs(x) < eps ? eps : std::sqrt(eps) * x;
78 volatile const A xph = x - h; // avoid away optimization
79 const A dx = x - xph;
80 return (fx - f(xph)) / dx;
81}
82
98template <int Order, int sign, class F, class A>
99auto derivative_one_sided(const F& f, A x, A eps = std::numeric_limits<A>::epsilon()) -> decltype(f(x))
100{
101 static_assert(Order <= 7, "1st forward derivative with order > 7 not implemented");
102 static_assert(sign == -1 || sign == +1, "sign must be either +1 or -1 for one-sided derivative");
103
104 using return_type = decltype(f(x));
105
106 // coefficients from Math. Comp. 51 (1988), 699-706, Table 3
107 // DOI: http://dx.doi.org/10.1090/S0025-5718-1988-0935077-0
108 static const std::vector<std::vector<double> > coeffs = {
109 {-1., 1.},
110 {-3./2., 2., -1./2.},
111 {-11./6., 3., -3./2., 1./3.},
112 {-25./12., 4., -3., 4./3., -1./4.},
113 {-137./60., 5., -5., 10./3., -5./4., 1./5.},
114 {-49./20., 6., -15./2., 20./3., -15./4., 6./5., -1./6.},
115 {-363./140., 7., -21./2., 35./3., -35./4., 21./5., -7./6., 1./7.},
116 {-761./280., 8., -14., 56./3., -35./2., 56./5., -14./3., 8./7., -1./8.}
117 };
118
119 const A h = std::fabs(x) < eps ? eps : std::sqrt(eps) * x;
120 return_type result = 0;
121
122 for (int i = 0; i < Order + 2; i++) {
123 const double coeff = coeffs[Order][i];
124 result += sign * coeff * f(x + sign*i*h);
125 }
126
127 return result / h;
128}
129
142template <int Order, class F, class A>
143auto derivative_forward(const F& f, A x, A eps = std::numeric_limits<A>::epsilon()) -> decltype(f(x))
144{
145 return derivative_one_sided<Order, -1>(f, x, eps);
146}
147
160template <int Order, class F, class A>
161auto derivative_backward(const F& f, A x, A eps = std::numeric_limits<A>::epsilon()) -> decltype(f(x))
162{
163 return derivative_one_sided<Order, +1>(f, x, eps);
164}
165
178template <int Order, class F, class A>
180 -> decltype(f(x))
181{
182 static_assert(Order <= 3, "1st central derivative with order > 3 not implemented");
183
184 using return_type = decltype(f(x));
185
186 // coefficients from Math. Comp. 51 (1988), 699-706, Table 1
187 // DOI: http://dx.doi.org/10.1090/S0025-5718-1988-0935077-0
188 static const std::vector<std::vector<double> > coeffs = {
189 {0.5},
190 {2./3., -1./12.},
191 {3./4., -3./20., 1./60.},
192 {4./5., -1./5., 4./105., -1./280.}
193 };
194
195 const A h = std::fabs(x) < eps ? eps : std::sqrt(eps) * x;
196 return_type result = 0;
197
198 for (int i = 0; i < Order + 1; i++) {
199 const double coeff = coeffs[Order][i];
200 const A step = (i + 1) * h;
201 result += coeff * (f(x + step) - f(x - step));
202 }
203
204 return result / h;
205}
206
207} // namespace flexiblesusy
208
209#endif
void() A(aa)) coeff_t &arr
auto derivative_one_sided(const F &f, A x, A eps=std::numeric_limits< A >::epsilon()) -> decltype(f(x))
Definition: derivative.hpp:99
const Real epsilon
Definition: mathdefs.hpp:18
auto derivative_backward(const F &f, A x, A eps=std::numeric_limits< A >::epsilon()) -> decltype(f(x))
Definition: derivative.hpp:161
auto derivative_central(const F &f, A x, A eps=std::numeric_limits< A >::epsilon()) -> decltype(f(x))
Definition: derivative.hpp:179
std::complex< double > f(double tau) noexcept
T sign(T x)
Definition: mathdefs.hpp:65
auto derivative_forward(const F &f, A x, A eps=std::numeric_limits< A >::epsilon()) -> decltype(f(x))
Definition: derivative.hpp:143
auto derivative_forward_fx(const F &f, A x, decltype(f(x)) fx, A eps=std::numeric_limits< A >::epsilon()) -> decltype(f(x))
Definition: derivative.hpp:49
auto derivative_backward_fx(const F &f, A x, decltype(f(x)) fx, A eps=std::numeric_limits< A >::epsilon()) -> decltype(f(x))
Definition: derivative.hpp:74