B
    [3                 @   s   d Z 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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 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 Z dd Z!dd Z"G dd deZ#dddZ$dS )zFourier Series    )print_functiondivision)pioo)Expr)Add)sympify)S)DummySymbol)is_sequence)Tuple)sincossinc)Interval)
SeriesBase)
SeqFormulac       	      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LZcos_termZformulaa0 r    3lib/python3.7/site-packages/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   Zsin_termr    r    r!   fourier_sin_seq   s
    r#   c             C   s   dd }d\}}}|dkr0|| t  t   }}}t|trnt|dkrR|\}}}nt|dkrn|| }|\}}t|tr|dks|dkrtdt| tj	tj
g}||ks||krt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.

    * 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 import pi
    >>> 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   sB   | j }t| j dkr| S t| j dkr2tdS td|  d S )Nr   r   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   Z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	   ZNegativeInfinityZInfinityr   )r   r   r)   r   startstopZ	unboundedr    r    r!   _process_limits'   s     

r/   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dd Zd2ddZd3ddZdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1S )4FourierSeriesa  Represents Fourier sine/cosine series.

    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| f| S )N)mapr   r   __new__)clsargsr    r    r!   r2   k   s    
zFourierSeries.__new__c             C   s
   | j d S )Nr   )r4   )selfr    r    r!   functiono   s    zFourierSeries.functionc             C   s   | j d d S )Nr   r   )r4   )r5   r    r    r!   r   s   s    zFourierSeries.xc             C   s   | j d d | j d d fS )Nr   r   )r4   )r5   r    r    r!   periodw   s    zFourierSeries.periodc             C   s   | j d d S )Nr   r   )r4   )r5   r    r    r!   r   {   s    zFourierSeries.a0c             C   s   | j d d S )Nr   r   )r4   )r5   r    r    r!   an   s    zFourierSeries.anc             C   s   | j d d S )Nr   )r4   )r5   r    r    r!   bn   s    zFourierSeries.bnc             C   s
   t dtS )Nr   )r   r   )r5   r    r    r!   interval   s    zFourierSeries.intervalc             C   s   | j jS )N)r:   inf)r5   r    r    r!   r-      s    zFourierSeries.startc             C   s   | j jS )N)r:   Zsup)r5   r    r    r!   r.      s    zFourierSeries.stopc             C   s   t S )N)r   )r5   r    r    r!   length   s    zFourierSeries.lengthc             C   s   | j }||r| S d S )N)r   Zhas)r5   oldnewr   r    r    r!   
_eval_subs   s    
zFourierSeries._eval_subsr*   c             C   sL   |dkrt | S g }x.| D ]&}t||kr,P |tjk	r|| qW 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   )r5   r   termstr    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.

        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k	rtt|   | qS r    )r	   r   r   r   ).0irC   )r   r    r!   
<listcomp>  s    z5FourierSeries.sigma_approximation.<locals>.<listcomp>N)	enumerater   )r5   r   rB   r    )r   r!   sigma_approximation   s    =z!FourierSeries.sigma_approximationc             C   s\   t || j }}||jkr*td||f | j| }| j| }| || jd || j| j	fS )a  Shift the function by a term independent of x.

        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
        z '%s' should be independent of %sr   )
r   r   r%   r(   r   r6   r   r4   r8   r9   )r5   sr   r   sfuncr    r    r!   shift  s    


zFourierSeries.shiftc             C   s|   t || j }}||jkr*td||f | j||| }| j||| }| j||| }| || j	d | j
||fS )a  Shift x by a term independent of x.

        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
        z '%s' should be independent of %sr   )r   r   r%   r(   r8   r   r9   r6   r   r4   r   )r5   rJ   r   r8   r9   rK   r    r    r!   shiftx"  s    
zFourierSeries.shiftxc             C   st   t || j }}||jkr*td||f | j|}| j|}| j| }| jd | }| 	|| jd |||fS )a  Scale the function by a term independent of x.

        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
        z '%s' should be independent of %sr   r   )
r   r   r%   r(   r8   Z	coeff_mulr9   r   r4   r   )r5   rJ   r   r8   r9   r   rK   r    r    r!   scale>  s    

zFourierSeries.scalec             C   s|   t || j }}||jkr*td||f | j||| }| j||| }| j||| }| || j	d | j
||fS )a  Scale x by a term independent of x.

        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
        z '%s' should be independent of %sr   )r   r   r%   r(   r8   r   r9   r6   r   r4   r   )r5   rJ   r   r8   r9   rK   r    r    r!   scalex[  s    
zFourierSeries.scalexc             C   s    x| D ]}|t jk	r|S qW d S )N)r	   r   )r5   r   rC   r    r    r!   _eval_as_leading_termw  s    

z#FourierSeries._eval_as_leading_termc             C   s&   |dkr| j S | j|| j| S )Nr   )r   r8   Zcoeffr9   )r5   Zptr    r    r!   
_eval_term|  s    zFourierSeries._eval_termc             C   s
   |  dS )N)rN   )r5   r    r    r!   __neg__  s    zFourierSeries.__neg__c             C   s   t |tr| j|jkrtd| j|j }}| j|j|| }| j|jkrP|S | j|j }| j	|j	 }| j
|j
 }| || jd |||fS t| |S )Nz(Both the series should have same periodsr   )r+   r0   r7   r(   r   r6   r   r%   r8   r9   r   r   r4   r   )r5   otherr   yr6   r8   r9   r   r    r    r!   __add__  s    
zFourierSeries.__add__c             C   s   |  | S )N)rV   )r5   rT   r    r    r!   __sub__  s    zFourierSeries.__sub__N)r*   )r*   )__name__
__module____qualname____doc__r2   propertyr6   r   r7   r   r8   r9   r:   r-   r.   r<   r?   rD   rI   rL   rM   rN   rO   rP   rQ   rS   rV   rW   r    r    r    r!   r0   ]   s0   
*
Ar0   Nc             C   s   t | } t| |}|d }|| jkr(| S td}| || }| |krft| ||\}}tddtf}nH| | krtj	}tddtf}t
| ||}nt| ||\}}t
| ||}t| ||||fS )a  Computes Fourier sine/cosine series expansion.

    Returns a :class:`FourierSeries` object.

    Examples
    ========

    >>> from sympy import fourier_series, pi, cos
    >>> from sympy.abc import x

    >>> s = fourier_series(x**2, (x, -pi, pi))
    >>> s.truncate(n=3)
    -4*cos(x) + cos(2*x) + pi**2/3

    Shifting

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

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

    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] mathworld.wolfram.com/FourierSeries.html
    r   r   r   )r   r/   r%   r
   r   r"   r   r   r	   r   r#   r0   )fr   r   r   Zneg_fr   r8   r9   r    r    r!   fourier_series  s"    6


r^   )N)%r[   Z
__future__r   r   Zsympyr   r   Zsympy.core.exprr   Zsympy.core.addr   Zsympy.core.sympifyr   Zsympy.core.singletonr	   Zsympy.core.symbolr
   r   Zsympy.core.compatibilityr   Zsympy.core.containersr   Z(sympy.functions.elementary.trigonometricr   r   r   Zsympy.sets.setsr   Zsympy.series.series_classr   Zsympy.series.sequencesr   r"   r#   r/   r0   r^   r    r    r    r!   <module>   s(   	6  @