scijit.interpolate.CubicSpline¶
- scijit.interpolate.CubicSpline(x, y, axis=0, bc_type='not-a-knot', extrapolate=None)¶
C2 cubic spline interpolator over piecewise-cubic segments.
The interpolant is twice continuously differentiable, and the boundary condition fixes the two remaining degrees of freedom.
- 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 at the breakpoints. Its length along axis must be n. Every position on the other axes is an independent series over the same x. 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, which has only one axis.
ev(xs)returns the shape of y with this axis replaced bylen(xs);ev_oneand integral return the shape of y with this axis removed.- bc_typestr or 2-element sequence, optional
Boundary condition. A single string applies the same condition at BOTH ends:
'not-a-knot' the default 'natural' second derivative zero at the ends 'clamped' first derivative zero at the ends 'periodic' the spline repeats with period ``x[-1] - x[0]``; requires ``y[0] == y[-1]``, and evaluation folds the query into that period rather than extrapolatingOtherwise a 2-element sequence giving the ends separately. Each element is independently one of the first three strings above or an
(order, value)pair fixingS^(order)to value at that end, with order 1 or 2. So((1, 0.0), (1, 0.0))is'clamped',((2, 1.5), (1, -2.0))is a curvature at the left and a slope at the right, and('not-a-knot', (1, 3.0))mixes the two forms.'periodic'names a condition on the pair rather than on one end and is legal only as the single string; in the 2-element form it raisesValueError.An unrecognised string raises
ValueError; a shape that is neither is refused while compiling. A string may be a runtime value, not only a literal. The default applies inside@njitas well as from Python.- extrapolateNone, bool or str, optional
What a query outside
[x[0], x[-1]]gives:True the end segment polynomial, continued False NaN 'periodic' the query folded into ``[x[0], x[-1]]`` first None the default: ``'periodic'`` when ``bc_type='periodic'``, otherwise TrueA string other than
'periodic'raisesValueError. 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, as float64.
- c(4, n-1) float64 ndarray, or (4, n-1, T) for an N-D y
PPoly coefficients:
c[k, i]multiplies(x - x[i]) ** (3 - k)on segment[x[i], x[i+1]]. For an N-D y the trailing axes are flattened into one; get_coeffs unflattens them.- nint
Number of breakpoints.
- bc_typeint
Which condition built the spline: 0 not-a-knot, 1 natural, 2 clamped, 3 periodic, 4 any other derivative pair.
- extrapolateint
The resolved extrapolation mode: 0 NaN outside the data, 1 the end segment continued, 2 the query folded into the base period.
Methods
ev(xs), ev_one(x), __getitem__(xs), derivative_ev(xs, nu),
integral(a, b), get_knots(), get_coeffs()
- Returns:
- _CubicSpline
A callable jitclass instance:
cs(xs)runs ev andcs(x)runs ev_one. A rank-2 or rank-3 y gives _CubicSplineND1 or _CubicSplineND2, which carry the same methods.
See also
scipy.interpolate.CubicSplineThe scipy routine this mirrors.
Notes
Deviations from scipy. extrapolate reads back as the resolved int code rather than the caller’s value, and an unrecognised string raises where scipy extrapolates. A derivative value is one scalar per end and applies to every series of an N-D y, where scipy takes an array of the trailing shape. y is capped at rank 3 and is float64, where scipy takes any rank and promotes a complex y to
complex128; a jitclass field has a fixed rank and a fixed dtype, so each supported rank is a separate class. A rank-2 x raisesTypingErrorwhere scipy raisesValueError('`x` must be 1-dimensional.'); both refuse and only the class differs. Evaluation isev(xs)andderivative_ev(xs, nu), where scipy spells both ascs(xs, nu); a two-argument call raises on arity here. There is no.derivative()or.antiderivative()returning a new object, and nosolve,roots,extend,construct_fast,from_splineorfrom_bernstein_basis.CubicSplineis an@njitfactory over the jitclass_CubicSpline, sobc_typeand extrapolate may be omitted from Python AND from inside@njit, and the strings resolve there, before the jitclass is constructed. Method defaults such asderivative_ev’snu=1work in both too.Measured against scipy 1.18 on 5 nodes spanning
[0, 1.4], queried at 2.0 and -1.0:extrapolate=Nonegives 13.1204501 and -13.35208741 on both sides,extrapolate=FalseNaN on both,extrapolate='periodic'0.80812133 and 0.96731898, andbc_type='periodic'withextrapolate=None0.83153846 and 1.00846154.Accuracy vs
scipy.interpolate.CubicSplineon 15 random nodes over 211 in-range points, for each of the three bc types: values 4.6e-15 to 5.4e-15, first derivative 7.1e-15 to 1.4e-14, second derivative 2.8e-13 to 4.0e-13,integrate(x[0], x[-1])8.9e-16 to 2.2e-15, and PPoly coefficients 2.0e-13 (natural) to 4.7e-11 (not-a-knot) in absolute terms on coefficients whose magnitude reaches 5.0e3, i.e. about 1e-14 relative. On 9 nodes at five points, values, coefficients, first derivative andintegraltogether: the per-end(order, value)pairs 2.220e-16, and'periodic'0.000e+00 at n=9 with 2.132e-13 on the coefficients at n=12.Extrapolating 50 units past each end: 2.3e-10 absolute, 8.9e-16 relative. The n=2 not-a-knot case is exactly 0.0 and the n=3 parabola special case 4.4e-16.
prange-safe: yes – pure numpy, no module state, no callback. Both construction and evaluation may run inside a
prangebody.Examples
>>> import numpy as np >>> from numba import njit >>> from scijit.interpolate import CubicSpline >>> x = np.linspace(0.0, 1.0, 9) >>> y = np.sin(3.0 * x) >>> cs = CubicSpline(x, y) # 'not-a-knot', extrapolating >>> np.round(cs(np.array([0.25, 0.75])), 6) array([0.681639, 0.778073])
Inside compiled code, the mean of the curve over its domain:
>>> @njit ... def mean(cs): ... xs = np.linspace(0.0, 1.0, 201) ... return np.mean(cs(xs)) >>> float(np.round(mean(cs), 6)) 0.660382