csaps 0.5.0

Cubic spline approximation (smoothing)
Documentation
use ndarray::{ArrayView, ArrayView1, Dimension};

use crate::validate::{validate_data_sites, validate_smooth_value};
use crate::{CsapsError::InvalidInputData, Real, Result};

use super::GridCubicSmoothingSpline;

impl<'a, T, D> GridCubicSmoothingSpline<'a, T, D>
where
    T: Real<T>,
    D: Dimension,
{
    pub(super) fn make_validate(&self) -> Result<()> {
        validate_xy(&self.x, self.y.view())?;
        validate_weights(&self.x, &self.weights)?;
        validate_smooth(&self.x, &self.smooth)?;

        Ok(())
    }

    pub(super) fn evaluate_validate(&self, xi: &[ArrayView1<'a, T>]) -> Result<()> {
        let x_len = self.x.len();
        let xi_len = xi.len();

        if xi_len != x_len {
            return Err(InvalidInputData(format!(
                "The number of `xi` vectors ({}) is not equal to the number of dimensions ({})",
                xi_len, x_len
            )));
        }

        for xi_ax in xi.iter() {
            if xi_ax.is_empty() {
                return Err(InvalidInputData(
                    "The sizes of `xi` vectors must be greater or equal to 1".to_string(),
                ));
            }
        }

        Ok(())
    }
}

pub(super) fn validate_xy<T, D>(x: &[ArrayView1<'_, T>], y: ArrayView<'_, T, D>) -> Result<()>
where
    T: Real<T>,
    D: Dimension,
{
    if x.len() != y.ndim() {
        return Err(InvalidInputData(format!(
            "The number of `x` data site vectors ({}) is not equal to `y` data dimensionality ({})",
            x.len(),
            y.ndim()
        )));
    }

    for (ax, (&xi, &ys)) in x.iter().zip(y.shape().iter()).enumerate() {
        let xi_len = xi.len();

        if xi_len < 2 {
            return Err(InvalidInputData(format!(
                "The size of `x` site vectors must be greater or equal to 2, axis {}",
                ax
            )));
        }

        validate_data_sites(xi.view())?;

        if xi_len != ys {
            return Err(InvalidInputData(format!(
                "`x` data sites vector size ({}) is not equal to `y` data size ({}) for axis {}",
                xi_len, ys, ax
            )));
        }
    }

    Ok(())
}

pub(super) fn validate_weights<T>(
    x: &[ArrayView1<'_, T>],
    w: &[Option<ArrayView1<'_, T>>],
) -> Result<()>
where
    T: Real<T>,
{
    let x_len = x.len();
    let w_len = w.len();

    if w_len != x_len {
        return Err(InvalidInputData(format!(
            "The number of `weights` vectors ({}) is not equal to the number of dimensions ({})",
            w_len, x_len
        )));
    }

    for (ax, (xi, wi)) in x.iter().zip(w.iter()).enumerate() {
        if let Some(wi_view) = wi {
            let xi_len = xi.len();
            let wi_len = wi_view.len();

            if wi_len != xi_len {
                return Err(InvalidInputData(format!(
                    "`weights` vector size ({}) is not equal to `x` vector size ({}) for axis {}",
                    wi_len, xi_len, ax
                )));
            }
        }
    }

    Ok(())
}

pub(super) fn validate_smooth<T>(x: &[ArrayView1<'_, T>], smooth: &[Option<T>]) -> Result<()>
where
    T: Real<T>,
{
    let x_len = x.len();
    let s_len = smooth.len();

    if s_len != x_len {
        return Err(InvalidInputData(format!(
            "The number of `smooth` values ({}) is not equal to the number of dimensions ({})",
            s_len, x_len
        )));
    }

    for (ax, s_opt) in smooth.iter().enumerate() {
        if let Some(s) = s_opt {
            if let Err(err) = validate_smooth_value(*s) {
                return Err(InvalidInputData(format!("{} for axis {}", err, ax)));
            };
        }
    }

    Ok(())
}