Repository: pyg-team/pytorch_geometric
Pull request #8476 (2023-11-29 06:52:47)

`EdgeIndex.contiguous()` support

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/pyg-team/pytorch_geometric/pull/8476?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`c13c00f`)](https://app.codecov.io/gh/pyg-team/pytorch_geometric/commit/c13c00fd2ab26ce480f6a1d63740c92b08c5ba7c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team) 88.33% compared to head [(`412f78e`)](https://app.codecov.io/gh/pyg-team/pytorch_geometric/pull/8476?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team) 87.70%.

> :exclamation: Current head 412f78e differs from pull request most recent head 5473e07. Consider uploading reports for the commit 5473e07 to get more accurate results


<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #8476      +/-   ##
==========================================
- Coverage   88.33%   87.70%   -0.63%     
==========================================
  Files         478      478              
  Lines       29284    29287       +3     
==========================================
- Hits        25868    25687     -181     
- Misses       3416     3600     +184     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/pyg-team/pytorch_geometric/pull/8476?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team).


Patch:
diff --git a/torch_geometric/data/edge_index.py b/torch_geometric/data/edge_index.py
index 4011a6d99..2a2bf38c7 100644
--- a/torch_geometric/data/edge_index.py
+++ b/torch_geometric/data/edge_index.py
@@ -49,6 +49,12 @@ def assert_two_dimensional(tensor: Tensor):
                          f"[2, *] (got {list(tensor.size())})")
 
 
+def assert_contiguous(tensor: Tensor):
+    if not tensor.is_contiguous():
+        raise ValueError("'EdgeIndex' needs to be contiguous. Please call "
+                         "`edge_index.contiguous()` before proceeding.")
+
+
 class EdgeIndex(Tensor):
     r"""An advanced :obj:`edge_index` representation with additional (meta)data
     attached.
@@ -114,6 +120,7 @@ class EdgeIndex(Tensor):
         assert isinstance(data, Tensor)
         assert_valid_dtype(data)
         assert_two_dimensional(data)
+        assert_contiguous(data)
 
         out = super().__new__(cls, data)
 
@@ -130,6 +137,7 @@ class EdgeIndex(Tensor):
         """
         assert_valid_dtype(self)
         assert_two_dimensional(self)
+        assert_contiguous(self)
 
         if self.numel() > 0 and self.min() < 0:
             raise ValueError(f"'{self.__class__.__name__}' contains negative "
@@ -346,6 +354,11 @@ def share_memory_(tensor: EdgeIndex) -> EdgeIndex:
     return apply_(tensor, Tensor.share_memory_)
 
 
+@implements(Tensor.contiguous)
+def contiguous(tensor: EdgeIndex) -> EdgeIndex:
+    return apply_(tensor, Tensor.contiguous)
+
+
 @implements(torch.cat)
 def cat(
     tensors: List[Union[EdgeIndex, Tensor]],


Test patch:
diff --git a/test/data/test_edge_index.py b/test/data/test_edge_index.py
index 6e122e50c..27ff274e7 100644
--- a/test/data/test_edge_index.py
+++ b/test/data/test_edge_index.py
@@ -82,6 +82,17 @@ def test_share_memory():
     assert adj._rowptr.is_shared()
 
 
+def test_contiguous():
+    data = torch.tensor([[0, 1], [1, 0], [1, 2], [2, 1]]).t()
+
+    with pytest.raises(ValueError, match="needs to be contiguous"):
+        EdgeIndex(data)
+
+    adj = EdgeIndex(data.contiguous()).contiguous()
+    assert isinstance(adj, EdgeIndex)
+    assert adj.is_contiguous()
+
+
 def test_sort_by():
     adj = EdgeIndex([[0, 1, 1, 2], [1, 0, 2, 1]], sort_order='row')
     out = adj.sort_by('row')