| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824 |
- """
- fitpack (dierckx in netlib) --- A Python-C wrapper to FITPACK (by P. Dierckx).
- FITPACK is a collection of FORTRAN programs for curve and surface
- fitting with splines and tensor product splines.
- See
- https://web.archive.org/web/20010524124604/http://www.cs.kuleuven.ac.be:80/cwis/research/nalag/research/topics/fitpack.html
- or
- http://www.netlib.org/dierckx/
- Copyright 2002 Pearu Peterson all rights reserved,
- Pearu Peterson <pearu@cens.ioc.ee>
- Permission to use, modify, and distribute this software is given under the
- terms of the SciPy (BSD style) license. See LICENSE.txt that came with
- this distribution for specifics.
- NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
- TODO: Make interfaces to the following fitpack functions:
- For univariate splines: cocosp, concon, fourco, insert
- For bivariate splines: profil, regrid, parsur, surev
- """
- __all__ = ['splrep', 'splprep', 'splev', 'splint', 'sproot', 'spalde',
- 'bisplrep', 'bisplev', 'insert', 'splder', 'splantider']
- import warnings
- import numpy as np
- from . import _fitpack
- from numpy import (atleast_1d, array, ones, zeros, sqrt, ravel, transpose,
- empty, iinfo, asarray)
- # Try to replace _fitpack interface with
- # f2py-generated version
- from . import _dfitpack as dfitpack
- from scipy._lib._array_api import array_namespace, concat_1d, xp_capabilities
- dfitpack_int = dfitpack.types.intvar.dtype
- def _int_overflow(x, exception, msg=None):
- """Cast the value to an dfitpack_int and raise an OverflowError if the value
- cannot fit.
- """
- if x > iinfo(dfitpack_int).max:
- if msg is None:
- msg = f'{x!r} cannot fit into an {dfitpack_int!r}'
- raise exception(msg)
- return dfitpack_int.type(x)
- _iermess = {
- 0: ["The spline has a residual sum of squares fp such that "
- "abs(fp-s)/s<=0.001", None],
- -1: ["The spline is an interpolating spline (fp=0)", None],
- -2: ["The spline is weighted least-squares polynomial of degree k.\n"
- "fp gives the upper bound fp0 for the smoothing factor s", None],
- 1: ["The required storage space exceeds the available storage space.\n"
- "Probable causes: data (x,y) size is too small or smoothing parameter"
- "\ns is too small (fp>s).", ValueError],
- 2: ["A theoretically impossible result when finding a smoothing spline\n"
- "with fp = s. Probable cause: s too small. (abs(fp-s)/s>0.001)",
- ValueError],
- 3: ["The maximal number of iterations (20) allowed for finding smoothing\n"
- "spline with fp=s has been reached. Probable cause: s too small.\n"
- "(abs(fp-s)/s>0.001)", ValueError],
- 10: ["Error on input data", ValueError],
- 'unknown': ["An error occurred", TypeError]
- }
- _iermess2 = {
- 0: ["The spline has a residual sum of squares fp such that "
- "abs(fp-s)/s<=0.001", None],
- -1: ["The spline is an interpolating spline (fp=0)", None],
- -2: ["The spline is weighted least-squares polynomial of degree kx and ky."
- "\nfp gives the upper bound fp0 for the smoothing factor s", None],
- -3: ["Warning. The coefficients of the spline have been computed as the\n"
- "minimal norm least-squares solution of a rank deficient system.",
- None],
- 1: ["The required storage space exceeds the available storage space.\n"
- "Probable causes: nxest or nyest too small or s is too small. (fp>s)",
- ValueError],
- 2: ["A theoretically impossible result when finding a smoothing spline\n"
- "with fp = s. Probable causes: s too small or badly chosen eps.\n"
- "(abs(fp-s)/s>0.001)", ValueError],
- 3: ["The maximal number of iterations (20) allowed for finding smoothing\n"
- "spline with fp=s has been reached. Probable cause: s too small.\n"
- "(abs(fp-s)/s>0.001)", ValueError],
- 4: ["No more knots can be added because the number of B-spline\n"
- "coefficients already exceeds the number of data points m.\n"
- "Probable causes: either s or m too small. (fp>s)", ValueError],
- 5: ["No more knots can be added because the additional knot would\n"
- "coincide with an old one. Probable cause: s too small or too large\n"
- "a weight to an inaccurate data point. (fp>s)", ValueError],
- 10: ["Error on input data", ValueError],
- 11: ["rwrk2 too small, i.e., there is not enough workspace for computing\n"
- "the minimal least-squares solution of a rank deficient system of\n"
- "linear equations.", ValueError],
- 'unknown': ["An error occurred", TypeError]
- }
- _parcur_cache = {'t': array([], float), 'wrk': array([], float),
- 'iwrk': array([], dfitpack_int), 'u': array([], float),
- 'ub': 0, 'ue': 1}
- def splprep(x, w=None, u=None, ub=None, ue=None, k=3, task=0, s=None, t=None,
- full_output=0, nest=None, per=0, quiet=1):
- # see the docstring of `_fitpack_py/splprep`
- if task <= 0:
- _parcur_cache = {'t': array([], float), 'wrk': array([], float),
- 'iwrk': array([], dfitpack_int), 'u': array([], float),
- 'ub': 0, 'ue': 1}
- x = atleast_1d(x)
- idim, m = x.shape
- if per:
- for i in range(idim):
- if x[i][0] != x[i][-1]:
- if not quiet:
- warnings.warn(
- RuntimeWarning(f'Setting x[{i}][{m}]=x[{i}][0]'),
- stacklevel=2
- )
- x[i][-1] = x[i][0]
- if not 0 < idim < 11:
- raise TypeError('0 < idim < 11 must hold')
- if w is None:
- w = ones(m, float)
- else:
- w = atleast_1d(w)
- ipar = (u is not None)
- if ipar:
- _parcur_cache['u'] = u
- if ub is None:
- _parcur_cache['ub'] = u[0]
- else:
- _parcur_cache['ub'] = ub
- if ue is None:
- _parcur_cache['ue'] = u[-1]
- else:
- _parcur_cache['ue'] = ue
- else:
- _parcur_cache['u'] = zeros(m, float)
- if not (1 <= k <= 5):
- raise TypeError(f'1 <= k= {k} <=5 must hold')
- if not (-1 <= task <= 1):
- raise TypeError('task must be -1, 0 or 1')
- if (not len(w) == m) or (ipar == 1 and (not len(u) == m)):
- raise TypeError('Mismatch of input dimensions')
- if s is None:
- s = m - sqrt(2*m)
- if t is None and task == -1:
- raise TypeError('Knots must be given for task=-1')
- if t is not None:
- _parcur_cache['t'] = atleast_1d(t)
- n = len(_parcur_cache['t'])
- if task == -1 and n < 2*k + 2:
- raise TypeError('There must be at least 2*k+2 knots for task=-1')
- if m <= k:
- raise TypeError('m > k must hold')
- if nest is None:
- nest = m + 2*k
- if (task >= 0 and s == 0) or (nest < 0):
- if per:
- nest = m + 2*k
- else:
- nest = m + k + 1
- nest = max(nest, 2*k + 3)
- u = _parcur_cache['u']
- ub = _parcur_cache['ub']
- ue = _parcur_cache['ue']
- t = _parcur_cache['t']
- wrk = _parcur_cache['wrk']
- iwrk = _parcur_cache['iwrk']
- t, c, o = _fitpack._parcur(ravel(transpose(x)), w, u, ub, ue, k,
- task, ipar, s, t, nest, wrk, iwrk, per)
- _parcur_cache['u'] = o['u']
- _parcur_cache['ub'] = o['ub']
- _parcur_cache['ue'] = o['ue']
- _parcur_cache['t'] = t
- _parcur_cache['wrk'] = o['wrk']
- _parcur_cache['iwrk'] = o['iwrk']
- ier = o['ier']
- fp = o['fp']
- n = len(t)
- u = o['u']
- c = c.reshape((idim, n - k - 1))
- tcku = [t, list(c), k], u
- if ier <= 0 and not quiet:
- warnings.warn(
- RuntimeWarning(
- _iermess[ier][0] + f"\tk={k} n={len(t)} m={m} fp={fp} s={s}"
- ),
- stacklevel=2
- )
- if ier > 0 and not full_output:
- if ier in [1, 2, 3]:
- warnings.warn(RuntimeWarning(_iermess[ier][0]), stacklevel=2)
- else:
- try:
- raise _iermess[ier][1](_iermess[ier][0])
- except KeyError as e:
- raise _iermess['unknown'][1](_iermess['unknown'][0]) from e
- if full_output:
- try:
- return tcku, fp, ier, _iermess[ier][0]
- except KeyError:
- return tcku, fp, ier, _iermess['unknown'][0]
- else:
- return tcku
- _curfit_cache = {'t': array([], float), 'wrk': array([], float),
- 'iwrk': array([], dfitpack_int)}
- def splrep(x, y, w=None, xb=None, xe=None, k=3, task=0, s=None, t=None,
- full_output=0, per=0, quiet=1):
- # see the docstring of `_fitpack_py/splrep`
- if task <= 0:
- _curfit_cache = {}
- x, y = map(atleast_1d, [x, y])
- m = len(x)
- if w is None:
- w = ones(m, float)
- if s is None:
- s = 0.0
- else:
- w = atleast_1d(w)
- if s is None:
- s = m - sqrt(2*m)
- if not len(w) == m:
- raise TypeError(f'len(w)={len(w)} is not equal to m={m}')
- if (m != len(y)) or (m != len(w)):
- raise TypeError('Lengths of the first three arguments (x,y,w) must '
- 'be equal')
- if not (1 <= k <= 5):
- raise TypeError(
- f'Given degree of the spline (k={k}) is not supported. (1<=k<=5)'
- )
- if m <= k:
- raise TypeError('m > k must hold')
- if xb is None:
- xb = x[0]
- if xe is None:
- xe = x[-1]
- if not (-1 <= task <= 1):
- raise TypeError('task must be -1, 0 or 1')
- if t is not None:
- task = -1
- if task == -1:
- if t is None:
- raise TypeError('Knots must be given for task=-1')
- numknots = len(t)
- _curfit_cache['t'] = empty((numknots + 2*k + 2,), float)
- _curfit_cache['t'][k+1:-k-1] = t
- nest = len(_curfit_cache['t'])
- elif task == 0:
- if per:
- nest = max(m + 2*k, 2*k + 3)
- else:
- nest = max(m + k + 1, 2*k + 3)
- t = empty((nest,), float)
- _curfit_cache['t'] = t
- if task <= 0:
- if per:
- _curfit_cache['wrk'] = empty((m*(k + 1) + nest*(8 + 5*k),), float)
- else:
- _curfit_cache['wrk'] = empty((m*(k + 1) + nest*(7 + 3*k),), float)
- _curfit_cache['iwrk'] = empty((nest,), dfitpack_int)
- try:
- t = _curfit_cache['t']
- wrk = _curfit_cache['wrk']
- iwrk = _curfit_cache['iwrk']
- except KeyError as e:
- raise TypeError("must call with task=1 only after"
- " call with task=0,-1") from e
- if not per:
- n, c, fp, ier = dfitpack.curfit(task, x, y, w, t, wrk, iwrk,
- xb, xe, k, s)
- else:
- n, c, fp, ier = dfitpack.percur(task, x, y, w, t, wrk, iwrk, k, s)
- tck = (t[:n], c[:n], k)
- if ier <= 0 and not quiet:
- _mess = (_iermess[ier][0] + f"\tk={k} n={len(t)} m={m} fp={fp} s={s}")
- warnings.warn(RuntimeWarning(_mess), stacklevel=2)
- if ier > 0 and not full_output:
- if ier in [1, 2, 3]:
- warnings.warn(RuntimeWarning(_iermess[ier][0]), stacklevel=2)
- else:
- try:
- raise _iermess[ier][1](_iermess[ier][0])
- except KeyError as e:
- raise _iermess['unknown'][1](_iermess['unknown'][0]) from e
- if full_output:
- try:
- return tck, fp, ier, _iermess[ier][0]
- except KeyError:
- return tck, fp, ier, _iermess['unknown'][0]
- else:
- return tck
- def splev(x, tck, der=0, ext=0):
- # see the docstring of `_fitpack_py/splev`
- t, c, k = tck
- try:
- c[0][0]
- parametric = True
- except Exception:
- parametric = False
- if parametric:
- return list(map(lambda c, x=x, t=t, k=k, der=der:
- splev(x, [t, c, k], der, ext), c))
- else:
- if not (0 <= der <= k):
- raise ValueError(f"0<=der={der}<=k={k} must hold")
- if ext not in (0, 1, 2, 3):
- raise ValueError(f"ext = {ext} not in (0, 1, 2, 3) ")
- x = asarray(x)
- shape = x.shape
- x = atleast_1d(x).ravel()
- if der == 0:
- y, ier = dfitpack.splev(t, c, k, x, ext)
- else:
- y, ier = dfitpack.splder(t, c, k, x, der, ext)
- if ier == 10:
- raise ValueError("Invalid input data")
- if ier == 1:
- raise ValueError("Found x value not in the domain")
- if ier:
- raise TypeError("An error occurred")
- return y.reshape(shape)
- def splint(a, b, tck, full_output=0):
- # see the docstring of `_fitpack_py/splint`
- t, c, k = tck
- try:
- c[0][0]
- parametric = True
- except Exception:
- parametric = False
- if parametric:
- return list(map(lambda c, a=a, b=b, t=t, k=k:
- splint(a, b, [t, c, k]), c))
- else:
- aint, wrk = dfitpack.splint(t, c, k, a, b)
- if full_output:
- return aint, wrk
- else:
- return aint
- def sproot(tck, mest=10):
- # see the docstring of `_fitpack_py/sproot`
- t, c, k = tck
- if k != 3:
- raise ValueError("sproot works only for cubic (k=3) splines")
- try:
- c[0][0]
- parametric = True
- except Exception:
- parametric = False
- if parametric:
- return list(map(lambda c, t=t, k=k, mest=mest:
- sproot([t, c, k], mest), c))
- else:
- if len(t) < 8:
- raise TypeError(f"The number of knots {len(t)}>=8")
- z, m, ier = dfitpack.sproot(t, c, mest)
- if ier == 10:
- raise TypeError("Invalid input data. "
- "t1<=..<=t4<t5<..<tn-3<=..<=tn must hold.")
- if ier == 0:
- return z[:m]
- if ier == 1:
- warnings.warn(RuntimeWarning("The number of zeros exceeds mest"),
- stacklevel=2)
- return z[:m]
- raise TypeError("Unknown error")
- def spalde(x, tck):
- # see the docstring of `_fitpack_py/spalde`
- t, c, k = tck
- try:
- c[0][0]
- parametric = True
- except Exception:
- parametric = False
- if parametric:
- return list(map(lambda c, x=x, t=t, k=k:
- spalde(x, [t, c, k]), c))
- else:
- x = atleast_1d(x)
- if len(x) > 1:
- return list(map(lambda x, tck=tck: spalde(x, tck), x))
- d, ier = dfitpack.spalde(t, c, k+1, x[0])
- if ier == 0:
- return d
- if ier == 10:
- raise TypeError("Invalid input data. t(k)<=x<=t(n-k+1) must hold.")
- raise TypeError("Unknown error")
- # def _curfit(x,y,w=None,xb=None,xe=None,k=3,task=0,s=None,t=None,
- # full_output=0,nest=None,per=0,quiet=1):
- _surfit_cache = {'tx': array([], float), 'ty': array([], float),
- 'wrk': array([], float), 'iwrk': array([], dfitpack_int)}
- @xp_capabilities(out_of_scope=True)
- def bisplrep(x, y, z, w=None, xb=None, xe=None, yb=None, ye=None,
- kx=3, ky=3, task=0, s=None, eps=1e-16, tx=None, ty=None,
- full_output=0, nxest=None, nyest=None, quiet=1):
- """
- Find a bivariate B-spline representation of a surface.
- Given a set of data points (x[i], y[i], z[i]) representing a surface
- z=f(x,y), compute a B-spline representation of the surface. Based on
- the routine SURFIT from FITPACK.
- Parameters
- ----------
- x, y, z : ndarray
- Rank-1 arrays of data points.
- w : ndarray, optional
- Rank-1 array of weights. By default ``w=np.ones(len(x))``.
- xb, xe : float, optional
- End points of approximation interval in `x`.
- By default ``xb = x.min(), xe=x.max()``.
- yb, ye : float, optional
- End points of approximation interval in `y`.
- By default ``yb=y.min(), ye = y.max()``.
- kx, ky : int, optional
- The degrees of the spline (1 <= kx, ky <= 5).
- Third order (kx=ky=3) is recommended.
- task : int, optional
- If task=0, find knots in x and y and coefficients for a given
- smoothing factor, s.
- If task=1, find knots and coefficients for another value of the
- smoothing factor, s. bisplrep must have been previously called
- with task=0 or task=1.
- If task=-1, find coefficients for a given set of knots tx, ty.
- s : float, optional
- A non-negative smoothing factor. If weights correspond
- to the inverse of the standard-deviation of the errors in z,
- then a good s-value should be found in the range
- ``(m-sqrt(2*m),m+sqrt(2*m))`` where m=len(x).
- eps : float, optional
- A threshold for determining the effective rank of an
- over-determined linear system of equations (0 < eps < 1).
- `eps` is not likely to need changing.
- tx, ty : ndarray, optional
- Rank-1 arrays of the knots of the spline for task=-1
- full_output : int, optional
- Non-zero to return optional outputs.
- nxest, nyest : int, optional
- Over-estimates of the total number of knots. If None then
- ``nxest = max(kx+sqrt(m/2),2*kx+3)``,
- ``nyest = max(ky+sqrt(m/2),2*ky+3)``.
- quiet : int, optional
- Non-zero to suppress printing of messages.
- Returns
- -------
- tck : array_like
- A list [tx, ty, c, kx, ky] containing the knots (tx, ty) and
- coefficients (c) of the bivariate B-spline representation of the
- surface along with the degree of the spline.
- fp : ndarray
- The weighted sum of squared residuals of the spline approximation.
- ier : int
- An integer flag about splrep success. Success is indicated if
- ier<=0. If ier in [1,2,3] an error occurred but was not raised.
- Otherwise an error is raised.
- msg : str
- A message corresponding to the integer flag, ier.
- See Also
- --------
- splprep, splrep, splint, sproot, splev
- UnivariateSpline, BivariateSpline
- Notes
- -----
- See `bisplev` to evaluate the value of the B-spline given its tck
- representation.
- If the input data is such that input dimensions have incommensurate
- units and differ by many orders of magnitude, the interpolant may have
- numerical artifacts. Consider rescaling the data before interpolation.
- References
- ----------
- .. [1] Dierckx P.:An algorithm for surface fitting with spline functions
- Ima J. Numer. Anal. 1 (1981) 267-283.
- .. [2] Dierckx P.:An algorithm for surface fitting with spline functions
- report tw50, Dept. Computer Science,K.U.Leuven, 1980.
- .. [3] Dierckx P.:Curve and surface fitting with splines, Monographs on
- Numerical Analysis, Oxford University Press, 1993.
- Examples
- --------
- Examples are given :ref:`in the tutorial <tutorial-interpolate_2d_spline>`.
- """
- x, y, z = map(ravel, [x, y, z]) # ensure 1-d arrays.
- m = len(x)
- if not (m == len(y) == len(z)):
- raise TypeError('len(x)==len(y)==len(z) must hold.')
- if w is None:
- w = ones(m, float)
- else:
- w = atleast_1d(w)
- if not len(w) == m:
- raise TypeError(f'len(w)={len(w)} is not equal to m={m}')
- if xb is None:
- xb = x.min()
- if xe is None:
- xe = x.max()
- if yb is None:
- yb = y.min()
- if ye is None:
- ye = y.max()
- if not (-1 <= task <= 1):
- raise TypeError('task must be -1, 0 or 1')
- if s is None:
- s = m - sqrt(2*m)
- if tx is None and task == -1:
- raise TypeError('Knots_x must be given for task=-1')
- if tx is not None:
- _surfit_cache['tx'] = atleast_1d(tx)
- nx = len(_surfit_cache['tx'])
- if ty is None and task == -1:
- raise TypeError('Knots_y must be given for task=-1')
- if ty is not None:
- _surfit_cache['ty'] = atleast_1d(ty)
- ny = len(_surfit_cache['ty'])
- if task == -1 and nx < 2*kx+2:
- raise TypeError('There must be at least 2*kx+2 knots_x for task=-1')
- if task == -1 and ny < 2*ky+2:
- raise TypeError('There must be at least 2*ky+2 knots_x for task=-1')
- if not ((1 <= kx <= 5) and (1 <= ky <= 5)):
- raise TypeError(
- f'Given degree of the spline (kx,ky={kx},{ky}) is not supported. (1<=k<=5)'
- )
- if m < (kx + 1)*(ky + 1):
- raise TypeError('m >= (kx+1)(ky+1) must hold')
- if nxest is None:
- nxest = int(kx + sqrt(m/2))
- if nyest is None:
- nyest = int(ky + sqrt(m/2))
- nxest, nyest = max(nxest, 2*kx + 3), max(nyest, 2*ky + 3)
- if task >= 0 and s == 0:
- nxest = int(kx + sqrt(3*m))
- nyest = int(ky + sqrt(3*m))
- if task == -1:
- _surfit_cache['tx'] = atleast_1d(tx)
- _surfit_cache['ty'] = atleast_1d(ty)
- tx, ty = _surfit_cache['tx'], _surfit_cache['ty']
- wrk = _surfit_cache['wrk']
- u = nxest - kx - 1
- v = nyest - ky - 1
- km = max(kx, ky) + 1
- ne = max(nxest, nyest)
- bx, by = kx*v + ky + 1, ky*u + kx + 1
- b1, b2 = bx, bx + v - ky
- if bx > by:
- b1, b2 = by, by + u - kx
- msg = "Too many data points to interpolate"
- lwrk1 = _int_overflow(u*v*(2 + b1 + b2) +
- 2*(u + v + km*(m + ne) + ne - kx - ky) + b2 + 1,
- OverflowError,
- msg=msg)
- lwrk2 = _int_overflow(u*v*(b2 + 1) + b2, OverflowError, msg=msg)
- tx, ty, c, o = _fitpack._surfit(x, y, z, w, xb, xe, yb, ye, kx, ky,
- task, s, eps, tx, ty, nxest, nyest,
- wrk, lwrk1, lwrk2)
- _curfit_cache['tx'] = tx
- _curfit_cache['ty'] = ty
- _curfit_cache['wrk'] = o['wrk']
- ier, fp = o['ier'], o['fp']
- tck = [tx, ty, c, kx, ky]
- ierm = min(11, max(-3, ier))
- if ierm <= 0 and not quiet:
- _mess = (
- _iermess2[ierm][0] +
- f"\tkx,ky={kx},{ky} nx,ny={len(tx)},{len(ty)} m={m} fp={fp} s={s}"
- )
- warnings.warn(RuntimeWarning(_mess), stacklevel=2)
- if ierm > 0 and not full_output:
- if ier in [1, 2, 3, 4, 5]:
- _mess = (
- f"\n\tkx,ky={kx},{ky} nx,ny={len(tx)},{len(ty)} m={m} fp={fp} s={s}"
- )
- warnings.warn(RuntimeWarning(_iermess2[ierm][0] + _mess), stacklevel=2)
- else:
- try:
- raise _iermess2[ierm][1](_iermess2[ierm][0])
- except KeyError as e:
- raise _iermess2['unknown'][1](_iermess2['unknown'][0]) from e
- if full_output:
- try:
- return tck, fp, ier, _iermess2[ierm][0]
- except KeyError:
- return tck, fp, ier, _iermess2['unknown'][0]
- else:
- return tck
- @xp_capabilities(out_of_scope=True)
- def bisplev(x, y, tck, dx=0, dy=0):
- """
- Evaluate a bivariate B-spline and its derivatives.
- Return a rank-2 array of spline function values (or spline derivative
- values) at points given by the cross-product of the rank-1 arrays `x` and
- `y`. In special cases, return an array or just a float if either `x` or
- `y` or both are floats. Based on BISPEV and PARDER from FITPACK.
- Parameters
- ----------
- x, y : ndarray
- Rank-1 arrays specifying the domain over which to evaluate the
- spline or its derivative.
- tck : tuple
- A sequence of length 5 returned by `bisplrep` containing the knot
- locations, the coefficients, and the degree of the spline:
- [tx, ty, c, kx, ky].
- dx, dy : int, optional
- The orders of the partial derivatives in `x` and `y` respectively.
- Returns
- -------
- vals : ndarray
- The B-spline or its derivative evaluated over the set formed by
- the cross-product of `x` and `y`.
- See Also
- --------
- splprep, splrep, splint, sproot, splev
- UnivariateSpline, BivariateSpline
- Notes
- -----
- See `bisplrep` to generate the `tck` representation.
- References
- ----------
- .. [1] Dierckx P. : An algorithm for surface fitting
- with spline functions
- Ima J. Numer. Anal. 1 (1981) 267-283.
- .. [2] Dierckx P. : An algorithm for surface fitting
- with spline functions
- report tw50, Dept. Computer Science,K.U.Leuven, 1980.
- .. [3] Dierckx P. : Curve and surface fitting with splines,
- Monographs on Numerical Analysis, Oxford University Press, 1993.
- Examples
- --------
- Examples are given :ref:`in the tutorial <tutorial-interpolate_2d_spline>`.
- """
- tx, ty, c, kx, ky = tck
- if not (0 <= dx < kx):
- raise ValueError(f"0 <= dx = {dx} < kx = {kx} must hold")
- if not (0 <= dy < ky):
- raise ValueError(f"0 <= dy = {dy} < ky = {ky} must hold")
- x, y = map(atleast_1d, [x, y])
- if (len(x.shape) != 1) or (len(y.shape) != 1):
- raise ValueError("First two entries should be rank-1 arrays.")
- msg = "Too many data points to interpolate."
- _int_overflow(x.size * y.size, MemoryError, msg=msg)
- if dx != 0 or dy != 0:
- _int_overflow((tx.size - kx - 1)*(ty.size - ky - 1),
- MemoryError, msg=msg)
- z, ier = dfitpack.parder(tx, ty, c, kx, ky, dx, dy, x, y)
- else:
- z, ier = dfitpack.bispev(tx, ty, c, kx, ky, x, y)
- if ier == 10:
- raise ValueError("Invalid input data")
- if ier:
- raise TypeError("An error occurred")
- z = z.reshape((len(x), len(y)))
- if len(z) > 1:
- return z
- if len(z[0]) > 1:
- return z[0]
- return z[0][0]
- def dblint(xa, xb, ya, yb, tck):
- """Evaluate the integral of a spline over area [xa,xb] x [ya,yb].
- Parameters
- ----------
- xa, xb : float
- The end-points of the x integration interval.
- ya, yb : float
- The end-points of the y integration interval.
- tck : list [tx, ty, c, kx, ky]
- A sequence of length 5 returned by bisplrep containing the knot
- locations tx, ty, the coefficients c, and the degrees kx, ky
- of the spline.
- Returns
- -------
- integ : float
- The value of the resulting integral.
- """
- tx, ty, c, kx, ky = tck
- return dfitpack.dblint(tx, ty, c, kx, ky, xa, xb, ya, yb)
- def insert(x, tck, m=1, per=0):
- # see the docstring of `_fitpack_py/insert`
- t, c, k = tck
- try:
- c[0][0]
- parametric = True
- except Exception:
- parametric = False
- if parametric:
- cc = []
- for c_vals in c:
- tt, cc_val, kk = insert(x, [t, c_vals, k], m)
- cc.append(cc_val)
- return (tt, cc, kk)
- else:
- tt, cc, ier = _fitpack._insert(per, t, c, k, x, m)
- if ier == 10:
- raise ValueError("Invalid input data")
- if ier:
- raise TypeError("An error occurred")
- return (tt, cc, k)
- def splder(tck, n=1, xp=None):
- # see the docstring of `_fitpack_py/splder`
- if n < 0:
- return splantider(tck, -n)
- t, c, k = tck
- if xp is None:
- xp = array_namespace(t, c)
- if n > k:
- raise ValueError(f"Order of derivative (n = {n!r}) must be <= "
- f"order of spline (k = {tck[2]!r})")
- # Extra axes for the trailing dims of the `c` array:
- sh = (slice(None),) + ((None,)*len(c.shape[1:]))
- with np.errstate(invalid='raise', divide='raise'):
- try:
- for j in range(n):
- # See e.g. Schumaker, Spline Functions: Basic Theory, Chapter 5
- # Compute the denominator in the differentiation formula.
- # (and append trailing dims, if necessary)
- dt = t[k+1:-1] - t[1:-k-1]
- dt = dt[sh]
- # Compute the new coefficients
- c = (c[1:-1-k, ...] - c[:-2-k, ...]) * k / dt
- # Pad coefficient array to same size as knots (FITPACK
- # convention)
- c = concat_1d(xp, c, xp.zeros((k,) + c.shape[1:]))
- # Adjust knots
- t = t[1:-1]
- k -= 1
- except FloatingPointError as e:
- raise ValueError("The spline has internal repeated knots "
- f"and is not differentiable {n} times") from e
- return t, c, k
- def splantider(tck, n=1, *, xp=None):
- # see the docstring of `_fitpack_py/splantider`
- if n < 0:
- return splder(tck, -n)
- t, c, k = tck
- if xp is None:
- xp = array_namespace(t, c)
- # Extra axes for the trailing dims of the `c` array:
- sh = (slice(None),) + (None,)*len(c.shape[1:])
- for j in range(n):
- # This is the inverse set of operations to splder.
- # Compute the multiplier in the antiderivative formula.
- dt = t[k+1:] - t[:-k-1]
- dt = dt[sh]
- # Compute the new coefficients
- c = xp.cumulative_sum(c[:-k-1, ...] * dt, axis=0) / (k + 1)
- c = concat_1d(
- xp,
- xp.zeros((1,) + c.shape[1:]),
- c,
- xp.stack([c[-1, ...]] * (k+2)),
- )
- # New knots
- t = concat_1d(xp, t[0], t, t[-1])
- k += 1
- return t, c, k
|