33 double tolerance = 1e-6;
35 double alpha = sqrt(2.0 / 3.0);
36 double beta = 1.0 / sqrt(5.0);
37 double x1 = 0.942882415695480;
38 double x2 = 0.641853342345781;
39 double x3 = 0.236383199662150;
41 mutable std::vector<double> all_x_midpoints;
42 mutable std::vector<T> all_int;
45 static constexpr std::array<double, 4> coefficients = {11. / 210., 432.0 / 1470.0, 125. / 294., 16. / 35.};
47 std::vector<double> x_init = {-x1, -alpha, -x2, -beta, -x3, 0.0, x3, beta, x2, alpha, x1};
66 auto operator()(
auto f,
const std::pair<double, double> &domain)
const
67 requires(nda::clef::is_lazy<
decltype(f)>)
69 return nda::clef::make_expr_call(*
this, std::move(f), domain);
82 auto operator()(
auto const &f,
const std::pair<double, double> &domain)
const
83 requires(not nda::clef::is_lazy<
decltype(f)>)
87 auto h = 0.5 * (domain.second - domain.first);
89 auto m = 0.5 * (domain.first + domain.second);
92 std::vector<T> fx(11);
93 for (
int i = 0; i < 11; ++i) fx[i] = f(m + x_init[i] * h);
95 T fa = f(domain.first);
96 T fb = f(domain.second);
100 * (0.0158271919734802 * (fa + fb) + 0.0942738402188500 * (fx[0] + fx[10]) + 0.155071987336585 * (fx[1] + fx[9])
101 + 0.188821573960182 * (fx[2] + fx[8]) + 0.199773405226859 * (fx[3] + fx[7]) + 0.224926465333340 * (fx[4] + fx[6])
102 + 0.242611071901408 * fx[5]);
105 if constexpr (nda::Scalar<T>) {
106 if (std::abs(is) == 0.0) { is = domain.second - domain.first; }
108 nda::for_each(is.shape(), [&is, &domain](
auto... args) {
109 if (std::abs(is(args...)) == 0) is(args...) = domain.second - domain.first;
113 return adaptive_recursion(f, domain.first, domain.second, fx[0], fx[10], abs(is));
129 T adaptive_recursion(
auto &f,
const double xa,
const double xb,
const T fa,
const T fb,
const T is)
const {
132 double h = 0.5 * (xb - xa);
134 double midpoint = 0.5 * (xa + xb);
138 std::array<double, 5> x;
140 x[0] = midpoint - alpha * h;
141 x[1] = midpoint - beta * h;
143 x[3] = midpoint + beta * h;
144 x[4] = midpoint + alpha * h;
147 for (
int i = 0; i < 5; ++i) fx[i] = f(x[i]);
150 T i2 = (1. / 6. * h) * (fa + fb + 5.0 * (fx[1] + fx[3]));
152 T i1 = h * (coefficients[0] * (fa + fb) + coefficients[1] * (fx[0] + fx[4]) + coefficients[2] * (fx[1] + fx[3]) + coefficients[3] * fx[2]);
155 bool tolerance_met =
false;
156 if constexpr (nda::Scalar<T>) {
157 tolerance_met = std::abs(i1 - i2) <= std::abs(tolerance * is);
159 tolerance_met = nda::max_element(nda::abs(i1 - i2)) <= nda::max_element(nda::abs(tolerance * is));
161 if (tolerance_met || x[0] <= xa || xb <= x[4]) {
162 if ((midpoint <= xa || xb <= midpoint)) {
163 std::cerr <<
"Cannot subdivide integration domain further; however, desired acccuracy was not reached." << std::endl;
168 return adaptive_recursion(f, xa, x[0], fa, fx[0], is) + adaptive_recursion(f, x[0], x[1], fx[0], fx[1], is)
169 + adaptive_recursion(f, x[1], x[2], fx[1], fx[2], is) + adaptive_recursion(f, x[2], x[3], fx[2], fx[3], is)
170 + adaptive_recursion(f, x[3], x[4], fx[3], fx[4], is) + adaptive_recursion(f, x[4], xb, fx[4], fb, is);