use nalgebra::{
allocator::Allocator, storage::Storage, storage::StorageMut, DefaultAllocator, IsContiguous,
Vector,
};
use num_traits::Zero;
use super::{
base::{Problem, ProblemError},
system::System,
};
pub trait Function: Problem {
fn apply<Sx>(
&self,
x: &Vector<Self::Scalar, Self::Dim, Sx>,
) -> Result<Self::Scalar, ProblemError>
where
Sx: Storage<Self::Scalar, Self::Dim> + IsContiguous;
fn apply_eval<Sx, Sfx>(
&self,
x: &Vector<Self::Scalar, Self::Dim, Sx>,
fx: &mut Vector<Self::Scalar, Self::Dim, Sfx>,
) -> Result<Self::Scalar, ProblemError>
where
Sx: Storage<Self::Scalar, Self::Dim> + IsContiguous,
Sfx: StorageMut<Self::Scalar, Self::Dim>,
{
let norm = self.apply(x)?;
fx.fill(Self::Scalar::zero());
fx[0] = norm;
Ok(norm)
}
}
impl<F: System> Function for F
where
DefaultAllocator: Allocator<F::Scalar, F::Dim>,
{
fn apply<Sx>(
&self,
x: &Vector<Self::Scalar, Self::Dim, Sx>,
) -> Result<Self::Scalar, ProblemError>
where
Sx: Storage<Self::Scalar, Self::Dim> + IsContiguous,
{
let mut fx = x.clone_owned();
self.apply_eval(x, &mut fx)
}
fn apply_eval<Sx, Sfx>(
&self,
x: &Vector<Self::Scalar, Self::Dim, Sx>,
fx: &mut Vector<Self::Scalar, Self::Dim, Sfx>,
) -> Result<Self::Scalar, ProblemError>
where
Sx: Storage<Self::Scalar, Self::Dim> + IsContiguous,
Sfx: StorageMut<Self::Scalar, Self::Dim>,
{
self.eval(x, fx)?;
let norm = fx.norm();
Ok(norm)
}
}
pub trait FunctionResultExt<T> {
fn ignore_invalid_value(self, replace_with: T) -> Self;
}
impl<T> FunctionResultExt<T> for Result<T, ProblemError> {
fn ignore_invalid_value(self, replace_with: T) -> Self {
match self {
Ok(value) => Ok(value),
Err(ProblemError::InvalidValue) => Ok(replace_with),
Err(error) => Err(error),
}
}
}