a
    BCCfX                    @   s:  g d Z ddlmZ ddlZddlZddlmZmZmZm	Z	m
Z
mZmZmZmZ ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZmZ dd Z dZ!G dd dZ"dd Z#dd Z$G dd deZ%G dd dZ&G dd de&Z'G dd de&Z(G dd  d Z)dS )!)interp1dinterp2dlagrangePPolyBPolyNdPPoly    )prodN)	array	transposesearchsorted
atleast_1d
atleast_2dravelpoly1dasarrayintp)copy_if_needed)comb   )_fitpack_py)dfitpack)_Interpolator1D)_ppoly)_ndim_coords_from_arrays)make_interp_splineBSplinec                 C   sx   t | }td}t|D ]Z}t|| }t|D ]8}||kr>q0| | | |  }|td| |  g| 9 }q0||7 }q|S )ag  
    Return a Lagrange interpolating polynomial.

    Given two 1-D arrays `x` and `w,` returns the Lagrange interpolating
    polynomial through the points ``(x, w)``.

    Warning: This implementation is numerically unstable. Do not expect to
    be able to use more than about 20 points even if they are chosen optimally.

    Parameters
    ----------
    x : array_like
        `x` represents the x-coordinates of a set of datapoints.
    w : array_like
        `w` represents the y-coordinates of a set of datapoints, i.e., f(`x`).

    Returns
    -------
    lagrange : `numpy.poly1d` instance
        The Lagrange interpolating polynomial.

    Examples
    --------
    Interpolate :math:`f(x) = x^3` by 3 points.

    >>> import numpy as np
    >>> from scipy.interpolate import lagrange
    >>> x = np.array([0, 1, 2])
    >>> y = x**3
    >>> poly = lagrange(x, y)

    Since there are only 3 points, Lagrange polynomial has degree 2. Explicitly,
    it is given by

    .. math::

        \begin{aligned}
            L(x) &= 1\times \frac{x (x - 2)}{-1} + 8\times \frac{x (x-1)}{2} \\
                 &= x (-2 + 3x)
        \end{aligned}

    >>> from numpy.polynomial.polynomial import Polynomial
    >>> Polynomial(poly.coef[::-1]).coef
    array([ 0., -2.,  3.])

    >>> import matplotlib.pyplot as plt
    >>> x_new = np.arange(0, 2.1, 0.1)
    >>> plt.scatter(x, y, label='data')
    >>> plt.plot(x_new, Polynomial(poly.coef[::-1])(x_new), label='Polynomial')
    >>> plt.plot(x_new, 3*x_new**2 - 2*x_new + 0*x_new,
    ...          label=r"$3 x^2 - 2 x$", linestyle='-.')
    >>> plt.legend()
    >>> plt.show()

            g      ?)lenr   range)xwMpjptkZfac r&   Z/var/www/html/django/DPS/env/lib/python3.9/site-packages/scipy/interpolate/_interpolate.pyr      s    9
r   a  `interp2d` is deprecated in SciPy 1.10 and will be removed in SciPy 1.14.0.

For legacy code, nearly bug-for-bug compatible replacements are
`RectBivariateSpline` on regular grids, and `bisplrep`/`bisplev` for
scattered 2D data.

In new code, for regular grids use `RegularGridInterpolator` instead.
For scattered data, prefer `LinearNDInterpolator` or
`CloughTocher2DInterpolator`.

For more details see
`https://scipy.github.io/devdocs/notebooks/interp_transition_guide.html`
c                   @   s$   e Zd ZdZdddZdd	d
ZdS )r   av  
    interp2d(x, y, z, kind='linear', copy=True, bounds_error=False,
             fill_value=None)

    .. deprecated:: 1.10.0

        `interp2d` is deprecated in SciPy 1.10 and will be removed in SciPy
        1.14.0.

        For legacy code, nearly bug-for-bug compatible replacements are
        `RectBivariateSpline` on regular grids, and `bisplrep`/`bisplev` for
        scattered 2D data.

        In new code, for regular grids use `RegularGridInterpolator` instead.
        For scattered data, prefer `LinearNDInterpolator` or
        `CloughTocher2DInterpolator`.

        For more details see
        `https://scipy.github.io/devdocs/notebooks/interp_transition_guide.html
        <https://scipy.github.io/devdocs/notebooks/interp_transition_guide.html>`_


    Interpolate over a 2-D grid.

    `x`, `y` and `z` are arrays of values used to approximate some function
    f: ``z = f(x, y)`` which returns a scalar value `z`. This class returns a
    function whose call method uses spline interpolation to find the value
    of new points.

    If `x` and `y` represent a regular grid, consider using
    `RectBivariateSpline`.

    If `z` is a vector value, consider using `interpn`.

    Note that calling `interp2d` with NaNs present in input values, or with
    decreasing values in `x` an `y` results in undefined behaviour.

    Methods
    -------
    __call__

    Parameters
    ----------
    x, y : array_like
        Arrays defining the data point coordinates.
        The data point coordinates need to be sorted by increasing order.

        If the points lie on a regular grid, `x` can specify the column
        coordinates and `y` the row coordinates, for example::

          >>> x = [0,1,2];  y = [0,3]; z = [[1,2,3], [4,5,6]]

        Otherwise, `x` and `y` must specify the full coordinates for each
        point, for example::

          >>> x = [0,1,2,0,1,2];  y = [0,0,0,3,3,3]; z = [1,4,2,5,3,6]

        If `x` and `y` are multidimensional, they are flattened before use.
    z : array_like
        The values of the function to interpolate at the data points. If
        `z` is a multidimensional array, it is flattened before use assuming
        Fortran-ordering (order='F').  The length of a flattened `z` array
        is either len(`x`)*len(`y`) if `x` and `y` specify the column and
        row coordinates or ``len(z) == len(x) == len(y)`` if `x` and `y`
        specify coordinates for each point.
    kind : {'linear', 'cubic', 'quintic'}, optional
        The kind of spline interpolation to use. Default is 'linear'.
    copy : bool, optional
        If True, the class makes internal copies of x, y and z.
        If False, references may be used. The default is to copy.
    bounds_error : bool, optional
        If True, when interpolated values are requested outside of the
        domain of the input data (x,y), a ValueError is raised.
        If False, then `fill_value` is used.
    fill_value : number, optional
        If provided, the value to use for points outside of the
        interpolation domain. If omitted (None), values outside
        the domain are extrapolated via nearest-neighbor extrapolation.

    See Also
    --------
    RectBivariateSpline :
        Much faster 2-D interpolation if your input data is on a grid
    bisplrep, bisplev :
        Spline interpolation based on FITPACK
    BivariateSpline : a more recent wrapper of the FITPACK routines
    interp1d : 1-D version of this function
    RegularGridInterpolator : interpolation on a regular or rectilinear grid
        in arbitrary dimensions.
    interpn : Multidimensional interpolation on regular grids (wraps
        `RegularGridInterpolator` and `RectBivariateSpline`).

    Notes
    -----
    The minimum number of data points required along the interpolation
    axis is ``(k+1)**2``, with k=1 for linear, k=3 for cubic and k=5 for
    quintic interpolation.

    The interpolator is constructed by `bisplrep`, with a smoothing factor
    of 0. If more control over smoothing is needed, `bisplrep` should be
    used directly.

    The coordinates of the data points to interpolate `xnew` and `ynew`
    have to be sorted by ascending order.
    `interp2d` is legacy and is not
    recommended for use in new code. New code should use
    `RegularGridInterpolator` instead.

    Examples
    --------
    Construct a 2-D grid and interpolate on it:

    >>> import numpy as np
    >>> from scipy import interpolate
    >>> x = np.arange(-5.01, 5.01, 0.25)
    >>> y = np.arange(-5.01, 5.01, 0.25)
    >>> xx, yy = np.meshgrid(x, y)
    >>> z = np.sin(xx**2+yy**2)
    >>> f = interpolate.interp2d(x, y, z, kind='cubic')

    Now use the obtained interpolation function and plot the result:

    >>> import matplotlib.pyplot as plt
    >>> xnew = np.arange(-5.01, 5.01, 1e-2)
    >>> ynew = np.arange(-5.01, 5.01, 1e-2)
    >>> znew = f(xnew, ynew)
    >>> plt.plot(x, z[0, :], 'ro-', xnew, znew[0, :], 'b-')
    >>> plt.show()
    linearTFNc                    s  t jttdd t|}t|}t|}|jt|t| k}|r|jdkrj|j	t|t|fkrjt
dt|dd  |d d kst|}	||	 }|d d |	f }t|dd  |d d kst|}	||	 }||	d d f }t|j}n<t|}t|t|krt
dt|t|kr2t
dddd	d
}
z|
|  }}W nN ty } z4t
dt| ddtt|
 d|W Y d }~n
d }~0 0 |stj|||||dd| _nhtj|||d d d d ||dd
\}}}}}}}|d | |d | |d || d || d   ||f| _|| _|| _ fdd|||fD \| _| _| _t|t| | _| _ t|t| | _!| _"d S )N   
stacklevelzdWhen on a regular grid with x.size = m and y.size = n, if z.ndim == 2, then z must have shape (n, m)r   z8x and y must have equal lengths for non rectangular gridz3Invalid length for input z for non rectangular grid      )r(   cubicZquinticzUnsupported interpolation type z, must be either of z, .r   )kxkysc                 3   s   | ]}t | d V  qdS )copyN)r	   ).0ar4   r&   r'   	<genexpr>(      z$interp2d.__init__.<locals>.<genexpr>)#warningswarndep_mesgDeprecationWarningr   r   sizer   ndimshape
ValueErrornpallargsortTKeyErrorreprjoinmapr   Zbisplreptckr   Zregrid_smthbounds_error
fill_valuer   yzZaminZamaxx_minx_maxy_miny_max)selfr   rM   rN   kindr5   rK   rL   Zrectangular_gridr#   Zinterpolation_typesr1   r2   enxZtxnytycfpZierr&   r4   r'   __init__   sh    


2$zinterp2d.__init__r   c                 C   sX  t jttdd t|}t|}|jdks4|jdkr<td|s\tj|dd}tj|dd}| j	sl| j
dur|| jk || jkB }|| jk || jkB }t|}t|}	| j	r|s|	rtd| j| jfd	| j| jft||| j||}
t|
}
t|
}
| j
dur:|r"| j
|
dd|f< |	r:| j
|
|ddf< t|
dkrP|
d
 }
t|
S )a  Interpolate the function.

        Parameters
        ----------
        x : 1-D array
            x-coordinates of the mesh on which to interpolate.
        y : 1-D array
            y-coordinates of the mesh on which to interpolate.
        dx : int >= 0, < kx
            Order of partial derivatives in x.
        dy : int >= 0, < ky
            Order of partial derivatives in y.
        assume_sorted : bool, optional
            If False, values of `x` and `y` can be in any order and they are
            sorted first.
            If True, `x` and `y` have to be arrays of monotonically
            increasing values.

        Returns
        -------
        z : 2-D array with shape (len(y), len(x))
            The interpolated values.
        r)   r*   r   z!x and y should both be 1-D arrays	mergesortrT   Nz"Values out of range; x must be in z, y in r   )r:   r;   r<   r=   r   r?   rA   rB   sortrK   rL   rO   rP   rQ   rR   anyr   ZbisplevrJ   r   r
   r   r	   )rS   r   rM   dxZdyassume_sortedZout_of_bounds_xZout_of_bounds_yZany_out_of_bounds_xZany_out_of_bounds_yrN   r&   r&   r'   __call__-  s<    


zinterp2d.__call__)r(   TFN)r   r   F)__name__
__module____qualname____doc__r[   rb   r&   r&   r&   r'   r   o   s      
;r   c                 C   s   | j }t|t|krt|ddd |ddd D ]\}}|dkr4||kr4 qq4| jdkrx| j |krxt|| j|  } |  S t| d| d| dS )z7Helper to check that arr_from broadcasts up to shape_toNr,   r   z0 argument must be able to broadcast up to shape z but had shape )	r@   r   zipr>   rB   Zonesdtyper   rA   )Zarr_fromZshape_tonameZ
shape_fromtfr&   r&   r'   _check_broadcast_up_tom  s    &rl   c                 C   s   t | to| dkS )z?Helper to check if fill_value == "extrapolate" without warningsextrapolate)
isinstancestr)rL   r&   r&   r'   _do_extrapolate}  s    
rp   c                   @   s   e Zd ZdZddddejdfddZed	d
 Zej	dd
 Zdd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd ZdS )r   a  
    Interpolate a 1-D function.

    .. legacy:: class

        For a guide to the intended replacements for `interp1d` see
        :ref:`tutorial-interpolate_1Dsection`.

    `x` and `y` are arrays of values used to approximate some function f:
    ``y = f(x)``. This class returns a function whose call method uses
    interpolation to find the value of new points.

    Parameters
    ----------
    x : (npoints, ) array_like
        A 1-D array of real values.
    y : (..., npoints, ...) array_like
        A N-D array of real values. The length of `y` along the interpolation
        axis must be equal to the length of `x`. Use the ``axis`` parameter
        to select correct axis. Unlike other interpolators, the default
        interpolation axis is the last axis of `y`.
    kind : str or int, optional
        Specifies the kind of interpolation as a string or as an integer
        specifying the order of the spline interpolator to use.
        The string has to be one of 'linear', 'nearest', 'nearest-up', 'zero',
        'slinear', 'quadratic', 'cubic', 'previous', or 'next'. 'zero',
        'slinear', 'quadratic' and 'cubic' refer to a spline interpolation of
        zeroth, first, second or third order; 'previous' and 'next' simply
        return the previous or next value of the point; 'nearest-up' and
        'nearest' differ when interpolating half-integers (e.g. 0.5, 1.5)
        in that 'nearest-up' rounds up and 'nearest' rounds down. Default
        is 'linear'.
    axis : int, optional
        Axis in the ``y`` array corresponding to the x-coordinate values. Unlike
        other interpolators, defaults to ``axis=-1``.
    copy : bool, optional
        If ``True``, the class makes internal copies of x and y. If ``False``,
        references to ``x`` and ``y`` are used if possible. The default is to copy.
    bounds_error : bool, optional
        If True, a ValueError is raised any time interpolation is attempted on
        a value outside of the range of x (where extrapolation is
        necessary). If False, out of bounds values are assigned `fill_value`.
        By default, an error is raised unless ``fill_value="extrapolate"``.
    fill_value : array-like or (array-like, array_like) or "extrapolate", optional
        - if a ndarray (or float), this value will be used to fill in for
          requested points outside of the data range. If not provided, then
          the default is NaN. The array-like must broadcast properly to the
          dimensions of the non-interpolation axes.
        - If a two-element tuple, then the first element is used as a
          fill value for ``x_new < x[0]`` and the second element is used for
          ``x_new > x[-1]``. Anything that is not a 2-element tuple (e.g.,
          list or ndarray, regardless of shape) is taken to be a single
          array-like argument meant to be used for both bounds as
          ``below, above = fill_value, fill_value``. Using a two-element tuple
          or ndarray requires ``bounds_error=False``.

          .. versionadded:: 0.17.0
        - If "extrapolate", then points outside the data range will be
          extrapolated.

          .. versionadded:: 0.17.0
    assume_sorted : bool, optional
        If False, values of `x` can be in any order and they are sorted first.
        If True, `x` has to be an array of monotonically increasing values.

    Attributes
    ----------
    fill_value

    Methods
    -------
    __call__

    See Also
    --------
    splrep, splev
        Spline interpolation/smoothing based on FITPACK.
    UnivariateSpline : An object-oriented wrapper of the FITPACK routines.
    interp2d : 2-D interpolation

    Notes
    -----
    Calling `interp1d` with NaNs present in input values results in
    undefined behaviour.

    Input values `x` and `y` must be convertible to `float` values like
    `int` or `float`.

    If the values in `x` are not unique, the resulting behavior is
    undefined and specific to the choice of `kind`, i.e., changing
    `kind` will change the behavior for duplicates.


    Examples
    --------
    >>> import numpy as np
    >>> import matplotlib.pyplot as plt
    >>> from scipy import interpolate
    >>> x = np.arange(0, 10)
    >>> y = np.exp(-x/3.0)
    >>> f = interpolate.interp1d(x, y)

    >>> xnew = np.arange(0, 9, 0.1)
    >>> ynew = f(xnew)   # use interpolation function returned by `interp1d`
    >>> plt.plot(x, y, 'o', xnew, ynew, '-')
    >>> plt.show()
    r(   r,   TNFc	                 C   s  t j| |||d || _|| _|s(t| _|dv rHddddd| }	d}n(t|tr\|}	d}n|dvrptd	| t|| jd
}t|| jd
}|st	j
|dd}
||
 }t	j||
|d}|jdkrtd|jdkrtdt|jjt	js|t	j}||j | _|| _| | j| _|| _~~|| _|dv rd}|dkr|d| _| jd | _| jdd | jdd  | _| jj| _q|dkrd| _| jd | _| jdd | jdd  | _| jj| _q|dkr"d| _d| _t	 | jt	j! | _"| jj#| _t$|r| %  t	j&t	| jd|f}n|dkr~d| _d| _t	 | jt	j!| _"| jj#| _t$|r| %  t	| jd|t	j&f}nnt	t	jt	tf}| jj|v o| jj|v }|o| jjdk}|ot$| }|r| jj'| _n
| jj(| _n|	d }d}| j| j }}|	dkrt	)| j}|* rp| j|  }|j+dkrHtdt	,t	-| jt	.| jt/| j}d}t	)| j* rt	0| j}d}t1|||	dd| _2|r| jj3| _n
| jj4| _t/| j|k rtd| || _5dS )z- Initialize a 1-D linear interpolation class.axis)zeroZslinearZ	quadraticr/   r   r   r)   r-   Zspline)r(   nearest
nearest-uppreviousnextz8%s is unsupported: Use fitpack routines for other types.r4   r\   r]   z,the x array must have exactly one dimension.z-the y array must have at least one dimension.rt   leftg       @Nr,   ru   rightrv   rw   Fz`x` array is all-nanT)r%   Zcheck_finitez,x and y arrays must have at least %d entries)6r   r[   rK   r5   r   rn   intNotImplementedErrorr	   rB   rD   Ztaker?   rA   
issubclassrh   typeZinexactastypefloat64rr   rM   Z_reshape_yi_yr   _kind_sidex_bds	__class___call_nearest_call_ind	nextafterinf_x_shift_call_previousnextrp   0_check_and_update_bounds_error_for_extrapolationnan_call_linear_np_call_linearisnanr_   r>   ZlinspaceZnanminZnanmaxr   Z	ones_liker   _spline_call_nan_spline_call_splinerL   )rS   r   rM   rT   rr   r5   rK   rL   ra   orderindminvalZ	np_dtypesZcondZrewrite_nanxxyymasksxr&   r&   r'   r[     s    















zinterp1d.__init__c                 C   s   | j S )zThe fill value.)_fill_value_origrS   r&   r&   r'   rL     s    zinterp1d.fill_valuec                 C   s   t |r|   d| _n| jjd | j | jj| jd d   }t|dkrPd}t|trt|dkrt	
|d t	
|d g}d}tdD ]}t|| ||| ||< qnt	
|}t||dgd }|\| _| _d| _| jd u rd| _|| _d S )	NTr   r   r   r)   )zfill_value (below)zfill_value (above)rL   F)rp   r   _extrapolaterM   r@   rr   r   rn   tuplerB   r   r   rl   _fill_value_below_fill_value_aboverK   r   )rS   rL   Zbroadcast_shapeZbelow_abovenamesiir&   r&   r'   rL     s8    

c                 C   s   | j rtdd| _ d S )Nz.Cannot extrapolate and raise at the same time.F)rK   rA   r   r&   r&   r'   r     s    z9interp1d._check_and_update_bounds_error_for_extrapolationc                 C   s   t || j| jS N)rB   Zinterpr   rM   rS   x_newr&   r&   r'   r     s    zinterp1d._call_linear_npc                 C   s   t | j|}|dt| jd t}|d }|}| j| }| j| }| j| }| j| }|| || d d d f  }	|	|| d d d f  | }
|
S )Nr   )r   r   clipr   r~   rz   r   )rS   r   x_new_indiceslohiZx_loZx_hiZy_loZy_hiZslopey_newr&   r&   r'   r     s    



zinterp1d._call_linearc                 C   s<   t | j|| jd}|dt| jd t}| j| }|S )z5 Find nearest neighbor interpolated y_new = f(x_new).Zsider   r   )	r   r   r   r   r   r   r~   r   r   rS   r   r   r   r&   r&   r'   r     s    
zinterp1d._call_nearestc                 C   sN   t | j|| jd}|d| j t| j| j t}| j	|| j d  }|S )z6Use previous/next neighbor of x_new, y_new = f(x_new).r   r   )
r   r   r   r   r   r   r   r~   r   r   r   r&   r&   r'   r     s    zinterp1d._call_previousnextc                 C   s
   |  |S r   )r   r   r&   r&   r'   r     s    zinterp1d._call_splinec                 C   s   |  |}tj|d< |S )N.)r   rB   r   )rS   r   outr&   r&   r'   r     s    

zinterp1d._call_nan_splinec                 C   sL   t |}| | |}| jsH| |\}}t|dkrH| j||< | j||< |S Nr   )r   r   r   _check_boundsr   r   r   )rS   r   r   below_boundsabove_boundsr&   r&   r'   	_evaluate  s    

zinterp1d._evaluatec                 C   s   || j d k }|| j d k}| jrT| rT|t| }td| d| j d  d| jr| r|t| }td| d| j d  d||fS )a  Check the inputs for being in the bounds of the interpolated data.

        Parameters
        ----------
        x_new : array

        Returns
        -------
        out_of_bounds : bool array
            The mask on x_new of values that are out of the bounds.
        r   r,   z	A value (z=) in x_new is below the interpolation range's minimum value (z).z=) in x_new is above the interpolation range's maximum value ()r   rK   r_   rB   ZargmaxrA   )rS   r   r   r   Zbelow_bounds_valueZabove_bounds_valuer&   r&   r'   r     s    



zinterp1d._check_bounds)rc   rd   re   rf   rB   r   r[   propertyrL   setterr   r   r   r   r   r   r   r   r   r&   r&   r&   r'   r     s&   l
 

r   c                   @   sN   e Zd ZdZdZdddZdd Zedd	d
Zdd Z	dd Z
dddZdS )
_PPolyBasez%Base class for piecewise polynomials.)rY   r   rm   rr   Nr   c                 C   s  t || _t j|t jd| _|d u r,d}n|dkr<t|}|| _| jjdk rVt	dd|  krr| jjd k sn t	d| d	| jjd  || _
|dkrt | j|d d| _t | j|d d| _| jjdkrt	d
| jjdk rt	d| jjdk rt	d| jjd dkr"t	d| jjd | jjd krDt	dt | j}t |dksxt |dksxt	d| | jj}t j| j|d| _d S )Nrh   Tperiodicr)   z2Coefficients array must be at least 2-dimensional.r   r   zaxis=z must be between 0 and zx must be 1-dimensionalz!at least 2 breakpoints are neededz!c must have at least 2 dimensionsz&polynomial must be at least of order 0z"number of coefficients != len(x)-1z.`x` must be strictly increasing or decreasing.)rB   r   rY   ascontiguousarrayr   r   boolrm   r?   rA   rr   Zmoveaxisr>   r@   diffrC   
_get_dtyperh   )rS   rY   r   rm   rr   r`   rh   r&   r&   r'   r[   +  s<     z_PPolyBase.__init__c                 C   s0   t |t js t | jjt jr&t jS t jS d S r   rB   
issubdtypecomplexfloatingrY   rh   
complex128r   rS   rh   r&   r&   r'   r   X  s
    z_PPolyBase._get_dtypec                 C   s2   t | }||_||_||_|du r(d}||_|S )aH  
        Construct the piecewise polynomial without making checks.

        Takes the same parameters as the constructor. Input arguments
        ``c`` and ``x`` must be arrays of the correct shape and type. The
        ``c`` array can only be of dtypes float and complex, and ``x``
        array must have dtype float.
        NT)object__new__rY   r   rr   rm   )clsrY   r   rm   rr   rS   r&   r&   r'   construct_fast_  s    

z_PPolyBase.construct_fastc                 C   s0   | j jjs| j  | _ | jjjs,| j | _dS )zr
        c and x may be modified by the user. The Cython code expects
        that they are C contiguous.
        N)r   flagsc_contiguousr5   rY   r   r&   r&   r'   _ensure_c_contiguousr  s    

z_PPolyBase._ensure_c_contiguousc                 C   s  t |}t |}|jdk r&td|jdkr8td|jd |jd krftd|j d|j d|jdd	 | jjdd	 ks|j| jjkrtd
|j| jj|jdkrd	S t |}t 	|dkst 	|dkstd| j
d | j
d krR|d |d kstd|d | j
d kr.d}n"|d | j
d krHd}ntdnV|d |d ksltd|d | j
d krd}n"|d | j
d krd}ntd| |j}t|jd | jjd }t j|| jjd |jd  f| jjdd	  |d}|dkrn| j||| jjd  d	d	| jjd f< ||||jd  d	| jjd d	f< t j| j
|f | _
nh|dkr|||| jjd  d	d	|jd f< | j|||jd  d	|jd d	f< t j|| j
f | _
|| _d	S )a#  
        Add additional breakpoints and coefficients to the polynomial.

        Parameters
        ----------
        c : ndarray, size (k, m, ...)
            Additional coefficients for polynomials in intervals. Note that
            the first additional interval will be formed using one of the
            ``self.x`` end points.
        x : ndarray, size (m,)
            Additional breakpoints. Must be sorted in the same order as
            ``self.x`` and either to the right or to the left of the current
            breakpoints.
        r)   zinvalid dimensions for cr   zinvalid dimensions for xr   zShapes of x z and c z are incompatibleNz-Shapes of c {} and self.c {} are incompatiblez`x` is not sorted.r,   z,`x` is in the different order than `self.x`.appendprependz9`x` is neither on the left or on the right from `self.x`.r   )rB   r   r?   rA   r@   rY   formatr>   r   rC   r   r   rh   maxzerosZr_)rS   rY   r   r`   actionrh   Zk2c2r&   r&   r'   extend|  s\    



,



,
*&
&&z_PPolyBase.extendc                 C   s&  |du r| j }t|}|j|j }}tj| tjd}|dkrr| jd || jd  | jd | jd    }d}tj	t
|t| jjdd f| jjd}|   | |||| ||| jjdd  }| jdkr"tt|j}|||| j  |d|  ||| j d  }||}|S )aX  
        Evaluate the piecewise polynomial or its derivative.

        Parameters
        ----------
        x : array_like
            Points to evaluate the interpolant at.
        nu : int, optional
            Order of derivative to evaluate. Must be non-negative.
        extrapolate : {bool, 'periodic', None}, optional
            If bool, determines whether to extrapolate to out-of-bounds points
            based on first and last intervals, or to return NaNs.
            If 'periodic', periodic extrapolation is used.
            If None (default), use `self.extrapolate`.

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

        Notes
        -----
        Derivatives are evaluated piecewise for each polynomial
        segment, even if the polynomial is not differentiable at the
        breakpoints. The polynomial intervals are considered half-open,
        ``[a, b)``, except for the last interval which is closed
        ``[a, b]``.
        Nr   r   r   r,   Fr)   )rm   rB   r   r@   r?   r   r   r   r   emptyr   r   rY   rh   r   r   reshaperr   listr   r
   )rS   r   nurm   x_shapeZx_ndimr   lr&   r&   r'   rb     s"    
,*0
z_PPolyBase.__call__)Nr   )Nr   )r   N)rc   rd   re   rf   	__slots__r[   r   classmethodr   r   r   rb   r&   r&   r&   r'   r   '  s   
-
Nr   c                   @   sf   e Zd ZdZdd ZdddZdddZdd
dZdddZdddZ	e
dddZe
dddZd	S )r   aL  
    Piecewise polynomial in terms of coefficients and breakpoints

    The polynomial between ``x[i]`` and ``x[i + 1]`` is written in the
    local power basis::

        S = sum(c[m, i] * (xp - x[i])**(k-m) for m in range(k+1))

    where ``k`` is the degree of the polynomial.

    Parameters
    ----------
    c : ndarray, shape (k, m, ...)
        Polynomial coefficients, order `k` and `m` intervals.
    x : ndarray, shape (m+1,)
        Polynomial breakpoints. Must be sorted in either increasing or
        decreasing order.
    extrapolate : bool or 'periodic', optional
        If bool, determines whether to extrapolate to out-of-bounds points
        based on first and last intervals, or to return NaNs. If 'periodic',
        periodic extrapolation is used. Default is True.
    axis : int, optional
        Interpolation axis. Default is zero.

    Attributes
    ----------
    x : ndarray
        Breakpoints.
    c : ndarray
        Coefficients of the polynomials. They are reshaped
        to a 3-D array with the last dimension representing
        the trailing dimensions of the original coefficient array.
    axis : int
        Interpolation axis.

    Methods
    -------
    __call__
    derivative
    antiderivative
    integrate
    solve
    roots
    extend
    from_spline
    from_bernstein_basis
    construct_fast

    See also
    --------
    BPoly : piecewise polynomials in the Bernstein basis

    Notes
    -----
    High-order polynomials in the power basis can be numerically
    unstable. Precision problems can start to appear for orders
    larger than 20-30.
    c                 C   s:   t | j| jjd | jjd d| j||t|| d S Nr   r   r,   )r   evaluaterY   r   r@   r   r   rS   r   r   rm   r   r&   r&   r'   r   <  s    "zPPoly._evaluater   c                 C   s   |dk r|  | S |dkr(| j }n| jd| ddf  }|jd dkrptjd|jdd  |jd}tt	|jd dd|}||t
dfd|jd    9 }| || j| j| jS )a  
        Construct a new piecewise polynomial representing the derivative.

        Parameters
        ----------
        nu : int, optional
            Order of derivative to evaluate. Default is 1, i.e., compute the
            first derivative. If negative, the antiderivative is returned.

        Returns
        -------
        pp : PPoly
            Piecewise polynomial of order k2 = k - n representing the derivative
            of this polynomial.

        Notes
        -----
        Derivatives are evaluated piecewise for each polynomial
        segment, even if the polynomial is not differentiable at the
        breakpoints. The polynomial intervals are considered half-open,
        ``[a, b)``, except for the last interval which is closed
        ``[a, b]``.
        r   Nr   r   r   r,   r   )antiderivativerY   r5   r@   rB   r   rh   specpocharangeslicer?   r   r   rm   rr   )rS   r   r   factorr&   r&   r'   
derivative@  s     zPPoly.derivativec                 C   s  |dkr|  | S tj| jjd | | jjd f| jjdd  | jjd}| j|d| < tt| jjd dd|}|d|   |t	dfd|j
d      < |   t||jd |jd d| j|d  | jdkrd	}n| j}| || j|| jS )
a=  
        Construct a new piecewise polynomial representing the antiderivative.

        Antiderivative is also the indefinite integral of the function,
        and derivative is its inverse operation.

        Parameters
        ----------
        nu : int, optional
            Order of antiderivative to evaluate. Default is 1, i.e., compute
            the first integral. If negative, the derivative is returned.

        Returns
        -------
        pp : PPoly
            Piecewise polynomial of order k2 = k + n representing
            the antiderivative of this polynomial.

        Notes
        -----
        The antiderivative returned by this function is continuous and
        continuously differentiable to order n-1, up to floating point
        rounding error.

        If antiderivative is computed and ``self.extrapolate='periodic'``,
        it will be set to False for the returned instance. This is done because
        the antiderivative is no longer periodic and its correct evaluation
        outside of the initially given x interval is difficult.
        r   r   r)   Nr   r,   r   r   F)r   rB   r   rY   r@   rh   r   r   r   r   r?   r   r   fix_continuityr   r   rm   r   rr   )rS   r   rY   r   rm   r&   r&   r'   r   l  s     ..

zPPoly.antiderivativeNc                 C   s(  |du r| j }d}||k r(|| }}d}tjt| jjdd f| jjd}|   |dkr| jd | jd  }}|| }|| }	t	|	|\}
}|
dkrt
j| j| jjd | jjd d| j||d|d	 ||
9 }n
|d ||| |  }|| }t|}||krLt
j| j| jjd | jjd d| j||d|d	 ||7 }nt
j| j| jjd | jjd d| j||d|d	 ||7 }t
j| j| jjd | jjd d| j||| | | d|d	 ||7 }n8t
j| j| jjd | jjd d| j||t||d	 ||9 }|| jjdd S )
a  
        Compute a definite integral over a piecewise polynomial.

        Parameters
        ----------
        a : float
            Lower integration bound
        b : float
            Upper integration bound
        extrapolate : {bool, 'periodic', None}, optional
            If bool, determines whether to extrapolate to out-of-bounds points
            based on first and last intervals, or to return NaNs.
            If 'periodic', periodic extrapolation is used.
            If None (default), use `self.extrapolate`.

        Returns
        -------
        ig : array_like
            Definite integral of the piecewise polynomial over [a, b]
        Nr   r,   r)   r   r   r   F)r   )rm   rB   r   r   rY   r@   rh   r   r   divmodr   	integrater   fillZ
empty_liker   )rS   r7   brm   signZ	range_intxsxeperiodinterval	n_periodsrx   Zremainder_intr&   r&   r'   r     sZ    
$






zPPoly.integrater   Tc                 C   s   |du r| j }|   t| jjtjr0tdt|}t	
| j| jjd | jjd d| j|t|t|}| jjdkr|d S tjt| jjdd td}t|D ]\}}|||< q|| jjdd S dS )a  
        Find real solutions of the equation ``pp(x) == y``.

        Parameters
        ----------
        y : float, optional
            Right-hand side. Default is zero.
        discontinuity : bool, optional
            Whether to report sign changes across discontinuities at
            breakpoints as roots.
        extrapolate : {bool, 'periodic', None}, optional
            If bool, determines whether to return roots from the polynomial
            extrapolated based on first and last intervals, 'periodic' works
            the same as False. If None (default), use `self.extrapolate`.

        Returns
        -------
        roots : ndarray
            Roots of the polynomial(s).

            If the PPoly object describes multiple polynomials, the
            return value is an object array whose each element is an
            ndarray containing the roots.

        Notes
        -----
        This routine works only on real-valued polynomials.

        If the piecewise polynomial contains sections that are
        identically zero, the root list will contain the start point
        of the corresponding interval, followed by a ``nan`` value.

        If the polynomial is discontinuous across a breakpoint, and
        there is a sign change across the breakpoint, this is reported
        if the `discont` parameter is True.

        Examples
        --------

        Finding roots of ``[x**2 - 1, (x - 1)**2]`` defined on intervals
        ``[-2, 1], [1, 2]``:

        >>> import numpy as np
        >>> from scipy.interpolate import PPoly
        >>> pp = PPoly(np.array([[1, -4, 3], [1, 0, 0]]).T, [-2, 1, 2])
        >>> pp.solve()
        array([-1.,  1.])
        Nz0Root finding is only for real-valued polynomialsr   r   r,   r)   r   )rm   r   rB   r   rY   rh   r   rA   floatr   Z
real_rootsr   r@   r   r   r?   r   r   r   	enumerate)rS   rM   discontinuityrm   rr2r   rootr&   r&   r'   solve  s     1"
zPPoly.solvec                 C   s   |  d||S )a[  
        Find real roots of the piecewise polynomial.

        Parameters
        ----------
        discontinuity : bool, optional
            Whether to report sign changes across discontinuities at
            breakpoints as roots.
        extrapolate : {bool, 'periodic', None}, optional
            If bool, determines whether to return roots from the polynomial
            extrapolated based on first and last intervals, 'periodic' works
            the same as False. If None (default), use `self.extrapolate`.

        Returns
        -------
        roots : ndarray
            Roots of the polynomial(s).

            If the PPoly object describes multiple polynomials, the
            return value is an object array whose each element is an
            ndarray containing the roots.

        See Also
        --------
        PPoly.solve
        r   )r   )rS   r   rm   r&   r&   r'   roots=  s    zPPoly.rootsc           	      C   s   t |tr&|j\}}}|du r0|j}n
|\}}}tj|d t|d f|jd}t|ddD ]>}t	j
|dd ||d}|t|d  ||| ddf< q\| |||S )a	  
        Construct a piecewise polynomial from a spline

        Parameters
        ----------
        tck
            A spline, as returned by `splrep` or a BSpline object.
        extrapolate : bool or 'periodic', optional
            If bool, determines whether to extrapolate to out-of-bounds points
            based on first and last intervals, or to return NaNs.
            If 'periodic', periodic extrapolation is used. Default is True.

        Examples
        --------
        Construct an interpolating spline and convert it to a `PPoly` instance 

        >>> import numpy as np
        >>> from scipy.interpolate import splrep, PPoly
        >>> x = np.linspace(0, 1, 11)
        >>> y = np.sin(2*np.pi*x)
        >>> tck = splrep(x, y, s=0)
        >>> p = PPoly.from_spline(tck)
        >>> isinstance(p, PPoly)
        True

        Note that this function only supports 1D splines out of the box.

        If the ``tck`` object represents a parametric spline (e.g. constructed
        by `splprep` or a `BSpline` with ``c.ndim > 1``), you will need to loop
        over the dimensions manually.

        >>> from scipy.interpolate import splprep, splev
        >>> t = np.linspace(0, 1, 11)
        >>> x = np.sin(2*np.pi*t)
        >>> y = np.cos(2*np.pi*t)
        >>> (t, c, k), u = splprep([x, y], s=0)

        Note that ``c`` is a list of two arrays of length 11.

        >>> unew = np.arange(0, 1.01, 0.01)
        >>> out = splev(unew, (t, c, k))

        To convert this spline to the power basis, we convert each
        component of the list of b-spline coefficients, ``c``, into the
        corresponding cubic polynomial.

        >>> polys = [PPoly.from_spline((t, cj, k)) for cj in c]
        >>> polys[0].c.shape
        (4, 14)

        Note that the coefficients of the polynomials `polys` are in the
        power basis and their dimensions reflect just that: here 4 is the order
        (degree+1), and 14 is the number of intervals---which is nothing but
        the length of the knot array of the original `tck` minus one.

        Optionally, we can stack the components into a single `PPoly` along
        the third dimension:

        >>> cc = np.dstack([p.c for p in polys])    # has shape = (4, 14, 2)
        >>> poly = PPoly(cc, polys[0].x)
        >>> np.allclose(poly(unew).T,     # note the transpose to match `splev`
        ...             out, atol=1e-15)
        True

        Nr   r   r,   )Zder)rn   r   rJ   rm   rB   r   r   rh   r   r   Zsplevr   gammar   )	r   rJ   rm   rj   rY   r%   ZcvalsmrM   r&   r&   r'   from_splineZ  s    C

 $zPPoly.from_splinec              	   C   s   t |tstdt| t|j}|jjd d }d|jj	d  }t
|j}t|d D ]|}d| t|| |j|  }t||d D ]L}	t|| |	| d|	  }
|||	   ||
 |tdf|  |	  7  < qq^|du r|j}| ||j||jS )a  
        Construct a piecewise polynomial in the power basis
        from a polynomial in Bernstein basis.

        Parameters
        ----------
        bp : BPoly
            A Bernstein basis polynomial, as created by BPoly
        extrapolate : bool or 'periodic', optional
            If bool, determines whether to extrapolate to out-of-bounds points
            based on first and last intervals, or to return NaNs.
            If 'periodic', periodic extrapolation is used. Default is True.
        zC.from_bernstein_basis only accepts BPoly instances. Got %s instead.r   r   r   r)   r,   N)rn   r   	TypeErrorr}   rB   r   r   rY   r@   r?   
zeros_liker   r   r   rm   r   rr   )r   bprm   r`   r%   restrY   r7   r   r3   valr&   r&   r'   from_bernstein_basis  s     
2zPPoly.from_bernstein_basis)r   )r   )N)r   TN)TN)N)N)rc   rd   re   rf   r   r   r   r   r   r   r   r   r   r&   r&   r&   r'   r      s   ;
,
6
R
I
Pr   c                   @   s|   e Zd ZdZdd ZdddZdddZdd
dZdd Ze	jje_e
dddZe
dddZedd Zedd Zd	S )r   a	  Piecewise polynomial in terms of coefficients and breakpoints.

    The polynomial between ``x[i]`` and ``x[i + 1]`` is written in the
    Bernstein polynomial basis::

        S = sum(c[a, i] * b(a, k; x) for a in range(k+1)),

    where ``k`` is the degree of the polynomial, and::

        b(a, k; x) = binom(k, a) * t**a * (1 - t)**(k - a),

    with ``t = (x - x[i]) / (x[i+1] - x[i])`` and ``binom`` is the binomial
    coefficient.

    Parameters
    ----------
    c : ndarray, shape (k, m, ...)
        Polynomial coefficients, order `k` and `m` intervals
    x : ndarray, shape (m+1,)
        Polynomial breakpoints. Must be sorted in either increasing or
        decreasing order.
    extrapolate : bool, optional
        If bool, determines whether to extrapolate to out-of-bounds points
        based on first and last intervals, or to return NaNs. If 'periodic',
        periodic extrapolation is used. Default is True.
    axis : int, optional
        Interpolation axis. Default is zero.

    Attributes
    ----------
    x : ndarray
        Breakpoints.
    c : ndarray
        Coefficients of the polynomials. They are reshaped
        to a 3-D array with the last dimension representing
        the trailing dimensions of the original coefficient array.
    axis : int
        Interpolation axis.

    Methods
    -------
    __call__
    extend
    derivative
    antiderivative
    integrate
    construct_fast
    from_power_basis
    from_derivatives

    See also
    --------
    PPoly : piecewise polynomials in the power basis

    Notes
    -----
    Properties of Bernstein polynomials are well documented in the literature,
    see for example [1]_ [2]_ [3]_.

    References
    ----------
    .. [1] https://en.wikipedia.org/wiki/Bernstein_polynomial

    .. [2] Kenneth I. Joy, Bernstein polynomials,
       http://www.idav.ucdavis.edu/education/CAGDNotes/Bernstein-Polynomials.pdf

    .. [3] E. H. Doha, A. H. Bhrawy, and M. A. Saker, Boundary Value Problems,
           vol 2011, article ID 829546, :doi:`10.1155/2011/829543`.

    Examples
    --------
    >>> from scipy.interpolate import BPoly
    >>> x = [0, 1]
    >>> c = [[1], [2], [3]]
    >>> bp = BPoly(c, x)

    This creates a 2nd order polynomial

    .. math::

        B(x) = 1 \times b_{0, 2}(x) + 2 \times b_{1, 2}(x) + 3
               \times b_{2, 2}(x) \\
             = 1 \times (1-x)^2 + 2 \times 2 x (1 - x) + 3 \times x^2

    c                 C   s:   t | j| jjd | jjd d| j||t|| d S r   )r   Zevaluate_bernsteinrY   r   r@   r   r   r   r&   r&   r'   r   '  s    zBPoly._evaluater   c                 C   s   |dk r|  | S |dkr:| }t|D ]}| }q(|S |dkrN| j }nTd| jjd  }| jjd d }t| j	dt
df|  }|tj| jdd | }|jd dkrtjd|jdd  |jd}| || j	| j| jS )	a  
        Construct a new piecewise polynomial representing the derivative.

        Parameters
        ----------
        nu : int, optional
            Order of derivative to evaluate. Default is 1, i.e., compute the
            first derivative. If negative, the antiderivative is returned.

        Returns
        -------
        bp : BPoly
            Piecewise polynomial of order k - nu representing the derivative of
            this polynomial.

        r   r   r   r)   Nrq   r   r   )r   r   r   rY   r5   r?   r@   rB   r   r   r   r   rh   r   rm   rr   )rS   r   r   r%   r   r   r`   r&   r&   r'   r   ,  s     
zBPoly.derivativec           	      C   s4  |dkr|  | S |dkr:| }t|D ]}| }q(|S | j| j }}|jd }tj|d f|jdd  |jd}tj	|dd| |dddf< |dd |dd  }||dt
dfd|jd	    9 }|ddddf  tj	||ddf dddd 7  < | jd
krd}n| j}| j|||| jdS )a  
        Construct a new piecewise polynomial representing the antiderivative.

        Parameters
        ----------
        nu : int, optional
            Order of antiderivative to evaluate. Default is 1, i.e., compute
            the first integral. If negative, the derivative is returned.

        Returns
        -------
        bp : BPoly
            Piecewise polynomial of order k + nu representing the
            antiderivative of this polynomial.

        Notes
        -----
        If antiderivative is computed and ``self.extrapolate='periodic'``,
        it will be set to False for the returned instance. This is done because
        the antiderivative is no longer periodic and its correct evaluation
        outside of the initially given x interval is difficult.
        r   r   Nr   rq   .r,   r   r)   r   F)r   r   r   rY   r   r@   rB   r   rh   Zcumsumr   r?   rm   r   rr   )	rS   r   r   r%   rY   r   r   deltarm   r&   r&   r'   r   a  s$    

$":zBPoly.antiderivativeNc                 C   s  |   }|du r| j}|dkr$||_|dkr ||kr<d}n|| }}d}| jd | jd  }}|| }|| }	t|	|\}
}|
||||  }||| |  }|| }||kr||||| 7 }n0||||| ||| | |  || 7 }|| S |||| S dS )at  
        Compute a definite integral over a piecewise polynomial.

        Parameters
        ----------
        a : float
            Lower integration bound
        b : float
            Upper integration bound
        extrapolate : {bool, 'periodic', None}, optional
            Whether to extrapolate to out-of-bounds points based on first
            and last intervals, or to return NaNs. If 'periodic', periodic
            extrapolation is used. If None (default), use `self.extrapolate`.

        Returns
        -------
        array_like
            Definite integral of the piecewise polynomial over [a, b]

        Nr   r   r,   r   )r   rm   r   r   )rS   r7   r   rm   ibr   r   r   r   r   r   rx   resr&   r&   r'   r     s,    

0zBPoly.integratec                 C   sX   t | jjd |jd }| | j|| jjd  | _| |||jd  }t| ||S r   )r   rY   r@   _raise_degreer   r   )rS   rY   r   r%   r&   r&   r'   r     s    zBPoly.extendc           
   
   C   s   t |tstdt| t|j}|jjd d }d|jj	d  }t
|j}t|d D ]l}|j| t|||  |tdf|  ||   }t|| |d D ]"}	||	  |t|	||  7  < qq^|du r|j}| ||j||jS )a  
        Construct a piecewise polynomial in Bernstein basis
        from a power basis polynomial.

        Parameters
        ----------
        pp : PPoly
            A piecewise polynomial in the power basis
        extrapolate : bool or 'periodic', optional
            If bool, determines whether to extrapolate to out-of-bounds points
            based on first and last intervals, or to return NaNs.
            If 'periodic', periodic extrapolation is used. Default is True.
        z?.from_power_basis only accepts PPoly instances. Got %s instead.r   r   r   r)   N)rn   r   r   r}   rB   r   r   rY   r@   r?   r   r   r   r   rm   r   rr   )
r   pprm   r`   r%   r   rY   r7   r   r#   r&   r&   r'   from_power_basis  s    
2"zBPoly.from_power_basisc              
      sf  t |}t|t kr"tdt |dd |dd  dkrLtdt|d }zt fddt|D }W n. ty } ztd|W Y d}~n
d}~0 0 |du rdg| }nBt|t	t j
fr|g| }t|t|}td	d |D rtd
g }t|D ]<}	 |	  |	d   }
}||	 du rFt|
t| }}n||	 d }t|d t|
}t|| t|}t|| t|}|| |krd||	 t|
||	d  t|||	 f }t||t|
kr|t|kstdt||	 ||	d  |
d| |d| }t||k r:t||t| }|| qt |}| |dd||S )a6
  Construct a piecewise polynomial in the Bernstein basis,
        compatible with the specified values and derivatives at breakpoints.

        Parameters
        ----------
        xi : array_like
            sorted 1-D array of x-coordinates
        yi : array_like or list of array_likes
            ``yi[i][j]`` is the ``j``\ th derivative known at ``xi[i]``
        orders : None or int or array_like of ints. Default: None.
            Specifies the degree of local polynomials. If not None, some
            derivatives are ignored.
        extrapolate : bool or 'periodic', optional
            If bool, determines whether to extrapolate to out-of-bounds points
            based on first and last intervals, or to return NaNs.
            If 'periodic', periodic extrapolation is used. Default is True.

        Notes
        -----
        If ``k`` derivatives are specified at a breakpoint ``x``, the
        constructed polynomial is exactly ``k`` times continuously
        differentiable at ``x``, unless the ``order`` is provided explicitly.
        In the latter case, the smoothness of the polynomial at
        the breakpoint is controlled by the ``order``.

        Deduces the number of derivatives to match at each end
        from ``order`` and the number of derivatives available. If
        possible it uses the same number of derivatives from
        each end; if the number is odd it tries to take the
        extra one from y2. In any case if not enough derivatives
        are available at one end or another it draws enough to
        make up the total from the other end.

        If the order is too high and not enough derivatives are available,
        an exception is raised.

        Examples
        --------

        >>> from scipy.interpolate import BPoly
        >>> BPoly.from_derivatives([0, 1], [[1, 2], [3, 4]])

        Creates a polynomial `f(x)` of degree 3, defined on `[0, 1]`
        such that `f(0) = 1, df/dx(0) = 2, f(1) = 3, df/dx(1) = 4`

        >>> BPoly.from_derivatives([0, 1, 2], [[0, 1], [0], [2]])

        Creates a piecewise polynomial `f(x)`, such that
        `f(0) = f(1) = 0`, `f(2) = 2`, and `df/dx(0) = 1`.
        Based on the number of derivatives provided, the order of the
        local polynomials is 2 on `[0, 1]` and 1 on `[1, 2]`.
        Notice that no restriction is imposed on the derivatives at
        ``x = 1`` and ``x = 2``.

        Indeed, the explicit form of the polynomial is::

            f(x) = | x * (1 - x),  0 <= x < 1
                   | 2 * (x - 1),  1 <= x <= 2

        So that f'(1-0) = -1 and f'(1+0) = 2

        z&xi and yi need to have the same lengthr   Nr   z)x coordinates are not in increasing orderc                 3   s*   | ]"}t  | t  |d    V  qdS r   N)r   )r6   iyir&   r'   r8   N  r9   z)BPoly.from_derivatives.<locals>.<genexpr>z0Using a 1-D array for y? Please .reshape(-1, 1).c                 s   s   | ]}|d kV  qdS )r   Nr&   )r6   or&   r&   r'   r8   [  r9   zOrders must be positive.r)   zPPoint %g has %d derivatives, point %g has %d derivatives, but order %d requestedz0`order` input incompatible with length y1 or y2.)rB   r   r   rA   r_   r   r   r   rn   rz   integerminr   _construct_from_derivativesr  r   Zswapaxes)r   xir  Zordersrm   r   r%   rU   rY   r  y1y2Zn1Zn2nZmesgr   r&   r  r'   from_derivatives  s\    @
"
"
zBPoly.from_derivativesc              
   C   s  t |t | }}|jdd |jdd krFtd|j|j|j|j }}t |t jspt |t jrxt j}nt j	}t
|t
| }}|| }	t j|| f|jdd  |d}
td|D ]h}|| t|	| | ||  |  |
|< td|D ]0}|
|  d||  t|| |
|  8  <  qqtd|D ]}|| t|	| | d|  ||  |  |
| d < td|D ]@}|
| d   d|d  t||d  |
| |   8  < q|q8|
S )aL  Compute the coefficients of a polynomial in the Bernstein basis
        given the values and derivatives at the edges.

        Return the coefficients of a polynomial in the Bernstein basis
        defined on ``[xa, xb]`` and having the values and derivatives at the
        endpoints `xa` and `xb` as specified by `ya` and `yb`.
        The polynomial constructed is of the minimal possible degree, i.e.,
        if the lengths of `ya` and `yb` are `na` and `nb`, the degree
        of the polynomial is ``na + nb - 1``.

        Parameters
        ----------
        xa : float
            Left-hand end point of the interval
        xb : float
            Right-hand end point of the interval
        ya : array_like
            Derivatives at `xa`. ``ya[0]`` is the value of the function, and
            ``ya[i]`` for ``i > 0`` is the value of the ``i``\ th derivative.
        yb : array_like
            Derivatives at `xb`.

        Returns
        -------
        array
            coefficient array of a polynomial having specified derivatives

        Notes
        -----
        This uses several facts from life of Bernstein basis functions.
        First of all,

            .. math:: b'_{a, n} = n (b_{a-1, n-1} - b_{a, n-1})

        If B(x) is a linear combination of the form

            .. math:: B(x) = \sum_{a=0}^{n} c_a b_{a, n},

        then :math: B'(x) = n \sum_{a=0}^{n-1} (c_{a+1} - c_{a}) b_{a, n-1}.
        Iterating the latter one, one finds for the q-th derivative

            .. math:: B^{q}(x) = n!/(n-q)! \sum_{a=0}^{n-q} Q_a b_{a, n-q},

        with

          .. math:: Q_a = \sum_{j=0}^{q} (-)^{j+q} comb(q, j) c_{j+a}

        This way, only `a=0` contributes to :math: `B^{q}(x = xa)`, and
        `c_q` are found one by one by iterating `q = 0, ..., na`.

        At ``x = xb`` it's the same with ``a = n - q``.

        r   Nz*Shapes of ya {} and yb {} are incompatibler   r   r,   )rB   r   r@   rA   r   rh   r   r   r   r   r   r   r   r   r   r   )ZxaxbZyaZybZdtaZdtbdtnanbr  rY   qr#   r&   r&   r'   r  {  s.    7"(06Bz!BPoly._construct_from_derivativesc              
   C   s   |dkr| S | j d d }tj| j d | f| j dd  | jd}t| j d D ]X}| | t|| }t|d D ]4}|||   |t|| t|| ||  7  < qtqR|S )a  Raise a degree of a polynomial in the Bernstein basis.

        Given the coefficients of a polynomial degree `k`, return (the
        coefficients of) the equivalent polynomial of degree `k+d`.

        Parameters
        ----------
        c : array_like
            coefficient array, 1-D
        d : integer

        Returns
        -------
        array
            coefficient array, 1-D array of length `c.shape[0] + d`

        Notes
        -----
        This uses the fact that a Bernstein polynomial `b_{a, k}` can be
        identically represented as a linear combination of polynomials of
        a higher degree `k+d`:

            .. math:: b_{a, k} = comb(k, a) \sum_{j=0}^{d} b_{a+j, k+d} \
                                 comb(d, j) / comb(k+d, a+j)

        r   r   Nr   )r@   rB   r   rh   r   r   )rY   dr%   r   r7   rk   r#   r&   r&   r'   r    s    *4zBPoly._raise_degree)r   )r   )N)N)NN)rc   rd   re   rf   r   r   r   r   r   r   r   r  r  staticmethodr  r  r&   r&   r&   r'   r     s   V
5
8
@
"w
Vr   c                   @   sv   e Zd ZdZdddZedddZdd Zd	d
 ZdddZ	dd Z
dd Zdd Zdd ZdddZdddZdS )r   aW  
    Piecewise tensor product polynomial

    The value at point ``xp = (x', y', z', ...)`` is evaluated by first
    computing the interval indices `i` such that::

        x[0][i[0]] <= x' < x[0][i[0]+1]
        x[1][i[1]] <= y' < x[1][i[1]+1]
        ...

    and then computing::

        S = sum(c[k0-m0-1,...,kn-mn-1,i[0],...,i[n]]
                * (xp[0] - x[0][i[0]])**m0
                * ...
                * (xp[n] - x[n][i[n]])**mn
                for m0 in range(k[0]+1)
                ...
                for mn in range(k[n]+1))

    where ``k[j]`` is the degree of the polynomial in dimension j. This
    representation is the piecewise multivariate power basis.

    Parameters
    ----------
    c : ndarray, shape (k0, ..., kn, m0, ..., mn, ...)
        Polynomial coefficients, with polynomial order `kj` and
        `mj+1` intervals for each dimension `j`.
    x : ndim-tuple of ndarrays, shapes (mj+1,)
        Polynomial breakpoints for each dimension. These must be
        sorted in increasing order.
    extrapolate : bool, optional
        Whether to extrapolate to out-of-bounds points based on first
        and last intervals, or to return NaNs. Default: True.

    Attributes
    ----------
    x : tuple of ndarrays
        Breakpoints.
    c : ndarray
        Coefficients of the polynomials.

    Methods
    -------
    __call__
    derivative
    antiderivative
    integrate
    integrate_1d
    construct_fast

    See also
    --------
    PPoly : piecewise polynomials in 1D

    Notes
    -----
    High-order polynomials in the power basis can be numerically
    unstable.

    Nc                 C   s   t dd |D | _t|| _|d u r,d}t|| _t| j}tdd | jD r\t	dtdd | jD rxt	d|j
d| k rt	d	td
d | jD rt	dtdd t|j|d|  | jD rt	d| | jj}tj| j|d| _d S )Nc                 s   s   | ]}t j|t jd V  qdS )r   N)rB   r   r   r6   vr&   r&   r'   r8   ;  r9   z#NdPPoly.__init__.<locals>.<genexpr>Tc                 s   s   | ]}|j d kV  qdS r  )r?   r  r&   r&   r'   r8   B  r9   z"x arrays must all be 1-dimensionalc                 s   s   | ]}|j d k V  qdS )r)   Nr>   r  r&   r&   r'   r8   D  r9   z+x arrays must all contain at least 2 pointsr)   z(c must have at least 2*len(x) dimensionsc                 s   s0   | ](}t |d d |dd  dk V  qdS )r   Nr,   r   )rB   r_   r  r&   r&   r'   r8   H  r9   z)x-coordinates are not in increasing orderc                 s   s    | ]\}}||j d  kV  qdS r  r  )r6   r7   r   r&   r&   r'   r8   J  r9   z/x and c do not agree on the number of intervalsr   )r   r   rB   r   rY   r   rm   r   r_   rA   r?   rg   r@   r   rh   r   )rS   rY   r   rm   r?   rh   r&   r&   r'   r[   :  s$    

(zNdPPoly.__init__c                 C   s,   t | }||_||_|du r"d}||_|S )aJ  
        Construct the piecewise polynomial without making checks.

        Takes the same parameters as the constructor. Input arguments
        ``c`` and ``x`` must be arrays of the correct shape and type.  The
        ``c`` array can only be of dtypes float and complex, and ``x``
        array must have dtype float.

        NT)r   r   rY   r   rm   )r   rY   r   rm   rS   r&   r&   r'   r   P  s    
zNdPPoly.construct_fastc                 C   s0   t |t js t | jjt jr&t jS t jS d S r   r   r   r&   r&   r'   r   c  s
    zNdPPoly._get_dtypec                 C   s2   | j jjs| j  | _ t| jts.t| j| _d S r   )rY   r   r   r5   rn   r   r   r   r&   r&   r'   r   j  s    
zNdPPoly._ensure_c_contiguousc              	   C   sl  |du r| j }nt|}t| j}t|}|j}tj|d|jd tj	d}|du rjtj
|ftjd}n0tj|tjd}|jdks|jd |krtdt| jjd| }t| jj|d|  }t| jjd| d }tj| jjd| tjd}	tj|jd |f| jjd}
|   t| j|||| j|	||t||
 |
|dd | jjd| d  S )a  
        Evaluate the piecewise polynomial or its derivative

        Parameters
        ----------
        x : array-like
            Points to evaluate the interpolant at.
        nu : tuple, optional
            Orders of derivatives to evaluate. Each must be non-negative.
        extrapolate : bool, optional
            Whether to extrapolate to out-of-bounds points based on first
            and last intervals, or to return NaNs.

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

        Notes
        -----
        Derivatives are evaluated piecewise for each polynomial
        segment, even if the polynomial is not differentiable at the
        breakpoints. The polynomial intervals are considered half-open,
        ``[a, b)``, except for the last interval which is closed
        ``[a, b]``.

        Nr,   r   r   r   z&invalid number of derivative orders nur)   )rm   r   r   r   r   r@   rB   r   r   r   r   Zintcr   r?   rA   r   rY   r	   r   rh   r   r   Zevaluate_nd)rS   r   r   rm   r?   r   Zdim1Zdim2Zdim3ksr   r&   r&   r'   rb   p  s6    
zNdPPoly.__call__c                 C   s   |dk r|  | |S t| j}|| }|dkr4dS tdg| }td| d||< | jt| }|j| dkrt|j}d||< tj	||j
d}tt|j| dd|}dg|j }td||< ||t| 9 }|| _dS )zz
        Compute 1-D derivative along a selected dimension in-place
        May result to non-contiguous c array.
        r   Nr   r   r,   )_antiderivative_inplacer   r   r   rY   r   r@   r   rB   r   rh   r   r   r   r?   )rS   r   rr   r?   slr   Zshpr   r&   r&   r'   _derivative_inplace  s$    

zNdPPoly._derivative_inplacec           	      C   s  |dkr|  | |S t| j}|| }tt|}|| |d  |d< ||< |tt|| jj }| j|}tj	|j
d | f|j
dd  |jd}||d| < tt|j
d dd|}|d|   |tdfd|jd      < tt|j}|||  |d  |d< ||| < ||}| }t||j
d |j
d d| j| |d  ||}||}|| _dS )zu
        Compute 1-D antiderivative along a selected dimension
        May result to non-contiguous c array.
        r   r   Nr   r,   r   )r  r   r   r   r   rY   r?   r
   rB   r   r@   rh   r   r   r   r   r5   r   r   r   )	rS   r   rr   r?   permrY   r   r   Zperm2r&   r&   r'   r    s0    
 ."


zNdPPoly._antiderivative_inplacec                 C   sB   |  | j | j| j}t|D ]\}}||| q |  |S )a$  
        Construct a new piecewise polynomial representing the derivative.

        Parameters
        ----------
        nu : ndim-tuple of int
            Order of derivatives to evaluate for each dimension.
            If negative, the antiderivative is returned.

        Returns
        -------
        pp : NdPPoly
            Piecewise polynomial of orders (k[0] - nu[0], ..., k[n] - nu[n])
            representing the derivative of this polynomial.

        Notes
        -----
        Derivatives are evaluated piecewise for each polynomial
        segment, even if the polynomial is not differentiable at the
        breakpoints. The polynomial intervals in each dimension are
        considered half-open, ``[a, b)``, except for the last interval
        which is closed ``[a, b]``.

        )r   rY   r5   r   rm   r   r  r   rS   r   r"   rr   r  r&   r&   r'   r     s
    zNdPPoly.derivativec                 C   sB   |  | j | j| j}t|D ]\}}||| q |  |S )a  
        Construct a new piecewise polynomial representing the antiderivative.

        Antiderivative is also the indefinite integral of the function,
        and derivative is its inverse operation.

        Parameters
        ----------
        nu : ndim-tuple of int
            Order of derivatives to evaluate for each dimension.
            If negative, the derivative is returned.

        Returns
        -------
        pp : PPoly
            Piecewise polynomial of order k2 = k + n representing
            the antiderivative of this polynomial.

        Notes
        -----
        The antiderivative returned by this function is continuous and
        continuously differentiable to order n-1, up to floating point
        rounding error.

        )r   rY   r5   r   rm   r   r  r   r!  r&   r&   r'   r   	  s
    zNdPPoly.antiderivativec                 C   s(  |du r| j }nt|}t| j}t|| }| j}tt|j}|	d||  ||d = |	d|||   ||| d = |
|}tj||jd |jd d| j| |d}|j|||d}	|dkr|	|jdd S |	|jdd }| jd| | j|d d  }
| j||
|dS dS )a  
        Compute NdPPoly representation for one dimensional definite integral

        The result is a piecewise polynomial representing the integral:

        .. math::

           p(y, z, ...) = \int_a^b dx\, p(x, y, z, ...)

        where the dimension integrated over is specified with the
        `axis` parameter.

        Parameters
        ----------
        a, b : float
            Lower and upper bound for integration.
        axis : int
            Dimension over which to compute the 1-D integrals
        extrapolate : bool, optional
            Whether to extrapolate to out-of-bounds points based on first
            and last intervals, or to return NaNs.

        Returns
        -------
        ig : NdPPoly or array-like
            Definite integral of the piecewise polynomial over [a, b].
            If the polynomial was 1D, an array is returned,
            otherwise, an NdPPoly object.

        Nr   r   r,   rm   r)   )rm   r   r   r   rz   rY   r   r   r?   insertr
   r   r   r   r@   r   )rS   r7   r   rr   rm   r?   rY   swapr"   r   r   r&   r&   r'   integrate_1d>	  s,    


 zNdPPoly.integrate_1dc                 C   s   t | j}|du r| j}nt|}t|dr8t ||kr@td|   | j}t|D ]\}\}}t	t
|j}|d|||   ||| d = ||}tj|| j| |d}	|	j|||d}
|
|jdd }qV|S )aq  
        Compute a definite integral over a piecewise polynomial.

        Parameters
        ----------
        ranges : ndim-tuple of 2-tuples float
            Sequence of lower and upper bounds for each dimension,
            ``[(a[0], b[0]), ..., (a[ndim-1], b[ndim-1])]``
        extrapolate : bool, optional
            Whether to extrapolate to out-of-bounds points based on first
            and last intervals, or to return NaNs.

        Returns
        -------
        ig : array_like
            Definite integral of the piecewise polynomial over
            [a[0], b[0]] x ... x [a[ndim-1], b[ndim-1]]

        N__len__z&Range not a sequence of correct lengthr   r"  r)   )r   r   rm   r   hasattrrA   r   rY   r   r   r   r?   r#  r
   r   r   r   r   r@   )rS   rangesrm   r?   rY   r  r7   r   r$  r"   r   r&   r&   r'   r   {	  s"    

zNdPPoly.integrate)N)N)NN)N)N)rc   rd   re   rf   r[   r   r   r   r   rb   r  r  r   r   r%  r   r&   r&   r&   r'   r     s   >

A"(!"
=r   )*__all__mathr   r:   numpyrB   r	   r
   r   r   r   r   r   r   r   Zscipy.specialZspecialr   Zscipy._lib._utilr   r    r   r   Z_polyintr   r   Zinterpndr   Z	_bsplinesr   r   r   r<   r   rl   rp   r   r   r   r   r   r&   r&   r&   r'   <module>   sH   ,J      ' Z   S    /