class_docstr: Affine Grid Warper class.
  
  The affine grid warper generates a reference grid of n-dimensional points
  and warps it via an affine transformation model determined by an input
  parameter Tensor. Some of the transformation parameters can be fixed at
  construction time via an `AffineWarpConstraints` object.
docstr: Assembles the module network and adds it to the graph.
  
  The internal computation graph is assembled according to the set of
  constraints provided at construction time.
  
  inputs shape: batch_size x num_free_params
  
  Args:
    inputs: Tensor containing a batch of transformation parameters.
  
  Returns:
    A batch of warped grids.
  
  Raises:
    Error: If the input tensor size is not consistent
      with the constraints passed at construction time.
docstr_tok: ["Assembles","the","module","network","and","adds","it","to","the","graph",".","The","internal","computation","graph","is","assembled","according","to","the","set","of","constraints","provided","at","construction","time",".","inputs","shape",":","batch_size","x","num_free_params","Args",":","inputs",":","Tensor","containing","a","batch","of","transformation","parameters",".","Returns",":","A","batch","of","warped","grids",".","Raises",":","Error",":","If","the","input","tensor","size","is","not","consistent","with","the","constraints","passed","at","construction","time","."]
code: def layer_op(self, inputs):
      """Assembles the module network and adds it to the graph.
  
      The internal computation graph is assembled according to the set of
      constraints provided at construction time.
  
      inputs shape: batch_size x num_free_params
  
      Args:
        inputs: Tensor containing a batch of transformation parameters.
  
      Returns:
        A batch of warped grids.
  
      Raises:
        Error: If the input tensor size is not consistent
          with the constraints passed at construction time.
      """
      inputs = tf.to_float(inputs)
      batch_size, number_of_params = list(inputs.shape)
      input_dtype = inputs.dtype.as_numpy_dtype
      if number_of_params != self._constraints.num_free_params:
          tf.logging.fatal(
              "Input size is not consistent with constraint "
              "definition: (N, %s) parameters expected "
              "(where N is the batch size; > 1), but %s provided.",
              self._constraints.num_free_params,
              inputs.shape,
          )
          raise ValueError
      spatial_rank = len(self._source_shape)
  
      warped_grid = []
      var_index_offset = 0
      for i in range(spatial_rank):
          if self._psi[i] is not None:
              # The i-th output dimension is not fully specified
              # by the constraints, the graph is setup to perform
              # matrix multiplication in batch mode.
              grid_coord = self._psi[i].astype(input_dtype)
  
              num_active_vars = self._psi[i].shape[0]
              var_start = var_index_offset
              var_index_offset += num_active_vars
              warped_coord = tf.matmul(
                  inputs[:, var_start:var_index_offset], grid_coord
              )
              offset = self._psi[spatial_rank + i]
              if offset is not None:
                  offset = offset.astype(input_dtype)
                  # Some entries in the i-th row
                  # of the affine matrix were constrained
                  # and the corresponding matrix
                  # multiplications have been precomputed.
                  tiling_params = tf.concat(
                      [[batch_size], tf.ones_like(offset.shape)], 0
                  )
                  offset = np.expand_dims(offset, 0)
                  warped_coord += tf.tile(offset, tiling_params)
  
          else:
              # The i-th output dimension is fully specified
              # by the constraints, and the corresponding matrix
              # multiplications have been precomputed.
              warped_coord = self._psi[spatial_rank + i].astype(
                  input_dtype
              )
              tiling_params = tf.concat(
                  [[batch_size], tf.ones_like(warped_coord.shape)], 0
              )
              warped_coord = np.expand_dims(warped_coord, 0)
              warped_coord = tf.tile(warped_coord, tiling_params)
  
          # update global offset
          warped_coord = warped_coord + self._psi[i + 2 * spatial_rank]
          # Need to help TF figuring out shape inference
          # since tiling information
          # is held in Tensors which are not known until run time.
          warped_coord.set_shape(
              [batch_size, np.prod(self._output_shape)]
          )
          warped_grid.append(warped_coord)
  
      # Reshape all the warped coordinates tensors to
      # match the specified output
      # shape and concatenate into a single matrix.
      warped_grid = [
          tf.reshape(grid, (batch_size,) + self._output_shape)
          for grid in warped_grid
      ]
      return tf.stack(warped_grid, -1)
  
imports: from __future__ import absolute_import, division, print_function
  from itertools import chain
  import numpy
  import tensorflow
  from niftynet.layer.base_layer import Layer, LayerFromCallable, Invertible
label_desc: Use image node_id 4 for calling the AffineGridWarperLayer obj's underlying member method code with example usage: obj.layer_op(inputs) and returns: tf