B
    [.                 @   s  d Z ddlmZmZmZ ddlmZmZmZ ddl	m
Z
mZmZ ddlmZ ddlmZmZ ddlmZmZ ddlmZmZ dd	lmZ d%ddZd&ddZd'ddZej e_ d(ddZdd Zdd Zej e_ d)ddZ dd Z!dd Z"e!j e"_ dd Z#d*d!d"Z$d+d#d$Z%e$j e%_ dS ),zd
Discrete Fourier Transform, Number Theoretic Transform,
Walsh Hadamard Transform, Mobius Transform
    )print_functiondivisionunicode_literals)SSymbolsympify)as_intrangeiterable)
expand_mul)piI)sincos)isprimeprimitive_root)ibinFc                s  t | stddd | D }tdd |D r8tdt|dk rL|S  d }d @ rt|d7 }d| |tjgt|  7 }xRtdD ]D}t	t
||d	d
ddd d}||k r|| ||  ||< ||< qW |rdt  n
dt   dk	r d   fddtd D }d}x|kr|d |  }	}
x~td|D ]n}xft|	D ]Z}|||  t||| |	  ||
|    }}|| ||  ||| < ||| |	 < qlW q^W |d9 }q4W |rdk	rfdd|D nfdd|D }|S )z3Utility function for the Discrete Fourier TransformzAExpected a sequence of numeric coefficients for Fourier Transformc             S   s   g | ]}t |qS  )r   ).0argr   r   8lib/python3.7/site-packages/sympy/discrete/transforms.py
<listcomp>   s    z&_fourier_transform.<locals>.<listcomp>c             s   s   | ]}| tV  qd S )N)Zhasr   )r   xr   r   r   	<genexpr>    s    z%_fourier_transform.<locals>.<genexpr>z"Expected non-symbolic coefficients      T)strNc                s(   g | ] }t  | tt |   qS r   )r   r   r   )r   i)angr   r   r   7   s    r   c                s   g | ]}|   qS r   )evalf)r   r   )dpsnr   r   r   C   s    c                s   g | ]}|  qS r   r   )r   r   )r#   r   r   r   D   s    )r
   	TypeErrorany
ValueErrorlen
bit_lengthr   Zeror	   intr   r   r!   r   )seqr"   inverseabr   jwhhfutuvr   )r    r"   r#   r   _fourier_transform   sB    
.2r6   Nc             C   s   t | |dS )al  
    Performs the Discrete Fourier Transform (**DFT**) in the complex domain.

    The sequence is automatically padded to the right with zeros, as the
    *radix-2 FFT* requires the number of sample points to be a power of 2.

    This method should be used with default arguments only for short sequences
    as the complexity of expressions increases with the size of the sequence.

    Parameters
    ==========

    seq : iterable
        The sequence on which **DFT** is to be applied.
    dps : Integer
        Specifies the number of decimal digits for precision.

    Examples
    ========

    >>> from sympy import fft, ifft

    >>> fft([1, 2, 3, 4])
    [10, -2 - 2*I, -2, -2 + 2*I]
    >>> ifft(_)
    [1, 2, 3, 4]

    >>> ifft([1, 2, 3, 4])
    [5/2, -1/2 + I/2, -1/2, -1/2 - I/2]
    >>> fft(_)
    [1, 2, 3, 4]

    >>> ifft([1, 7, 3, 4], dps=15)
    [3.75, -0.5 - 0.75*I, -1.75, -0.5 + 0.75*I]
    >>> fft(_)
    [1.0, 7.0, 3.0, 4.0]

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm
    .. [2] http://mathworld.wolfram.com/FastFourierTransform.html

    )r"   )r6   )r+   r"   r   r   r   fftI   s    .r7   c             C   s   t | |ddS )NT)r"   r,   )r6   )r+   r"   r   r   r   ifftz   s    r8   c                sH  t | stdt| t s(td fdd| D }t|}|dk rN|S | d }||d @ rv|d7 }d| } d | rtd|dg|t|  7 }xRtd|D ]D}tt	||d	d
ddd d}||k r|| ||  ||< ||< qW t
 }t| d |  }	|r&t|	 d  }	dg|d  }
x0td|d D ]}|
|d  |	   |
|< qDW d}x||kr|d ||  }}xtd||D ]r}xjt|D ]^}|||  ||| |  |
||    }}||   ||    ||| < ||| | < qW qW |d9 }qlW |rDt| d   fdd|D }|S )z3Utility function for the Number Theoretic TransformzJExpected a sequence of integer coefficients for Number Theoretic Transformz5Expected prime modulus for Number Theoretic Transformc                s   g | ]}t |  qS r   )r   )r   r   )pr   r   r      s    z/_number_theoretic_transform.<locals>.<listcomp>r   r   z/Expected prime modulus of the form (m*2**k + 1)r   T)r   Nr   c                s   g | ]}|   qS r   r   )r   r   )r9   rvr   r   r      s    )r
   r$   r   r   r&   r'   r(   r	   r*   r   r   pow)r+   primer,   r-   r#   r.   r   r/   ZprZrtr0   r1   r2   r3   r4   r5   r   )r9   r:   r   _number_theoretic_transform   sN    *:r=   c             C   s   t | |dS )aQ  
    Performs the Number Theoretic Transform (**NTT**), which specializes the
    Discrete Fourier Transform (**DFT**) over quotient ring `Z/pZ` for prime
    `p` instead of complex numbers `C`.

    The sequence is automatically padded to the right with zeros, as the
    *radix-2 NTT* requires the number of sample points to be a power of 2.

    Parameters
    ==========

    seq : iterable
        The sequence on which **DFT** is to be applied.
    prime : Integer
        Prime modulus of the form `(m 2^k + 1)` to be used for performing
        **NTT** on the sequence.

    Examples
    ========

    >>> from sympy import ntt, intt
    >>> ntt([1, 2, 3, 4], prime=3*2**8 + 1)
    [10, 643, 767, 122]
    >>> intt(_, 3*2**8 + 1)
    [1, 2, 3, 4]
    >>> intt([1, 2, 3, 4], prime=3*2**8 + 1)
    [387, 415, 384, 353]
    >>> ntt(_, prime=3*2**8 + 1)
    [1, 2, 3, 4]

    References
    ==========

    .. [1] http://www.apfloat.org/ntt.html
    .. [2] http://mathworld.wolfram.com/NumberTheoreticTransform.html
    .. [3] https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29

    )r<   )r=   )r+   r<   r   r   r   ntt   s    (r>   c             C   s   t | |ddS )NT)r<   r,   )r=   )r+   r<   r   r   r   intt   s    r?   c       
         s  t | stddd | D }t|  dk r2|S   d @ rJd    |tjg t|  7 }d}x| kr|d  |  }}xjtd |D ]Z}xTt|D ]H}|||  ||| |   }}	||	 ||	  ||| < ||| | < qW qW |d9 }qhW |r fdd|D }|S )z1Utility function for the Walsh Hadamard Transformz@Expected a sequence of coefficients for Walsh Hadamard Transformc             S   s   g | ]}t |qS r   )r   )r   r   r   r   r   r      s    z-_walsh_hadamard_transform.<locals>.<listcomp>r   r   r   c                s   g | ]}|  qS r   r   )r   r   )r#   r   r   r     s    )r
   r$   r'   r(   r   r)   r	   )
r+   r,   r-   r1   r2   r3   r   r/   r4   r5   r   )r#   r   _walsh_hadamard_transform   s(    
.r@   c             C   s   t | S )aN  
    Performs the Walsh Hadamard Transform (**WHT**), and uses Hadamard
    ordering for the sequence.

    The sequence is automatically padded to the right with zeros, as the
    *radix-2 FWHT* requires the number of sample points to be a power of 2.

    Parameters
    ==========

    seq : iterable
        The sequence on which WHT is to be applied.

    Examples
    ========

    >>> from sympy import fwht, ifwht
    >>> fwht([4, 2, 2, 0, 0, 2, -2, 0])
    [8, 0, 8, 0, 8, 8, 0, 0]
    >>> ifwht(_)
    [4, 2, 2, 0, 0, 2, -2, 0]

    >>> ifwht([19, -1, 11, -9, -7, 13, -15, 5])
    [2, 0, 4, 0, 3, 10, 0, 0]
    >>> fwht(_)
    [19, -1, 11, -9, -7, 13, -15, 5]

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Hadamard_transform
    .. [2] https://en.wikipedia.org/wiki/Fast_Walsh%E2%80%93Hadamard_transform

    )r@   )r+   r   r   r   fwht  s    $rA   c             C   s   t | ddS )NT)r,   )r@   )r+   r   r   r   ifwht=  s    rB   c             C   s  t | stddd | D }t|}|dk r2|S ||d @ rJd|  }|tjg|t|  7 }|rd}x||k rx4t|D ](}||@ r~||  ||||A   7  < q~W |d9 }qlW nTd}xN||k r
x6t|D ]*}||@ rq||  ||||A   7  < qW |d9 }qW |S )u]   Utility function for performing Möbius Transform using
    Yate's Dynamic Programming methodz#Expected a sequence of coefficientsc             S   s   g | ]}t |qS r   )r   )r   r   r   r   r   r   P  s    z%_mobius_transform.<locals>.<listcomp>r   r   )r
   r$   r'   r(   r   r)   r	   )r+   sgnsubsetr-   r#   r   r/   r   r   r   _mobius_transformI  s0    
  rE   Tc             C   s   t | d|dS )u  
    Performs the Möbius Transform for subset lattice with indices of
    sequence as bitmasks.

    The indices of each argument, considered as bit strings, correspond
    to subsets of a finite set.

    The sequence is automatically padded to the right with zeros, as the
    definition of subset/superset based on bitmasks (indices) requires
    the size of sequence to be a power of 2.

    Parameters
    ==========

    seq : iterable
        The sequence on which Möbius Transform is to be applied.
    subset : bool
        Specifies if Möbius Transform is applied by enumerating subsets
        or supersets of the given set.

    Examples
    ========

    >>> from sympy import symbols
    >>> from sympy import mobius_transform, inverse_mobius_transform
    >>> x, y, z = symbols('x y z')

    >>> mobius_transform([x, y, z])
    [x, x + y, x + z, x + y + z]
    >>> inverse_mobius_transform(_)
    [x, y, z, 0]

    >>> mobius_transform([x, y, z], subset=False)
    [x + y + z, y, z, 0]
    >>> inverse_mobius_transform(_, subset=False)
    [x, y, z, 0]

    >>> mobius_transform([1, 2, 3, 4])
    [1, 3, 4, 10]
    >>> inverse_mobius_transform(_)
    [1, 2, 3, 4]
    >>> mobius_transform([1, 2, 3, 4], subset=False)
    [10, 6, 7, 4]
    >>> inverse_mobius_transform(_, subset=False)
    [1, 2, 3, 4]

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/M%C3%B6bius_inversion_formula
    .. [2] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf
    .. [3] https://arxiv.org/pdf/1211.0189.pdf

    r   )rC   rD   )rE   )r+   rD   r   r   r   mobius_transformo  s    8rF   c             C   s   t | d|dS )Nr   )rC   rD   )rE   )r+   rD   r   r   r   inverse_mobius_transform  s    rG   )F)N)N)F)F)T)T)&__doc__Z
__future__r   r   r   Z
sympy.corer   r   r   Zsympy.core.compatibilityr   r	   r
   Zsympy.core.functionr   Zsympy.core.numbersr   r   Z(sympy.functions.elementary.trigonometricr   r   Zsympy.ntheoryr   r   Zsympy.utilities.iterablesr   r6   r7   r8   r=   r>   r?   r@   rA   rB   rE   rF   rG   r   r   r   r   <module>   s0   	
1
1
	
:+	
'	&
:
