diff --git a/src/errors.rs b/src/errors.rs index 08bd0cb..c68d03b 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,6 +1,5 @@ -use thiserror::Error; use ndarray::ShapeError; - +use thiserror::Error; /// Enum provides error types #[derive(Error, Debug)] diff --git a/src/lib.rs b/src/lib.rs index 321a76b..bf019f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -120,13 +120,13 @@ //! mod errors; -mod traits; mod ndarrayext; +mod ndg; mod sprsext; -mod validate; -mod util; +mod traits; mod umv; -mod ndg; +mod util; +mod validate; use std::result; @@ -134,29 +134,27 @@ use std::result; pub type Result = result::Result; pub use errors::CsapsError; +pub use ndg::{GridCubicSmoothingSpline, NdGridSpline}; pub use traits::{Real, RealRef}; -pub use umv::{NdSpline, CubicSmoothingSpline}; -pub use ndg::{NdGridSpline, GridCubicSmoothingSpline}; - +pub use umv::{CubicSmoothingSpline, NdSpline}; // #[cfg(test)] // mod tests { -// use crate::CubicSmoothingSpline; +// use crate::CubicSmoothingSpline; // use ndarray::prelude::*; // #[test] -// fn test_new() { +// fn test_new() { -// let zeros = Array1::::zeros(1); +// let zeros = Array1::::zeros(1); // let x = zeros.view(); // let zeros = Array2::::zeros((1,1)); // let y = zeros.view(); - // let sp = CubicSmoothingSpline::new(x.view(), y.view()) // // .with_optional_weights(weights) // // .with_optional_smooth(s) // .make(); // } -// } \ No newline at end of file +// } diff --git a/src/ndarrayext.rs b/src/ndarrayext.rs index efe2ce1..a29ad01 100644 --- a/src/ndarrayext.rs +++ b/src/ndarrayext.rs @@ -1,19 +1,17 @@ -use ndarray::{prelude::*, IntoDimension, Slice}; use itertools::Itertools; - +use ndarray::{prelude::*, IntoDimension, Slice}; use crate::{ - Result, + util::dim_from_vec, CsapsError::{ReshapeFrom2d, ReshapeTo2d}, - util::dim_from_vec, Real + Real, Result, }; - pub fn diff<'a, T: 'a, D, V>(data: V, axis: Option) -> Array where T: Real, D: Dimension, - V: AsArray<'a, T, D> + V: AsArray<'a, T, D>, { let data_view = data.into(); let axis = axis.unwrap_or_else(|| Axis(data_view.ndim() - 1)); @@ -24,11 +22,10 @@ where &tail - &head } - pub fn to_2d<'a, T: 'a, D, I>(data: I, axis: Axis) -> Result> - where - D: Dimension, - I: AsArray<'a, T, D>, +where + D: Dimension, + I: AsArray<'a, T, D>, { let data_view = data.into(); let ndim = data_view.ndim(); @@ -48,21 +45,18 @@ pub fn to_2d<'a, T: 'a, D, I>(data: I, axis: Axis) -> Result> match data_view.permuted_axes(axes).into_shape(new_shape) { Ok(view_2d) => Ok(view_2d), - Err(error) => Err( - ReshapeTo2d { - input_shape: shape, - output_shape: new_shape.to_vec(), - axis: axis.0, - source: error, - } - ) + Err(error) => Err(ReshapeTo2d { + input_shape: shape, + output_shape: new_shape.to_vec(), + axis: axis.0, + source: error, + }), } } - pub fn to_2d_simple<'a, T: 'a, D>(data: ArrayView<'a, T, D>) -> Result> - where - D: Dimension +where + D: Dimension, { let ndim = data.ndim(); let shape = data.shape().to_vec(); @@ -70,23 +64,24 @@ pub fn to_2d_simple<'a, T: 'a, D>(data: ArrayView<'a, T, D>) -> Result Ok(data_2d), - Err(error) => Err( - ReshapeTo2d { - input_shape: shape, - output_shape: new_shape.to_vec(), - axis: ndim - 1, - source: error, - } - ) + Err(error) => Err(ReshapeTo2d { + input_shape: shape, + output_shape: new_shape.to_vec(), + axis: ndim - 1, + source: error, + }), } } - -pub fn from_2d<'a, T: 'a, D, S, I>(data: I, shape: S, axis: Axis) -> Result> - where - D: Dimension, - S: IntoDimension, - I: AsArray<'a, T, Ix2>, +pub fn from_2d<'a, T: 'a, D, S, I>( + data: I, + shape: S, + axis: Axis, +) -> Result> +where + D: Dimension, + S: IntoDimension, + I: AsArray<'a, T, Ix2>, { let shape = shape.into_dimension(); let ndim = shape.ndim(); @@ -106,29 +101,25 @@ pub fn from_2d<'a, T: 'a, D, S, I>(data: I, shape: S, axis: Axis) -> Result Err( - ReshapeFrom2d { - input_shape: data_view.shape().to_vec(), - output_shape: new_shape_vec, - axis: axis.0, - source: error, - } - ) + } + Err(error) => Err(ReshapeFrom2d { + input_shape: data_view.shape().to_vec(), + output_shape: new_shape_vec, + axis: axis.0, + source: error, + }), } } - /// Returns the indices of the bins to which each value in input array belongs /// /// This code works if `bins` is increasing pub fn digitize<'a, T: 'a, A, B>(arr: A, bins: B) -> Array1 - where - T: Real, - // T: Clone + NdFloat + AlmostEqual, - - A: AsArray<'a, T, Ix1>, - B: AsArray<'a, T, Ix1>, +where + T: Real, + // T: Clone + NdFloat + AlmostEqual, + A: AsArray<'a, T, Ix1>, + B: AsArray<'a, T, Ix1>, { let arr_view = arr.into(); let bins_view = bins.into(); @@ -136,9 +127,11 @@ pub fn digitize<'a, T: 'a, A, B>(arr: A, bins: B) -> Array1 let mut indices = Array1::zeros((arr_view.len(),)); let mut kstart: usize = 0; - for (i, &a) in arr_view.iter().enumerate() - .sorted_by(|e1, e2| e1.1.partial_cmp(e2.1).unwrap()) { - + for (i, &a) in arr_view + .iter() + .enumerate() + .sorted_by(|e1, e2| e1.1.partial_cmp(e2.1).unwrap()) + { let mut k = kstart; for bins_win in bins_view.slice(s![kstart..]).windows(2) { @@ -158,53 +151,55 @@ pub fn digitize<'a, T: 'a, A, B>(arr: A, bins: B) -> Array1 indices } - #[cfg(test)] mod tests { - use std::f64; - use ndarray::{array, Array1, Axis, Ix1, Ix2, Ix3}; use crate::ndarrayext::*; + use ndarray::{array, Array1, Axis, Ix1, Ix2, Ix3}; + use std::f64; #[test] fn test_diff_1d() { let a = array![1., 2., 3., 4., 5.]; - assert_eq!(diff(&a, None), - array![1., 1., 1., 1.]); + assert_eq!(diff(&a, None), array![1., 1., 1., 1.]); - assert_eq!(diff(&a, Some(Axis(0))), - array![1., 1., 1., 1.]); + assert_eq!(diff(&a, Some(Axis(0))), array![1., 1., 1., 1.]); } #[test] fn test_diff_2d() { let a = array![[1., 2., 3., 4.], [1., 2., 3., 4.]]; - assert_eq!(diff(&a, None), - array![[1., 1., 1.], [1., 1., 1.]]); + assert_eq!(diff(&a, None), array![[1., 1., 1.], [1., 1., 1.]]); - assert_eq!(diff(&a, Some(Axis(0))), - array![[0., 0., 0., 0.]]); + assert_eq!(diff(&a, Some(Axis(0))), array![[0., 0., 0., 0.]]); - assert_eq!(diff(&a, Some(Axis(1))), - array![[1., 1., 1.], [1., 1., 1.]]); + assert_eq!(diff(&a, Some(Axis(1))), array![[1., 1., 1.], [1., 1., 1.]]); } #[test] fn test_diff_3d() { let a = array![[[1., 2., 3.], [1., 2., 3.]], [[1., 2., 3.], [1., 2., 3.]]]; - assert_eq!(diff(&a, None), - array![[[1., 1.], [1., 1.]], [[1., 1.], [1., 1.]]]); - - assert_eq!(diff(&a, Some(Axis(0))), - array![[[0., 0., 0.], [0., 0., 0.]]]); - - assert_eq!(diff(&a, Some(Axis(1))), - array![[[0., 0., 0.]], [[0., 0., 0.]]]); - - assert_eq!(diff(&a, Some(Axis(2))), - array![[[1., 1.], [1., 1.]], [[1., 1.], [1., 1.]]]); + assert_eq!( + diff(&a, None), + array![[[1., 1.], [1., 1.]], [[1., 1.], [1., 1.]]] + ); + + assert_eq!( + diff(&a, Some(Axis(0))), + array![[[0., 0., 0.], [0., 0., 0.]]] + ); + + assert_eq!( + diff(&a, Some(Axis(1))), + array![[[0., 0., 0.]], [[0., 0., 0.]]] + ); + + assert_eq!( + diff(&a, Some(Axis(2))), + array![[[1., 1.], [1., 1.]], [[1., 1.], [1., 1.]]] + ); } #[test] @@ -218,8 +213,14 @@ mod tests { fn test_to_2d_from_2d() { let a = array![[1, 2, 3, 4], [5, 6, 7, 8]]; - assert_eq!(to_2d(&a, Axis(0)).unwrap(), array![[1, 5], [2, 6], [3, 7], [4, 8]]); - assert_eq!(to_2d(&a, Axis(1)).unwrap(), array![[1, 2, 3, 4], [5, 6, 7, 8]]); + assert_eq!( + to_2d(&a, Axis(0)).unwrap(), + array![[1, 5], [2, 6], [3, 7], [4, 8]] + ); + assert_eq!( + to_2d(&a, Axis(1)).unwrap(), + array![[1, 2, 3, 4], [5, 6, 7, 8]] + ); } #[test] @@ -229,7 +230,10 @@ mod tests { // FIXME: incompatible memory layout // assert_eq!(to_2d(&a, Axis(0)).unwrap(), array![[1, 7], [2, 8], [3, 9], [4, 10], [5, 11], [6, 12]]); // assert_eq!(to_2d(&a, Axis(1)).unwrap(), array![[1, 4], [2, 5], [3, 6], [7, 10], [8, 11], [9, 12]]); - assert_eq!(to_2d(&a, Axis(2)).unwrap(), array![[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]); + assert_eq!( + to_2d(&a, Axis(2)).unwrap(), + array![[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]] + ); } #[test] @@ -241,13 +245,19 @@ mod tests { #[test] fn test_to_2d_simple_from_2d() { let a = array![[1, 2, 3, 4], [5, 6, 7, 8]]; - assert_eq!(to_2d_simple(a.view()).unwrap(), array![[1, 2, 3, 4], [5, 6, 7, 8]]); + assert_eq!( + to_2d_simple(a.view()).unwrap(), + array![[1, 2, 3, 4], [5, 6, 7, 8]] + ); } #[test] fn test_to_2d_simple_from_3d() { let a = array![[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]; - assert_eq!(to_2d_simple(a.view()).unwrap(), array![[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]); + assert_eq!( + to_2d_simple(a.view()).unwrap(), + array![[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]] + ); } #[test] @@ -258,7 +268,8 @@ mod tests { let r = from_2d(&a, s, Axis(2)) .unwrap() - .into_dimensionality::().unwrap(); + .into_dimensionality::() + .unwrap(); assert_eq!(r, e); } @@ -369,7 +380,10 @@ mod tests { let indices = digitize(&xi, &edges); - assert_eq!(indices, array![1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]) + assert_eq!( + indices, + array![1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3] + ) } #[test] @@ -389,6 +403,9 @@ mod tests { let indices = digitize(&xi, &edges); - assert_eq!(indices, array![0, 1, 0, 2, 2, 1, 0, 3, 4, 4, 3, 3, 2, 2, 1, 0]) + assert_eq!( + indices, + array![0, 1, 0, 2, 2, 1, 0, 3, 4, 4, 3, 3, 2, 2, 1, 0] + ) } } diff --git a/src/ndg.rs b/src/ndg.rs index 1c50b8f..70c2e19 100644 --- a/src/ndg.rs +++ b/src/ndg.rs @@ -1,18 +1,11 @@ -mod validate; -mod make; mod evaluate; +mod make; mod util; +mod validate; -use ndarray::{ - Dimension, - AsArray, - Array, - ArrayView, - ArrayView1, -}; - -use crate::{Real, Result, RealRef}; +use ndarray::{Array, ArrayView, ArrayView1, AsArray, Dimension}; +use crate::{Real, RealRef, Result}; /// N-d grid spline PP-form representation /// @@ -25,9 +18,9 @@ use crate::{Real, Result, RealRef}; /// #[derive(Debug)] pub struct NdGridSpline<'a, T, D> - where - T: Real, - D: Dimension +where + T: Real, + D: Dimension, { /// The grid dimensionality ndim: usize, @@ -46,11 +39,10 @@ pub struct NdGridSpline<'a, T, D> coeffs: Array, } - impl<'a, T, D> NdGridSpline<'a, T, D> - where - T: Real, - D: Dimension +where + T: Real, + D: Dimension, { /// Creates `NdGridSpline` struct from given `breaks` and `coeffs` /// @@ -66,7 +58,11 @@ impl<'a, T, D> NdGridSpline<'a, T, D> pub fn new(breaks: Vec>, coeffs: Array) -> Self { let ndim = breaks.len(); let pieces: Vec = breaks.iter().map(|x| x.len() - 1).collect(); - let order: Vec = pieces.iter().zip(coeffs.shape().iter()).map(|(p, s)| s / p).collect(); + let order: Vec = pieces + .iter() + .zip(coeffs.shape().iter()) + .map(|(p, s)| s / p) + .collect(); NdGridSpline { ndim, @@ -78,19 +74,29 @@ impl<'a, T, D> NdGridSpline<'a, T, D> } /// Returns the n-d grid spline dimensionality - pub fn ndim(&self) -> usize { self.ndim } + pub fn ndim(&self) -> usize { + self.ndim + } /// Returns the vector of the spline order for each dimension - pub fn order(&self) -> &Vec { &self.order } + pub fn order(&self) -> &Vec { + &self.order + } /// Returns the vector of the number of pieces of the spline for each dimension - pub fn pieces(&self) -> &Vec { &self.pieces } + pub fn pieces(&self) -> &Vec { + &self.pieces + } /// Returns the vector of views to the breaks for each dimension - pub fn breaks(&self) -> &Vec> { &self.breaks } + pub fn breaks(&self) -> &Vec> { + &self.breaks + } /// Returns the view to the spline coefficients array - pub fn coeffs(&self) -> ArrayView<'_, T, D> { self.coeffs.view() } + pub fn coeffs(&self) -> ArrayView<'_, T, D> { + self.coeffs.view() + } /// Evaluates the spline on the given data sites pub fn evaluate(&self, xi: &'a [ArrayView1<'a, T>]) -> Array { @@ -98,7 +104,6 @@ impl<'a, T, D> NdGridSpline<'a, T, D> } } - /// N-dimensional grid cubic smoothing spline calculator/evaluator /// /// The struct represents n-dimensional grid smoothing cubic spline and allows you to make @@ -133,9 +138,9 @@ impl<'a, T, D> NdGridSpline<'a, T, D> /// ``` /// pub struct GridCubicSmoothingSpline<'a, T, D> - where - T: Real, - D: Dimension +where + T: Real, + D: Dimension, { /// X data sites (also breaks) x: Vec>, @@ -150,16 +155,15 @@ pub struct GridCubicSmoothingSpline<'a, T, D> smooth: Vec>, /// `NdGridSpline` struct with computed spline - spline: Option> + spline: Option>, } - impl<'a, T, D> GridCubicSmoothingSpline<'a, T, D> - where - T: Real, - for<'r> &'r T: RealRef<&'r T, T>, - - D: Dimension +where + T: Real, + for<'r> &'r T: RealRef<&'r T, T>, + + D: Dimension, { /// Creates `NdGridCubicSmoothingSpline` struct from the given `X` data sites and `Y` data values /// @@ -170,8 +174,8 @@ impl<'a, T, D> GridCubicSmoothingSpline<'a, T, D> /// - `y` -- The Y-data n-d grid values array-like. `ndim` can be from 1 to N. /// pub fn new(x: &[ArrayView1<'a, T>], y: Y) -> Self - where - Y: AsArray<'a, T, D> + where + Y: AsArray<'a, T, D>, { let ndim = x.len(); diff --git a/src/ndg/evaluate.rs b/src/ndg/evaluate.rs index 290f46e..63f493c 100644 --- a/src/ndg/evaluate.rs +++ b/src/ndg/evaluate.rs @@ -1,23 +1,13 @@ -use ndarray::{Dimension, Array, ArrayView1}; +use ndarray::{Array, ArrayView1, Dimension}; -use crate::{ - Real, - NdSpline, - ndarrayext::to_2d_simple, - util::dim_from_vec -}; - -use super::{ - NdGridSpline, - GridCubicSmoothingSpline, - util::permute_axes -}; +use crate::{ndarrayext::to_2d_simple, util::dim_from_vec, NdSpline, Real}; +use super::{util::permute_axes, GridCubicSmoothingSpline, NdGridSpline}; impl<'a, T, D> NdGridSpline<'a, T, D> - where - T: Real, - D: Dimension +where + T: Real, + D: Dimension, { /// Implements evaluating the spline on the given mesh of Xi-sites pub(super) fn evaluate_spline(&self, xi: &[ArrayView1<'a, T>]) -> Array { @@ -47,7 +37,8 @@ impl<'a, T, D> NdGridSpline<'a, T, D> let shape: D = dim_from_vec(self.ndim, coeffs_shape); coeffs_2d - .into_shape(shape).unwrap() + .into_shape(shape) + .unwrap() .permuted_axes(permuted_axes.clone()) .to_owned() }; @@ -59,11 +50,10 @@ impl<'a, T, D> NdGridSpline<'a, T, D> } } - impl<'a, T, D> GridCubicSmoothingSpline<'a, T, D> - where - T: Real, - D: Dimension +where + T: Real, + D: Dimension, { pub(super) fn evaluate_spline(&self, xi: &[ArrayView1<'a, T>]) -> Array { self.spline.as_ref().unwrap().evaluate_spline(&xi) diff --git a/src/ndg/make.rs b/src/ndg/make.rs index b00a00d..99e8e4d 100644 --- a/src/ndg/make.rs +++ b/src/ndg/make.rs @@ -1,26 +1,15 @@ use ndarray::Dimension; use crate::util::dim_from_vec; -use crate::{ - Real, - RealRef, - Result, - CubicSmoothingSpline, - ndarrayext::to_2d_simple, -}; - -use super::{ - GridCubicSmoothingSpline, - NdGridSpline, - util::permute_axes -}; +use crate::{ndarrayext::to_2d_simple, CubicSmoothingSpline, Real, RealRef, Result}; +use super::{util::permute_axes, GridCubicSmoothingSpline, NdGridSpline}; impl<'a, T, D> GridCubicSmoothingSpline<'a, T, D> - where - T: Real, - for<'r> &'r T: RealRef<&'r T, T>, - D: Dimension +where + T: Real, + for<'r> &'r T: RealRef<&'r T, T>, + D: Dimension, { pub(super) fn make_spline(&mut self) -> Result<()> { let ndim = self.x.len(); @@ -49,7 +38,7 @@ impl<'a, T, D> GridCubicSmoothingSpline<'a, T, D> // ::zeros(1).view(); // let y = Array2::::zeros((1,1)).view(); let sp = CubicSmoothingSpline::new(x, y) @@ -65,8 +54,10 @@ impl<'a, T, D> GridCubicSmoothingSpline<'a, T, D> coeffs_shape[ndim_m1] = spline.pieces() * spline.order(); let new_shape: D = dim_from_vec(ndim, coeffs_shape); - spline.coeffs() - .into_shape(new_shape).unwrap() + spline + .coeffs() + .into_shape(new_shape) + .unwrap() .permuted_axes(permuted_axes.clone()) .to_owned() }; diff --git a/src/ndg/util.rs b/src/ndg/util.rs index d08145c..42ace6a 100644 --- a/src/ndg/util.rs +++ b/src/ndg/util.rs @@ -1,9 +1,8 @@ use ndarray::Dimension; - pub(super) fn permute_axes(ndim: usize) -> D - where - D: Dimension +where + D: Dimension, { let mut permute_axes = D::zeros(ndim); diff --git a/src/ndg/validate.rs b/src/ndg/validate.rs index 6bd5bc0..5b864aa 100644 --- a/src/ndg/validate.rs +++ b/src/ndg/validate.rs @@ -1,19 +1,14 @@ -use ndarray::{ - ArrayView, - ArrayView1, - Dimension, -}; +use ndarray::{ArrayView, ArrayView1, Dimension}; -use crate::{Real, Result, CsapsError::InvalidInputData}; 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, - D: Dimension +where + T: Real, + D: Dimension, { pub(super) fn make_validate(&self) -> Result<()> { validate_xy(&self.x, self.y.view())?; @@ -28,21 +23,17 @@ impl<'a, T, D> GridCubicSmoothingSpline<'a, T, D> 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) - ) - ) + 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() - ) - ) + return Err(InvalidInputData( + "The sizes of `xi` vectors must be greater or equal to 1".to_string(), + )); } } @@ -50,66 +41,57 @@ impl<'a, T, D> GridCubicSmoothingSpline<'a, T, D> } } - pub(super) fn validate_xy(x: &[ArrayView1<'_, T>], y: ArrayView<'_, T, D>) -> Result<()> - where - T: Real, - D: Dimension +where + T: Real, + 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()) - ) - ) + 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() - { + 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) - ) - ) + 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) - ) - ) + 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(x: &[ArrayView1<'_, T>], w: &[Option>]) -> Result<()> - where - T: Real +pub(super) fn validate_weights( + x: &[ArrayView1<'_, T>], + w: &[Option>], +) -> Result<()> +where + T: Real, { 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) - ) - ) + 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() { @@ -118,12 +100,10 @@ pub(super) fn validate_weights(x: &[ArrayView1<'_, T>], w: &[Option(x: &[ArrayView1<'_, T>], w: &[Option(x: &[ArrayView1<'_, T>], smooth: &[Option]) -> Result<()> - where - T: Real +where + T: Real, { 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) - ) - ) + 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))) + return Err(InvalidInputData(format!("{} for axis {}", err, ax))); }; } } diff --git a/src/sprsext.rs b/src/sprsext.rs index d4ce126..801628c 100644 --- a/src/sprsext.rs +++ b/src/sprsext.rs @@ -1,24 +1,20 @@ use std::iter::FromIterator; -use ndarray::{prelude::*}; +use ndarray::prelude::*; -use sprs::{CsMat, TriMat, Shape, IndPtrBase}; +use sprs::{CsMat, IndPtrBase, Shape, TriMat}; use sprs_ldl::LdlNumeric; use crate::Real; - - - /// Creates CSR matrix from given diagonals /// /// The created matrix represents diagonal-like sparse matrix (DIA), but in CSR data storage /// because sprs crate does not provide DIA matrices currently. /// pub fn diags(diags: Array2, offsets: &[isize], shape: Shape) -> CsMat - where - T: Real - // T: Clone + NdFloat +where + T: Real, // T: Clone + NdFloat { let (rows, cols) = shape; @@ -74,13 +70,12 @@ pub fn diags(diags: Array2, offsets: &[isize], shape: Shape) -> CsMat mat.to_csr() } - /// Returns values on k-diagonal for given sparse matrix /// /// pub fn diagonal(m: &CsMat, k: isize) -> Array1 - where - T: Real +where + T: Real, { let (rows, cols) = m.shape(); @@ -91,14 +86,15 @@ pub fn diagonal(m: &CsMat, k: isize) -> Array1 } } - -fn diagonal_csr(k: isize, - shape: Shape, - indptr: IndPtrBase, - indices: &[usize], - data: &[T]) -> Array1 - where - T: Real +fn diagonal_csr( + k: isize, + shape: Shape, + indptr: IndPtrBase, + indices: &[usize], + data: &[T], +) -> Array1 +where + T: Real, { let (rows, cols) = shape; @@ -110,7 +106,7 @@ fn diagonal_csr(k: isize, let first_col = if k >= 0 { k as usize } else { 0 }; let diag_size = (rows - first_row).min(cols - first_col) as usize; - let mut diag = Array1::::zeros((diag_size, )); + let mut diag = Array1::::zeros((diag_size,)); for i in 0..diag_size { let row = first_row + i; @@ -131,15 +127,14 @@ fn diagonal_csr(k: isize, diag } - /// Solves linear system Ax = b for symmetric CSR matrix A and dense vector(s) b /// /// A: ref to CSR symmetric sparse matrix /// b: MxN stack of b-vectors where M is equal to A rows/cols and N is the data dimensional /// pub fn solve(a: &CsMat, b: &Array2) -> Array2 - where - T: Real +where + T: Real, { let mut x = Array2::::zeros(b.raw_dim()); @@ -166,7 +161,6 @@ pub fn solve(a: &CsMat, b: &Array2) -> Array2 x } - #[cfg(test)] mod tests { use ndarray::array; @@ -174,7 +168,6 @@ mod tests { use crate::sprsext; - #[test] fn test_diags_1() { /* @@ -183,11 +176,7 @@ mod tests { 0 2 6 */ - let diags = array![ - [1., 2., 3.], - [4., 5., 6.], - [7., 8., 9.], - ]; + let diags = array![[1., 2., 3.], [4., 5., 6.], [7., 8., 9.],]; let shape = (3, 3); @@ -198,7 +187,8 @@ mod tests { vec![0, 1, 0, 1, 2, 1, 2], vec![0, 0, 1, 1, 1, 2, 2], vec![4., 1., 8., 5., 2., 9., 6.], - ).to_csr(); + ) + .to_csr(); assert_eq!(mat, mat_expected); } @@ -211,11 +201,7 @@ mod tests { 0 3 6 9 0 */ - let diags = array![ - [1., 2., 3.], - [4., 5., 6.], - [7., 8., 9.], - ]; + let diags = array![[1., 2., 3.], [4., 5., 6.], [7., 8., 9.],]; let shape = (3, 5); @@ -226,7 +212,8 @@ mod tests { vec![0, 1, 0, 1, 2, 1, 2, 2], vec![0, 0, 1, 1, 1, 2, 2, 3], vec![4., 2., 7., 5., 3., 8., 6., 9.], - ).to_csr(); + ) + .to_csr(); assert_eq!(mat, mat_expected); } @@ -241,11 +228,7 @@ mod tests { 0 0 0 */ - let diags = array![ - [1., 2., 3.], - [4., 5., 6.], - [7., 8., 9.], - ]; + let diags = array![[1., 2., 3.], [4., 5., 6.], [7., 8., 9.],]; let shape: Shape = (5, 3); @@ -256,7 +239,8 @@ mod tests { vec![0, 1, 0, 1, 2, 1, 2, 3], vec![0, 0, 1, 1, 1, 2, 2, 2], vec![4., 1., 8., 5., 2., 9., 6., 3.], - ).to_csr(); + ) + .to_csr(); assert_eq!(mat, mat_expected); } @@ -271,11 +255,7 @@ mod tests { 0 0 3 */ - let diags = array![ - [1., 2., 3.], - [4., 5., 6.], - [7., 8., 9.], - ]; + let diags = array![[1., 2., 3.], [4., 5., 6.], [7., 8., 9.],]; let shape: Shape = (5, 3); @@ -286,7 +266,8 @@ mod tests { vec![0, 1, 2, 1, 2, 3, 2, 3, 4], vec![0, 0, 0, 1, 1, 1, 2, 2, 2], vec![7., 4., 1., 8., 5., 2., 9., 6., 3.], - ).to_csr(); + ) + .to_csr(); assert_eq!(mat, mat_expected); } @@ -308,7 +289,8 @@ mod tests { vec![0, 1, 2], vec![0, 1, 2], vec![1., 2., 3.], - ).to_csr(); + ) + .to_csr(); assert_eq!(mat, mat_expected); } @@ -385,4 +367,4 @@ mod tests { // T: Real { // type Output = CsMatI; -// } \ No newline at end of file +// } diff --git a/src/traits.rs b/src/traits.rs index f3c2e33..a4ce019 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,7 +1,7 @@ -use std::ops::{Add, Mul}; -use num_traits::{Num, MulAdd, Float}; use almost::AlmostEqual; use ndarray::NdFloat; +use num_traits::{Float, MulAdd, Num}; +use std::ops::{Add, Mul}; /// Floating-point element types `f32` and `f64`. /// @@ -11,19 +11,22 @@ use ndarray::NdFloat; /// /// This trait can only be implemented by `f32` and `f64`. pub trait Real: - Num + NdFloat + Default + AlmostEqual + Float + Num + + NdFloat + + Default + + AlmostEqual + + Float + for<'r> std::ops::DivAssign<&'r T> - + MulAdd + + MulAdd { } -pub trait RealRef: Add + Mul {} +pub trait RealRef: Add + Mul {} impl Real for f32 {} impl Real for f64 {} -impl RealRef<&f32,f32> for &f32 {} -impl RealRef<&f64,f64> for &f64 {} - +impl RealRef<&f32, f32> for &f32 {} +impl RealRef<&f64, f64> for &f64 {} // fn test( // a: &CsMatBase, Vec, Vec, usize>, diff --git a/src/umv/make.rs b/src/umv/make.rs index fb670e7..5f0b3a0 100644 --- a/src/umv/make.rs +++ b/src/umv/make.rs @@ -1,20 +1,17 @@ -use ndarray::{prelude::*, concatenate, s}; +use ndarray::{concatenate, prelude::*, s}; use crate::{ - Real, - Result, ndarrayext::{diff, to_2d}, - sprsext, RealRef + sprsext, Real, RealRef, Result, }; -use super::{NdSpline, CubicSmoothingSpline}; - +use super::{CubicSmoothingSpline, NdSpline}; impl<'a, T, D> CubicSmoothingSpline<'a, T, D> where T: Real, for<'r> &'r T: RealRef<&'r T, T>, - D: Dimension + D: Dimension, { pub(super) fn make_spline(&mut self) -> Result<()> { // todo!(); @@ -26,7 +23,8 @@ where let breaks = self.x; let weights_default = Array1::ones(breaks.raw_dim()); - let weights = self.weights + let weights = self + .weights .map(|v| v.reborrow()) // without it we will get an error: "[E0597] `weights_default` does not live long enough" .unwrap_or_else(|| weights_default.view()); @@ -49,11 +47,11 @@ where self.smooth = Some(one); self.spline = Some(NdSpline::new(breaks, coeffs)); - return Ok(()) + return Ok(()); } // General computing cubic smoothing spline for NxM data (3 and more data points) - let ones = |n| Array1::::ones((n, )); + let ones = |n| Array1::::ones((n,)); let qtwq = { let qt = { @@ -87,7 +85,7 @@ where }; let auto_smooth = || { - let trace = |m| { sprsext::diagonal(m, 0).sum() }; + let trace = |m| sprsext::diagonal(m, 0).sum(); one / (one + trace(&r) / (six * trace(&qtwq))) }; @@ -150,7 +148,10 @@ where drop(c3); - concatenate(Axis(0), &[p1.view(), p2.view(), p3.view(), p4]).unwrap().t().to_owned() + concatenate(Axis(0), &[p1.view(), p2.view(), p3.view(), p4]) + .unwrap() + .t() + .to_owned() }; self.smooth = Some(smooth); diff --git a/src/umv/validate.rs b/src/umv/validate.rs index d518a0b..b9aeed9 100644 --- a/src/umv/validate.rs +++ b/src/umv/validate.rs @@ -1,76 +1,61 @@ -use ndarray::{ - Dimension, - Axis, - ArrayView1, -}; +use ndarray::{ArrayView1, Axis, Dimension}; use crate::{ - Real, - CubicSmoothingSpline, + validate::{validate_data_sites, validate_smooth_value}, CsapsError::InvalidInputData, - Result, - validate::{validate_data_sites, validate_smooth_value}, RealRef, + CubicSmoothingSpline, Real, RealRef, Result, }; - impl<'a, T, D> CubicSmoothingSpline<'a, T, D> - where - T: Real, +where + T: Real, for<'r> &'r T: RealRef<&'r T, T>, - D: Dimension + D: Dimension, { pub(super) fn make_validate(&self) -> Result<()> { let x_size = self.x.len(); if x_size < 2 { - return Err( - InvalidInputData( - "The size of data vectors must be greater or equal to 2".to_string() - ) - ) + return Err(InvalidInputData( + "The size of data vectors must be greater or equal to 2".to_string(), + )); } validate_data_sites(self.x)?; if self.y.ndim() == 0 { - return Err( - InvalidInputData("`y` has zero dimensionality".to_string()) - ) + return Err(InvalidInputData("`y` has zero dimensionality".to_string())); } let default_axis = Axis(self.y.ndim() - 1); let axis = self.axis.unwrap_or(default_axis); if axis > default_axis { - return Err( - InvalidInputData( - format!("`axis` value ({}) is out of bounds `y` dimensionality ({})", - axis.0, self.y.ndim()) - ) - ) + return Err(InvalidInputData(format!( + "`axis` value ({}) is out of bounds `y` dimensionality ({})", + axis.0, + self.y.ndim() + ))); } let y_size = self.y.len_of(axis); if x_size != y_size { - return Err( - InvalidInputData( - format!("The shape[{}] ({}) of `y` data is not equal to `x` size ({})", - axis.0, y_size, x_size) - ) - ) + return Err(InvalidInputData(format!( + "The shape[{}] ({}) of `y` data is not equal to `x` size ({})", + axis.0, y_size, x_size + ))); } if let Some(weights) = self.weights { let w_size = weights.len(); if w_size != x_size { - return Err( - InvalidInputData( - format!("`weights` size ({}) is not equal to `x` size ({})", w_size, x_size) - ) - ) + return Err(InvalidInputData(format!( + "`weights` size ({}) is not equal to `x` size ({})", + w_size, x_size + ))); } } @@ -83,19 +68,15 @@ impl<'a, T, D> CubicSmoothingSpline<'a, T, D> pub(super) fn evaluate_validate(&self, xi: ArrayView1<'a, T>) -> Result<()> { if xi.is_empty() { - return Err( - InvalidInputData( - "The size of `xi` vector must be greater or equal to 1".to_string() - ) - ) + return Err(InvalidInputData( + "The size of `xi` vector must be greater or equal to 1".to_string(), + )); } if self.spline.is_none() { - return Err( - InvalidInputData( - "The spline has not been computed, use `make` method before".to_string() - ) - ) + return Err(InvalidInputData( + "The spline has not been computed, use `make` method before".to_string(), + )); } Ok(()) diff --git a/src/util.rs b/src/util.rs index 60ae29d..13d1e8a 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,11 +1,10 @@ -use ndarray::Dimension; use itertools::Itertools; - +use ndarray::Dimension; /// Creates a dimension from the vector with the specified ndim pub(crate) fn dim_from_vec(ndim: usize, dimv: Vec) -> D - where - D: Dimension +where + D: Dimension, { let mut dim = D::zeros(ndim); dim.as_array_view_mut().iter_mut().set_from(dimv); diff --git a/src/validate.rs b/src/validate.rs index de41d11..e5da691 100644 --- a/src/validate.rs +++ b/src/validate.rs @@ -2,37 +2,32 @@ use ndarray::ArrayView1; use crate::{CsapsError::InvalidInputData, Real, Result}; - pub(crate) fn validate_data_sites(x: ArrayView1) -> Result<()> where - T: Real + T: Real, { for w in x.windows(2) { let e1 = w[0]; let e2 = w[1]; if e2 < e1 || e2.almost_equals(e1) { - return Err( - InvalidInputData( - "Data site values must satisfy the condition: x1 < x2 < ... < xN".to_string() - ) - ) + return Err(InvalidInputData( + "Data site values must satisfy the condition: x1 < x2 < ... < xN".to_string(), + )); } } Ok(()) } - pub(crate) fn validate_smooth_value(smooth: T) -> Result<()> where - T: Real + T: Real, { if smooth < T::zero() || smooth > T::one() { - return Err( - InvalidInputData( - format!("`smooth` value must be in range 0..1, given {:?}", smooth) - ) - ) + return Err(InvalidInputData(format!( + "`smooth` value must be in range 0..1, given {:?}", + smooth + ))); } Ok(()) diff --git a/tests/ndg_evaluate.rs b/tests/ndg_evaluate.rs index f6d17d1..0ab08db 100644 --- a/tests/ndg_evaluate.rs +++ b/tests/ndg_evaluate.rs @@ -1,9 +1,8 @@ -use ndarray::array; use approx::assert_abs_diff_eq; +use ndarray::array; use csaps::GridCubicSmoothingSpline; - #[test] fn test_make_vector_1() { let x0 = array![1., 2., 3., 4.]; @@ -12,13 +11,14 @@ fn test_make_vector_1() { let y = array![1., 2., 3., 4.]; let yi = GridCubicSmoothingSpline::new(&x, &y) - .make().unwrap() - .evaluate(&x).unwrap(); + .make() + .unwrap() + .evaluate(&x) + .unwrap(); assert_abs_diff_eq!(yi, y); } - #[test] fn test_make_vector_2() { let x0 = array![1., 2., 3., 4.]; @@ -31,33 +31,31 @@ fn test_make_vector_2() { let yi_expected = array![1., 1.5, 2., 2.5, 3., 3.5, 4.]; let yi = GridCubicSmoothingSpline::new(&x, &y) - .make().unwrap() - .evaluate(&xi).unwrap(); + .make() + .unwrap() + .evaluate(&xi) + .unwrap(); assert_abs_diff_eq!(yi, yi_expected); } - #[test] fn test_make_surface_1() { let x0 = array![1., 2., 3.]; let x1 = array![1., 2., 3., 4.]; let x = vec![x0.view(), x1.view()]; - let y = array![ - [1., 2., 3., 4.], - [5., 6., 7., 8.], - [9., 10., 11., 12.], - ]; + let y = array![[1., 2., 3., 4.], [5., 6., 7., 8.], [9., 10., 11., 12.],]; let yi = GridCubicSmoothingSpline::new(&x, &y) - .make().unwrap() - .evaluate(&x).unwrap(); + .make() + .unwrap() + .evaluate(&x) + .unwrap(); assert_abs_diff_eq!(yi, y); } - #[test] fn test_make_surface_2() { let x0 = array![1., 2., 3.]; @@ -68,11 +66,7 @@ fn test_make_surface_2() { let xi1 = array![1., 1.5, 2., 2.5, 3., 3.5, 4.]; let xi = vec![xi0.view(), xi1.view()]; - let y = array![ - [1., 2., 3., 4.], - [5., 6., 7., 8.], - [9., 10., 11., 12.], - ]; + let y = array![[1., 2., 3., 4.], [5., 6., 7., 8.], [9., 10., 11., 12.],]; let yi_expected = array![ [1., 1.5, 2., 2.5, 3., 3.5, 4.], @@ -83,8 +77,10 @@ fn test_make_surface_2() { ]; let yi = GridCubicSmoothingSpline::new(&x, &y) - .make().unwrap() - .evaluate(&xi).unwrap(); + .make() + .unwrap() + .evaluate(&xi) + .unwrap(); assert_abs_diff_eq!(yi, yi_expected); } diff --git a/tests/ndg_make.rs b/tests/ndg_make.rs index 76ddba2..9c088a7 100644 --- a/tests/ndg_make.rs +++ b/tests/ndg_make.rs @@ -1,9 +1,8 @@ -use ndarray::{array, Array1}; use approx::assert_abs_diff_eq; +use ndarray::{array, Array1}; use csaps::GridCubicSmoothingSpline; - #[test] fn test_make_surface() { let x0 = array![1., 2., 3.]; @@ -11,14 +10,9 @@ fn test_make_surface() { let x = vec![x0.view(), x1.view()]; - let y = array![ - [1., 2., 3., 4.], - [5., 6., 7., 8.], - [9., 10., 11., 12.], - ]; + let y = array![[1., 2., 3., 4.], [5., 6., 7., 8.], [9., 10., 11., 12.],]; - let s = GridCubicSmoothingSpline::new(&x, &y) - .make().unwrap(); + let s = GridCubicSmoothingSpline::new(&x, &y).make().unwrap(); let coeffs_expected = array![ [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], @@ -29,7 +23,7 @@ fn test_make_surface() { [0., 0., 0., 0., 0., 0., 0., 0., 0., 4., 4., 4.], [0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 2., 3.], [0., 0., 0., 0., 0., 0., 1., 1., 1., 5., 6., 7.], - ]; + ]; let smooth: Array1 = s.smooth().iter().map(|v| v.unwrap()).collect(); diff --git a/tests/umv_evaluate.rs b/tests/umv_evaluate.rs index 06aeb64..0a00187 100644 --- a/tests/umv_evaluate.rs +++ b/tests/umv_evaluate.rs @@ -1,6 +1,5 @@ -use ndarray::array; use csaps::CubicSmoothingSpline; - +use ndarray::array; #[test] fn test_evaluate_1d() { @@ -8,56 +7,53 @@ fn test_evaluate_1d() { let y = array![1., 2., 3., 4.]; let xi = array![1., 1.5, 2., 2.5, 3., 3.5, 4.]; - let spline = CubicSmoothingSpline::new(&x, &y) - .make() - .unwrap(); + let spline = CubicSmoothingSpline::new(&x, &y).make().unwrap(); let ys = spline.evaluate(&xi).unwrap(); assert_eq!(ys, array![1., 1.5, 2., 2.5, 3., 3.5, 4.]); } - #[test] fn test_evaluate_2d_1() { let x = array![1., 2., 3., 4.]; let y = array![[1., 2., 3., 4.], [3., 5., 7., 9.]]; - let spline = CubicSmoothingSpline::new(&x, &y) - .make() - .unwrap(); + let spline = CubicSmoothingSpline::new(&x, &y).make().unwrap(); let ys = spline.evaluate(&x).unwrap(); assert_eq!(ys, y); } - #[test] fn test_evaluate_2d_2() { let x = array![1., 2., 3., 4.]; let y = array![[1., 2., 3., 4.], [3., 5., 7., 9.]]; let xi = array![1., 1.5, 2., 2.5, 3., 3.5, 4.]; - let spline = CubicSmoothingSpline::new(&x, &y) - .make() - .unwrap(); + let spline = CubicSmoothingSpline::new(&x, &y).make().unwrap(); let ys = spline.evaluate(&xi).unwrap(); - assert_eq!(ys, array![[1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0], - [3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]]); + assert_eq!( + ys, + array![ + [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0], + [3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] + ] + ); } - #[test] fn test_evaluate_3d() { let x = array![1., 2., 3., 4.]; - let y = array![[[1., 2., 3., 4.], [2., 4., 6., 8.]], [[1., 3., 5., 7.], [3., 5., 7., 9.]]]; + let y = array![ + [[1., 2., 3., 4.], [2., 4., 6., 8.]], + [[1., 3., 5., 7.], [3., 5., 7., 9.]] + ]; - let spline = CubicSmoothingSpline::new(&x, &y) - .make() - .unwrap(); + let spline = CubicSmoothingSpline::new(&x, &y).make().unwrap(); let ys = spline.evaluate(&x).unwrap(); diff --git a/tests/umv_full.rs b/tests/umv_full.rs index 8d2eed0..5a0a194 100644 --- a/tests/umv_full.rs +++ b/tests/umv_full.rs @@ -1,89 +1,115 @@ -use ndarray::{array, Array1, Axis}; use approx::assert_abs_diff_eq; +use ndarray::{array, Array1, Axis}; use csaps::CubicSmoothingSpline; - const EPS: f64 = 1e-08; - #[test] fn test_without_weights_auto_smooth_1() { let x = array![1.0, 2.0, 3.0, 4.0, 5.0]; let y = array![1.5, 3.5, 2.6, 1.2, 4.4]; - let s = CubicSmoothingSpline::new(&x, &y) - .make() - .unwrap(); + let s = CubicSmoothingSpline::new(&x, &y).make().unwrap(); assert_abs_diff_eq!(s.smooth().unwrap(), 0.8999999999999999); let coeffs_expected = array![[ - -0.41780962939499505, 0.39429046563192893, - 0.6284368070953434, -0.6049176433322773, - 0.0, -1.253428888184985, - -0.07055749128919839, 1.814752929996832, - 1.597869813113715, 0.3444409249287297, - -0.979545454545454, 0.7646499841621794, - 1.7785397529299969, 2.958599936648717, - 2.44390243902439, 2.022236300285081, - - ]]; + -0.41780962939499505, + 0.39429046563192893, + 0.6284368070953434, + -0.6049176433322773, + 0.0, + -1.253428888184985, + -0.07055749128919839, + 1.814752929996832, + 1.597869813113715, + 0.3444409249287297, + -0.979545454545454, + 0.7646499841621794, + 1.7785397529299969, + 2.958599936648717, + 2.44390243902439, + 2.022236300285081, + ]]; assert_abs_diff_eq!(s.spline().unwrap().coeffs(), coeffs_expected, epsilon = EPS); let ys = s.evaluate(&x).unwrap(); let ys_expected = array![ - 1.7785397529299969, 2.958599936648717, 2.44390243902439, 2.022236300285081, 3.9967215711118156 + 1.7785397529299969, + 2.958599936648717, + 2.44390243902439, + 2.022236300285081, + 3.9967215711118156 ]; assert_abs_diff_eq!(ys, ys_expected, epsilon = EPS); } - #[test] fn test_without_weights_auto_smooth_2() { let x = array![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]; let y = array![1.5, 3.5, 2.6, 1.2, 4.4, 2.2, 1.6, 7.8, 9.1]; - let s = CubicSmoothingSpline::new(&x, &y) - .make() - .unwrap(); + let s = CubicSmoothingSpline::new(&x, &y).make().unwrap(); let coeffs_expected = Array1::from(vec![ - -0.40104239278928844, 0.40119697598279225, - 0.4627405882617183, -1.0601182231124329, - 0.8508522158245622, 0.6042037115821123, - -1.312753456982271, 0.4549205812328071, - 0.0, -1.2031271783678652, - 0.0004637495805114, 1.3886855143656665, - -1.7916691549716321, 0.7608874925020545, - 2.5734986272483913, -1.3647617436984212, - 1.5988545517483752, 0.3957273733805099, - -0.8069360554068441, 0.5822132085393337, - 0.17922956793336786, -0.8515520945362101, - 2.482834025214236, 3.6915709087642057, - 1.7673615951928592, 2.965173754151946, - 2.5589709251473827, 2.2152392075827683, - 3.1260197073753355, 2.3644323361616335, - 2.87797144570959, 6.6215506411899465, - ]).insert_axis(Axis(0)); + -0.40104239278928844, + 0.40119697598279225, + 0.4627405882617183, + -1.0601182231124329, + 0.8508522158245622, + 0.6042037115821123, + -1.312753456982271, + 0.4549205812328071, + 0.0, + -1.2031271783678652, + 0.0004637495805114, + 1.3886855143656665, + -1.7916691549716321, + 0.7608874925020545, + 2.5734986272483913, + -1.3647617436984212, + 1.5988545517483752, + 0.3957273733805099, + -0.8069360554068441, + 0.5822132085393337, + 0.17922956793336786, + -0.8515520945362101, + 2.482834025214236, + 3.6915709087642057, + 1.7673615951928592, + 2.965173754151946, + 2.5589709251473827, + 2.2152392075827683, + 3.1260197073753355, + 2.3644323361616335, + 2.87797144570959, + 6.6215506411899465, + ]) + .insert_axis(Axis(0)); assert_abs_diff_eq!(s.spline().unwrap().coeffs(), coeffs_expected, epsilon = EPS); let ys = s.evaluate(&x).unwrap(); let ys_expected = array![ - 1.7673615951928592, 2.965173754151946, 2.5589709251473827, - 2.2152392075827683, 3.1260197073753355, 2.3644323361616335, - 2.87797144570959, 6.6215506411899465, 9.403280387488538, + 1.7673615951928592, + 2.965173754151946, + 2.5589709251473827, + 2.2152392075827683, + 3.1260197073753355, + 2.3644323361616335, + 2.87797144570959, + 6.6215506411899465, + 9.403280387488538, ]; assert_abs_diff_eq!(ys, ys_expected, epsilon = EPS); } - #[test] fn test_with_weights_and_smooth() { let x = array![1.0, 2.0, 3.0, 4.0, 5.0]; @@ -97,18 +123,34 @@ fn test_with_weights_and_smooth() { .unwrap(); let coeffs_expected = array![[ - -0.1877506234413966, 0.18106733167082298, 0.34543640897755623, -0.33875311720698265, - 0.0, -0.5632518703241898, -0.020049875311720824, 1.016259351620948, - 0.7996708229426432, 0.23641895261845425, -0.34688279301745645, 0.6493266832917706, - 1.7816259351620949, 2.3935461346633415, 2.247780548628429, 2.226284289276808 - ]]; + -0.1877506234413966, + 0.18106733167082298, + 0.34543640897755623, + -0.33875311720698265, + 0.0, + -0.5632518703241898, + -0.020049875311720824, + 1.016259351620948, + 0.7996708229426432, + 0.23641895261845425, + -0.34688279301745645, + 0.6493266832917706, + 1.7816259351620949, + 2.3935461346633415, + 2.247780548628429, + 2.226284289276808 + ]]; assert_abs_diff_eq!(s.spline().unwrap().coeffs(), coeffs_expected, epsilon = EPS); let ys = s.evaluate(&x).unwrap(); let ys_expected = array![ - 1.7816259351620949, 2.3935461346633415, 2.247780548628429, 2.226284289276808, 3.553117206982544 + 1.7816259351620949, + 2.3935461346633415, + 2.247780548628429, + 2.226284289276808, + 3.553117206982544 ]; assert_abs_diff_eq!(ys, ys_expected, epsilon = EPS); diff --git a/tests/umv_make.rs b/tests/umv_make.rs index 2319454..04f36c9 100644 --- a/tests/umv_make.rs +++ b/tests/umv_make.rs @@ -1,17 +1,18 @@ -use ndarray::{array, Array, Array2, Dimension, Array1}; -use csaps::{Real, CubicSmoothingSpline, RealRef}; - - -fn test_driver_make_nd_npt(x: Array1, y: Array, - order: usize, pieces: usize, coeffs: Array2) - where - T: Real, - for<'r> &'r T: RealRef<&'r T, T>, - D: Dimension +use csaps::{CubicSmoothingSpline, Real, RealRef}; +use ndarray::{array, Array, Array1, Array2, Dimension}; + +fn test_driver_make_nd_npt( + x: Array1, + y: Array, + order: usize, + pieces: usize, + coeffs: Array2, +) where + T: Real, + for<'r> &'r T: RealRef<&'r T, T>, + D: Dimension, { - let s = CubicSmoothingSpline::new(&x, &y) - .make() - .unwrap(); + let s = CubicSmoothingSpline::new(&x, &y).make().unwrap(); let spline = s.spline().unwrap(); @@ -22,35 +23,30 @@ fn test_driver_make_nd_npt(x: Array1, y: Array, } fn test_driver_make_nd_2pt(x: Array1, y: Array, coeffs: Array2) - where - T: Real, +where + T: Real, for<'r> &'r T: RealRef<&'r T, T>, - // for<'r> &'r T: Add<&'r T, Output = T>, - // T: MulAcc, - // for<'r> &'r T: Mul<&'r T, Output = T>, - D: Dimension + // for<'r> &'r T: Add<&'r T, Output = T>, + // T: MulAcc, + // for<'r> &'r T: Mul<&'r T, Output = T>, + D: Dimension, { test_driver_make_nd_npt(x, y, 2, 1, coeffs); } fn test_driver_make_nd_4pt(x: Array1, y: Array, coeffs: Array2) - where - T: Real, - D: Dimension, +where + T: Real, + D: Dimension, for<'r> &'r T: RealRef<&'r T, T>, - { test_driver_make_nd_npt(x, y, 4, 3, coeffs); } #[test] fn test_make_1d_2pt() { - test_driver_make_nd_2pt( - array![1., 2.], - array![1., 2.], - array![[1., 1.]] - ); + test_driver_make_nd_2pt(array![1., 2.], array![1., 2.], array![[1., 1.]]); } #[test] @@ -58,7 +54,7 @@ fn test_make_2d_2pt() { test_driver_make_nd_2pt( array![1., 2.], array![[1., 2.], [3., 5.]], - array![[1., 1.], [2., 3.]] + array![[1., 1.], [2., 3.]], ); } @@ -67,7 +63,7 @@ fn test_make_3d_2pt() { test_driver_make_nd_2pt( array![1., 2.], array![[[1., 2.], [3., 5.]], [[2., 4.], [4., 7.]]], - array![[1., 1.], [2., 3.], [2., 2.], [3., 4.]] + array![[1., 1.], [2., 3.], [2., 2.], [3., 4.]], ); } @@ -76,7 +72,7 @@ fn test_make_1d_4pt() { test_driver_make_nd_4pt( array![1., 2., 3., 4.], array![1., 2., 3., 4.], - array![[0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 2., 3.]] + array![[0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 2., 3.]], ); } @@ -87,7 +83,8 @@ fn test_make_2d_4pt() { array![[1., 2., 3., 4.], [1., 3., 5., 7.]], array![ [0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 2., 3.], - [0., 0., 0., 0., 0., 0., 2., 2., 2., 1., 3., 5.]] + [0., 0., 0., 0., 0., 0., 2., 2., 2., 1., 3., 5.] + ], ); } @@ -95,12 +92,16 @@ fn test_make_2d_4pt() { fn test_make_3d_4pt() { test_driver_make_nd_4pt( array![1., 2., 3., 4.], - array![[[1., 2., 3., 4.], [1., 3., 5., 7.]], [[2., 4., 6., 8.], [3., 4., 5., 6.]]], + array![ + [[1., 2., 3., 4.], [1., 3., 5., 7.]], + [[2., 4., 6., 8.], [3., 4., 5., 6.]] + ], array![ [0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 2., 3.], [0., 0., 0., 0., 0., 0., 2., 2., 2., 1., 3., 5.], [0., 0., 0., 0., 0., 0., 2., 2., 2., 2., 4., 6.], - [0., 0., 0., 0., 0., 0., 1., 1., 1., 3., 4., 5.]] + [0., 0., 0., 0., 0., 0., 1., 1., 1., 3., 4., 5.] + ], ); } @@ -122,8 +123,7 @@ fn test_make_2d_12x3_from_coeffs() { [3., 7., 11.], ]; - let spline = CubicSmoothingSpline::new(&x, &y) - .make().unwrap(); + let spline = CubicSmoothingSpline::new(&x, &y).make().unwrap(); let coeffs_expected = array![ [0., 0., 0., 0., 0., 0., 0., 0.], diff --git a/tests/umv_validate.rs b/tests/umv_validate.rs index f9ae9fc..3e76482 100644 --- a/tests/umv_validate.rs +++ b/tests/umv_validate.rs @@ -1,6 +1,5 @@ -use ndarray::{array, Array0, Axis}; use csaps::CubicSmoothingSpline; - +use ndarray::{array, Array0, Axis}; #[test] #[should_panic(expected = "Data site values must satisfy the condition: x1 < x2 < ... < xN")] @@ -8,48 +7,36 @@ fn test_sites_invalid_order_1() { let x = array![1., 2., 2., 4.]; let y = array![1., 2., 3., 4.]; - CubicSmoothingSpline::new(&x, &y) - .make() - .unwrap(); + CubicSmoothingSpline::new(&x, &y).make().unwrap(); } - #[test] #[should_panic(expected = "Data site values must satisfy the condition: x1 < x2 < ... < xN")] fn test_sites_invalid_order_2() { let x = array![1., 2., 3., 1.]; let y = array![1., 2., 3., 4.]; - CubicSmoothingSpline::new(&x, &y) - .make() - .unwrap(); + CubicSmoothingSpline::new(&x, &y).make().unwrap(); } - #[test] #[should_panic(expected = "`y` has zero dimensionality")] fn test_zero_ndim_y_error() { let x = array![1., 2., 3., 4.]; let y = Array0::::zeros(()); - CubicSmoothingSpline::new(&x, &y) - .make() - .unwrap(); + CubicSmoothingSpline::new(&x, &y).make().unwrap(); } - #[test] #[should_panic(expected = "The shape[0] (5) of `y` data is not equal to `x` size (4)")] fn test_data_size_mismatch_error() { let x = array![1., 2., 3., 4.]; let y = array![1., 2., 3., 4., 5.]; - CubicSmoothingSpline::new(&x, &y) - .make() - .unwrap(); + CubicSmoothingSpline::new(&x, &y).make().unwrap(); } - #[test] #[should_panic(expected = "`axis` value (1) is out of bounds `y` dimensionality (1)")] fn test_axis_out_of_bounds_error() { @@ -62,7 +49,6 @@ fn test_axis_out_of_bounds_error() { .unwrap(); } - #[test] #[should_panic(expected = "`weights` size (5) is not equal to `x` size (4)")] fn test_weights_size_mismatch_error() { @@ -76,7 +62,6 @@ fn test_weights_size_mismatch_error() { .unwrap(); } - #[test] #[should_panic(expected = "`smooth` value must be in range 0..1, given -0.5")] fn test_smooth_less_than_error() { @@ -90,7 +75,6 @@ fn test_smooth_less_than_error() { .unwrap(); } - #[test] #[should_panic(expected = "`smooth` value must be in range 0..1, given 1.5")] fn test_smooth_greater_than_error() { @@ -104,7 +88,6 @@ fn test_smooth_greater_than_error() { .unwrap(); } - #[test] #[should_panic(expected = "The spline has not been computed, use `make` method before")] fn test_evaluate_not_valid_error() {