use super::Vector;
use crate::StrError;
use crate::deriv1_approx_eq;
pub fn vec_deriv1_approx_eq<F, A>(dv_ds: &Vector, at_s: f64, args: &mut A, tol: f64, mut f: F)
where
F: FnMut(&mut Vector, f64, &mut A) -> Result<(), StrError>,
{
let n = dv_ds.dim();
let mut v = Vector::new(n);
for i in 0..n {
deriv1_approx_eq(dv_ds[i], at_s, args, tol, |s, a| {
f(&mut v, s, a)?;
Ok(v[i])
});
}
}
#[cfg(test)]
mod tests {
use super::vec_deriv1_approx_eq;
use crate::StrError;
use crate::Vector;
struct Arguments {}
fn placeholder(_: &mut Vector, _: f64, _: &mut Arguments) -> Result<(), StrError> {
Err("NOT HERE")
}
#[test]
fn placeholder_returns_error() {
let args = &mut Arguments {};
let mut v = Vector::new(1);
assert_eq!(placeholder(&mut v, 0.0, args).err(), Some("NOT HERE"));
}
#[test]
#[should_panic(expected = "the function returned an error: NOT HERE")]
fn panics_on_function_error() {
let args = &mut Arguments {};
let dv_ds = Vector::new(1);
vec_deriv1_approx_eq(&dv_ds, 1.5, args, 1e-1, &placeholder);
}
#[test]
#[should_panic(expected = "the derivative is NaN")]
fn panics_on_nan_1() {
let args = &mut Arguments {};
let dv_ds = Vector::from(&[f64::NAN; 1]);
vec_deriv1_approx_eq(&dv_ds, 1.5, args, 1e-1, &placeholder);
}
#[test]
#[should_panic(expected = "the derivative is Inf")]
fn panics_on_inf_1() {
let args = &mut Arguments {};
let dv_ds = Vector::from(&[f64::INFINITY; 1]);
vec_deriv1_approx_eq(&dv_ds, 1.5, args, 1e-1, &placeholder);
}
#[test]
#[should_panic(expected = "the numerical derivative is NaN")]
fn panics_on_nan_2() {
let f = |v: &mut Vector, _: f64, _: &mut Arguments| {
v[0] = f64::NAN;
Ok(())
};
let args = &mut Arguments {};
let dv_ds = Vector::new(1);
vec_deriv1_approx_eq(&dv_ds, 1.5, args, 1e-1, f);
}
#[test]
#[should_panic(expected = "the numerical derivative is NaN")]
fn panics_on_inf_2() {
let f = |v: &mut Vector, _: f64, _: &mut Arguments| {
v[0] = f64::INFINITY; Ok(())
};
let args = &mut Arguments {};
let dv_ds = Vector::new(1);
vec_deriv1_approx_eq(&dv_ds, 1.5, args, 1e-1, f);
}
#[test]
#[should_panic(expected = "derivative is not approximately equal to numerical value. diff = ")]
fn panics_on_different_deriv_1() {
let f = |v: &mut Vector, s: f64, _: &mut Arguments| {
v[0] = s * s / 2.0;
v[1] = s * s / 2.0;
Ok(())
};
let args = &mut Arguments {};
let at_s = 1.5;
let dv_ds = Vector::from(&[1.51, 1.501]);
vec_deriv1_approx_eq(&dv_ds, at_s, args, 1e-2, f);
}
#[test]
#[should_panic(expected = "derivative is not approximately equal to numerical value. diff = ")]
fn panics_on_different_deriv_2() {
let f = |v: &mut Vector, s: f64, _: &mut Arguments| {
v[0] = s * s / 2.0;
v[1] = s * s / 2.0;
Ok(())
};
let args = &mut Arguments {};
let at_s = 1.5;
let dv_ds = Vector::from(&[1.501, 1.51]);
vec_deriv1_approx_eq(&dv_ds, at_s, args, 1e-2, f);
}
#[test]
fn accepts_approx_equal_deriv() {
let f = |v: &mut Vector, s: f64, _: &mut Arguments| {
v[0] = s * s / 2.0;
v[1] = s * s / 2.0;
Ok(())
};
let args = &mut Arguments {};
let at_s = 1.5;
let dv_ds = Vector::from(&[1.501, 1.501]);
vec_deriv1_approx_eq(&dv_ds, at_s, args, 1e-2, f);
}
}