numerics
Loading...
Searching...
No Matches
quadrature.cpp
Go to the documentation of this file.
1/// @file quadrature.cpp
3#include "analysis/types.hpp"
4#include <cmath>
5#include <stdexcept>
6#include <vector>
7
8#ifdef NUMERICS_HAS_OMP
9#include <omp.h>
10#endif
11
12namespace num {
13
15 real h = (b - a) / n;
16 real sum = 0.0;
17#ifdef NUMERICS_HAS_OMP
18 #pragma omp parallel for reduction(+:sum) schedule(static) if(backend == Backend::omp)
19#endif
20 for (idx i = 1; i < n; ++i)
21 sum += f(a + i * h);
22 return h * (0.5 * (f(a) + f(b)) + sum);
23}
24
26 if (n % 2 != 0)
27 throw std::invalid_argument("simpson: n must be even");
28 real h = (b - a) / n;
29 real sum = f(a) + f(b);
30#ifdef NUMERICS_HAS_OMP
31 #pragma omp parallel for reduction(+:sum) schedule(static) if(backend == Backend::omp)
32#endif
33 for (idx i = 1; i < n; ++i)
34 sum += f(a + i * h) * (i % 2 == 0 ? 2.0 : 4.0);
35 return h / 3.0 * sum;
36}
37
38// Gauss-Legendre nodes and weights on [-1, 1] for p = 1..5
39// Source: Abramowitz & Stegun, Table 25.4
40static constexpr real GL_NODES[5][5] = {
41 {0.0, 0, 0, 0, 0},
42 {-0.5773502691896257, 0.5773502691896257, 0, 0, 0},
43 {-0.7745966692414834, 0.0, 0.7745966692414834, 0, 0},
44 {-0.8611363115940526, -0.3399810435848563,
45 0.3399810435848563, 0.8611363115940526, 0},
46 {-0.9061798459386640, -0.5384693101056831, 0.0,
47 0.5384693101056831, 0.9061798459386640}
48};
49static constexpr real GL_WEIGHTS[5][5] = {
50 {2.0, 0, 0, 0, 0},
51 {1.0, 1.0, 0, 0, 0},
52 {0.5555555555555556, 0.8888888888888889, 0.5555555555555556, 0, 0},
53 {0.3478548451374538, 0.6521451548625461,
54 0.6521451548625461, 0.3478548451374538, 0},
55 {0.2369268850561891, 0.4786286704993665, 0.5688888888888889,
56 0.4786286704993665, 0.2369268850561891}
57};
58
60 if (p < 1 || p > 5)
61 throw std::invalid_argument("gauss_legendre: p must be 1..5");
62 real mid = 0.5 * (a + b);
63 real half = 0.5 * (b - a);
64 real sum = 0.0;
65 for (idx i = 0; i < p; ++i)
66 sum += GL_WEIGHTS[p - 1][i] * f(mid + half * GL_NODES[p - 1][i]);
67 return half * sum;
68}
69
70// Recursive adaptive Simpson helper
71static real adaptive_helper(ScalarFn f, real a, real b,
72 real fa, real fm, real fb,
74 real mid_l = 0.5 * (a + b * 0.5 + a * 0.5); // midpoint of [a, mid]
75 real mid_r = 0.5 * (0.5 * (a + b) + b); // midpoint of [mid, b]
76 real mid = 0.5 * (a + b);
77 real fl = f(0.5 * (a + mid));
78 real fr = f(0.5 * (mid + b));
80
81 real left = (b - a) / 12.0 * (fa + 4.0 * fl + fm);
82 real right = (b - a) / 12.0 * (fm + 4.0 * fr + fb);
84
85 if (depth == 0 || std::abs(delta) <= 15.0 * tol)
86 return left + right + delta / 15.0;
87
88 return adaptive_helper(f, a, mid, fa, fl, fm, left, tol * 0.5, depth - 1)
89 + adaptive_helper(f, mid, b, fm, fr, fb, right, tol * 0.5, depth - 1);
90}
91
93 real fa = f(a), fb = f(b), fm = f(0.5 * (a + b));
94 real est = (b - a) / 6.0 * (fa + 4.0 * fm + fb);
95 return adaptive_helper(f, a, b, fa, fm, fb, est, tol, max_depth);
96}
97
99 std::vector<std::vector<real>> R(max_levels, std::vector<real>(max_levels, 0.0));
100 R[0][0] = 0.5 * (b - a) * (f(a) + f(b));
101
102 for (idx i = 1; i < max_levels; ++i) {
103 idx n = idx(1) << i; // 2^i panels
104 real h = (b - a) / n;
105 real sum = 0.0;
106 for (idx k = 1; k < n; k += 2)
107 sum += f(a + k * h);
108 R[i][0] = 0.5 * R[i - 1][0] + h * sum;
109
110 // Richardson extrapolation
111 real factor = 1.0;
112 for (idx j = 1; j <= i; ++j) {
113 factor *= 4.0;
114 R[i][j] = R[i][j - 1] + (R[i][j - 1] - R[i - 1][j - 1]) / (factor - 1.0);
115 }
116
117 if (i > 0 && std::abs(R[i][i] - R[i - 1][i - 1]) < tol)
118 return R[i][i];
119 }
120 return R[max_levels - 1][max_levels - 1];
121}
122
123} // namespace num
Common function type aliases for the analysis module.
real trapz(ScalarFn f, real a, real b, idx n=100, Backend backend=Backend::seq)
Trapezoidal rule with n panels.
double real
Definition types.hpp:10
Backend
Selects which backend handles a linalg operation.
Definition policy.hpp:19
constexpr T ipow(T x) noexcept
Compute x^N at compile time via repeated squaring.
std::size_t idx
Definition types.hpp:11
real gauss_legendre(ScalarFn f, real a, real b, idx p=5)
Gauss-Legendre quadrature (exact for polynomials up to degree 2p-1)
real adaptive_simpson(ScalarFn f, real a, real b, real tol=1e-8, idx max_depth=50)
Adaptive Simpson quadrature.
real simpson(ScalarFn f, real a, real b, idx n=100, Backend backend=Backend::seq)
Simpson's 1/3 rule with n panels (n must be even)
std::function< real(real)> ScalarFn
Real-valued scalar function f(x)
Definition types.hpp:11
real romberg(ScalarFn f, real a, real b, real tol=1e-10, idx max_levels=12)
Romberg integration (Richardson extrapolation on trapezoidal rule)
Numerical integration (quadrature) on [a, b].