use ndarray::{ArrayBase, AsArray, Ix1, ViewRepr, s};
use rayon::prelude::*;
use crate::prelude::*;
#[inline]
pub fn composite_simpson<'a, T, A>(x: A, delta_x: Option<f64>, threads: Option<usize>) -> f64
where
A: AsArray<'a, T, Ix1>,
T: 'a + AsNumeric,
{
let x: ArrayBase<ViewRepr<&'a T>, Ix1> = x.into();
let d_x: f64 = delta_x.unwrap_or(1.0);
let n: usize = x.len() - 1;
if n.is_multiple_of(2) {
simpson(x, delta_x, threads).unwrap()
} else {
let integral: f64 = simpson(x.slice(s![..n]), delta_x, threads).unwrap();
let trap: f64 = (d_x / 2.0) * (x[n - 1] + x[n]).to_f64();
integral + trap
}
}
#[inline]
pub fn simpson<'a, T, A>(
x: A,
delta_x: Option<f64>,
threads: Option<usize>,
) -> Result<f64, ImgalError>
where
A: AsArray<'a, T, Ix1>,
T: 'a + AsNumeric,
{
let x: ArrayBase<ViewRepr<&'a T>, Ix1> = x.into();
let d_x: f64 = delta_x.unwrap_or(1.0);
let n: usize = x.len() - 1;
if !n.is_multiple_of(2) {
return Err(ImgalError::InvalidGeneric {
msg: "An odd number of subintervals is not allowed in Simpson's 1/3 rule integration.",
});
}
let seq_integration_calc = || {
let integral = (1..n).fold((x[0] + x[n]).to_f64(), |acc, i| {
let coef = if i % 2 == 1 { 4.0 } else { 2.0 };
acc + coef * x[i].to_f64()
});
(d_x / 3.0) * integral
};
let par_integration_calc = || {
let integral = (1..n)
.into_par_iter()
.map(|i| {
let coef = if i % 2 == 1 { 4.0 } else { 2.0 };
coef * x[i].to_f64()
})
.reduce(|| 0.0, |acc, v| acc + v)
+ (x[0] + x[n]).to_f64();
(d_x / 3.0) * integral
};
Ok(par!(threads,
seq_exp: seq_integration_calc(),
par_exp: par_integration_calc()))
}