use crate::linear_algebra::Matrix;
use crate::numerical_derivative::autodiff::AutoDiffMulti;
use crate::numerical_derivative::derivator::DerivatorMultiVariable;
use crate::scalar::VectorFn;
use crate::scalar::function::Component;
use crate::utils::error_codes::CalcError;
#[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], CalcError> {
if NUM_FUNCS == 0 {
return Err(CalcError::EmptyFunctionSet);
}
let mut result: Matrix<NUM_FUNCS, NUM_VARS, D::Scalar> = Matrix::zeros();
for m in 0..NUM_FUNCS {
let component = Component::new(function, m);
for n in 0..NUM_VARS {
result[(m, n)] =
self.derivator
.get_single_partial(&component, n, vector_of_points)?;
}
}
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>>, CalcError> {
if NUM_FUNCS == 0 {
return Err(CalcError::EmptyFunctionSet);
}
let mut result: Vec<Vec<D::Scalar>> = Vec::new();
for m in 0..NUM_FUNCS {
let component = Component::new(function, m);
let mut cur_row: Vec<D::Scalar> = Vec::new();
for col_index in 0..NUM_VARS {
cur_row.push(self.derivator.get_single_partial(
&component,
col_index,
vector_of_points,
)?);
}
result.push(cur_row);
}
Ok(result)
}
}