use crate::{
linalg::Matrix,
traits::{DefaultState, Real, State},
};
pub trait DAE<T = f64, V = DefaultState<T>>
where
T: Real,
V: State<T>,
{
fn diff(&self, t: T, y: &V, f: &mut V);
fn mass(&self, m: &mut Matrix<T>);
fn jacobian(&self, t: T, y: &V, j: &mut Matrix<T>) {
let dim = y.len();
let mut y_perturbed = y.clone();
let mut f_perturbed = y.zeros_like();
let mut f_origin = y.zeros_like();
self.diff(t, y, &mut f_origin);
let eps = T::default_epsilon().sqrt();
for j_col in 0..dim {
let y_original_j = y.get_component(j_col);
let perturbation = eps * y_original_j.abs().max(T::one());
y_perturbed.copy_from_state(y);
y_perturbed.set_component(j_col, y_original_j + perturbation);
self.diff(t, &y_perturbed, &mut f_perturbed);
for i_row in 0..dim {
j[(i_row, j_col)] = (f_perturbed.get_component(i_row)
- f_origin.get_component(i_row))
/ perturbation;
}
}
}
}