20template <std::
floating_po
int Real>
23 std::vector<std::complex<Real>> older(partialSums.size() + 1);
24 std::vector<std::complex<Real>> previous = partialSums;
25 std::complex<Real> best = partialSums.back();
26 std::complex<Real> lastEstimate = best;
27 Real bestDifference = std::numeric_limits<Real>::infinity();
28 const int maxOrder = std::min<int>(20,
static_cast<int>(partialSums.size()) - 1);
29 for (
int order = 1; order <= maxOrder; ++order) {
30 std::vector<std::complex<Real>> current(previous.size() - 1);
31 for (std::size_t i = 0; i < current.size(); ++i) {
32 const std::complex<Real> difference = previous[i + 1] - previous[i];
33 const Real scale = std::max({Real{1}, std::abs(previous[i]), std::abs(previous[i + 1])});
34 if (std::abs(difference) <= 20 * std::numeric_limits<Real>::epsilon() * scale)
35 current[i] = std::complex<Real>(std::numeric_limits<Real>::infinity(), 0);
37 current[i] = older[i + 1] + Real{1} / difference;
40 const std::complex<Real> estimate = current.back();
41 if (std::isfinite(estimate.real()) && std::isfinite(estimate.imag())) {
42 const Real difference = std::abs(estimate - lastEstimate);
43 if (difference < bestDifference) {
45 bestDifference = difference;
47 lastEstimate = estimate;
50 older = std::move(previous);
51 previous = std::move(current);
53 return {best, bestDifference};
56template <std::
floating_po
int Real>
71template <std::
floating_po
int Real,
class F>
74 static constexpr long double xgk[11] = {0.995657163025808080735527280689003L,
75 0.973906528517171720077964012084452L,
76 0.930157491355708226001207180059508L,
77 0.865063366688984510732096688423493L,
78 0.780817726586416897063717578345042L,
79 0.679409568299024406234327365114874L,
80 0.562757134668604683339000099272694L,
81 0.433395394129247190799265943165784L,
82 0.294392862701460198131126603103866L,
83 0.148874338981631210884826001129720L,
85 static constexpr long double wgk[11] = {0.011694638867371874278064396062192L, 0.032558162307964727478818972459390L,
86 0.054755896574351996031381300244580L, 0.075039674810919952767043140916190L,
87 0.093125454583697605535065465083366L, 0.109387158802297641899210590325805L,
88 0.123491976262065851077208980292818L, 0.134709217311473325928054001771707L,
89 0.142775938577060080797094273138717L, 0.147739104901338491374841515972068L,
90 0.149445554002916905664936468389821L};
91 static constexpr long double wg[5] = {0.066671344308688137593568809893332L, 0.149451349150580593145776339657697L,
92 0.219086362515982043995534934228163L, 0.269266719309996355091226921569469L,
93 0.295524224714752870173892994651338L};
94 const Real center = (a + b) / 2, half = (b - a) / 2;
95 const Real fc = f(center);
96 Real kronrod =
static_cast<Real
>(wgk[10]) * fc, gauss = 0, absSum =
static_cast<Real
>(wgk[10]) * std::fabs(fc);
97 for (
int j = 0; j < 10; ++j) {
98 const Real dx = half *
static_cast<Real
>(xgk[j]);
99 const Real f1 = f(center - dx), f2 = f(center + dx);
100 kronrod +=
static_cast<Real
>(wgk[j]) * (f1 + f2);
101 absSum +=
static_cast<Real
>(wgk[j]) * (std::fabs(f1) + std::fabs(f2));
103 gauss +=
static_cast<Real
>(wg[j / 2]) * (f1 + f2);
105 absEstimate += std::fabs(half) * absSum;
106 return {a, b, kronrod * half, std::fabs((kronrod - gauss) * half)};
110template <std::
floating_po
int Real,
class F>
116 Real absEstimate = 0;
117 std::vector<Segment<Real>> heap{
gaussKronrod21(f, a, b, absEstimate)};
118 Real estimate = heap.front().estimate, error = heap.front().error;
121 int stalledBisections = 0, growingBisections = 0;
122 for (
int i = 0; i < maxSubdivisions && stalledBisections < 6 && growingBisections < 20; ++i) {
123 Real limit = std::max(tolerance * std::fabs(estimate), 50 * std::numeric_limits<Real>::epsilon() * absEstimate);
124 if (!(error > limit) || !std::isfinite(estimate))
126 std::pop_heap(heap.begin(), heap.end());
129 Real middle = (worst.
a + worst.
b) / 2;
130 if (!(middle > worst.
a && middle < worst.
b)) {
131 heap.push_back(worst);
132 std::push_heap(heap.begin(), heap.end());
140 if (std::fabs(worst.
estimate - childEstimate) <= Real(1e-5) * std::fabs(childEstimate) &&
141 childError >= Real(0.99) * worst.
error)
143 if (i >= 10 && childError > worst.
error)
148 heap.push_back(left);
149 std::push_heap(heap.begin(), heap.end());
150 heap.push_back(right);
151 std::push_heap(heap.begin(), heap.end());
156 sum += segment.estimate;
160template <std::
floating_po
int Real,
class F>
163 if constexpr (std::invocable<F, Real, Real>)
164 return static_cast<Real
>(f(x, endpointDistance));
166 return static_cast<Real
>(f(x));
169template <std::
floating_po
int Real,
class F>
172 const Real halfWidth = (b - a) / 2;
173 const Real center = a + halfWidth;
174 const Real halfPi = std::numbers::pi_v<Real> / 2;
175 const Real centerWeight = halfWidth * halfPi;
176 const Real centerValue = evaluateTanhSinh<Real>(f, center, b - center);
177 Real sum = centerWeight * centerValue;
178 Real absoluteSum = centerWeight * std::fabs(centerValue);
180 for (
int k = 1; k < 32768; ++k) {
181 const Real t = step *
static_cast<Real
>(k);
182 const Real coshT = std::cosh(t);
183 const Real transformed = halfPi * std::sinh(t);
184 const Real q = std::exp(-2 * transformed);
187 const Real onePlusQ = 1 + q;
188 const Real endpointDistance = (b - a) * q / onePlusQ;
189 if (endpointDistance < std::numeric_limits<Real>::min())
191 const Real weight = halfWidth * halfPi * coshT * 4 * q / (onePlusQ * onePlusQ);
195 const Real left = a + endpointDistance;
196 const Real right = b - endpointDistance;
197 Real leftValue = 0, rightValue = 0;
198 if constexpr (std::invocable<F, Real, Real>) {
199 leftValue = evaluateTanhSinh<Real>(f, left, -endpointDistance);
200 rightValue = evaluateTanhSinh<Real>(f, right, endpointDistance);
203 leftValue = evaluateTanhSinh<Real>(f, left, -endpointDistance);
205 rightValue = evaluateTanhSinh<Real>(f, right, endpointDistance);
207 sum += weight * (leftValue + rightValue);
208 absoluteSum += weight * (std::fabs(leftValue) + std::fabs(rightValue));
210 return {step * sum, step * absoluteSum};
225template <std::
floating_po
int Real =
double,
class F>
226Real
integrate(
const F &f, std::type_identity_t<Real> a, std::type_identity_t<Real> b,
227 std::type_identity_t<Real> tolerance = 1e-11,
int maxSubdivisions = 512)
230 return -integrate<Real>(f, b, a, tolerance, maxSubdivisions);
233 const bool lowerInfinite = std::isinf(a), upperInfinite = std::isinf(b);
234 if (!lowerInfinite && !upperInfinite)
236 auto distance = [](Real t) {
return (1 - t) / t; };
237 if (lowerInfinite && upperInfinite) {
239 [&f, &distance](Real t) {
240 Real x = distance(t);
241 return (f(x) + f(-x)) / (t * t);
243 0, 1, tolerance, maxSubdivisions);
247 tolerance, maxSubdivisions);
250 tolerance, maxSubdivisions);
265template <std::
floating_po
int Real =
double,
class F>
267 std::type_identity_t<Real> tolerance = 1e-11,
int maxRefinements = 12)
269 if (!std::isfinite(a) || !std::isfinite(b))
270 throw std::invalid_argument(
"tanh-sinh quadrature requires finite limits");
272 return -integrateTanhSinh<Real>(f, b, a, tolerance, maxRefinements);
275 if (!(tolerance > 0) || maxRefinements < 1)
276 throw std::invalid_argument(
"tanh-sinh quadrature requires a positive tolerance and refinement count");
279 for (
int level = 0; level <= maxRefinements; ++level) {
280 const Real step = std::ldexp(Real{1}, -level);
282 const Real roundoff = 50 * std::numeric_limits<Real>::epsilon() * absoluteEstimate;
283 const Real target = std::max(tolerance * absoluteEstimate, roundoff);
284 if (level >= 2 && std::fabs(estimate - previous) <= target)
294template <std::
floating_po
int Real,
class F,
class TailMass>
295std::complex<Real>
integrateHalfPeriods(
const F &litude, Real frequency, Real lower, Real tolerance,
int maxCycles,
296 const TailMass &tailMass)
298 if (!(frequency > 0) || !std::isfinite(frequency) || !std::isfinite(lower) || !(tolerance > 0) || maxCycles < 4)
299 throw std::invalid_argument(
"oscillatory quadrature requires finite limits, positive frequency and tolerance");
301 const Real halfPeriod = std::numbers::pi_v<Real> / frequency;
302 std::vector<std::complex<Real>> partialSums;
303 partialSums.reserve(maxCycles);
304 std::complex<Real> sum = 0;
305 int negligibleCycles = 0;
306 for (
int cycle = 0; cycle < maxCycles; ++cycle) {
307 const Real a = lower +
static_cast<Real
>(cycle) * halfPeriod;
308 const Real b = a + halfPeriod;
309 const Real cosine = integrate<Real>(
310 [&litude, frequency](Real x) {
return static_cast<Real
>(amplitude(x)) * std::cos(frequency * x); }, a, b,
311 tolerance * 0.1, 128);
312 const Real sine = integrate<Real>(
313 [&litude, frequency](Real x) {
return static_cast<Real
>(amplitude(x)) * std::sin(frequency * x); }, a, b,
314 tolerance * 0.1, 128);
315 const std::complex<Real> contribution(cosine, sine);
317 partialSums.push_back(sum);
321 const Real remaining =
static_cast<Real
>(tailMass(b));
322 if (std::isnan(remaining)) {
323 negligibleCycles = (std::abs(contribution) <= tolerance) ? negligibleCycles + 1 : 0;
324 if (negligibleCycles >= 3)
326 }
else if (remaining <= tolerance) {
329 if (!(remaining > Real{0.5}) && partialSums.size() >= 12 && partialSums.size() % 4 == 0) {
331 if (error <= tolerance * std::max(Real{1}, std::abs(estimate)))
351template <std::
floating_po
int Real =
double,
class F>
353 std::type_identity_t<Real> lower = 0,
354 std::type_identity_t<Real> tolerance = 1e-10,
int maxCycles = 512)
357 [](Real) {
return std::numeric_limits<Real>::quiet_NaN(); });
371template <std::
floating_po
int Real =
double,
class F,
class TailMass>
372 requires std::invocable<const TailMass &, Real>
374 std::type_identity_t<Real> lower,
const TailMass &tailMass,
375 std::type_identity_t<Real> tolerance = 1e-10,
int maxCycles = 512)
Real standardNormal(G &g)
Ziggurat algorithm of Marsaglia and Tsang with 256 layers and an explicit sign bit.
Definition variates.hpp:45
std::complex< Real > integrateHalfPeriods(const F &litude, Real frequency, Real lower, Real tolerance, int maxCycles, const TailMass &tailMass)
Definition quadrature.hpp:295
Real evaluateTanhSinh(const F &f, Real x, Real endpointDistance)
Definition quadrature.hpp:161
std::pair< Real, Real > tanhSinhLevel(const F &f, Real a, Real b, Real step)
Definition quadrature.hpp:170
Segment< Real > gaussKronrod21(const F &f, Real a, Real b, Real &absEstimate)
21-point Gauss-Kronrod rule with its embedded 10-point Gauss rule (QUADPACK qk21)
Definition quadrature.hpp:72
Real integrateFinite(const F &f, Real a, Real b, Real tolerance, int maxSubdivisions)
Global adaptive scheme (QUADPACK QAG) on a finite interval.
Definition quadrature.hpp:111
std::pair< std::complex< Real >, Real > accelerateOscillatorySums(const std::vector< std::complex< Real > > &partialSums)
Definition quadrature.hpp:21
Beta-related functions.
Definition math/beta.hpp:14
Real integrateTanhSinh(const F &f, std::type_identity_t< Real > a, std::type_identity_t< Real > b, std::type_identity_t< Real > tolerance=1e-11, int maxRefinements=12)
Double-exponential tanh-sinh quadrature on a finite interval.
Definition quadrature.hpp:266
std::complex< Real > integrateOscillatory(const F &litude, std::type_identity_t< Real > frequency, std::type_identity_t< Real > lower=0, std::type_identity_t< Real > tolerance=1e-10, int maxCycles=512)
QAWF-style Fourier integral on a semi-infinite interval.
Definition quadrature.hpp:352
Real integrate(const F &f, std::type_identity_t< Real > a, std::type_identity_t< Real > b, std::type_identity_t< Real > tolerance=1e-11, int maxSubdivisions=512)
Global adaptive Gauss-Kronrod quadrature (QUADPACK QAG).
Definition quadrature.hpp:226
Definition quadrature.hpp:58
Real a
Definition quadrature.hpp:59
bool operator<(const Segment &other) const
Definition quadrature.hpp:60
Real error
Definition quadrature.hpp:59
Real estimate
Definition quadrature.hpp:59
Real b
Definition quadrature.hpp:59