B
    &]\                 @   s   d dl mZmZmZ d dlZd dlZd dlZd dlm	Z	 d dl
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
dgZdd Zdd Zd ddZG dd	 d	eZdd Zdd Zdd Zdd Zd!dd
Zd"ddZdS )#    )divisionprint_functionabsolute_importN)string_types)get_lapack_funcsLinAlgErrorcholesky_bandedcho_solve_banded   )_bspl)_fitpack_impl)_fitpackBSplinemake_interp_splinemake_lsq_splinec             C   s   t | dkrdS ttj| S )zFProduct of a list of numbers; ~40x faster vs np.prod for Python tuplesr   r
   )len	functoolsreduceoperatormul)x r   :lib/python3.7/site-packages/scipy/interpolate/_bsplines.pyprod   s    r   c             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_)dtyper   r   r   
_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)r   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 order
    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|| _tj	|tj
d| _|dkrH|| _n
t|| _| jjd | j d }d|  kr| jjk sn td||jf || _|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  rtd
tt| j||d  d	k rDtdt| j s^td| jjdk rttd| jjd |k rtdt| jj}tj	| j|d| _d S )N)r   periodicr   r
   z%s must be between 0 and %sz 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.)superr   __init__r   indexkr   asarraycr   Zfloat64textrapolateboolshapendimr"   axisrollaxisZdiffanyr   uniquer    r!   r   r   )selfr-   r,   r*   r.   r2   nZ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.   r2   )clsr-   r,   r*   r.   r2   r6   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*   )r6   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 order 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 second order 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      ?)r   r$   r   r_Z
zeros_liker<   )r;   r-   r.   r*   r,   r   r   r   basis_element   s    8,
zBSpline.basis_elementNc       	      C   s>  |dk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`.

        N)r   r%   r
   Fr   )r.   r   r+   r0   r1   r   Zravelr   r-   sizer*   emptyr   r   r,   r   _ensure_c_contiguous	_evaluatereshaper2   listrangeZ	transpose)	r6   r   nur.   Zx_shapeZx_ndimr7   outlr   r   r   __call__6  s&    
 *0
zBSpline.__call__c          	   C   s0   t | j| j| jjd d| j|||| d S )Nr   r>   )r   evaluate_spliner-   r,   rE   r0   r*   )r6   ZxprH   r.   rI   r   r   r   rD   e  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,   )r6   r   r   r   rC   i  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.   r2   )r,   r   r-   r   r?   zerosr0   r   Zsplderr*   r<   r.   r2   )r6   rH   r,   ctr=   r   r   r   
derivativet  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%   F)r.   r2   )r,   r   r-   r   r?   rO   r0   r   
splantiderr*   r.   r<   r2   )r6   rH   r,   rP   r=   r.   r   r   r   antiderivative  s    $
zBSpline.antiderivativec          	   C   sf  |dk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.   rC   r-   rA   r*   maxminr,   r1   r=   _dierckxZ_splintr   rB   r   r0   r   r   r?   rO   r   rR   divmodr+   r   r   rL   rE   )r6   abr.   Zsignr7   r-   r,   r*   ZintegralZwrkrI   rP   ZtaZcaZkaZtsZteZperiodZintervalZ	n_periodsleftr   r   r   r   	integrate  sn    0
&
$



zBSpline.integrate)Tr   )Tr   )T)r   N)r
   )r
   )N)__name__
__module____qualname____doc__r(   classmethodr<   propertyr=   r@   rK   rD   rC   rQ   rS   r[   __classcell__r   r   )r8   r   r   .   s    />
/

(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_knotB  s    
,rd   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   _augkntO  s    re   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)
isinstancer   r   rO   r"   )derivZtarget_shaper   r   r   _convert_string_aliasesT  s    
rh   c             C   sR   | d k	r<yt |  \}}W qF tk
r8   d}t|Y qFX 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)rg   ZordsZvalsmsgr   r   r   _process_deriv_spec_  s    
rl      Tc          
   C   s  |dks|dkrd\}}nDt |tr0|| }}n.y|\}}W n  tk
r\   td| Y nX t|}|j |  kr|jk sn td||dk r||j7 }|dkr&tdd |||fD rtd	t	| |} tj
| | d
 f }t|}	t|	|}	tj|	t|	jd}	tj||	||dS |dkr|dkr|dkrN|dksVtdt	| |} tj
| d | | d
 f }t|}	t|	|}	tj|	t|	jd}	tj||	||dS t	| |} t	||}t|}|dkrb|dkrX|dkrX|dkrL| dd | dd
  d }tj
| d f|d  |dd
 | d
 f|d  f }n
t| |}n
t| |}t	||}t||}| jdkst| dd | dd
 krtd|dk rtd|jdkst|dd |dd
 k rtd| j|jd krtd|j| j| d k r>td|j| j| d f | d || k sd| d
 ||  krptd|  t||jdd }t|\}
}|
jd }t||jdd }t|\}}|jd }| j}|j| d }|| || kr td|| ||f | }}tjd| | d |ftjdd}tj| ||||d |dkrbt||| d ||||
 |dkrtj||| d
 |||||| d t|jdd }tj||f|jd}|dkr| d
||d|< | d
||||| < |dkr| d
|||| d< |r&t!tj"||f\}}t#d||f\}|||||ddd\}}}	}|dkrft$dn|dk r~t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``.

    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()

    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-knot)NNzUnknown boundary condition: %szaxis {} is out of boundsr   c             s   s   | ]}|d k	V  qd S )Nr   ).0_r   r   r   	<genexpr>  s    z%make_interp_spline.<locals>.<genexpr>z6Too much info for k=0: t and bc_type can only be None.r>   )r   )r2   r
   z0Too much info for k=1: bc_type can only be None.r&   g       @z'Expect x to be a 1-D sorted array_like.zExpect non-negative k.z'Expect t to be a 1-D sorted array_like.zx and y are incompatible.zGot %d knots, need at least %d.zOut of bounds w/ x = %s.zNThe number of derivatives at boundaries does not match: expected %s, got %s+%sF)r   order)offset)gbsvT)overwrite_aboverwrite_bzCollocation matix is singular.z0illegal value in %d-th argument of internal gbsv)%rf   r   rj   r"   r   r+   r1   formatr4   r$   r?   r3   r   r   r   r   r<   r   r)   rd   re   rA   r0   rh   rl   rO   r   r   Z_collocZ_handle_lhs_derivativesr   rB   rE   mapZasarray_chkfiniter   r   )r   yr*   r-   Zbc_typer2   r#   Zderiv_lZderiv_rr,   Zderiv_l_ordsZderiv_l_valsZnleftZderiv_r_ordsZderiv_r_valsZnrightr7   ntZklZkuabextradimrhsrt   ZluZpivinfor   r   r   r   l  s    s
















,
,&

"







 c          	   C   sX  t | |} t ||}t ||}|dk	r2t ||}n
t| }t|}|j |  kr`|jk spn td||dk r||j7 }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st	|dd |dd  dk r$td	| j|j
d kr>td
|dkrvt	| || k | ||  kB rvtd|  | j|jkrtd|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:

    >>> x = np.linspace(-3, 3, 50)
    >>> y = np.exp(-x**2) + 0.1 * np.random.randn(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

    Nzaxis {} is out of boundsr   r
   r>   z'Expect x to be a 1-D sorted array_like.zNeed more x points.zExpect non-negative k.z'Expect t to be a 1-D sorted array_like.zx & y are incompatible.zOut of bounds w/ x = %s.zIncompatible weights.Trq   )r   rr   )ru   lowerr#   )rv   r#   )r2   )r$   r   Z	ones_liker   r)   r1   r"   rw   r3   r4   r0   rA   r   rO   r   r   r   Z_norm_eq_lsqrE   r   r	   r   r   r<   )r   ry   r-   r*   wr2   r#   r7   r   r|   r{   r}   Z
cho_decompr,   r   r   r   r   `  sT    i





,0,


)F)rm   NNr   T)rm   Nr   T) Z
__future__r   r   r   r   r   Znumpyr   Zscipy._lib.sixr   Zscipy.linalgr   r   r   r	    r   r   r   rV   __all__r   r   r$   r9   r   rd   re   rh   rl   r   r   r   r   r   r   <module>   s2   

     
 t