Module peroxide::numerical::spline

source ·
Expand description

Spline interpolations

§Available splines

  • Cubic spline
  • Cubic Hermite spline
  • B-spline

§Spline<T> trait

§Methods

  • fn eval(&self, t: f64) -> T : Evaluate the spline at t
    • For Cubic Spline, t means x (domain) and T = f64
    • For B-Spline, t means parameter of curve and T = (f64, f64)
  • fn eval_vec(&self, v: &[f64]) -> Vec<T> : Evaluate spline values for an array v
  • fn eval_with_cond<F>(&self, t: f64, cond: F) -> T : Evaluate the spline at t, with a condition
  • fn eval_vec_with_cond<F>(&self, v: &[f64], cond: F) -> Vec<T> : Evaluate spline values for an array v, with a condition

§PolynomialSpline trait

§Methods

  • fn polynomial_at(&self, x: f64) -> &Polynomial : Get the polynomial at x
  • fn number_of_polynomials(&self) -> usize : Get the number of polynomials
  • fn get_ranged_polynomials(&self) -> &Vec<(Range<f64>, Polynomial)> : Get the polynomials

§Low-level interface

§Members

  • CubicSpline: Structure for cubic spline
    • fn from_nodes(node_x: &[f64], node_y: &[f64]) -> Result<Self> : Create a cubic spline from nodes
    • fn extend_with_nodes(&mut self, node_x: Vec<f64>, node_y: Vec<f64>) -> Result<()> : Extend the spline with nodes
  • CubicHermiteSpline: Structure for cubic Hermite spline
    • fn from_nodes_with_slopes(node_x: &[f64], node_y: &[f64], m: &[f64]) -> Result<Self> : Create a Cubic Hermite spline from nodes with slopes
    • fn from_nodes(node_x: &[f64], node_y: &[f64], slope_method: SlopeMethod) -> Result<Self> : Create a Cubic Hermite spline from nodes with slope estimation methods
    • SlopeMethod: Enum for slope estimation methods
      • Akima: Akima’s method to estimate slopes (Akima (1970))
      • Quadratic: Using quadratic interpolation to estimate slopes
  • BSpline: Structure for B-Spline
    • fn open(degree: usize, knots: Vec<f64>, control_points: Vec<Vec<f64>>) -> Result<Self> : Create an open B-Spline
    • fn clamped(degree: usize, knots: Vec<f64>, control_points: Vec<Vec<f64>>) -> Result<Self> : Create a clamped B-Spline
    • fn cox_de_boor(t: f64, i: f64) : Cox-de Boor recursion formula (Here, use iteration instead of recursion)

§Usage (Cubic Spline Family)

use peroxide::fuga::*;

fn main() -> Result<(), Box<dyn Error>> {
    let x = seq(0, 10, 1);
    let y = x.fmap(|t| t.sin());
     
    let cs = CubicSpline::from_nodes(&x, &y)?;
    let cs_akima = CubicHermiteSpline::from_nodes(&x, &y, Akima)?;
    let cs_quad = CubicHermiteSpline::from_nodes(&x, &y, Quadratic)?;

    cs.polynomial_at(0f64).print();
    cs_akima.polynomial_at(0f64).print();
    cs_quad.polynomial_at(0f64).print();
    // -0.1523x^3 + 0.9937x
    // 0.1259x^3 - 0.5127x^2 + 1.2283x
    // -0.0000x^3 - 0.3868x^2 + 1.2283x

    let new_x = seq(4, 6, 0.1);
    let new_y = new_x.fmap(|t| t.sin());

    let y_cs = cs.eval_vec(&new_x);
    let y_akima = cs_akima.eval_vec(&new_x);
    let y_quad = cs_quad.eval_vec(&new_x);

    let mut df = DataFrame::new(vec![]);
    df.push("x", Series::new(new_x));
    df.push("y", Series::new(new_y));
    df.push("y_cs", Series::new(y_cs));
    df.push("y_akima", Series::new(y_akima));
    df.push("y_quad", Series::new(y_quad));

    df.print();
    //          x       y    y_cs y_akima  y_quad
    //  r[0]    5 -0.9589 -0.9589 -0.9589 -0.9589
    //  r[1]  5.2 -0.8835 -0.8826 -0.8583 -0.8836
    //  r[2]  5.4 -0.7728 -0.7706 -0.7360 -0.7629
    //  r[3]  5.6 -0.6313 -0.6288 -0.5960 -0.6120
    //  r[4]  5.8 -0.4646 -0.4631 -0.4424 -0.4459
    //  r[5]    6 -0.2794 -0.2794 -0.2794 -0.2794

    Ok(())
}

§Usage (B-Spline)

use peroxide::fuga::*;

fn main() -> Result<(), Box<dyn Error>> {
    let knots = vec![0f64, 1f64, 2f64, 3f64];
    let degree = 3;
    let control_points = vec![
        vec![0f64, 2f64],
        vec![0.2, -1f64],
        vec![0.4, 1f64],
        vec![0.6, -1f64],
        vec![0.8, 1f64],
        vec![1f64, 2f64],
    ];

  
    let spline = BSpline::clamped(degree, knots, control_points.clone())?;
    let t = linspace(0f64, 3f64, 200);
    let (x, y): (Vec<f64>, Vec<f64>) = spline.eval_vec(&t).into_iter().unzip();

        let control_x = control_points.iter().map(|v| v[0]).collect::<Vec<f64>>();
        let control_y = control_points.iter().map(|v| v[1]).collect::<Vec<f64>>();

        let mut plt = Plot2D::new();
        plt
            .insert_pair((x.clone(), y.clone()))
            .insert_pair((control_x.clone(), control_y.clone()))
            .set_plot_type(vec![(1, PlotType::Scatter)])
            .set_color(vec![(0, "darkblue"), (1, "red")])
            .set_xlabel(r"$x$")
            .set_ylabel(r"$y$")
            .set_style(PlotStyle::Nature)
            .set_dpi(600)
            .set_path("example_data/b_spline_test.png")
            .savefig()?;

    let mut df = DataFrame::new(vec![]);
    df.push("t", Series::new(t));
    df.push("x", Series::new(x));
    df.push("y", Series::new(y));
    df.print();

    Ok(())
}
  • Result for above code is: b_spline_test

§High-level interface

§Functions

  • fn cubic_spline(node_x: &[f64], node_y: &[f64]) -> CubicSpline : Create a cubic spline from nodes
  • fn cubic_hermite_spline(node_x: &[f64], node_y: &[f64], m: &[f64]) -> CubicHermiteSpline : Create a cubic Hermite spline from nodes with slopes

§Usage

use peroxide::fuga::*;

fn main() -> Result<(), Box<dyn Error>> {
    let x = seq(0, 10, 1);
    let y = x.fmap(|t| t.sin());
     
    let cs = cubic_spline(&x, &y)?;
    let cs_akima = cubic_hermite_spline(&x, &y, Akima)?;
    let cs_quad = cubic_hermite_spline(&x, &y, Quadratic)?;

    cs.polynomial_at(0f64).print();
    cs_akima.polynomial_at(0f64).print();
    cs_quad.polynomial_at(0f64).print();
    // -0.1523x^3 + 0.9937x
    // 0.1259x^3 - 0.5127x^2 + 1.2283x
    // -0.0000x^3 - 0.3868x^2 + 1.2283x

    let new_x = seq(4, 6, 0.1);
    let new_y = new_x.fmap(|t| t.sin());

    let y_cs = cs.eval_vec(&new_x);
    let y_akima = cs_akima.eval_vec(&new_x);
    let y_quad = cs_quad.eval_vec(&new_x);

    let mut df = DataFrame::new(vec![]);
    df.push("x", Series::new(new_x));
    df.push("y", Series::new(new_y));
    df.push("y_cs", Series::new(y_cs));
    df.push("y_akima", Series::new(y_akima));
    df.push("y_quad", Series::new(y_quad));

    df.print();
    //          x       y    y_cs y_akima  y_quad
    //  r[0]    5 -0.9589 -0.9589 -0.9589 -0.9589
    //  r[1]  5.2 -0.8835 -0.8826 -0.8583 -0.8836
    //  r[2]  5.4 -0.7728 -0.7706 -0.7360 -0.7629
    //  r[3]  5.6 -0.6313 -0.6288 -0.5960 -0.6120
    //  r[4]  5.8 -0.4646 -0.4631 -0.4424 -0.4459
    //  r[5]    6 -0.2794 -0.2794 -0.2794 -0.2794

    Ok(())
}

§Calculus with polynomial splines

§Usage

use peroxide::fuga::*;
use std::f64::consts::PI;

fn main() -> Result<(), Box<dyn Error>> {
    let x = seq(0, 10, 1);
    let y = x.fmap(|t| t.sin());
     
    let cs = cubic_spline(&x, &y)?;
    let cs_akima = cubic_hermite_spline(&x, &y, Akima)?;
    let cs_quad = cubic_hermite_spline(&x, &y, Quadratic)?;

    println!("============ Polynomial at x=0 ============");

    cs.polynomial_at(0f64).print();
    cs_akima.polynomial_at(0f64).print();
    cs_quad.polynomial_at(0f64).print();

    println!("============ Derivative at x=0 ============");

    cs.derivative().polynomial_at(0f64).print();
    cs_akima.derivative().polynomial_at(0f64).print();
    cs_quad.derivative().polynomial_at(0f64).print();

    println!("============ Integral at x=0 ============");

    cs.integral().polynomial_at(0f64).print();
    cs_akima.integral().polynomial_at(0f64).print();
    cs_quad.integral().polynomial_at(0f64).print();

    println!("============ Integrate from x=0 to x=pi ============");

    cs.integrate((0f64, PI)).print();
    cs_akima.integrate((0f64, PI)).print();
    cs_quad.integrate((0f64, PI)).print();

    // ============ Polynomial at x=0 ============
    // -0.1523x^3 + 0.9937x
    // 0.1259x^3 - 0.5127x^2 + 1.2283x
    // -0.0000x^3 - 0.3868x^2 + 1.2283x
    // ============ Derivative at x=0 ============
    // -0.4568x^2 + 0.9937
    // 0.3776x^2 - 1.0254x + 1.2283
    // -0.0000x^2 - 0.7736x + 1.2283
    // ============ Integral at x=0 ============
    // -0.0381x^4 + 0.4969x^2
    // 0.0315x^4 - 0.1709x^3 + 0.6141x^2
    // -0.0000x^4 - 0.1289x^3 + 0.6141x^2
    // ============ Integrate from x=0 to x=pi ============
    // 1.9961861265456702
    // 2.0049920614062775
    // 2.004327391790717

    Ok(())
}

§B-Spline utils

  • UnitCubicBasis: Single cubic B-Spline basis function
  • CubicBSplineBases: Uniform Cubic B-Spline basis functions

§References

  • Gary D. Knott, Interpolating Splines, Birkhäuser Boston, MA, (2000).

Structs§

Enums§

Traits§

Functions§