29 : rule_{std::move(rule)}, accumulator_template_{std::move(acc)} {}
31 template<concepts::UnivariateFunction<T> F>
33 return integrate_interval(std::forward<F>(f), a, b);
36 template<concepts::UnivariateFunction<T> F>
38 return adaptive_integrate(std::forward<F>(f), a, b, tol);
43 Acc accumulator_template_;
46 constexpr result_type integrate_interval(F&& f, T a, T b)
const {
47 Acc acc = accumulator_template_;
48 const T half_width = (b - a) / T(2);
49 const T center = (a + b) / T(2);
51 for (std::size_t i = 0; i < rule_.size(); ++i) {
52 T x = center + half_width * rule_.abscissa(i);
53 acc += rule_.weight(i) * f(x);
56 T integral = half_width * acc();
57 return {integral, std::numeric_limits<T>::epsilon() * std::abs(integral), rule_.size()};
61 constexpr result_type adaptive_integrate(F&& f, T a, T b, T tol, std::size_t depth = 0)
const {
62 constexpr std::size_t max_depth = 30;
66 if (depth >= max_depth) {
70 T mid = (a + b) / T(2);
75 T error = std::abs(whole.value() - combined.value());
79 T refined = combined.value() + (combined.value() - whole.value()) / T(15);
80 return {refined, error, combined.evaluations()};
84 result_type left_refined = adaptive_integrate(f, a, mid, tol / T(2), depth + 1);
85 result_type right_refined = adaptive_integrate(f, mid, b, tol / T(2), depth + 1);
87 return left_refined + right_refined;
104 template<concepts::UnivariateFunction<T> F>
105 constexpr
result_type operator()(F&& f, T a, T b, T tol = default_tolerance())
const {
106 if (std::isinf(a) && std::isinf(b)) {
107 return integrate_infinite(std::forward<F>(f), tol);
108 }
else if (std::isinf(a)) {
109 return integrate_left_infinite(std::forward<F>(f), b, tol);
110 }
else if (std::isinf(b)) {
111 return integrate_right_infinite(std::forward<F>(f), a, tol);
113 return integrate_finite(std::forward<F>(f), a, b, tol);
118 static constexpr T default_tolerance() {
return std::sqrt(std::numeric_limits<T>::epsilon()); }
121 constexpr result_type integrate_finite(F&& f, T a, T b, T tol)
const {
122 const T center = (a + b) / T(2);
123 const T half_width = (b - a) / T(2);
125 auto transformed = [&](T t) -> T {
126 return f(center + half_width * t);
129 return integrate_symmetric(transformed, half_width, tol);
133 constexpr result_type integrate_infinite(F&& f, T tol)
const {
134 auto transformed = [&](T t) -> T {
135 T scale = T(1) / (T(1) - t * t);
136 return f(t * scale) * scale * scale;
139 return integrate_symmetric(transformed, T(1), tol);
143 constexpr result_type integrate_left_infinite(F&& f, T b, T tol)
const {
144 auto transformed = [&](T t) -> T {
145 T scale = T(1) / (T(1) + t);
146 T
x = b - scale * (T(1) - t);
147 return f(x) * scale * scale;
150 return integrate_symmetric(transformed, T(1), tol);
154 constexpr result_type integrate_right_infinite(F&& f, T a, T tol)
const {
155 auto transformed = [&](T t) -> T {
156 T scale = T(1) / (T(1) - t);
157 T
x = a + scale * (T(1) + t);
158 return f(x) * scale * scale;
161 return integrate_symmetric(transformed, T(1), tol);
165 constexpr result_type integrate_symmetric(F&& f, T scale, T tol)
const {
166 quadrature::tanh_sinh_nodes<T> nodes;
170 std::size_t total_evals = 0;
172 for (std::size_t level = 0; level < nodes.max_level; ++level) {
174 std::size_t level_evals = 0;
177 T w = nodes.weight(0, 0);
178 level_acc += w * f(T(0));
181 std::size_t n = 1 << (level - 1);
182 for (std::size_t i = 1; i <= n; ++i) {
183 std::size_t index = 2 * i - 1;
184 T
x = nodes.abscissa(level, index);
185 T w = nodes.weight(level, index);
187 T val = f(x) + f(-x);
188 if (!std::isfinite(val))
break;
190 level_acc += w * val;
196 total_evals += level_evals;
198 T
sum = scale * h * acc();
199 T error = std::abs(sum - prev_sum);
201 if (level > 3 && error < tol * std::abs(sum)) {
202 return {
sum, error, level + 1, total_evals};
209 return {scale * h * acc(), tol, nodes.max_level, total_evals};