61 lines
2.0 KiB
Go
61 lines
2.0 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|||
|
|
// SPDX-License-Identifier: MIT
|
||
|
|
|
||
|
|
package integrate
|
||
|
|
|
||
|
|
import (
|
||
|
|
"math"
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Benchmarks for the adaptive cubature's low-dimensional workloads,
|
||
|
|
// the ones whose bisection loop turns often enough against a cheap
|
||
|
|
// integrand that the worst-box selection is a visible share of the
|
||
|
|
// cost. The three-dimensional workload lives in bench_test.go.
|
||
|
|
|
||
|
|
// BenchmarkIntegrateND1D runs the oscillatory task of
|
||
|
|
// TestCubatureMatches1D: a degenerate dimension whose boxes bisect
|
||
|
|
// for sixteen evaluations apiece, so the selection runs at its
|
||
|
|
// cheapest per box.
|
||
|
|
func BenchmarkIntegrateND1D(b *testing.B) {
|
||
|
|
f := func(x []float64) float64 { return math.Exp(-x[0]) * math.Cos(3*x[0]) }
|
||
|
|
lo := []float64{0}
|
||
|
|
hi := []float64{5}
|
||
|
|
b.ReportAllocs()
|
||
|
|
for b.Loop() {
|
||
|
|
if _, err := IntegrateND(f, lo, hi, CubatureOptions{Tolerance: 1e-12}); err != nil {
|
||
|
|
b.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// BenchmarkIntegrateND2D runs the Gaussian of TestCubatureGaussian at
|
||
|
|
// its test tolerance: the subdivision reaches into the thousands of
|
||
|
|
// boxes, the regime where the worst-box choice dominates over the
|
||
|
|
// arithmetic inside each box.
|
||
|
|
func BenchmarkIntegrateND2D(b *testing.B) {
|
||
|
|
f := func(x []float64) float64 { return math.Exp(-x[0]*x[0] - x[1]*x[1]) }
|
||
|
|
lo := []float64{-3, -3}
|
||
|
|
hi := []float64{3, 3}
|
||
|
|
b.ReportAllocs()
|
||
|
|
for b.Loop() {
|
||
|
|
if _, err := IntegrateND(f, lo, hi, CubatureOptions{Tolerance: 1e-11}); err != nil {
|
||
|
|
b.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// BenchmarkIntegrateFilon runs the oscillatory integral over enough
|
||
|
|
// carrier wavelengths that the automatic panel count keeps the weights
|
||
|
|
// busy: the amplitude stays smooth, so the per-panel cost is the node
|
||
|
|
// sweep and the phase rotation.
|
||
|
|
func BenchmarkIntegrateFilon(b *testing.B) {
|
||
|
|
f := func(x float64) (float64, error) { return math.Exp(-0.1 * x), nil }
|
||
|
|
b.ReportAllocs()
|
||
|
|
for b.Loop() {
|
||
|
|
if _, _, err := IntegrateFilon(f, 0, 100, 40*math.Pi, FilonOptions{}); err != nil {
|
||
|
|
b.Fatal(err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|