pub mod types;
pub use types::SplineBoundaryCondition;
pub mod algorithms;
pub mod utils;
pub mod core;
pub use core::{CubicSpline, CubicSplineBuilder};
pub mod evaluation;
pub mod integration;
pub mod traits_impl;
pub mod api;
pub use api::{
cubic_spline_scipy,
make_interp_spline,
interp1d_scipy,
cubic_spline_second_derivative,
cubic_spline_parabolic_runout,
};
pub use crate::error::{InterpolateError, InterpolateResult};
pub use crate::traits::InterpolationFloat;
#[cfg(test)]
mod tests {
use super::*;
use scirs2_core::ndarray::array;
use approx::assert_abs_diff_eq;
#[test]
fn test_basic_cubic_spline() {
let x = array![0.0, 1.0, 2.0, 3.0];
let y = array![0.0, 1.0, 4.0, 9.0];
let spline = CubicSpline::new(&x.view(), &y.view()).expect("Operation failed");
assert_abs_diff_eq!(spline.evaluate(0.0).expect("Operation failed"), 0.0, epsilon = 1e-10);
assert_abs_diff_eq!(spline.evaluate(1.0).expect("Operation failed"), 1.0, epsilon = 1e-10);
assert_abs_diff_eq!(spline.evaluate(2.0).expect("Operation failed"), 4.0, epsilon = 1e-10);
assert_abs_diff_eq!(spline.evaluate(3.0).expect("Operation failed"), 9.0, epsilon = 1e-10);
}
#[test]
fn test_boundary_conditions() {
let x = array![0.0, 1.0, 2.0, 3.0];
let y = array![0.0, 1.0, 4.0, 9.0];
let natural = CubicSpline::new(&x.view(), &y.view()).expect("Operation failed");
let not_a_knot = CubicSpline::new_not_a_knot(&x.view(), &y.view()).expect("Operation failed");
assert_abs_diff_eq!(natural.evaluate(1.5).expect("Operation failed"), not_a_knot.evaluate(1.5).expect("Operation failed"), epsilon = 0.1);
}
#[test]
fn test_derivatives() {
let x = array![0.0, 1.0, 2.0, 3.0];
let y = array![0.0, 1.0, 4.0, 9.0];
let spline = CubicSpline::new(&x.view(), &y.view()).expect("Operation failed");
let deriv_at_1 = spline.derivative(1.0).expect("Operation failed");
assert!((deriv_at_1 - 2.0_f64).abs() < 0.5_f64, "First derivative at x=1 should be close to 2");
let deriv_at_2 = spline.derivative(2.0).expect("Operation failed");
assert!((deriv_at_2 - 4.0_f64).abs() < 0.5_f64, "First derivative at x=2 should be close to 4");
}
#[test]
fn test_integration() {
let x = array![0.0, 1.0, 2.0];
let y = array![0.0, 1.0, 4.0];
let spline = CubicSpline::new(&x.view(), &y.view()).expect("Operation failed");
assert_abs_diff_eq!(spline.integrate(1.0, 1.0).expect("Operation failed"), 0.0, epsilon = 1e-10);
let integral = spline.integrate(0.0, 2.0).expect("Operation failed");
assert!(integral > 0.0);
}
#[test]
fn test_scipy_compatibility() {
let x = array![0.0, 1.0, 2.0, 3.0];
let y = array![0.0, 1.0, 4.0, 9.0];
let spline = cubic_spline_scipy(&x.view(), &y.view(), "natural", None, false).expect("Operation failed");
assert_abs_diff_eq!(spline.evaluate(1.0).expect("Operation failed"), 1.0, epsilon = 1e-10);
assert_abs_diff_eq!(spline.evaluate(2.0).expect("Operation failed"), 4.0, epsilon = 1e-10);
}
#[test]
fn test_builder_pattern() {
let x = array![0.0, 1.0, 2.0, 3.0];
let y = array![0.0, 1.0, 4.0, 9.0];
let spline = CubicSpline::builder()
.x(x)
.y(y)
.boundary_condition(SplineBoundaryCondition::Natural)
.build()
.expect("Operation failed");
assert_abs_diff_eq!(spline.evaluate(1.5).expect("Operation failed"), spline.evaluate(1.5).expect("Operation failed"), epsilon = 1e-10);
}
#[test]
fn test_error_handling() {
let x = array![0.0, 1.0];
let y = array![0.0, 1.0];
assert!(CubicSpline::new(&x.view(), &y.view()).is_err());
let x = array![0.0, 1.0, 2.0, 3.0];
let y = array![0.0, 1.0, 4.0];
assert!(CubicSpline::new(&x.view(), &y.view()).is_err());
}
#[test]
fn test_out_of_bounds() {
let x = array![1.0, 2.0, 3.0, 4.0];
let y = array![1.0, 4.0, 9.0, 16.0];
let spline = CubicSpline::new(&x.view(), &y.view()).expect("Operation failed");
assert!(spline.evaluate(0.5).is_err());
assert!(spline.evaluate(4.5).is_err());
}
}