use nabled::ml::jacobian::{self as jacobian, JacobianConfig, JacobianError};
use ndarray::Array1;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = JacobianConfig::default();

    let f_vec = |x: &Array1<f64>| -> Result<Array1<f64>, JacobianError> {
        Ok(Array1::from_vec(vec![x[0] * x[0], x[1] * x[1]]))
    };
    let x = Array1::from_vec(vec![2.0, 3.0]);
    let jacobian = jacobian::numerical_jacobian(&f_vec, &x, &config)?;
    println!("jacobian:\n{jacobian:?}");

    let f_scalar = |x: &Array1<f64>| -> Result<f64, JacobianError> {
        Ok(x.iter().map(|value| value * value).sum())
    };
    let gradient = jacobian::numerical_gradient(&f_scalar, &x, &config)?;
    println!("gradient: {gradient:?}");

    let hessian = jacobian::numerical_hessian(&f_scalar, &x, &config)?;
    println!("hessian:\n{hessian:?}");

    Ok(())
}
