mod evaluate;
mod make;
mod validate;
use ndarray::{Array, Array2, ArrayView, ArrayView1, ArrayView2, AsArray, Axis, Dimension};
use crate::{Real, RealRef, Result};
#[derive(Debug)]
pub struct NdSpline<'a, T>
where
T: Real<T>,
{
ndim: usize,
order: usize,
pieces: usize,
breaks: ArrayView1<'a, T>,
coeffs: Array2<T>,
}
impl<'a, T> NdSpline<'a, T>
where
T: Real<T>,
{
pub fn new(breaks: ArrayView1<'a, T>, coeffs: Array2<T>) -> NdSpline<'a, T> {
let c_shape = coeffs.shape();
let ndim = c_shape[0];
let pieces = breaks.len() - 1;
let order = c_shape[1] / pieces;
NdSpline {
ndim,
order,
pieces,
breaks,
coeffs,
}
}
pub fn ndim(&self) -> usize {
self.ndim
}
pub fn order(&self) -> usize {
self.order
}
pub fn pieces(&self) -> usize {
self.pieces
}
pub fn breaks(&self) -> ArrayView1<'_, T> {
self.breaks.view()
}
pub fn coeffs(&self) -> ArrayView2<'_, T> {
self.coeffs.view()
}
pub fn evaluate(&self, xi: ArrayView1<'a, T>) -> Array2<T> {
Self::evaluate_spline(
self.order,
self.pieces,
self.breaks.view(),
self.coeffs.view(),
xi,
)
}
}
pub struct CubicSmoothingSpline<'a, T, D>
where
T: Real<T>,
for<'r> &'r T: RealRef<&'r T, T>,
D: Dimension,
{
x: ArrayView1<'a, T>,
y: ArrayView<'a, T, D>,
axis: Option<Axis>,
weights: Option<ArrayView1<'a, T>>,
smooth: Option<T>,
spline: Option<NdSpline<'a, T>>,
}
impl<'a, T, D> CubicSmoothingSpline<'a, T, D>
where
T: Real<T>,
for<'r> &'r T: RealRef<&'r T, T>,
D: Dimension,
{
pub fn new<X, Y>(x: X, y: Y) -> Self
where
X: AsArray<'a, T>,
Y: AsArray<'a, T, D>,
{
CubicSmoothingSpline {
x: x.into(),
y: y.into(),
axis: None,
weights: None,
smooth: None,
spline: None,
}
}
pub fn with_axis(mut self, axis: Axis) -> Self {
self.invalidate();
self.axis = Some(axis);
self
}
pub fn with_weights<W>(mut self, weights: W) -> Self
where
W: AsArray<'a, T>,
{
self.invalidate();
self.weights = Some(weights.into());
self
}
pub fn with_optional_weights<W>(mut self, weights: Option<W>) -> Self
where
W: AsArray<'a, T>,
{
self.invalidate();
self.weights = weights.map(|w| w.into());
self
}
pub fn with_smooth(mut self, smooth: T) -> Self {
self.invalidate();
self.smooth = Some(smooth);
self
}
pub fn with_optional_smooth(mut self, smooth: Option<T>) -> Self {
self.invalidate();
self.smooth = smooth;
self
}
pub fn evaluate<X>(&self, xi: X) -> Result<Array<T, D>>
where
X: AsArray<'a, T>,
{
let xi = xi.into();
self.evaluate_validate(xi)?;
let yi = self.evaluate_spline(xi)?;
Ok(yi)
}
pub fn smooth(&self) -> Option<T> {
self.smooth
}
pub fn spline(&self) -> Option<&NdSpline<'a, T>> {
self.spline.as_ref()
}
fn invalidate(&mut self) {
self.spline = None;
}
pub fn make(mut self) -> Result<Self> {
self.make_validate()?;
self.make_spline()?;
Ok(self)
}
}