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.
Implemented local cubic interpolation methods:
- Akima
- Makima
- PCHIP
- Steffen
- Catmull-Rom
- Cardinal
- Fritsch-Butland
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.
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());[features]
default = ["std"]
std = ["alloc", "dep:csv"]
alloc = []stdis enabled by default. It enables the full API, including CSV helpers and multi-spline/search-tree helpers.allocenables heap-backed spline containers such asSpline<T>without requiringstd.--no-default-featuresbuilds the allocation-freeno_stdAPI. In this mode, single-interval functions and alpha conversions remain available, butSpline<T>,MultiSpline, and CSV loading are not compiled.
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"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);
}xvalues should be monotonic.- NaN and infinity are not supported in interval lookup.
- The
stdfeature is required for CSV loading and the currentMultiSpline/SearchTreehelpers.
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.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE)
- MIT license (LICENSE-MIT)
at your option.