o
    8Va'                     @   sn   d dl mZmZ d dlmZmZ d dlmZ d dlm	Z	 dd Z
dd Ze	d	d
dd Zdd Zdd ZdS )    )Ssympify)	Piecewisepiecewise_fold)Interval)	lru_cachec                 C   sZ   ddl m} t| |r't| jdkr'| j\}}|j|kr!||}}|j|jfS td|  )zreturn the interval corresponding to the condition

    Conditions in spline's Piecewise give the range over
    which an expression is valid like (lo <= x) & (x <= hi).
    This function returns (lo, hi).
    r   )And   zunexpected cond type: %s)Zsympy.logic.boolalgr   
isinstancelenargsZltsZgts	TypeError)condxr   ab r   B/usr/lib/python3/dist-packages/sympy/functions/special/bsplines.py_ivl   s   


r   c                 C   sN  |t jks
| t jkrt|| }| S |t jks|t jkr(t| | }| S g }t| | }t|| }t|jdd }	|jdd D ]K}
|
j}|
j}t||d }t|	D ]0\}}|j}|j}t||\}}||krw||7 }|	|=  n||k r||kr|	| |	|=  nqY|	||f qF|
|	 |	d t|ddi}| S )zConstruct c*b1 + d*b2.Nr   r   TZevaluateF)r   Zeror   listr   exprr   r   	enumerateappendextendr   expand)cb1db2r   Zrvnew_argsZp1Zp2Zp2argsargr   r   loweriZarg2Zexpr2Zcond2Zlower_2Zupper_2r   r   r   _add_splines   s@   42


r&      )maxsizec                 C   sr  ddl m} |}| }tdd |D }t| } t|}t|}|d }||  d |kr0td| dkrIttjt	|| ||d  
|fd}ni| dkr|||  d  ||d   }	|	tjkrx|||  d  | |	 }
t| d ||d |}ntj }}
|||   ||  }	|	tjkr|||  |	 }t| d |||}ntj }}t|||
||}ntd| |||iS )	a0  
    The $n$-th B-spline at $x$ of degree $d$ with knots.

    Explanation
    ===========

    B-Splines are piecewise polynomials of degree $d$. They are defined on a
    set of knots, which is a sequence of integers or floats.

    Examples
    ========

    The 0th degree splines have a value of 1 on a single interval:

        >>> from sympy import bspline_basis
        >>> from sympy.abc import x
        >>> d = 0
        >>> knots = tuple(range(5))
        >>> bspline_basis(d, knots, 0, x)
        Piecewise((1, (x >= 0) & (x <= 1)), (0, True))

    For a given ``(d, knots)`` there are ``len(knots)-d-1`` B-splines
    defined, that are indexed by ``n`` (starting at 0).

    Here is an example of a cubic B-spline:

        >>> bspline_basis(3, tuple(range(5)), 0, x)
        Piecewise((x**3/6, (x >= 0) & (x <= 1)),
                  (-x**3/2 + 2*x**2 - 2*x + 2/3,
                  (x >= 1) & (x <= 2)),
                  (x**3/2 - 4*x**2 + 10*x - 22/3,
                  (x >= 2) & (x <= 3)),
                  (-x**3/6 + 2*x**2 - 8*x + 32/3,
                  (x >= 3) & (x <= 4)),
                  (0, True))

    By repeating knot points, you can introduce discontinuities in the
    B-splines and their derivatives:

        >>> d = 1
        >>> knots = (0, 0, 2, 3, 4)
        >>> bspline_basis(d, knots, 0, x)
        Piecewise((1 - x/2, (x >= 0) & (x <= 2)), (0, True))

    It is quite time consuming to construct and evaluate B-splines. If
    you need to evaluate a B-spline many times, it is best to lambdify them
    first:

        >>> from sympy import lambdify
        >>> d = 3
        >>> knots = tuple(range(10))
        >>> b0 = bspline_basis(d, knots, 0, x)
        >>> f = lambdify(x, b0)
        >>> y = f(0.5)

    Parameters
    ==========

    d : integer
        degree of bspline

    knots : list of integer values
        list of knots points of bspline

    n : integer
        $n$-th B-spline

    x : symbol

    See Also
    ========

    bspline_basis_set

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/B-spline

    r   )Dummyc                 s   s    | ]}t |V  qd S Nr   ).0kr   r   r   	<genexpr>   s    z bspline_basis.<locals>.<genexpr>   z(n + d + 1 must not exceed len(knots) - 1r   zdegree must be non-negative: %r)Zsympy.core.symbolr)   tupleintr   
ValueErrorr   r   ZOner   containsr   bspline_basisr&   Zxreplace)r    knotsnr   r)   ZxvarZn_knotsZn_intervalsresultZdenomBr!   Ar   r   r   r   r4   S   s8   R"



r4   c                    s*   t   d } fddt|D S )a|  
    Return the ``len(knots)-d-1`` B-splines at *x* of degree *d*
    with *knots*.

    Explanation
    ===========

    This function returns a list of piecewise polynomials that are the
    ``len(knots)-d-1`` B-splines of degree *d* for the given knots.
    This function calls ``bspline_basis(d, knots, n, x)`` for different
    values of *n*.

    Examples
    ========

    >>> from sympy import bspline_basis_set
    >>> from sympy.abc import x
    >>> d = 2
    >>> knots = range(5)
    >>> splines = bspline_basis_set(d, knots, x)
    >>> splines
    [Piecewise((x**2/2, (x >= 0) & (x <= 1)),
               (-x**2 + 3*x - 3/2, (x >= 1) & (x <= 2)),
               (x**2/2 - 3*x + 9/2, (x >= 2) & (x <= 3)),
               (0, True)),
    Piecewise((x**2/2 - x + 1/2, (x >= 1) & (x <= 2)),
              (-x**2 + 5*x - 11/2, (x >= 2) & (x <= 3)),
              (x**2/2 - 4*x + 8, (x >= 3) & (x <= 4)),
              (0, True))]

    Parameters
    ==========

    d : integer
        degree of bspline

    knots : list of integers
        list of knots points of bspline

    x : symbol

    See Also
    ========

    bspline_basis

    r/   c                    s   g | ]}t  t|qS r   )r4   r0   r,   r%   r    r5   r   r   r   
<listcomp>   s    z%bspline_basis_set.<locals>.<listcomp>)r   range)r    r5   r   Z	n_splinesr   r;   r   bspline_basis_set   s   0r>   c                    s"  ddl m}m} ddlm} ddlm} t| } | jr| j	s$t
d|  t|t|kr0t
dt|| d k r<t
dtd	d
 t||dd D sPt
ddd |D }| jrh| d d }|||  }	n| d }dd t||| d  ||d |  D }	|d g| d  t|	 |d g| d   }
t| |
  fdd|D }|||||f|dt||d}t|d }dd  D }fdd|D }t||}t|dd d}dd |D }dd  D }g }|D ]tfddt||D tj}||f qt| S )a  
    Return spline of degree *d*, passing through the given *X*
    and *Y* values.

    Explanation
    ===========

    This function returns a piecewise function such that each part is
    a polynomial of degree not greater than *d*. The value of *d*
    must be 1 or greater and the values of *X* must be strictly
    increasing.

    Examples
    ========

    >>> from sympy import interpolating_spline
    >>> from sympy.abc import x
    >>> interpolating_spline(1, x, [1, 2, 4, 7], [3, 6, 5, 7])
    Piecewise((3*x, (x >= 1) & (x <= 2)),
            (7 - x/2, (x >= 2) & (x <= 4)),
            (2*x/3 + 7/3, (x >= 4) & (x <= 7)))
    >>> interpolating_spline(3, x, [-2, 0, 1, 3, 4], [4, 2, 1, 1, 3])
    Piecewise((7*x**3/117 + 7*x**2/117 - 131*x/117 + 2, (x >= -2) & (x <= 1)),
            (10*x**3/117 - 2*x**2/117 - 122*x/117 + 77/39, (x >= 1) & (x <= 4)))

    Parameters
    ==========

    d : integer
        Degree of Bspline strictly greater than equal to one

    x : symbol

    X : list of strictly increasing integer values
        list of X coordinates through which the spline passes

    Y : list of strictly increasing integer values
        list of Y coordinates through which the spline passes

    See Also
    ========

    bspline_basis_set, interpolating_poly

    r   )symbolsr)   )linsolve)Matrixz1Spline degree must be a positive integer, not %s.z/Number of X and Y coordinates must be the same.r/   z6Degree must be less than the number of control points.c                 s   s    | ]	\}}||k V  qd S r*   r   r,   r   r   r   r   r   r.   :  s    z'interpolating_spline.<locals>.<genexpr>Nz.The x-coordinates must be strictly increasing.c                 S   s   g | ]}t |qS r   r+   r:   r   r   r   r<   <      z(interpolating_spline.<locals>.<listcomp>r	   c                 S   s   g | ]
\}}|| d  qS )r	   r   rB   r   r   r   r<   D  s    r   c                    s    g | ]  fd dD qS )c                    s   g | ]}|  qS r   )Zsubsr,   r   )vr   r   r   r<   L  s    z3interpolating_spline.<locals>.<listcomp>.<listcomp>r   )r,   )basisr   )rE   r   r<   L  s     zc0:{})clsc                 S   s(   h | ]}|j D ]
\}}|d kr|qqS )Tr   )r,   r   er   r   r   r   	<setcomp>P  s   ( z'interpolating_spline.<locals>.<setcomp>c                    s   g | ]}t | qS r   )r   )r,   r   r   r   r   r<   T      c                 S   s   | d S )Nr   r   rK   r   r   r   <lambda>V  s    z&interpolating_spline.<locals>.<lambda>)keyc                 S   s   g | ]\}}|qS r   r   )r,   r   yr   r   r   r<   W  rC   c                 S   s   g | ]
}d d |j D qS )c                 S   s   i | ]\}}||qS r   r   )r,   rI   r   r   r   r   
<dictcomp>Y  rL   z3interpolating_spline.<locals>.<listcomp>.<dictcomp>rH   rD   r   r   r   r<   Y  s    c                    s"   g | ]\}}||  tj qS r   )getr   r   )r,   r   r    )r%   r   r   r<   ]  s   " )Zsympyr?   r)   Zsympy.solvers.solvesetr@   Zsympy.matrices.denserA   r   Z
is_IntegerZis_positiver2   r   allzipZis_oddr   r>   formatsortedsumr   r   r   r   )r    r   XYr?   r)   r@   rA   jZinterior_knotsr5   r9   ZcoeffZ	intervalsZivalZcomZbasis_dictsZsplineZpiecer   )rF   r%   r   r   interpolating_spline   sL   . $,(
rZ   N)Z
sympy.corer   r   Zsympy.functionsr   r   Zsympy.sets.setsr   Zsympy.core.cacher   r   r&   r4   r>   rZ   r   r   r   r   <module>   s    ;
x4