Repository: Theano/Theano

Issue:
Numpy-like interface for stack.
Fixes #3182



Discussion:
@bouthilx : Sorry for the mess! Hope it is allright now!

@Thrandis Arnaud confirmed new docstring format is supported. You can modify to this style

``` python
"""
Parameters
----------
parameter_name : type
    description
"""
```

Oops! Looking at the new docstring I realized that using the function as  

``` python
stack(tensors=[A, B, C], axis=1)
```

would not work. We need to handle **kwargs during the deprecation phase. Sorry @Thrandis ! Please add a test case to verify this function signature.

@bouthilx there you go!

@bouthilx I'm not able to test the warning properly. It seems that it is not possible to re-raise a warning if it has been raised previously (even with `warnings.resetwarnings()`). I tested it manually with a `print` instead of a `warning`, but I don't know how I can do it in a more 'official' way.

@Thrandis What if you add `warnings.simplefilter('always', DeprecationWarning)` at the beginning of your test? (Make sure you sure you use `DeprecationWarning` when you raise the message)

I was using warnings.simplefilter('always')
Le 4 sept. 2015 11:50 AM, "Xavier Bouthillier" notifications@github.com a
écrit :

> @Thrandis https://github.com/Thrandis What if you add warnings.simplefilter('always',
> DeprecationWarning) at the beginning of your test? (Make sure you sure
> you use DeprecationWarning when you raise the message)
> 
> —
> Reply to this email directly or view it on GitHub
> https://github.com/Theano/Theano/pull/3318#issuecomment-137773705.

Ok, try with DeprecationWarning. For me it didn't work without it.

I'll try that just after Aaron's class

@bouthilx I made the changes. 
The weird thing is that if the warning has been raised in the code before, then it wont't be raised again (even with `warnings.simplefilter('always', DeprecationWarning`). So I switched to the new interface for the whole test script.

oh! You should change the stack() calls to the new interface everywhere. 

@bouthilx ahah damn you're right! I'll make those changes!

@bouthilx 
I added stack([a, b], axis=1) and made the change in the whole theano code!
Last thing to do is to check for those negative axis!

@bouthilx how should I handle an out-of-bounds case?

Right now, if the tensor shape is let's say 3, and we want to stack them on the axis 5, it will add a new dimension and stack them on that dimension (so the tensor will be of size 4 instead of 5), because `list.insert()` allows it.

Shall I test that `abs(axis)` is not bigger than `tensors[0].ndim + 1` and raise an error if it is?

You should test it like in numpy ([check here](https://github.com/numpy/numpy/blob/master/numpy/core/shape_base.py#L342)).

Yep if you have tensors of dimension 3, axis=5 is out of bound.

@bouthilx added negative axis. Let me know if there is other modifications to do!

@bouthilx there you go :-)

Sorry @Thrandis for the two late minor fixes.

Thanks!


Resolving patch:
diff --git a/theano/tensor/basic.py b/theano/tensor/basic.py
--- a/theano/tensor/basic.py
+++ b/theano/tensor/basic.py
@@ -3933,6 +3933,7 @@ def shape_padleft(t, n_ones=1):
 
     See Also
     --------
+    shape_padaxis
     shape_padright
     Dimshuffle
 
@@ -3949,6 +3950,7 @@ def shape_padright(t, n_ones=1):
 
     See Also
     --------
+    shape_padaxis
     shape_padleft
     Dimshuffle
 
@@ -3961,7 +3963,19 @@ def shape_padright(t, n_ones=1):
 
 @constructor
 def shape_padaxis(t, axis):
-    """Reshape `t` by adding 1 at the dimension `axis`.
+    """Reshape `t` by inserting 1 at the dimension `axis`.
+
+    Example
+    -------
+    >>> tensor = theano.tensor.tensor3()
+    >>> theano.tensor.shape_padaxis(tensor, axis=0)
+    DimShuffle{x,0,1,2}.0
+    >>> theano.tensor.shape_padaxis(tensor, axis=1)
+    DimShuffle{0,x,1,2}.0
+    >>> theano.tensor.shape_padaxis(tensor, axis=3)
+    DimShuffle{0,1,2,x}.0
+    >>> theano.tensor.shape_padaxis(tensor, axis=-1)
+    DimShuffle{0,1,2,x}.0
 
     See Also
     --------


Test patch: