
Xc           @` su  d  Z  d d l m Z m Z m Z d d l Z d d l Z d d l m Z d d l	 Z	 d d l
 Z
 d d l
 m Z d d l m Z m Z m Z m Z m Z d d l m Z d d l m Z m Z y0 d d	 l m Z m Z d d
 l m Z e Z Wn e k
 r	e Z n Xd Z  e j! d  Z" e# e# d d d f d  Z$ d e f d     YZ% d Z& d Z' d d d  Z( d Z) d S(   s  
Contains an Op for convolving input images with a set of filters. This was
developed especially for Convolutional Neural Networks.

For related ops, including downsampling and subsampling, see
tensor.signal and tensor.signal.pool.

See especially conv2d().
i    (   t   absolute_importt   print_functiont   divisionN(   t   xrange(   t   OpenMPOp(   t   as_tensor_variablet   blast   get_scalar_constant_valuet   patternbroadcastt   NotScalarConstantError(   t   Apply(   t   get_conv_output_shapet   get_conv_shape_1axis(   t   _valfrommodet   _bvalfromboundary(   t   _convolve2ds   restructuredtext ens   theano.tensor.nnet.convt   validi   c         K` s  | d k	 r t |  } x t t |   D] } | | d k	 r+ y t t | |   | | <Wn% t k
 r t d | |   n X| | j t j	 j
 k s t  t | |  | | <q+ q+ Wn  | d k	 rt |  } x t t |   D] } | | d k	 r y t t | |   | | <Wn% t k
 rJt d | |   n X| | j t j	 j
 k sjt  t | |  | | <q q Wn  | r| ryA | d d k	 r| d d k	 r| d | d k st  n  Wqt k
 rt d | d |    qXn  | d k	 r%| d } | d }	 n d \ } }	 | d k	 rT| d }
 | d } n d \ }
 } t d | d	 | d d
 | d d | d |	 d | d |
 |  } | |  |  S(   s	  
    Deprecated, old conv2d interface.
    This function will build the symbolic graph for convolving a stack of
    input images with a set of filters. The implementation is modelled after
    Convolutional Neural Networks (CNN). It is simply a wrapper to the ConvOp
    but provides a much cleaner interface.

    Parameters
    ----------
    input : symbolic 4D tensor
        Mini-batch of feature map stacks, of shape
        (batch size, stack size, nb row, nb col)
        see the optional parameter image_shape
    filters: symbolic 4D tensor
        Set of filters used in CNN layer of shape
        (nb filters, stack size, nb row, nb col)
        see the optional parameter filter_shape
    border_mode : {'valid', 'full'}
       'valid'only apply filter to complete patches of the image. Generates
       output of shape: image_shape - filter_shape + 1.
       'full' zero-pads image to multiple of filter shape to generate output
       of shape: image_shape + filter_shape - 1.
    subsample: tuple of len 2
        Factor by which to subsample the output. Also called strides elsewhere.
    image_shape: None, tuple/list of len 4 of int, None or Constant variable
        The shape of the input parameter.
        Optional, used for optimization like loop unrolling
        You can put None for any element of the list to tell that this element
        is not constant.
    filter_shape : None, tuple/list of len 4 of int, None or Constant variable
        Optional, used for optimization like loop unrolling
        You can put None for any element of the list
        to tell that this element is not constant.
    kwargs
        Kwargs are passed onto ConvOp. Can be used to set the following:
        unroll_batch, unroll_kern, unroll_patch, openmp (see ConvOp doc).

        openmp: By default have the same value as
                config.openmp. For small image, filter,
                batch size, nkern and stack size, it can be
                faster to disable manually openmp. A fast and
                incomplete test show that with image size
                6x6, filter size 4x4, batch size==1,
                n kern==1 and stack size==1, it is faster
                to disable it in valid mode. But if we
                grow the batch size to 10, it is faster
                with openmp on a core 2 duo.

    Returns
    -------
    symbolic 4D tensor
        Set of feature maps generated by convolutional layer. Tensor is
        of shape (batch size, nb filters, output row, output col).

    sl   The convolution need that the shape information are constant values. We got %s for the image_shape parametersm   The convolution need that the shape information are constant values. We got %s for the filter_shape parameteri   s   image s	    filters i    i   t   output_modet   dxt   dyt   imshpt   kshpt   nkernt   bsizeN(   NN(   NN(   t   Nonet   listR   t   lenR   R   R	   t   dtypet   theanot   tensort   discrete_dtypest   AssertionErrort   intt	   Exceptiont   printt   ConvOp(   t   inputt   filterst   image_shapet   filter_shapet   border_modet	   subsamplet   kargst   iR   R   R   R   t   op(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   conv2d(   sX    ; !


 R#   c        4   B` s  e  Z d  Z d d d d d d d d d	 d
 d d d g Z d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d d g1 Z dw dx g Z dy dz g Z e d d d{   Z e d d| d}   Z	 d d d d d d d| d d d d d e d~ d d d d  Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z d   Z  d   Z! RS(   s  
    This Op serves a dual purpose: it can implement a vanilla 2D convolution
    (as taught in any signal processing class) or implement the
    convolutional layers found in Convolutional Neural Networks.

    In this setting, a set of 3D images is convolved with a set of 3D kernels,
    with the particularity that their leading dimensions are of equal length.
    Vanilla 2D convolution is treated as a special case of this.

    The input parameter represents a mini-batch of multiple images. Its shape is:
        batch size x num. input feature maps x image height x image width

    The kernel parameter represents a set of 3D kernels. Its shape is:
        number of filters x num. input images x filter height x filter width

    The output of ConvOp is a 4D tensor, generated as follows:
        output[b,k,:,:] = \sum_i input[b,i,:,:] * filter[k,i,:,:] orall b,k
    where b is the mini-batch index, k the filter index and * is the
    convolution operator.

    The constructor initializes a ConvOp with given output_mode (full/valid).
    All other parameters are optional and are only used to generate more
    optimized c code, or to enable graph optimizers to optimally replace the
    ConvOp.

    NOTES ON OPTIMIZATION:
    There are two types of optimization. The first is the selection of the
    fastest algo when bsize and nkern are provided with imshp and kshp.
    By default we try to select the fastest version. You can specify it
    with the unroll_batch, unroll_kern, and unroll_patch parameter.

    The second type of optimization is hardcoding some dimensions into the
    code when all shape are know.
    This make a significant difference for the 'full' output_mode.

    Sometimes, the fastest implementation on x86-64 uses
    {unroll_batch=4, unroll_kern=4, unroll_patch=False}
    with all other shape parameters being provided.

    For optimizing other architectures, see:
    Kazushige Goto and Robert A. Van De Geijn, Anatomy of High-Performance
    Matrix Multiplication, (mr x nr). ACM Transactions on Mathematical
    Software, May 2008.
    Figure 12: (mr x nr). For x86 use 2x4, itanium 8x8, etc.

    Parameters
    ----------
    output_mode : {'valid', 'full'}
        'valid' gives an output smaller then the image.
        'full' gives an output bigger then the image.
         See 'border_mode' in conv2d's doc.

    Optional parameters: (will generate more optimal c code)

    imshp : tuple of len 2 or 3: 2 for 2d image, 3 for a stack of 2d images.
        Stacksize, nb image row, nb image col.
    kshp : tuple of len 2
        Nb kernel row, nb kernel col.
    nkern : int
        The number of kernel.
    bsize : int
        The size of the minibatch.
    dx : int
        Patch stride rows.
    dy : int
        Patch stride cols

    Params which select the version of code used:

    unroll_patch : bool
        Use a version of c_code that unroll the patch loop that don't
        request all shape information to work, but if all shape information
        are present, will use it to hardcode the value in the code for
        faster code.
    unroll_batch : int
        Use a version of c_code that unroll the batch (by unroll_batch)
        and the nkern (by unroll_kern) loop. The size must by a multiple
        of bsize or nkern respectively.
    unroll_kern : int
        Use a version of c_code that unroll the batch
        (by unroll_batch) and the nkern(by unroll_kern) loop. The size
        must by a multiple of bsize or nkern respectively.
    verbose : int
        Passed to GpuConv.
    version: int or str
        Passed to GpuConv, if version='no_fft', fft
        optimization will be desactivated at the op level.
    direction_hint: {'forward', 'bprop weights', 'bprop inputs'}
        Passed to GpuConv, used by graph optimizers to aid algorithm choice.

    The 3 following parameters are used internally when we generate
    the gradient when dx!=1 or dy!=1.

    imshp_logical
        Default None. None value is equivalent to imshp value.
        When imshp_logical != imshp, it tell we need to insert 0 in
        the image before we do the convolution. For example, when dx==dy==2
        and the image is [[1, 2], [3, 4]], we should make as if the image
        was [[1, 0, 2, 0], [0, 0, 0, 0], [3, 0, 4, 0], [0, 0, 0, 0]].
        Our python code insert the zero, but the c code optimize it.
        imshp_logical != imshp when taking the grad again the weights or
        the image when the output_mode is full and `dx != 1` or `dy != 1`.
    kshp_logical
        Idem but for kshp and used for the grad again the
        weights when the output_mode is valid and `dx != 1` or `dy != 1`.
    kshp_logical_top_aligned
        Used in the same case. Default to True.
        Set to False in the grad again the weight when the
        output_mode is full.

    R   R   R   R   R   R   t   out_modet   unroll_batcht   unroll_kernt   unroll_patcht   imshp_logicalt   kshp_logicalt   kshp_logical_top_alignedi   g   @g   m0@i   g    d?g   P@i   g   3?g   WF@i   g    e?g   
@i   g   ?g    '	@i   g   ?g   4@i
   g   !j?g   @V@g   ?g   @g   e?g    D@g   6?g   b@g   @?g   c@g   v?g   03@g   E?g   @g   @5?g   	@g   Y?g   `@g   @7?g    !@g   @?g   `<\@g    
J?g    B+@g   ?g   a@g   @Q?g   @g   ?g    (@g   w?g   [
@g   @?g   `V@g   ?g   ?@g   @?g   `@g    |?g   h@g   '?g   i@g   n?g   @V@g   ʕ?g   `d	@g   @i?g   R@g   &?g   @g   ?g   @g   @?g   ]2@g   @u?g   @g    ?g   @g    =?g   B+@g   [?g   B@g   ?g    @g   @?g    v@g    8Y?g   `j@g    ?g   @g   ?g   @@g   @=?g   @g    @y?g   @@g   ŵ?g   @g   @s?g   Q@g   ?g   @;@g   W?g   @f@g   @9?g   9@g    X @g   0E@g    g?g    @c         C` sB   | d  k	 oA | d  k	 oA t d   |  D  oA t d   | D  S(   Nc         s` s   |  ] } | d  k	 Vq d  S(   N(   R   (   t   .0t   shp(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>W  s    c         s` s   |  ] } | d  k	 Vq d  S(   N(   R   (   R5   R6   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>X  s    (   R   t   all(   R   R   R   R   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   has_all_shapeT  s    R   c         ` s9   t  j d d d t   f d   t |  | |  D  S(   s
  
        Computes the output dimensions of convolving an image of shape "inshp"
        with kernels of shape "kshp". Accepts symbolic or integer shapes.
        Propagates `None`s (for unknown shapes).

        Parameters
        ----------
        inshp
            (rows,cols) of input image.
        kshp
            (rows,cols) of filters.
        mode: {'valid', 'full'}
            See 'border_mode' in conv2d's doc.

        Returns
        -------
        object
            (rows,cols) of output image.

        sM   The method `getOutputShape` is deprecated use`get_conv_output_shape` instead.t
   stackleveli   c         3` s-   |  ]# \ } } } t  | |   |  Vq d  S(   N(   R   (   R5   R+   t   kt   d(   t   mode(    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>u  s   (   t   warningst   warnt   tuplet   zip(   t   inshpR   t   strideR<   (    (   R<   s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   getOutputShapeZ  s    i    it   forwardc      	   C` s  | d k r t  |  _ d } n	 t |  _ | d  k r< d } n t |  } | d  k r] d } n t |  } t |  d k r d | } n+ t |  d k r t d t |    n  t |  d k r t d t |    n  | d  k r d } n  | d  k rd } n  t |  | k r,t d |   n  t |  } t |  | k r\t d	 |   n  t |  } |  j	 | | | |  } | s|	 r| rt
 d
   n  t t |   j d |  | s|  j rt }
 n  | |  _ | |  _ | |  _ | |  _ | |  _ | |  _ | |  _ | |  _ | |  _ | d  k r@|  j |  _ n@ t |  } t |  d k rwt d t |    n  | |  _ | d  k r|  j |  _ n@ t |  } t |  d k rt d t |    n  | |  _ | |  _ | |  _ |	 |  _ |
 |  _ |  j r|  j rd |  _ n  |  j r=|  j r=d |  _ n  |  j d  k	 r|  j d k r|  j |  j d k r|  j |  j k r|  j |  _ q|  j } | d k st  x! |  j | d k r| d 8} qWd } t j  | |  j |  j |  | |  _ n  |  j d  k	 r|  j d k r|  j |  j d k r|  j |  j k rT|  j |  _ q|  j } | d k sot  x! |  j | d k r| d 8} qrWd } t j  | |  j |  j |  | |  _ n  t! d |  j d |  j | | | f  d |  _" t! d |  j d |  j | d  d |  _# | |  _$ |  j$ d  k rOt
 d t% |  j$    n  t& d   |  j" D  rt
 d |  j |  j f   n  |  j d  k ry|  j d  k ry|  j d  k ry|  j d  k r|  j d  k rt |  _ ng|  j d  k	 rE|  j d  k	 rE|  j } |  j } d } |  j$ d k r,d } n  |  j	 |  j |  j  rT|  j' | } n |  j( | } d } x t) t |  j*   D]x } | |  j* | d d k r}| |  j* | d d k r}|  j* | d | | k  r|  j* | d | } | } qq}q}W| | k  rt |  _ qE|  j* | d |  _ |  j* | d |  _ t  |  _ n  t j+ d |  j |  j |  j |  j |  j | |  n  |  j,   d  S(!   Nt   no_fftii   i   i   s!   len(imshp) must be 2 or 3, got %ds   len(kshp) must be 2, got %ds'   ConvOp.__init__ param dx must be an ints'   ConvOp.__init__ param dy must be an intsI   In ConvOp, when using unroll_batch and unroll_nkern, all shape are neededt   openmps$   len(imshp_logical) must be 3, got %ds#   len(kshp_logical) must be 2, got %di    s   OPTIMISATION WARNING: in ConvOp.__init__() unroll_batch(%i) must be 0 or a divisor of bsize(%i). We revert it to %i. This won't change the result, but may make it slower.s   OPTIMISATION WARNING: in ConvOp.__init__() unroll_kern(%i) should be 0 or a divisor of nkern(%i). We revert it to %i. This won't change the result, but may make it slower.R   t   fulls   Mode %s not implementedc         s` s'   |  ] } | d k	 o | d  k Vq d S(   i    N(   R   (   R5   R6   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>  s    s   Bad size for the output shape. Verify that [post-supersampling] input shape (%s) and kern shape(%s) are ok. (Hint: kerns must fit inside image in valid mode)i s;   AUTO FIND VERSION OF C_CODE OF CONV OP %s %s %s %s %s %s %s(   NNN(   NN(   i   (   N(   NN(   N(   NN(   i   i   (   R   s   full(-   t   Falset   fft_optt   TrueR   R?   R   t
   ValueErrorR    t	   TypeErrorR8   R!   t   superR#   t   __init__RF   R   R   R   R   R   R   t   verboset   versiont   direction_hintR2   R3   R4   R/   R0   R1   R   t   _loggerR>   R   t   outshpt
   fulloutshpR.   t   strt   anyt   speed_unroll_patch_shapet   speed_unroll_patch_noshapeR   t   speed_unroll_batch_kernt   debugt   _rehash(   t   selfR   R   R   R   R   R   R   R/   R0   R1   R2   R3   R4   RO   RP   RQ   RF   t	   all_shapet   newt   warnstrt   mode_idxt   time_unroll_patcht   time_unroll_batch_kernR+   t   time_unroll_batch_kern_idx(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyRN   x  s   																							4	4	



					
c         C` sV   t  |   t  |  k r t Sx3 |  j D]( } t |  |  t | |  k r& t Sq& Wt S(   N(   t   typeRH   t   _ConvOp__attrnamest   getattrRJ   (   R\   t   othert   a(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   __eq__H  s    c         C` s9   t  t |   j |  | j d d   |  _ |  j   d  S(   NRQ   (   RM   R#   t   __setstate__t   getR   RQ   R[   (   R\   R;   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyRj   P  s    c         C` sL   t  t |    } x* |  j D] } | t  t |  |   A} q W| |  _ d  S(   N(   t   hashRd   Re   Rf   t   _ConvOp__hashval(   R\   t   hashvalRh   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyR[   U  s    c         C` s   |  j  S(   N(   Rm   (   R\   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   __hash__[  s    c         ` s(   d d j    f d     j D  d S(   Ns   ConvOp{t   ,c         3` s*   |  ]  } t  | t   |  f  Vq d  S(   N(   RU   Rf   (   R5   Rh   (   R\   (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>_  s   t   }(   t   joinRe   (   R\   (    (   R\   s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   __str__^  s    c         C` s   | \ } } | \ } | d | d k s/ t   d } |  j d k r | d | d d } | | d | d 9} | | d | d | d 9} n> | d | d | d | d | d | d | d d } | S(   sI   
        Useful with the hack in profiling to print the MFlops.

        i   i    R   i   i   (   R   R.   (   R\   t   inputst   outputst   imagest   kernst   outt   flops(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyRy   b  s    	!>c         C` s  t  |  } t  |  } | j d k rC t d | | j f   n  | j d k ra t d   n  | j j | j j k r t d | j | j f   n  |  j d d k |  j d d k g } t j j d | j j d | j	 d | j	 d g |  } t
 |  | | g | g  S(	   s   
        Parameters
        ----------
        inputs
            4 dim: batches x stacksize x rows x cols.
        kerns
            4 dim: nkern x stackidx x rows x cols.

        i   sI   ConvOp (make_node) requires input be a 4D tensor; received "%s" (%i dims)s'   make_node requires 4D tensor of kernelssF   The image and the kernel must have the same type.inputs(%s), kerns(%s)i    i   R   t   broadcastable(   R   t   ndimRL   Rd   R   t   NotImplementedErrorRS   R   R   Rz   R
   (   R\   Rt   Rw   t   _inputst   _kernst   bcastable23t   output(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt	   make_nodex  s"    &

c   	      C` sG  | d } | d } | d t  | d  } } | d t  | d  } } |  j d  k	 re |  j } n  x> d d d g D]- } |  j | d  k	 ru |  j | | | <qu qu W|  j d  k	 r |  j } n  x; d d g D]- } |  j | d  k	 r |  j | | | <q q Wt | f t |  | d  f t |  |  j |  j	 |  j
 f  } | g S(   Ni    i   i   (   R   R   R   R2   R   R3   R   R?   R.   R   R   (	   R\   t   nodet   input_shapesR   R   R   R   R+   t   res(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   infer_shape  s(    

c         C` s  | \ } } | \ } t  sH t j j j d t |   |  j j d   n  |  j } t	 d   | D  r} t
 | j d  } n  | | j d k r t d | | j d   n  |  j } t	 d   | D  r t
 | j d  } n  | | j d k rt d | | j d   n  |  j }	 |	 d k r5| j d	 }	 n/ |	 | j d	 k rdt d
 |	 | j d	   n  |  j }
 |
 d k r| j d	 }
 n/ |
 | j d	 k rt d |
 | j d	   n  |  j } | d	 d k r| d	 f | d } n  | d d k r| d	 | d | d f } n  | d d k r?| d  | d f } n  t d   | D  s[t  |  j } | d	 d k r| d	 | d f } n  | d d k r| d	 | d f } n  t d   | D  st  t d   |  j D  rt
 |  j  } n$ t d | d | |  j d  d } | d	 d k sJ| d	 j |	 |
 f | k rst j |	 |
 f | d | j | d	 <n  | d	 } | d	 } | j |	 f |  } | j |
 | f |  } |  j |  j k r{t t j | d t | d    } t t j | d t | d    } t j |	 f | d | j } | | d d  d d  d d |  d d |  f <| } ~ ~ ~ n  | | k rt t j | d	 t | d	    } t t j | d t | d    } t j |
 | f |  j d | j } |  j rd	 } } nh | d	 | d	 | d | | } | d | d | d | | } | d	 k sft  | d	 k sxt  | | d d  d d  | d |  | d |  f <| } ~ ~ ~ n  t  |  j  } t! d  } t" j#    t" j$ d t j%  x t& |	  D] } x t& |
  D] } | | | d f j' d	  x\ t& |  D]N } | | | d f c t( | | | d f | | | d f d | | d	  7<qFWqWqWWd QXt) rt) rk|  j d k rkt j |	 | | d d | d	 d | d d | d d f  } | | d d  d d  | d	 d | d	 d | d  | d d | d d | d  f <| } n  x!t& |	  D]} xt& |
  D] } | | | d f j' d	  x t& |  D] } x t& d	 | j d |  j*  D] } x t& d	 | j d |  j+  D]z } | | | | | f c | | | | | | d	  | | | d  f | | | d d d  d d d  f j,   7<qWqWqWqWqxWn  |  j* d k s|  j+ d k r| d d  d d  d	 d |  j*  d	 d |  j+  f j-   } n  | | d	 <d S(   s=   
        By default if len(img2d.shape)==3, we TODO

        t	   c_headerss   Need the python package for scipy.signal to be installed for the python implementation. You can use the C implementation instead.c         s` s   |  ] } | d  k Vq d  S(   N(   R   (   R5   t   x(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>  s    i   sS   The image shape provided at build time is different from the one passed at run timec         s` s   |  ] } | d  k Vq d  S(   N(   R   (   R5   R   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>  s    i   sT   The filter shape provided at build time is different from the one passed at run timei    sR   The batch size provided at build time is different from the one passed at run timesY   The number of filters provided at build time is different from the one passed at run timec         s` s   |  ] } | d  k	 Vq d  S(   N(   R   (   R5   R   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>  s    c         s` s   |  ] } | d  k	 Vq d  S(   N(   R   (   R5   R   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>  s    c         s` s   |  ] } | d  k	 Vq d  S(   N(   R   (   R5   R6   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>  s    R   Nt   fillt   ignore.RG   i   i(   N(   NN(   i   i   (.   t   imported_scipy_signalR   t   goft   utilst   MethodNotDefinedRd   t	   __class__t   __name__R   RV   R?   t   shapeRK   R   R   R   R   R2   R7   R   R3   RT   R   R.   t   numpyt   zerosR   t   reshapeR    t   ceilt   floatR4   R   R   R=   t   catch_warningst   simplefiltert   ComplexWarningR   R   R   RH   R   R   t   sumt   copy(   R\   R   t   inpRx   t   img2dt   filtersflippedt   zR   R   R   R   R2   R3   RT   t   zzt   stacklent   rstridet   cstridet   buft   roffsett   coffsett   valt   bvalt   bt   nt   im0t   img2d2t   rowt   col(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   perform  s    							-

''4''	""4&$ ^	##FCc         C` s   d  } | d d  k	 r: |  j | d | d  j d } n  | d d  k	 r | d  k rz |  j | d | d  j d } q | |  j | d | d  j d 7} n  | g S(   Ni    i   (   R   R   Ru   (   R\   Rt   t   eval_pointst   rval(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   R_opF  s    $$(c         C` s  | \ } } | \ } |  j  |  j k s9 |  j |  j k rH t d   n  |  j d k r|  j |  j f d' k r| j d d d d d  } | j	 d  k	 r d | j	 | _	 n  | d  d   d  d   d  d  d	  d  d  d	  f } | j	 d  k	 rd
 | j	 | _	 n  | j d d d d d  } | j	 d  k	 r?d | j	 | _	 n  t j j j d | d | d t j j t j d d | j | j d  d |  j |  j d f  }	 t j j |	 d  j d d d d  }
 t j j d d  d i | |
 6d | | g  S|  j d( k s|  j d) k r t d   n  |  j |  j  |  j |  j |  j  } | rx|  j d k si|  j d k rxt d   n  | j d k r| j d k st  | j d*  } | j d+  } |  j } |  j d k rI| | } } |  j } t } d  } |  j  d |  j } } |  j |  j  d |  j  d f } |  j  } |  j! } |  j" } n |  j d k r| | } } d  } t# } |  j |  j d |  j d f } |  j |  j  d } } |  j |  j  d |  j  d f } |  j  d } |  j" } |  j! } n t d   | d  d   d  d   d  d  d	  d  d  d	  f } t$ | | | | d d d d d d  d d  d d  d | d | d | d  |  j% d! d" d# |  j& 
} | | |  } | rt' d$   t( | j) j* j  |  j  D  st  n  |  j d k r%| j d,  } | d  d   d  d   d  d  d	  d  d  d	  f } n  d } |  j d k sCd } n  | j d-  } | d  d   d  d   d  d  d	  d  d  d	  f } |  j  d } |  j |  j  d |  j  d f } |  j |  j d |  j d f } t$ | |  j | |  j d d d | d d  d d  d d  d | d d  d  d	 d! d% d# |  j& 	} | | |  } t' d&   t( | j) j* j  |  j  d  D  sqt  t+ | | j,  } t+ | | j,  } | | g S(.   Nt   todoR   i   i    i   i   R   s   shuffle_for_conv3D(%s)is   flipped(%s)s   shuffled_for_conv3D(%s)t   Vt   WR   R   R;   i   t   costt   known_gradst   wrts   ERROR: We disable ConvOp.grad now when output_mode is not 'valid' and dx or dy are greater than 2, as there is a bug in it. See `abstract_conv2d <>`_ for a version that support this.sO   ConvOp.grad when dx!=1 or dy!=1 we must have all the optional shape informationRG   s0   Only [full,valid] modes are currently supported.R   R/   R0   R1   R2   R3   R4   RP   RQ   s   bprop weightsRO   c         s` s!   |  ] \ } } | | k Vq d  S(   N(    (   R5   t   oR:   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>  s    s   bprop inputsc         s` s-   |  ]# \ } } | d  k p$ | | k Vq d  S(   N(   R   (   R5   R   R+   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pys	   <genexpr>  s   (   i   i   (   i   i   (   i   i   (   i   i    i   i   (   i   i    i   i   (   i   i    i   i   (   i   i    i   i   (-   R   R2   R   R3   R|   R.   R   R   t
   dimshufflet   nameR   R   R   t   nnett   conv3Dt   allocR   t   asarrayR   R   t   addbroadcastt   gradientt   gradR8   R   R   R!   R{   R   R1   RT   RH   RS   R/   R0   RJ   R#   RP   RO   R7   R@   t   ownerR,   R   Rz   (   R\   R   t   gradsRt   Rw   t   gzt   shuffled_inputst   flipped_kernst   shuffled_kernst   tmp_nodeR   R]   t   newint   newgzt   un_pt   imgR%   R3   R4   R2   R   R   R   R   t   un_bt   un_kt   dwR<   t   din(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyR   Q  s    	$'4	%$		 		
 		4"	47	4 	,c         C` s   d d d g S(   Ns   <numpy/noprefix.h>s
   <iostream>s	   <sstream>(    (   R\   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyR     s    c         C` s   d |  j  t j   f S(   Ni   (   RF   R   t   blas_header_version(   R\   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   c_code_cache_version	  s    c         C` s   d t  j   S(   Ns   
#define STRIDES(arr) (PyArray_STRIDES(arr))
#define FULL  2
#define SAME  1
#define VALID 0
#define MOD %
using namespace std;
(   R   t   blas_header_text(   R\   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   c_support_code  s    c         C` s   |  j  d k r |  j d k r |  j d k r |  j |  j k sx |  j |  j k sx |  j sx |  j d k sx |  j	 d k r| t
 St St
 S(   s=    Return True if we will generate code that use gemm.
        R   i    (   R.   R   R   R   R2   R   R3   R1   R/   R0   RH   RJ   (   R\   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   use_blas  s    -	c         C` s   |  j    r t j   Sg  S(   N(   R   R   t   ldflags(   R\   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   c_libraries%  s    
c         C` s6   t  j j j   d k r. |  j d k r. d g Sg  Sd  S(   Ns   4.3.0i   s   -O3(   s   4.3.0(   i   i   (   R   R   t   cmodulet   gcc_versionR   (   R\   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   c_no_compile_args*  s    c         C` s   g  } |  j    r- t j d t d t  } n  t j j j   d k rd |  j	 d k rd | d g 7} n  | t
 t |   j   7} | S(   Nt   libst   flagss   4.3.0i   s   -O2(   s   4.3.0(   i   i   (   R   R   R   RH   RJ   R   R   R   R   R   RM   R#   t   c_compile_args(   R\   t   ret(    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyR   3  s    c         C` s&   |  j    r" t j d t d t  Sg  S(   NR   t   libs_dir(   R   R   R   RH   RJ   (   R\   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt
   c_lib_dirs@  s    c         C` s&   |  j    r" t j d t d t  Sg  S(   NR   t   include_dir(   R   R   R   RH   RJ   (   R\   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   c_header_dirsE  s    c      
   C` sr	  | \ } } | \ } | j  d j j | j  d j j k rG t    n  | j  d j j | j  d j j k ss t  t   }	 |	 j |  |  j |  j |  j	 |  j
 |  j  o |  j |  j |  j  }
 |  j |	 d <|  j |	 d <|  j |	 d <|  j j   |	 d <d |	 d <d	 |	 |	 d
 <d |	 |	 d <d |	 d <d |	 d <d |	 |	 d <d |	 |	 d <d |	 |	 d <d |	 |	 d <d |	 |	 d <d |	 d <|  j	 d d  k	 r|	 d } |  j	 d } |	 d c d t d | d | |  7<|  j	 d |	 d <n  |  j	 d d  k	 rQ|	 d } |  j	 d } |	 d c d t d | d | |  7<|  j	 d |	 d <n  |  j d d  k	 rd  } |  j d } |	 d c d! t d | d | |  7<|  j d |	 d <n  |  j d d  k	 rd" } |  j d } |	 d c d# t d | d | |  7<|  j d |	 d <n  |  j d d  k	 r|	 d } |  j d } |	 d c d$ t d | d | |  7<d% } |  j d } |	 d c d& t d | d | |  7<|  j d |	 d <n  |  j d d  k	 r|	 d } |  j d } |	 d c d' t d | d | |  7<|  j d |	 d <n  |  j d( d  k	 rv|	 d } |  j d( } |	 d c d) t d | d | |  7<|  j d( |	 d <n  |  j d  k	 r|	 d
 } |  j } |	 d c d* t d | d | |  7<|  j |	 d
 <n  |  j
 d  k	 r&|	 d } |  j
 } |	 d c d+ t d | d | |  7<|  j
 |	 d <n  |
 ru|  j d |	 d, <|  j d |	 d- <t t j |  j d t |  j	 d    |	 d. <t t j |  j d t |  j	 d    |	 d/ <|  j d |	 d0 <|  j d( |	 d1 <t t j |  j d t |  j d    |	 d2 <t t j |  j d( t |  j d(    |	 d3 <|  j d d k sTd4 |	 d <n  d5 |	 d6 <d7 |	 d8 <d |	 d9 <n@ d4 |	 d <d: |	 d6 <d |	 d8 <d; |	 |	 d9 <|	 d c d< | 7<|  j rd |	 d= <d |	 d> <n{ |
 rP|	 d. } |	 d/ } |  j d |  j	 d | d | | |	 d= <|  j d |  j	 d | d | | |	 d> <~ ~ n  | j  d j j d? k rvd@ |	 dA <nC | j  d j j dB k rdC |	 dA <n t dD | j  d j j   dE |	 dF <|	 dA dC k sdG |	 dF <n  |  j |  j k s|  j	 |  j k r%|  j rt j dH  n  t |	 S|  j rR|  j rJt j dI |
  n  t  |	 S|  j! d  k	 rp|  j! d k s|  j" d  k	 r|  j" d k r|  j! d k st  |  j" d k st  |  j rt j dJ t# |  j!  t# |  j"   n  t$ |	 |  j! |  j"  S|  j dK k rM	|  j d k rM	|  j d k rM	|  j rE	t j dL  n  t% |	 S|  j rf	t j dM  n  t |	 Sd  S(N   Ni    i   t   self_out_modet   self_dxt   self_dyR<   t   =t   affectations   PyArray_DIMS(%(img2d)s)[0]t
   self_bsizes#   PyArray_DIMS(%(filtersflipped)s)[0]t
   self_nkerns   -1t   self_outshp0t   self_outshp1s   PyArray_DIMS(%(img2d)s)[1]t   self_imshp0s   PyArray_DIMS(%(img2d)s)[2]t   self_imshp1s   PyArray_DIMS(%(img2d)s)[3]t   self_imshp2s#   PyArray_DIMS(%(filtersflipped)s)[2]t
   self_kshp0s#   PyArray_DIMS(%(filtersflipped)s)[3]t
   self_kshp1t    t   assert_sizes  
if(%(value)s != %(expected)s){
    PyErr_Format(PyExc_ValueError,
            "The hardcoded shape for the number of rows in the filter "
            "(%%ld) isn't the run time shape (%%ld).",
            (long)%(value)s, (long)%(expected)s);
    %(fail)s;
}
            t   expectedt   values  
if(%(value)s != %(expected)s){
    PyErr_Format(PyExc_ValueError,
            "The hardcoded shape for the number of columns in the filter "
            "(%%ld) isn't the run time shape (%%ld).",
            (long)%(value)s, (long)%(expected)s);
    %(fail)s;
}
            s	   dim_zz[0]s  
if(%(value)s != %(expected)s){
    PyErr_Format(PyExc_ValueError,
            "The hardcoded shape for the number of rows in the output "
            "(%%ld) isn't the run time shape (%%ld).",
            (long)%(value)s, (long)%(expected)s);
    %(fail)s;
}
            s	   dim_zz[1]s  
if(%(value)s != %(expected)s){
    PyErr_Format(PyExc_ValueError,
            "The hardcoded shape for the number of columns in the output "
            "(%%ld) isn't the run time shape (%%ld).",
            (long)%(value)s, (long)%(expected)s);
    %(fail)s;
}
            s  
if(%(value)s != %(expected)s){
    PyErr_Format(PyExc_ValueError,
            "The hardcoded shape for the image stack size (%%ld) "
            "isn't the run time shape (%%ld).",
            (long)%(value)s, (long)%(expected)s);
    %(fail)s;
}
            s   kerns_dim[1]s  
if(%(value)s != %(expected)s){
    PyErr_Format(PyExc_ValueError,
            "The hardcoded shape for the kernel stack size (%%ld) "
            "isn't the run time shape (%%ld).",
            (long)%(value)s, (long)%(expected)s);
    %(fail)s;
}
            s  
if(%(value)s != %(expected)s){
    PyErr_Format(PyExc_ValueError,
            "The hardcoded shape for the number of rows in the image "
            "(%%ld) isn't the run time shape (%%ld).",
            (long)%(value)s, (long)%(expected)s);
    %(fail)s;
}
            i   s  
if(%(value)s != %(expected)s){
    PyErr_Format(PyExc_ValueError,
            "The hardcoded shape for the number of columns in the image "
            "(%%ld) isn't the run time shape (%%ld).",
            (long)%(value)s, (long)%(expected)s);
    %(fail)s;
}
            s   
if(%(value)s != %(expected)s){
    PyErr_Format(PyExc_ValueError,
            "The hardcoded shape for the batch size (%%ld) "
            "isn't the run time shape (%%ld).",
            (long)%(value)s, (long)%(expected)s);
    %(fail)s;
}
            s  
if(%(value)s != %(expected)s){
    PyErr_Format(PyExc_ValueError,
            "The hardcoded shape for the number of kernels in the filter "
            "(%%ld) isn't the run time shape (%%ld).",
            (long)%(value)s, (long)%(expected)s);
    %(fail)s;
}
            t   self_kshp_logical_rt   self_kshp_logical_ct   self_kshp_logical_stride_rt   self_kshp_logical_stride_ct   self_imshp_logical_rt   self_imshp_logical_ct   self_imshp_logical_stride_rt   self_imshp_logical_stride_cs   +=t   1R]   t   constt   dim_zz_constt   dim_zz_affectt   0s>  
  if (mode == FULL) {
    dim_zz[0] = (int)ceil((dim_im[0]+dim_ker0-1)/float(%(self_dx)s));
    dim_zz[1] = (int)ceil((dim_im[1]+dim_ker1-1)/float(%(self_dy)s));
  } else {
    dim_zz[0] = (int)ceil((dim_im[0]-dim_ker0+1)/float(%(self_dx)s));
    dim_zz[1] = (int)ceil((dim_im[1]-dim_ker1+1)/float(%(self_dy)s));
  }
s"  
// Check the stack size of the filter and images are equals
if(kerns_dim[1] != img2d_dim[1]){
    PyErr_Format(PyExc_ValueError,
            "the filter stack size (%%ld) and image stack size (%%ld) differ",
            (long)kerns_dim[1], (long)img2d_dim[1]);
    %(fail)s;
}
            t   self_kshp_logical_offset_rt   self_kshp_logical_offset_ct   float32R   Rd   t   float64t   doubles   Type %s not implementedt   dgemm_t   gemmt   sgemm_sK   return imshp!=imshp_logical or self.kshp != self.kshp_logical shape versions)   return unroll patch version. all_shape=%ss-   return unrolled batch (%s) and kern code (%s)R   s   return gemm versions   return no gemm version(&   Rt   Rd   R   R|   R   t   localst   updateR8   R   R   R   R   R2   R3   R.   R   R   t   upperR   t   dictRS   R    R   R   R   R4   R!   RO   RR   RZ   t   _conv_op_code_aR1   t   _conv_op_code_unroll_patchR/   R0   RU   t   gen_conv_code_unroll_batch_kernt   _conv_op_code_valid_gemm(   R\   R   R   R   Rx   t   subR   R   R   R;   R]   R   R   R   R   (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   c_codeJ  s,   	&,	

















	

	
	(	(	(	(




	

	


,,	
$				
		
-		(   i   i   g   @g   m0@(   i   i   g    d?g   P@(   i   i   g   3?g   WF@(   i   i   g    e?g   
@(   i   i   g   ?g    '	@(   i   i   g   ?g   4@(   i   i
   g   !j?g   @V@(   i   i   g   ?g   @(   i   i   g   e?g    D@(   i   i   g   6?g   b@(   i   i   g   @?g   c@(   i   i   g   v?g   03@(   i   i   g   E?g   @(   i   i
   g   @5?g   	@(   i   i   g   Y?g   `@(   i   i   g   @7?g    !@(   i   i   g   @?g   `<\@(   i   i   g    
J?g    B+@(   i   i   g   ?g   a@(   i   i   g   @Q?g   @(   i   i
   g   ?g    (@(   i   i   g   w?g   [
@(   i   i   g   @?g   `V@(   i   i   g   ?g   ?@(   i   i   g   @?g   `@(   i   i   g    |?g   h@(   i   i   g   '?g   i@(   i   i
   g   n?g   @V@(   i   i   g   ʕ?g   `d	@(   i   i   g   @i?g   R@(   i   i   g   &?g   @(   i   i   g   ?g   @(   i   i   g   @?g   ]2@(   i   i   g   @u?g   @(   i   i
   g    ?g   @(   i   i   g    =?g   B+@(   i   i   g   [?g   B@(   i   i   g   ?g    @(   i   i   g   @?g    v@(   i   i   g    8Y?g   `j@(   i   i   g    ?g   @(   i   i
   g   ?g   @@(   i
   i   g   @=?g   @(   i
   i   g    @y?g   @@(   i
   i   g   ŵ?g   @(   i
   i   g   @s?g   Q@(   i
   i   g   ?g   @;@(   i
   i   g   W?g   @f@(   i
   i
   g   @9?g   9@(   i   i   N("   R   t
   __module__t   __doc__Re   RY   RX   RW   t   staticmethodR8   RC   R   RJ   RN   Ri   Rj   R[   Ro   Rs   Ry   R   R   R   R   R   R   R   R   R   R   R   R   R   R   R  (    (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyR#      s   o									 							
							s'  
const int mode=%(mode)s;
int typenum=0, typenum_f=0;
PyArrayObject *ain1=NULL, *ain2=NULL;
PyArrayObject *filtersflipped_arr=NULL, *img2d_arr=NULL, *z_arr=NULL;
const %(type)s fill_value = 0;

int type_im=PyArray_TYPE(%(img2d)s);
int type_ker=PyArray_TYPE(%(filtersflipped)s);

npy_intp dim_zz[2]={%(self_outshp0)s,%(self_outshp1)s};
npy_intp dim_im_phys[2]={%(self_imshp1)s,%(self_imshp2)s};
npy_intp dim_im_log[2]={%(self_imshp_logical_r)s,%(self_imshp_logical_c)s};
npy_intp dim_ker_phys[2]={%(self_kshp0)s,%(self_kshp1)s};
npy_intp dim_ker_log[2]={%(self_kshp_logical_r)s,%(self_kshp_logical_c)s};

PyArray_Dims img2d_shape;
npy_intp img2d_dim[4]={1,1,0,0};
img2d_shape.ptr=img2d_dim;
img2d_shape.len=4;

PyArray_Dims kerns_shape;
npy_intp kerns_dim[4]={1,1,0,0};
kerns_shape.ptr=kerns_dim;
kerns_shape.len=4;
PyObject *img2d=NULL, *contig, *filtersflipped=NULL;


if(PyArray_NDIM(%(img2d)s)==2){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[0];
}else if(PyArray_NDIM(%(img2d)s)==3){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[2];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[0]=PyArray_DIMS(%(img2d)s)[0];
}else if(PyArray_NDIM(%(img2d)s)==4){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[3];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[2];
  img2d_dim[1]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[0]=PyArray_DIMS(%(img2d)s)[0];
}else {
    PyErr_SetString(PyExc_ValueError, "img don't have a good shape");
    %(fail)s;
}

if(PyArray_NDIM(%(filtersflipped)s)==3){
  kerns_dim[3]=PyArray_DIMS(%(filtersflipped)s)[2];
  kerns_dim[2]=PyArray_DIMS(%(filtersflipped)s)[1];
  kerns_dim[0]=PyArray_DIMS(%(filtersflipped)s)[0];
}else if(PyArray_NDIM(%(filtersflipped)s)==4){
  kerns_dim[3]=PyArray_DIMS(%(filtersflipped)s)[3];
  kerns_dim[2]=PyArray_DIMS(%(filtersflipped)s)[2];
  kerns_dim[1]=PyArray_DIMS(%(filtersflipped)s)[1];
  kerns_dim[0]=PyArray_DIMS(%(filtersflipped)s)[0];
}else{
    std::stringstream temp;
    temp << "nddim="<<PyArray_NDIM(%(filtersflipped)s);
    std::string param = temp.str();
    PyErr_SetString(PyExc_ValueError,
      ("kernel don't have a good shape. " + param).c_str());
    %(fail)s;
}

%(assert_size)s

img2d = PyArray_Newshape(%(img2d)s,&img2d_shape, NPY_CORDER);
img2d_arr = (PyArrayObject*)img2d;
if ((PyArray_STRIDES(img2d_arr)[3] != (npy_intp)sizeof(%(type)s))
     || (PyArray_STRIDES(img2d_arr)[2] != PyArray_DIMS(img2d_arr)[3]*(npy_intp)sizeof(%(type)s))){
    contig = (PyObject*)(PyArray_GETCONTIGUOUS((PyArrayObject*)img2d));
    Py_DECREF(img2d);
    img2d = contig;
    img2d_arr = (PyArrayObject*)img2d;
    if (!PyArray_ISCONTIGUOUS(img2d_arr)){
        PyErr_SetString(PyExc_ValueError, "img2d isn't contiguous");
        %(fail)s;
    }
}

filtersflipped = PyArray_Newshape(%(filtersflipped)s,&kerns_shape, NPY_CORDER);
filtersflipped_arr = (PyArrayObject*)filtersflipped;
if ((PyArray_STRIDES(filtersflipped_arr)[3] != (npy_intp)sizeof(%(type)s))
     || (PyArray_STRIDES(filtersflipped_arr)[2] != PyArray_DIMS(filtersflipped_arr)[3]*(npy_intp)sizeof(%(type)s))){
    contig = (PyObject*)(PyArray_GETCONTIGUOUS((PyArrayObject*)filtersflipped));
    Py_DECREF(filtersflipped);
    filtersflipped = contig;
    filtersflipped_arr = (PyArrayObject*)filtersflipped;
    if (!PyArray_ISCONTIGUOUS(filtersflipped_arr)){
        PyErr_SetString(PyExc_ValueError, "filtersflipped isn't contiguous");
        %(fail)s;
    }
}

if(mode != VALID && mode != FULL){
  PyErr_SetString(PyExc_ValueError,
                  "invalid mode, only full and valid are supported");
  %(fail)s;
}
typenum = PyArray_ObjectType((PyObject*)%(img2d)s, 0);
typenum_f = PyArray_ObjectType((PyObject*)%(filtersflipped)s, 0);
if (typenum < 0) {PyErr_SetString(PyExc_ValueError, "Invalid type"); %(fail)s;}
if (typenum != typenum_f) {
  PyErr_SetString(PyExc_ValueError, "Input types must match");
  %(fail)s;
}

if (!img2d)
{
    PyErr_SetString(PyExc_AssertionError, "!img2d");
    %(fail)s;
}
if (!filtersflipped)
{
    PyErr_SetString(PyExc_AssertionError, "!filtersflipped");
    %(fail)s;
}

if ((!%(z)s)
  || *PyArray_DIMS(%(z)s)!=4
  ||(PyArray_DIMS(%(z)s)[0] != %(self_bsize)s)
  ||(PyArray_DIMS(%(z)s)[1] != %(self_nkern)s)
  ||(PyArray_DIMS(%(z)s)[2] != dim_zz[0])
  ||(PyArray_DIMS(%(z)s)[3] != dim_zz[1])
  ||!PyArray_ISCONTIGUOUS(%(z)s)
  )
{
  {Py_XDECREF(%(z)s);}
  npy_intp dims[4] = {0,0,0,0};
  dims[0]=%(self_bsize)s;
  dims[1]=%(self_nkern)s;
  dims[2]=dim_zz[0];
  dims[3]=dim_zz[1];
  %(z)s = (PyArrayObject*) PyArray_ZEROS(4, dims, typenum,0);
}else{
  //PyArray_FILLWBYTE((PyObject*)%(z)s,0);
}
z_arr = (PyArrayObject*) %(z)s;

int Os[2];
Os[0]=%(self_outshp0)s;
Os[1]=%(self_outshp1)s;

//assertions
if (!PyArray_ISCONTIGUOUS(%(z)s))
{
    PyErr_SetString(PyExc_AssertionError, "Output (%(z)s) not contiguous");
    %(fail)s;
}

for(int b=0;b< %(self_bsize)s;b++){
  for(int n_kern=0;n_kern<%(self_nkern)s;n_kern++){

    %(type)s * __restrict__ out=(%(type)s *)(PyArray_GETPTR2(z_arr,b,n_kern));
    for (int i = 0; i < dim_zz[0]*dim_zz[1]; ++i) out[i] = 0;

    for(int stack_size=0;stack_size<%(self_imshp0)s;stack_size++){

      const %(type)s * __restrict__ in=(%(type)s *)(PyArray_GETPTR2(img2d_arr,b,stack_size));
      const %(type)s * __restrict__ hvals=(%(type)s *)(PyArray_GETPTR2(filtersflipped_arr,n_kern,stack_size));


      for (int iter_m=0; iter_m < Os[0]; iter_m++) {
        // Reposition index into input image based on requested output size
        //row position in logical output image
        int pos_m = iter_m*%(self_dx)s;
        //row anchor in logical input image (we will loop upward from here)
        int new_m;
        if (mode == FULL) new_m = pos_m ;
        else new_m = (pos_m+dim_ker_log[0]-1);

        for (int iter_n=0; iter_n < Os[1]; iter_n++) {  // loop over columns
          // current col position in logical output image
          int pos_n=iter_n*%(self_dy)s;
          %(type)s sum=0;

          // Sum over kernel, if index into image is out of bounds
          // fill with the value
          // loop over logical rows in kernel
          for (int j_log=0; j_log < %(self_kshp_logical_r)s; j_log++) {
            // ind0_log: row position in logical input image
            int ind0_log = (new_m-j_log);

            if ((j_log < %(self_kshp_logical_offset_r)s) ||
                (j_log - %(self_kshp_logical_offset_r)s) MOD %(self_kshp_logical_stride_r)s)
                continue;

            if (ind0_log MOD %(self_imshp_logical_stride_r)s)
                continue;

            int j_phys = ((j_log- %(self_kshp_logical_offset_r)s) /
                          %(self_kshp_logical_stride_r)s);
            int ind0_phys = (ind0_log / %(self_imshp_logical_stride_r)s);
            //std::cerr <<"j_log" << j_log << " j_phys " << j_phys << " " << ind0_phys << "\n";

            if(mode==FULL){
              //This is a pointer to the current row of the kernel
              const %(type)s * idx_hvals=&hvals[j_phys*dim_ker_phys[1]];
              if(ind0_log < 0 || ind0_log >= dim_im_log[0]){
                   // the current row of the kernel is off the image
              }else{
                int k = max((int)(pos_n-dim_im_log[1])+1,0);
                int max_k=min(pos_n+1,(int)dim_ker_log[1]);
                const %(type)s * idx_in=&in[ind0_phys*dim_im_phys[1]];
                for (int ind1_log=pos_n-k; k<max_k; k++,ind1_log--) {
                    if (1)
                    {
                                if ((k < %(self_kshp_logical_offset_c)s) ||
                                    (k - %(self_kshp_logical_offset_c)s) MOD
                                    %(self_kshp_logical_stride_c)s)
                                    continue;

                                if (ind1_log MOD
                                    %(self_imshp_logical_stride_c)s)
                                    continue;
                    }
                  sum += idx_hvals[(k-%(self_kshp_logical_offset_c)s) /
                                   %(self_kshp_logical_stride_c)s] *
                            idx_in[ind1_log / %(self_imshp_logical_stride_c)s];
                }
              }
            }else{ // mode==VALID
              //JB: should be dim_im[1] right? (was dim_im[0])
              const %(type)s* idx_in=&in[ind0_phys*dim_im_phys[1]];
              const %(type)s* idx_hvals=&hvals[j_phys*dim_ker_phys[1]];
              int new_n = (pos_n+dim_ker_log[1]-1);
              if (%(self_imshp_logical_stride_c)s != 1)  // a general loop
              {
                  for (int k=0,last=new_n; k < dim_ker_log[1]; k++,last--) {
                        if ((k < %(self_kshp_logical_offset_c)s) ||
                            (k - %(self_kshp_logical_offset_c)s) MOD
                            %(self_kshp_logical_stride_c)s)
                            continue;

                        else if (last MOD %(self_imshp_logical_stride_c)s)
                            continue;
                            else
                            {
                    sum+=idx_hvals[(k-%(self_kshp_logical_offset_c)s) /
                                   %(self_kshp_logical_stride_c)s] *
                             idx_in[last/%(self_imshp_logical_stride_c)s];
                    }
                  }
              }
              else  // self_imshp_stride_c == 1
              {
                  int offset = %(self_kshp_logical_offset_c)s;
                  int k_phys=0;
                  for (int k_log=offset,last=new_n-offset;
                       k_log < dim_ker_log[1]; ) {
                    sum += idx_hvals[k_phys]*idx_in[last];
                    ++k_phys;
                    last -= %(self_kshp_logical_stride_c)s;
                    k_log += %(self_kshp_logical_stride_c)s;
                  }
              }
            }
          }//for j_log
          out[iter_m*dim_zz[1]+iter_n] %(affectation)s sum;
        }//for iter_n
      }//for iter_m
    }//for stack_size
    if (0 && (mode==FULL)){
      for (int i = 0; i < dim_zz[0]*dim_zz[1]; ++i)
        std::cout << " " << out[i];
      std::cout << "\n";
    }
  }//for n_kern
}//for b
Py_XDECREF(img2d);
Py_XDECREF(filtersflipped);
s!  
int typenum=0, typenum_f=0;
PyArrayObject *ain1=NULL, *ain2=NULL, *img2d_arr=NULL, *z_arr=NULL;
const int NKERN = %(self_nkern)s;

int type_im=PyArray_TYPE(%(img2d)s);
int type_ker=PyArray_TYPE(%(filtersflipped)s);

npy_intp dim_zz[2]={%(self_outshp0)s,%(self_outshp1)s};
npy_intp dim_im[2]={%(self_imshp1)s,%(self_imshp2)s};
const npy_intp dim_ker0=%(self_kshp0)s;
const npy_intp dim_ker1=%(self_kshp1)s;

PyArray_Dims img2d_shape;
npy_intp img2d_dim[4]={1,1,0,0};
img2d_shape.ptr=img2d_dim;
img2d_shape.len=4;

PyArray_Dims kerns_shape;
npy_intp kerns_dim[4]={1,1,0,0};
kerns_shape.ptr=kerns_dim;
kerns_shape.len=4;
PyObject *img2d=NULL, *contig;

if(PyArray_NDIM(%(img2d)s)==2){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[0];
}else if(PyArray_NDIM(%(img2d)s)==3){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[2];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[0]=PyArray_DIMS(%(img2d)s)[0];
}else if(PyArray_NDIM(%(img2d)s)==4){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[3];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[2];
  img2d_dim[1]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[0]=PyArray_DIMS(%(img2d)s)[0];
}else {
    PyErr_SetString(PyExc_ValueError, "img don't have a good shape");
    %(fail)s;
}

if(PyArray_NDIM(%(filtersflipped)s)==3){
  kerns_dim[3]=PyArray_DIMS(%(filtersflipped)s)[2];
  kerns_dim[2]=PyArray_DIMS(%(filtersflipped)s)[1];
  kerns_dim[0]=PyArray_DIMS(%(filtersflipped)s)[0];
}else if(PyArray_NDIM(%(filtersflipped)s)==4){
  kerns_dim[3]=PyArray_DIMS(%(filtersflipped)s)[3];
  kerns_dim[2]=PyArray_DIMS(%(filtersflipped)s)[2];
  kerns_dim[1]=PyArray_DIMS(%(filtersflipped)s)[1];
  kerns_dim[0]=PyArray_DIMS(%(filtersflipped)s)[0];
}else{
    std::stringstream temp;
    temp << "nddim="<<PyArray_NDIM(%(filtersflipped)s);
    std::string param = temp.str();
    PyErr_SetString(PyExc_ValueError,
      ("kernel don't have a good shape. " + param).c_str());
    %(fail)s;
}
if (NKERN != kerns_dim[0])
{
    PyErr_SetString(PyExc_NotImplementedError, "nonsense nkern");
    %(fail)s;
}

img2d = PyArray_Newshape(%(img2d)s,&img2d_shape, NPY_CORDER);
img2d_arr = (PyArrayObject*)img2d;
if ((PyArray_STRIDES(img2d_arr)[3] != (npy_intp)sizeof(%(type)s))
     || (PyArray_STRIDES(img2d_arr)[2] != PyArray_DIMS(img2d_arr)[3]*(npy_intp)sizeof(%(type)s))){
    contig = (PyObject*)(PyArray_GETCONTIGUOUS((PyArrayObject*)img2d));
    Py_DECREF(img2d);
    img2d = contig;
    img2d_arr = (PyArrayObject*)img2d;
    if (!PyArray_ISCONTIGUOUS(img2d_arr)){
        PyErr_SetString(PyExc_ValueError, "img2d isn't contiguous");
        %(fail)s;
    }
}

typenum = PyArray_ObjectType((PyObject*)%(img2d)s, 0);
typenum_f = PyArray_ObjectType((PyObject*)%(filtersflipped)s, 0);
if (typenum < 0) {PyErr_SetString(PyExc_ValueError, "Invalid type"); %(fail)s;}
if (typenum != typenum_f) {PyErr_SetString(PyExc_ValueError, "Input types must match"); %(fail)s;}

if (!img2d) {
    PyErr_SetString(PyExc_ValueError, "Null argument img2d");
    %(fail)s;
}
if ((!%(z)s)
  || *PyArray_DIMS(%(z)s)!=4
  ||(PyArray_DIMS(%(z)s)[0] != %(self_bsize)s)
  ||(PyArray_DIMS(%(z)s)[1] != %(self_nkern)s)
  ||(PyArray_DIMS(%(z)s)[2] != dim_zz[0])
  || (PyArray_DIMS(%(z)s)[3] != dim_zz[1])
  )
{
  {Py_XDECREF(%(z)s);}
  npy_intp dims[4] = {0,0,0,0};
  dims[0]=%(self_bsize)s;
  dims[1]=%(self_nkern)s;
  dims[2]=dim_zz[0];
  dims[3]=dim_zz[1];
  %(z)s = (PyArrayObject*) PyArray_ZEROS(4, dims, typenum,0);
}else{
  PyArray_FILLWBYTE((PyObject*)%(z)s,0);
}
z_arr = (PyArrayObject*) %(z)s;

%(assert_size)s

int Os[2];
Os[0] = dim_im[0]-dim_ker0+1;
Os[1] = dim_im[1]-dim_ker1+1;

// allocate a temporary buffer for storing the inner product of each nth kernel row
// with each row of an image
{
%(type)s * kbuf = (%(type)s *)malloc((Os[0] * NKERN + PyArray_Size((PyObject*)%(filtersflipped)s))* (npy_intp)sizeof(%(type)s));
int kbufstride = NKERN;
%(type)s * myfilters = kbuf + Os[0] * NKERN;

//copy out filtersflipped into filters un-flipped format
//std::cerr << "__filling myfilters__\n";
for(int i=0;i < kerns_dim[0];++i){
    for(int j=0;j < kerns_dim[1];++j){
        for(int k=0;k < kerns_dim[2];++k){
            for(int l=0;l < kerns_dim[3];++l){
                %(type)s * ff = ((PyArray_NDIM(%(filtersflipped)s)) == 3)
                    ? (%(type)s *)PyArray_GETPTR3(%(filtersflipped)s, i, kerns_dim[2]-1-k, kerns_dim[3]-1-l)
                    : (%(type)s *)PyArray_GETPTR4(%(filtersflipped)s, i, j, kerns_dim[2]-1-k, kerns_dim[3]-1-l);
                myfilters[i * (kerns_dim[1]*kerns_dim[2]*kerns_dim[3])
                          + j * (kerns_dim[2]*kerns_dim[3])
                          + k * (kerns_dim[3])
                          + l] = ff[0];
                //std::cerr << " " << ff[0];
            }
            //std::cerr << "\n";
        }
        //std::cerr << "(end of stack/batch " <<j << "/" << i << "  ) \n";
    }
}

//std::cerr << "-----new loop ----\n";
for(int b=0;b< %(self_bsize)s;b++){
    for (int img_col = 0; img_col < Os[1]; ++img_col){
        for (int filter_row = 0; filter_row < kerns_dim[2]; ++filter_row){
            for (int stackidx = 0; stackidx < %(self_imshp0)s; ++stackidx){
                %(type)s * img_colview =
                    (%(type)s *)(PyArray_GETPTR4(img2d, b, stackidx, filter_row, img_col));
                %(type)s * filter_rows = myfilters + stackidx * (kerns_dim[2]*kerns_dim[3]) +
                filter_row * kerns_dim[3];
                //std::cerr << "filterview offset: " << filter_rows - myfilters << "\n";

                char N = 'N'; char T = 'T';
                int Nz0 = Os[0];
                int Nz1 = NKERN;
                int K = kerns_dim[3];
                %(type)s alpha = 1.0;
                %(type)s beta = stackidx ? 1.0 : 0.0;
                int imgview_stride = dim_im[1];
                int filter_rows_stride =kerns_dim[1]*kerns_dim[2]*kerns_dim[3];
                //remember, Fortran wants a column-major interpretation
                assert(PyArray_STRIDES(img2d)[3] == (npy_intp)sizeof(%(type)s));

                if (0){
                    std::cerr << "b " << b << " img_col " << img_col << " filterrow " << filter_row << " stackidx " <<stackidx << "\n";
                    std::cerr << "colview (physical layout) stride: " << imgview_stride << "\n";
                    for (int ii = 0; ii < Nz0; ++ii){
                        for (int jj = 0; jj < K; ++jj){
                            std::cerr << " " << img_colview[ii * imgview_stride + jj];
                        }
                        std::cerr << "\n";
                    }
                    std::cerr << "filterview ("<<filter_row<<"'th rows) stride: " << filter_rows_stride << "\n";
                    for (int ii = 0; ii < Nz1; ++ii){
                        for (int jj = 0; jj < K; ++jj){
                            std::cerr << " " << filter_rows[ii * filter_rows_stride + jj];
                        }
                        std::cerr << "\n";
                    }

                    std::cerr << Nz1 << " " << Nz0 << " " << K << "\n" ;
                }

                %(gemm)s(&T, &N,
                    &Nz1, &Nz0, &K,
                    &alpha,
                    filter_rows, &filter_rows_stride,
                    img_colview, &imgview_stride,
                    &beta, kbuf, &kbufstride);

                if (0){
                    std::cerr << "z (logical layout) beta" << beta << "\n";
                    for (int ii = 0; ii < Nz0; ++ii){
                        for (int jj = 0; jj < Nz1; ++jj){
                            std::cerr << " " << kbuf[ii * kbufstride + jj];
                        }
                        std::cerr << "\n";
                    }
                }
            }
            // now kbuf the sum over the stack, put it into the outbuf
            for (int img_row = 0; img_row < Os[0]; ++img_row) {
                for (int kernel_idx = 0; kernel_idx < NKERN; ++kernel_idx) {
                    %(type)s * z_p =  (%(type)s *)PyArray_GETPTR4(%(z)s, b, kernel_idx, img_row, img_col);
                    if (0)
                    {
                        if (b >= PyArray_DIMS(%(z)s)[0]) %(fail)s;
                        if (kernel_idx >= PyArray_DIMS(%(z)s)[1]) %(fail)s;
                        if (img_row >= PyArray_DIMS(%(z)s)[2]) %(fail)s;
                        if (img_col >= PyArray_DIMS(%(z)s)[3]) %(fail)s;
                    }
                    z_p[0] += kbuf[img_row * kbufstride + kernel_idx];
                }
            }
        }
    }
}
free(kbuf);
}
Py_XDECREF(img2d);
c         ` sv   d k r  d k s t   d   k sZ d   k sZ d   k sZ d   k sZ d   k ri t d   n    j        d <   d <  f d   }     f d	   } d
   } | | d  7} | | d    7} | d   7} | | d   7} | | d   7} | d   7} | | d    7} | d   7} | | d   7} | d   7} | | d  7} | d   7} | | d  7} | d   7} | | d   7} | d   7} | | d  7} | d   7} | | d  7} | d   7} | | d   7} | | d   7} | d   7} | | d   7} | d!   7} | | d"    7} | d# 7} | S($   s=   
    c_code for ConvOp that unroll the batch size loop.

    i    t   unroll_bsizet   unroll_ksizet   unroll_itert   unroll_bitert   unroll_kitersG   We can't use this dictionnary as we will overwrite some of its containtc         ` s=   d } x, t  |  D] } |   d <| |    7} q W| d S(   NR   R  s   
(   R   (   t   stt   sizet   sR+   (   R;   (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   my_dupQ  s
    
c         ` sx   d } d } xa t    D]S } |   d <x@ t    D]2 } |   d <|   d <| d 7} | |    7} q6 Wq W| d S(   NR   i    R  R  R  i   s   
(   R   (   R  R  t   iterR+   t   j(   R;   R  R  (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   my_dup2X  s    



s  
const int mode=%(mode)s;
int typenum=0, typenum_f=0;
PyArrayObject *ain1=NULL, *ain2=NULL, *filtersflipped_arr=NULL, *img2d_arr=NULL, *z_arr=NULL;;
const %(type)s fill_value = 0;

int type_im=PyArray_TYPE(%(img2d)s);
int type_ker=PyArray_TYPE(%(filtersflipped)s);

npy_intp dim_zz[2]={%(self_outshp0)s,%(self_outshp1)s};
npy_intp dim_im[2]={%(self_imshp1)s,%(self_imshp2)s};
const npy_intp dim_ker0=%(self_kshp0)s;
const npy_intp dim_ker1=%(self_kshp1)s;

PyArray_Dims img2d_shape;
npy_intp img2d_dim[4]={1,1,0,0};
img2d_shape.ptr=img2d_dim;
img2d_shape.len=4;

PyArray_Dims kerns_shape;
npy_intp kerns_dim[4]={1,1,0,0};
kerns_shape.ptr=kerns_dim;
kerns_shape.len=4;
PyObject *img2d=NULL, *contig, *filtersflipped=NULL;

if(PyArray_NDIM(%(img2d)s)==2){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[0];
}else if(PyArray_NDIM(%(img2d)s)==3){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[2];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[0]=PyArray_DIMS(%(img2d)s)[0];
}else if(PyArray_NDIM(%(img2d)s)==4){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[3];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[2];
  img2d_dim[1]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[0]=PyArray_DIMS(%(img2d)s)[0];
}else {
    std::stringstream temp;
    temp << "nddim="<<PyArray_NDIM(%(img2d)s);
    std::string param = temp.str();
    PyErr_SetString(PyExc_ValueError,
      ("img don't have a good shape. " + param).c_str());
    %(fail)s;
}

if(PyArray_NDIM(%(filtersflipped)s)==3){
  kerns_dim[3]=PyArray_DIMS(%(filtersflipped)s)[2];
  kerns_dim[2]=PyArray_DIMS(%(filtersflipped)s)[1];
  kerns_dim[0]=PyArray_DIMS(%(filtersflipped)s)[0];
}else if(PyArray_NDIM(%(filtersflipped)s)==4){
  kerns_dim[3]=PyArray_DIMS(%(filtersflipped)s)[3];
  kerns_dim[2]=PyArray_DIMS(%(filtersflipped)s)[2];
  kerns_dim[1]=PyArray_DIMS(%(filtersflipped)s)[1];
  kerns_dim[0]=PyArray_DIMS(%(filtersflipped)s)[0];
}else{
    PyErr_SetString(PyExc_ValueError, "kernel don't have a good shape");
    %(fail)s;
}

%(assert_size)s

img2d = PyArray_Newshape(%(img2d)s,&img2d_shape, NPY_CORDER);
img2d_arr = (PyArrayObject*)img2d;
if ((PyArray_STRIDES(img2d_arr)[3] != (npy_intp)sizeof(%(type)s))
     || (PyArray_STRIDES(img2d_arr)[2] != PyArray_DIMS(img2d_arr)[3]*(npy_intp)sizeof(%(type)s))){
    contig = (PyObject*)(PyArray_GETCONTIGUOUS((PyArrayObject*)img2d));
    Py_DECREF(img2d);
    img2d = contig;
    img2d_arr = (PyArrayObject*)img2d;
    if (!PyArray_ISCONTIGUOUS(img2d_arr)){
        PyErr_SetString(PyExc_ValueError, "img2d isn't contiguous");
        %(fail)s;
    }
}

filtersflipped = PyArray_Newshape(%(filtersflipped)s,&kerns_shape, NPY_CORDER);
filtersflipped_arr = (PyArrayObject*)filtersflipped;
if ((PyArray_STRIDES(filtersflipped_arr)[3] != (npy_intp)sizeof(%(type)s))
     || (PyArray_STRIDES(filtersflipped_arr)[2] != PyArray_DIMS(filtersflipped_arr)[3]*(npy_intp)sizeof(%(type)s))){
    contig = (PyObject*)(PyArray_GETCONTIGUOUS((PyArrayObject*)filtersflipped));
    Py_DECREF(filtersflipped);
    filtersflipped = contig;
    filtersflipped_arr = (PyArrayObject*)filtersflipped;
    if (!PyArray_ISCONTIGUOUS(filtersflipped_arr)){
        PyErr_SetString(PyExc_ValueError, "filtersflipped isn't contiguous");
        %(fail)s;
    }
}

if(mode != VALID && mode != FULL){
  PyErr_SetString(PyExc_ValueError, "invalid mode, only full and valid are supported"); %(fail)s;
}
typenum = PyArray_ObjectType((PyObject*)%(img2d)s, 0);
typenum_f = PyArray_ObjectType((PyObject*)%(filtersflipped)s, 0);
if (typenum < 0) {PyErr_SetString(PyExc_ValueError, "Invalid type"); %(fail)s;}
if (typenum != typenum_f) {PyErr_SetString(PyExc_ValueError, "Input types must match"); %(fail)s;}

if (!img2d)
{
    PyErr_SetString(PyExc_AssertionError, "!img2d");
    %(fail)s;
}
if (!filtersflipped)
{
    PyErr_SetString(PyExc_AssertionError, "!filtersflipped");
    %(fail)s;
}

if ((!%(z)s)
  || *PyArray_DIMS(%(z)s)!=4
  ||(PyArray_DIMS(%(z)s)[0] != %(self_bsize)s)
  ||(PyArray_DIMS(%(z)s)[1] != %(self_nkern)s)
  ||(PyArray_DIMS(%(z)s)[2] != dim_zz[0])
  ||(PyArray_DIMS(%(z)s)[3] != dim_zz[1])
  ||!PyArray_ISCONTIGUOUS(%(z)s)
  )
{
  {Py_XDECREF(%(z)s);}
  npy_intp dims[4] = {0,0,0,0};
  dims[0]=%(self_bsize)s;
  dims[1]=%(self_nkern)s;
  dims[2]=dim_zz[0];
  dims[3]=dim_zz[1];
  %(z)s = (PyArrayObject*) PyArray_ZEROS(4, dims, typenum,0);
}else{
  //PyArray_FILLWBYTE((PyObject*)%(z)s,0);
}
z_arr = (PyArrayObject*) %(z)s;

int Os[2];
Os[0]=%(self_outshp0)s;
Os[1]=%(self_outshp1)s;

//assertions
if (!PyArray_ISCONTIGUOUS(%(z)s))
{
    PyErr_SetString(PyExc_AssertionError, "Output (%(z)s) not contiguous");
    %(fail)s;
}

for(int b=0;b< %(self_bsize)s ;b+=%(unroll_bsize)s){
  for(int n_kern=0;n_kern<%(self_nkern)s;n_kern+=%(unroll_ksize)s){

s{   %(type)s * __restrict__ out%(unroll_iter)s=(%(type)s *)(PyArray_GETPTR2(z_arr,b+%(unroll_biter)s,n_kern+%(unroll_kiter)s));sH   for (int i = 0; i < dim_zz[0]*dim_zz[1]; ++i) out%(unroll_iter)s[i] = 0;sD   
    for(int stack_size=0;stack_size<%(self_imshp0)s;stack_size++){
sv   const %(type)s * __restrict__ in%(unroll_iter)d=(%(type)s *)(PyArray_GETPTR2(img2d_arr,b+%(unroll_iter)s,stack_size));s   const %(type)s * __restrict__ hvals%(unroll_iter)s=(%(type)s *)(PyArray_GETPTR2(filtersflipped_arr,n_kern+%(unroll_iter)s,stack_size));s  

      int new_m;

      for (int iter_m=0; iter_m < Os[0]; iter_m++) {
        // Reposition index into input image based on requested output size
        int pos_m = iter_m*%(self_dx)s;//The position of the patch in the image
        if (mode == FULL) new_m = pos_m ;
        else new_m = (pos_m+dim_ker0-1);

        for (int iter_n=0; iter_n < Os[1]; iter_n++) {  // loop over columns
          int pos_n=iter_n*%(self_dy)s;
        s   %(type)s sum%(unroll_iter)s=0;s   

          // Sum over kernel, if index into image is out of bounds
          // fill with the value
          for (int j=0; j < dim_ker0; j++) {
            int ind0 = (new_m-j);

            if(mode==FULL){
sL   const %(type)s * idx_hvals%(unroll_iter)s=&hvals%(unroll_iter)s[j*dim_ker1];s   
              if(ind0 < 0 || ind0 >= dim_im[0]){
                if(fill_value!=0)
                  for (int k=0; k < dim_ker1; k++) {
s@   sum%(unroll_iter)s += idx_hvals%(unroll_kiter)s[k] * fill_value;s   
                  }
              }else{
                //do the part where kernel is to the right of the img

                int k=0,max_k=max((int)(pos_n-dim_im[1])+1,0);
                if(fill_value!=0){

                  for(k=0;k<max_k;k++){
s   
                  }
                }else {k=max_k;}

                //do the part where the kernel is on the img
                max_k=min(pos_n+1,(int)dim_ker1);
sJ   const %(type)s * idx_in%(unroll_iter)s=&in%(unroll_iter)s[ind0*dim_im[1]];s@   
                for (int ind1=pos_n-k; k<max_k; k++,ind1--) {

sQ   sum%(unroll_iter)s+= idx_hvals%(unroll_kiter)s[k] * idx_in%(unroll_biter)s[ind1];s   
                }
                //do the part to the left of the img
                if(fill_value!=0)
                  for(;k<dim_ker1;k++){
sD   
                  }
              }
            }else{//valid mode
sI   const %(type)s* idx_in%(unroll_iter)s=&in%(unroll_iter)s[ind0*dim_im[1]];sK   const %(type)s* idx_hvals%(unroll_iter)s=&hvals%(unroll_iter)s[j*dim_ker1];ss   
              int new_n = (pos_n+dim_ker1-1);

              for (int k=0,last=new_n; k < dim_ker1; k++,last--) {
sN   sum%(unroll_iter)s+=idx_hvals%(unroll_kiter)s[k]*idx_in%(unroll_biter)s[last];s3   
              }
            }

          }//for j
sO   out%(unroll_iter)s[iter_m*dim_zz[1]+iter_n] %(affectation)s sum%(unroll_iter)s;s   
        }//for n
      }//for m
    }//for stack_size
  }//for n_kern
}//for b
Py_XDECREF(img2d);
Py_XDECREF(filtersflipped);
(   R   R!   R   (   R;   R  R  R  R"  R   (    (   R;   R  R  s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyR  D  sd    <


	s*  
const int mode=%(mode)s;
int typenum=0, typenum_f=0;
PyArrayObject *ain1=NULL, *ain2=NULL, *filtersflipped_arr=NULL, *img2d_arr=NULL, *z_arr=NULL;
const %(type)s fill_value = 0;//only value of 0 are currently tested and correctly implemented

int type_im=PyArray_TYPE(%(img2d)s);
int type_ker=PyArray_TYPE(%(filtersflipped)s);

const npy_intp dim_im[2]={%(self_imshp1)s,%(self_imshp2)s};
//The following line caused gcc 4.3.0 20080428 (Red Hat 4.3.0-8) to crash
//const npy_intp dim_ker[2]={%(self_kshp0)s,%(self_kshp1)s};
// The next line had gcc don't crash.
const npy_intp dim_ker0=%(self_kshp0)s;
const npy_intp dim_ker1=%(self_kshp1)s;
%(dim_zz_const)s npy_intp dim_zz[2]={%(self_outshp0)s,%(self_outshp1)s};

%(dim_zz_affect)s
PyArray_Dims img2d_shape;
npy_intp img2d_dim[4]={1,1,0,0};
img2d_shape.ptr=img2d_dim;
img2d_shape.len=4;

PyArray_Dims kerns_shape;
npy_intp kerns_dim[4]={1,1,0,0};
kerns_shape.ptr=kerns_dim;
kerns_shape.len=4;
PyObject *img2d=NULL, *contig, *filtersflipped=NULL;

if(PyArray_NDIM(%(img2d)s)==2){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[0];
}else if(PyArray_NDIM(%(img2d)s)==3){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[2];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[0]=PyArray_DIMS(%(img2d)s)[0];
}else if(PyArray_NDIM(%(img2d)s)==4){
  img2d_dim[3]=PyArray_DIMS(%(img2d)s)[3];
  img2d_dim[2]=PyArray_DIMS(%(img2d)s)[2];
  img2d_dim[1]=PyArray_DIMS(%(img2d)s)[1];
  img2d_dim[0]=PyArray_DIMS(%(img2d)s)[0];
}else {
    PyErr_Format(PyExc_ValueError,
      "image don't have a good number of dimensions %%d. ", PyArray_NDIM(%(filtersflipped)s));
    %(fail)s;
}

if(PyArray_NDIM(%(filtersflipped)s)==3){
  kerns_dim[3]=PyArray_DIMS(%(filtersflipped)s)[2];
  kerns_dim[2]=PyArray_DIMS(%(filtersflipped)s)[1];
  kerns_dim[0]=PyArray_DIMS(%(filtersflipped)s)[0];
}else if(PyArray_NDIM(%(filtersflipped)s)==4){
  kerns_dim[3]=PyArray_DIMS(%(filtersflipped)s)[3];
  kerns_dim[2]=PyArray_DIMS(%(filtersflipped)s)[2];
  kerns_dim[1]=PyArray_DIMS(%(filtersflipped)s)[1];
  kerns_dim[0]=PyArray_DIMS(%(filtersflipped)s)[0];
}else{
    PyErr_Format(PyExc_ValueError,
      "kernel don't have a good number of dimensions %%d. ", PyArray_NDIM(%(filtersflipped)s));
    %(fail)s;
}

%(assert_size)s

img2d = PyArray_Newshape(%(img2d)s,&img2d_shape, NPY_CORDER);
img2d_arr = (PyArrayObject*)img2d;
if ((PyArray_STRIDES(img2d_arr)[3] != sizeof(%(type)s))
     || (PyArray_STRIDES(img2d_arr)[2] != PyArray_DIMS(img2d_arr)[3]*sizeof(%(type)s))){
    contig = (PyObject*)(PyArray_GETCONTIGUOUS((PyArrayObject*)img2d));
    Py_DECREF(img2d);
    img2d = contig;
    img2d_arr = (PyArrayObject*)img2d;
    if (!PyArray_ISCONTIGUOUS(img2d_arr)){
        PyErr_SetString(PyExc_ValueError, "img2d isn't contiguous");
        %(fail)s;
    }
}

filtersflipped = PyArray_Newshape(%(filtersflipped)s,&kerns_shape, NPY_CORDER);
filtersflipped_arr = (PyArrayObject*)filtersflipped;
if ((PyArray_STRIDES(filtersflipped_arr)[3] != sizeof(%(type)s))
     || (PyArray_STRIDES(filtersflipped_arr)[2] != PyArray_DIMS(filtersflipped_arr)[3]*sizeof(%(type)s))){
    contig = (PyObject*)(PyArray_GETCONTIGUOUS((PyArrayObject*)filtersflipped));
    Py_DECREF(filtersflipped);
    filtersflipped = contig;
    filtersflipped_arr = (PyArrayObject*)filtersflipped;
    if (!PyArray_ISCONTIGUOUS(filtersflipped_arr)){
        PyErr_SetString(PyExc_ValueError, "filtersflipped isn't contiguous");
        %(fail)s;
    }
}

if(mode != VALID && mode != FULL){
  PyErr_SetString(PyExc_ValueError, "invalid mode, only full and valid are supported"); %(fail)s;
}

if(dim_zz[0]<=0 || dim_zz[1]<=0){
PyErr_Format(PyExc_ValueError,
      "Output dimensions are not valid %%ldx%%ld",(long int)dim_zz[0],(long int)dim_zz[1]);
      %(fail)s;
}

typenum = PyArray_ObjectType((PyObject*)%(img2d)s, 0);
typenum_f = PyArray_ObjectType((PyObject*)%(filtersflipped)s, 0);
if (typenum < 0) {PyErr_SetString(PyExc_ValueError, "Invalid type"); %(fail)s;}
if (typenum != typenum_f) {PyErr_SetString(PyExc_ValueError, "Input types must match"); %(fail)s;}

if (!img2d) %(fail)s;
if (!filtersflipped) %(fail)s;
if ((!%(z)s)
  || *PyArray_DIMS(%(z)s)!=4
  ||(PyArray_DIMS(%(z)s)[0] != %(self_bsize)s)
  ||(PyArray_DIMS(%(z)s)[1] != %(self_nkern)s)
  ||(PyArray_DIMS(%(z)s)[2] != dim_zz[0])
  || (PyArray_DIMS(%(z)s)[3] != dim_zz[1])
  )
{
  if (%(z)s) Py_DECREF(%(z)s);
  npy_intp dims[4] = {0,0,0,0};
  if(!dims) %(fail)s;
  dims[0]=%(self_bsize)s;
  dims[1]=%(self_nkern)s;
  dims[2]=dim_zz[0];
  dims[3]=dim_zz[1];
  %(z)s = (PyArrayObject*) PyArray_ZEROS(4, dims, typenum,0);
}else{
  //PyArray_FILLWBYTE((PyObject*)%(z)s,0);
}
z_arr = (PyArrayObject*) %(z)s;

// assert the output is C-contiguous
if (!PyArray_ISCONTIGUOUS(%(z)s))
{
    PyErr_SetString(PyExc_AssertionError, "Output (%(z)s) not contiguous");
    %(fail)s;
}

//The if on the number of loop make a speed up for small array.
//with g++ 4.5.1. The compiler should be smart enough to do this himself!
#pragma omp parallel for schedule(static) if(%(self_bsize)s * %(self_nkern)s > 1)
// We merge the 2 loop into one to make it easier to parallelize on both
// This is the equivalent of those 2 lines.
//for(int b=0;b< %(self_bsize)s;b++){
// for(int n_kern=0;n_kern<%(self_nkern)s;n_kern++){
for(int batch_kern_idx=0;
    batch_kern_idx < %(self_bsize)s * %(self_nkern)s;
    batch_kern_idx++){
    int b = batch_kern_idx / %(self_nkern)s;
    int n_kern = batch_kern_idx %% %(self_nkern)s;

    %(type)s * __restrict__ out=(%(type)s *)(PyArray_GETPTR2(z_arr,b,n_kern));
    for (int i = 0; i < dim_zz[0]*dim_zz[1]; ++i) out[i] = 0;

    for(int stack_size=0;stack_size<%(self_imshp0)s;stack_size++){

      const %(type)s * __restrict__ in=(%(type)s *)(PyArray_GETPTR2(img2d_arr,b,stack_size));
      const %(type)s * __restrict__ hvals=(%(type)s *)(PyArray_GETPTR2(filtersflipped_arr,n_kern,stack_size));

      int new_m;

      for (int iter_m=0; iter_m < dim_zz[0]; iter_m++) {
        // Reposition index into input image based on requested output size
        int pos_m = iter_m*%(self_dx)s;//The position of the patch in the image
        if (mode == FULL) new_m = pos_m ;
        else new_m = (pos_m+dim_ker0-1);

        for (int iter_n=0; iter_n < dim_zz[1]; iter_n++) {  // loop over columns
          int pos_n=iter_n*%(self_dy)s;
          %(type)s sum=0;
          %(type)s sum2=0;
          %(type)s sum3=0;
          %(type)s sum4=0;
          int nb_sum=0;
          // Sum over kernel, if index into image is out of bounds
          // fill with the value
          for (int j=0; j < dim_ker0; j++) {
            int ind0 = (new_m-j);

            if(mode==FULL){
              const %(type)s * idx_hvals=&hvals[j*dim_ker1];
              if(ind0 < 0 || ind0 >= dim_im[0]){
                if(fill_value!=0)
                  for (int k=0; k < dim_ker1; k++) {
                    sum+= idx_hvals[k] * fill_value;
                  }
              }else{
                //do the part where kernel is to the right of the img
                int k=0,max_k=max((int)(pos_n-dim_im[1])+1,0);
                if(fill_value!=0){

                  for(k=0;k<max_k;k++){
                    sum+= idx_hvals[k]*fill_value;
                  }
                }else {k=max_k;}

                //do the part where the kernel is on the img
                max_k=min(pos_n+1,(int)dim_ker1);
                const %(type)s * idx_in=&in[ind0*dim_im[1]];

                if(iter_n + 4*%(self_dy)s < dim_zz[1]
                         && iter_n>dim_ker1-1
                         && iter_n<dim_im[1]-dim_ker1+1-3){
                  nb_sum=4;
                  for (int ind1=pos_n-k; k<max_k; k++,ind1--) {
                    sum+=idx_hvals[k]*idx_in[ind1];
                    sum2+=idx_hvals[k]*idx_in[ind1+%(self_dy)s];
                    sum3+=idx_hvals[k]*idx_in[ind1+2*%(self_dy)s];
                    sum4+=idx_hvals[k]*idx_in[ind1+3*%(self_dy)s];
                  }
                }else if(iter_n + 2*%(self_dy)s < dim_zz[1]
                         && iter_n>dim_ker1-1
                         && iter_n<dim_im[1]-dim_ker1+1){
                  nb_sum=2;
                  for (int ind1=pos_n-k; k<max_k; k++,ind1--) {
                    sum+=idx_hvals[k]*idx_in[ind1];
                    sum2+=idx_hvals[k]*idx_in[ind1+%(self_dy)s];
                  }
                }else{
                  nb_sum=1;
                  /*
                  %(type)s sum_=0;
                  if((k-max_k) & 0x1 != 0){
                    sum+= idx_hvals[k] * idx_in[pos_n-k];
                  }
                  for (int ind1=pos_n-k; k<max_k; k+=2,ind1-=2) {
                    sum+= idx_hvals[k] * idx_in[ind1];
                    sum_+= idx_hvals[k+1] * idx_in[ind1-1];
                  }
                  sum+=sum_;
                  */
                  for (int ind1=pos_n-k; k<max_k; k++,ind1--) {
                    sum+=idx_hvals[k]*idx_in[ind1];
                  }
                }
                //do the part to the left of the img
                if(fill_value!=0)
                  for(;k<dim_ker1;k++) sum+= idx_hvals[k]*fill_value;
              }
            }else{//valid mode
              const %(type)s* idx_in=&in[ind0*dim_im[1]];
              const %(type)s* idx_hvals=&hvals[j*dim_ker1];
              if(iter_n + 4*%(self_dy)s < dim_zz[1]){
                nb_sum=4;
                for (int k=dim_ker1-1,im_idx=pos_n; k >=0; k--,im_idx++) {
                  sum+=idx_hvals[k]*idx_in[im_idx];
                  sum2+=idx_hvals[k]*idx_in[im_idx+%(self_dy)s];
                  sum3+=idx_hvals[k]*idx_in[im_idx+2*%(self_dy)s];
                  sum4+=idx_hvals[k]*idx_in[im_idx+3*%(self_dy)s];
                }
              }else if(iter_n + 2*%(self_dy)s < dim_zz[1]){
                nb_sum=2;
                for (int k=dim_ker1-1,im_idx=pos_n; k >=0; k--,im_idx++) {
                  sum+=idx_hvals[k]*idx_in[im_idx];
                  sum2+=idx_hvals[k]*idx_in[im_idx+%(self_dy)s];
                }
              }else{
                nb_sum=1;
                for (int k=dim_ker1-1,im_idx=pos_n; k >=0; k--,im_idx++) {
                  sum+=idx_hvals[k]*idx_in[im_idx];
                }
              }
            }//else valid mode
          }//for j
          switch(nb_sum){
          case 4: out[iter_m*dim_zz[1]+iter_n+3] %(affectation)s sum4;
          case 3: out[iter_m*dim_zz[1]+iter_n+2] %(affectation)s sum3;
          case 2: out[iter_m*dim_zz[1]+iter_n+1] %(affectation)s sum2;
          case 1: out[iter_m*dim_zz[1]+iter_n] %(affectation)s sum;
          }
          iter_n+=nb_sum-1;
        }//for iter_n
      }//for iter_m
    }//for stack_size
}//for b and n_kern

Py_XDECREF(img2d);
Py_XDECREF(filtersflipped);
(*   R  t
   __future__R    R   R   t   loggingR   t	   six.movesR   R=   R   R   t   theano.tensorR   R   R   R   R	   t
   theano.gofR
   t    theano.tensor.nnet.abstract_convR   R   t   scipy.signal.signaltoolsR   R   t   scipy.signal.sigtoolsR   RJ   R   t   ImportErrorRH   t   __docformat__t	   getLoggerRR   R   R-   R#   R  R  R  R  (    (    (    s7   /tmp/pip-build-X4mzal/theano/theano/tensor/nnet/conv.pyt   <module>	   s@   (

s       +