use crate::error::DiffError;
use crate::linear_algebra::Matrix;
use crate::numerical_derivative::autodiff::AutoDiffMulti;
use crate::numerical_derivative::derivator::DerivatorMultiVariable;
use crate::scalar::VectorFn;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
pub struct Jacobian<D: DerivatorMultiVariable = AutoDiffMulti> {
derivator: D,
}
impl<D: DerivatorMultiVariable + Default> Default for Jacobian<D> {
fn default() -> Self {
Jacobian {
derivator: D::default(),
}
}
}
impl<D: DerivatorMultiVariable> Jacobian<D> {
pub fn from_derivator(derivator: D) -> Self {
Jacobian { derivator }
}
pub fn get<F: VectorFn<NUM_VARS, NUM_FUNCS>, const NUM_FUNCS: usize, const NUM_VARS: usize>(
&self,
function: &F,
vector_of_points: &[D::Scalar; NUM_VARS],
) -> Result<[[D::Scalar; NUM_VARS]; NUM_FUNCS], DiffError> {
if NUM_FUNCS == 0 {
return Err(DiffError::EmptyFunctionSet);
}
let mut result: Matrix<NUM_FUNCS, NUM_VARS, D::Scalar> = Matrix::zeros();
for n in 0..NUM_VARS {
let column = self
.derivator
.jacobian_column(function, n, vector_of_points)?;
for (m, &value) in column.iter().enumerate() {
result[(m, n)] = value;
}
}
Ok(result.into_array())
}
#[cfg(feature = "alloc")]
pub fn get_on_heap<
F: VectorFn<NUM_VARS, NUM_FUNCS>,
const NUM_FUNCS: usize,
const NUM_VARS: usize,
>(
&self,
function: &F,
vector_of_points: &[D::Scalar; NUM_VARS],
) -> Result<Vec<Vec<D::Scalar>>, DiffError> {
if NUM_FUNCS == 0 {
return Err(DiffError::EmptyFunctionSet);
}
let mut result: Vec<Vec<D::Scalar>> = Vec::with_capacity(NUM_FUNCS);
for _ in 0..NUM_FUNCS {
result.push(Vec::with_capacity(NUM_VARS));
}
for n in 0..NUM_VARS {
let column = self
.derivator
.jacobian_column(function, n, vector_of_points)?;
for (m, &value) in column.iter().enumerate() {
result[m].push(value);
}
}
Ok(result)
}
}