rsl-interpolation 0.1.18

A re-write of GSL's Interpolation Routines in Rust.
Documentation
use std::ops::Deref;

use crate::Accelerator;
use crate::Cache;
use crate::Interp2dType;
use crate::Interpolation2d;
use crate::InterpolationError;

/// 2D Interpolator with runtime-determined Interpolation Type.
pub type DynInterpolation2d<T> = Box<dyn Interpolation2d<T> + Send + Sync + 'static>;

/// Representation of a 2d Interpolation Type that is not known in compile-time.
pub struct DynInterp2dType<T> {
    #[allow(clippy::type_complexity)]
    build: Box<
        dyn Fn(&[T], &[T], &[T]) -> Result<DynInterpolation2d<T>, InterpolationError>
            + Send
            + Sync
            + 'static,
    >,
    name: Box<str>,
    min_size: usize,
}

impl<T> DynInterp2dType<T> {
    pub fn new<I>(interp: I) -> Self
    where
        I: Interp2dType<T> + Send + Sync + 'static,
        I::Interpolation2d: Send + Sync + 'static,
    {
        Self {
            name: interp.name().into(),
            min_size: interp.min_size(),
            build: Box::new(move |xa, ya, za| match interp.build(xa, ya, za) {
                Ok(interp) => Ok(Box::new(interp)),
                Err(err) => Err(err),
            }),
        }
    }
}

impl<T> Interp2dType<T> for DynInterp2dType<T> {
    type Interpolation2d = DynInterpolation2d<T>;

    fn build(
        &self,
        xa: &[T],
        ya: &[T],
        za: &[T],
    ) -> Result<DynInterpolation2d<T>, InterpolationError> {
        (self.build)(xa, ya, za)
    }

    fn name(&self) -> &str {
        &self.name
    }

    fn min_size(&self) -> usize {
        self.min_size
    }
}

impl<T> Interpolation2d<T> for DynInterpolation2d<T> {
    fn eval_extrap(
        &self,
        xa: &[T],
        ya: &[T],
        za: &[T],
        x: T,
        y: T,
        xacc: &mut Accelerator,
        yacc: &mut Accelerator,
        cache: &mut Cache<T>,
    ) -> Result<T, crate::DomainError> {
        self.deref()
            .eval_extrap(xa, ya, za, x, y, xacc, yacc, cache)
    }

    fn eval_deriv_x(
        &self,
        xa: &[T],
        ya: &[T],
        za: &[T],
        x: T,
        y: T,
        xacc: &mut Accelerator,
        yacc: &mut Accelerator,
        cache: &mut Cache<T>,
    ) -> Result<T, crate::DomainError> {
        self.deref()
            .eval_deriv_x(xa, ya, za, x, y, xacc, yacc, cache)
    }

    fn eval_deriv_y(
        &self,
        xa: &[T],
        ya: &[T],
        za: &[T],
        x: T,
        y: T,
        xacc: &mut Accelerator,
        yacc: &mut Accelerator,
        cache: &mut Cache<T>,
    ) -> Result<T, crate::DomainError> {
        self.deref()
            .eval_deriv_y(xa, ya, za, x, y, xacc, yacc, cache)
    }

    fn eval_deriv_xx(
        &self,
        xa: &[T],
        ya: &[T],
        za: &[T],
        x: T,
        y: T,
        xacc: &mut Accelerator,
        yacc: &mut Accelerator,
        cache: &mut Cache<T>,
    ) -> Result<T, crate::DomainError> {
        self.deref()
            .eval_deriv_xx(xa, ya, za, x, y, xacc, yacc, cache)
    }

    fn eval_deriv_yy(
        &self,
        xa: &[T],
        ya: &[T],
        za: &[T],
        x: T,
        y: T,
        xacc: &mut Accelerator,
        yacc: &mut Accelerator,
        cache: &mut Cache<T>,
    ) -> Result<T, crate::DomainError> {
        self.deref()
            .eval_deriv_yy(xa, ya, za, x, y, xacc, yacc, cache)
    }

    fn eval_deriv_xy(
        &self,
        xa: &[T],
        ya: &[T],
        za: &[T],
        x: T,
        y: T,
        xacc: &mut Accelerator,
        yacc: &mut Accelerator,
        cache: &mut Cache<T>,
    ) -> Result<T, crate::DomainError> {
        self.deref()
            .eval_deriv_xy(xa, ya, za, x, y, xacc, yacc, cache)
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::*;

    #[test]
    fn test_dyn_interp2d_type() {
        let xa = [0.0, 1.0, 2.0, 3.0];
        let ya = [0.0, 1.0, 2.0, 3.0];
        #[rustfmt::skip]
        let za = [
            1.0, 1.1, 1.2, 1.3,
            1.1, 1.2, 1.3, 1.4,
            1.2, 1.3, 1.4, 1.5,
            1.3, 1.4, 1.5, 1.6,
        ];

        let mut xacc = Accelerator::new();
        let mut yacc = Accelerator::new();
        let mut cache = Cache::new();
        let interp: DynInterpolation2d<f64> =
            DynInterp2dType::new(Bicubic).build(&xa, &ya, &za).unwrap();

        let _ = interp
            .eval(&xa, &ya, &za, 1.0, 1.0, &mut xacc, &mut yacc, &mut cache)
            .unwrap();
    }
}