
    (ph                         S SK r S SKrS SKJr  S SKJrJrJrJ	r	  / SQr
S r " S S5      r " S S	\5      r " S
 S\5      rSS jrSS jr " S S\5      rSS SS.S jjrg)    N)	factorial)_asarray_validatedfloat_factorialcheck_random_state_transition_to_rng)KroghInterpolatorkrogh_interpolateBarycentricInterpolatorbarycentric_interpolateapproximate_taylor_polynomialc                     [         R                  " U 5      =(       d"    [        U S5      =(       a    U R                  S:H  $ )z-Check whether x is if a scalar type, or 0-dimshape )npisscalarhasattrr   )xs    M/var/www/html/venv/lib/python3.13/site-packages/scipy/interpolate/_polyint.py	_isscalarr      s)    ;;q>BWQ0BQWW]B    c                   \    \ rS rSrSrSrSS jrS rS rS r	S	 r
SS
 jrSS jrSS jrSrg)_Interpolator1D   a  
Common features in univariate interpolation

Deal with input data type and interpolation axis rolling. The
actual interpolator can assume the y-data is of shape (n, r) where
`n` is the number of x-points, and `r` the number of variables,
and use self.dtype as the y-data type.

Attributes
----------
_y_axis
    Axis along which the interpolation goes in the original array
_y_extra_shape
    Additional trailing shape of the input arrays, excluding
    the interpolation axis.
dtype
    Dtype of the y-data arrays. Can be set via _set_dtype, which
    forces it to be float or complex.

Methods
-------
__call__
_prepare_x
_finish_y
_reshape_yi
_set_yi
_set_dtype
_evaluate

)_y_axis_y_extra_shapedtypeNc                 T    X0l         S U l        S U l        Ub  U R                  X!US9  g g )Nxiaxis)r   r   r   _set_yi)selfr   yir    s       r   __init___Interpolator1D.__init__5   s0    "
>LLL. r   c                 l    U R                  U5      u  pU R                  U5      nU R                  X25      $ )ax  
Evaluate the interpolant

Parameters
----------
x : array_like
    Point or points at which to evaluate the interpolant.

Returns
-------
y : array_like
    Interpolated values. Shape is determined by replacing
    the interpolation axis in the original array with the shape of `x`.

Notes
-----
Input values `x` must be convertible to `float` values like `int`
or `float`.

)
_prepare_x	_evaluate	_finish_y)r"   r   x_shapeys       r   __call___Interpolator1D.__call__<   s1    * __Q'
NN1~~a))r   c                     [        5       e)z2
Actually evaluate the value of the interpolator.
NotImplementedErrorr"   r   s     r   r(   _Interpolator1D._evaluateU   s     "##r   c                 T    [        USSS9nUR                  nUR                  5       U4$ )zReshape input x array to 1-DFT)check_finite
as_inexact)r   r   ravel)r"   r   r*   s      r   r'   _Interpolator1D._prepare_x[   s*    quF''wwy'!!r   c                    UR                  X R                  -   5      nU R                  S:w  a  US:w  a  [        U5      n[        U R                  5      n[	        [        X3U R                  -   5      5      [	        [        U5      5      -   [	        [        X0R                  -   X4-   5      5      -   nUR                  U5      nU$ )z@Reshape interpolated y back to an N-D array similar to initial yr   r   )reshaper   r   lenlistrange	transpose)r"   r+   r*   nxnyss         r   r)   _Interpolator1D._finish_ya   s    IIg 3 334<<1BWBT(()BeBT\\ 123b	?#%)%<<*G%HIAAAr   c                    [         R                  " [         R                  " U5      U R                  S5      nU(       ad  UR                  SS  U R
                  :w  aG  U R
                  U R                  * S  < SU R
                  S U R                  *  < 3n[        SU 35      eUR                  UR                  S   S45      $ )Nr      z
 + (N,) + zData must be of shape )r   moveaxisasarrayr   r   r   
ValueErrorr9   )r"   r#   checkok_shapes       r   _reshape_yi_Interpolator1D._reshape_yil   s    [[Bq9RXXab\T%8%88..}~>A..~>ACH5hZ@AAzz288A;+,,r   c                    Uc  U R                   nUc  [        S5      e[        R                  " U5      nUR                  nUS:X  a  SnUb  XC   [        U5      :w  a  [        S5      eX1R                  -  U l         UR                  S U R                    UR                  U R                   S-   S  -   U l        S U l        U R                  UR                  5        g )Nzno interpolation axis specifiedr   rC   z@x and y arrays must be equal in length along interpolation axis.rC   )
r   rG   r   rF   r   r:   ndimr   r   
_set_dtype)r"   r#   r   r    r   s        r   r!   _Interpolator1D._set_yit   s    <<<D<>??ZZ^B;E>ekSW4 3 4 4 ww hh}5a8QQ
!r   c                 b   [         R                  " U[         R                  5      (       d4  [         R                  " U R                  [         R                  5      (       a  [         R                  U l        g U(       a  U R                  [         R                  :w  a  [         R
                  U l        g g N)r   
issubdtypecomplexfloatingr   
complex128float64)r"   r   unions      r   rO   _Interpolator1D._set_dtype   sa    == 2 233--

B,>,>??DJDJJ"--7ZZ
 8r   )NNN)F)NN)__name__
__module____qualname____firstlineno____doc__	__slots__r$   r,   r(   r'   r)   rJ   r!   rO   __static_attributes__r   r   r   r   r      s6    > 7I/*2$"	-"((r   r   c                   2    \ rS rSrSS jrSS jrSS jrSrg)	_Interpolator1DWithDerivatives   Nc                    U R                  U5      u  pU R                  X5      nUR                  UR                  S   4U-   U R                  -   5      nU R
                  S:w  a  US:w  a  [        U5      n[        U R                  5      nS/[        [        US-   XPR
                  -   S-   5      5      -   [        [        SUS-   5      5      -   [        [        US-   U R
                  -   XV-   S-   5      5      -   nUR                  U5      nU$ )a  
Evaluate several derivatives of the polynomial at the point `x`

Produce an array of derivatives evaluated at the point `x`.

Parameters
----------
x : array_like
    Point or points at which to evaluate the derivatives
der : int or list or None, optional
    How many derivatives to evaluate, or None for all potentially
    nonzero derivatives (that is, a number equal to the number
    of points), or a list of derivatives to evaluate. This number
    includes the function value as the '0th' derivative.

Returns
-------
d : ndarray
    Array with derivatives; ``d[j]`` contains the jth derivative.
    Shape of ``d[j]`` is determined by replacing the interpolation
    axis in the original array with the shape of `x`.

Examples
--------
>>> from scipy.interpolate import KroghInterpolator
>>> KroghInterpolator([0,0,0],[1,2,3]).derivatives(0)
array([1.0,2.0,3.0])
>>> KroghInterpolator([0,0,0],[1,2,3]).derivatives([0,0])
array([[1.0,1.0],
       [2.0,2.0],
       [3.0,3.0]])

r   r   rC   )
r'   _evaluate_derivativesr9   r   r   r   r:   r;   r<   r=   )r"   r   derr*   r+   r>   r?   r@   s           r   derivatives*_Interpolator1DWithDerivatives.derivatives   s    D __Q'
&&q.IIqwwqzmg-0C0CCD<<1BWBT(()BtE"Q$\\(9!(;<==aA'(eBqD-ruQw789A AAr   c                 x    U R                  U5      u  pU R                  XS-   5      nU R                  XB   U5      $ )a  
Evaluate a single derivative of the polynomial at the point `x`.

Parameters
----------
x : array_like
    Point or points at which to evaluate the derivatives

der : integer, optional
    Which derivative to evaluate (default: first derivative).
    This number includes the function value as 0th derivative.

Returns
-------
d : ndarray
    Derivative interpolated at the x-points. Shape of `d` is
    determined by replacing the interpolation axis in the
    original array with the shape of `x`.

Notes
-----
This may be computed by evaluating all derivatives up to the desired
one (using self.derivatives()) and then discarding the rest.

rC   r'   rd   r)   r"   r   re   r*   r+   s        r   
derivative)_Interpolator1DWithDerivatives.derivative   s;    4 __Q'
&&qa%0~~afg..r   c                     [        5       e)a  
Actually evaluate the derivatives.

Parameters
----------
x : array_like
    1D array of points at which to evaluate the derivatives
der : integer, optional
    The number of derivatives to evaluate, from 'order 0' (der=1)
    to order der-1.  If omitted, return all possibly-non-zero
    derivatives, ie 0 to order n-1.

Returns
-------
d : ndarray
    Array of shape ``(der, x.size, self.yi.shape[1])`` containing
    the derivatives from 0 to der-1
r/   )r"   r   re   s      r   rd   4_Interpolator1DWithDerivatives._evaluate_derivatives   s    & "##r   r   rR   rM   )rY   rZ   r[   r\   rf   rk   rd   r_   r   r   r   ra   ra      s    -^/<$r   ra   c                   @   ^  \ rS rSrSrSU 4S jjrS rSS jrSrU =r	$ )	r      aX
  
Interpolating polynomial for a set of points.

The polynomial passes through all the pairs ``(xi, yi)``. One may
additionally specify a number of derivatives at each point `xi`;
this is done by repeating the value `xi` and specifying the
derivatives as successive `yi` values.

Allows evaluation of the polynomial and all its derivatives.
For reasons of numerical stability, this function does not compute
the coefficients of the polynomial, although they can be obtained
by evaluating all the derivatives.

Parameters
----------
xi : array_like, shape (npoints, )
    Known x-coordinates. Must be sorted in increasing order.
yi : array_like, shape (..., npoints, ...)
    Known y-coordinates. When an xi occurs two or more times in
    a row, the corresponding yi's represent derivative values. The length of `yi`
    along the interpolation axis must be equal to the length of `xi`. Use the
    `axis` parameter to select the correct axis.
axis : int, optional
    Axis in the `yi` array corresponding to the x-coordinate values. Defaults to
    ``axis=0``.

Notes
-----
Be aware that the algorithms implemented here are not necessarily
the most numerically stable known. Moreover, even in a world of
exact computation, unless the x coordinates are chosen very
carefully - Chebyshev zeros (e.g., cos(i*pi/n)) are a good choice -
polynomial interpolation itself is a very ill-conditioned process
due to the Runge phenomenon. In general, even with well-chosen
x values, degrees higher than about thirty cause problems with
numerical instability in this code.

Based on [1]_.

References
----------
.. [1] Krogh, "Efficient Algorithms for Polynomial Interpolation
    and Numerical Differentiation", 1970.

Examples
--------
To produce a polynomial that is zero at 0 and 1 and has
derivative 2 at 0, call

>>> from scipy.interpolate import KroghInterpolator
>>> KroghInterpolator([0,0,1],[0,2,0])

This constructs the quadratic :math:`2x^2-2x`. The derivative condition
is indicated by the repeated zero in the `xi` array; the corresponding
yi values are 0, the function value, and 2, the derivative value.

For another example, given `xi`, `yi`, and a derivative `ypi` for each
point, appropriate arrays can be constructed as:

>>> import numpy as np
>>> rng = np.random.default_rng()
>>> xi = np.linspace(0, 1, 5)
>>> yi, ypi = rng.random((2, 5))
>>> xi_k, yi_k = np.repeat(xi, 2), np.ravel(np.dstack((yi,ypi)))
>>> KroghInterpolator(xi_k, yi_k)

To produce a vector-valued polynomial, supply a higher-dimensional
array for `yi`:

>>> KroghInterpolator([0,1],[[2,3],[4,5]])

This constructs a linear polynomial giving (2,3) at 0 and (4,5) at 1.

c                   > [         T
U ]  XU5        [        R                  " U5      U l        U R                  U5      U l        U R                  R                  u  U l        U l	        U R                  R                  =nS:  a  [        R                  " U S3SS9  [        R                  " U R                  S-   U R                  4U R                  S9nU R                  S   US'   [        R                  " U R                  U R                  4U R                  S9n[        SU R                  5       H  nSnX::  a&  XU-
     X   :X  a  US-  nX::  a  XU-
     X   :X  a  M  US-  nU R                  U   [!        U5      -  US'   [        Xx-
  5       HS  n	X   X   :X  a  [#        S5      eUS:X  a  XY   Xi   -
  X   X   -
  -  XiS-   '   M8  XiS-      Xi   -
  X   X   -
  -  XiS-   '   MU     XgU-
     XW'   M     XPl        g )	N   zv degrees provided, degrees higher than about thirty cause problems with numerical instability with 'KroghInterpolator'   )
stacklevelrC   r   r   z Elements of `xi` can't be equal.)superr$   r   rF   r   rJ   r#   r   nrsizewarningswarnzerosr   r<   r   rG   c)r"   r   r#   r    degr}   Vkkr@   i	__class__s             r   r$   KroghInterpolator.__init__A  s   &**R.""2&77<<C2%MMSE "5 5ABD HHdffQh'tzz:wwqz!XXtvvtvv&djj9q$&&!AA&R!W-Q &R!W-FAGGAJq11BqE13Z5BE>$%GHH6 tBEzBE"%K8BsG!A#wru}ruRU{;BsG   c7AD " r   c                 v   Sn[         R                  " [        U5      U R                  4U R                  S9nX0R
                  S[         R                  S S 24   -  n[        SU R                  5       HD  nXR                  US-
     -
  nXR-  nX2S S 2[         R                  4   U R
                  U   -  -  nMF     U$ )NrC   ru   r   )
r   r|   r:   rx   r   r}   newaxisr<   rw   r   )r"   r   pipr   ws         r   r(   KroghInterpolator._evaluate`  s    HHc!fdff%TZZ8	VVAbjjN##q$&&!AGGAaCL ABAbjjL!DFF1I--A " r   c                 l   U R                   nU R                  nUc  U R                   n[        R                  " U[	        U5      45      n[        R                  " U[	        U5      45      nSUS'   [        R                  " [	        U5      U R                  4U R
                  S9nXpR                  S[        R                  S S 24   -  n[        SU5       HW  nXR                  US-
     -
  XhS-
  '   XhS-
     XXS-
     -  XX'   XuUS S 2[        R                  4   U R                  U   -  -  nMY     [        R                  " [        X#S-   5      [	        U5      U4U R
                  S9n	U	S US-   2S S 2S S 24==   U R                  S US-   2[        R                  S S 24   -  ss'   XyS'   [        SU5       Ho  n[        SX8-
  S-   5       HB  n
XhU
-   S-
     XZS-
     -  XZ   -   XZ'   X   XZS S 2[        R                  4   XU
-      -  -   X'   MD     X==   [        U5      -  ss'   Mq     SXS S 2S S 24'   U	S U $ )NrC   r   ru   )rw   rx   r   r|   r:   r   r}   r   r<   r   maxr   )r"   r   re   rw   rx   r   r   r   r   cnr   s              r   rd   'KroghInterpolator._evaluate_derivativesj  s    FFFF;&&CXXq#a&k"HHaQ[!1HHc!fdff%TZZ8	VVArzz1$%%q!A1%AcFcFR!W$BEAq"**$%q	11A 
 XXs3!}c!fa0

C
4AaC4A:$&&!A#rzz1!4551q!A1ac!e_A#a%aC(250a#3 4R!W << % E_Q''E	  a7$3xr   )r}   rw   rx   r   r#   r   rR   )
rY   rZ   r[   r\   r]   r$   r(   rd   r_   __classcell__r   s   @r   r   r      s    IV> r   r   c                     [        XUS9nUS:X  a  U" U5      $ [        U5      (       a  UR                  X#S9$ UR                  U[        R
                  " U5      S-   S9U   $ )a+  
Convenience function for polynomial interpolation.

See `KroghInterpolator` for more details.

Parameters
----------
xi : array_like
    Interpolation points (known x-coordinates).
yi : array_like
    Known y-coordinates, of shape ``(xi.size, R)``. Interpreted as
    vectors of length R, or scalars if R=1.
x : array_like
    Point or points at which to evaluate the derivatives.
der : int or list or None, optional
    How many derivatives to evaluate, or None for all potentially
    nonzero derivatives (that is, a number equal to the number
    of points), or a list of derivatives to evaluate. This number
    includes the function value as the '0th' derivative.
axis : int, optional
    Axis in the `yi` array corresponding to the x-coordinate values.

Returns
-------
d : ndarray
    If the interpolator's values are R-D then the
    returned array will be the number of derivatives by N by R.
    If `x` is a scalar, the middle dimension will be dropped; if
    the `yi` are scalars then the last dimension will be dropped.

See Also
--------
KroghInterpolator : Krogh interpolator

Notes
-----
Construction of the interpolating polynomial is a relatively expensive
process. If you want to evaluate it repeatedly consider using the class
KroghInterpolator (which is what this function uses).

Examples
--------
We can interpolate 2D observed data using Krogh interpolation:

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from scipy.interpolate import krogh_interpolate
>>> x_observed = np.linspace(0.0, 10.0, 11)
>>> y_observed = np.sin(x_observed)
>>> x = np.linspace(min(x_observed), max(x_observed), num=100)
>>> y = krogh_interpolate(x_observed, y_observed, x)
>>> plt.plot(x_observed, y_observed, "o", label="observation")
>>> plt.plot(x, y, label="krogh interpolation")
>>> plt.legend()
>>> plt.show()
r    r   re   rC   )r   r   rk   rf   r   amax)r   r#   r   re   r    Ps         r   r	   r	     s_    t 	"t,A
axt	3||A|''}}QBGGCLN}3C88r   c           
      \   Uc  UnUS-   nU[         R                  " [         R                  " S[         R                  XUS-  S95      -  U-   n[	        X`" U5      5      nUR                  XS-   S9n[         R                  " U[        [         R                  " US-   5      5      -  SSS2   5      $ )a  
Estimate the Taylor polynomial of f at x by polynomial fitting.

Parameters
----------
f : callable
    The function whose Taylor polynomial is sought. Should accept
    a vector of `x` values.
x : scalar
    The point at which the polynomial is to be evaluated.
degree : int
    The degree of the Taylor polynomial
scale : scalar
    The width of the interval to use to evaluate the Taylor polynomial.
    Function values spread over a range this wide are used to fit the
    polynomial. Must be chosen carefully.
order : int or None, optional
    The order of the polynomial to be used in the fitting; `f` will be
    evaluated ``order+1`` times. If None, use `degree`.

Returns
-------
p : poly1d instance
    The Taylor polynomial (translated to the origin, so that
    for example p(0)=f(x)).

Notes
-----
The appropriate choice of "scale" is a trade-off; too large and the
function differs from its Taylor polynomial too much to get a good
answer, too small and round-off errors overwhelm the higher-order terms.
The algorithm used becomes numerically unstable around order 30 even
under ideal circumstances.

Choosing order somewhat larger than degree may improve the higher-order
terms.

Examples
--------
We can calculate Taylor approximation polynomials of sin function with
various degrees:

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from scipy.interpolate import approximate_taylor_polynomial
>>> x = np.linspace(-10.0, 10.0, num=100)
>>> plt.plot(x, np.sin(x), label="sin curve")
>>> for degree in np.arange(1, 15, step=2):
...     sin_taylor = approximate_taylor_polynomial(np.sin, 0, degree, 1,
...                                                order=degree + 2)
...     plt.plot(x, sin_taylor(x), label=f"degree={degree}")
>>> plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left',
...            borderaxespad=0.0, shadow=True)
>>> plt.tight_layout()
>>> plt.axis([-10, 10, -10, 10])
>>> plt.show()

NrC   r   )endpointr   rD   )	r   coslinspacer   r   rf   poly1dr   arange)	fr   degreescaleorderrw   xsr   ds	            r   r   r     s    v }aA
 
rvvbkk!BEE!U;<	<q	@B"ae$A	a1H%A99a	"))F1H"566"=>>r   c                      ^  \ rS rSrSr\" SSS9SSSS.U 4S jjj5       rSS	 jrSS
 jrS r	S r
SS jrSS jrSrU =r$ )r
   i  a  Interpolating polynomial for a set of points.

Constructs a polynomial that passes through a given set of points.
Allows evaluation of the polynomial and all its derivatives,
efficient changing of the y-values to be interpolated,
and updating by adding more x- and y-values.

For reasons of numerical stability, this function does not compute
the coefficients of the polynomial.

The values `yi` need to be provided before the function is
evaluated, but none of the preprocessing depends on them, so rapid
updates are possible.

Parameters
----------
xi : array_like, shape (npoints, )
    1-D array of x coordinates of the points the polynomial
    should pass through
yi : array_like, shape (..., npoints, ...), optional
    N-D array of y coordinates of the points the polynomial should pass through.
    If None, the y values will be supplied later via the `set_y` method.
    The length of `yi` along the interpolation axis must be equal to the length
    of `xi`. Use the ``axis`` parameter to select correct axis.
axis : int, optional
    Axis in the yi array corresponding to the x-coordinate values. Defaults
    to ``axis=0``.
wi : array_like, optional
    The barycentric weights for the chosen interpolation points `xi`.
    If absent or None, the weights will be computed from `xi` (default).
    This allows for the reuse of the weights `wi` if several interpolants
    are being calculated using the same nodes `xi`, without re-computation.
rng : {None, int, `numpy.random.Generator`}, optional
    If `rng` is passed by keyword, types other than `numpy.random.Generator` are
    passed to `numpy.random.default_rng` to instantiate a ``Generator``.
    If `rng` is already a ``Generator`` instance, then the provided instance is
    used. Specify `rng` for repeatable interpolation.

    If this argument `random_state` is passed by keyword,
    legacy behavior for the argument `random_state` applies:

    - If `random_state` is None (or `numpy.random`), the `numpy.random.RandomState`
      singleton is used.
    - If `random_state` is an int, a new ``RandomState`` instance is used,
      seeded with `random_state`.
    - If `random_state` is already a ``Generator`` or ``RandomState`` instance then
      that instance is used.

    .. versionchanged:: 1.15.0
        As part of the `SPEC-007 <https://scientific-python.org/specs/spec-0007/>`_
        transition from use of `numpy.random.RandomState` to
        `numpy.random.Generator` this keyword was changed from `random_state` to `rng`.
        For an interim period, both keywords will continue to work (only specify
        one of them). After the interim period using the `random_state` keyword will emit
        warnings. The behavior of the `random_state` and `rng` keywords is outlined above.

Notes
-----
This class uses a "barycentric interpolation" method that treats
the problem as a special case of rational function interpolation.
This algorithm is quite stable, numerically, but even in a world of
exact computation, unless the x coordinates are chosen very
carefully - Chebyshev zeros (e.g., cos(i*pi/n)) are a good choice -
polynomial interpolation itself is a very ill-conditioned process
due to the Runge phenomenon.

Based on Berrut and Trefethen 2004, "Barycentric Lagrange Interpolation".

Examples
--------
To produce a quintic barycentric interpolant approximating the function
:math:`\sin x`, and its first four derivatives, using six randomly-spaced
nodes in :math:`(0, \frac{\pi}{2})`:

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from scipy.interpolate import BarycentricInterpolator
>>> rng = np.random.default_rng()
>>> xi = rng.random(6) * np.pi/2
>>> f, f_d1, f_d2, f_d3, f_d4 = np.sin, np.cos, lambda x: -np.sin(x), lambda x: -np.cos(x), np.sin
>>> P = BarycentricInterpolator(xi, f(xi), random_state=rng)
>>> fig, axs = plt.subplots(5, 1, sharex=True, layout='constrained', figsize=(7,10))
>>> x = np.linspace(0, np.pi, 100)
>>> axs[0].plot(x, P(x), 'r:', x, f(x), 'k--', xi, f(xi), 'xk')
>>> axs[1].plot(x, P.derivative(x), 'r:', x, f_d1(x), 'k--', xi, f_d1(xi), 'xk')
>>> axs[2].plot(x, P.derivative(x, 2), 'r:', x, f_d2(x), 'k--', xi, f_d2(xi), 'xk')
>>> axs[3].plot(x, P.derivative(x, 3), 'r:', x, f_d3(x), 'k--', xi, f_d3(xi), 'xk')
>>> axs[4].plot(x, P.derivative(x, 4), 'r:', x, f_d4(x), 'k--', xi, f_d4(xi), 'xk')
>>> axs[0].set_xlim(0, np.pi)
>>> axs[4].set_xlabel(r"$x$")
>>> axs[4].set_xticks([i * np.pi / 4 for i in range(5)],
...                   ["0", r"$\frac{\pi}{4}$", r"$\frac{\pi}{2}$", r"$\frac{3\pi}{4}$", r"$\pi$"])
>>> axs[0].set_ylabel("$f(x)$")
>>> axs[1].set_ylabel("$f'(x)$")
>>> axs[2].set_ylabel("$f''(x)$")
>>> axs[3].set_ylabel("$f^{(3)}(x)$")
>>> axs[4].set_ylabel("$f^{(4)}(x)$")
>>> labels = ['Interpolation nodes', 'True function $f$', 'Barycentric interpolation']
>>> axs[0].legend(axs[0].get_lines()[::-1], labels, bbox_to_anchor=(0., 1.02, 1., .102),
...               loc='lower left', ncols=3, mode="expand", borderaxespad=0., frameon=False)
>>> plt.show()
random_stateF)replace_docN)wirngc                  > [         TU ]  XU5        [        U5      n[        R                  " U[        R
                  S9U l        U R                  U5        [        U R                  5      U l	        S U l
        Ub  X@l        g S[        R                  " U R                  5      [        R                  " U R                  5      -
  -  U l        UR                  U R                  5      n[        R                   " U R                  [        R"                  S9n[        R$                  " U R                  5      Xv'   [        R                   " U R                  5      U l        ['        U R                  5       Ho  nU R                  U R                  U   U R                  U   -
  -  n	SXU   '   [        R(                  " U	5      n
U
S:X  a  [+        S5      eSU
-  U R                  U'   Mq     g )Nru   g      @g      ?g        z)Interpolation points xi must be distinct.)rv   r$   r   r   rF   rV   r   set_yir:   rw   	_diff_cijr   r   min_inv_capacitypermutationr|   int32r   r<   prodrG   )r"   r   r#   r    r   r   permuteinv_permuter   distr   r   s              r   r$    BarycentricInterpolator.__init__  sY   & %**Rrzz2BTWW >G "%tww"&&/(I!JDoodff/G((466:K#%99TVV#4K hhtvv&DG466]))TWWQZ$''':J-JK'*^$wwt}3;$ &2 3 3 4Z
 #r   c                     Uc  SU l         gU R                  XR                  US9  U R                  U5      U l         U R                   R                  u  U l        U l        SU l        g)a  
Update the y values to be interpolated

The barycentric interpolation algorithm requires the calculation
of weights, but these depend only on the `xi`. The `yi` can be changed
at any time.

Parameters
----------
yi : array_like
    The y-coordinates of the points the polynomial will pass through.
    If None, the y values must be supplied later.
axis : int, optional
    Axis in the `yi` array corresponding to the x-coordinate values.

Nr   )r#   r!   r   rJ   r   rw   rx   _diff_baryint)r"   r#   r    s      r   r   BarycentricInterpolator.set_yi  sV    " :DGRGG$/""2&!r   c           
         UbP  U R                   c  [        S5      eU R                  USS9n[        R                  " U R                   U45      U l         OU R                   b  [        S5      eU R
                  n[        R                  " U R                  U45      U l        [        U R                  5      U l        U =R                  S-  sl	        U R                  n[        R                  " U R
                  5      U l	        X@R                  SU& [        X0R
                  5       H  nU R                  SU=== U R                  U R                  U   U R                  SU -
  -  -  sss& [        R                  R                  U R                  U R                  SU U R                  U   -
  -  5      U R                  U'   M     U =R                  S-  sl	        SU l        SU l        g)a\  
Add more x values to the set to be interpolated

The barycentric interpolation algorithm allows easy updating by
adding more points for the polynomial to pass through.

Parameters
----------
xi : array_like
    The x coordinates of the points that the polynomial should pass
    through.
yi : array_like, optional
    The y coordinates of the points the polynomial should pass through.
    Should have shape ``(xi.size, R)``; if R > 1 then the polynomial is
    vector-valued.
    If `yi` is not given, the y values will be supplied later. `yi`
    should be given if and only if the interpolator has y values
    specified.

Notes
-----
The new points added by `add_xi` are not randomly permuted
so there is potential for numerical instability,
especially for a large number of points. If this
happens, please reconstruct interpolation from scratch instead.
NzNo previous yi value to update!T)rH   zNo update to yi provided!rD   )r#   rG   rJ   r   vstackrw   concatenater   r:   r   r|   r<   r   multiplyreducer   r   )r"   r   r#   old_nold_wijs         r   add_xiBarycentricInterpolator.add_xi  sp   6 >ww !BCC!!"D!1Bii-DGww" !<==..$''".TWWB((466" uff%AGGBQK4--DGGBQK1GHHK++""dggbqk$''!*&<=DGGAJ &
 	B!r   c                 ,    [         R                  X5      $ )a  Evaluate the interpolating polynomial at the points x

Parameters
----------
x : array_like
    Point or points at which to evaluate the interpolant.

Returns
-------
y : array_like
    Interpolated values. Shape is determined by replacing
    the interpolation axis in the original array with the shape of `x`.

Notes
-----
Currently the code computes an outer product between `x` and the
weights, that is, it constructs an intermediate array of size
``(N, len(x))``, where N is the degree of the polynomial.
)r   r,   r1   s     r   r,    BarycentricInterpolator.__call__  s    ( ''00r   c                    UR                   S:X  a-  [        R                  " SU R                  4U R                  S9nU$ US[        R
                  4   U R                  -
  nUS:H  nSX4'   U R                  U-  n[        R                  " SS9   [        R                  " X0R                  5      [        R                  " USS9S[        R
                  4   -  nS S S 5        [        R                  " U5      n[        U5      S:X  a)  [        US   5      S:  a  U R                  US   S      nW$ U R                  US      WUS S '   U$ ! , (       d  f       Nv= f)	Nr   ru   .rC   ignore)dividerD   r   )ry   r   r|   rx   r   r   r   r   errstatedotr#   sumnonzeror:   )r"   r   r   r}   zrx   s         r   r(   !BarycentricInterpolator._evaluate  s   66Q;!TVVDJJ7A  #rzz/"TWW,AQAAD!AH-FF1gg&);CO)LL . 

1A1v{qt9q=!Q(A  !GGAbEN!CR&	 .-s   A
E
Ec                 p    U R                  U5      u  pU R                  XS-   SS9nU R                  XC5      $ )a  
Evaluate a single derivative of the polynomial at the point x.

Parameters
----------
x : array_like
    Point or points at which to evaluate the derivatives
der : integer, optional
    Which derivative to evaluate (default: first derivative).
    This number includes the function value as 0th derivative.

Returns
-------
d : ndarray
    Derivative interpolated at the x-points. Shape of `d` is
    determined by replacing the interpolation axis in the
    original array with the shape of `x`.
rC   F	all_lowerri   rj   s        r   rk   "BarycentricInterpolator.derivative  s<    & __Q'
&&qa%5&A~~a))r   c                    U(       dK  UR                   S:X  d  U R                  S:X  a+  [        R                  " SU R                  4U R                  S9$ U(       d  US:X  a  U R                  U5      $ U(       dC  X R                  :  a4  [        R                  " [        U5      U R                  4U R                  S9$ Uc  U R                  nU(       aU  UR                   S:X  d  U R                  S:X  a5  [        R                  " U[        U5      U R                  4U R                  S9$ U R                  c  U R                  S S 2[        R                  4   U R                  -
  n[        R                  " US5        U R                  X@R                  S[        R                  4   -  -  n[        R                  " US5        UR                  SS9* n[        R                  " XE5        X@l        U R                  cV  [        U R                  U R                  U R                   -  U R                  S9U l        U R                  U R                  l        U(       ae  [        R                  " U[        U5      U R                  4U R                  S9n[#        U5       H  nU R%                  XS-   SS9XeS S 2S S 24'   M!     U$ U R                  R%                  XS-
  SS9$ )	Nr   ru   rC   .r   )r   r#   r   Fr   )ry   rx   r   r|   r   r(   rw   r:   r   r   r   fill_diagonalr   r   r   r
   r#   r<   rd   )r"   r   re   r   r}   r   r   s          r   rd   -BarycentricInterpolator._evaluate_derivatives2  s(    !tvv{88QKtzz::sax>>!$$ff88SVTVV,DJJ??;&&C!&&A+188S#a&$&&1DD>>!2::&0A Q" !ggc2::o667A Q" AAQ"N% "9DGG<@NNTWW<T<@GG"ED ,0>>D( 3A/tzzBB3Z"88aC58Qa7  I !!77q5E7RRr   )r   r   r   rw   rx   r   r   r#   )Nr   rR   rM   )NT)rY   rZ   r[   r\   r]   r   r$   r   r   r,   r(   rk   rd   r_   r   r   s   @r   r
   r
     sZ    eN E:$($D $( $( ;$(L"21"f1,&*.>S >Sr   r
   )re   r   c                    [        XX5S9nUS:X  a  U" U5      $ [        U5      (       a  UR                  X$S9$ UR                  U[        R
                  " U5      S-   S9U   $ )a
  
Convenience function for polynomial interpolation.

Constructs a polynomial that passes through a given set of points,
then evaluates the polynomial. For reasons of numerical stability,
this function does not compute the coefficients of the polynomial.

This function uses a "barycentric interpolation" method that treats
the problem as a special case of rational function interpolation.
This algorithm is quite stable, numerically, but even in a world of
exact computation, unless the `x` coordinates are chosen very
carefully - Chebyshev zeros (e.g., cos(i*pi/n)) are a good choice -
polynomial interpolation itself is a very ill-conditioned process
due to the Runge phenomenon.

Parameters
----------
xi : array_like
    1-D array of x coordinates of the points the polynomial should
    pass through
yi : array_like
    The y coordinates of the points the polynomial should pass through.
x : scalar or array_like
    Point or points at which to evaluate the interpolant.
axis : int, optional
    Axis in the `yi` array corresponding to the x-coordinate values.
der : int or list or None, optional
    How many derivatives to evaluate, or None for all potentially
    nonzero derivatives (that is, a number equal to the number
    of points), or a list of derivatives to evaluate. This number
    includes the function value as the '0th' derivative.
rng : `numpy.random.Generator`, optional
    Pseudorandom number generator state. When `rng` is None, a new
    `numpy.random.Generator` is created using entropy from the
    operating system. Types other than `numpy.random.Generator` are
    passed to `numpy.random.default_rng` to instantiate a ``Generator``.

Returns
-------
y : scalar or array_like
    Interpolated values. Shape is determined by replacing
    the interpolation axis in the original array with the shape of `x`.

See Also
--------
BarycentricInterpolator : Barycentric interpolator

Notes
-----
Construction of the interpolation weights is a relatively slow process.
If you want to call this many times with the same xi (but possibly
varying yi or x) you should use the class `BarycentricInterpolator`.
This is what this function uses internally.

Examples
--------
We can interpolate 2D observed data using barycentric interpolation:

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> from scipy.interpolate import barycentric_interpolate
>>> x_observed = np.linspace(0.0, 10.0, 11)
>>> y_observed = np.sin(x_observed)
>>> x = np.linspace(min(x_observed), max(x_observed), num=100)
>>> y = barycentric_interpolate(x_observed, y_observed, x)
>>> plt.plot(x_observed, y_observed, "o", label="observation")
>>> plt.plot(x, y, label="barycentric interpolation")
>>> plt.legend()
>>> plt.show()

)r    r   r   r   rC   )r
   r   rk   rf   r   r   )r   r#   r   r    re   r   r   s          r   r   r   s  s_    P 	 T;A
axt	3||A|''}}QBGGCLN}3C88r   )r   r   rR   r   )rz   numpyr   scipy.specialr   scipy._lib._utilr   r   r   r   __all__r   r   ra   r   r	   r   r
   r   r   r   r   <module>r      s      #2 2,
C
{( {(|a$_ a$HQ6 Qh@9FH?VYS< YSx
N9aT N9r   