scijit.interpolate.Akima1DInterpolator

scijit.interpolate.Akima1DInterpolator(x, y, axis=0, method='akima', extrapolate=None)

Akima piecewise-cubic interpolator.

Akima’s local slope rule damps the overshoot a C2 cubic spline shows on step-like data, at the price of only C1 continuity.

Parameters:
x1-D float64 ndarray, length n >= 2

Breakpoints, strictly increasing. A non-increasing pair raises ValueError.

yfloat64 ndarray of rank 1, 2 or 3

Values, real. Its length along axis must be n. Rank 4 and above raise ValueError.

axisint, optional

Which axis of y the interpolation runs along, default 0. Negative values count from the end. Ignored for a 1-D y. ev(xs) returns the shape of y with this axis replaced by len(xs); a scalar query returns it with this axis removed.

methodstr, optional

The slope rule: 'akima' (the default) for Akima’s weights, 'makima' for the modified weights of Moler and Ionita, which remove the overshoot Akima’s rule leaves on step-like data and the 0/0 edge case. A runtime string works as well as a literal. Anything else raises NotImplementedError.

extrapolateNone, bool or str, optional

What a query outside [x[0], x[-1]] gives.

True the end polynomial, extended False NaN, and a NaN input also gives NaN ‘periodic’ the query folded into [x[0], x[-1]] first None the default, which is False

That default is the OPPOSITE of BSpline and CubicSpline, where extrapolation is on. A string other than 'periodic' raises ValueError. 0 and 1 are accepted for False and True. May be a runtime value, not only a literal.

Attributes:
x1-D float64 ndarray

The breakpoints.

c(4, n-1) float64 ndarray

PPoly coefficients: c[k, i] multiplies (x - x[i]) ** (3 - k) on [x[i], x[i+1]].

nint

Number of breakpoints.

extrapolatebool

Whether a query outside the data range is evaluated at all.

periodicbool

Whether the query is folded into the data range first.

Methods

ev(xs), ev_one(x), __getitem__(xs), derivative_ev(xs, nu),

get_knots(), get_coeffs()

Returns:
_Akima1DInterpolator

A callable jitclass instance: ak(xs) runs ev and ak(x) runs ev_one. A rank-2 or rank-3 y gives _Akima1DInterpolatorND1 or _Akima1DInterpolatorND2, which carry the same methods.

See also

scipy.interpolate.Akima1DInterpolator

The scipy routine this mirrors.

Notes

Deviations from scipy. There is no .derivative() or .antiderivative() object API, no .roots() and no integrate. A complex y raises ValueError naming np.real, which is scipy’s own refusal, from Python and from inside @njit. A rank-2 x raises TypingError where scipy raises ValueError('`x` must be 1-dimensional.'); both refuse and only the class differs. The resolved mode is split across the extrapolate and periodic attributes, where scipy keeps the caller’s value in one; an unrecognised string raises where scipy extrapolates. Evaluation is ev(xs) and derivative_ev(xs, nu), where scipy spells both as ak(xs, nu); a two-argument call raises on arity here. scipy takes method as a keyword-only string; here it is a positional-or-keyword argument, and it takes the same two strings. The n == 2 case falls back to the single linear slope.

Akima1DInterpolator is an @njit factory over the jitclass _Akima1DInterpolator, so extrapolate and method may be omitted from Python AND from inside @njit.

Measured against scipy 1.18 on 5 nodes spanning [0, 1.4], queried at 2.0 and -1.0: extrapolate=None gives NaN on both sides, extrapolate=True 2.90115132 and -2.3627451, extrapolate='periodic' 0.74828791 and 0.91284842.

Accuracy vs scipy.interpolate.Akima1DInterpolator, both methods, over 211 points on each of five fixtures (15 random nodes, the step data from scipy’s own docstring, a 21-point sine, all-zero y, and n = 3): PPoly coefficients EXACTLY 0.0, values 2.2e-15, first derivative 1.1e-14. The coefficients agree bit for bit; the residual is in the Horner evaluation. With extrapolate=True evaluated two units past each end, 7.1e-15. With extrapolate=False the outside points are NaN, in the same positions as scipy’s.

prange-safe: yes.

Examples

>>> import numpy as np
>>> from numba import njit
>>> from scijit.interpolate import Akima1DInterpolator
>>> x = np.linspace(0.0, 10.0, 11)
>>> y = np.array([0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1.])
>>> ak = Akima1DInterpolator(x, y)
>>> np.round(ak(np.array([2.5, 3.5])), 6)
array([0.5, 1. ])

Inside compiled code, the mean of the interpolant over its domain:

>>> @njit
... def mean(ak):
...     xs = np.linspace(0.0, 10.0, 201)
...     return np.mean(ak(xs))
>>> float(np.round(mean(ak), 6))
0.748756