Skip to content

Repository files navigation

spline1d

A pure Rust library for fast 1D cubic interpolation primitives, plus single-interval quadratic primitives derived from the same endpoint logic.

The crate provides both allocation-free single-interval functions and allocation-backed spline containers.

Methods

Implemented local cubic interpolation methods:

  • Akima
  • Makima
  • PCHIP
  • Steffen
  • Catmull-Rom
  • Cardinal
  • Fritsch-Butland

Single-interval coefficient forms

Cubic single-interval APIs provide either direct local coefficients [a, b, c, d] or normalized endpoint coefficients [alpha0, alpha1]:

y(t) = y1 * (1 - t) + y2 * t + (1 - t) * t * (alpha0 + alpha1 * t)

Quadratic single-interval APIs provide direct local coefficients [a, b, c] or one normalized coefficient alpha:

y(t) = y1 * (1 - t) + y2 * t + alpha * (1 - t) * t

For a middle interval [x1, x2], its quadratic alpha is deliberately the arithmetic mean of the endpoint-derived estimates from the two adjacent three-point windows:

alpha_middle = (alpha_from_left + alpha_from_right) / 2

It is not a polynomial fit through all four points. Quadratic endpoint alphas are derived directly from the corresponding existing cubic endpoint alphas.

Public single-interval API

The generic API accepts an InterpolationType<T>:

cubic_single_left / cubic_single_middle / cubic_single_right
cubic_single_left_alpha / cubic_single_middle_alpha / cubic_single_right_alpha

quadratic_single_left / quadratic_single_middle / quadratic_single_right
quadratic_single_left_alpha / quadratic_single_middle_alpha / quadratic_single_right_alpha

InterpolationType selects Akima, Makima, PCHIP, Steffen, Catmull-Rom, Cardinal, or Fritsch-Butland. Method-specific APIs are public for every method; for example, PCHIP provides pchip_single_middle_quadratic and pchip_single_middle_quadratic_alpha. Cardinal quadratic functions accept the same final tension argument as the existing Cardinal cubic functions.

alpha_to_quadratic_coeffs converts normalized quadratic alpha to local [a, b, c]; quadratic_coeffs_to_alpha performs the reverse conversion when the interval width is known.

use spline1d::{quadratic_single_middle, InterpolationType};

let coeffs = quadratic_single_middle(
    InterpolationType::PCHIP,
    0.0, 0.0,
    0.7, 1.0,
    2.1, 1.5,
    4.8, 3.0,
);
let x = 1.2;
let dx = x - 0.7;
let y = (coeffs[0] * dx + coeffs[1]) * dx + coeffs[2];
assert!(y.is_finite());

Feature flags

[features]
default = ["std"]
std = ["alloc", "dep:csv"]
alloc = []
  • std is enabled by default. It enables the full API, including CSV helpers and multi-spline/search-tree helpers.
  • alloc enables heap-backed spline containers such as Spline<T> without requiring std.
  • --no-default-features builds the allocation-free no_std API. In this mode, single-interval functions and alpha conversions remain available, but Spline<T>, MultiSpline, and CSV loading are not compiled.

no_std usage

For allocation-free single-interval interpolation:

spline1d = { version = "0.1", default-features = false }

Example:

use spline1d::pchip_single_middle;

let coeffs = pchip_single_middle(
    0.0, 0.0,
    1.0, 1.0,
    2.0, 1.5,
    3.0, 2.0,
);

For heap-backed Spline<T> without std:

spline1d = { version = "0.1", default-features = false, features = ["alloc"] }

For the default desktop/server API:

spline1d = "0.1.1"

Basic usage

use spline1d::makima;

fn main() {
    let x = vec![0.0, 1.0, 2.0, 3.0];
    let y = vec![0.0, 2.0, 1.0, 3.0];

    let spline = makima(&x, &y);
    let value = spline.interpolate(&1.5);

    println!("Interpolated value: {:?}", value);
}

Current limitations

  • x values should be monotonic.
  • NaN and infinity are not supported in interval lookup.
  • The std feature is required for CSV loading and the current MultiSpline / SearchTree helpers.

Inverse lookup and multi-value interpolation

spline1d supports inverse lookup through SearchTree and SearchNode.

This is useful when the independent and dependent variables need to be swapped, for example when finding all values of x corresponding to a target value of y.

Unlike a simple binary search, inverse lookup cannot assume that the spline is globally monotone. A single value of y may correspond to several different x values. SearchTree handles this by splitting the spline into monotone regions and searching only the regions whose value ranges contain the requested target.

Conceptually, this allows queries such as:

x -> y

and also:

y -> all matching x values

The tree is built from a MultiSpline:

use spline1d::*;

let tree = SearchTree::new(&multispline);

Then interpolation can be performed between any registered variables:

let values = tree.interpolate(&key_x, &key_y, &value);

Depending on the selected keys, this can perform:

  • ordinary interpolation from the principal coordinate to a dependent variable;
  • inverse interpolation from a dependent variable back to the principal coordinate;
  • cross-variable interpolation through the principal coordinate;
  • identity lookup when both keys refer to the principal coordinate.

For non-monotone data, the returned Vec<T> may contain multiple values. This means spline1d can find all valid solutions instead of returning only the first match or requiring the user to scan intervals manually.

Internally, each SearchNode stores an interval of spline indices and value ranges for every variable. During lookup, branches whose min/max range cannot contain the target value are skipped. Candidate monotone regions are then searched and evaluated locally.

License

Licensed under either of

at your option.

About

1D cubic splines (makima, best for engineering purposes) in Rust

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages