lmm 0.0.1

WIP: A language agnostic framework to reality.
Documentation
use crate::error::Result;
use crate::tensor::Tensor;
use crate::traits::Simulatable;

pub struct Simulator {
    pub step_size: f64,
}

impl Simulator {
    pub fn euler_step<M: Simulatable>(&self, model: &M, current: &Tensor) -> Result<Tensor> {
        let deriv = model.evaluate_derivatives(current)?;
        let delta = deriv.scale(self.step_size);
        current + &delta
    }

    pub fn rk4_step<M: Simulatable>(&self, model: &M, current: &Tensor) -> Result<Tensor> {
        let k1 = model.evaluate_derivatives(current)?;
        let half_step_k1 = k1.scale(self.step_size / 2.0);
        let s2 = (current + &half_step_k1)?;
        let k2 = model.evaluate_derivatives(&s2)?;
        let half_step_k2 = k2.scale(self.step_size / 2.0);
        let s3 = (current + &half_step_k2)?;
        let k3 = model.evaluate_derivatives(&s3)?;
        let full_step_k3 = k3.scale(self.step_size);
        let s4 = (current + &full_step_k3)?;
        let k4 = model.evaluate_derivatives(&s4)?;

        let sum1 = (&k1 + &k2.scale(2.0))?;
        let sum2 = (&k3.scale(2.0) + &k4)?;
        let total = (&sum1 + &sum2)?;
        let avg_deriv = total.scale(1.0 / 6.0);
        let delta = avg_deriv.scale(self.step_size);
        current + &delta
    }
}