Slicing pytorch tensors and use of data_ptr()
a = tensor([[ 1,  2,  3,  4,  5],
        [ 6,  7,  8,  8, 10],
        [11, 12, 13, 14, 15]])

I have a torch tensor and I need to index a tensor c such that c = [[3], [8], [13]]
So I did c = a[:,[2]] which gave me the expected answer, but it still failed on the autograder.
The autograder uses a check function as follows -
def check(orig, actual, expected):
  expected = torch.tensor(expected)
  same_elements = (actual == expected).all().item() == 1
  same_storage = (orig.storage().data_ptr() == actual.storage().data_ptr())
  return same_elements and same_storage

print('c correct:', check(a, c, [[3], [8], [13]]))

I tried debugging it and it turns out that same_storage is false, I don't understand why orig.storage().data_ptr() == actual.storage().data_ptr() should be True, and how it makes a difference.
Update
I was able to get the correct answer by doing c = a[:, 2:3] instead of c = a[:, [2]] what is the difference?

PyTorch allows tensor to be a &quot;view&quot; of an existing tensor, such that it shares the same underlying data with its base tensor, thus avoiding explicit data copy to be able to perform fast and memory efficient operations.
As mentioned in the Tensor View docs,

When accessing the contents of a tensor via indexing, PyTorch follows Numpy behaviors that basic indexing returns views, while advanced indexing returns a copy.

In your example, c = a[:, 2:3] is basic indexing, while, c = a[:, [2]] is advanced indexing. That's why a view is created in the first case only. Thus, .storage().data_ptr() gives same result.
You can read about basic and advanced indexing in Numpy indexing docs.

Advanced indexing is triggered when the selection object, obj, is a non-tuple sequence object, an ndarray (of data type integer or bool), or a tuple with at least one sequence object or ndarray (of data type integer or bool).

