pub fn composite_trapezoid(a: f64, b: f64, n: i64, f: fn(f64) -> f64) -> f64{
let h : f64 = (b-a)/(n as f64).abs();
let mut sum : f64 = 0.0;
for i in 1..n {
sum += f(a+(i as f64)*h);
}
return h*(sum + f(a)/(2 as f64) + f(b)/(2 as f64));
}
pub fn simpson_quadrature(a: f64, b: f64, n:i64, f: fn(f64) -> f64) -> f64{
let h : f64 = (b-a)/(n as f64).abs();
let mut sum :f64 = 0.0;
for i in 1..n{
if i % 2 == 1 {
sum += 4.0 * f(a+(i as f64)*h);
} else {
sum += 2.0 * f(a+(i as f64)*h);
}
}
return h*(sum + f(a) + f(b))/(3.0);
}
pub fn adaptive_simpson(a: f64, b: f64, f: fn(f64) -> f64, eps: f64) -> f64 {
let fa : f64 = f(a);
let fb : f64 = f(b);
let (m, fm, whole) = simpson_single_eval(f, a, b, fa, fb);
return adaptive_simpson_quadrature(f, a, b, fa, fb, eps, m, fm, whole);
}
fn adaptive_simpson_quadrature(f: fn(f64) -> f64, a: f64, b: f64, fa: f64, fb: f64, eps: f64, m: f64, fm: f64, whole: f64) -> f64 {
let (lm, flm, left) = simpson_single_eval(f, a, m, fa, fm);
let (rm, frm, right) = simpson_single_eval(f, m, b, fm, fb);
let delta : f64 = left+right-whole;
if delta.abs() <= 15.0*eps {
return left+right+delta/15.0;
}
return adaptive_simpson_quadrature(f, a, m, fa, fm, eps/2.0, lm, flm, left) + adaptive_simpson_quadrature(f, m, b, fm, fb, eps/2.0, rm, frm, right);
}
fn simpson_single_eval(f: fn(f64) -> f64, a: f64, b: f64, fa: f64, fb: f64) -> (f64, f64, f64) {
let m : f64 = (a+b)/2.0;
let fm : f64 = f(m);
return (m, fm, (b-a).abs() / 6.0 * (fa + 4.0*fm + fb));
}
pub fn three_eighths_simpson(a: f64, b: f64, n: i64, f: fn(f64) -> f64) -> f64{
let h : f64 = (b-a)/(n as f64).abs();
let mut sum : f64 = 0.0;
for i in 1..n{
if i % 3 == 0 {
sum += 2.0*f(a+(i as f64)*h);
} else{
sum += 3.0*f(a+(i as f64)*h);
}
}
return 3.0*h*sum/8.0;
}
#[cfg(test)]
mod tests{
use super::*;
use assert_approx_eq::assert_approx_eq;
fn square(x : f64) -> f64 {
return x*x;
}
#[test]
fn trapezoid_quad() {
let a : f64 = 0.66679;
assert_approx_eq!(a, composite_trapezoid(-1.0, 1.0, 100, square), 2 as f64);
}
#[test]
fn simpson_test() {
let a : f64 = 0.66679;
assert_approx_eq!(a, simpson_quadrature(-1.0, 1.0, 100, square), 2 as f64);
}
#[test]
fn three_eighth_simpson_test() {
let a: f64 = 0.66679;
assert_approx_eq!(a, three_eighths_simpson(-1.0, 1.0, 100, square), 2 as f64);
}
}