class_docstr: 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.
docstr: In defining the gradient, the Finite Fourier Transform is viewed as
  a complex-differentiable function of a complex variable
code: def grad(self, inputs, cost_grad):
      """
      In defining the gradient, the Finite Fourier Transform is viewed as
      a complex-differentiable function of a complex variable
      """
      a = inputs[0]
      n = inputs[1]
      axis = inputs[2]
      grad = cost_grad[0]
      if not isinstance(axis, tensor.TensorConstant):
          raise NotImplementedError(
              "%s: gradient is currently implemented"
              " only for axis being a Theano constant"
              % self.__class__.__name__
          )
      axis = int(axis.data)
      # notice that the number of actual elements in wrto is independent of
      # possible padding or truncation:
      elem = tensor.arange(0, tensor.shape(a)[axis], 1)
      # accounts for padding:
      freq = tensor.arange(0, n, 1)
      outer = tensor.outer(freq, elem)
      pow_outer = tensor.exp(((-2 * math.pi * 1j) * outer) / (1.0 * n))
      res = tensor.tensordot(grad, pow_outer, (axis, 0))
  
      # This would be simpler but not implemented by theano:
      # res = tensor.switch(tensor.lt(n, tensor.shape(a)[axis]),
      # tensor.set_subtensor(res[...,n::], 0, False, False), res)
  
      # Instead we resort to that to account for truncation:
      flip_shape = list(np.arange(0, a.ndim)[::-1])
      res = res.dimshuffle(flip_shape)
      res = tensor.switch(
          tensor.lt(n, tensor.shape(a)[axis]),
          tensor.set_subtensor(res[n::,], 0, False, False),
          res,
      )
      res = res.dimshuffle(flip_shape)
  
      # insures that gradient shape conforms to input shape:
      out_shape = (
          list(np.arange(0, axis))
          + [a.ndim - 1]
          + list(np.arange(axis, a.ndim - 1))
      )
      res = res.dimshuffle(*out_shape)
      return [res, None, None]
  
file_path: Theano/theano/tensor/fourier.py
imports: from __future__ import absolute_import, print_function, division
  import numpy
  import math
  from theano import gof, tensor
label_desc: Use image node_id 4 for calling the Fourier obj's underlying member method code with example usage: obj.grad(inputs, cost_grad) and returns: list