o
    EOf1                     @   s   d dl Z d dlZd dlZd dlZd dlmZ ddlmZ d dl	m
  mZ d dlmZ ddlmZ dgZdd	 ZG d
d dZejfddZdejdddZdS )    N)prod   )_bspl)	csr_array)_not_a_knot	NdBSplinec                 C   s   t | t jr
t jS t jS )z>Return np.complex128 for complex dtypes, np.float64 otherwise.)np
issubdtypecomplexfloatingZ
complex128Zfloat64dtype r   <lib/python3.10/site-packages/scipy/interpolate/_ndbspline.py
_get_dtype   s   r   c                   @   s<   e Zd ZdZddddZdddddZedd
dZdS )r   a  Tensor product spline object.

    The value at point ``xp = (x1, x2, ..., xN)`` is evaluated as a linear
    combination of products of one-dimensional b-splines in each of the ``N``
    dimensions::

       c[i1, i2, ..., iN] * B(x1; i1, t1) * B(x2; i2, t2) * ... * B(xN; iN, tN)


    Here ``B(x; i, t)`` is the ``i``-th b-spline defined by the knot vector
    ``t`` evaluated at ``x``.

    Parameters
    ----------
    t : tuple of 1D ndarrays
        knot vectors in directions 1, 2, ... N,
        ``len(t[i]) == n[i] + k + 1``
    c : ndarray, shape (n1, n2, ..., nN, ...)
        b-spline coefficients
    k : int or length-d tuple of integers
        spline degrees.
        A single integer is interpreted as having this degree for
        all dimensions.
    extrapolate : bool, optional
        Whether to extrapolate out-of-bounds inputs, or return `nan`.
        Default is to extrapolate.

    Attributes
    ----------
    t : tuple of ndarrays
        Knots vectors.
    c : ndarray
        Coefficients of the tensor-produce spline.
    k : tuple of integers
        Degrees for each dimension.
    extrapolate : bool, optional
        Whether to extrapolate or return nans for out-of-bounds inputs.
        Defaults to true.

    Methods
    -------
    __call__
    design_matrix

    See Also
    --------
    BSpline : a one-dimensional B-spline object
    NdPPoly : an N-dimensional piecewise tensor product polynomial

    N)extrapolatec                C   s:  t |}zt | W n ty   |f| }Y nw t ||kr.tdt |dt |dtdd |D | _tdd |D | _t|| _|d u rNd}t	|| _
t|| _t|D ]}| j| }| j| }|jd | d	 }	|dk r~td
| d|jd	krtd| d|	|d	 k rtdd| d  d| d| dt|dk  rtd| dt t|||	d	  dk rtd| dt| std| d| jj|k rtd| d| jj| |	krtd| d| jj|  dt | d|	 d| dq]t| jj}
tj| j|
d| _d S )Nz	len(t) = z != len(k) = .c                 s   s    | ]}t |V  qd S N)operatorindex).0Zkir   r   r   	<genexpr>Y   s    z%NdBSpline.__init__.<locals>.<genexpr>c                 s   s    | ]
}t j|td V  qdS r   N)r   ascontiguousarrayfloatr   Ztir   r   r   r   Z   s    Tr   r   zSpline degree in dimension z cannot be negative.zKnot vector in dimension z must be one-dimensional.zNeed at least    z knots for degree z in dimension zKnots in dimension z# must be in a non-decreasing order.z.Need at least two internal knots in dimension z should not have nans or infs.zCoefficients must be at least z-dimensional.z,Knots, coefficients and degree in dimension z are inconsistent: got z coefficients for z knots, need at least z for k=r   )len	TypeError
ValueErrortuplektr   asarraycboolr   rangeshapendimZdiffanyuniqueZisfiniteallr   r   r   )selfr!   r#   r    r   r'   dZtdkdnZdtr   r   r   __init__M   sp   








zNdBSpline.__init__)nur   c                   s\  t | j}|du r| j}t|}|du rtj|ftjd}n/tj|tjd}|jdks2|j	d |kr@t
d|dt | j dt|dk rMt
d|tj|td}|j	}|d	|d	 }t|}|d	 |krtt
d
| d| tj| jtdd}dd | jD }tj|t|ftd}|tj t|D ]}	| j|	 ||	dt | j|	 f< qtj|tdd}tdd | jD }
ttt|
|
}tj|tjdj}| j| jj	d| d    }tj fdd jD tjd} j	d	 }tj|j	dd	 |f  jd}t ||||||||||| ||dd	 | jj	|d  S )a@  Evaluate the tensor product b-spline at ``xi``.

        Parameters
        ----------
        xi : array_like, shape(..., ndim)
            The coordinates to evaluate the interpolator at.
            This can be a list or tuple of ndim-dimensional points
            or an array with the shape (num_points, ndim).
        nu : array_like, optional, shape (ndim,)
            Orders of derivatives to evaluate. Each must be non-negative.
            Defaults to the zeroth derivivative.
        extrapolate : bool, optional
            Whether to exrapolate based on first and last intervals in each
            dimension, or return `nan`. Default is to ``self.extrapolate``.

        Returns
        -------
        values : ndarray, shape ``xi.shape[:-1] + self.c.shape[ndim:]``
            Interpolated values at ``xi``
        Nr   r   r   z)invalid number of derivative orders nu = z for ndim = r   z'derivatives must be positive, got nu = zShapes: xi.shape=z
 and ndim=Zlongc                 S   s   g | ]}t |qS r   r   r   r   r   r   
<listcomp>   s    z&NdBSpline.__call__.<locals>.<listcomp>c                 s   s    | ]}|d  V  qdS )r   Nr   )r   r-   r   r   r   r          z%NdBSpline.__call__.<locals>.<genexpr>)r1   c                    s   g | ]}| j j qS r   )r   itemsize)r   sZc1r   r   r3      s    )!r   r!   r   r$   r   ZzerosZintcr"   r'   r&   r   r(   r   reshaper   r    r   emptymaxfillnanr%   r   Zunravel_indexZaranger   ZintpTr#   Zravelstridesr   Zevaluate_ndbspline)r+   Zxir0   r   r'   xi_shapeZ_kZlen_tZ_tr,   r&   indicesZ_indices_k1dZc1rZ_strides_c1Znum_c_troutr   r7   r   __call__   sj   

"
 "zNdBSpline.__call__Tc           
      C   s   t j|td}|jd }t||krtdt| d|dzt| W n ty3   |f| }Y nw t j|t jd}t	|||\}}}	t
|||	fS )a  Construct the design matrix as a CSR format sparse array.

        Parameters
        ----------
        xvals :  ndarray, shape(npts, ndim)
            Data points. ``xvals[j, :]`` gives the ``j``-th data point as an
            ``ndim``-dimensional array.
        t : tuple of 1D ndarrays, length-ndim
            Knot vectors in directions 1, 2, ... ndim,
        k : int
            B-spline degree.
        extrapolate : bool, optional
            Whether to extrapolate out-of-bounds values of raise a `ValueError`

        Returns
        -------
        design_matrix : a CSR array
            Each row of the design matrix corresponds to a value in `xvals` and
            contains values of b-spline basis elements which are non-zero
            at this value.

        r   r1   z*Data and knots are inconsistent: len(t) = z for  ndim = r   )r   r"   r   r&   r   r   r   Zint32r   Z
_colloc_ndr   )
clsxvalsr!   r    r   r'   Zkkdatar@   Zindptrr   r   r   design_matrix   s    
zNdBSpline.design_matrix)T)__name__
__module____qualname____doc__r/   rB   classmethodrF   r   r   r   r   r      s    29Xc           	   	   K   s  t |jt jr$t| |j|fi |}t| |j|fi |}|d|  S |jdkrj|jd dkrjt 	|}t
|jd D ]+}|| |d d |f fi |\|d d |f< }|dkrgtd|d|d| dq<|S || |fi |\}}|dkrtd|d	|d|S )
Ny              ?r   r   r   z	solver = z returns info =z for column r   z returns info = )r   r	   r   r
   _iter_solverealimagr'   r&   Z
empty_liker%   r   )	absolversolver_argsrM   rN   resjinfor   r   r   rL     s    
.rL      rQ   c                   sr  t }tdd D }zt   W n ty!    f|  Y nw tD ](\}}t t|}	|	 | krNtd|	 d| d |  d | d  d	q&t fd	dt|D }
tjd
d t	j
 D td}t||
 }|j}t|d| t||d f}||}|tjkrtjt|d}d|vrd|d< |||fi |}||||d  }t|
| S )a  Construct an interpolating NdBspline.

    Parameters
    ----------
    points : tuple of ndarrays of float, with shapes (m1,), ... (mN,)
        The points defining the regular grid in N dimensions. The points in
        each dimension (i.e. every element of the `points` tuple) must be
        strictly ascending or descending.      
    values : ndarray of float, shape (m1, ..., mN, ...)
        The data on the regular grid in n dimensions.
    k : int, optional
        The spline degree. Must be odd. Default is cubic, k=3
    solver : a `scipy.sparse.linalg` solver (iterative or direct), optional.
        An iterative solver from `scipy.sparse.linalg` or a direct one,
        `sparse.sparse.linalg.spsolve`.
        Used to solve the sparse linear system
        ``design_matrix @ coefficients = rhs`` for the coefficients.
        Default is `scipy.sparse.linalg.gcrotmk`
    solver_args : dict, optional
        Additional arguments for the solver. The call signature is
        ``solver(csr_array, rhs_vector, **solver_args)``

    Returns
    -------
    spl : NdBSpline object

    Notes
    -----
    Boundary conditions are not-a-knot in all dimensions.
    c                 s   s    | ]}t |V  qd S r   r2   )r   xr   r   r   r   @  r4   zmake_ndbspl.<locals>.<genexpr>z
There are z points in dimension z, but order z requires at least  r   z points per dimension.c                 3   s,    | ]}t tj| td  | V  qdS r   )r   r   r"   r   )r   r,   r    pointsr   r   r   O  s    $c                 S   s   g | ]}|qS r   r   )r   Zxvr   r   r   r3   Q  s    zmake_ndbspl.<locals>.<listcomp>r   NrW   Zatolgư>)r   r   r   	enumerater   Z
atleast_1dr   r%   r"   	itertoolsproductr   r   rF   r&   r   r8   sslZspsolve	functoolspartialrL   )rZ   valuesr    rQ   rR   r'   r?   r,   ZpointZnumptsr!   rD   ZmatrZv_shapeZ
vals_shapeZvalsZcoefr   rY   r   make_ndbspl   s>   

 

rb   )rV   )r\   r_   r   Znumpyr   Zmathr    r   Zscipy.sparse.linalgZsparseZlinalgr^   Zscipy.sparser   Z	_bsplinesr   __all__r   r   ZgcrotmkrL   rb   r   r   r   r   <module>   s     o