Skip to main content

Fast, Numba-compatible Akima/makima spline interpolation for regular and irregular grids

Project description

pyakima

PyPI DOI License
Test Coverage Typed Documentation Status

pyakima is a fast, JIT-compatible Akima spline implementation written in pure Python.

Akima splines are a type of cubic spline that can guarantee continuous differentiability and local behavior while minimizing overshoot on both regular and irregular interpolation grids.

pyakima ships a small object-oriented Python API for ordinary use and Numba-friendly helper functions for building and evaluating splines inside fully jitted code.

The implementation is fully typed (py.typed) and keeps the public surface small: AkimaSpline is an object-oriented interface which simplifies calls for non-jitted Python callers; it has only a constructor and a __call__ method. For jitted workloads,

  1. The spline interpolation itself is represented as a set of coefficients stored in a SplineCoeffs object, computed once via make_akima_coeffs.
  2. The spline is called from cubic_call, which selects the appropriate coefficients and evaluates the polynomial with spline_single_knot_eval.
Two-panel animation. Top: as one control point slides up and down, the pyakima makima curve hugs the data while a natural cubic spline rings above and below the spike. Bottom: a zoom on a sharp kink where the non-rounded, akima, and makima corner models round the corner by differing amounts.

The top panel slides one control point up and down: the pyakima makima fit stays local and flat on either side of the spike, while a natural cubic spline rings above and below it. The bottom panel zooms into a sharp kink to show the three corner models pyakima exports:

  1. non-rounded: Algorithm based on [1], comparable numerical behavior to GSL; note the unstable behavior is because the algorithm is non-differentiable at corners, not a peculiar limitation of this implementation [2].
  2. akima (SciPy parity) [3]. Discontinuous behavior is less severe than non-rounded; slightly more prone to overshoot, and still has special edge-case handling.
  3. makima Modified Akima Algorithm [4]; recommended default Less overshoot than akima, while mathematically guaranteed to preserve differentiability/continuous behavior at corners without special edge-case handling. Similar performance to akima in most cases.
Single panel animation. As the control points slide between a regular and irregular grid, the pyakima makima curve smoothly hugs the data, while the scipy default cubic spline oscillates so strongly it extends off the plotted y axis.

The control points oscillate smoothly between regular uniform-grid spacing and an inverse-CDF-based spacing. Such a spacing is similar to what might be used when using Akima splines for a PSD estimation task, or in approximating a function with sharp features with as few control points as possible. Such uses with irregular grids are a key modern application of Akima splines, and are of central importance to their utility in gravitational-wave detection applications, such as using trans-dimensional MCMC to adaptively fit Akima splines to un-modeled gravitational-wave sources [5], [6], [7]. Cubic splines, such as scipy's default CubicSpline plotted above, oscillate wildly on the same irregularly-spaced grid, which typically makes them unsuitable for such analysis tasks.

Table of Contents

Installation

pip install pyakima

pyakima requires Python 3.10 or newer, NumPy, and Numba. The optional demo dependencies are available with:

pip install "pyakima[demos]"

Note that pygsl_lite from the demos dependencies may not always succeed on a pip install; any demo that uses it recovers gracefully if it cannot be imported. pyakima.demos.speed_demo can recover if none of the demos dependencies are present. pyakima.demos.step_demo runs if only matplotlib is present.

Quick Start

import numpy as np

from pyakima import AkimaSpline

x = np.linspace(0.0, 10.0, 16)
y = np.sin(x)

spline = AkimaSpline(x, y, corner_model="makima", ext=3)

print(spline(2.5))
print(spline(np.linspace(-1.0, 11.0, 1000)))

AkimaSpline is the ergonomic Python interface. The class stores a compiled coefficient bundle and dispatches scalar or vector evaluations to the fast helper functions.

Jitted Use

Use make_akima_coeffs and cubic_call when the spline should be created or evaluated from inside an njit function.

import numpy as np
from numba import njit

from pyakima import make_akima_coeffs, cubic_call


@njit
def build_and_evaluate(x: np.ndarray, y: np.ndarray, x_eval: np.ndarray) -> np.ndarray:
    coeffs = make_akima_coeffs(x, y, corner_model=2)
    return cubic_call(x_eval, coeffs, 0)

For lower-level control, call cubic_call_scalar, cubic_call_vector, or cubic_call_vector_linear directly.

Spline Options

pyakima supports several Akima corner models:

AkimaSpline option helper option Behavior
"non-rounded" 0 Wodicka/GSL-style non-rounded sharp corners.
"akima" 1 Classic Akima behavior, close to scipy method="akima".
"makima" 2 Modified Akima weights, close to scipy method="makima".

Boundary handling uses SciPy-like ext values:

ext Out-of-bounds behavior
0 Extrapolate.
1 Return zero.
3 Return the nearest boundary value.
4 Return nan.

ext=2 (raise on out-of-bounds) is not implemented. ext=4 is added for NaN boundary handling. AkimaSpline defaults to ext=3.

Regenerating the Demo

pyakima.demos ships as an example subpackage; run it from a source checkout so it can write the README assets:

pip install -e '.[demos]'                  # scipy, matplotlib, pygsl_lite
python -m pyakima.demos.animate_demo       # writes assets/akima_demo_{light,dark}.gif
python -m pyakima.demos.animate_grid_demo  # writes assets/akima_grid_{light,dark}.gif
python -m pyakima.demos.step_demo          # writes assets/akima_step_{light,dark}.png

Performance Snapshot

Run python -m pyakima.demos.speed_demo to compare pyakima with the optional SciPy and pygsl_lite backends available in your environment.

The current 0.1.0 snapshot was measured on a single Apple Silicon M3 core with Python 3.14.6, Numba 0.66.0, NumPy 2.4.6, SciPy 1.17.1, and pygsl_lite 0.1.8. The demo used 50 repeats, with each repeat adaptively looped to at least 0.100 s, and a representative range of spline and caller sizes. The full benchmark is available in docs/benchmarks/m3_0_1_0_speeds.txt.

Highlights from that run:

  • pyakima was minimum 1.7x faster than SciPy Akima1DInterpolator across all benchmarks.
  • Spline creation was about 5.7-32.6x faster than SciPy.
  • With Python-call overhead, scalar evaluation was about 2.3x faster than SciPy but 0.3-0.4x slower than pygsl_lite. When called fully jitted (no Python-call overhead), scalar evaluation was about 109-361x faster than SciPy and 18-52x faster than pygsl_lite.
  • Python-call vector evaluation was faster than SciPy in every tested case (about 1.7-4.8x in the SciPy-style rows).
  • Against pygsl_lite, Python-call vector evaluation was faster once the call did enough work (for example, 1,000 or more evaluation points in the sampled cases), while scalar and tiny-vector cases can be dominated by dispatch overhead.
  • Fully jitted vector evaluation was faster than SciPy in every tested case (about 1.7-29.0x). It was also faster than pygsl_lite for most non-tiny vector workloads in the sample (about 2.3-11.2x for 1,000 or more evaluation points).

Benchmark results depend on hardware, Python/NumPy/Numba versions, and whether the call is made through Python or entirely inside jitted code.

Quality Gates

The CI suite checks the package with:

  • pytest unit test suite; pull requests to dev only test modern versions, while pull requests targeting main run for all supported versions.
  • coverage.py branch coverage; pull requests targeting main are gated at 100% total coverage, while other targets use the development threshold in the coverage workflow.
  • strict mypy, plus Pyrefly and Pyright type checking.
  • Ruff with select = ["ALL"] and ruff format, run through prek pre-commit hooks.
  • Skylos dead-code detection.
  • Pylint and pydoclint docstring/signature checks.
  • source distribution and wheel builds, including install/import checks across the supported dependency range.

Useful local checks:

python -m pytest
NUMBA_DISABLE_JIT=1 python -m coverage run --branch --source=pyakima --omit='*/demos/*' -m pytest
python -m coverage report -m --fail-under=100
uvx prek run --all-files --show-diff-on-failure --color=always
uvx skylos pyakima tests

Contributing

Thank you for your interest in helping improve the repository! Feature requests and bug reports can be made through GitHub Issues. Bug reports should be accompanied by a minimal reproducing example and description of the desired behavior. Suggested contributions or fixes should be made through pull requests to dev. All new code must be fully type annotated, and pass the static type-checking and linting rules; to reduce churn, ensure, at minimum, prek run --all-files passes before attempting to commit. New core/utility functions should have full numpy-style docstrings (verify with pydoclint --style=numpy), and full unit test coverage, verified with:

NUMBA_DISABLE_JIT=1 python -m coverage run --branch --source=pyakima --omit='*/demos/*' -m pytest
python -m coverage report -m --fail-under=100

License

pyakima is distributed under the Apache License 2.0. See LICENSE for the full license text.

References

  1. G. Engeln-Müllges & F. Uhlig, Numerical Algorithms with C, Springer, 1996, ch. 13 "Akima and Renner Subsplines," Algorithm 13.1. ISBN 978-3-642-64682-9.
  2. Note: the internals of the GSL implementation have never been viewed by the repository author. However, calls to GSL exhibit near-identical behavior, supporting that the issue is algorithmic rather than due to implementation error.
  3. Akima, Hiroshi. "A new method of interpolation and smooth curve fitting based on local procedures." Journal of the ACM (JACM) , 17.4, 1970, pp. 589–602.
  4. C. Moler, Makima Piecewise Cubic Interpolation, Cleve's Corner (MathWorks blog), 2019.
  5. Detecting gravitational wave signals using a flexible model for the amplitude and frequency evolution. T Gupta, NJ Cornish. Physical Review D, 2024•APS arXiv:2404.11719.
  6. Model-agnostic gravitational-wave background characterization algorithm. T Knapp, PM Meyers, AI Renzini.Physical Review D, 2025•APS. arXiv:2507.08095
  7. “Precise analysis of gravitational waves from binary neutron star coalescence using Hilbert–Huang transform based on Akima spline interpolation.” Yoda, Itsuki et al. Progress of Theoretical and Experimental Physics (2023). DOI:10.1093/ptep/ptad101

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyakima-0.1.0.tar.gz (46.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyakima-0.1.0-py3-none-any.whl (32.1 kB view details)

Uploaded Python 3

File details

Details for the file pyakima-0.1.0.tar.gz.

File metadata

  • Download URL: pyakima-0.1.0.tar.gz
  • Upload date:
  • Size: 46.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for pyakima-0.1.0.tar.gz
Algorithm Hash digest
SHA256 5ce5b1b79b888f45fc1b51cd1b1bf92e0cf7880e8be6c235061f7815ec94acaa
MD5 4ea0ed34b4be9976732672b94dd92d4c
BLAKE2b-256 d0492579937f2654329fb406ac8fc57502a6313b79cea70c888ef3d97a13a1bd

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyakima-0.1.0.tar.gz:

Publisher: publish.yml on mcdigman/pyakima

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyakima-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pyakima-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 32.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for pyakima-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a455b6b46554618cac8f17e735c80e8558bf9927da41a85f000bcb53d6029e27
MD5 ca18f0d901f228881b1d949975493b10
BLAKE2b-256 2481e1ccccad57c8b1eac835bc8c65bce781ddb0336acdd81622847c0fa2589d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyakima-0.1.0-py3-none-any.whl:

Publisher: publish.yml on mcdigman/pyakima

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page