ó
àÆ÷Xc           @` sp   d  d l  m Z m Z m Z d  d l Z d  d l Z d  d l m Z m Z d e j	 f d „  ƒ  YZ
 e
 ƒ  Z d S(   i    (   t   absolute_importt   print_functiont   divisionN(   t   goft   tensort   Fourierc           B` s8   e  Z d  Z d Z d „  Z d „  Z d „  Z d „  Z RS(   s£  
    WARNING: for officially supported FFTs, use theano.tensor.fft, which
    provides real-input FFTs. Gradients are supported, as well as optimization
    transfers to GPU ops.

    An instance of this class returns a finite fourier transform calcutated
    along one dimension of an input array.

    inputs:

    a : Array of at least one dimension.  Can be complex.
    n : Integer, optional. Length of the transformed axis of the output. If n
    is smaller than the length of the input, the input is cropped. If it is
    larger, the input is padded with zeros. If n is not given, the length of
    the input (along the axis specified by axis) is used.
    axis : Integer, optional. Axis over which to compute the FFT. If not
    supplied, the last axis is used.

    output:

    Complex array.  The input array, transformed along the axis
    indicated by 'axis' or along the last axis if 'axis' is not specified. It
    is truncated or zero-padded as required if 'n' is specified.
    (From numpy.fft.fft's documentation:)
    The values in the output follow so-called standard order. If A = fft(a, n),
    then A[0] contains the zero-frequency term (the mean of the signal), which
    is always purely real for real inputs. Then A[1:n/2] contains the
    positive-frequency terms, and A[n/2+1:] contains the negative-frequency
    terms, in order of decreasingly negative frequency. For an even number of
    input points, A[n/2] represents both positive and negative Nyquist
    frequency, and is also purely real for real input. For an odd number of
    input points, A[(n-1)/2] contains the largest positive frequency, while
    A[(n+1)/2] contains the largest negative frequency.
    c         C` sÝ  t  j | ƒ } | j d k  r7 t d |  j j ƒ ‚ n  | d  k rb | j d } t  j | ƒ } n™ t  j | ƒ } | j t  j k rœ t d |  j j ƒ ‚ n_ | j d k sâ t	 | t  j
 ƒ rû | j d k  sâ | j | j d k rû t d |  j j ƒ ‚ n  | d  k r&| j | } t  j | ƒ } nƒ t  j | ƒ } | j t  j k r`t d |  j j ƒ ‚ nI | j d k st	 | t  j
 ƒ r©| j d k  r©t d |  j j ƒ ‚ n  t j |  | | | g t  j d | j j ƒ ƒ  g ƒ S(	   Ni   s(   %s: input must be an array, not a scalars9   %s: index of the transformed axis must be of type integeri    si   %s: index of the transformed axis must be a scalar not smaller than 0 and smaller than dimension of arrays:   %s: length of the transformed axis must be of type integersE   %s: length of the transformed axis must be a strictly positive scalart
   complex128(   R   t   as_tensor_variablet   ndimt	   TypeErrort	   __class__t   __name__t   Nonet   dtypet   integer_dtypest
   isinstancet   TensorConstantt   datat   shapeR   t   Applyt
   TensorTypet   typet   broadcastable(   t   selft   at   nt   axis(    (    s5   /tmp/pip-build-X4mzal/theano/theano/tensor/fourier.pyt	   make_node,   s8    !%!c   
      C` s  | d } | j  d } | j  d } t | ƒ d k r@ | f g St | t j ƒ r t | d | j j ƒ  !ƒ | g t | | j d ƒ } n„ t | ƒ } t j | ƒ } t j	 | d | !| g | | d f ƒ } d g | } t j
 | | | ƒ } g  | D] }	 |	 d ^ qû } | g S(   Ni    i   i   (   t   inputst   lenR   R   R   t   listR   t   itemt   stackt   concatenatet   split(
   R   t   nodet	   in_shapest   shape_aR   R   t	   out_shapet   lt   n_splitsR   (    (    s5   /tmp/pip-build-X4mzal/theano/theano/tensor/fourier.pyt   infer_shapeN   s     

 c         C` sT   | d } | d } | d } t  j j | d t | ƒ d | j ƒ  ƒ| d d <d  S(   Ni    i   i   R   R   (   t   numpyt   fftt   intR   (   R   R#   R   t   output_storageR   R   R   (    (    s5   /tmp/pip-build-X4mzal/theano/theano/tensor/fourier.pyt   performa   s    


c         C` sá  | d } | d } | d } | d } t  | t j ƒ sS t d |  j j ƒ ‚ n  t | j ƒ } t j d t j	 | ƒ | d ƒ } t j d | d ƒ } t j
 | | ƒ }	 t j d t j d |	 d | ƒ }
 t j | |
 | d f ƒ } t t j d | j ƒ d d d	 … ƒ } | j | ƒ } t j t j | t j	 | ƒ | ƒ t j | | d d … f d t t ƒ | ƒ } | j | ƒ } t t j d | ƒ ƒ | j d g t t j | | j d ƒ ƒ } | j | Œ  } | d d g S(
   s•   
        In defining the gradient, the Finite Fourier Transform is viewed as
        a complex-differentiable function of a complex variable
        i    i   i   sK   %s: gradient is currently implemented only for axis being a Theano constantiþÿÿÿy              ð?g      ð?Niÿÿÿÿ(   R   R   R   t   NotImplementedErrorR
   R   R,   R   t   arangeR   t   outert   expt   matht   pit	   tensordotR   R*   R   t
   dimshufflet   switcht   ltt   set_subtensorR   t   False(   R   R   t	   cost_gradR   R   R   t   gradt   elemt   freqR1   t	   pow_outert   rest
   flip_shapeR&   (    (    s5   /tmp/pip-build-X4mzal/theano/theano/tensor/fourier.pyR<   g   s.    



"&("%	# (    (   R   t
   __module__t   __doc__t	   __props__R   R)   R.   R<   (    (    (    s5   /tmp/pip-build-X4mzal/theano/theano/tensor/fourier.pyR      s   "	"		(   t
   __future__R    R   R   R*   R3   t   theanoR   R   t   OpR   R+   (    (    (    s5   /tmp/pip-build-X4mzal/theano/theano/tensor/fourier.pyt   <module>   s
   Š