Repository: pyg-team/pytorch_geometric
Pull request #7995 (2023-09-07 06:31:22)

Warn on isolated/non-existing node types in `HeteroData.validate()`

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/pyg-team/pytorch_geometric/pull/7995?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team) Report
> Merging [#7995](https://app.codecov.io/gh/pyg-team/pytorch_geometric/pull/7995?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team) (7ddb297) into [master](https://app.codecov.io/gh/pyg-team/pytorch_geometric/commit/be6ce568d2f175bdb6c0842cb38d7c7d343d88b2?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team) (be6ce56) will **decrease** coverage by `0.73%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##           master    #7995      +/-   ##
==========================================
- Coverage   90.29%   89.57%   -0.73%     
==========================================
  Files         460      460              
  Lines       26965    26972       +7     
==========================================
- Hits        24349    24161     -188     
- Misses       2616     2811     +195     
```


| [Files Changed](https://app.codecov.io/gh/pyg-team/pytorch_geometric/pull/7995?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team) | Coverage Δ | |
|---|---|---|
| [torch\_geometric/data/hetero\_data.py](https://app.codecov.io/gh/pyg-team/pytorch_geometric/pull/7995?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team#diff-dG9yY2hfZ2VvbWV0cmljL2RhdGEvaGV0ZXJvX2RhdGEucHk=) | `88.03% <100.00%> (+0.21%)` | :arrow_up: |

... and [32 files with indirect coverage changes](https://app.codecov.io/gh/pyg-team/pytorch_geometric/pull/7995/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team)

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pyg-team)


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5ddf75080..18f974b42 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 
 ### Added
 
+- Added a warning for isolated/non-existing node types in `HeteroData.validate()` ([#7995](https://github.com/pyg-team/pytorch_geometric/pull/7995))
 - Added `utils.cumsum` implementation ([#7994](https://github.com/pyg-team/pytorch_geometric/pull/7994))
 - Added the `BrcaTcga` dataset ([#7905](https://github.com/pyg-team/pytorch_geometric/pull/7905))
 - Added the `MyketDataset` ([#7959](https://github.com/pyg-team/pytorch_geometric/pull/7959))
diff --git a/torch_geometric/data/hetero_data.py b/torch_geometric/data/hetero_data.py
index a3e6cd37d..4df5ce69a 100644
--- a/torch_geometric/data/hetero_data.py
+++ b/torch_geometric/data/hetero_data.py
@@ -387,6 +387,23 @@ class HeteroData(BaseData, FeatureStore, GraphStore):
         cls_name = self.__class__.__name__
         status = True
 
+        node_types = set(self.node_types)
+        num_src_node_types = {src for src, _, _ in self.edge_types}
+        num_dst_node_types = {dst for _, _, dst in self.edge_types}
+
+        dangling_types = (num_src_node_types | num_dst_node_types) - node_types
+        if len(dangling_types) > 0:
+            status = False
+            warn_or_raise(
+                f"The node types {dangling_types} are referenced in edge "
+                f"types but do not exist as node types", raise_on_error)
+
+        dangling_types = node_types - (num_src_node_types | num_dst_node_types)
+        if len(dangling_types) > 0:
+            warn_or_raise(  # May be intended.
+                f"The node types {dangling_types} are isolated and are not "
+                f"referenced by any edge type ", raise_on_error=False)
+
         for edge_type, store in self._edge_store_dict.items():
             src, _, dst = edge_type
 
diff --git a/torch_geometric/utils/functions.py b/torch_geometric/utils/functions.py
index 6708de7fe..c6931ec7c 100644
--- a/torch_geometric/utils/functions.py
+++ b/torch_geometric/utils/functions.py
@@ -3,8 +3,8 @@ from torch import Tensor
 
 
 def cumsum(x: Tensor, dim: int = 0) -> Tensor:
-    r"""Returns the cumulative sum of elements of :obj:`inputs`.
-    In contrast to :meth:`torch.cumsum`, preprends the output with a zero.
+    r"""Returns the cumulative sum of elements of :obj:`x`.
+    In contrast to :meth:`torch.cumsum`, prepends the output with zero.
 
     Args:
         x (torch.Tensor): The input tensor.


Test patch:
diff --git a/test/data/test_hetero_data.py b/test/data/test_hetero_data.py
index bea01b6ad..b820d0815 100644
--- a/test/data/test_hetero_data.py
+++ b/test/data/test_hetero_data.py
@@ -33,7 +33,8 @@ def test_init_hetero_data():
     data['paper', 'paper'].edge_index = edge_index_paper_paper
     data['paper', 'author'].edge_index = edge_index_paper_author
     data['author', 'paper'].edge_index = edge_index_author_paper
-    data.validate(raise_on_error=True)
+    with pytest.warns(UserWarning, match="{'v1'} are isolated"):
+        data.validate(raise_on_error=True)
 
     assert len(data) == 2
     assert data.node_types == ['v1', 'paper', 'author']
@@ -193,6 +194,18 @@ def test_hetero_data_rename():
     assert edge_index.tolist() == edge_index_paper_paper.tolist()
 
 
+def test_dangling_types():
+    data = HeteroData()
+    data['src', 'to', 'dst'].edge_index = torch.randint(0, 10, (2, 20))
+    with pytest.raises(ValueError, match="do not exist as node types"):
+        data.validate()
+
+    data = HeteroData()
+    data['node'].num_nodes = 10
+    with pytest.warns(UserWarning, match="{'node'} are isolated"):
+        data.validate()
+
+
 def test_hetero_data_subgraph():
     data = HeteroData()
     data.num_node_types = 3