use crate::algebra::abstr::Real;
use crate::analysis::integral::newton_cotes::ClosedFixedIntervalIterator;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct NewtonCotes<T>
where
T: Real,
{
weight: Vec<T>,
}
impl<T> NewtonCotes<T>
where
T: Real,
{
pub fn new(n: u8) -> NewtonCotes<T> {
if !(1..=5).contains(&n) {
panic!("'n' is out of bounds");
}
let weight = match n {
1 => vec![T::from_f32(0.5), T::from_f32(0.5)],
2 => vec![
T::from_f64(1.0 / 6.0),
T::from_f64(2.0 / 3.0),
T::from_f64(1.0 / 6.0),
],
3 => vec![
T::from_f64(1.0 / 8.0),
T::from_f64(3.0 / 8.0),
T::from_f64(3.0 / 8.0),
T::from_f64(1.0 / 8.0),
],
4 => vec![
T::from_f64(7.0 / 90.0),
T::from_f64(16.0 / 45.0),
T::from_f64(2.0 / 15.0),
T::from_f64(16.0 / 45.0),
T::from_f64(7.0 / 90.0),
],
5 => vec![
T::from_f64(19.0 / 288.0),
T::from_f64(25.0 / 96.0),
T::from_f64(25.0 / 144.0),
T::from_f64(25.0 / 144.0),
T::from_f64(25.0 / 96.0),
T::from_f64(19.0 / 288.0),
],
_ => panic!(""),
};
NewtonCotes { weight }
}
pub fn integrate<F>(&self, f: F, a: T, b: T, num_subintervals: u32) -> T
where
F: Fn(T) -> T,
{
let mut sub_interval: ClosedFixedIntervalIterator<T> =
ClosedFixedIntervalIterator::new(a, b, num_subintervals);
let mut lower_bound: T = sub_interval.next().unwrap();
let num_intervals = self.weight.len() as u32 - 1;
let mut sum = T::zero();
sub_interval.for_each(|x_i: T| {
let interval: ClosedFixedIntervalIterator<T> =
ClosedFixedIntervalIterator::new(lower_bound, x_i, num_intervals);
let h = x_i - lower_bound;
let sum_i = interval
.zip(self.weight.iter())
.map(|(x, w)| *w * f(x))
.fold(T::zero(), |a, b| a + b)
* h;
sum += sum_i;
lower_bound = x_i;
});
sum
}
}