class_docstr: Reshapes the input as a 2D tensor where each row is an pooling
  example.
  
  Parameters
  ----------
  mode : {'valid', 'ignore_borders', 'wrap_centered'}
      - 'valid' :
          Requires an input that is a multiple of the pooling factor
          (in each direction).
      - 'half' :
          Equivalent to 'valid' if we pre-pad with zeros the input on
          each side by (neib_shape[0]//2, neib_shape[1]//2)
      - 'full' :
          Equivalent to 'valid' if we pre-pad with zeros the input on
          each side by (neib_shape[0] - 1, neib_shape[1] - 1)
      - 'ignore_borders' :
          Same as valid, but will ignore the borders if the shape(s)
          of the input is not a multiple of the pooling factor(s).
      - 'wrap_centered' :
          ?? TODO comment
class_docstr_tok: ["Reshapes","the","input","as","a","2D","tensor","where","each","row","is","an","pooling","example",".","Parameters","--","--","--","--","--","mode",":","{","'valid","'",",","'ignore_borders","'",",","'wrap_centered","'","}","-","'valid","'",":","Requires","an","input","that","is","a","multiple","of","the","pooling","factor","(","in","each","direction",")",".","-","'half","'",":","Equivalent","to","'valid","'","if","we","pre-pad","with","zeros","the","input","on","each","side","by","(","neib_shape","[","0","]","\/\/2",",","neib_shape","[","1","]","\/\/2",")","-","'full","'",":","Equivalent","to","'valid","'","if","we","pre-pad","with","zeros","the","input","on","each","side","by","(","neib_shape","[","0","]","-","1",",","neib_shape","[","1","]","-","1",")","-","'ignore_borders","'",":","Same","as","valid",",","but","will","ignore","the","borders","if","the","shape","(","s",")","of","the","input","is","not","a","multiple","of","the","pooling","factor","(","s",")",".","-","'wrap_centered","'",":","?","?","TODO","comment"]
code: def perform(self, node, inp, out_, params):
      ten4, neib_shape, neib_step = inp
      (z,) = out_
      # GpuImages2Neibs should not run this perform in DebugMode
      if type(self) != Images2Neibs:
          raise theano.gof.utils.MethodNotDefined()
  
      def CEIL_INTDIV(a, b):
          if a % b:
              return (a // b) + 1
          else:
              return a // b
  
      grid_c = -1  # number of patch in height
      grid_d = -1  # number of patch in width
      assert ten4.ndim == 4
      assert neib_shape.ndim == 1
      assert neib_shape.shape[0] == 2
      assert neib_step.ndim == 1
      assert neib_step.shape[0] == 2
      c, d = neib_shape
      step_x, step_y = neib_step
      mode = self.mode
      if step_x <= 0 or step_y <= 0:
          raise ValueError(
              "neib_step wrong step ; values <= 0. Got "
              + str(neib_step)
          )
      if c <= 0 or d <= 0:
          raise ValueError(
              "neib_shape values <=0. Got " + str(neib_shape)
          )
  
      if mode == "wrap_centered":
          if (c % 2 != 1) or (d % 2 != 1):
              raise TypeError(
                  "Images2Neibs:"
                  " in mode wrap_centered need patch with odd shapes"
              )
  
          if (ten4.shape[2] < c) or (ten4.shape[3] < d):
              raise TypeError(
                  "Images2Neibs: in wrap_centered mode, don't support"
                  " image shapes smaller then the patch shapes:"
                  " neib_shape=(%d,%d), ten4[2:]=[%d,%d]"
                  % (c, d, ten4.shape[2], ten4.shape[3])
              )
          grid_c = CEIL_INTDIV(ten4.shape[2], step_x)
          grid_d = CEIL_INTDIV(ten4.shape[3], step_y)
      elif mode == "valid":
          if (ten4.shape[2] < c) or (
              ((ten4.shape[2] - c) % step_x) != 0
          ):
              raise TypeError(
                  "neib_shape[0]=%d, neib_step[0]=%d and"
                  " ten4.shape[2]=%d not consistent"
                  % (c, step_x, ten4.shape[2])
              )
          if (ten4.shape[3] < d) or (
              ((ten4.shape[3] - d) % step_y) != 0
          ):
              raise TypeError(
                  "neib_shape[1]=%d, neib_step[1]=%d and"
                  " ten4.shape[3]=%d not consistent"
                  % (d, step_y, ten4.shape[3])
              )
          # number of patch in height
          grid_c = 1 + ((ten4.shape[2] - c) // step_x)
          # number of patch in width
          grid_d = 1 + ((ten4.shape[3] - d) // step_y)
      elif mode == "ignore_borders":
          # number of patch in height
          grid_c = 1 + ((ten4.shape[2] - c) // step_x)
          # number of patch in width
          grid_d = 1 + ((ten4.shape[3] - d) // step_y)
      elif mode == "half":
          # This is equivalent to 'valid' with padding (c // 2, d // 2) on both sides
          # Thus the expanded image will have size (h + 2 * (c // 2), w + 2 * (d // 2))
          # Plugging these in the equation for 'valid' we get
          # h + 2 * (c // 2) - c  = h - (c % 2)
          # w + 2 * (d // 2) - c  = w - (d % 2)
          if (ten4.shape[2] < c) or (
              ((ten4.shape[2] - (c % 2)) % step_x) != 0
          ):
              raise TypeError(
                  "neib_shape[0]=%d, neib_step[0]=%d and"
                  " ten4.shape[2]=%d not consistent"
                  % (c, step_x, ten4.shape[2])
              )
          if (ten4.shape[3] < d) or (
              ((ten4.shape[3] - (d % 2)) % step_y) != 0
          ):
              raise TypeError(
                  "neib_shape[1]=%d, neib_step[1]=%d and"
                  " ten4.shape[3]=%d not consistent"
                  % (d, step_y, ten4.shape[3])
              )
          # number of patch in height
          grid_c = 1 + ((ten4.shape[2] - (c % 2)) // step_x)
          # number of patch in width
          grid_d = 1 + ((ten4.shape[3] - (d % 2)) // step_y)
      elif mode == "full":
          # This is equivalent to 'valid' with padding (c - 1, d - 1) on both sides
          # Thus the expanded image will have size (h + 2 * (c - 1), w + 2 * (d - 1))
          # Plugging these in the equation for 'valid' we get
          # h + 2 * (c - 1) - c  = h + c - 2
          # w + 2 * (d - 1) - c  = w + d - 2
          if (ten4.shape[2] < c) or (
              ((ten4.shape[2] + c - 2) % step_x) != 0
          ):
              raise TypeError(
                  "neib_shape[0]=%d, neib_step[0]=%d and"
                  " ten4.shape[2]=%d not consistent"
                  % (c, step_x, ten4.shape[2])
              )
          if (ten4.shape[3] < d) or (
              ((ten4.shape[3] + d - 2) % step_y) != 0
          ):
              raise TypeError(
                  "neib_shape[1]=%d, neib_step[1]=%d and"
                  " ten4.shape[3]=%d not consistent"
                  % (d, step_y, ten4.shape[3])
              )
          # number of patch in height
          grid_c = 1 + ((ten4.shape[2] + c - 2) // step_x)
          # number of patch in width
          grid_d = 1 + ((ten4.shape[3] + d - 2) // step_y)
      else:
          raise TypeError("Images2Neibs: unknow mode '%s'" % mode)
      z_dim0 = grid_c * grid_d * ten4.shape[1] * ten4.shape[0]
      z_dim1 = c * d
      z[0] = np.empty((z_dim0, z_dim1), dtype=node.outputs[0].dtype)
  
      nb_batch = ten4.shape[0]
      nb_stack = ten4.shape[1]
      height = ten4.shape[2]
      width = ten4.shape[3]
  
      wrap_centered_half_idx_shift_x = c // 2
      wrap_centered_half_idx_shift_y = d // 2
      for n in range(nb_batch):
          for s in range(nb_stack):
              # loop over the number of patch in height
              for a in range(grid_c):
                  # loop over the number of patch in width
                  for b in range(grid_d):
                      z_row = b + grid_d * (
                          a + grid_c * (s + nb_stack * n)
                      )
                      for i in range(c):
                          ten4_2 = i + a * step_x
                          if mode == "wrap_centered":
                              ten4_2 -= wrap_centered_half_idx_shift_x
                              if ten4_2 < 0:
                                  ten4_2 += height
                              elif ten4_2 >= height:
                                  ten4_2 -= height
                          elif mode == "half":
                              ten4_2 -= wrap_centered_half_idx_shift_x
                          elif mode == "full":
                              ten4_2 -= c - 1
                          if ten4_2 < 0 or ten4_2 >= height:
                              z[0][z_row, d * i : d * i + d] = 0
                          else:
                              for j in range(d):
                                  ten4_3 = j + b * step_y
                                  if mode == "wrap_centered":
                                      ten4_3 -= (
                                          wrap_centered_half_idx_shift_y
                                      )
                                      if ten4_3 < 0:
                                          ten4_3 += width
                                      elif ten4_3 >= width:
                                          ten4_3 -= width
                                  elif mode == "half":
                                      ten4_3 -= (
                                          wrap_centered_half_idx_shift_y
                                      )
                                  elif mode == "full":
                                      ten4_3 -= d - 1
                                  z_col = j + d * i
                                  if ten4_3 < 0 or ten4_3 >= width:
                                      z[0][z_row, z_col] = 0
                                  else:
                                      z[0][z_row, z_col] = ten4[
                                          n, s, ten4_2, ten4_3
                                      ]
  
imports: from __future__ import absolute_import, print_function, division
  import numpy
  import theano
  from theano import Op, Apply
  from theano.gof import EnumList
  import theano.tensor
  from theano.gradient import grad_not_implemented
  from theano.gradient import grad_undefined
label_desc: Use image node_id 8 for calling the Images2Neibs obj's underlying member method code with example usage: obj.perform(node, inp, out_, params) and returns: unknown, unknown