use ndarray::*;
use ndarray_linalg::*;
use num_traits::Float;
use super::traits::*;
pub struct Jacobian<'a, A, S, D, TEO>
where A: Scalar,
S: Data<Elem = A>,
D: Dimension,
TEO: 'a
{
f: &'a TEO,
x: ArrayBase<S, D>,
fx: ArrayBase<S, D>,
alpha: A::Real,
}
pub fn jacobian<'a, A, S, D, TEO>(f: &'a TEO,
x: ArrayBase<S, D>,
alpha: A::Real)
-> Jacobian<'a, A, S, D, TEO>
where A: Scalar,
S: DataClone<Elem = A> + DataMut,
D: Dimension,
TEO: TimeEvolutionBase<S, D>
{
let mut fx = x.clone();
f.iterate(&mut fx);
Jacobian {
f: f,
x: x,
fx: fx,
alpha: alpha,
}
}
impl<'j, A, S, Sr, D, TEO> OperatorMut<Sr, D> for Jacobian<'j, A, S, D, TEO>
where A: Scalar,
S: Data<Elem = A>,
Sr: DataMut<Elem = A>,
D: Dimension,
TEO: TimeEvolutionBase<Sr, D>
{
fn op_mut<'a>(&self, dx: &'a mut ArrayBase<Sr, D>) -> &'a mut ArrayBase<Sr, D> {
let dx_nrm = dx.norm_l2().max(self.alpha);
let n = self.alpha / dx_nrm;
Zip::from(&mut *dx)
.and(&self.x)
.apply(|dx, &x| { *dx = x + dx.mul_real(n); });
let x_dx = self.f.iterate(dx);
Zip::from(&mut *x_dx)
.and(&self.fx)
.apply(|x_dx, &fx| { *x_dx = (*x_dx - fx).div_real(n); });
x_dx
}
}
impl<'j, A, S, Sr, D, TEO> OperatorInto<Sr, D> for Jacobian<'j, A, S, D, TEO>
where A: Scalar,
S: Data<Elem = A>,
Sr: DataMut<Elem = A>,
D: Dimension,
TEO: TimeEvolutionBase<Sr, D>
{
fn op_into(&self, mut dx: ArrayBase<Sr, D>) -> ArrayBase<Sr, D> {
self.op_mut(&mut dx);
dx
}
}
impl<'j, A, Si, S, D, TEO> Operator<A, Si, D> for Jacobian<'j, A, S, D, TEO>
where A: Scalar,
S: Data<Elem = A>,
Si: Data<Elem = A>,
D: Dimension,
TEO: TimeEvolutionBase<OwnedRepr<A>, D>
{
fn op(&self, dx: &ArrayBase<Si, D>) -> Array<A, D> {
let dx = replicate(dx);
self.op_into(dx)
}
}