teqp 0.22.0
Loading...
Searching...
No Matches
finite_derivs.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <valarray>
4#include <map>
5
6namespace teqp{
7
21template<int Nderiv, int Norder, typename Function, typename Scalar>
22auto centered_diff(const Function &f, const Scalar x, const Scalar h) {
23
24 struct DiffCoeffs {
25 std::valarray<int> k;
26 std::valarray<Scalar> c;
27 };
28
29 // See https://en.wikipedia.org/wiki/Finite_difference_coefficient#Central_finite_difference
30 // Watch out that if you would like to use extended precision, you also need to keep
31 // all the coefficients in extended precision too
32 //
33 // This is because 1.0/2.0 is different than casting each of 1.0 and 2.0 to extended precision
34 // and then taking their ratio
35 using r = Scalar;
36 static std::map<std::tuple<int, int>, DiffCoeffs> CentralDiffCoeffs = {
37 {{1, 2}, {{-1,1}, {-r(1)/r(2), r(1)/r(2)}} },
38 {{1, 4}, {{-2,-1,1,2}, {r(1)/ r(12), -r(2)/r(3), r(2)/r(3), -r(1)/r(12)}} },
39 {{1, 6}, {{-3,-2,-1,1,2,3}, {-r(1)/r(60), r(3)/r(20), -r(3)/r(4), r(3)/r(4), -r(3)/r(20), r(1)/r(60)}} },
40
41 {{2, 2}, {{-1,0,1}, {1, -2, 1} }},
42 {{2, 4}, {{-2,-1,0,1,2}, {r(-1)/r(12), r(4)/r(3), r(-5)/r(2), r(4)/r(3), r(-1)/r(12)}} },
43 {{2, 6}, {{-3,-2,-1,0,1,2,3}, {r(1)/r(90), r(-3)/r(20), r(3)/r(2), r(-49)/r(18), r(3)/r(2), r(-3)/r(20), r(1)/r(90)}} },
44
45 {{3, 2}, {{-2, -1, 0, 1, 2}, {r(-1)/r(2), r(1), 0, r(-1), r(1)/r(2)}} },
46 {{3, 4}, {{-3,-2,-1,0,1,2,3}, {r(1)/r(8), r(-1), r(13)/r(8), 0, r(-13)/r(8), r(1), r(-1)/r(8)}} },
47 {{3, 6}, {{-4,-3,-2,-1,0,1,2,3,4}, {r(-7)/r(240), r(3)/r(10), r(-169)/r(120), r(61)/r(30), 0, r(-61)/r(30), r(169)/r(120), r(-3)/r(10), r(7)/r(240)}} },
48
49 {{4, 2}, {{-2,-1,0,1,2}, {1,-4,6,-4,1}} },
50 {{4, 4}, {{-3,-2,-1,0,1,2,3}, {-r(1)/r(6), r(2), -r(13)/r(2), r(28)/r(3.0), -r(13)/r(2), r(2), -r(1)/r(6)}} },
51 {{4, 6}, {{-4,-3,-2,-1,0,1,2,3,4}, {r(7)/r(240), -r(2)/r(5), r(169)/r(60), -r(122)/r(15), r(91)/r(8), -r(122)/r(15), r(169)/r(60), -r(2)/r(5), r(7)/r(240)}} },
52 };
53
54 auto [k, c] = CentralDiffCoeffs[std::make_tuple(Nderiv, Norder)];
55 if (c.size() == 0) {
56 throw std::invalid_argument("Cannot obtain the necessary finite differentiation coefficients");
57 }
58 // Sanity check...
59 if (c.size() != k.size()) {
60 throw std::invalid_argument("Finite differentiation coefficient arrays not the same size");
61 }
62 Scalar num = 0.0;
63 for (auto i = 0U; i < k.size(); ++i) {
64 num = num + c[i]*f(x + h*k[i]);
65 }
66 auto val = num / pow(h, Nderiv);
67 return val;
68}
69
70template<typename Function, typename Scalarx, typename Scalary>
71auto centered_diff_xy(const Function &f, const Scalarx x, const Scalary y, const Scalarx dx, const Scalary dy) {
72 return (f(x+dx, y+dy) - f(x+dx, y-dy) - f(x-dx, y+dy) + f(x-dx, y-dy))/(4*dx*dy);
73}
74
75template<typename Function, typename Vec, typename Scalar>
76auto gradient_forward(const Function &f, const Vec& x, Scalar h) {
77 Vec out = 0.0*x, xplus = x;
78 for (auto i = 0; i < out.size(); ++i){
79 xplus = x;
80 xplus[i] += h;
81 out[i] = (f(xplus)-f(x))/h;
82 }
83 return out;
84}
85
86}; // namespace teqp
auto gradient_forward(const Function &f, const Vec &x, Scalar h)
auto centered_diff(const Function &f, const Scalar x, const Scalar h)
auto centered_diff_xy(const Function &f, const Scalarx x, const Scalary y, const Scalarx dx, const Scalary dy)
auto pow(const double &x, const double &e)
Definition types.hpp:195