o
    *ήceY                     @   s   d Z ddlmZmZ ddlmZ ddlmZ ddlm	Z	 ddl
mZ ddlmZ ddlmZmZ dd	lmZ dd
l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 dd Zdd Zdd Z dd Z!G dd deZ"G dd de"Z#dddZ$dS ) zFourier Series    )oopi)Wild)Expr)Add)Tuple)S)DummySymbol)sympify)sincossinc)
SeriesBase)
SeqFormula)Interval)is_sequencec           	      C   s   ddl m} |d |d |d  }}td| t | | }d| || | | | }||tjd }|td| || | | | |dtffS )z,Returns the cos sequence in a Fourier seriesr   	integrate      )	sympy.integralsr   r   r   subsr   Zeror   r   )	funclimitsnr   xLcos_termformulaa0 r"   ;/tmp/pip-target-vg8gfxp4/lib/python/sympy/series/fourier.pyfourier_cos_seq   s   r$   c                 C   sd   ddl m} |d |d |d  }}td| t | | }td| || | | | |dtfS )z,Returns the sin sequence in a Fourier seriesr   r   r   r   )r   r   r   r   r   r   )r   r   r   r   r   r   sin_termr"   r"   r#   fourier_sin_seq   s   r&   c                 C   s   dd }d\}}}|du r|| t  t }}}t|tr7t|dkr)|\}}}nt|dkr7|| }|\}}t|trD|du sD|du rLtdt| tj	tj
g}||v sZ||v r^tdt|||fS )	a  
    Limits should be of the form (x, start, stop).
    x should be a symbol. Both start and stop should be bounded.

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

    * If x is not given, x is determined from func.
    * If limits is None. Limit of the form (x, -pi, pi) is returned.

    Examples
    ========

    >>> from sympy.series.fourier import _process_limits as pari
    >>> from sympy.abc import x
    >>> pari(x**2, (x, -2, 2))
    (x, -2, 2)
    >>> pari(x**2, (-2, 2))
    (x, -2, 2)
    >>> pari(x**2, None)
    (x, -pi, pi)
    c                 S   s2   | j }t|dkr| S |stdS td|  )Nr   kz specify dummy variables for %s. If the function contains more than one free symbol, a dummy variable should be supplied explicitly e.g. FourierSeries(m*n**2, (n, -pi, pi)))free_symbolslenpopr	   
ValueError)r   freer"   r"   r#   _find_x=   s   z _process_limits.<locals>._find_x)NNNN   r   zInvalid limits given: %sz.Both the start and end value should be bounded)r   r   r   r)   
isinstancer
   r+   strr   NegativeInfinityInfinityr   )r   r   r-   r   startstop	unboundedr"   r"   r#   _process_limits&   s    

r6   c                    s   dd } fdd}ddl m}m}m} |||| }| }	tddd	 d
d	 gd tdfdd	gd|	d D ] }
|
 d }|D ]}||s[|||s[d| f    S qFq<d|fS )Nc                 S   s
   || j vS Nr(   )exprsr   r"   r"   r#   check_fx`      
zfinite_check.<locals>.check_fxc                    sB   t | ttfr| jd }| t|  |  d urdS dS d S )Nr   TF)r/   r   r   argsmatchr   )_exprr   r   sincos_args)abr"   r#   check_sincosc   s   
z"finite_check.<locals>.check_sincosr   )TR2TR1sincos_to_sumr@   c                 S      | j S r7   
is_Integerr'   r"   r"   r#   <lambda>p       zfinite_check.<locals>.<lambda>c                 S   s
   | t jkS r7   r   r   rI   r"   r"   r#   rJ   p      
 
propertiesrA   c                    
    | j vS r7   r8   rI   r   r"   r#   rJ   q   rM   r   FT)sympy.simplify.furC   rD   rE   as_coeff_addr   as_coeff_mul)fr   r   r:   rB   rC   rD   rE   r>   	add_coeffs
mul_coeffstr"   )r@   rA   r   r#   finite_check^   s   	rZ   c                   @   s  e Zd ZdZdd Zedd Zedd Zedd	 Zed
d Z	edd Z
edd Zedd Zedd Zedd Zedd Zedd Zdd Zd5ddZd5dd Zd!d" Zd#d$ Zd%d& Zd'd( Zd6d+d,Zd-d. Zd/d0 Zd1d2 Zd3d4 Zd)S )7FourierSeriesa9  Represents Fourier sine/cosine series.

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

    This class only represents a fourier series.
    No computation is performed.

    For how to compute Fourier series, see the :func:`fourier_series`
    docstring.

    See Also
    ========

    sympy.series.fourier.fourier_series
    c                 G   s   t t|}tj| g|R  S r7   )mapr   r   __new__)clsr<   r"   r"   r#   r]      s   
zFourierSeries.__new__c                 C   s
   | j d S Nr   r<   selfr"   r"   r#   function      
zFourierSeries.functionc                 C      | j d d S Nr   r   r`   ra   r"   r"   r#   r         zFourierSeries.xc                 C   s   | j d d | j d d fS )Nr   r   r`   ra   r"   r"   r#   period      zFourierSeries.periodc                 C   re   )Nr   r   r`   ra   r"   r"   r#   r!      rg   zFourierSeries.a0c                 C   re   )Nr   r   r`   ra   r"   r"   r#   an   rg   zFourierSeries.anc                 C   s   | j d d S )Nr   r`   ra   r"   r"   r#   bn   rg   zFourierSeries.bnc                 C   s
   t dtS r_   )r   r   ra   r"   r"   r#   interval   rd   zFourierSeries.intervalc                 C      | j jS r7   )rl   infra   r"   r"   r#   r3         zFourierSeries.startc                 C   rm   r7   )rl   supra   r"   r"   r#   r4      ro   zFourierSeries.stopc                 C   s   t S r7   )r   ra   r"   r"   r#   length   s   zFourierSeries.lengthc                 C   s   t | jd | jd  d S )Nr   r   r   )absrh   ra   r"   r"   r#   r      ri   zFourierSeries.Lc                 C   s   | j }||r
| S d S r7   )r   has)rb   oldnewr   r"   r"   r#   
_eval_subs   s   
zFourierSeries._eval_subsr.   c                 C   sP   |du rt | S g }| D ]}t||kr t| S |tjur#|| qt| S )a  
        Return the first n nonzero terms of the series.

        If ``n`` is None return an iterator.

        Parameters
        ==========

        n : int or None
            Amount of non-zero terms in approximation or None.

        Returns
        =======

        Expr or iterator :
            Approximation of function expanded into Fourier series.

        Examples
        ========

        >>> from sympy import fourier_series, pi
        >>> from sympy.abc import x
        >>> s = fourier_series(x, (x, -pi, pi))
        >>> s.truncate(4)
        2*sin(x) - sin(2*x) + 2*sin(3*x)/3 - sin(4*x)/2

        See Also
        ========

        sympy.series.fourier.FourierSeries.sigma_approximation
        N)iterr)   r   r   appendr   )rb   r   termsrY   r"   r"   r#   truncate   s    

zFourierSeries.truncatec                    s&    fddt | d  D }t| S )a  
        Return :math:`\sigma`-approximation of Fourier series with respect
        to order n.

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

        Sigma approximation adjusts a Fourier summation to eliminate the Gibbs
        phenomenon which would otherwise occur at discontinuities.
        A sigma-approximated summation for a Fourier series of a T-periodical
        function can be written as

        .. math::
            s(\theta) = \frac{1}{2} a_0 + \sum _{k=1}^{m-1}
            \operatorname{sinc} \Bigl( \frac{k}{m} \Bigr) \cdot
            \left[ a_k \cos \Bigl( \frac{2\pi k}{T} \theta \Bigr)
            + b_k \sin \Bigl( \frac{2\pi k}{T} \theta \Bigr) \right],

        where :math:`a_0, a_k, b_k, k=1,\ldots,{m-1}` are standard Fourier
        series coefficients and
        :math:`\operatorname{sinc} \Bigl( \frac{k}{m} \Bigr)` is a Lanczos
        :math:`\sigma` factor (expressed in terms of normalized
        :math:`\operatorname{sinc}` function).

        Parameters
        ==========

        n : int
            Highest order of the terms taken into account in approximation.

        Returns
        =======

        Expr :
            Sigma approximation of function expanded into Fourier series.

        Examples
        ========

        >>> from sympy import fourier_series, pi
        >>> from sympy.abc import x
        >>> s = fourier_series(x, (x, -pi, pi))
        >>> s.sigma_approximation(4)
        2*sin(x)*sinc(pi/4) - 2*sin(2*x)/pi + 2*sin(3*x)*sinc(3*pi/4)/3

        See Also
        ========

        sympy.series.fourier.FourierSeries.truncate

        Notes
        =====

        The behaviour of
        :meth:`~sympy.series.fourier.FourierSeries.sigma_approximation`
        is different from :meth:`~sympy.series.fourier.FourierSeries.truncate`
        - it takes all nonzero terms of degree smaller than n, rather than
        first n nonzero ones.

        References
        ==========

        .. [1] https://en.wikipedia.org/wiki/Gibbs_phenomenon
        .. [2] https://en.wikipedia.org/wiki/Sigma_approximation
        c                    s.   g | ]\}}|t jurtt|   | qS r"   )r   r   r   r   ).0irY   r   r"   r#   
<listcomp>0  s    z5FourierSeries.sigma_approximation.<locals>.<listcomp>N)	enumerater   )rb   r   ry   r"   r}   r#   sigma_approximation   s   Bz!FourierSeries.sigma_approximationc                 C   s\   t || j}}||jv rtd||f | j| }| j| }| || jd || j| j	fS )a  
        Shift the function by a term independent of x.

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

        f(x) -> f(x) + s

        This is fast, if Fourier series of f(x) is already
        computed.

        Examples
        ========

        >>> from sympy import fourier_series, pi
        >>> from sympy.abc import x
        >>> s = fourier_series(x**2, (x, -pi, pi))
        >>> s.shift(1).truncate()
        -4*cos(x) + cos(2*x) + 1 + pi**2/3
         '%s' should be independent of %sr   )
r   r   r(   r+   r!   rc   r   r<   rj   rk   )rb   rW   r   r!   sfuncr"   r"   r#   shift4  s   


zFourierSeries.shiftc                 C   s|   t || j}}||jv rtd||f | j||| }| j||| }| j||| }| || j	d | j
||fS )a  
        Shift x by a term independent of x.

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

        f(x) -> f(x + s)

        This is fast, if Fourier series of f(x) is already
        computed.

        Examples
        ========

        >>> from sympy import fourier_series, pi
        >>> from sympy.abc import x
        >>> s = fourier_series(x**2, (x, -pi, pi))
        >>> s.shiftx(1).truncate()
        -4*cos(x + 1) + cos(2*x + 2) + pi**2/3
        r   r   r   r   r(   r+   rj   r   rk   rc   r   r<   r!   rb   rW   r   rj   rk   r   r"   r"   r#   shiftxS     
zFourierSeries.shiftxc                 C   st   t || j}}||jv rtd||f | j|}| j|}| j| }| jd | }| 	|| jd |||fS )a  
        Scale the function by a term independent of x.

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

        f(x) -> s * f(x)

        This is fast, if Fourier series of f(x) is already
        computed.

        Examples
        ========

        >>> from sympy import fourier_series, pi
        >>> from sympy.abc import x
        >>> s = fourier_series(x**2, (x, -pi, pi))
        >>> s.scale(2).truncate()
        -8*cos(x) + 2*cos(2*x) + 2*pi**2/3
        r   r   r   )
r   r   r(   r+   rj   	coeff_mulrk   r!   r<   r   )rb   rW   r   rj   rk   r!   r   r"   r"   r#   scales  s   

zFourierSeries.scalec                 C   s|   t || j}}||jv rtd||f | j||| }| j||| }| j||| }| || j	d | j
||fS )a  
        Scale x by a term independent of x.

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

        f(x) -> f(s*x)

        This is fast, if Fourier series of f(x) is already
        computed.

        Examples
        ========

        >>> from sympy import fourier_series, pi
        >>> from sympy.abc import x
        >>> s = fourier_series(x**2, (x, -pi, pi))
        >>> s.scalex(2).truncate()
        -4*cos(2*x) + cos(4*x) + pi**2/3
        r   r   r   r   r"   r"   r#   scalex  r   zFourierSeries.scalexNr   c                 C   s    | D ]}|t jur|  S qd S r7   rL   )rb   r   logxcdirrY   r"   r"   r#   _eval_as_leading_term  s
   
z#FourierSeries._eval_as_leading_termc                 C   s&   |dkr| j S | j|| j| S r_   )r!   rj   coeffrk   )rb   ptr"   r"   r#   
_eval_term  s   zFourierSeries._eval_termc                 C   s
   |  dS )N)r   ra   r"   r"   r#   __neg__  r;   zFourierSeries.__neg__c                 C   s   t |trG| j|jkrtd| j|j}}| j|j|| }| j|jvr(|S | j|j }| j	|j	 }| j
|j
 }| || jd |||fS t| |S )N(Both the series should have same periodsr   )r/   r[   rh   r+   r   rc   r   r(   rj   rk   r!   r   r<   r   )rb   otherr   yrc   rj   rk   r!   r"   r"   r#   __add__  s   

zFourierSeries.__add__c                 C   s   |  | S r7   )r   )rb   r   r"   r"   r#   __sub__  s   zFourierSeries.__sub__)r.   r_   )__name__
__module____qualname____doc__r]   propertyrc   r   rh   r!   rj   rk   rl   r3   r4   rq   r   rv   rz   r   r   r   r   r   r   r   r   r   r   r"   r"   r"   r#   r[   |   sJ    












,F !
 r[   c                   @   sX   e Zd ZdZdd Zedd Zedd Zdd	 Zd
d Z	dd Z
dd Zdd ZdS )FiniteFourierSeriesa  Represents Finite Fourier sine/cosine series.

    For how to compute Fourier series, see the :func:`fourier_series`
    docstring.

    Parameters
    ==========

    f : Expr
        Expression for finding fourier_series

    limits : ( x, start, stop)
        x is the independent variable for the expression f
        (start, stop) is the period of the fourier series

    exprs: (a0, an, bn) or Expr
        a0 is the constant term a0 of the fourier series
        an is a dictionary of coefficients of cos terms
         an[k] = coefficient of cos(pi*(k/L)*x)
        bn is a dictionary of coefficients of sin terms
         bn[k] = coefficient of sin(pi*(k/L)*x)

        or exprs can be an expression to be converted to fourier form

    Methods
    =======

    This class is an extension of FourierSeries class.
    Please refer to sympy.series.fourier.FourierSeries for
    further information.

    See Also
    ========

    sympy.series.fourier.FourierSeries
    sympy.series.fourier.fourier_series
    c                    s  t |}t |}t |}t|trt|dks| \}}ddlm  |t fdd|D   }|jddddd \}}|d t	|d |d	  d }	t
d
dd dd gd}
t
dfddgd}i }i }|D ]L}||t|
t|	    }||t|
t|	    }|r|| |||
 tj |||
 < qj|r|| |||
 tj |||
 < qj||7 }qjt|||}t| |||S )Nr.   r   TR10c                    s   g | ]} |qS r"   r"   )r{   r|   r   r"   r#   r~     s    z/FiniteFourierSeries.__new__.<locals>.<listcomp>F)trig
power_base	power_explogr   r   r@   c                 S   rF   r7   rG   rI   r"   r"   r#   rJ     rK   z-FiniteFourierSeries.__new__.<locals>.<lambda>c                 S   s
   | t juS r7   rL   rI   r"   r"   r#   rJ     rM   rN   rA   c                    rP   r7   r8   rI   rQ   r"   r#   rJ     rM   )r   r/   r   r)   rS   rR   r   r   expandrr   r   r=   r   r   r   getr   r   r   r]   )r^   rU   r   r9   cerexprr!   exp_lsr   r@   rA   rj   rk   prY   qr"   )r   r   r#   r]     s0   $$
zFiniteFourierSeries.__new__c                 C   sB   | j rdnd}|tt| j t| j d 7 }td|S rf   )r!   maxsetrj   keysunionrk   r   )rb   _lengthr"   r"   r#   rl   #  s   *
zFiniteFourierSeries.intervalc                 C   s   | j | j S r7   )r4   r3   ra   r"   r"   r#   rq   )  s   zFiniteFourierSeries.lengthc                 C   sd   t || j}}||jv rtd||f |  ||| }| j||| }| || jd |S Nr   r   	r   r   r(   r+   rz   r   rc   r   r<   rb   rW   r   r>   r   r"   r"   r#   r   -     
zFiniteFourierSeries.shiftxc                 C   sT   t || j}}||jv rtd||f |  | }| j| }| || jd |S r   )r   r   r(   r+   rz   rc   r   r<   r   r"   r"   r#   r   8  s   

zFiniteFourierSeries.scalec                 C   sd   t || j}}||jv rtd||f |  ||| }| j||| }| || jd |S r   r   r   r"   r"   r#   r   C  r   zFiniteFourierSeries.scalexc                 C   sb   |dkr| j S | j|tjt|t| j  | j  | j	|tjt
|t| j  | j   }|S r_   )r!   rj   r   r   r   r   r   r   r   rk   r   )rb   r   _termr"   r"   r#   r   N  s   &&zFiniteFourierSeries._eval_termc                 C   s   t |tr|t| j| jd ddS t |trD| j|jkr"td| j	|j	}}| j|j
|| }| j	|jvr;|S t|| jd dS d S )Nr   F)finiter   )r   )r/   r[   r   fourier_seriesrc   r<   r   rh   r+   r   r   r(   )rb   r   r   r   rc   r"   r"   r#   r   V  s   

zFiniteFourierSeries.__add__N)r   r   r   r   r]   r   rl   rq   r   r   r   r   r   r"   r"   r"   r#   r     s    &$

r   NTc                 C   s6  t | } t| |}|d }|| jvr| S |r2t|d |d  d }t| ||\}}|r2t| ||S td}|d |d  d }|jr| || }	| |	krft	| ||\}
}t
ddtf}t| ||
||fS | |	 krtj}
t
ddtf}t| ||}t| ||
||fS t	| ||\}
}t| ||}t| ||
||fS )a`  Computes the Fourier trigonometric series expansion.

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

    Fourier trigonometric series of $f(x)$ over the interval $(a, b)$
    is defined as:

    .. math::
        \frac{a_0}{2} + \sum_{n=1}^{\infty}
        (a_n \cos(\frac{2n \pi x}{L}) + b_n \sin(\frac{2n \pi x}{L}))

    where the coefficients are:

    .. math::
        L = b - a

    .. math::
        a_0 = \frac{2}{L} \int_{a}^{b}{f(x) dx}

    .. math::
        a_n = \frac{2}{L} \int_{a}^{b}{f(x) \cos(\frac{2n \pi x}{L}) dx}

    .. math::
        b_n = \frac{2}{L} \int_{a}^{b}{f(x) \sin(\frac{2n \pi x}{L}) dx}

    The condition whether the function $f(x)$ given should be periodic
    or not is more than necessary, because it is sufficient to consider
    the series to be converging to $f(x)$ only in the given interval,
    not throughout the whole real line.

    This also brings a lot of ease for the computation because
    you do not have to make $f(x)$ artificially periodic by
    wrapping it with piecewise, modulo operations,
    but you can shape the function to look like the desired periodic
    function only in the interval $(a, b)$, and the computed series will
    automatically become the series of the periodic version of $f(x)$.

    This property is illustrated in the examples section below.

    Parameters
    ==========

    limits : (sym, start, end), optional
        *sym* denotes the symbol the series is computed with respect to.

        *start* and *end* denotes the start and the end of the interval
        where the fourier series converges to the given function.

        Default range is specified as $-\pi$ and $\pi$.

    Returns
    =======

    FourierSeries
        A symbolic object representing the Fourier trigonometric series.

    Examples
    ========

    Computing the Fourier series of $f(x) = x^2$:

    >>> from sympy import fourier_series, pi
    >>> from sympy.abc import x
    >>> f = x**2
    >>> s = fourier_series(f, (x, -pi, pi))
    >>> s1 = s.truncate(n=3)
    >>> s1
    -4*cos(x) + cos(2*x) + pi**2/3

    Shifting of the Fourier series:

    >>> s.shift(1).truncate()
    -4*cos(x) + cos(2*x) + 1 + pi**2/3
    >>> s.shiftx(1).truncate()
    -4*cos(x + 1) + cos(2*x + 2) + pi**2/3

    Scaling of the Fourier series:

    >>> s.scale(2).truncate()
    -8*cos(x) + 2*cos(2*x) + 2*pi**2/3
    >>> s.scalex(2).truncate()
    -4*cos(2*x) + cos(4*x) + pi**2/3

    Computing the Fourier series of $f(x) = x$:

    This illustrates how truncating to the higher order gives better
    convergence.

    .. plot::
        :context: reset
        :format: doctest
        :include-source: True

        >>> from sympy import fourier_series, pi, plot
        >>> from sympy.abc import x
        >>> f = x
        >>> s = fourier_series(f, (x, -pi, pi))
        >>> s1 = s.truncate(n = 3)
        >>> s2 = s.truncate(n = 5)
        >>> s3 = s.truncate(n = 7)
        >>> p = plot(f, s1, s2, s3, (x, -pi, pi), show=False, legend=True)

        >>> p[0].line_color = (0, 0, 0)
        >>> p[0].label = 'x'
        >>> p[1].line_color = (0.7, 0.7, 0.7)
        >>> p[1].label = 'n=3'
        >>> p[2].line_color = (0.5, 0.5, 0.5)
        >>> p[2].label = 'n=5'
        >>> p[3].line_color = (0.3, 0.3, 0.3)
        >>> p[3].label = 'n=7'

        >>> p.show()

    This illustrates how the series converges to different sawtooth
    waves if the different ranges are specified.

    .. plot::
        :context: close-figs
        :format: doctest
        :include-source: True

        >>> s1 = fourier_series(x, (x, -1, 1)).truncate(10)
        >>> s2 = fourier_series(x, (x, -pi, pi)).truncate(10)
        >>> s3 = fourier_series(x, (x, 0, 1)).truncate(10)
        >>> p = plot(x, s1, s2, s3, (x, -5, 5), show=False, legend=True)

        >>> p[0].line_color = (0, 0, 0)
        >>> p[0].label = 'x'
        >>> p[1].line_color = (0.7, 0.7, 0.7)
        >>> p[1].label = '[-1, 1]'
        >>> p[2].line_color = (0.5, 0.5, 0.5)
        >>> p[2].label = '[-pi, pi]'
        >>> p[3].line_color = (0.3, 0.3, 0.3)
        >>> p[3].label = '[0, 1]'

        >>> p.show()

    Notes
    =====

    Computing Fourier series can be slow
    due to the integration required in computing
    an, bn.

    It is faster to compute Fourier series of a function
    by using shifting and scaling on an already
    computed Fourier series rather than computing
    again.

    e.g. If the Fourier series of ``x**2`` is known
    the Fourier series of ``x**2 - 1`` can be found by shifting by ``-1``.

    See Also
    ========

    sympy.series.fourier.FourierSeries

    References
    ==========

    .. [1] https://mathworld.wolfram.com/FourierSeries.html
    r   r   r   r   )r   r6   r(   rr   rZ   r   r	   is_zeror   r$   r   r   r[   r   r   r&   )rU   r   r   r   r   	is_finiteres_fr   centerneg_fr!   rj   rk   r"   r"   r#   r   g  s6    %


r   )NT)%r   sympy.core.numbersr   r   sympy.core.symbolr   sympy.core.exprr   sympy.core.addr   sympy.core.containersr   sympy.core.singletonr   r	   r
   sympy.core.sympifyr   (sympy.functions.elementary.trigonometricr   r   r   sympy.series.series_classr   sympy.series.sequencesr   sympy.sets.setsr   sympy.utilities.iterablesr   r$   r&   r6   rZ   r[   r   r   r"   r"   r"   r#   <module>   s0    	8  ^ 