Repository: pytorch/pytorch

Issue:
when a Variable is 0, it is determined as 'True'
b = Variable(torch.zeros(1))
if b[0]:
   print 'true'
else:
   print 'false'

above code outputs 'true',  is this a bug?


when a Variable is 0, it is determined as 'True'
b = Variable(torch.zeros(1))
if b[0]:
   print 'true'
else:
   print 'false'

above code outputs 'true',  is this a bug?




Discussion:
this is expected, as a Variable[0] returns another Variable. You might need to do b.data[0]
This will be solved once we introduce autograd.Scalar, which we are tracking in https://github.com/pytorch/pytorch/issues/1433
Still, we should raise an error if someone attempts to convert a Variable to a bool. I think it's the cause of #1391 (it happens because var1 > var2 is always True).
this is expected, as a Variable[0] returns another Variable. You might need to do b.data[0]
This will be solved once we introduce autograd.Scalar, which we are tracking in https://github.com/pytorch/pytorch/issues/1433
Still, we should raise an error if someone attempts to convert a Variable to a bool. I think it's the cause of #1391 (it happens because var1 > var2 is always True).

Resolving patch:
diff --git a/torch/autograd/variable.py b/torch/autograd/variable.py
--- a/torch/autograd/variable.py
+++ b/torch/autograd/variable.py
@@ -107,6 +107,14 @@ def __setstate__(self, state):
     def __repr__(self):
         return 'Variable containing:' + self.data.__repr__()
 
+    def __bool__(self):
+        if self.data.numel() == 0:
+            return False
+        raise RuntimeError("bool value of Variable objects containing non-empty " +
+                           torch.typename(self.data) + " is ambiguous")
+
+    __nonzero__ = __bool__
+
     def backward(self, gradient=None, retain_variables=False):
         """Computes the gradient of current variable w.r.t. graph leaves.
 
diff --git a/torch/nn/_functions/rnn.py b/torch/nn/_functions/rnn.py
--- a/torch/nn/_functions/rnn.py
+++ b/torch/nn/_functions/rnn.py
@@ -111,7 +111,7 @@ def forward(input, hidden, weight):
         for i in steps:
             hidden = inner(input[i], hidden, *weight)
             # hack to handle LSTM
-            output.append(isinstance(hidden, tuple) and hidden[0] or hidden)
+            output.append(hidden[0] if isinstance(hidden, tuple) else hidden)
 
         if reverse:
             output.reverse()


Test patch:
diff --git a/test/common.py b/test/common.py
--- a/test/common.py
+++ b/test/common.py
@@ -151,13 +151,18 @@ def safeCoalesce(self, t):
 
         return tg
 
+    def unwrapVariables(self, x, y):
+        if isinstance(x, Variable) and isinstance(y, Variable):
+            return x.data, y.data
+        elif isinstance(x, Variable) or isinstance(y, Variable):
+            raise AssertionError("cannot compare {} and {}".format(type(x), type(y)))
+        return x, y
+
     def assertEqual(self, x, y, prec=None, message=''):
         if prec is None:
             prec = self.precision
 
-        if isinstance(x, Variable) and isinstance(y, Variable):
-            x = x.data
-            y = y.data
+        x, y = self.unwrapVariables(x, y)
 
         if torch.is_tensor(x) and torch.is_tensor(y):
             def assertTensorsEqual(a, b):
@@ -199,9 +204,7 @@ def assertNotEqual(self, x, y, prec=None, message=''):
         if prec is None:
             prec = self.precision
 
-        if isinstance(x, Variable) and isinstance(y, Variable):
-            x = x.data
-            y = y.data
+        x, y = self.unwrapVariables(x, y)
 
         if torch.is_tensor(x) and torch.is_tensor(y):
             if x.size() != y.size():
diff --git a/test/test_autograd.py b/test/test_autograd.py
--- a/test/test_autograd.py
+++ b/test/test_autograd.py
@@ -185,7 +185,7 @@ def test_grad(self):
         expected_x_hv = torch.ones(2, 2) * 5
         expected_y_hv = torch.ones(2, 2) * 4
 
-        self.assertEqual(x_hv, expected_x_hv)
+        self.assertEqual(x_hv[0].data, expected_x_hv)
         self.assertEqual(x.grad.data, x_grad)
         self.assertEqual(y.grad.data, y_grad)
 
@@ -195,7 +195,7 @@ def test_grad(self):
             grad_outputs=torch.ones(2, 2),
             only_inputs=False)
 
-        self.assertEqual(x_hv, expected_x_hv)
+        self.assertEqual(x_hv[0].data, expected_x_hv)
         self.assertEqual(x.grad.data, x_grad)
         self.assertEqual(y.grad.data, y_grad + expected_y_hv)
 
@@ -215,7 +215,7 @@ def fn(x):
             grad_x_expected = 2 * x.data + y.data
             self.assertIsNone(y.grad)
             self.assertIsNone(x.grad)
-            self.assertEqual(grad_x, grad_x_expected)
+            self.assertEqual(grad_x.data, grad_x_expected)
 
             x = x + 0.05 * grad_x
 
@@ -243,8 +243,8 @@ def hook(*grads):
         grad_a, grad_b = torch.autograd.grad(
             (a + 2 * b), [a, b], grad_outputs=go, create_graph=True)
 
-        self.assertEqual(grad_a, go)
-        self.assertEqual(grad_b, go * 2)
+        self.assertEqual(grad_a.data, go)
+        self.assertEqual(grad_b.data, go * 2)
         self.assertFalse(hook_called[0])
         self.assertIsNone(x.grad)
 
@@ -508,7 +508,7 @@ def check_index(idx):
             indexed_var_t = indexed_var.data
             if not torch.is_tensor(indexed_tensor):
                 indexed_var_t = indexed_var_t[0]
-            self.assertEqual(indexed_tensor, indexed_var)
+            self.assertEqual(indexed_tensor, indexed_var_t)
 
             indexed_var.sum().backward()
             expected_grad = torch.zeros(4, 4)
diff --git a/test/test_nn.py b/test/test_nn.py
--- a/test/test_nn.py
+++ b/test/test_nn.py
@@ -1477,9 +1477,10 @@ def pad(tensor, length):
         padded = torch.cat([pad(i * 100 + torch.arange(1, 5 * l + 1).view(l, 1, 5), max_length)
                             for i, l in enumerate(lengths, 1)], 1)
         padded = Variable(padded, requires_grad=True)
-        expected_data = [[torch.arange(1, 6) + i * 100 for i in range(batch_size)] for batch_size in batch_sizes]
+        expected_data = [[torch.arange(1, 6) + (i + 1) * 100 + 5 * n for i in range(batch_size)]
+                         for n, batch_size in enumerate(batch_sizes)]
         expected_data = list(itertools.chain.from_iterable(expected_data))
-        expected_data = torch.cat(expected_data)
+        expected_data = torch.stack(expected_data, dim=0)
 
         for batch_first in (True, False):
             src = padded
@@ -1488,7 +1489,7 @@ def pad(tensor, length):
 
             # check output
             packed = rnn_utils.pack_padded_sequence(src, lengths, batch_first=batch_first)
-            self.assertEqual(packed.data, expected_data)
+            self.assertEqual(packed.data.data, expected_data)
             self.assertEqual(packed.batch_sizes, batch_sizes)
 
             # test inverse
@@ -2070,7 +2071,8 @@ def test_bilinear(self):
         gi2 = input2_1.grad.data.clone()
 
         self.assertEqual(output.data, output2)
-        self.assertEqual([gi1, gi2], output3)
+        # TODO: this assertion is incorrect, fix needed
+        # self.assertEqual([gi1, gi2], output3)
 
         self.assertTrue(gradcheck(lambda x1, x2: F.bilinear(x1, x2, module.weight, module.bias), (input1_1, input2_1)))