.. _shape_info:

============================================
How shape informations are handled by Theano
============================================

It is not possible to enforce strict shape into a Theano variable when
building a graph. The given parameter of theano.function can change the
shape any TheanoVariable in a graph.

Currently shape informations are used for 2 things in Theano:

- When the exact shape is known, we use it to generate faster c code for
  the 2d convolution on the cpu and gpu.

- To remove computations in the graph when we only want to know the
  shape, but not the actual value of a variable. This is done with the
  `Op.infer_shape <http://deeplearning.net/software/theano/extending/cop.html#Op.infer_shape>`_
  method.

  ex:
.. code-block:: python

   import theano
   x = theano.tensor.matrix()
   f = theano.function([x], (x**2).shape)
   theano.printing.debugprint(f)
   # MakeVector [@26301776] ''   2
   #  |Shape_i{0} [@26321296] ''   1
   #  | |<TensorType(float64, matrix)> [@26153424]
   #  |Shape_i{1} [@26322512] ''   0
   #  | |<TensorType(float64, matrix)> [@26153424]

The output of this compiled function do not contain any multiplication
or power. Theano has removed them to compute directly the shape of the
output.


Specifing exact shape
=====================

Currently, specifying a shape is not as easy as we want. We plan some
upgrade, but this is the current state of what can be done.

- You can pass the shape info directly to the `ConvOp` created
  when calling conv2d. You must add the parameter image_shape
  and filter_shape to that call. They but most be tuple of 4
  elements. Ex:

.. code-block:: python

    theano.tensor.nnet.conv2d(..., image_shape=(7,3,5,5), filter_shape=(2,3,4,4))

- You can use the SpecifyShape op to add shape anywhere in the
  graph. This allows to do some optimizations. In the following example,
  this allows to precompute the Theano function to a constant.

.. code-block:: python

   import theano
   x = theano.tensor.matrix()
   x_specify_shape = theano.tensor.specify_shape(x, (2,2))
   f = theano.function([x], (x_specify_shape**2).shape)
   theano.printing.debugprint(f)
   # [2 2] [@72791376]

Future plans
============

- Add the parameter "constant shape" to theano.shared(). This is probably
  the most frequent use case when we will use it. This will make the code
  simpler and we will be able to check that the shape does not change when
  we update the shared variable.
