a
    a                     @   s   d dl Z d dlZd dlmZ d dl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 g d	Zd
d Zd'ddZG d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#d$Zd)d%d&Z dS )*    N)normalize_axis_index)get_lapack_funcsLinAlgErrorcholesky_bandedcho_solve_bandedsolvesolve_banded   )_bspl)_fitpack_impl)_fitpack)prod)BSplinemake_interp_splinemake_lsq_splinec                 C   s   t | t jrt jS t jS dS )z>Return np.complex128 for complex dtypes, np.float64 otherwise.N)npZ
issubdtypeZcomplexfloatingZcomplex_float_dtype r   k/Users/vegardjervell/Documents/master/model/venv/lib/python3.9/site-packages/scipy/interpolate/_bsplines.py
_get_dtype   s    r   Fc                 C   s@   t | } t| j}| j|dd} |r<t |  s<td| S )zConvert the input into a C contiguous float array.

    NB: Upcasts half- and single-precision floats to double precision.
    F)copyz$Array must not contain infs or nans.)r   ascontiguousarrayr   r   Zastypeisfiniteall
ValueError)xcheck_finiteZdtypr   r   r   _as_float_array   s    

r   c                       s   e Zd ZdZd fdd	ZedddZedd	 Zedd
dZ	dddZ
dd Zdd ZdddZdddZd ddZ  ZS )!r   a  Univariate spline in the B-spline basis.

    .. math::

        S(x) = \sum_{j=0}^{n-1} c_j  B_{j, k; t}(x)

    where :math:`B_{j, k; t}` are B-spline basis functions of degree `k`
    and knots `t`.

    Parameters
    ----------
    t : ndarray, shape (n+k+1,)
        knots
    c : ndarray, shape (>=n, ...)
        spline coefficients
    k : int
        B-spline degree
    extrapolate : bool or 'periodic', optional
        whether to extrapolate beyond the base interval, ``t[k] .. t[n]``,
        or to return nans.
        If True, extrapolates the first and last polynomial pieces of b-spline
        functions active on the base interval.
        If 'periodic', periodic extrapolation is used.
        Default is True.
    axis : int, optional
        Interpolation axis. Default is zero.

    Attributes
    ----------
    t : ndarray
        knot vector
    c : ndarray
        spline coefficients
    k : int
        spline degree
    extrapolate : bool
        If True, extrapolates the first and last polynomial pieces of b-spline
        functions active on the base interval.
    axis : int
        Interpolation axis.
    tck : tuple
        A read-only equivalent of ``(self.t, self.c, self.k)``

    Methods
    -------
    __call__
    basis_element
    derivative
    antiderivative
    integrate
    construct_fast

    Notes
    -----
    B-spline basis elements are defined via

    .. math::

        B_{i, 0}(x) = 1, \textrm{if $t_i \le x < t_{i+1}$, otherwise $0$,}

        B_{i, k}(x) = \frac{x - t_i}{t_{i+k} - t_i} B_{i, k-1}(x)
                 + \frac{t_{i+k+1} - x}{t_{i+k+1} - t_{i+1}} B_{i+1, k-1}(x)

    **Implementation details**

    - At least ``k+1`` coefficients are required for a spline of degree `k`,
      so that ``n >= k+1``. Additional coefficients, ``c[j]`` with
      ``j > n``, are ignored.

    - B-spline basis elements of degree `k` form a partition of unity on the
      *base interval*, ``t[k] <= x <= t[n]``.


    Examples
    --------

    Translating the recursive definition of B-splines into Python code, we have:

    >>> def B(x, k, i, t):
    ...    if k == 0:
    ...       return 1.0 if t[i] <= x < t[i+1] else 0.0
    ...    if t[i+k] == t[i]:
    ...       c1 = 0.0
    ...    else:
    ...       c1 = (x - t[i])/(t[i+k] - t[i]) * B(x, k-1, i, t)
    ...    if t[i+k+1] == t[i+1]:
    ...       c2 = 0.0
    ...    else:
    ...       c2 = (t[i+k+1] - x)/(t[i+k+1] - t[i+1]) * B(x, k-1, i+1, t)
    ...    return c1 + c2

    >>> def bspline(x, t, c, k):
    ...    n = len(t) - k - 1
    ...    assert (n >= k+1) and (len(c) >= n)
    ...    return sum(c[i] * B(x, k, i, t) for i in range(n))

    Note that this is an inefficient (if straightforward) way to
    evaluate B-splines --- this spline class does it in an equivalent,
    but much more efficient way.

    Here we construct a quadratic spline function on the base interval
    ``2 <= x <= 4`` and compare with the naive way of evaluating the spline:

    >>> from scipy.interpolate import BSpline
    >>> k = 2
    >>> t = [0, 1, 2, 3, 4, 5, 6]
    >>> c = [-1, 2, 0, -1]
    >>> spl = BSpline(t, c, k)
    >>> spl(2.5)
    array(1.375)
    >>> bspline(2.5, t, c, k)
    1.375

    Note that outside of the base interval results differ. This is because
    `BSpline` extrapolates the first and last polynomial pieces of B-spline
    functions active on the base interval.

    >>> import matplotlib.pyplot as plt
    >>> fig, ax = plt.subplots()
    >>> xx = np.linspace(1.5, 4.5, 50)
    >>> ax.plot(xx, [bspline(x, t, c ,k) for x in xx], 'r-', lw=3, label='naive')
    >>> ax.plot(xx, spl(xx), 'b-', lw=4, alpha=0.7, label='BSpline')
    >>> ax.grid(True)
    >>> ax.legend(loc='best')
    >>> plt.show()


    References
    ----------
    .. [1] Tom Lyche and Knut Morken, Spline methods,
        http://www.uio.no/studier/emner/matnat/ifi/INF-MAT5340/v05/undervisningsmateriale/
    .. [2] Carl de Boor, A practical guide to splines, Springer, 2001.

    Tr   c                    s  t    t|| _t|| _tj|tj	d| _
|dkrD|| _n
t|| _| j
jd | j d }t|| jj}|| _|dkrt| j|| _|dk rtd| j
jdkrtd|| jd k rtdd| d |f t| j
dk  rtd	tt| j
||d  dk r td
t| j
 s:td| jjdk rPtd| jjd |k rjtdt| jj}tj| j|d| _d S )Nr   periodicr   r	   z Spline order cannot be negative.z$Knot vector must be one-dimensional.z$Need at least %d knots for degree %d   z(Knots must be in a non-decreasing order.z!Need at least two internal knots.z#Knots should not have nans or infs.z,Coefficients must be at least 1-dimensional.z0Knots, coefficients and degree are inconsistent.)super__init__operatorindexkr   asarraycr   Zfloat64textrapolateboolshaper   ndimaxisrollaxisr   diffanylenuniquer   r   r   r   )selfr)   r(   r&   r*   r.   ndt	__class__r   r   r#      s@    

"zBSpline.__init__c                 C   s0   t | }|||  |_|_|_||_||_|S )zConstruct a spline without making checks.

        Accepts same parameters as the regular constructor. Input arrays
        `t` and `c` must of correct shape and dtype.
        )object__new__r)   r(   r&   r*   r.   )clsr)   r(   r&   r*   r.   r4   r   r   r   construct_fast   s
    
zBSpline.construct_fastc                 C   s   | j | j| jfS )z@Equivalent to ``(self.t, self.c, self.k)`` (read-only).
        )r)   r(   r&   r4   r   r   r   tck   s    zBSpline.tckc                 C   sb   t |d }t|}tj|d d f| ||d d f| f }t|}d||< | ||||S )a]  Return a B-spline basis element ``B(x | t[0], ..., t[k+1])``.

        Parameters
        ----------
        t : ndarray, shape (k+1,)
            internal knots
        extrapolate : bool or 'periodic', optional
            whether to extrapolate beyond the base interval, ``t[0] .. t[k+1]``,
            or to return nans.
            If 'periodic', periodic extrapolation is used.
            Default is True.

        Returns
        -------
        basis_element : callable
            A callable representing a B-spline basis element for the knot
            vector `t`.

        Notes
        -----
        The degree of the B-spline, `k`, is inferred from the length of `t` as
        ``len(t)-2``. The knot vector is constructed by appending and prepending
        ``k+1`` elements to internal knots `t`.

        Examples
        --------

        Construct a cubic B-spline:

        >>> from scipy.interpolate import BSpline
        >>> b = BSpline.basis_element([0, 1, 2, 3, 4])
        >>> k = b.k
        >>> b.t[k:-k]
        array([ 0.,  1.,  2.,  3.,  4.])
        >>> k
        3

        Construct a quadratic B-spline on ``[0, 1, 1, 2]``, and compare
        to its explicit form:

        >>> t = [-1, 0, 1, 1, 2]
        >>> b = BSpline.basis_element(t[1:])
        >>> def f(x):
        ...     return np.where(x < 1, x*x, (2. - x)**2)

        >>> import matplotlib.pyplot as plt
        >>> fig, ax = plt.subplots()
        >>> x = np.linspace(0, 2, 51)
        >>> ax.plot(x, b(x), 'g', lw=3)
        >>> ax.plot(x, f(x), 'r', lw=8, alpha=0.4)
        >>> ax.grid(True)
        >>> plt.show()

        r!   r   r	   g      ?)r2   r   r   r_
zeros_liker<   )r;   r)   r*   r&   r(   r   r   r   basis_element   s    8,
zBSpline.basis_elementNc           	      C   s>  |du r| j }t|}|j|j }}tj| tjd}|dkr| jj	| j
 d }| j| j
 || j| j
  | j| | j| j
    }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 )a  
        Evaluate a spline function.

        Parameters
        ----------
        x : array_like
            points to evaluate the spline at.
        nu: int, optional
            derivative to evaluate (default is 0).
        extrapolate : bool or 'periodic', optional
            whether to extrapolate based on the first and last intervals
            or return nans. If 'periodic', periodic extrapolation is used.
            Default is `self.extrapolate`.

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

        Nr   r    r	   Fr   )r*   r   r'   r,   r-   r   Zravelr   r)   sizer&   emptyr2   r   r(   r   _ensure_c_contiguous	_evaluatereshaper.   listrangeZ	transpose)	r4   r   nur*   Zx_shapeZx_ndimr5   outlr   r   r   __call__-  s(    
 
*0
zBSpline.__call__c              	   C   s0   t | j| j| jjd d| j|||| d S )Nr   r?   )r
   evaluate_spliner)   r(   rG   r,   r&   )r4   ZxprJ   r*   rK   r   r   r   rF   \  s    zBSpline._evaluatec                 C   s0   | j jjs| j  | _ | jjjs,| j | _dS )zs
        c and t may be modified by the user. The Cython code expects
        that they are C contiguous.

        N)r)   flagsc_contiguousr   r(   r=   r   r   r   rE   `  s    

zBSpline._ensure_c_contiguousr	   c                 C   sp   | j }t| jt| }|dkrDtj|t|f|jdd  f }t| j|| j	f|}| j
|| j| jdS )ad  Return a B-spline representing the derivative.

        Parameters
        ----------
        nu : int, optional
            Derivative order.
            Default is 1.

        Returns
        -------
        b : BSpline object
            A new instance representing the derivative.

        See Also
        --------
        splder, splantider

        r   r	   Nr*   r.   )r(   r2   r)   r   r@   zerosr,   r   Zsplderr&   r<   r*   r.   )r4   rJ   r(   ctr>   r   r   r   
derivativek  s    $
zBSpline.derivativec                 C   s   | j }t| jt| }|dkrDtj|t|f|jdd  f }t| j|| j	f|}| j
dkrjd}n| j
}| j||| jdS )a  Return a B-spline representing the antiderivative.

        Parameters
        ----------
        nu : int, optional
            Antiderivative order. Default is 1.

        Returns
        -------
        b : BSpline object
            A new instance representing the antiderivative.

        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.

        See Also
        --------
        splder, splantider

        r   r	   Nr    FrQ   )r(   r2   r)   r   r@   rR   r,   r   
splantiderr&   r*   r<   r.   )r4   rJ   r(   rS   r>   r*   r   r   r   antiderivative  s    $
zBSpline.antiderivativec              	   C   sf  |du r| j }|   d}||k r0|| }}d}| jj| j d }|dkr|st|| j| j }t|| j| }| jjdkr| j	\}}}t
|||||\}	}
|	| S tjdt| jjdd f| jjd}| j}t| jt| }|dkrtj|t|f|jdd  f }t| j|| jfd\}}}|dkr| j| j | j|  }}|| }|| }t||\}}|dkrtj||gtjd}t|||jd d||dd| |d |d  }	|	|9 }	n&tjdt| jjdd f| jjd}	||| |  }|| }||kr`tj||gtjd}t|||jd d||dd| |	|d |d  7 }	ntj||gtjd}t|||jd d||dd| |	|d |d  7 }	tj||| | gtjd}t|||jd d||dd| |	|d |d  7 }	nHtj||gtjd}t|||jd d||d|| |d |d  }	|	|9 }	|	|jdd S )	a  Compute a definite integral of the spline.

        Parameters
        ----------
        a : float
            Lower limit of integration.
        b : float
            Upper limit of integration.
        extrapolate : bool or 'periodic', optional
            whether to extrapolate beyond the base interval,
            ``t[k] .. t[-k-1]``, or take the spline to be zero outside of the
            base interval. If 'periodic', periodic extrapolation is used.
            If None (default), use `self.extrapolate`.

        Returns
        -------
        I : array_like
            Definite integral of the spline over the interval ``[a, b]``.

        Examples
        --------
        Construct the linear spline ``x if x < 1 else 2 - x`` on the base
        interval :math:`[0, 2]`, and integrate it

        >>> from scipy.interpolate import BSpline
        >>> b = BSpline.basis_element([0, 1, 2])
        >>> b.integrate(0, 1)
        array(0.5)

        If the integration limits are outside of the base interval, the result
        is controlled by the `extrapolate` parameter

        >>> b.integrate(-1, 1)
        array(0.0)
        >>> b.integrate(-1, 1, extrapolate=False)
        array(0.5)

        >>> import matplotlib.pyplot as plt
        >>> fig, ax = plt.subplots()
        >>> ax.grid(True)
        >>> ax.axvline(0, c='r', lw=5, alpha=0.5)  # base interval
        >>> ax.axvline(2, c='r', lw=5, alpha=0.5)
        >>> xx = [-1, 1, 2]
        >>> ax.plot(xx, b(xx))
        >>> plt.show()

        Nr	   r?   r    r!   r   r   F)r*   rE   r)   rC   r&   maxminr(   r-   r>   _dierckxZ_splintr   rD   r   r,   r   r2   r@   rR   r   rU   divmodr'   r   r
   rN   rG   )r4   abr*   signr5   r)   r(   r&   ZintegralZwrkrK   rS   tacakatsteZperiodintervalZ	n_periodsleftr   r   r   r   	integrate  sz    0
&
$








zBSpline.integrate)Tr   )Tr   )T)r   N)r	   )r	   )N)__name__
__module____qualname____doc__r#   classmethodr<   propertyr>   rB   rM   rF   rE   rT   rV   re   __classcell__r   r   r7   r   r   %   s    /
>
/

(r   c                 C   st   t | } |d dkr"td| |d d }| |d | d  }t j| d f|d  || d f|d  f }|S )zSGiven data x, construct the knot vector w/ not-a-knot BC.
    cf de Boor, XIII(12).r!   r	   z Odd degree for now only. Got %s.r   r?   )r   r'   r   r@   )r   r&   mr)   r   r   r   _not_a_knot9  s    
,rn   c                 C   s$   t j| d f| | | d f| f S )zBConstruct a knot vector appropriate for the order-k interpolation.r   r?   )r   r@   )r   r&   r   r   r   _augkntF  s    ro   c                 C   sN   t | trJ| dkr$dt|fg} n&| dkr>dt|fg} ntd|  | S )NZclampedr	   Znaturalr!   zUnknown boundary condition : %s)
isinstancestrr   rR   r   )derivZtarget_shaper   r   r   _convert_string_aliasesK  s    
rs   c              
   C   sd   | d urNzt |  \}}W qX tyJ } zd}t||W Y d }~qXd }~0 0 n
g g  }}t||S )Nz^Derivatives, `bc_type`, should be specified as a pair of iterables of pairs of (order, value).)zip	TypeErrorr   r   Z
atleast_1d)rr   Zordsvalsemsgr   r   r   _process_deriv_specV  s    "
ry   c                 C   s  ||d  }t |d d |d d  }| jd d }t|d |f}t||d f}	||d|d|f< d|	t|t|| f< ||| d| df< d|	t|| t|f< t||f| |}
tt||	|
  t|}t||f| |}||
||	|    }|S )aK  
    Solve a cyclic banded linear system with upper right
    and lower blocks of size ``(k-1) / 2`` using
    the Woodbury formula
    
    Parameters
    ----------
    A : 2-D array, shape(k, n)
        Matrix of diagonals of original matrix(see 
        ``solve_banded`` documentation).
    ur : 2-D array, shape(bs, bs)
        Upper right block matrix.
    ll : 2-D array, shape(bs, bs)
        Lower left block matrix.
    b : 1-D array, shape(n,)
        Vector of constant terms of the system of linear equations.
    k : int
        B-spline degree.
        
    Returns
    -------
    c : 1-D array, shape(n,)
        Solution of the original system of linear equations.
        
    Notes
    -----
    This algorithm works only for systems with banded matrix A plus
    a correction term U @ V.T, where the matrix U @ V.T gives upper right
    and lower left block of A
    The system is solved with the following steps:
        1.  New systems of linear equations are constructed:
            A @ z_i = u_i,
            u_i - columnn vector of U,
            i = 1, ..., k - 1
        2.  Matrix Z is formed from vectors z_i:
            Z = [ z_1 | z_2 | ... | z_{k - 1} ]
        3.  Matrix H = (1 + V.T @ Z)^{-1}
        4.  The system A' @ y = b is solved
        5.  x = y - Z @ (H @ V.T @ y)
    Also, ``n`` should be greater than ``k``, otherwise corner block
    elements will intersect with diagonals.

    Examples
    --------
    Consider the case of n = 8, k = 5 (size of blocks - 2 x 2).
    The matrix of a system:       U:          V:
      x  x  x  *  *  a  b         a b 0 0     0 0 1 0
      x  x  x  x  *  *  c         0 c 0 0     0 0 0 1
      x  x  x  x  x  *  *         0 0 0 0     0 0 0 0
      *  x  x  x  x  x  *         0 0 0 0     0 0 0 0
      *  *  x  x  x  x  x         0 0 0 0     0 0 0 0
      d  *  *  x  x  x  x         0 0 d 0     1 0 0 0
      e  f  *  *  x  x  x         0 0 e f     0 1 0 0

    References
    ----------
    .. [1] William H. Press, Saul A. Teukolsky, William T. Vetterling
           and Brian P. Flannery, Numerical Recipes, 2007, Section 2.7.3

    r!   r	   N)intr,   r   rR   Zaranger   r   identity)Aurllr\   r&   Zk_modbsr5   UVTZHyr(   r   r   r   _woodbury_algorithmb  s    =r   c                 C   s   t | }t|}|d dkrHt |}|dd  |dd d 8  < t |}t |d|  }|||| < td|D ]^}|||  |||d   d   ||| d < || | d  |||d    || | < q||S )z+
    returns vector of nodes on circle
    r!   r   r	   r?   N)r   r   r2   r0   rR   rI   )r   r&   Zxcr5   Zdxr)   ir   r   r   _periodic_knots  s    

 
..r   c                 C   sZ  t tj| ||f\} }}| j}t|| d || d f}t|d D ]}tj||| d ||d d}||d|d f  |7  < tj||| d || d |d ddd }||| df  |8  < qHt|D ]^}| | }||| kr|}	nt||d }	t||||	}|||| d |	| |	d f< qtj	dg|d  |f }
t
||
}|S )a/  
    Returns a solution of a system for B-spline interpolation with periodic
    boundary conditions. First ``k - 1`` rows of matrix are condtions of
    periodicity (continuity of ``k - 1`` derivatives at the boundary points).
    Last ``n`` rows are interpolation conditions.
    RHS is ``k - 1`` zeros and ``n`` ordinates in this case.

    Parameters
    ----------
    x : 1-D array, shape (n,)
        Values of x - coordinate of a given set of points.
    y : 1-D array, shape (n,)
        Values of y - coordinate of a given set of points.
    t : 1-D array, shape(n+2*k,)
        Vector of knots.
    k : int
        The maximum degree of spline

    Returns
    -------
    c : 1-D array, shape (n+k-1,)
        B-spline coefficients

    Notes
    -----
    ``t`` is supposed to be taken on circle.

    r	   r   )rJ   Nr?   )mapr   r'   rC   rR   rI   r
   Zevaluate_all_bsplZsearchsortedr@   r   )r   r   r)   r&   r5   Zmatrr   ZbbZxvalrd   r\   r(   r   r   r   _make_interp_per_full_matr  s$    ,"
r   c              
   C   sl  |j d }t|j dd }|||}t|| d |f}||krt|D ]*}	t| |dd|	f |||dd|	f< qNt||| d f|j dd  }tj	|||d|dS t
|| d }
t|d }tjd| d |
ftjdd	}t||f}t|}tj| ||||d
 || |d d  dddf }t|D ]d}	|tj||	 d |	|f |	d7 }|tj||	| |d  |d d|  |	 f |	 d7 }qF|dd|| | f }t|D ]`}	t||||dd|	f dd |}t|| d ||d||d   f|dd|	f< qt||| d f|j dd  }tj	|||d|dS )a  
    Compute the (coefficients of) interpolating B-spline with periodic
    boundary conditions.

    Parameters
    ----------
    x : array_like, shape (n,)
        Abscissas.
    y : array_like, shape (n,)
        Ordinates.
    k : int
        B-spline degree.
    t : array_like, shape (n + 2 * k,).
        Knots taken on a circle, ``k`` on the left and ``k`` on the right
        of the vector ``x``.

    Returns
    -------
    b : a BSpline object of the degree ``k`` and with knots ``t``.

    Notes
    -----
    The original system is formed by ``n + k - 1`` equations where the first
    ``k - 1`` of them stand for the ``k - 1`` derivatives continuity on the
    edges while the other equations correspond to an interpolating case
    (matching all the input points). Due to a special form of knot vector, it
    can be proved that in the original system the first and last ``k``
    coefficients of a spline function are the same, respectively. It follows
    from the fact that all ``k - 1`` derivatives are equal term by term at ends
    and that the matrix of the original system of linear equations is
    non-degenerate. So, we can reduce the number of equations to ``n - 1``
    (first ``k - 1`` equations could be reduced). Another trick of this
    implementation is cyclic shift of values of B-splines due to equality of
    ``k`` unknown coefficients. With this we can receive matrix of the system
    with upper right and lower left blocks, and ``k`` diagonals.  It allows
    to use Woodbury formula to optimize the computations.

    r   r	   Nr    rQ   r!      Fr   orderoffset)r&   r?   )r,   r   rG   r   rR   rI   r   r   r   r<   r2   rz   r   rA   r
   _collocZdiagr   Zconcatenate)r   r   r)   r&   r.   r5   extradimZy_newr(   r   ntZkulabr}   r~   r|   ccr   r   r   _make_periodic_spline	  s2    '
((
"$>$:(r   r   Tc              
   C   s  |du s|dks|dkr"d\}}nVt |tr8|| }}n@z|\}}W n2 tyv }	 ztd| |	W Y d}	~	n
d}	~	0 0 t|}t||j}t| |} t||}t	||}|dkrtj
|d |d dd	std
|dkrDtdd |||fD rtdtj| | d f }t|}
tj|
t|
jd}
tj||
||dS |dkr|du r|du rl|du sttdtj| d | | d f }t|}
tj|
t|
jd}
tj||
||dS t|}|dkr|durtd|du r|du r~|du r~|dkrt| |}nf|dkrr| dd | dd  d }tj| d f|d  |dd | d f|d  f }n
t| |}n
t| |}t||}| jdkst| dd | dd k rtdt| dd | dd krtd|dk r td|jdks,t|dd |dd k r4td| j|jd krZtd| j|j|j| j| d k rtd|j| j| d f | d || k s| d ||  krtd|  |dkrt| ||||S t||jdd }t|\}}|jd }t||jdd }t|\}}|jd }| j}|j| d }|| || krhtd|| ||f | }}tjd| | d |ftjdd}t j!| ||||d |dkrt "||| d |||| |dkrt j"||| d |||||| d t#|jdd }tj$||f|jd}|dkr:|%d||d|< |%d||||| < |dkrt|%d|||| d< |rt&tj'||f\}}t(d ||f\}|||||d!d!d"\}}}
}|dkrt)d#n|dk rtd$|  t|
%|f|jdd  }
tj||
||dS )%a	  Compute the (coefficients of) interpolating B-spline.

    Parameters
    ----------
    x : array_like, shape (n,)
        Abscissas.
    y : array_like, shape (n, ...)
        Ordinates.
    k : int, optional
        B-spline degree. Default is cubic, k=3.
    t : array_like, shape (nt + k + 1,), optional.
        Knots.
        The number of knots needs to agree with the number of datapoints and
        the number of derivatives at the edges. Specifically, ``nt - n`` must
        equal ``len(deriv_l) + len(deriv_r)``.
    bc_type : 2-tuple or None
        Boundary conditions.
        Default is None, which means choosing the boundary conditions
        automatically. Otherwise, it must be a length-two tuple where the first
        element sets the boundary conditions at ``x[0]`` and the second
        element sets the boundary conditions at ``x[-1]``. Each of these must
        be an iterable of pairs ``(order, value)`` which gives the values of
        derivatives of specified orders at the given edge of the interpolation
        interval.
        Alternatively, the following string aliases are recognized:

        * ``"clamped"``: The first derivatives at the ends are zero. This is
           equivalent to ``bc_type=([(1, 0.0)], [(1, 0.0)])``.
        * ``"natural"``: The second derivatives at ends are zero. This is
          equivalent to ``bc_type=([(2, 0.0)], [(2, 0.0)])``.
        * ``"not-a-knot"`` (default): The first and second segments are the
          same polynomial. This is equivalent to having ``bc_type=None``.
        * ``"periodic"``: The values and the first ``k-1`` derivatives at the
          ends are equivalent.

    axis : int, optional
        Interpolation axis. Default is 0.
    check_finite : bool, optional
        Whether to check that the input arrays contain only finite numbers.
        Disabling may give a performance gain, but may result in problems
        (crashes, non-termination) if the inputs do contain infinities or NaNs.
        Default is True.

    Returns
    -------
    b : a BSpline object of the degree ``k`` and with knots ``t``.

    Examples
    --------

    Use cubic interpolation on Chebyshev nodes:

    >>> def cheb_nodes(N):
    ...     jj = 2.*np.arange(N) + 1
    ...     x = np.cos(np.pi * jj / 2 / N)[::-1]
    ...     return x

    >>> x = cheb_nodes(20)
    >>> y = np.sqrt(1 - x**2)

    >>> from scipy.interpolate import BSpline, make_interp_spline
    >>> b = make_interp_spline(x, y)
    >>> np.allclose(b(x), y)
    True

    Note that the default is a cubic spline with a not-a-knot boundary condition

    >>> b.k
    3

    Here we use a 'natural' spline, with zero 2nd derivatives at edges:

    >>> l, r = [(2, 0.0)], [(2, 0.0)]
    >>> b_n = make_interp_spline(x, y, bc_type=(l, r))  # or, bc_type="natural"
    >>> np.allclose(b_n(x), y)
    True
    >>> x0, x1 = x[0], x[-1]
    >>> np.allclose([b_n(x0, 2), b_n(x1, 2)], [0, 0])
    True

    Interpolation of parametric curves is also supported. As an example, we
    compute a discretization of a snail curve in polar coordinates

    >>> phi = np.linspace(0, 2.*np.pi, 40)
    >>> r = 0.3 + np.cos(phi)
    >>> x, y = r*np.cos(phi), r*np.sin(phi)  # convert to Cartesian coordinates

    Build an interpolating curve, parameterizing it by the angle

    >>> from scipy.interpolate import make_interp_spline
    >>> spl = make_interp_spline(phi, np.c_[x, y])

    Evaluate the interpolant on a finer grid (note that we transpose the result
    to unpack it into a pair of x- and y-arrays)

    >>> phi_new = np.linspace(0, 2.*np.pi, 100)
    >>> x_new, y_new = spl(phi_new).T

    Plot the result

    >>> import matplotlib.pyplot as plt
    >>> plt.plot(x, y, 'o')
    >>> plt.plot(x_new, y_new, '-')
    >>> plt.show()

    Build a B-spline curve with 2 dimensional y
    
    >>> x = np.linspace(0, 2*np.pi, 10)
    >>> y = np.array([np.sin(x), np.cos(x)])

    Periodic condition is satisfied because y coordinates of points on the ends
    are equivalent

    >>> ax = plt.axes(projection='3d')
    >>> xx = np.linspace(0, 2*np.pi, 100)
    >>> bspl = make_interp_spline(x, y, k=5, bc_type='periodic', axis=1)
    >>> ax.plot3D(xx, *bspl(xx))
    >>> ax.scatter3D(x, *y, color='red')
    >>> plt.show()

    See Also
    --------
    BSpline : base class representing the B-spline objects
    CubicSpline : a cubic spline in the polynomial basis
    make_lsq_spline : a similar factory function for spline fitting
    UnivariateSpline : a wrapper over FITPACK spline fitting routines
    splrep : a wrapper over FITPACK spline fitting routines

    Nz
not-a-knotr    )NNzUnknown boundary condition: %sr   r?   gV瞯<)ZatolzAFirst and last points does not match while periodic case expectedc                 s   s   | ]}|d uV  qd S )Nr   ).0_r   r   r   	<genexpr>      z%make_interp_spline.<locals>.<genexpr>z6Too much info for k=0: t and bc_type can only be None.r   r.   r	   z0Too much info for k=1: bc_type can only be None.zOFor periodic case t is constructed automatically and can not be passed manuallyr!   g       @'Expect x to be a 1-D sorted array_like.zExpect x to not have duplicatesExpect non-negative k.'Expect t to be a 1-D sorted array_like.(Shapes of x {} and y {} are incompatiblezGot %d knots, need at least %d.Out of bounds w/ x = %s.zNThe number of derivatives at boundaries does not match: expected %s, got %s+%sr   r   r   )gbsvT)overwrite_aboverwrite_bzCollocation matix is singular.z0illegal value in %d-th argument of internal gbsv)*rp   rq   ru   r   r   r'   r   r-   r   r/   Zallcloser1   r@   r   r   r   r   r<   r$   r%   NotImplementedErrorr   rn   ro   rC   r,   formatr   rs   ry   rR   r   r
   r   Z_handle_lhs_derivativesr   rD   rG   r   Zasarray_chkfiniter   r   )r   r   r&   r)   Zbc_typer.   r   Zderiv_lZderiv_rrw   r(   Zderiv_l_ordsZderiv_l_valsZnleftZderiv_r_ordsZderiv_r_valsZnrightr5   r   klZkur   r   rhsr   Zlupivinfor   r   r   r   a  s     

$


 









, 
,&


"







 r   c              	   C   s<  t | |} t ||}t ||}|dur2t ||}n
t| }t|}t||j}t||}| jdkst| dd | dd  dkrt	d| j
d |d k rt	d|dk rt	d|jdkst|dd |dd  dk rt	d| j|j
d krt	d	| j
|j
|dkrNt| || k | ||  kB rNt	d
|  | j|jkrpt	d| j
|j
|j| d }d}t|j
dd }	tj|d |ftjdd}
tj||	f|jdd}t| |||d|	||
| ||f|j
dd  }t|
d||d}t||f|d|d}t|}tj||||dS )a+  Compute the (coefficients of) an LSQ B-spline.

    The result is a linear combination

    .. math::

            S(x) = \sum_j c_j B_j(x; t)

    of the B-spline basis elements, :math:`B_j(x; t)`, which minimizes

    .. math::

        \sum_{j} \left( w_j \times (S(x_j) - y_j) \right)^2

    Parameters
    ----------
    x : array_like, shape (m,)
        Abscissas.
    y : array_like, shape (m, ...)
        Ordinates.
    t : array_like, shape (n + k + 1,).
        Knots.
        Knots and data points must satisfy Schoenberg-Whitney conditions.
    k : int, optional
        B-spline degree. Default is cubic, k=3.
    w : array_like, shape (n,), optional
        Weights for spline fitting. Must be positive. If ``None``,
        then weights are all equal.
        Default is ``None``.
    axis : int, optional
        Interpolation axis. Default is zero.
    check_finite : bool, optional
        Whether to check that the input arrays contain only finite numbers.
        Disabling may give a performance gain, but may result in problems
        (crashes, non-termination) if the inputs do contain infinities or NaNs.
        Default is True.

    Returns
    -------
    b : a BSpline object of the degree `k` with knots `t`.

    Notes
    -----

    The number of data points must be larger than the spline degree `k`.

    Knots `t` must satisfy the Schoenberg-Whitney conditions,
    i.e., there must be a subset of data points ``x[j]`` such that
    ``t[j] < x[j] < t[j+k+1]``, for ``j=0, 1,...,n-k-2``.

    Examples
    --------
    Generate some noisy data:

    >>> rng = np.random.default_rng()
    >>> x = np.linspace(-3, 3, 50)
    >>> y = np.exp(-x**2) + 0.1 * rng.standard_normal(50)

    Now fit a smoothing cubic spline with a pre-defined internal knots.
    Here we make the knot vector (k+1)-regular by adding boundary knots:

    >>> from scipy.interpolate import make_lsq_spline, BSpline
    >>> t = [-1, 0, 1]
    >>> k = 3
    >>> t = np.r_[(x[0],)*(k+1),
    ...           t,
    ...           (x[-1],)*(k+1)]
    >>> spl = make_lsq_spline(x, y, t, k)

    For comparison, we also construct an interpolating spline for the same
    set of data:

    >>> from scipy.interpolate import make_interp_spline
    >>> spl_i = make_interp_spline(x, y)

    Plot both:

    >>> import matplotlib.pyplot as plt
    >>> xs = np.linspace(-3, 3, 100)
    >>> plt.plot(x, y, 'ro', ms=5)
    >>> plt.plot(xs, spl(xs), 'g-', lw=3, label='LSQ spline')
    >>> plt.plot(xs, spl_i(xs), 'b-', lw=3, alpha=0.7, label='interp spline')
    >>> plt.legend(loc='best')
    >>> plt.show()

    **NaN handling**: If the input arrays contain ``nan`` values, the result is
    not useful since the underlying spline fitting routines cannot deal with
    ``nan``. A workaround is to use zero weights for not-a-number data points:

    >>> y[8] = np.nan
    >>> w = np.isnan(y)
    >>> y[w] = 0.
    >>> tck = make_lsq_spline(x, y, t, w=~w)

    Notice the need to replace a ``nan`` by a numerical value (precise value
    does not matter as long as the corresponding weight is zero.)

    See Also
    --------
    BSpline : base class representing the B-spline objects
    make_interp_spline : a similar factory function for interpolating splines
    LSQUnivariateSpline : a FITPACK-based spline fitting routine
    splrep : a FITPACK-based fitting routine

    Nr	   r?   r   r   zNeed more x points.r   r   r   r   z(Shapes of x {} and w {} are incompatibleTr   r   )r   lowerr   )r   r   r   )r   r   Z	ones_liker$   r%   r   r-   r/   r1   r   r,   rC   r   r   rR   r   r   r
   Z_norm_eq_lsqrG   r   r   r   r   r<   )r   r   r)   r&   wr.   r   r5   r   r   r   r   Z
cho_decompr(   r   r   r   r   p  s\    j




,,,


r   )F)r   NNr   T)r   Nr   T)!r$   Znumpyr   Znumpy.core.multiarrayr   Zscipy.linalgr   r   r   r   r   r    r
   r   r   rY   Zscipy._lib._utilr   __all__r   r   r   rn   ro   rs   ry   r   r   r   r   r   r   r   r   r   r   <module>   s:    
    U>X  
  