use crate::error::DiffError;
use crate::linear_algebra::Matrix;
use crate::numerical_derivative::autodiff::AutoDiffMulti;
use crate::numerical_derivative::derivator::DerivatorMultiVariable;
use crate::scalar::{Numeric, ScalarFnN};
pub struct Hessian<D: DerivatorMultiVariable = AutoDiffMulti> {
derivator: D,
}
impl<D: DerivatorMultiVariable + Default> Default for Hessian<D> {
fn default() -> Self {
Hessian {
derivator: D::default(),
}
}
}
impl Hessian<AutoDiffMulti> {
#[inline]
pub const fn new() -> Self {
Self::from_derivator(AutoDiffMulti::new())
}
}
impl<D: DerivatorMultiVariable> Hessian<D> {
pub const fn from_derivator(derivator: D) -> Self {
Hessian { derivator }
}
pub fn evaluate<F: ScalarFnN<NUM_VARS>, const NUM_VARS: usize>(
&self,
function: &F,
vector_of_points: &[D::Scalar; NUM_VARS],
) -> Result<Matrix<NUM_VARS, NUM_VARS, D::Scalar>, DiffError> {
let mut result: Matrix<NUM_VARS, NUM_VARS, D::Scalar> =
Matrix::from_fn(|_, _| <D::Scalar as Numeric>::NAN);
for row_index in 0..NUM_VARS {
for col_index in 0..NUM_VARS {
if result[(row_index, col_index)].is_nan() {
let value = self.derivator.second_partial_derivative(
function,
&[row_index, col_index],
vector_of_points,
)?;
result[(row_index, col_index)] = value;
result[(col_index, row_index)] = value;
}
}
}
Ok(result)
}
}