U
    ZÊ¹jO  ã                   @   sÚ   d dl mZ ddlmZ z
ejZW n ek
r<   ejZY nX edd„ ƒZdd„ Z	ed dd	„ƒZ
d
d„ Zed!dd„ƒZdd„ Zedd„ ƒZi fdd„Zedd„ ƒZed"dd„ƒZed#dd„ƒZedd„ ƒZedd„ ƒZdS )$é   )Úxrangeé   )Údefunc                 C   sT   t |ƒ}| j}d|d@  }t|d ƒD ](}||||  7 }|||  |d  }q&|S )zÄ
    Given a sequence `(s_k)` containing at least `n+1` items, returns the
    `n`-th forward difference,

    .. math ::

        \Delta^n = \sum_{k=0}^{\infty} (-1)^{k+n} {n \choose k} s_k.
    éÿÿÿÿr   )ÚintÚzeror   )ÚctxÚsÚnÚdÚbÚk© r   ú^/var/www/html/bwave/python/venv/lib/python3.8/site-packages/mpmath/calculus/differentiation.pyÚ
difference   s    
r   c                    s   |  d¡}|  dd¡}|  dd¡}|d|  |d  }	| j}
zÖ|	| _|  d¡‰ˆd krŒ|  d	¡rpt|  ˆ¡ƒ}nd}|  d| | | ¡‰n
|  ˆ¡‰|  dd¡}|rÆˆ|  |¡9 ‰t|d ƒ}ˆ}nt| |d dƒ}dˆ }|rðˆd
ˆ 7 ‰‡ ‡‡fdd„|D ƒ}|||	fW ¢S |
| _X d S )NÚsingularÚaddprecé
   Ú	directioné    r   r   ÚhÚrelativeg      à?c                    s   g | ]}ˆ ˆ|ˆ  ƒ‘qS r   r   )Ú.0r   ©Úfr   Úxr   r   Ú
<listcomp>=   s     zhsteps.<locals>.<listcomp>)ÚgetÚprecr   ÚmagÚldexpÚconvertÚsignr   )r   r   r   r
   r   Úoptionsr   r   r   ÚworkprecÚorigZ	hextramagZstepsÚnormÚvaluesr   r   r   Úhsteps   s4    



r(   c                    s^  d}zt ˆƒ}t ˆƒ‰d}W n tk
r0   Y nX |rX‡ fdd„ˆD ƒ‰tˆ ˆˆ||ƒS | dd¡}ˆdkrŒ|dkrŒ| d	¡sŒˆˆ  ˆ¡ƒS ˆ j}z¼|dkrÒtˆ ˆˆˆ|f|Ž\}	}
}|ˆ _ˆ  |	ˆ¡|
ˆ  }nz|dk�r@ˆ  jd
7  _ˆ  | dd¡¡‰‡ ‡‡‡‡fdd„}ˆ  |ddˆ j	 g¡}|ˆ  
ˆ¡ dˆ j	  }ntd| ƒ‚W 5 |ˆ _X |
 S )aÌ  
    Numerically computes the derivative of `f`, `f'(x)`, or generally for
    an integer `n \ge 0`, the `n`-th derivative `f^{(n)}(x)`.
    A few basic examples are::

        >>> from mpmath import *
        >>> mp.dps = 15; mp.pretty = True
        >>> diff(lambda x: x**2 + x, 1.0)
        3.0
        >>> diff(lambda x: x**2 + x, 1.0, 2)
        2.0
        >>> diff(lambda x: x**2 + x, 1.0, 3)
        0.0
        >>> nprint([diff(exp, 3, n) for n in range(5)])   # exp'(x) = exp(x)
        [20.0855, 20.0855, 20.0855, 20.0855, 20.0855]

    Even more generally, given a tuple of arguments `(x_1, \ldots, x_k)`
    and order `(n_1, \ldots, n_k)`, the partial derivative
    `f^{(n_1,\ldots,n_k)}(x_1,\ldots,x_k)` is evaluated. For example::

        >>> diff(lambda x,y: 3*x*y + 2*y - x, (0.25, 0.5), (0,1))
        2.75
        >>> diff(lambda x,y: 3*x*y + 2*y - x, (0.25, 0.5), (1,1))
        3.0

    **Options**

    The following optional keyword arguments are recognized:

    ``method``
        Supported methods are ``'step'`` or ``'quad'``: derivatives may be
        computed using either a finite difference with a small step
        size `h` (default), or numerical quadrature.
    ``direction``
        Direction of finite difference: can be -1 for a left
        difference, 0 for a central difference (default), or +1
        for a right difference; more generally can be any complex number.
    ``addprec``
        Extra precision for `h` used to account for the function's
        sensitivity to perturbations (default = 10).
    ``relative``
        Choose `h` relative to the magnitude of `x`, rather than an
        absolute value; useful for large or tiny `x` (default = False).
    ``h``
        As an alternative to ``addprec`` and ``relative``, manually
        select the step size `h`.
    ``singular``
        If True, evaluation exactly at the point `x` is avoided; this is
        useful for differentiating functions with removable singularities.
        Default = False.
    ``radius``
        Radius of integration contour (with ``method = 'quad'``).
        Default = 0.25. A larger radius typically is faster and more
        accurate, but it must be chosen so that `f` has no
        singularities within the radius from the evaluation point.

    A finite difference requires `n+1` function evaluations and must be
    performed at `(n+1)` times the target precision. Accordingly, `f` must
    support fast evaluation at high precision.

    With integration, a larger number of function evaluations is
    required, but not much extra precision is required. For high order
    derivatives, this method may thus be faster if f is very expensive to
    evaluate at high precision.

    **Further examples**

    The direction option is useful for computing left- or right-sided
    derivatives of nonsmooth functions::

        >>> diff(abs, 0, direction=0)
        0.0
        >>> diff(abs, 0, direction=1)
        1.0
        >>> diff(abs, 0, direction=-1)
        -1.0

    More generally, if the direction is nonzero, a right difference
    is computed where the step size is multiplied by sign(direction).
    For example, with direction=+j, the derivative from the positive
    imaginary direction will be computed::

        >>> diff(abs, 0, direction=j)
        (0.0 - 1.0j)

    With integration, the result may have a small imaginary part
    even even if the result is purely real::

        >>> diff(sqrt, 1, method='quad')    # doctest:+ELLIPSIS
        (0.5 - 4.59...e-26j)
        >>> chop(_)
        0.5

    Adding precision to obtain an accurate value::

        >>> diff(cos, 1e-30)
        0.0
        >>> diff(cos, 1e-30, h=0.0001)
        -9.99999998328279e-31
        >>> diff(cos, 1e-30, addprec=100)
        -1.0e-30

    FTc                    s   g | ]}ˆ   |¡‘qS r   )r!   )r   Ú_©r   r   r   r   ´   s     zdiff.<locals>.<listcomp>ÚmethodÚstepr   Úquadr   r   Úradiusg      Ð?c                    s&   ˆˆ   | ¡ }ˆ| }ˆ|ƒ|ˆ  S ©N)Zexpj)ÚtZreiÚz©r   r   r
   r.   r   r   r   ÚgÂ   s    zdiff.<locals>.gr   zunknown method: %r)ÚlistÚ	TypeErrorÚ_partial_diffr   r!   r   r(   r   ZquadtsÚpiÚ	factorialÚ
ValueError)r   r   r   r
   r#   ÚpartialÚordersr+   r   r'   r&   r$   Úvr3   r   r   r2   r   ÚdiffC   s8    i
r=   c                    sp   |s
ˆƒ S t |ƒsˆ|Ž S d‰tt|ƒƒD ]‰|ˆ r* q<q*|ˆ ‰‡ ‡‡‡‡fdd„}d|ˆ< tˆ |||ˆƒS )Nr   c                     s&   ‡‡ ‡fdd„}ˆj |ˆ ˆ ˆfˆŽS )Nc                    s&   ˆ ˆd ˆ… | f ˆˆd d …  Ž S ©Nr   r   ©r0   )r   Úf_argsÚir   r   ÚinnerÙ   s    z1_partial_diff.<locals>.fdiff_inner.<locals>.inner©r=   )r@   rB   ©r   r   rA   r#   Úorder)r@   r   Úfdiff_innerØ   s    z"_partial_diff.<locals>.fdiff_inner)ÚsumÚrangeÚlenr6   )r   r   Zxsr;   r#   rF   r   rD   r   r6   Î   s    r6   Nc              	   k   sP  |dkr| j }nt|ƒ}| dd¡dkrZd}||d k rV| j|||f|ŽV  |d7 }q,dS | d¡}|r~| j||ddd�V  n||  |¡ƒV  |dk ršdS || j kr®d	\}}nd|d  }}| j}	t| ||||	f|Ž\}
}}t||ƒD ]B}z|| _|  |
|¡||  }W 5 |	| _X |
 V  ||kræ dS qæ|t|d
 d ƒ }}t	||ƒ}q¼dS )ad  
    Returns a generator that yields the sequence of derivatives

    .. math ::

        f(x), f'(x), f''(x), \ldots, f^{(k)}(x), \ldots

    With ``method='step'``, :func:`~mpmath.diffs` uses only `O(k)`
    function evaluations to generate the first `k` derivatives,
    rather than the roughly `O(k^2)` evaluations
    required if one calls :func:`~mpmath.diff` `k` separate times.

    With `n < \infty`, the generator stops as soon as the
    `n`-th derivative has been generated. If the exact number of
    needed derivatives is known in advance, this is further
    slightly more efficient.

    Options are the same as for :func:`~mpmath.diff`.

    **Examples**

        >>> from mpmath import *
        >>> mp.dps = 15
        >>> nprint(list(diffs(cos, 1, 5)))
        [0.540302, -0.841471, -0.540302, 0.841471, 0.540302, -0.841471]
        >>> for i, d in zip(range(6), diffs(cos, 1)):
        ...     print("%s %s" % (i, d))
        ...
        0 0.54030230586814
        1 -0.841470984807897
        2 -0.54030230586814
        3 0.841470984807897
        4 0.54030230586814
        5 -0.841470984807897

    Nr+   r,   r   r   r   T)r   )r   r   gffffffö?)
Úinfr   r   r=   r!   r   r(   r   r   Úmin)r   r   r   r
   r#   r   r   ÚAÚBZcallprecÚyr&   r$   r   r   r   r   Údiffsß   s<    &



rO   c                    s   t ˆƒ‰g ‰ ‡ ‡fdd„}|S )Nc                    s.   t tˆ ƒ| d ƒD ]}ˆ  tˆƒ¡ qˆ |  S r>   )r   rI   ÚappendÚnext)r   rA   ©ÚdataÚgenr   r   r   ,  s    ziterable_to_function.<locals>.f)Úiter)rT   r   r   rR   r   Úiterable_to_function)  s    rV   c           
      c   sÊ   t |ƒ}|dkr&|d D ]
}|V  qn t|  |d|d … ¡ƒ}t|  ||d d… ¡ƒ}d}||ƒ|dƒ }d}td|d ƒD ]4}	|||	 d  |	 }|||||	 ƒ ||	ƒ 7 }q€|V  |d7 }q^dS )aV  
    Given a list of `N` iterables or generators yielding
    `f_k(x), f'_k(x), f''_k(x), \ldots` for `k = 1, \ldots, N`,
    generate `g(x), g'(x), g''(x), \ldots` where
    `g(x) = f_1(x) f_2(x) \cdots f_N(x)`.

    At high precision and for large orders, this is typically more efficient
    than numerical differentiation if the derivatives of each `f_k(x)`
    admit direct computation.

    Note: This function does not increase the working precision internally,
    so guard digits may have to be added externally for full accuracy.

    **Examples**

        >>> from mpmath import *
        >>> mp.dps = 15; mp.pretty = True
        >>> f = lambda x: exp(x)*cos(x)*sin(x)
        >>> u = diffs(f, 1)
        >>> v = mp.diffs_prod([diffs(exp,1), diffs(cos,1), diffs(sin,1)])
        >>> next(u); next(v)
        1.23586333600241
        1.23586333600241
        >>> next(u); next(v)
        0.104658952245596
        0.104658952245596
        >>> next(u); next(v)
        -5.96999877552086
        -5.96999877552086
        >>> next(u); next(v)
        -12.4632923122697
        -12.4632923122697

    r   r   Nr   )rI   rV   Ú
diffs_prodr   )
r   ZfactorsÚNÚcÚur<   r
   r	   Úar   r   r   r   rW   2  s    $
rW   c           
      C   s6  | |kr||  S |s ddi|d< t | d ƒ}tdd„ t|ƒD ƒƒ}i }t|ƒD ]D\}}|d d f|dd…  }||krŠ||  |7  < qN|||< qNt|ƒD ]ˆ\}}t|ƒs®qœt|ƒD ]l\}}|r¶|d|… |d ||d  d f ||d d…  }	|	|k�r||	  || 7  < q¶|| ||	< q¶qœ||| < ||  S )z¤
    nth differentiation polynomial for exp (Faa di Bruno's formula).

    TODO: most exponents are zero, so maybe a sparse representation
    would be better.
    ©r   r   r   c                 s   s   | ]\}}|d  |fV  qdS )r\   Nr   )r   rY   r<   r   r   r   Ú	<genexpr>t  s     zdpoly.<locals>.<genexpr>Nr   )ÚdpolyÚdictÚ	iteritemsrG   Ú	enumerate)
r
   Ú_cacheÚRZRaÚpowersÚcountZpowers1r   ÚpZpowers2r   r   r   r^   h  s.    
4
r^   c                 #   s|   t |ƒ‰ |  ˆ dƒ¡}|V  d}|  d¡}tt|ƒƒD ],\}}|||  ‡ fdd„t|ƒD ƒ¡ 7 }q6|| V  |d7 }q dS )aÐ  
    Given an iterable or generator yielding `f(x), f'(x), f''(x), \ldots`
    generate `g(x), g'(x), g''(x), \ldots` where `g(x) = \exp(f(x))`.

    At high precision and for large orders, this is typically more efficient
    than numerical differentiation if the derivatives of `f(x)`
    admit direct computation.

    Note: This function does not increase the working precision internally,
    so guard digits may have to be added externally for full accuracy.

    **Examples**

    The derivatives of the gamma function can be computed using
    logarithmic differentiation::

        >>> from mpmath import *
        >>> mp.dps = 15; mp.pretty = True
        >>>
        >>> def diffs_loggamma(x):
        ...     yield loggamma(x)
        ...     i = 0
        ...     while 1:
        ...         yield psi(i,x)
        ...         i += 1
        ...
        >>> u = diffs_exp(diffs_loggamma(3))
        >>> v = diffs(gamma, 3)
        >>> next(u); next(v)
        2.0
        2.0
        >>> next(u); next(v)
        1.84556867019693
        1.84556867019693
        >>> next(u); next(v)
        2.49292999190269
        2.49292999190269
        >>> next(u); next(v)
        3.44996501352367
        3.44996501352367

    r   r   c                 3   s&   | ]\}}|rˆ |d  ƒ| V  qdS )r   Nr   )r   r   rf   ©Úfnr   r   r]   ¼  s      zdiffs_exp.<locals>.<genexpr>N)rV   ÚexpZmpfr`   r^   Zfprodra   )r   ZfdiffsZf0rA   r	   rd   rY   r   rg   r   Ú	diffs_exp‰  s    ,
&
rj   r   c                    sX   t tˆ  ˆ  |¡¡ƒd dƒ}|| d ‰‡ ‡‡‡fdd„}ˆ  |||¡ˆ  || ¡ S )a…	  
    Calculates the Riemann-Liouville differintegral, or fractional
    derivative, defined by

    .. math ::

        \,_{x_0}{\mathbb{D}}^n_xf(x) = \frac{1}{\Gamma(m-n)} \frac{d^m}{dx^m}
        \int_{x_0}^{x}(x-t)^{m-n-1}f(t)dt

    where `f` is a given (presumably well-behaved) function,
    `x` is the evaluation point, `n` is the order, and `x_0` is
    the reference point of integration (`m` is an arbitrary
    parameter selected automatically).

    With `n = 1`, this is just the standard derivative `f'(x)`; with `n = 2`,
    the second derivative `f''(x)`, etc. With `n = -1`, it gives
    `\int_{x_0}^x f(t) dt`, with `n = -2`
    it gives `\int_{x_0}^x \left( \int_{x_0}^t f(u) du \right) dt`, etc.

    As `n` is permitted to be any number, this operator generalizes
    iterated differentiation and iterated integration to a single
    operator with a continuous order parameter.

    **Examples**

    There is an exact formula for the fractional derivative of a
    monomial `x^p`, which may be used as a reference. For example,
    the following gives a half-derivative (order 0.5)::

        >>> from mpmath import *
        >>> mp.dps = 15; mp.pretty = True
        >>> x = mpf(3); p = 2; n = 0.5
        >>> differint(lambda t: t**p, x, n)
        7.81764019044672
        >>> gamma(p+1)/gamma(p-n+1) * x**(p-n)
        7.81764019044672

    Another useful test function is the exponential function, whose
    integration / differentiation formula easy generalizes
    to arbitrary order. Here we first compute a third derivative,
    and then a triply nested integral. (The reference point `x_0`
    is set to `-\infty` to avoid nonzero endpoint terms.)::

        >>> differint(lambda x: exp(pi*x), -1.5, 3)
        0.278538406900792
        >>> exp(pi*-1.5) * pi**3
        0.278538406900792
        >>> differint(lambda x: exp(pi*x), 3.5, -3, -inf)
        1922.50563031149
        >>> exp(pi*3.5) / pi**3
        1922.50563031149

    However, for noninteger `n`, the differentiation formula for the
    exponential function must be modified to give the same result as the
    Riemann-Liouville differintegral::

        >>> x = mpf(3.5)
        >>> c = pi
        >>> n = 1+2*j
        >>> differint(lambda x: exp(c*x), x, n)
        (-123295.005390743 + 140955.117867654j)
        >>> x**(-n) * exp(c)**x * (x*c)**n * gammainc(-n, 0, x*c) / gamma(-n)
        (-123295.005390743 + 140955.117867654j)


    r   c                    s   ˆ  ‡‡‡ fdd„ˆˆ g¡S )Nc                    s   ˆ|  ˆ ˆ | ƒ S r/   r   r?   )r   Úrr   r   r   Ú<lambda>  ó    z-differint.<locals>.<lambda>.<locals>.<lambda>)r-   ©r   ©r   r   rk   Úx0rn   r   rl     rm   zdifferint.<locals>.<lambda>)Úmaxr   ÚceilÚrer=   Úgamma)r   r   r   r
   rp   Úmr3   r   ro   r   Ú	differintÀ  s    Drv   c                    s"   ˆdkrˆS ‡ ‡‡‡fdd„}|S )a3  
    Given a function `f`, returns a function `g(x)` that evaluates the nth
    derivative `f^{(n)}(x)`::

        >>> from mpmath import *
        >>> mp.dps = 15; mp.pretty = True
        >>> cos2 = diffun(sin)
        >>> sin2 = diffun(sin, 4)
        >>> cos(1.3), cos2(1.3)
        (0.267498828624587, 0.267498828624587)
        >>> sin(1.3), sin2(1.3)
        (0.963558185417193, 0.963558185417193)

    The function `f` must support arbitrary precision evaluation.
    See :func:`~mpmath.diff` for additional details and supported
    keyword options.
    r   c                    s   ˆ j ˆ| ˆfˆŽS r/   rC   rn   ©r   r   r
   r#   r   r   r3     s    zdiffun.<locals>.gr   )r   r   r
   r#   r3   r   rw   r   Údiffun	  s    rx   c                    sJ   t ˆ j|||f|Žƒ}| dd¡r4‡ fdd„|D ƒS ‡ fdd„|D ƒS dS )a§  
    Produces a degree-`n` Taylor polynomial around the point `x` of the
    given function `f`. The coefficients are returned as a list.

        >>> from mpmath import *
        >>> mp.dps = 15; mp.pretty = True
        >>> nprint(chop(taylor(sin, 0, 5)))
        [0.0, 1.0, 0.0, -0.166667, 0.0, 0.00833333]

    The coefficients are computed using high-order numerical
    differentiation. The function must be possible to evaluate
    to arbitrary precision. See :func:`~mpmath.diff` for additional details
    and supported keyword options.

    Note that to evaluate the Taylor polynomial as an approximation
    of `f`, e.g. with :func:`~mpmath.polyval`, the coefficients must be reversed,
    and the point of the Taylor expansion must be subtracted from
    the argument:

        >>> p = taylor(exp, 2.0, 10)
        >>> polyval(p[::-1], 2.5 - 2.0)
        12.1824939606092
        >>> exp(2.5)
        12.1824939607035

    ÚchopTc                    s$   g | ]\}}ˆ   |¡ˆ  |¡ ‘qS r   )ry   r8   ©r   rA   r   r*   r   r   r   @  s     ztaylor.<locals>.<listcomp>c                    s   g | ]\}}|ˆ   |¡ ‘qS r   )r8   rz   r*   r   r   r   B  s     N)ra   rO   r   )r   r   r   r
   r#   rT   r   r*   r   Útaylor"  s    r{   c                 C   sH  t |ƒ|| d k rtdƒ‚|dkrT|dkr<| jg| jgfS |d|d … | jgfS |  |¡}t|ƒD ]8}tt||| d ƒƒD ]}||| |  |||f< q€qf|  ||d || d … ¡ }|  ||¡}| jgt|ƒ }	dg|d  }
t|d ƒD ]H}|| }tdt||ƒd ƒD ]}||	| |||   7 }�q||
|< qö|
|	fS )aä  
    Computes a Pade approximation of degree `(L, M)` to a function.
    Given at least `L+M+1` Taylor coefficients `a` approximating
    a function `A(x)`, :func:`~mpmath.pade` returns coefficients of
    polynomials `P, Q` satisfying

    .. math ::

        P = \sum_{k=0}^L p_k x^k

        Q = \sum_{k=0}^M q_k x^k

        Q_0 = 1

        A(x) Q(x) = P(x) + O(x^{L+M+1})

    `P(x)/Q(x)` can provide a good approximation to an analytic function
    beyond the radius of convergence of its Taylor series (example
    from G.A. Baker 'Essentials of Pade Approximants' Academic Press,
    Ch.1A)::

        >>> from mpmath import *
        >>> mp.dps = 15; mp.pretty = True
        >>> one = mpf(1)
        >>> def f(x):
        ...     return sqrt((one + 2*x)/(one + x))
        ...
        >>> a = taylor(f, 0, 6)
        >>> p, q = pade(a, 3, 3)
        >>> x = 10
        >>> polyval(p[::-1], x)/polyval(q[::-1], x)
        1.38169105566806
        >>> f(x)
        1.38169855941551

    r   z%L+M+1 Coefficients should be providedr   N)rI   r9   ÚoneÚmatrixrH   rK   Zlu_solver4   )r   r[   ÚLÚMrL   ÚjrA   r<   r   Úqrf   r	   r   r   r   ÚpadeD  s(    (
 
r‚   )r   )N)r   r   )r   )Zlibmp.backendr   Zcalculusr   r_   r`   ÚAttributeErrorÚitemsr   r(   r=   r6   rO   rV   rW   r^   rj   rv   rx   r{   r‚   r   r   r   r   Ú<module>   s8   

$ I	
5!
6H
!