scijit.interpolate.BSpline¶
- scijit.interpolate.BSpline(t, c, k, extrapolate=True, axis=0)¶
Univariate spline in the B-spline basis.
S(x) = sum_j c[j] * B_{j,k;t}(x), evaluated with the de Boor recursion. This accepts an ARBITRARY knot vector, so hand-built or textbook knots work as well as a FITPACKtck.- Parameters:
- t1-D float64 ndarray
Knot vector, non-decreasing and finite. Must hold at least
2*k+2knots and at least two distinct values int[k:n+1]; otherwiseValueError. A decreasing pair, a NaN or an inf also raises.- c1-D float64 ndarray
B-spline coefficients. Only the first
n = len(t) - k - 1entries are used and stored, so a FITPACKtck(whose c is padded tolen(t)) can be passed straight in.len(c) < nraisesValueError. 1-D real only.- kint
Spline degree, >= 0. Negative raises
ValueError.- extrapolatebool, str or None, optional
What a query outside the base interval
[t[k], t[n]]gives.True the first/last polynomial piece, extended False NaN ‘periodic’ the query folded into
[t[k], t[n]]first None NaNDefault True. A string other than
'periodic'raisesValueError. 0 and 1 are accepted for False and True. May be a runtime value, not only a literal.- axisint, optional
Which axis of c the interpolation runs along, default 0. Negative values count from the end. Ignored for a 1-D c.
ev(xs)returns the shape of c with this axis replaced bylen(xs); a scalar query returns it with this axis removed.
- Attributes:
- t1-D float64 ndarray
The knot vector (a copy).
- c1-D float64 ndarray, length n
The coefficients actually used (a copy, trailing entries dropped).
- k, nint
Degree and number of coefficients,
n = len(t) - k - 1.- extrapolatebool
Whether a query outside the base interval is evaluated at all.
- periodicbool
Whether the query is folded into the base interval first.
Methods
ev(xs), ev_one(x), __getitem__(xs), derivative_ev(xs, nu),
antiderivative_ev(xs, nu), integral(a, b), get_knots(), get_coeffs()
- Returns:
- _BSpline
A callable jitclass instance:
spl(xs)runs ev andspl(x)runs ev_one. A rank-2 or rank-3 c gives _BSplineND1 or _BSplineND2, which carry the same methods.
See also
scipy.interpolate.BSplineThe scipy routine this mirrors.
Notes
Deviations from scipy: no
.derivative()/.antiderivative()returning new objects (use the_evmethods, orsplder/splantiderfor the tck); no.roots(),.design_matrix,.basis_elementor.from_power_basis. 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. An axis naming an axis of c that does not exist raisesnumpy.exceptions.AxisError. c is float64, where scipy derives the coefficient dtype from c and supportscomplex128. Evaluation isev(xs)andderivative_ev(xs, nu), where scipy spells both asspl(xs, nu); a two-argument call raises on arity here.BSplineis an@njitfactory over the jitclass_BSpline, soextrapolatemay be omitted from Python AND from inside@njit. Method defaults such asderivative_ev’snu=1work in both too.Measured against scipy 1.18 on a k=3 spline over
[0, 1]queried at 1.3 and -0.2:extrapolate=Truegives -10.21 and -1.672,extrapolate=Falseandextrapolate=NoneNaN,extrapolate='periodic'1.018 and 1.74.integrate(-1, 2)under'periodic'gives 3.5625, three times the 1.1875 of one period.Accuracy vs
scipy.interpolate.BSplineon random knots and coefficients, 137 points across the base interval, for every degree k = 0..5: values, first derivative, first antiderivative andintegrate(t[k], t[n])all EXACTLY 0.0. Withextrapolate=Falsethe NaN pattern matches scipy’s element for element and the finite values agree exactly.prange-safe: yes – pure de Boor, no shared state, no library call.
Examples
>>> import numpy as np >>> from numba import njit >>> from scijit.interpolate import BSpline >>> t = np.array([0., 0., 0., 0., 1., 2., 3., 3., 3., 3.]) >>> c = np.array([0., 1., -1., 2., 0., 1.]) >>> spl = BSpline(t, c, 3) # build once from knots and coefficients >>> np.round(spl(np.array([0.5, 1.5, 2.5])), 6) array([0.375, 0.5 , 0.625])
Inside compiled code, scanning the domain for the curve’s peak:
>>> @njit ... def peak(spl): ... xs = np.linspace(0.0, 3.0, 301) ... return np.max(spl(xs)) >>> float(np.round(peak(spl), 6)) 1.0