use std::f64::consts::{E, FRAC_PI_2, PI};
use peroxide::fuga::*;
const TOL: f64 = 1e-10;
fn assert_close(actual: f64, expected: f64) {
assert!(
(actual - expected).abs() < TOL,
"actual = {:.17e}, expected = {:.17e}, diff = {:.3e}",
actual, expected, (actual - expected).abs()
);
}
fn gk_methods(tol: f64) -> [Integral; 6] {
[
G7K15R(tol, 20),
G10K21R(tol, 20),
G15K31R(tol, 20),
G20K41R(tol, 20),
G25K51R(tol, 20),
G30K61R(tol, 20),
]
}
#[test]
fn test_polynomial() {
for m in gk_methods(1e-8) {
let r: f64 = integrate(|x: f64| x.powi(3), (0.0, 1.0), m);
assert_close(r, 0.25);
}
}
#[test]
fn test_trig() {
for m in gk_methods(1e-8) {
let r: f64 = integrate(|x: f64| x.cos(), (0.0, 1.0), m);
assert_close(r, 1f64.sin());
}
for m in gk_methods(1e-8) {
let r: f64 = integrate(|x: f64| x.sin(), (0.0, PI), m);
assert_close(r, 2.0);
}
}
#[test]
fn test_exponential() {
for m in gk_methods(1e-8) {
let r: f64 = integrate(|x: f64| x.exp(), (0.0, 2.0), m);
assert_close(r, E * E - 1.0);
}
}
#[test]
fn test_gaussian() {
let expected = 0.746_824_132_812_427_f64;
for m in gk_methods(1e-10) {
let r: f64 = integrate(|x: f64| (-x * x).exp(), (0.0, 1.0), m);
assert_close(r, expected);
}
}
#[test]
fn test_rational_symmetric() {
for m in gk_methods(1e-10) {
let r: f64 = integrate(|x: f64| 1.0 / (1.0 + x * x), (-1.0, 1.0), m);
assert_close(r, FRAC_PI_2);
}
}
#[test]
fn test_oscillatory() {
let abs_methods = [
G7K15(1e-10, 20),
G10K21(1e-10, 20),
G15K31(1e-10, 20),
G20K41(1e-10, 20),
G25K51(1e-10, 20),
G30K61(1e-10, 20),
];
for m in abs_methods {
let r: f64 = integrate(|x: f64| (5.0 * x).sin(), (0.0, 2.0 * PI), m);
assert_close(r, 0.0);
}
}
#[test]
fn test_endpoint_independence() {
let m = || G10K21R(1e-10, 20);
let f = |x: f64| (-x).exp() + x.sin();
let full: f64 = integrate(f, (0.0, 3.0), m());
let left: f64 = integrate(f, (0.0, 1.7), m());
let right: f64 = integrate(f, (1.7, 3.0), m());
assert_close(full, left + right);
}