numeric-algs 0.5.1

Crate implementing some numerical algorithms
Documentation
use super::{Integrator, StepSize};
use crate::traits::State;

// Source: https://core.ac.uk/download/pdf/42883081.pdf section 6.6

pub struct RK8Integrator {
    default_step: f64,
}

impl RK8Integrator {
    pub fn new(step_size: f64) -> Self {
        RK8Integrator {
            default_step: step_size,
        }
    }

    pub fn set_default_step(&mut self, step: f64) {
        self.default_step = step;
    }
}

impl<S: State> Integrator<S> for RK8Integrator {
    fn propagate_in_place<D>(&mut self, start: &mut S, diff_eq: D, step_size: StepSize)
    where
        D: Fn(&S) -> S::Derivative,
    {
        let h = match step_size {
            StepSize::UseDefault => self.default_step,
            StepSize::Step(x) => x,
        };

        let mut f = vec![diff_eq(start)];

        let a: [(f64, f64); 9] = [
            (4.0, 27.0),
            (2.0, 9.0),
            (1.0, 3.0),
            (1.0, 2.0),
            (2.0, 3.0),
            (1.0, 6.0),
            (1.0, 1.0),
            (5.0, 6.0),
            (1.0, 1.0),
        ];

        let b: [(f64, Vec<f64>); 9] = [
            (1.0, vec![1.0]),
            (4.0, vec![1.0, 3.0]),
            (4.0, vec![1.0, 0.0, 3.0]),
            (4.0, vec![1.0, 0.0, 0.0, 3.0]),
            (36.0, vec![13.0, 0.0, -27.0, 42.0, 8.0]),
            (720.0, vec![389.0, 0.0, -54.0, 966.0, -824.0, 243.0]),
            (20.0, vec![-231.0, 0.0, 81.0, -1164.0, 656.0, -122.0, 800.0]),
            (
                240.0,
                vec![-127.0, 0.0, 18.0, -678.0, 456.0, -9.0, 576.0, 4.0],
            ),
            (
                820.0,
                vec![
                    1481.0, 0.0, -81.0, 7104.0, -3376.0, 72.0, -5040.0, -60.0, 720.0,
                ],
            ),
        ];

        for i in 0..9 {
            assert_eq!(f.len(), b[i].1.len());
            let k = f
                .iter()
                .zip(b[i].1.iter())
                .map(|(f, b)| f.clone() * *b)
                .reduce(|v1, v2| v1 + v2)
                .unwrap()
                / b[i].0;
            let a = a[i];
            let new_f = diff_eq(&start.shift(&k, h * a.0 / a.1));
            f.push(new_f);
        }

        let c: [f64; 10] = [41.0, 0.0, 0.0, 27.0, 272.0, 27.0, 216.0, 0.0, 216.0, 41.0];

        assert_eq!(f.len(), 10);

        let shift = f
            .iter()
            .zip(c.iter())
            .map(|(f, c)| f.clone() * *c)
            .reduce(|v1, v2| v1 + v2)
            .unwrap()
            / 840.0;

        start.shift_in_place(&shift, h);
    }
}