Repository: Theano/Theano

Issue:
slicetype breaks with GpuArray
```
import theano
var = theano.shared(np.zeros([3, 3], dtype=theano.config.floatX))
slc = theano.tensor.slicetype()
f = theano.function([slc], var[slc])
s = slice(1, 3)
f(s)
```

Works on CPU, but on GPU returns:

```
Traceback (most recent call last):
  File "/home/adam/GitRepos/Theano/theano/compile/function_module.py", line 884, in __call__
    self.fn() if output_subset is None else\
  File "/home/adam/GitRepos/Theano/theano/gof/op.py", line 888, in rval
Process Process-3:
    r = p(n, [x[0] for x in i], o)
  File "/home/adam/GitRepos/Theano/theano/gpuarray/subtensor.py", line 559, in perform
    take_idx = sum((i * s for i, s in zip(nidx, strides)))
  File "/home/adam/GitRepos/Theano/theano/gpuarray/subtensor.py", line 559, in <genexpr>
Traceback (most recent call last):
  File "/home/adam/GitRepos/Theano/theano/compile/function_module.py", line 884, in __call__
    self.fn() if output_subset is None else\
  File "/home/adam/GitRepos/Theano/theano/gof/op.py", line 888, in rval
    r = p(n, [x[0] for x in i], o)
  File "/home/adam/GitRepos/Theano/theano/gpuarray/subtensor.py", line 559, in perform
    take_idx = sum((i * s for i, s in zip(nidx, strides)))
  File "/home/adam/GitRepos/Theano/theano/gpuarray/subtensor.py", line 559, in <genexpr>
    take_idx = sum((i * s for i, s in zip(nidx, strides)))
TypeError: unsupported operand type(s) for *: 'slice' and 'int'
```

and 

```
TypeError: unsupported operand type(s) for *: 'slice' and 'int'
Apply node that caused the error: GpuAdvancedSubtensor(<GpuArrayType<None>(float32, matrix)>, <slice>)
Toposort index: 0
Inputs types: [GpuArrayType<None>(float32, matrix), <theano.tensor.type_other.SliceType object at 0x7fb98e45b898>]
Inputs shapes: [(50, 2), 'No shapes']
Inputs strides: [(8, 4), 'No strides']
Inputs values: ['not shown', slice(0, 16, None)]
Outputs clients: [[HostFromGpu(gpuarray)(GpuAdvancedSubtensor.0)]]
```

Using var[start:stop] works fine.


Discussion:

Resolving patch:
diff --git a/theano/gpuarray/subtensor.py b/theano/gpuarray/subtensor.py
--- a/theano/gpuarray/subtensor.py
+++ b/theano/gpuarray/subtensor.py
@@ -544,6 +544,13 @@ def perform(self, node, inputs, out_):
         idx_ = ([slice(None)] * p + nidx[p:])
         x = x.__getitem__(idx_)
 
+        if p == 0:
+            # The only indexing was through slices and indices.
+            # This can happen with symbolic slices for instance.
+            # Since no view_map is set, we need to copy the returned value
+            out[0] = x.copy()
+            return
+
         # flatten the array-indexed dimensions
         shape = ((np.prod(x.shape[0: p]),) +
                  x.shape[p:])
diff --git a/theano/tensor/subtensor.py b/theano/tensor/subtensor.py
--- a/theano/tensor/subtensor.py
+++ b/theano/tensor/subtensor.py
@@ -2169,9 +2169,14 @@ def infer_shape(self, node, ishapes):
 
     def perform(self, node, inputs, out_):
         out, = out_
-        # TODO: in general, we need to re-pack the inputs into a valid
-        # index, just like subtensor
-        out[0] = inputs[0].__getitem__(inputs[1:])
+        rval = inputs[0].__getitem__(inputs[1:])
+        # When there are no arrays, we are not actually doing advanced
+        # indexing, so __getitem__ will not return a copy.
+        # Since no view_map is set, we need to copy the returned value
+        if not any(isinstance(v.type, TensorType) and v.ndim > 0
+                   for v in node.inputs[1:]):
+            rval = rval.copy()
+        out[0] = rval
 
     def connection_pattern(self, node):
         rval = [[True]]


Test patch:
diff --git a/theano/tensor/tests/test_subtensor.py b/theano/tensor/tests/test_subtensor.py
--- a/theano/tensor/tests/test_subtensor.py
+++ b/theano/tensor/tests/test_subtensor.py
@@ -1623,6 +1623,14 @@ def test_adv_sub_3d(self):
         out = X[b_idx, r_idx, c_idx].eval({X: xx})
         utt.assert_allclose(out, xx[b_idx, r_idx, c_idx])
 
+    def test_adv_sub_slice(self):
+        # Reported in https://github.com/Theano/Theano/issues/5898
+        var = self.shared(np.zeros([3, 3], dtype=config.floatX))
+        slc = tensor.slicetype()
+        f = theano.function([slc], var[slc])
+        s = slice(1, 3)
+        f(s)
+
     def test_grad(self):
         ones = np.ones((1, 3), dtype=self.dtype)
         n = self.shared(ones * 5, broadcastable=(True, False))