From c9a1839b8fbfcb6568d1fd81f1fea8b340b54865 Mon Sep 17 00:00:00 2001 From: Tiziano Date: Tue, 3 Feb 2026 14:44:09 +0100 Subject: [PATCH 01/24] fix: ensure tensors are on the correct device --- hyperbench/data/dataset.py | 10 +++-- hyperbench/tests/types/hdata_test.py | 60 ++++++++++++++++++++++++++++ hyperbench/train/negative_sampler.py | 7 +++- hyperbench/types/hdata.py | 9 ++++- 4 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 hyperbench/tests/types/hdata_test.py diff --git a/hyperbench/data/dataset.py b/hyperbench/data/dataset.py index 70c3a1d..a603067 100644 --- a/hyperbench/data/dataset.py +++ b/hyperbench/data/dataset.py @@ -6,7 +6,7 @@ import requests from enum import Enum -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any, Dict, List, Optional, Tuple from torch import Tensor from torch.utils.data import Dataset as TorchDataset from hyperbench.types.hypergraph import HIFHypergraph @@ -318,7 +318,7 @@ def __sample_edge_index( node_ids = edge_index[0] edge_ids = edge_index[1] - sampled_node_ids = torch.tensor(sampled_node_ids_list) + sampled_node_ids = torch.tensor(sampled_node_ids_list, device=node_ids.device) # Find incidences where the node is in our sampled node set # Example: edge_index[0] = [0, 0, 1, 2, 3, 4], sampled_node_ids = [0, 3] @@ -401,9 +401,11 @@ def __to_0based_ids( Returns: Tensor of 0-based ids. """ - id_to_0based_id = torch.zeros(n, dtype=torch.long) + device = original_ids.device + + id_to_0based_id = torch.zeros(n, dtype=torch.long, device=device) n_ids_to_keep = len(ids_to_keep) - id_to_0based_id[ids_to_keep] = torch.arange(n_ids_to_keep) + id_to_0based_id[ids_to_keep] = torch.arange(n_ids_to_keep, device=device) return id_to_0based_id[original_ids] diff --git a/hyperbench/tests/types/hdata_test.py b/hyperbench/tests/types/hdata_test.py new file mode 100644 index 0000000..e94171a --- /dev/null +++ b/hyperbench/tests/types/hdata_test.py @@ -0,0 +1,60 @@ +import pytest +import torch + +from hyperbench.types import HData + + +@pytest.fixture +def mock_hdata(): + x = torch.randn(5, 4) # 5 nodes with 4 features each + edge_index = torch.tensor( + [ + [0, 1, 2, 3, 4, 0], # node IDs + [0, 0, 1, 1, 2, 2], + ] + ) # hyperedge IDs + edge_attr = torch.randn(3, 2) # 3 hyperedges with 2 features each + + return HData(x=x, edge_index=edge_index, edge_attr=edge_attr) + + +def test_hdata_to_cpu(mock_hdata): + returned = mock_hdata.to("cpu") + + assert returned is mock_hdata + assert mock_hdata.x.device.type == "cpu" + assert mock_hdata.edge_index.device.type == "cpu" + assert mock_hdata.edge_attr is not None + assert mock_hdata.edge_attr.device.type == "cpu" + + +def test_hdata_to_cpu_handles_none_edge_attr(mock_hdata): + mock_hdata.edge_attr = None + returned = mock_hdata.to("cpu") + + assert returned is mock_hdata + assert mock_hdata.x.device.type == "cpu" + assert mock_hdata.edge_index.device.type == "cpu" + assert mock_hdata.edge_attr is None + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA not available") +def test_hdata_to_cuda(mock_hdata): + returned = mock_hdata.to("cuda") + + assert returned is mock_hdata + assert mock_hdata.x.device.type == "cuda" + assert mock_hdata.edge_index.device.type == "cuda" + assert mock_hdata.edge_attr is not None + assert mock_hdata.edge_attr.device.type == "cuda" + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA not available") +def test_hdata_to_cuda_handles_none_edge_attr(mock_hdata): + mock_hdata.edge_attr = None + returned = mock_hdata.to("cuda") + + assert returned is mock_hdata + assert mock_hdata.x.device.type == "cuda" + assert mock_hdata.edge_index.device.type == "cuda" + assert mock_hdata.edge_attr is None diff --git a/hyperbench/train/negative_sampler.py b/hyperbench/train/negative_sampler.py index 57e54c1..d8fbb49 100644 --- a/hyperbench/train/negative_sampler.py +++ b/hyperbench/train/negative_sampler.py @@ -71,13 +71,14 @@ def sample(self, data: HData) -> HData: sampled_edge_indexes: List[Tensor] = [] sampled_edge_attrs: List[Tensor] = [] + device = data.x.device new_edge_id_offset = data.num_edges for new_edge_id in range(self.num_negative_samples): # Sample with multinomial without replacement to ensure unique node ids # and assign each node id equal probability of being selected by setting all of them to 1 # Example: num_nodes_per_sample=3, max_node_id=5 # -> possible output: [2, 0, 4] - equal_probabilities = torch.ones(data.num_nodes) + equal_probabilities = torch.ones(data.num_nodes, device=device) sampled_node_ids = torch.multinomial( equal_probabilities, self.num_nodes_per_sample, replacement=False ) @@ -86,7 +87,9 @@ def sample(self, data: HData) -> HData: # -> edge_index = [[2, 0, 4], # [3, 3, 3]] sampled_edge_id_tensor = torch.full( - (self.num_nodes_per_sample,), new_edge_id + new_edge_id_offset + (self.num_nodes_per_sample,), + new_edge_id + new_edge_id_offset, + device=device, ) sampled_edge_index = torch.stack( [sampled_node_ids, sampled_edge_id_tensor], dim=0 diff --git a/hyperbench/types/hdata.py b/hyperbench/types/hdata.py index a8df730..83938a6 100644 --- a/hyperbench/types/hdata.py +++ b/hyperbench/types/hdata.py @@ -1,4 +1,4 @@ -from torch import Tensor +from torch import Tensor, device from typing import Optional @@ -45,6 +45,13 @@ def __init__( max_edge_id = edge_index[1].max().item() if edge_index.size(1) > 0 else -1 self.num_edges: int = num_edges if num_edges is not None else max_edge_id + 1 + def to(self, device: device | str, non_blocking: bool = False) -> "HData": + self.x = self.x.to(device=device, non_blocking=non_blocking) + self.edge_index = self.edge_index.to(device=device, non_blocking=non_blocking) + if self.edge_attr is not None: + self.edge_attr = self.edge_attr.to(device=device, non_blocking=non_blocking) + return self + def __repr__(self) -> str: return ( f"{self.__class__.__name__}(\n" From 7087427834dd89df2c6f34c4682f21e6b92c527b Mon Sep 17 00:00:00 2001 From: Tiziano Date: Tue, 3 Feb 2026 18:16:55 +0100 Subject: [PATCH 02/24] fix: rename node features to x everywhere --- hyperbench/data/dataset.py | 4 ++-- hyperbench/data/loader.py | 8 +++---- hyperbench/train/negative_sampler.py | 32 ++-------------------------- hyperbench/train/trainer.py | 4 ++-- 4 files changed, 10 insertions(+), 38 deletions(-) diff --git a/hyperbench/data/dataset.py b/hyperbench/data/dataset.py index a603067..3c4d616 100644 --- a/hyperbench/data/dataset.py +++ b/hyperbench/data/dataset.py @@ -133,14 +133,14 @@ def __getitem__(self, index: int | List[int]) -> HData: sampled_edge_index, sampled_node_ids, sampled_edge_ids ) - new_node_features = self.hdata.x[sampled_node_ids] + new_x = self.hdata.x[sampled_node_ids] new_edge_attr = None if self.hdata.edge_attr is not None and len(sampled_edge_ids) > 0: new_edge_attr = self.hdata.edge_attr[sampled_edge_ids] return HData( - x=new_node_features, + x=new_x, edge_index=new_edge_index, edge_attr=new_edge_attr, num_nodes=len(sampled_node_ids), diff --git a/hyperbench/data/loader.py b/hyperbench/data/loader.py index 1fd8d58..b7f3752 100644 --- a/hyperbench/data/loader.py +++ b/hyperbench/data/loader.py @@ -97,13 +97,13 @@ def __batch_node_features(self, batch: List[HData]) -> Tuple[Tensor, int]: Returns: Tensor: Concatenated node features with shape (total_nodes, num_features). """ - per_sample_node_features = [data.x for data in batch] + per_sample_x = [data.x for data in batch] # Stack all nodes along the node dimension from all samples into a single tensor - batched_node_features = torch.cat(per_sample_node_features, dim=0) - total_nodes = batched_node_features.size(0) + batched_x = torch.cat(per_sample_x, dim=0) + total_nodes = batched_x.size(0) - return batched_node_features, total_nodes + return batched_x, total_nodes def __batch_edges(self, batch: List[HData]) -> Tuple[Tensor, Optional[Tensor], int]: """Batches hyperedge indices and attributes, adjusting indices for concatenated nodes. diff --git a/hyperbench/train/negative_sampler.py b/hyperbench/train/negative_sampler.py index d8fbb49..5b40489 100644 --- a/hyperbench/train/negative_sampler.py +++ b/hyperbench/train/negative_sampler.py @@ -105,7 +105,7 @@ def sample(self, data: HData) -> HData: random_edge_attr = torch.randn_like(data.edge_attr[0]) sampled_edge_attrs.append(random_edge_attr) - negative_node_features = data.x[sorted(negative_node_ids)] + negative_x = data.x[sorted(negative_node_ids)] negative_edge_index = self.__new_negative_edge_index(sampled_edge_indexes) negative_edge_attr = ( torch.stack(sampled_edge_attrs, dim=0) @@ -114,7 +114,7 @@ def sample(self, data: HData) -> HData: ) return HData( - x=negative_node_features, + x=negative_x, edge_index=negative_edge_index, edge_attr=negative_edge_attr, num_nodes=len(negative_node_ids), @@ -140,31 +140,3 @@ def __new_negative_edge_index(self, sampled_edge_indexes: List[Tensor]) -> Tenso # [3, 4, 4, 3, 4, 3]] negative_edge_index = negative_edge_index[:, node_ids_order] return negative_edge_index - - -if __name__ == "__main__": - edge_index = torch.tensor([[0, 1, 2], [0, 1, 2]]) - x = torch.randn(3, 2) - edge_attr = torch.randn(3, 3) - print(f"Original node features:\n{x}") - print(f"Original edge_attr:\n{edge_attr}") - - sampler = RandomNegativeSampler(num_negative_samples=4, num_nodes_per_sample=2) - negative_hdata = sampler.sample( - HData(x=x, edge_index=edge_index, edge_attr=edge_attr) - ) - print(f"HData: {negative_hdata}") - - try: - RandomNegativeSampler(num_negative_samples=-1, num_nodes_per_sample=2) - except ValueError as e: - print(f"Caught expected exception: {e}") - try: - RandomNegativeSampler(num_negative_samples=2, num_nodes_per_sample=-1) - except ValueError as e: - print(f"Caught expected exception: {e}") - try: - s = RandomNegativeSampler(num_negative_samples=2, num_nodes_per_sample=10) - s.sample(HData(x=x, edge_index=edge_index, edge_attr=edge_attr)) - except ValueError as e: - print(f"Caught expected exception: {e}") diff --git a/hyperbench/train/trainer.py b/hyperbench/train/trainer.py index bdba4ef..c2fb6a1 100644 --- a/hyperbench/train/trainer.py +++ b/hyperbench/train/trainer.py @@ -14,7 +14,7 @@ class MultiModelTrainer: - """ + r""" A trainer class to handle training multiple models with individual trainers. Args: @@ -83,7 +83,7 @@ class MultiModelTrainer: enable_checkpointing: If ``True``, enable checkpointing. It will configure a default ModelCheckpoint callback if there is no user-defined ModelCheckpoint in - :paramref:`~lightning.pytorch.trainer.trainer.Trainer.callbacks`. + :paramref:`~hyperbench.train.MultiModelTrainer.callbacks`. Default: ``True``. enable_progress_bar: Whether to enable the progress bar by default. From 5b26a722a456bd5452a2ea929501c37d07ed62e2 Mon Sep 17 00:00:00 2001 From: Tiziano Date: Wed, 4 Feb 2026 17:50:42 +0100 Subject: [PATCH 03/24] feat: add unit tests for hdata on mps --- hyperbench/tests/types/hdata_test.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/hyperbench/tests/types/hdata_test.py b/hyperbench/tests/types/hdata_test.py index e94171a..9eccaa8 100644 --- a/hyperbench/tests/types/hdata_test.py +++ b/hyperbench/tests/types/hdata_test.py @@ -58,3 +58,25 @@ def test_hdata_to_cuda_handles_none_edge_attr(mock_hdata): assert mock_hdata.x.device.type == "cuda" assert mock_hdata.edge_index.device.type == "cuda" assert mock_hdata.edge_attr is None + + +@pytest.mark.skipif(not torch.mps.is_available(), reason="MPS not available") +def test_hdata_to_mps(mock_hdata): + returned = mock_hdata.to("mps") + + assert returned is mock_hdata + assert mock_hdata.x.device.type == "mps" + assert mock_hdata.edge_index.device.type == "mps" + assert mock_hdata.edge_attr is not None + assert mock_hdata.edge_attr.device.type == "mps" + + +@pytest.mark.skipif(not torch.mps.is_available(), reason="MPS not available") +def test_hdata_to_mps_handles_none_edge_attr(mock_hdata): + mock_hdata.edge_attr = None + returned = mock_hdata.to("mps") + + assert returned is mock_hdata + assert mock_hdata.x.device.type == "mps" + assert mock_hdata.edge_index.device.type == "mps" + assert mock_hdata.edge_attr is None From 34e94dc2493c0bf1b46b434b7e2b415550d8fb31 Mon Sep 17 00:00:00 2001 From: Tiziano Date: Wed, 4 Feb 2026 17:55:51 +0100 Subject: [PATCH 04/24] fix: add default to ones for missing node features --- hyperbench/data/dataset.py | 4 ++-- hyperbench/tests/data/dataset_test.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hyperbench/data/dataset.py b/hyperbench/data/dataset.py index 3c4d616..0f2275f 100644 --- a/hyperbench/data/dataset.py +++ b/hyperbench/data/dataset.py @@ -181,8 +181,8 @@ def process(self) -> HData: ] ) else: - # Fallback to zeros if no numeric attributes - x = torch.zeros((num_nodes, 1), dtype=torch.float) + # Fallback to ones if no numeric attributes + x = torch.ones((num_nodes, 1), dtype=torch.float) # remap node and edge IDs to 0-based contiguous IDs # Use dict comprehension for faster lookups diff --git a/hyperbench/tests/data/dataset_test.py b/hyperbench/tests/data/dataset_test.py index 0cead09..8e14f26 100644 --- a/hyperbench/tests/data/dataset_test.py +++ b/hyperbench/tests/data/dataset_test.py @@ -725,7 +725,7 @@ class TestDataset(Dataset): def test_process_with_no_node_attributes_fallback(): - """Test process() falls back to torch zeros when no numeric attributes.""" + """Test process() falls back to torch ones when no node features.""" mock_hypergraph = HIFHypergraph( network_type="undirected", nodes=[ @@ -744,7 +744,7 @@ class TestDataset(Dataset): dataset = TestDataset() assert dataset.hdata.x.shape == (2, 1) - assert torch.allclose(dataset.hdata.x, torch.tensor([[0.0], [0.0]])) + assert torch.allclose(dataset.hdata.x, torch.tensor([[1.0], [1.0]])) def test_process_with_single_node_attribute(): From bb68ccfc0484da7c027479afffa02e9a46be232d Mon Sep 17 00:00:00 2001 From: Tiziano Date: Wed, 4 Feb 2026 17:55:51 +0100 Subject: [PATCH 05/24] fix: add default to ones for missing node features --- hyperbench/data/dataset.py | 8 ++++---- hyperbench/tests/data/dataset_test.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hyperbench/data/dataset.py b/hyperbench/data/dataset.py index 3c4d616..bea0faf 100644 --- a/hyperbench/data/dataset.py +++ b/hyperbench/data/dataset.py @@ -9,8 +9,7 @@ from typing import Any, Dict, List, Optional, Tuple from torch import Tensor from torch.utils.data import Dataset as TorchDataset -from hyperbench.types.hypergraph import HIFHypergraph -from hyperbench.types.hdata import HData +from hyperbench.types import HData, HIFHypergraph from hyperbench.utils.hif_utils import validate_hif_json @@ -181,8 +180,9 @@ def process(self) -> HData: ] ) else: - # Fallback to zeros if no numeric attributes - x = torch.zeros((num_nodes, 1), dtype=torch.float) + # Fallback to ones if no node features, 1 is better as it can help during + # training (e.g., avoid zero multiplication), especially in first epochs + x = torch.ones((num_nodes, 1), dtype=torch.float) # remap node and edge IDs to 0-based contiguous IDs # Use dict comprehension for faster lookups diff --git a/hyperbench/tests/data/dataset_test.py b/hyperbench/tests/data/dataset_test.py index 0cead09..8e14f26 100644 --- a/hyperbench/tests/data/dataset_test.py +++ b/hyperbench/tests/data/dataset_test.py @@ -725,7 +725,7 @@ class TestDataset(Dataset): def test_process_with_no_node_attributes_fallback(): - """Test process() falls back to torch zeros when no numeric attributes.""" + """Test process() falls back to torch ones when no node features.""" mock_hypergraph = HIFHypergraph( network_type="undirected", nodes=[ @@ -744,7 +744,7 @@ class TestDataset(Dataset): dataset = TestDataset() assert dataset.hdata.x.shape == (2, 1) - assert torch.allclose(dataset.hdata.x, torch.tensor([[0.0], [0.0]])) + assert torch.allclose(dataset.hdata.x, torch.tensor([[1.0], [1.0]])) def test_process_with_single_node_attribute(): From af6979d1470cb80e65b72b9faec24b9cbd4f7702 Mon Sep 17 00:00:00 2001 From: Tiziano Date: Thu, 5 Feb 2026 11:14:05 +0100 Subject: [PATCH 06/24] feat: add sparse dropout --- hyperbench/tests/utils/sparse_utils_test.py | 284 ++++++++++++++++++++ hyperbench/utils/__init__.py | 6 +- hyperbench/utils/sparse_utils.py | 71 +++++ 3 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 hyperbench/tests/utils/sparse_utils_test.py create mode 100644 hyperbench/utils/sparse_utils.py diff --git a/hyperbench/tests/utils/sparse_utils_test.py b/hyperbench/tests/utils/sparse_utils_test.py new file mode 100644 index 0000000..0f98ffd --- /dev/null +++ b/hyperbench/tests/utils/sparse_utils_test.py @@ -0,0 +1,284 @@ +import pytest +import re as regex +import torch + +from hyperbench.utils import sparse_dropout + + +@pytest.fixture +def mock_indices(): + return torch.tensor([[0, 1, 2], [0, 1, 2]]) + + +@pytest.fixture +def mock_values(): + return torch.tensor([1.0, 2.0, 3.0]) + + +def test_dropout_zero_probability(mock_indices, mock_values): + """Test that zero dropout probability returns the original sparse tensor.""" + sparse_tensor = torch.sparse_coo_tensor(mock_indices, mock_values, (3, 3)) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.0) + + assert torch.allclose(result.coalesce().values(), mock_values) + assert torch.equal(result.coalesce().indices(), sparse_tensor.coalesce().indices()) + + +def test_dropout_full_probability(mock_indices, mock_values): + """Test that full dropout probability (1.0) drops all elements.""" + sparse_tensor = torch.sparse_coo_tensor(mock_indices, mock_values, (3, 3)) + + result = sparse_dropout(sparse_tensor, dropout_prob=1.0) + + # All values should be zero when fill_value is 0 + assert torch.allclose(result.coalesce().values(), torch.zeros_like(mock_values)) + + +@pytest.mark.parametrize("invalid_prob", [-0.5, 1.5]) +def test_dropout_invalid_probability_out_of_range( + mock_indices, mock_values, invalid_prob +): + """Test that dropout probability below 0 raises ValueError.""" + sparse_tensor = torch.sparse_coo_tensor(mock_indices, mock_values, (2, 2)) + + with pytest.raises( + ValueError, + match=regex.escape("Dropout probability must be in the range [0, 1]"), + ): + sparse_dropout(sparse_tensor, dropout_prob=invalid_prob) + + +def test_dropout_preserves_indices(): + """Test that dropout preserves the sparsity pattern (indices) unchanged.""" + indices = torch.tensor([[0, 1, 2, 0], [0, 1, 2, 2]]) + values = torch.tensor([1.0, 2.0, 3.0, 4.0]) + sparse_tensor = torch.sparse_coo_tensor(indices, values, (3, 3)) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.5) + + # Indices should remain the same (in coalesced form) + assert torch.equal(result.coalesce().indices(), sparse_tensor.coalesce().indices()) + + +def test_dropout_preserves_shape(): + """Test that dropout preserves the tensor shape.""" + shape = (5, 10) # Shape of the tensor if it were dense + indices = torch.tensor([[0, 2, 4], [1, 5, 9]]) + values = torch.tensor([1.0, 2.0, 3.0]) + sparse_tensor = torch.sparse_coo_tensor(indices, values, shape) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.5) + + assert result.size() == shape + + +def test_dropout_preserves_dtype(): + """Test that dropout preserves the tensor dtype.""" + indices = torch.tensor([[0, 1], [0, 1]]) + values = torch.tensor([1.0, 2.0], dtype=torch.float32) + sparse_tensor = torch.sparse_coo_tensor( + indices, values, (2, 2), dtype=torch.float32 + ) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.5) + + assert result.dtype == sparse_tensor.dtype + + +def test_dropout_with_fill_value_zero(mock_indices): + """Test dropout with fill_value=0.0 (default behavior).""" + values = torch.tensor([5.0, 10.0, 15.0]) + sparse_tensor = torch.sparse_coo_tensor(mock_indices, values, (3, 3)) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.5, fill_value=0.0) + + coalesced = result.coalesce() + + # Values should be either original or zero + for val in coalesced.values(): + assert val in [0.0, 5.0, 10.0, 15.0] + + +def test_dropout_with_nonzero_fill_value(mock_indices): + """Test dropout with a non-zero fill_value.""" + values = torch.tensor([5.0, 10.0, 15.0]) + sparse_tensor = torch.sparse_coo_tensor(mock_indices, values, (3, 3)) + fill_value = 99.0 + + result = sparse_dropout(sparse_tensor, dropout_prob=0.5, fill_value=fill_value) + + coalesced = result.coalesce() + + # Values should be either original or fill_value + for val in coalesced.values(): + assert val in [5.0, 10.0, 15.0, fill_value] + + +def test_dropout_with_negative_values(): + """Test dropout with negative values in the sparse tensor.""" + indices = torch.tensor([[0, 1, 2], [0, 1, 2]]) + values = torch.tensor([-1.0, -5.0, -10.0]) + sparse_tensor = torch.sparse_coo_tensor(indices, values, (3, 3)) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.5) + + # Should handle negative values correctly + assert result.size() == sparse_tensor.size() + assert result.coalesce().values().dtype == values.dtype + + +def test_dropout_preserves_cpu_device(): + """Test that dropout preserves the device.""" + device = torch.device("cpu") + + indices = torch.tensor([[0, 1], [0, 1]], device=device) + values = torch.tensor([1.0, 2.0], device=device) + sparse_tensor = torch.sparse_coo_tensor(indices, values, (2, 2), device=device) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.5) + + assert result.device == sparse_tensor.device + + +@pytest.mark.skipif(not torch.cuda.is_available(), reason="Cuda not available") +def test_dropout_preserves_cuda_device(): + """Test that dropout preserves the device.""" + device = torch.device("cuda") + + indices = torch.tensor([[0, 1], [0, 1]], device=device) + values = torch.tensor([1.0, 2.0], device=device) + sparse_tensor = torch.sparse_coo_tensor(indices, values, (2, 2), device=device) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.5) + + assert result.device == sparse_tensor.device + + +@pytest.mark.skipif(not torch.mps.is_available(), reason="MPS not available") +def test_dropout_preserves_mps_device(): + """Test that dropout preserves the device.""" + device = torch.device("mps") + + indices = torch.tensor([[0, 1], [0, 1]], device=device) + values = torch.tensor([1.0, 2.0], device=device) + sparse_tensor = torch.sparse_coo_tensor(indices, values, (2, 2), device=device) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.5) + + assert result.device == sparse_tensor.device + + +def test_dropout_fill_value_with_full_dropout(): + """Test that fill_value is applied correctly when dropout is 1.0.""" + indices = torch.tensor([[0, 1], [0, 1]]) + values = torch.tensor([1.0, 2.0]) + sparse_tensor = torch.sparse_coo_tensor(indices, values, (2, 2)) + fill_value = 7.0 + + result = sparse_dropout(sparse_tensor, dropout_prob=1.0, fill_value=fill_value) + + # All values should be the fill_value + assert torch.allclose( + result.coalesce().values(), torch.full_like(values, fill_value) + ) + + +def test_dropout_with_unsorted_indices(): + """Test that dropout handles unsorted indices correctly.""" + # Create a sparse tensor with unsorted/duplicate indices + indices = torch.tensor([[2, 0, 1, 0], [2, 0, 1, 0]]) + values = torch.tensor([3.0, 1.0, 2.0, 4.0]) + sparse_tensor = torch.sparse_coo_tensor(indices, values, (3, 3)) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.5) + + coalesced = result.coalesce() + + # Should coalesce without errors + assert coalesced is not None + + # Original had 3 unique indices (0,0), (1,1), (2,2) + assert len(coalesced.indices()[0]) == 3 + assert len(coalesced.indices()[1]) == 3 + + +def test_dropout_single_element(): + """Test dropout on a sparse tensor with a single element.""" + indices = torch.tensor([[0], [0]]) + values = torch.tensor([42.0]) + sparse_tensor = torch.sparse_coo_tensor(indices, values, (1, 1)) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.5) + + coalesced = result.coalesce() + + # Result should contain one value, either 0 or the original value + assert len(coalesced.values()) == 1 + assert coalesced.values().item() in [0.0, 42.0] + + +def test_dropout_large_sparse_matrix(): + """Test dropout on a large sparse matrix.""" + size = 1000 + num_nonzero_elements = 500 + rows = torch.randint(0, size, (num_nonzero_elements,)) + cols = torch.randint(0, size, (num_nonzero_elements,)) + + indices = torch.stack([rows, cols]) + values = torch.randn(num_nonzero_elements) + sparse_tensor = torch.sparse_coo_tensor(indices, values, (size, size)) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.2) + + assert result.size() == sparse_tensor.size() + + +def test_dropout_returns_new_tensor(mock_indices, mock_values): + """Test that dropout returns a new tensor, not a reference to the original.""" + sparse_tensor = torch.sparse_coo_tensor(mock_indices, mock_values, (2, 2)) + + result = sparse_dropout(sparse_tensor, dropout_prob=0.0) + + # Even with 0 dropout, the returned tensor should be a different object + assert result is not sparse_tensor + + +def test_dropout_statistical_property_moderate_rate(): + """Test that dropout approximately respects the expected keep probability.""" + # Create a larger sparse tensor for statistical testing + num_elements = 1000 + + indices = torch.tensor([list(range(num_elements)), list(range(num_elements))]) + values = torch.ones(num_elements) + sparse_tensor = torch.sparse_coo_tensor( + indices, values, (num_elements, num_elements) + ) + + dropout_prob = 0.3 + keep_prob = 1 - dropout_prob # Keep ~70% of elements + + result = sparse_dropout(sparse_tensor, dropout_prob=dropout_prob, fill_value=0.0) + result_values = result.coalesce().values() + + # Count non-zero values (kept elements) + kept_count = (result_values != 0).sum().item() + actual_keep_prob = kept_count / num_elements + + # Allow 10% tolerance for statistical variance + tolerance = 0.1 + assert abs(actual_keep_prob - keep_prob) < tolerance + + +def test_dropout_statistical_variance(): + """Test that different calls to dropout produce different results (stochasticity).""" + indices = torch.tensor([[0, 1, 2], [0, 1, 2]]) + values = torch.tensor([1.0, 2.0, 3.0]) + sparse_tensor = torch.sparse_coo_tensor(indices, values, (3, 3)) + + result1 = sparse_dropout(sparse_tensor, dropout_prob=0.5) + result2 = sparse_dropout(sparse_tensor, dropout_prob=0.5) + + # Results should be different due to stochastic nature + # (with very high probability for 0.5 dropout) + assert not torch.allclose(result1.coalesce().values(), result2.coalesce().values()) diff --git a/hyperbench/utils/__init__.py b/hyperbench/utils/__init__.py index ad4010e..9e7de11 100644 --- a/hyperbench/utils/__init__.py +++ b/hyperbench/utils/__init__.py @@ -1,4 +1,3 @@ -from .hif_utils import validate_hif_json from .data_utils import ( empty_edgeattr, empty_edgeindex, @@ -7,6 +6,8 @@ empty_nodefeatures, to_non_empty_edgeattr, ) +from .hif_utils import validate_hif_json +from .sparse_utils import sparse_dropout __all__ = [ "empty_edgeattr", @@ -14,6 +15,7 @@ "empty_hdata", "empty_hifhypergraph", "empty_nodefeatures", - "validate_hif_json", + "sparse_dropout", "to_non_empty_edgeattr", + "validate_hif_json", ] diff --git a/hyperbench/utils/sparse_utils.py b/hyperbench/utils/sparse_utils.py new file mode 100644 index 0000000..d3c477c --- /dev/null +++ b/hyperbench/utils/sparse_utils.py @@ -0,0 +1,71 @@ +import torch + +from torch import Tensor + + +def sparse_dropout( + sparse_tensor: Tensor, + dropout_prob: float, + fill_value: float = 0.0, +) -> Tensor: + r"""Dropout function for sparse matrix. This function will return a new sparse matrix with the same shape as the input sparse matrix, but with some elements dropped out. + + Args: + sparse_tensor: The sparse matrix with format ``torch.sparse_coo_tensor``. + dropout_prob: Probability of an element to be dropped. + fill_value: The fill value for dropped elements. Defaults to ``0.0``. + + Returns: + A new sparse matrix with the same shape as the input sparse matrix, but with some elements dropped out. + """ + device = sparse_tensor.device + + # Sparse tensors may be unsorted indices or have duplicate entries + # 'coalesce()' will sum duplicates and sort indices to have a consistent format for dropout + sparse_tensor = sparse_tensor.coalesce() + + if dropout_prob > 1 or dropout_prob < 0: + raise ValueError("Dropout probability must be in the range [0, 1]") + + # Nothing to drop, return the original sparse tensor + if dropout_prob == 0: + return sparse_tensor + + values = sparse_tensor.values() + indices = sparse_tensor.indices() + + keep_prob = 1 - dropout_prob + + # Generate a binary mask matching the shape of values for elements to keep + # 'torch.bernoulli()' samples 1 with probability keep_prob and 0 with probability dropout_prob + # Example: values = [0.5, 1.2, 3.4], keep_prob = 0.8 + # -> keep_mask might be [1, 0, 1], meaning we keep the 1st and 3rd elements, drop the 2nd + keep_mask = torch.bernoulli(torch.full_like(values, keep_prob)).to(device) + + if fill_value == 0.0: + # If fill_value is 0, just zero out the dropped elements, + # as keep_mask will be 0 for dropped elements and 1 for kept elements + # Example: values = [0.5, 1.2, 3.4], keep_mask = [1, 0, 1], fill_value = 0.0 + # -> new_values = [0.5*1, 1.2*0, 3.4*1] = [0.5, 0.0, 3.4] + new_values = values * keep_mask + else: + # If fill_value is non-zero, we must fill the dropped elements with the specified fill_value instead of zero + # 'torch.logical_not(keep_mask)' identifies dropped elements where mask is 0 and + # Example: values = [0.5, 1.2, 3.4], keep_mask = [1, 0, 1], fill_value = 9.9 + # -> values_to_fill_mask = [0, 1, 0] + # -> fill_values = [0*9.9, 1*9.9, 0*9.9] = [0.0, 9.9, 0.0] + # -> new_values = [0.5*1 + 0.0, 1.2*0 + 9.9, 3.4*1 + 0.0] = [0.5, 9.9, 3.4] + values_to_fill_mask = torch.logical_not(keep_mask) + fill_values = values_to_fill_mask * fill_value + new_values = values * keep_mask + fill_values + + # Reuse the original indices and shape to preserve spasity but change values + dropout_sparse_tensor = torch.sparse_coo_tensor( + indices=indices, + values=new_values, + size=sparse_tensor.size(), + dtype=sparse_tensor.dtype, + device=device, + ) + + return dropout_sparse_tensor From 37137152b49c7e663e9b5c58a2f2a340e4706aae Mon Sep 17 00:00:00 2001 From: Tiziano Date: Thu, 5 Feb 2026 11:17:00 +0100 Subject: [PATCH 07/24] fix: remove flaky test --- hyperbench/tests/utils/sparse_utils_test.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/hyperbench/tests/utils/sparse_utils_test.py b/hyperbench/tests/utils/sparse_utils_test.py index 0f98ffd..6b628ca 100644 --- a/hyperbench/tests/utils/sparse_utils_test.py +++ b/hyperbench/tests/utils/sparse_utils_test.py @@ -268,17 +268,3 @@ def test_dropout_statistical_property_moderate_rate(): # Allow 10% tolerance for statistical variance tolerance = 0.1 assert abs(actual_keep_prob - keep_prob) < tolerance - - -def test_dropout_statistical_variance(): - """Test that different calls to dropout produce different results (stochasticity).""" - indices = torch.tensor([[0, 1, 2], [0, 1, 2]]) - values = torch.tensor([1.0, 2.0, 3.0]) - sparse_tensor = torch.sparse_coo_tensor(indices, values, (3, 3)) - - result1 = sparse_dropout(sparse_tensor, dropout_prob=0.5) - result2 = sparse_dropout(sparse_tensor, dropout_prob=0.5) - - # Results should be different due to stochastic nature - # (with very high probability for 0.5 dropout) - assert not torch.allclose(result1.coalesce().values(), result2.coalesce().values()) From 9ec15554acaa169258fe5f8cac7dd8bdd2db4040 Mon Sep 17 00:00:00 2001 From: Tiziano Date: Wed, 4 Feb 2026 17:55:51 +0100 Subject: [PATCH 08/24] fix: add default to ones for missing node features --- hyperbench/data/dataset.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hyperbench/data/dataset.py b/hyperbench/data/dataset.py index bea0faf..ad9f0d6 100644 --- a/hyperbench/data/dataset.py +++ b/hyperbench/data/dataset.py @@ -180,8 +180,7 @@ def process(self) -> HData: ] ) else: - # Fallback to ones if no node features, 1 is better as it can help during - # training (e.g., avoid zero multiplication), especially in first epochs + # Fallback to ones if no numeric attributes x = torch.ones((num_nodes, 1), dtype=torch.float) # remap node and edge IDs to 0-based contiguous IDs From 9f26c2274320f7a93abfc8a8d543f6d11041560c Mon Sep 17 00:00:00 2001 From: Tiziano Date: Thu, 5 Feb 2026 11:28:38 +0100 Subject: [PATCH 09/24] refactor: improve comment on node feature fallback --- hyperbench/data/dataset.py | 3 ++- hyperbench/tests/train/trainer_test.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hyperbench/data/dataset.py b/hyperbench/data/dataset.py index ad9f0d6..bea0faf 100644 --- a/hyperbench/data/dataset.py +++ b/hyperbench/data/dataset.py @@ -180,7 +180,8 @@ def process(self) -> HData: ] ) else: - # Fallback to ones if no numeric attributes + # Fallback to ones if no node features, 1 is better as it can help during + # training (e.g., avoid zero multiplication), especially in first epochs x = torch.ones((num_nodes, 1), dtype=torch.float) # remap node and edge IDs to 0-based contiguous IDs diff --git a/hyperbench/tests/train/trainer_test.py b/hyperbench/tests/train/trainer_test.py index c82f121..0ec694c 100644 --- a/hyperbench/tests/train/trainer_test.py +++ b/hyperbench/tests/train/trainer_test.py @@ -20,8 +20,8 @@ def mock_model_configs(): model_config.version = f"{i}" model_config.model = model model_config.trainer = None - model_config.full_model_name = ( - lambda self=model_config: f"{self.name}:{self.version}" + model_config.full_model_name = lambda self=model_config: ( + f"{self.name}:{self.version}" ) model_configs.append(model_config) From fedfaec721f21d4ec0912fa8e8491acec05b5ff9 Mon Sep 17 00:00:00 2001 From: Daniele De Vinco Date: Thu, 5 Feb 2026 11:20:38 +0100 Subject: [PATCH 10/24] feat: add standard datasets (#27) * feat: removing local dataset * docs: format docs * feat: added IMDB PATENT COURSERA datasets * feat: add cora --- .gitignore | 3 +++ docs/contributing.md | 3 +++ hyperbench/data/dataset.py | 20 ++++++++++++++++++++ hyperbench/data/datasets/.gitkeep | 0 hyperbench/data/datasets/algebra.json.zst | Bin 29749 -> 0 bytes hyperbench/data/datasets/dblp.json.zst | Bin 409827 -> 0 bytes 6 files changed, 26 insertions(+) create mode 100644 docs/contributing.md create mode 100644 hyperbench/data/datasets/.gitkeep delete mode 100644 hyperbench/data/datasets/algebra.json.zst delete mode 100644 hyperbench/data/datasets/dblp.json.zst diff --git a/.gitignore b/.gitignore index e5819bb..b613cc7 100644 --- a/.gitignore +++ b/.gitignore @@ -121,3 +121,6 @@ cython_debug/ # MacOS .DS_Store + +# Datasets +data/datasets/*.zst diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..73d56b1 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,3 @@ +# Contributing to Hyperbench + +Thank you for your interest in contributing to Hyperbench! diff --git a/hyperbench/data/dataset.py b/hyperbench/data/dataset.py index bea0faf..76201f4 100644 --- a/hyperbench/data/dataset.py +++ b/hyperbench/data/dataset.py @@ -22,11 +22,14 @@ class DatasetNames(Enum): AMAZON = "amazon" CONTACT_HIGH_SCHOOL = "contact-high-school" CONTACT_PRIMARY_SCHOOL = "contact-primary-school" + CORA = "cora" + COURSERA = "coursera" DBLP = "dblp" EMAIL_ENRON = "email-Enron" EMAIL_W3C = "email-W3C" GEOMETRY = "geometry" GOT = "got" + IMBD = "imdb" MUSIC_BLUES_REVIEWS = "music-blues-reviews" NBA = "nba" NDC_CLASSES = "NDC-classes" @@ -36,6 +39,7 @@ class DatasetNames(Enum): THREADS_MATH_SX = "threads-math-sx" TWITTER = "twitter" VEGAS_BARS_REVIEWS = "vegas-bars-reviews" + PATENT = "patent" class HIFConverter: @@ -419,3 +423,19 @@ class DBLPDataset(Dataset): class ThreadsMathsxDataset(Dataset): DATASET_NAME = "THREADSMATHSX" + + +class PatentDataset(Dataset): + DATASET_NAME = "PATENT" + + +class CourseraDataset(Dataset): + DATASET_NAME = "COURSERA" + + +class IMDBDataset(Dataset): + DATASET_NAME = "IMDB" + + +class CoraDataset(Dataset): + DATASET_NAME = "CORA" diff --git a/hyperbench/data/datasets/.gitkeep b/hyperbench/data/datasets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/hyperbench/data/datasets/algebra.json.zst b/hyperbench/data/datasets/algebra.json.zst deleted file mode 100644 index afb69c485acac262a6bcc76c72395cafa78fc7f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29749 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 N0=UnltCf2Ae*m65R6_s& diff --git a/hyperbench/data/datasets/dblp.json.zst b/hyperbench/data/datasets/dblp.json.zst deleted file mode 100644 index 5e4e896c2d21b969505c126de68a8c8e25a3af87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 409827 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%0D)0a%r9b5;2|*|ED84SR|!Mx6HQ;3+f(Ns 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

$%+llFUhh%t3tdgCFahJF)Q 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 From 50d07238d1022d8bf7335a75ee31e311be44009a Mon Sep 17 00:00:00 2001 From: Tiziano Date: Thu, 5 Feb 2026 12:22:28 +0100 Subject: [PATCH 11/24] feat: add graph structure --- hyperbench/tests/types/graph_test.py | 230 +++++++++++++++++++++++++++ hyperbench/types/__init__.py | 4 +- hyperbench/types/graph.py | 63 ++++++++ 3 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 hyperbench/tests/types/graph_test.py create mode 100644 hyperbench/types/graph.py diff --git a/hyperbench/tests/types/graph_test.py b/hyperbench/tests/types/graph_test.py new file mode 100644 index 0000000..3919d5f --- /dev/null +++ b/hyperbench/tests/types/graph_test.py @@ -0,0 +1,230 @@ +import pytest +import torch + +from hyperbench.types.graph import Graph + + +@pytest.fixture +def mock_empty_graph(): + return Graph([]) + + +@pytest.fixture +def mock_single_edge_graph(): + return Graph([[0, 1]]) + + +@pytest.fixture +def mock_linear_graph(): + # Linear graph: 0-1-2-3 + return Graph([[0, 1], [1, 2], [2, 3]]) + + +@pytest.fixture +def mock_graph_with_only_self_loops(): + return Graph([[0, 0], [1, 1]]) + + +@pytest.fixture +def mock_graph_with_one_self_loop(): + return Graph([[0, 1], [1, 1], [2, 3]]) + + +def test_init_empty_edges(mock_empty_graph): + assert mock_empty_graph.edges == [] + + +def test_init_single_edge(mock_single_edge_graph): + assert mock_single_edge_graph.edges == [[0, 1]] + + +def test_init_multiple_edges(mock_linear_graph): + assert mock_linear_graph.edges == [[0, 1], [1, 2], [2, 3]] + + +@pytest.mark.parametrize( + "graph, expected_num_nodes", + [ + (Graph([]), 0), # Empty graph + (Graph([[0, 1]]), 2), # Single edge + (Graph([[0, 0]]), 1), # Single edge, self-loop + (Graph([[0, 1], [1, 2], [2, 3]]), 4), # Linear graph + (Graph([[0, 0], [1, 1]]), 2), # Graph with only self-loops + (Graph([[0, 1], [1, 1], [2, 3]]), 4), # Graph with one self-loop + (Graph([[0, 1], [2, 3]]), 4), # Disconnected graph + (Graph([[0, 1], [0, 1], [1, 2]]), 3), # Graph with duplicate edges + (Graph([[0, 1], [0, 2], [1, 2]]), 3), # Complete graph + ], +) +def test_num_nodes(graph, expected_num_nodes): + assert graph.num_nodes == expected_num_nodes + + +@pytest.mark.parametrize( + "graph, expected_num_edges", + [ + (Graph([]), 0), # Empty graph + (Graph([[0, 1]]), 1), # Single edge + (Graph([[0, 0]]), 1), # Single edge, self-loop + (Graph([[0, 1], [1, 2], [2, 3]]), 3), # Linear graph + (Graph([[0, 0], [1, 1]]), 2), # Graph with only self-loops + (Graph([[0, 1], [1, 1], [2, 3]]), 3), # Graph with one self-loop + (Graph([[0, 1], [2, 3]]), 2), # Disconnected graph + (Graph([[0, 1], [0, 1], [1, 2]]), 3), # Graph with duplicate edges + (Graph([[0, 1], [0, 2], [1, 2]]), 3), # Complete graph + ], +) +def test_num_edges(graph, expected_num_edges): + assert graph.num_edges == expected_num_edges + + +@pytest.mark.parametrize( + "graph, expected_edges_after_removal", + [ + (Graph([]), []), # Empty graph + (Graph([[0, 1], [2, 3]]), [[0, 1], [2, 3]]), # No self-loops + (Graph([[0, 0]]), []), # One edge, one self-loop + (Graph([[0, 1], [1, 1]]), [[0, 1]]), # One self-loop + (Graph([[0, 0], [1, 1], [2, 2]]), []), # All self-loops + (Graph([[0, 1], [1, 2], [2, 2]]), [[0, 1], [1, 2]]), # Mixed edges + ( + Graph([[0, 0], [0, 1], [1, 1], [1, 2]]), + [[0, 1], [1, 2]], + ), # Mixed edges with multiple self-loops + ( + Graph([[0, 0], [1, 1], [2, 2], [3, 4]]), + [[3, 4]], + ), # Multiple consecutive self-loops + ], +) +def test_remove_self_loops(graph, expected_edges_after_removal): + """Test removing self-loops for various graph configurations.""" + graph.remove_self_loops() + assert graph.edges == expected_edges_after_removal + + +def test_remove_self_loops_preserves_order(): + graph = Graph([[0, 1], [1, 1], [2, 3], [3, 3], [4, 5]]) + graph.remove_self_loops() + assert graph.edges == [[0, 1], [2, 3], [4, 5]] + + +@pytest.mark.parametrize( + "graph, expected_edge_index", + [ + (Graph([]), torch.empty((2, 0), dtype=torch.long)), # Empty graph + (Graph([[0, 1]]), torch.tensor([[0], [1]], dtype=torch.long)), # Single edge + ( + Graph([[0, 1], [1, 2]]), + torch.tensor([[0, 1], [1, 2]], dtype=torch.long), + ), # Multiple edges + ( + Graph([[0, 1], [1, 2], [2, 3]]), + torch.tensor([[0, 1, 2], [1, 2, 3]], dtype=torch.long), + ), # Linear graph + ( + Graph([[0, 0], [1, 1]]), + torch.tensor([[0, 1], [0, 1]], dtype=torch.long), + ), # Graph with only self-loops + ( + Graph([[0, 1], [0, 1], [1, 2]]), + torch.tensor([[0, 0, 1], [1, 1, 2]], dtype=torch.long), + ), # Graph with duplicate edges + ], +) +def test_to_edge_index(graph, expected_edge_index): + edge_index = graph.to_edge_index() + assert torch.equal(edge_index, expected_edge_index) + + +def test_to_edge_index_returns_long_dtype(mock_single_edge_graph): + edge_index = mock_single_edge_graph.to_edge_index() + assert edge_index.dtype == torch.long + + +def test_to_edge_index_large_graph(): + edges = [[i, i + 1] for i in range(1000)] + graph = Graph(edges) + + edge_index = graph.to_edge_index() + + assert edge_index.shape == (2, 1000) + assert edge_index[0, 0] == 0 + assert edge_index[1, -1] == 1000 + + +def test_to_edge_index_does_not_modify_graph(mock_linear_graph): + original_edges = [edge[:] for edge in mock_linear_graph.edges] + _ = mock_linear_graph.to_edge_index() + + assert mock_linear_graph.edges == original_edges + + +def test_to_edge_index_is_contiguous(mock_single_edge_graph): + """Test that to_edge_index returns a contiguous tensor.""" + edge_index = mock_single_edge_graph.to_edge_index() + assert edge_index.is_contiguous() + + +def test_to_edge_index_before_and_after_removal_all_self_loops( + mock_graph_with_only_self_loops, +): + edge_index_before = mock_graph_with_only_self_loops.to_edge_index() + assert edge_index_before.shape == (2, 2) + + mock_graph_with_only_self_loops.remove_self_loops() + edge_index_after = mock_graph_with_only_self_loops.to_edge_index() + + expected = torch.tensor([], dtype=torch.long).reshape(2, 0) + + assert edge_index_after.shape == (2, 0) + assert torch.equal(edge_index_after, expected) + + +def test_to_edge_index_before_and_after_removal_one_self_loops( + mock_graph_with_one_self_loop, +): + edge_index_before = mock_graph_with_one_self_loop.to_edge_index() + assert edge_index_before.shape == (2, 3) + + mock_graph_with_one_self_loop.remove_self_loops() + edge_index_after = mock_graph_with_one_self_loop.to_edge_index() + + expected = torch.tensor([[0, 2], [1, 3]]) + + assert edge_index_after.shape == (2, 2) + assert torch.equal(edge_index_after, expected) + + +def test_bidirectional_edges(): + graph = Graph([[0, 1], [1, 0]]) + assert graph.num_edges == 2 + assert graph.num_nodes == 2 + + edge_index = graph.to_edge_index() + + expected = torch.tensor([[0, 1], [1, 0]]) + + assert torch.equal(edge_index, expected) + + +def test_star_graph(): + """Test star graph (all edges connected to central node).""" + graph = Graph([[0, 1], [0, 2], [0, 3], [0, 4]]) + assert graph.num_nodes == 5 + assert graph.num_edges == 4 + + edge_index = graph.to_edge_index() + + assert edge_index.shape == (2, 4) + + +def test_cyclic_graph(): + """Test cyclic graph (a closed loop).""" + graph = Graph([[0, 1], [1, 2], [2, 3], [3, 0]]) + assert graph.num_nodes == 4 + assert graph.num_edges == 4 + + edge_index = graph.to_edge_index() + + assert edge_index.shape == (2, 4) diff --git a/hyperbench/types/__init__.py b/hyperbench/types/__init__.py index d183b2b..ddff129 100644 --- a/hyperbench/types/__init__.py +++ b/hyperbench/types/__init__.py @@ -1,11 +1,13 @@ +from .graph import Graph from .hypergraph import HIFHypergraph from .hdata import HData from .model import CkptStrategy, ModelConfig, TestResult __all__ = [ "CkptStrategy", - "HIFHypergraph", + "Graph", "HData", + "HIFHypergraph", "ModelConfig", "TestResult", ] diff --git a/hyperbench/types/graph.py b/hyperbench/types/graph.py new file mode 100644 index 0000000..bbdd802 --- /dev/null +++ b/hyperbench/types/graph.py @@ -0,0 +1,63 @@ +import torch + +from torch import Tensor +from typing import List + + +class Graph: + """A simple graph data structure using edge list representation.""" + + def __init__(self, edges: List[List[int]]): + self.edges = edges + + @property + def num_nodes(self) -> int: + """Return the number of nodes in the graph.""" + nodes = set() + for edge in self.edges: + nodes.update(edge) + return len(nodes) + + @property + def num_edges(self) -> int: + """Return the number of edges in the graph.""" + return len(self.edges) + + def remove_self_loops(self): + """ + Remove self-loops from the graph. + + Returns: + List of edges without self-loops. + """ + if self.num_edges == 0: + return + + graph_edges_tensor = torch.tensor(self.edges, dtype=torch.long) + + # Example: edges = [[0, 1], + # [1, 1], + # [2, 3]] shape (|E|, 2) + # -> no_self_loop_mask = [True, False, True] + # -> edges without self-loops = [[0, 1], + # [2, 3]] + no_self_loop_mask = graph_edges_tensor[:, 0] != graph_edges_tensor[:, 1] + self.edges = graph_edges_tensor[no_self_loop_mask].tolist() + + def to_edge_index(self) -> Tensor: + """ + Convert the graph to edge index representation. + + Returns: + edge_index: Tensor of shape (2, |E|) representing edges. + """ + if self.num_edges == 0: + return torch.empty((2, 0), dtype=torch.long) + + # Example: edges = [[0, 1], + # [1, 2], + # [2, 3]] shape (|E|, 2) + # -> edge_index = [[0, 1, 2], + # [1, 2, 3]] shape (2, |E|) + edge_index = torch.tensor(self.edges, dtype=torch.long).t() + return edge_index From a4f405dd72dee4a6ec057a37eff8f7305e9e9f22 Mon Sep 17 00:00:00 2001 From: Daniele De Vinco Date: Thu, 5 Feb 2026 14:36:20 +0100 Subject: [PATCH 12/24] docs: update with news modules and update actions (#28) * docs: update with news modules - update actions * docs: added make req --- .github/mkdocs.yml | 1 + .github/workflows/chore.yaml | 12 +++-- .gitignore | 1 + CONTRIBUTING.md | 12 +++++ README.md | 66 +++++++--------------------- docs/api/reference.md | 41 ++++++++++++----- docs/contributing.md | 42 +++++++++++++++++- docs/getting-started/installation.md | 52 ++++++++++++++++++++++ docs/index.md | 4 ++ 9 files changed, 165 insertions(+), 66 deletions(-) diff --git a/.github/mkdocs.yml b/.github/mkdocs.yml index e9ebde9..d760d21 100644 --- a/.github/mkdocs.yml +++ b/.github/mkdocs.yml @@ -40,6 +40,7 @@ nav: - API Reference: - API: api/reference.md - Dev: ref.md + - Contributing: contributing.md markdown_extensions: - admonition diff --git a/.github/workflows/chore.yaml b/.github/workflows/chore.yaml index 7109ef4..ba51209 100644 --- a/.github/workflows/chore.yaml +++ b/.github/workflows/chore.yaml @@ -26,10 +26,16 @@ jobs: uv venv uv pip install -e . - - name: Run tests - run: uv run pytest --cov --cov-branch --cov-report=xml + - name: Test with pytest + run: | + uv run pytest --cov --junitxml=junit.xml - - name: Upload results to Codecov + - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} + - name: Upload test results to Codecov + if: ${{ !cancelled() }} + uses: codecov/test-results-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index b613cc7..45ae82e 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ htmlcov/ .cache nosetests.xml coverage.xml +junit.xml *.cover *.py.cover .hypothesis/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f251894..b6f11d1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,6 +2,18 @@ The project main language is English. +## Pre-commit hooks + +Run the following command to install the pre-commit hook: + +```bash +make setup + +pre-commit install --config .github/hooks/.pre-commit-config.yaml --hook-type pre-commit --install-hooks --overwrite +``` + +This will ensure that your code adheres to the project's coding standards before each commit. + ## Commit message style Commit messages should follow the [conventional commit specification](https://www.conventionalcommits.org/en/v1.0.0/). diff --git a/README.md b/README.md index eb9da44..6d4748d 100644 --- a/README.md +++ b/README.md @@ -15,76 +15,39 @@ WIP ## Getting started +See the [Documentation][docs] for more details. + ### Prerequisites -WIP +- [uv](https://github.com/astral-sh/uv) +- [make](https://www.gnu.org/software/make/) ### Installation -WIP - -## Usage - -## Contributing - -See [CONTRIBUTING.md](CONTRIBUTING.md) for details on contributing to the project. - -### Build - +## Build To build the project, run: - ```bash make ``` -### Linter and type checker - -Use [Ruff](https://github.com/charliermarsh/ruff) for linting and formatting: - -```bash -make lint -``` - -Use [Ty](https://docs.astral.sh/ty/) for type checking: - -```bash -make typecheck -``` - -Use the `check` target to run both linter and type checker: - -```bash -make check -``` - -### Tests - -Use [pytest](https://docs.pytest.org/en/latest/) to run the test suite: - -```bash -make test - -# Run tests with HTML report -uv run pytest --cov=hyperbench --cov-report=html -``` - -### Pre-commit hooks +## Usage -Run the following command to install the pre-commit hook: +WIP -```bash -make setup +## Contributing -pre-commit install --config .github/hooks/.pre-commit-config.yaml --hook-type pre-commit --install-hooks --overwrite -``` +See [CONTRIBUTING.md](CONTRIBUTING.md) for details on contributing to the project. ## License WIP -## Contact +## Discussion -WIP +Most development discussions take place on GitHub in this repo, via the [GitHub issue tracker][issues]. + + +![Alt](https://repobeats.axiom.co/api/embed/c168082ecb1f9f843c1b170dcfee93542b576f61.svg "Repobeats analytics image") [contributors-shield]: https://img.shields.io/github/contributors/hypernetwork-research-group/hyperbench.svg?style=for-the-badge @@ -98,3 +61,4 @@ WIP [license-shield]: https://img.shields.io/github/license/hypernetwork-research-group/hyperbench.svg?style=for-the-badge [license-url]: https://github.com/hypernetwork-research-group/hyperbench/blob/master/LICENSE.txt [docs]: https://hypernetwork-research-group.github.io/hyperbench/ +[issues]: https://github.com/hypernetwork-research-group/hyperbench/issues diff --git a/docs/api/reference.md b/docs/api/reference.md index d7131e2..4cc53bc 100644 --- a/docs/api/reference.md +++ b/docs/api/reference.md @@ -2,9 +2,7 @@ Complete API documentation for all Hyperbench modules. -## Core Modules - -### Data Module +## Data Module ::: hyperbench.data.dataset options: @@ -13,6 +11,29 @@ Complete API documentation for all Hyperbench modules. members_order: source show_submodules: true +::: hyperbench.data.loader + options: + show_root_heading: true + show_source: true + members_order: source + show_submodules: true + +## Train Module + +### Trainer + +::: hyperbench.train.trainer + options: + show_root_heading: true + show_source: true + +### Negative Sampler + +::: hyperbench.train.negative_sampler + options: + show_root_heading: true + show_source: true + ## Types Module ### HData @@ -29,6 +50,13 @@ Complete API documentation for all Hyperbench modules. show_root_heading: true show_source: true +### Model + +::: hyperbench.types.model + options: + show_root_heading: true + show_source: true + ## Utils Module ### Data Utils @@ -44,10 +72,3 @@ Complete API documentation for all Hyperbench modules. options: show_root_heading: true show_source: true - -## Data Loader - -::: hyperbench.data.loader - options: - show_root_heading: true - show_source: true diff --git a/docs/contributing.md b/docs/contributing.md index 73d56b1..b6f11d1 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,3 +1,41 @@ -# Contributing to Hyperbench +# How to contribute -Thank you for your interest in contributing to Hyperbench! +The project main language is English. + +## Pre-commit hooks + +Run the following command to install the pre-commit hook: + +```bash +make setup + +pre-commit install --config .github/hooks/.pre-commit-config.yaml --hook-type pre-commit --install-hooks --overwrite +``` + +This will ensure that your code adheres to the project's coding standards before each commit. + +## Commit message style + +Commit messages should follow the [conventional commit specification](https://www.conventionalcommits.org/en/v1.0.0/). + +The allowed structural elements are: +- `feat` for new features. +- `fix` for bug fixes. +- `chore` for changes to the build process or auxiliary tools and libraries such as documentation generation. +- `refactor` for code changes that neither fix a bug nor add a feature. +- `docs` for any documentation/README changes. + +Commit messages should be structured in a way that can be read as if they were completing the sentence *"If applied, this commit will..."*. For example: + +> feat: add new authentication method to API + +Reads as *"If applied, this commit will add new authentication method to API"*. + +## Branch naming + +Branch names should be descriptive and use hyphens to separate words. They should also follow the same structure as commit messages, using the allowed structural elements. For example: +- `feat/add-user-authentication` +- `fix/issue-with-database-connection` +- `chore/update-dependencies` +- `refactor/improve-code-structure` +- `docs/update-contributing-guidelines` diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index a37a120..286b1be 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -1,3 +1,55 @@ # Installation ## Prerequisites + +- [uv](https://github.com/astral-sh/uv) +- [make](https://www.gnu.org/software/make/) + +## Build +To build the project, run: +```bash +make +``` + +### Linter and type checker + +Use [Ruff](https://github.com/charliermarsh/ruff) for linting and formatting: + +```bash +make lint +``` + +Use [Ty](https://docs.astral.sh/ty/) for type checking: + +```bash +make typecheck +``` + +Use the `check` target to run both linter and type checker: + +```bash +make check +``` + +### Tests + +Use [pytest](https://docs.pytest.org/en/latest/) to run the test suite: + +```bash +make test + +# Run tests with HTML report +uv run pytest --cov=hyperbench --cov-report=html +``` + +### Pre-commit hooks + +Run the following command to install the pre-commit hook: + +```bash +make setup + +pre-commit install --config .github/hooks/.pre-commit-config.yaml --hook-type pre-commit --install-hooks --overwrite +``` + +This will ensure that your code adheres to the project's coding standards before each commit. diff --git a/docs/index.md b/docs/index.md index c2cbf3d..902ef39 100644 --- a/docs/index.md +++ b/docs/index.md @@ -11,3 +11,7 @@ Welcome to Hyperbench - A comprehensive benchmarking framework for hypergraph ne ## Overview Hyperbench provides tools for working with hypergraph data in machine learning contexts. It supports loading datasets in HIF format, transforming them into PyTorch tensors, and preparing them for training hypergraph neural networks. + +## Architecture + +![Architecture Diagram](design.png) From b7c7031b913f560017029dea3ba977b9b73177da Mon Sep 17 00:00:00 2001 From: Daniele De Vinco Date: Thu, 5 Feb 2026 14:57:29 +0100 Subject: [PATCH 13/24] fix: action syntax (#29) --- .github/workflows/chore.yaml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/chore.yaml b/.github/workflows/chore.yaml index ba51209..6b907ae 100644 --- a/.github/workflows/chore.yaml +++ b/.github/workflows/chore.yaml @@ -26,16 +26,22 @@ jobs: uv venv uv pip install -e . - - name: Test with pytest + - name: Run tests with coverage run: | - uv run pytest --cov --junitxml=junit.xml + uv run pytest --cov --cov-branch --cov-report=xml - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} + + - name: Test with pytest + run: | + uv run pytest --cov --junitxml=junit.xml + - name: Upload test results to Codecov - if: ${{ !cancelled() }} - uses: codecov/test-results-action@v1 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} + report_type: test_results + files: junit.xml From 08458060516d54bbb81db950dbf9bd6355160651 Mon Sep 17 00:00:00 2001 From: Daniele De Vinco Date: Thu, 5 Feb 2026 15:49:27 +0100 Subject: [PATCH 14/24] feat: complete test for dataset (#30) --- hyperbench/tests/data/dataset_test.py | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/hyperbench/tests/data/dataset_test.py b/hyperbench/tests/data/dataset_test.py index 8e14f26..404e4ab 100644 --- a/hyperbench/tests/data/dataset_test.py +++ b/hyperbench/tests/data/dataset_test.py @@ -1,3 +1,5 @@ +import zstandard as zstd +import json import requests import torch import pytest @@ -852,3 +854,42 @@ class TestDataset(Dataset): assert torch.allclose( result, torch.tensor([1.5, 0.8]) ) # weight, score (insertion order) + + +def test_load_from_hif_file_exists(): + """Test loading dataset when file already exists locally (skip download).""" + dataset_name = "ALGEBRA" + + sample_hif = { + "network-type": "undirected", + "nodes": [{"node": "0"}, {"node": "1"}], + "edges": [{"edge": "0"}], + "incidences": [{"node": "0", "edge": "0"}], + } + + mock_hypergraph = HIFHypergraph( + network_type="undirected", + nodes=[{"node": "0"}, {"node": "1"}], + edges=[{"edge": "0"}], + incidences=[{"node": "0", "edge": "0"}], + ) + + with ( + patch("hyperbench.data.dataset.requests.get") as mock_get, + patch("hyperbench.data.dataset.os.path.exists", return_value=True), + patch("builtins.open", mock_open()) as mock_file, + patch("hyperbench.data.dataset.zstd.ZstdDecompressor") as mock_decomp, + patch("hyperbench.data.dataset.tempfile.NamedTemporaryFile") as mock_temp, + patch("hyperbench.data.dataset.json.load", return_value=sample_hif), + patch("hyperbench.data.dataset.validate_hif_json", return_value=True), + patch.object(HIFHypergraph, "from_hif", return_value=mock_hypergraph), + ): + mock_dctx = mock_decomp.return_value + mock_dctx.copy_stream = lambda input_f, tmp_file: None + + mock_temp_instance = mock_temp.return_value.__enter__.return_value + mock_temp_instance.name = "/tmp/decompressed.json" + + result = HIFConverter.load_from_hif(dataset_name, save_on_disk=True) + mock_get.assert_not_called() + assert result == mock_hypergraph From 86539a59f7811b3824ef7fc5b7f516ba1acf2438 Mon Sep 17 00:00:00 2001 From: Daniele De Vinco Date: Thu, 5 Feb 2026 11:20:38 +0100 Subject: [PATCH 15/24] feat: add standard datasets (#27) * feat: removing local dataset * docs: format docs * feat: added IMDB PATENT COURSERA datasets * feat: add cora --- docs/contributing.md | 42 ++---------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index b6f11d1..73d56b1 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,41 +1,3 @@ -# How to contribute +# Contributing to Hyperbench -The project main language is English. - -## Pre-commit hooks - -Run the following command to install the pre-commit hook: - -```bash -make setup - -pre-commit install --config .github/hooks/.pre-commit-config.yaml --hook-type pre-commit --install-hooks --overwrite -``` - -This will ensure that your code adheres to the project's coding standards before each commit. - -## Commit message style - -Commit messages should follow the [conventional commit specification](https://www.conventionalcommits.org/en/v1.0.0/). - -The allowed structural elements are: -- `feat` for new features. -- `fix` for bug fixes. -- `chore` for changes to the build process or auxiliary tools and libraries such as documentation generation. -- `refactor` for code changes that neither fix a bug nor add a feature. -- `docs` for any documentation/README changes. - -Commit messages should be structured in a way that can be read as if they were completing the sentence *"If applied, this commit will..."*. For example: - -> feat: add new authentication method to API - -Reads as *"If applied, this commit will add new authentication method to API"*. - -## Branch naming - -Branch names should be descriptive and use hyphens to separate words. They should also follow the same structure as commit messages, using the allowed structural elements. For example: -- `feat/add-user-authentication` -- `fix/issue-with-database-connection` -- `chore/update-dependencies` -- `refactor/improve-code-structure` -- `docs/update-contributing-guidelines` +Thank you for your interest in contributing to Hyperbench! From ae160998bd715b9fdb1a961fe5800a89bddaf29a Mon Sep 17 00:00:00 2001 From: Tiziano Date: Fri, 6 Feb 2026 10:23:45 +0100 Subject: [PATCH 16/24] feat: add hypergraph structure --- hyperbench/tests/types/hypergraph_test.py | 89 ++++++++++++++++++++++- hyperbench/types/__init__.py | 3 +- hyperbench/types/hypergraph.py | 44 +++++++++++ 3 files changed, 134 insertions(+), 2 deletions(-) diff --git a/hyperbench/tests/types/hypergraph_test.py b/hyperbench/tests/types/hypergraph_test.py index d66e083..c7ce3e2 100644 --- a/hyperbench/tests/types/hypergraph_test.py +++ b/hyperbench/tests/types/hypergraph_test.py @@ -1,6 +1,8 @@ +import pytest import json +import torch -from hyperbench.types import HIFHypergraph +from hyperbench.types import HIFHypergraph, Hypergraph from hyperbench.tests import MOCK_BASE_PATH @@ -11,3 +13,88 @@ def test_build_HIFHypergraph_instance(): hypergraph = HIFHypergraph.from_hif(hiftext) assert isinstance(hypergraph, HIFHypergraph) + + +@pytest.mark.parametrize( + "edges, expected_edges", + [ + ([], []), # Empty hypergraph + ([[0]], [[0]]), # Single node in single edge + ([[0, 1, 2]], [[0, 1, 2]]), # Single edge with multiple nodes + ([[0, 1], [2, 3, 4], [5]], [[0, 1], [2, 3, 4], [5]]), # Multiple edges + ( + [[0, 1, 2], [1, 2, 3], [2, 3, 4]], + [[0, 1, 2], [1, 2, 3], [2, 3, 4]], + ), # Multiple overlapping edges + ([[0, 0, 1]], [[0, 0, 1]]), # Duplicate node within edge + ([[9, 2, 5, 1]], [[9, 2, 5, 1]]), # Unordered nodes + ], +) +def test_init_preserves_edges(edges, expected_edges): + hypergraph = Hypergraph(edges) + assert hypergraph.edges == expected_edges + + +@pytest.mark.parametrize( + "edges, expected_num_nodes", + [ + ([], 0), # Empty hypergraph + ([[0]], 1), # Single node in single edge + ([[0, 1, 2]], 3), # Multiple nodes in single edge + ([[0], [1], [2]], 3), # Three singleton edges + ([[0], [1], [1]], 2), # Three singleton edges, two overlapping + ([[0, 1], [2, 3]], 4), # Two disjoint edges + ([[0, 1], [1, 2]], 3), # Two overlapping edges + ([[0, 1, 2], [1, 2, 3]], 4), # Overlapping edges with multiple nodes + ([[0, 1, 2], [3, 4, 5], [6, 7, 8]], 9), # Multiple disjoint edges + ([[5, 10, 15]], 3), # Non-contiguous node IDs + ([[0, 0, 1]], 2), # Edge with duplicate node + ([[0, 1], [0, 1, 2]], 3), # One edge is subset of another + ([[9, 2, 5, 1]], 4), # Unordered node IDs + ], +) +def test_num_nodes(edges, expected_num_nodes): + hypergraph = Hypergraph(edges) + assert hypergraph.num_nodes == expected_num_nodes + + +@pytest.mark.parametrize( + "edges, expected_num_edges", + [ + ([], 0), # Empty hypergraph + ([[0]], 1), # Single edge with one node + ([[0, 1, 2]], 1), # Single edge with multiple nodes + ([[0], [1], [2]], 3), # Three singleton edges + ([[0, 1], [2, 3]], 2), # Two disjoint edges + ([[0, 1], [1, 2]], 2), # Two overlapping edges + ([[0, 1, 2], [1, 2, 3], [3, 4]], 3), # Three edges with overlap + ], +) +def test_num_edges(edges, expected_num_edges): + hypergraph = Hypergraph(edges) + assert hypergraph.num_edges == expected_num_edges + + +@pytest.mark.parametrize( + "edge_index_data, expected_edges", + [ + # Empty hypergraph + ([[[], []]], []), + # Single node, single edge + ([[[0], [0]]], [[0]]), + # Multiple nodes, single edge + ([[[0, 1, 2, 3], [0, 0, 0, 0]]], [[0, 1, 2, 3]]), + # Multiple edges, each with single node + ([[[0, 1, 2], [0, 1, 2]]], [[0], [1], [2]]), + # Two edges with multiple nodes each + ([[[0, 1, 2, 3], [0, 0, 1, 1]]], [[0, 1], [2, 3]]), + # Complex structure with varying edge sizes + ([[[0, 1, 2, 3, 4, 5], [0, 0, 1, 2, 2, 2]]], [[0, 1], [2], [3, 4, 5]]), + ], +) +def test_from_edge_index_parametrized(edge_index_data, expected_edges): + nodes, edges = edge_index_data[0] + edge_index = torch.tensor([nodes, edges], dtype=torch.long) + hypergraph = Hypergraph.from_edge_index(edge_index) + + assert hypergraph.edges == expected_edges diff --git a/hyperbench/types/__init__.py b/hyperbench/types/__init__.py index ddff129..ac37759 100644 --- a/hyperbench/types/__init__.py +++ b/hyperbench/types/__init__.py @@ -1,5 +1,5 @@ from .graph import Graph -from .hypergraph import HIFHypergraph +from .hypergraph import HIFHypergraph, Hypergraph from .hdata import HData from .model import CkptStrategy, ModelConfig, TestResult @@ -8,6 +8,7 @@ "Graph", "HData", "HIFHypergraph", + "Hypergraph", "ModelConfig", "TestResult", ] diff --git a/hyperbench/types/hypergraph.py b/hyperbench/types/hypergraph.py index ea038c6..09364bf 100644 --- a/hyperbench/types/hypergraph.py +++ b/hyperbench/types/hypergraph.py @@ -1,3 +1,4 @@ +from torch import Tensor from typing import Optional, List, Dict, Any, Literal @@ -55,3 +56,46 @@ def num_nodes(self) -> int: def num_edges(self) -> int: """Return the number of edges in the hypergraph.""" return len(self.edges) + + +class Hypergraph: + """ + A simple hypergraph data structure using edge list representation. + """ + + def __init__(self, edges: List[List[int]]): + self.edges = edges + + @property + def num_nodes(self) -> int: + """Return the number of nodes in the hypergraph.""" + nodes = set() + for edge in self.edges: + nodes.update(edge) + return len(nodes) + + @property + def num_edges(self) -> int: + """Return the number of edges in the hypergraph.""" + return len(self.edges) + + @classmethod + def from_edge_index(cls, edge_index: Tensor) -> "Hypergraph": + """ + Create a Hypergraph from an edge index representation. + + Args: + edge_index: Tensor of shape (2, |E|) representing hyperedges, where each column is (node, hyperedge). + + Returns: + Hypergraph instance + """ + if edge_index.size(1) < 1: + return cls(edges=[]) + + max_edge_id = int(edge_index[1].max().item()) + edges = [ + edge_index[0, edge_index[1] == edge_id].tolist() + for edge_id in range(max_edge_id + 1) + ] + return cls(edges=edges) From f04bb0efa50d92ab22122f73526ba321bae94878 Mon Sep 17 00:00:00 2001 From: Tiziano Date: Fri, 6 Feb 2026 10:25:09 +0100 Subject: [PATCH 17/24] refactor: move hif_test to hif_utils_test --- hyperbench/tests/utils/{hif_test.py => hif_utils_test.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename hyperbench/tests/utils/{hif_test.py => hif_utils_test.py} (100%) diff --git a/hyperbench/tests/utils/hif_test.py b/hyperbench/tests/utils/hif_utils_test.py similarity index 100% rename from hyperbench/tests/utils/hif_test.py rename to hyperbench/tests/utils/hif_utils_test.py From d82b11c60ddcc700d9f492f8a1be2c991e2380a7 Mon Sep 17 00:00:00 2001 From: Tiziano Date: Fri, 6 Feb 2026 10:42:05 +0100 Subject: [PATCH 18/24] refactor: move tests to parametrized with pytest.param for better readability --- hyperbench/tests/types/graph_test.py | 139 +++++++++++++--------- hyperbench/tests/types/hypergraph_test.py | 111 ++++++++++------- hyperbench/tests/utils/data_utils_test.py | 1 - 3 files changed, 157 insertions(+), 94 deletions(-) diff --git a/hyperbench/tests/types/graph_test.py b/hyperbench/tests/types/graph_test.py index 3919d5f..7808f21 100644 --- a/hyperbench/tests/types/graph_test.py +++ b/hyperbench/tests/types/graph_test.py @@ -4,11 +4,6 @@ from hyperbench.types.graph import Graph -@pytest.fixture -def mock_empty_graph(): - return Graph([]) - - @pytest.fixture def mock_single_edge_graph(): return Graph([[0, 1]]) @@ -30,30 +25,38 @@ def mock_graph_with_one_self_loop(): return Graph([[0, 1], [1, 1], [2, 3]]) -def test_init_empty_edges(mock_empty_graph): - assert mock_empty_graph.edges == [] - - -def test_init_single_edge(mock_single_edge_graph): - assert mock_single_edge_graph.edges == [[0, 1]] - - -def test_init_multiple_edges(mock_linear_graph): - assert mock_linear_graph.edges == [[0, 1], [1, 2], [2, 3]] +@pytest.mark.parametrize( + "graph, expected_edges", + [ + pytest.param(Graph([]), [], id="empty_graph"), + pytest.param(Graph([[0, 1]]), [[0, 1]], id="single_edge"), + pytest.param( + Graph([[0, 1], [1, 2], [2, 3]]), + [[0, 1], [1, 2], [2, 3]], + id="linear_graph", + ), + ], +) +def test_init_edges(graph, expected_edges): + assert graph.edges == expected_edges @pytest.mark.parametrize( "graph, expected_num_nodes", [ - (Graph([]), 0), # Empty graph - (Graph([[0, 1]]), 2), # Single edge - (Graph([[0, 0]]), 1), # Single edge, self-loop - (Graph([[0, 1], [1, 2], [2, 3]]), 4), # Linear graph - (Graph([[0, 0], [1, 1]]), 2), # Graph with only self-loops - (Graph([[0, 1], [1, 1], [2, 3]]), 4), # Graph with one self-loop - (Graph([[0, 1], [2, 3]]), 4), # Disconnected graph - (Graph([[0, 1], [0, 1], [1, 2]]), 3), # Graph with duplicate edges - (Graph([[0, 1], [0, 2], [1, 2]]), 3), # Complete graph + pytest.param(Graph([]), 0, id="empty_graph"), + pytest.param(Graph([[0, 1]]), 2, id="single_edge"), + pytest.param(Graph([[0, 0]]), 1, id="single_edge_self_loop"), + pytest.param(Graph([[0, 1], [1, 2], [2, 3]]), 4, id="linear_graph"), + pytest.param(Graph([[0, 0], [1, 1]]), 2, id="only_self_loops"), + pytest.param(Graph([[0, 1], [1, 1], [2, 3]]), 4, id="one_self_loop"), + pytest.param(Graph([[0, 1], [2, 3]]), 4, id="disconnected_graph"), + pytest.param( + Graph([[0, 1], [0, 1], [1, 2]]), + 3, + id="duplicate_edges", + ), + pytest.param(Graph([[0, 1], [0, 2], [1, 2]]), 3, id="complete_graph"), ], ) def test_num_nodes(graph, expected_num_nodes): @@ -63,15 +66,19 @@ def test_num_nodes(graph, expected_num_nodes): @pytest.mark.parametrize( "graph, expected_num_edges", [ - (Graph([]), 0), # Empty graph - (Graph([[0, 1]]), 1), # Single edge - (Graph([[0, 0]]), 1), # Single edge, self-loop - (Graph([[0, 1], [1, 2], [2, 3]]), 3), # Linear graph - (Graph([[0, 0], [1, 1]]), 2), # Graph with only self-loops - (Graph([[0, 1], [1, 1], [2, 3]]), 3), # Graph with one self-loop - (Graph([[0, 1], [2, 3]]), 2), # Disconnected graph - (Graph([[0, 1], [0, 1], [1, 2]]), 3), # Graph with duplicate edges - (Graph([[0, 1], [0, 2], [1, 2]]), 3), # Complete graph + pytest.param(Graph([]), 0, id="empty_graph"), + pytest.param(Graph([[0, 1]]), 1, id="single_edge"), + pytest.param(Graph([[0, 0]]), 1, id="single_edge_self_loop"), + pytest.param(Graph([[0, 1], [1, 2], [2, 3]]), 3, id="linear_graph"), + pytest.param(Graph([[0, 0], [1, 1]]), 2, id="only_self_loops"), + pytest.param(Graph([[0, 1], [1, 1], [2, 3]]), 3, id="one_self_loop"), + pytest.param(Graph([[0, 1], [2, 3]]), 2, id="disconnected_graph"), + pytest.param( + Graph([[0, 1], [0, 1], [1, 2]]), + 3, + id="duplicate_edges", + ), + pytest.param(Graph([[0, 1], [0, 2], [1, 2]]), 3, id="complete_graph"), ], ) def test_num_edges(graph, expected_num_edges): @@ -81,20 +88,34 @@ def test_num_edges(graph, expected_num_edges): @pytest.mark.parametrize( "graph, expected_edges_after_removal", [ - (Graph([]), []), # Empty graph - (Graph([[0, 1], [2, 3]]), [[0, 1], [2, 3]]), # No self-loops - (Graph([[0, 0]]), []), # One edge, one self-loop - (Graph([[0, 1], [1, 1]]), [[0, 1]]), # One self-loop - (Graph([[0, 0], [1, 1], [2, 2]]), []), # All self-loops - (Graph([[0, 1], [1, 2], [2, 2]]), [[0, 1], [1, 2]]), # Mixed edges - ( + pytest.param(Graph([]), [], id="empty_graph"), + pytest.param( + Graph([[0, 1], [2, 3]]), + [[0, 1], [2, 3]], + id="no_self_loops", + ), + pytest.param(Graph([[0, 0]]), [], id="one_edge_one_self_loop"), + pytest.param(Graph([[0, 1], [1, 1]]), [[0, 1]], id="one_self_loop"), + pytest.param( + Graph([[0, 0], [1, 1], [2, 2]]), + [], + id="all_self_loops", + ), + pytest.param( + Graph([[0, 1], [1, 2], [2, 2]]), + [[0, 1], [1, 2]], + id="mixed_edges", + ), + pytest.param( Graph([[0, 0], [0, 1], [1, 1], [1, 2]]), [[0, 1], [1, 2]], - ), # Mixed edges with multiple self-loops - ( + id="mixed_edges_multiple_self_loops", + ), + pytest.param( Graph([[0, 0], [1, 1], [2, 2], [3, 4]]), [[3, 4]], - ), # Multiple consecutive self-loops + id="multiple_consecutive_self_loops", + ), ], ) def test_remove_self_loops(graph, expected_edges_after_removal): @@ -112,24 +133,36 @@ def test_remove_self_loops_preserves_order(): @pytest.mark.parametrize( "graph, expected_edge_index", [ - (Graph([]), torch.empty((2, 0), dtype=torch.long)), # Empty graph - (Graph([[0, 1]]), torch.tensor([[0], [1]], dtype=torch.long)), # Single edge - ( + pytest.param( + Graph([]), + torch.empty((2, 0), dtype=torch.long), + id="empty_graph", + ), + pytest.param( + Graph([[0, 1]]), + torch.tensor([[0], [1]], dtype=torch.long), + id="single_edge", + ), + pytest.param( Graph([[0, 1], [1, 2]]), torch.tensor([[0, 1], [1, 2]], dtype=torch.long), - ), # Multiple edges - ( + id="multiple_edges", + ), + pytest.param( Graph([[0, 1], [1, 2], [2, 3]]), torch.tensor([[0, 1, 2], [1, 2, 3]], dtype=torch.long), - ), # Linear graph - ( + id="linear_graph", + ), + pytest.param( Graph([[0, 0], [1, 1]]), torch.tensor([[0, 1], [0, 1]], dtype=torch.long), - ), # Graph with only self-loops - ( + id="only_self_loops", + ), + pytest.param( Graph([[0, 1], [0, 1], [1, 2]]), torch.tensor([[0, 0, 1], [1, 1, 2]], dtype=torch.long), - ), # Graph with duplicate edges + id="duplicate_edges", + ), ], ) def test_to_edge_index(graph, expected_edge_index): diff --git a/hyperbench/tests/types/hypergraph_test.py b/hyperbench/tests/types/hypergraph_test.py index c7ce3e2..2ffa4bf 100644 --- a/hyperbench/tests/types/hypergraph_test.py +++ b/hyperbench/tests/types/hypergraph_test.py @@ -18,16 +18,25 @@ def test_build_HIFHypergraph_instance(): @pytest.mark.parametrize( "edges, expected_edges", [ - ([], []), # Empty hypergraph - ([[0]], [[0]]), # Single node in single edge - ([[0, 1, 2]], [[0, 1, 2]]), # Single edge with multiple nodes - ([[0, 1], [2, 3, 4], [5]], [[0, 1], [2, 3, 4], [5]]), # Multiple edges - ( + pytest.param([], [], id="empty_hypergraph"), + pytest.param([[0]], [[0]], id="single_node_single_edge"), + pytest.param( + [[0, 1, 2]], + [[0, 1, 2]], + id="single_edge_multiple_nodes", + ), + pytest.param( + [[0, 1], [2, 3, 4], [5]], + [[0, 1], [2, 3, 4], [5]], + id="multiple_edges", + ), + pytest.param( [[0, 1, 2], [1, 2, 3], [2, 3, 4]], [[0, 1, 2], [1, 2, 3], [2, 3, 4]], - ), # Multiple overlapping edges - ([[0, 0, 1]], [[0, 0, 1]]), # Duplicate node within edge - ([[9, 2, 5, 1]], [[9, 2, 5, 1]]), # Unordered nodes + id="multiple_overlapping_edges", + ), + pytest.param([[0, 0, 1]], [[0, 0, 1]], id="duplicate_node_within_edge"), + pytest.param([[9, 2, 5, 1]], [[9, 2, 5, 1]], id="unordered_nodes"), ], ) def test_init_preserves_edges(edges, expected_edges): @@ -38,19 +47,27 @@ def test_init_preserves_edges(edges, expected_edges): @pytest.mark.parametrize( "edges, expected_num_nodes", [ - ([], 0), # Empty hypergraph - ([[0]], 1), # Single node in single edge - ([[0, 1, 2]], 3), # Multiple nodes in single edge - ([[0], [1], [2]], 3), # Three singleton edges - ([[0], [1], [1]], 2), # Three singleton edges, two overlapping - ([[0, 1], [2, 3]], 4), # Two disjoint edges - ([[0, 1], [1, 2]], 3), # Two overlapping edges - ([[0, 1, 2], [1, 2, 3]], 4), # Overlapping edges with multiple nodes - ([[0, 1, 2], [3, 4, 5], [6, 7, 8]], 9), # Multiple disjoint edges - ([[5, 10, 15]], 3), # Non-contiguous node IDs - ([[0, 0, 1]], 2), # Edge with duplicate node - ([[0, 1], [0, 1, 2]], 3), # One edge is subset of another - ([[9, 2, 5, 1]], 4), # Unordered node IDs + pytest.param([], 0, id="empty_hypergraph"), + pytest.param([[0]], 1, id="single_node_single_edge"), + pytest.param([[0, 1, 2]], 3, id="multiple_nodes_single_edge"), + pytest.param([[0], [1], [2]], 3, id="three_singleton_edges"), + pytest.param([[0], [1], [1]], 2, id="three_singleton_edges_two_overlapping"), + pytest.param([[0, 1], [2, 3]], 4, id="two_disjoint_edges"), + pytest.param([[0, 1], [1, 2]], 3, id="two_overlapping_edges"), + pytest.param( + [[0, 1, 2], [1, 2, 3]], + 4, + id="overlapping_edges_multiple_nodes", + ), + pytest.param( + [[0, 1, 2], [3, 4, 5], [6, 7, 8]], + 9, + id="multiple_disjoint_edges", + ), + pytest.param([[5, 10, 15]], 3, id="non_contiguous_node_ids"), + pytest.param([[0, 0, 1]], 2, id="edge_with_duplicate_node"), + pytest.param([[0, 1], [0, 1, 2]], 3, id="edge_subset_of_another"), + pytest.param([[9, 2, 5, 1]], 4, id="unordered_node_ids"), ], ) def test_num_nodes(edges, expected_num_nodes): @@ -61,13 +78,17 @@ def test_num_nodes(edges, expected_num_nodes): @pytest.mark.parametrize( "edges, expected_num_edges", [ - ([], 0), # Empty hypergraph - ([[0]], 1), # Single edge with one node - ([[0, 1, 2]], 1), # Single edge with multiple nodes - ([[0], [1], [2]], 3), # Three singleton edges - ([[0, 1], [2, 3]], 2), # Two disjoint edges - ([[0, 1], [1, 2]], 2), # Two overlapping edges - ([[0, 1, 2], [1, 2, 3], [3, 4]], 3), # Three edges with overlap + pytest.param([], 0, id="empty_hypergraph"), + pytest.param([[0]], 1, id="single_edge_one_node"), + pytest.param([[0, 1, 2]], 1, id="single_edge_multiple_nodes"), + pytest.param([[0], [1], [2]], 3, id="three_singleton_edges"), + pytest.param([[0, 1], [2, 3]], 2, id="two_disjoint_edges"), + pytest.param([[0, 1], [1, 2]], 2, id="two_overlapping_edges"), + pytest.param( + [[0, 1, 2], [1, 2, 3], [3, 4]], + 3, + id="three_edges_with_overlap", + ), ], ) def test_num_edges(edges, expected_num_edges): @@ -78,18 +99,28 @@ def test_num_edges(edges, expected_num_edges): @pytest.mark.parametrize( "edge_index_data, expected_edges", [ - # Empty hypergraph - ([[[], []]], []), - # Single node, single edge - ([[[0], [0]]], [[0]]), - # Multiple nodes, single edge - ([[[0, 1, 2, 3], [0, 0, 0, 0]]], [[0, 1, 2, 3]]), - # Multiple edges, each with single node - ([[[0, 1, 2], [0, 1, 2]]], [[0], [1], [2]]), - # Two edges with multiple nodes each - ([[[0, 1, 2, 3], [0, 0, 1, 1]]], [[0, 1], [2, 3]]), - # Complex structure with varying edge sizes - ([[[0, 1, 2, 3, 4, 5], [0, 0, 1, 2, 2, 2]]], [[0, 1], [2], [3, 4, 5]]), + pytest.param([[[], []]], [], id="empty_hypergraph"), + pytest.param([[[0], [0]]], [[0]], id="single_node_single_edge"), + pytest.param( + [[[0, 1, 2, 3], [0, 0, 0, 0]]], + [[0, 1, 2, 3]], + id="multiple_nodes_single_edge", + ), + pytest.param( + [[[0, 1, 2], [0, 1, 2]]], + [[0], [1], [2]], + id="multiple_edges_single_nodes", + ), + pytest.param( + [[[0, 1, 2, 3], [0, 0, 1, 1]]], + [[0, 1], [2, 3]], + id="two_edges_multiple_nodes", + ), + pytest.param( + [[[0, 1, 2, 3, 4, 5], [0, 0, 1, 2, 2, 2]]], + [[0, 1], [2], [3, 4, 5]], + id="complex_varying_edge_sizes", + ), ], ) def test_from_edge_index_parametrized(edge_index_data, expected_edges): diff --git a/hyperbench/tests/utils/data_utils_test.py b/hyperbench/tests/utils/data_utils_test.py index d0f18bb..87fe363 100644 --- a/hyperbench/tests/utils/data_utils_test.py +++ b/hyperbench/tests/utils/data_utils_test.py @@ -1,4 +1,3 @@ -import pytest import torch from torch import Tensor From d8989a16d9cc86d09535cb812165a568da9bba2f Mon Sep 17 00:00:00 2001 From: Tiziano Date: Fri, 6 Feb 2026 11:24:42 +0100 Subject: [PATCH 19/24] feat: add graph utils and partial unit testing --- hyperbench/tests/utils/graph_utils_test.py | 295 +++++++++++++++++++++ hyperbench/utils/__init__.py | 8 + hyperbench/utils/graph_utils.py | 242 +++++++++++++++++ 3 files changed, 545 insertions(+) create mode 100644 hyperbench/tests/utils/graph_utils_test.py create mode 100644 hyperbench/utils/graph_utils.py diff --git a/hyperbench/tests/utils/graph_utils_test.py b/hyperbench/tests/utils/graph_utils_test.py new file mode 100644 index 0000000..6ba6c08 --- /dev/null +++ b/hyperbench/tests/utils/graph_utils_test.py @@ -0,0 +1,295 @@ +import pytest +import torch + +from hyperbench.utils import reduce_to_graph_edge_index +from hyperbench.utils.graph_utils import get_sparse_adjacency_matrix + + +@pytest.fixture(autouse=True) +def seed(): + """Fix random seed for deterministic projections.""" + torch.manual_seed(42) + + +def test_get_sparse_adjacency_matrix_returns_sparse_tensor(): + edge_index = torch.tensor([[0, 1], [1, 0]]) + result = get_sparse_adjacency_matrix(edge_index, num_nodes=2) + + assert result.is_sparse + + +@pytest.mark.parametrize( + "edge_index, num_nodes", + [ + pytest.param(torch.tensor([[0, 1], [1, 0]]), 2, id="2_nodes"), + pytest.param(torch.tensor([[0, 1, 2], [1, 2, 0]]), 4, id="4_nodes_3_edges"), + pytest.param(torch.tensor([[], []], dtype=torch.long), 5, id="5_nodes_empty"), + ], +) +def test_get_sparse_adjacency_matrix_shape(edge_index, num_nodes): + result = get_sparse_adjacency_matrix(edge_index, num_nodes=num_nodes) + + assert result.shape == (num_nodes, num_nodes) + + +def test_get_sparse_adjacency_matrix_empty_edge_index(): + """Empty edge_index produces all-zero adjacency matrix when converted to dense.""" + edge_index = torch.tensor([[], []], dtype=torch.long) + result = get_sparse_adjacency_matrix(edge_index, num_nodes=3) + dense = result.to_dense() + + assert torch.all(dense == 0) + + +@pytest.mark.parametrize( + "edge_index, num_nodes, expected_entries", + [ + pytest.param( + torch.tensor([[0], [2]]), + 3, + [(0, 2, 1.0)], + id="single_directed_edge", + ), + pytest.param( + torch.tensor([[0, 1], [1, 0]]), + 2, + [(0, 1, 1.0), (1, 0, 1.0)], + id="undirected_edge", + ), + pytest.param( + torch.tensor([[1], [1]]), + 3, + [(1, 1, 1.0)], + id="self_loop", + ), + pytest.param( + torch.tensor([[0, 1, 2], [1, 2, 0]]), + 3, + [(0, 1, 1.0), (1, 2, 1.0), (2, 0, 1.0)], + id="triangle_directed", + ), + pytest.param( + torch.tensor([[0, 1, 2, 2], [1, 2, 0, 1]]), + 3, + [(0, 1, 1.0), (1, 2, 1.0), (2, 0, 1.0), (2, 1, 1.0)], + id="multiple_edges_between_nodes", + ), + pytest.param( + torch.tensor([[0, 1, 2, 2], [1, 2, 0, 0]]), + 3, + [(0, 1, 1.0), (1, 2, 1.0), (2, 0, 2.0)], # Duplicate edges are summed + id="duplicate_edges_to_same_target", + ), + ], +) +def test_get_sparse_adjacency_matrix_entries(edge_index, num_nodes, expected_entries): + result = get_sparse_adjacency_matrix(edge_index, num_nodes=num_nodes) + dense = result.to_dense() + + for row, col, val in expected_entries: + assert dense[row, col] == val + + +def test_get_sparse_adjacency_matrix_preserves_device(): + edge_index = torch.tensor([[0], [1]], device="cpu") + + result = get_sparse_adjacency_matrix(edge_index, num_nodes=2) + + assert result.device == edge_index.device + + +@pytest.mark.parametrize( + "edge_index, num_nodes, isolated_nodes", + [ + pytest.param( + torch.tensor([[0], [1]]), + 4, + [2, 3], + id="two_isolated_nodes", + ), + pytest.param( + torch.tensor([[0, 1], [1, 0]]), + 5, + [2, 3, 4], + id="three_isolated_nodes", + ), + ], +) +def test_get_sparse_adjacency_matrix_isolated_nodes( + edge_index, num_nodes, isolated_nodes +): + """Nodes not in edge_index have zero rows and columns.""" + result = get_sparse_adjacency_matrix(edge_index, num_nodes=num_nodes) + dense = result.to_dense() + + for node in isolated_nodes: + assert torch.all(dense[node, :] == 0) + assert torch.all(dense[:, node] == 0) + + +@pytest.mark.parametrize( + "x, edge_index, with_mediators, expected_num_edges", + [ + pytest.param( + torch.tensor([[1.0, 0.0], [0.0, 1.0]]), + torch.tensor([[0, 1], [0, 0]]), + False, + 1, # One hyperedge, so one graph edge, no mediators to create additional edges + id="single_hyperedge_2_nodes_no_mediators", + ), + pytest.param( + torch.tensor([[1.0, 0.0], [0.0, 1.0]]), + torch.tensor([[0, 1], [0, 0]]), + True, + # Only 2 nodes and both are extremes (argmin/argmax) + # No mediators exist (mediators are nodes that are neither argmin nor argmax) + # So, with mediators enabled and no mediators -> 0 edges produced + 0, + id="single_hyperedge_2_nodes_with_mediators_produces_no_edges", + ), + pytest.param( + torch.tensor([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]), + torch.tensor([[0, 1, 2], [0, 0, 0]]), + False, + 1, # One hyperedge, so one graph edge, no mediators to create additional edges + id="single_hyperedge_3_nodes_no_mediators", + ), + pytest.param( + torch.tensor([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]), + torch.tensor([[0, 1, 2], [0, 0, 0]]), + True, + 2, # If argmin = 0 and argmax = 2, mediator 1 creates 2 edges [0,1] and [1,2] + id="single_hyperedge_3_nodes_with_mediators", + ), + pytest.param( + torch.tensor([[1.0, 0.0], [0.0, 1.0], [0.5, 0.5], [1.0, 1.0]]), + torch.tensor([[0, 1, 2, 3], [0, 0, 0, 0]]), + True, + # 2 nodes are extremes (argmin/argmax), 2 are mediators + # Each mediator connects to both extremes: 2 mediators * 2 edges = 4 edges + 4, + id="single_hyperedge_4_nodes_with_mediators", + ), + pytest.param( + torch.tensor([[1.0, 0.0], [0.0, 1.0], [0.5, 0.5], [1.0, 1.0]]), + torch.tensor([[0, 1, 2, 3], [0, 0, 1, 1]]), + False, + # Two hyperedges, each with 2 nodes -> 2 graph edges, + # there are no mediators to create additional edges + 2, + id="two_hyperedges_no_mediators", + ), + pytest.param( + torch.tensor( + [ + [1.0, 0.0, 0.0], + [0.0, 1.0, 0.0], + [0.0, 0.0, 1.0], + [0.5, 0.5, 0.0], + [0.0, 0.5, 0.5], + ] + ), + torch.tensor([[0, 1, 2, 2, 3, 4], [0, 0, 0, 1, 1, 1]]), + True, + # Hyperedge 0 has 3 nodes -> 1 mediator -> 2 edges + # Hyperedge 1 has 3 nodes -> 1 mediator -> 2 edges + # -> 4 edges, there are no mediators to create additional edges + 4, + id="two_hyperedges_3_nodes_each_with_mediators", + ), + ], +) +def test_reduce_to_graph_edge_count(x, edge_index, with_mediators, expected_num_edges): + result = reduce_to_graph_edge_index( + x, edge_index, with_mediators=with_mediators, remove_selfloops=False + ) + + assert result.shape[1] == expected_num_edges + + +@pytest.mark.parametrize( + "x, edge_index", + [ + pytest.param( + torch.tensor([[1.0, 0.0], [0.0, 1.0]]), + torch.tensor([[0, 1], [0, 0]]), + id="2_nodes_1_hyperedge", + ), + pytest.param( + torch.tensor([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]]), + torch.tensor([[0, 1, 2], [0, 0, 0]]), + id="3_nodes_1_hyperedge", + ), + pytest.param( + torch.tensor([[1.0, 0.0], [0.0, 1.0], [0.5, 0.5], [1.0, 1.0]]), + torch.tensor([[0, 1, 2, 3], [0, 0, 1, 1]]), + id="4_nodes_2_hyperedges", + ), + ], +) +def test_reduce_to_graph_output_has_two_rows(x, edge_index): + result = reduce_to_graph_edge_index(x, edge_index) + + assert result.shape[0] == 2 + + +def test_reduce_to_graph_output_dtype_is_long(): + x = torch.tensor([[1.0, 0.0], [0.0, 1.0]]) + edge_index = torch.tensor([[0, 1], [0, 0]]) + + result = reduce_to_graph_edge_index(x, edge_index) + + assert result.dtype == torch.long + + +def test_reduce_to_graph_output_nodes_are_within_bounds(): + """All node indices in the output are valid indices from the input node set.""" + x = torch.tensor( + [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [0.5, 0.5, 0.0]] + ) + edge_index = torch.tensor([[0, 1, 2, 1, 2, 3], [0, 0, 0, 1, 1, 1]]) + + result = reduce_to_graph_edge_index(x, edge_index) + num_nodes = x.shape[0] + + assert result.min() >= 0 + assert result.max() < num_nodes + + +def test_reduce_to_graph_removes_selfloops(): + # Duplicate node in hyperedge forces a self-loop: projections are identical, + # so argmax and argmin both select index 0, producing edge [0, 0]. + x = torch.tensor([[1.0, 0.0], [0.0, 1.0]]) + edge_index = torch.tensor([[0, 0], [0, 0]]) + + result = reduce_to_graph_edge_index(x, edge_index, remove_selfloops=True) + + # Either zero or one edge remains, the reason why one edge may remain is that + # after removing self-loops, there could be multiple hyperedges projecting to + # the same graph edge, which would be kept as a single edge + # Example: hyperedges [[0,1,1],[0,0,2]] both project to graph edge [0,2] + assert result.shape[1] <= 1 + + if result.shape[1] > 0: + # If any edges remain, check that no self-loops are present + assert not torch.any(result[0] == result[1]).item() + + +def test_reduce_to_graph_keeps_selfloops_when_disabled(): + x = torch.tensor([[1.0, 0.0], [0.0, 1.0]]) + edge_index = torch.tensor([[0, 0], [0, 0]]) + + result = reduce_to_graph_edge_index(x, edge_index, remove_selfloops=False) + + assert result.shape[1] == 1 # One node, one hyperedge + assert result[0, 0] == result[1, 0] # Self-loop edge [0, 0] is preserved + + +def test_reduce_to_graph_raises_on_single_node_hyperedge(): + x = torch.tensor([[1.0, 0.0], [0.0, 1.0]]) + edge_index = torch.tensor([[0], [0]]) + + with pytest.raises( + ValueError, match="The number of vertices in an hyperedge must be >= 2." + ): + reduce_to_graph_edge_index(x, edge_index) diff --git a/hyperbench/utils/__init__.py b/hyperbench/utils/__init__.py index 9e7de11..c5f314a 100644 --- a/hyperbench/utils/__init__.py +++ b/hyperbench/utils/__init__.py @@ -6,6 +6,11 @@ empty_nodefeatures, to_non_empty_edgeattr, ) +from .graph_utils import ( + reduce_to_graph_edge_index, + smoothing_with_gcn_laplacian_matrix, + get_sparse_normalized_laplacian, +) from .hif_utils import validate_hif_json from .sparse_utils import sparse_dropout @@ -15,7 +20,10 @@ "empty_hdata", "empty_hifhypergraph", "empty_nodefeatures", + "reduce_to_graph_edge_index", + "smoothing_with_gcn_laplacian_matrix", "sparse_dropout", + "get_sparse_normalized_laplacian", "to_non_empty_edgeattr", "validate_hif_json", ] diff --git a/hyperbench/utils/graph_utils.py b/hyperbench/utils/graph_utils.py new file mode 100644 index 0000000..fff5507 --- /dev/null +++ b/hyperbench/utils/graph_utils.py @@ -0,0 +1,242 @@ +import torch + +from torch import Tensor +from typing import List, Optional +from hyperbench.types import Graph, Hypergraph + +from .sparse_utils import sparse_dropout + + +def get_sparse_adjacency_matrix(edge_index: Tensor, num_nodes: int) -> Tensor: + """ + Compute the sparse adjacency matrix from a graph edge index. + To get the normalized adjacency matrix, add self-loops to the edge_index. + + + Args: + edge_index: Edge index tensor of shape (2, |E|). + num_nodes: The number of nodes in the graph. + + Returns: + The sparse adjacency matrix of shape (num_nodes, num_nodes). + """ + src, dest = edge_index + + # Example: undirected_edge_index = [[0, 1, 2, 3], + # [1, 0, 3, 2]] + # -> adj_values = [1, 1, 1, 1] + # -> adj_indices = [[0, 1, 2, 3], + # [1, 0, 3, 2]] + # 0 1 2 3 + # -> A = [[0, 1, 0, 0], 1 + # [1, 0, 0, 0], 0 + # [0, 0, 0, 1], 3 + # [0, 0, 1, 0]] 2 + # Note: We don't have duplicate edges in undirected_edge_index, but + # even if we did, torch.sparse_coo_tensor would sum them up automatically + adj_values = torch.ones(src.size(0), device=edge_index.device) + adj_indices = torch.stack([src, dest], dim=0) + adj_matrix = torch.sparse_coo_tensor( + adj_indices, adj_values, (num_nodes, num_nodes) + ) + return adj_matrix + + +def get_sparse_normalized_degree_matrix(edge_index: Tensor, num_nodes: int) -> Tensor: + device = edge_index.device + src, _ = edge_index + + # Compute degree for each node, initially degree matrix D has all zeros + degrees: Tensor = torch.zeros(num_nodes, device=device) + + # Example: src = [0, 1, 2, 1], degree_matrix = [0, 0, 0, 0] + # -> degree_matrix[0] += 1 = degree_matrix = [1,0,0,0] + # -> degree_matrix[1] += 1 = degree_matrix = [1,1,0,0] + # -> degree_matrix[2] += 1 = degree_matrix = [1,1,1,0] + # -> degree_matrix[1] += 1 = degree_matrix = [1,2,1,0] + # -> final degree_matrix = [1,2,1,0] + degrees.scatter_add_(dim=0, index=src, src=torch.ones(src.size(0), device=device)) + + # Compute D^-1/2 == D^-0.5 + degree_inv_sqrt: Tensor = degrees.pow(-0.5) + # Handle isolated nodes where degree is 0, which lead to inf values in degree_inv_sqrt + degree_inv_sqrt[degree_inv_sqrt == float("inf")] = 0 + + # Convert degree vector to a diagonal sparse normalized matrix D + # Example: degree_inv_sqrt = [1, 0.707, 1, 0] + # -> diagonal_indices = [[0, 1, 2, 3], + # [0, 1, 2, 3]] + # 0 1 2 3 + # -> D = [[1, 0, 0, 0], 0 + # [0, 0.707, 0, 0], 1 + # [0, 0, 1, 0], 2 + # [0, 0, 0, 0]] 3 + diagonal_indices = torch.arange(num_nodes, device=device).unsqueeze(0).repeat(2, 1) + degree_matrix = torch.sparse_coo_tensor( + indices=diagonal_indices, values=degree_inv_sqrt, size=(num_nodes, num_nodes) + ) + return degree_matrix + + +def get_sparse_normalized_laplacian( + edge_index: Tensor, + num_nodes: Optional[int] = None, +) -> Tensor: + """ + Compute the sparse Laplacian matrix from a graph edge index. + + The GCN Laplacian is defined as: L_GCN = D_hat^-1/2 * A_hat * D_hat^-1/2, + where A_hat = A + I (adjacency with self-loops) and D_hat is the degree matrix of A_hat. + + Args: + edge_index: Edge index tensor of shape (2, |E|). + num_nodes: The number of nodes in the graph. If ``None``, + it will be inferred from ``edge_index`` as ``edge_index.max().item() + 1`` + + Returns: + The sparse symmetrically normalized Laplacian matrix of shape (num_nodes, num_nodes). + """ + undirected_edge_index = to_undirected_edge_index(edge_index, with_self_loops=True) + + # num_nodes assumes that the node indices in edge_index are in the range [0, num_nodes-1], + # as this is the default logic in the library dataset preprocessing. + num_nodes = ( + int(undirected_edge_index.max().item()) + 1 if num_nodes is None else num_nodes + ) + + degree_matrix = get_sparse_normalized_degree_matrix( + edge_index=undirected_edge_index, num_nodes=num_nodes + ) + + adj_matrix = get_sparse_adjacency_matrix( + edge_index=undirected_edge_index, num_nodes=num_nodes + ) + + # Compute normalized Laplacian matrix: L = D^-1/2 * A * D^-1/2 + normalized_laplacian_matrix = torch.sparse.mm( + degree_matrix, torch.sparse.mm(adj_matrix, degree_matrix) + ) + return normalized_laplacian_matrix.coalesce() + + +def reduce_to_graph_edge_index( + x: Tensor, + edge_index: Tensor, + with_mediators: bool = False, + remove_selfloops: bool = True, +) -> Tensor: + r""" + Construct a graph from a hypergraph with methods proposed in `HyperGCN: A New Method of Training Graph Convolutional Networks on Hypergraphs `_ paper + Reference implementation: `source `_. + + Args: + x: Node feature matrix. Size ``(|V|, C)``. + edge_index: Hypergraph edge index. Size ``(2, |E|)``. + with_mediator: Whether to use mediator to transform the hyperedges to edges in the graph. Defaults to ``False``. + remove_selfloops: Whether to remove self-loops. Defaults to ``True``. + + Returns: + The graph edge index. Size ``(2, |E'|)``. + """ + device = x.device + + hypergraph = Hypergraph.from_edge_index(edge_index) + hypergraph_edges: List[List[int]] = hypergraph.edges + graph_edges: List[List[int]] = [] + + # Random direction (feature_dim, 1) for projecting nodes in each hyperedge + # Geometrically, we are choosing a random line through the origin in ℝᵈ, where ᵈ = feature_dim + random_direction = torch.rand((x.shape[1], 1), device=device) + + for edge in hypergraph_edges: + num_nodes_in_edge = len(edge) + if num_nodes_in_edge < 2: + raise ValueError("The number of vertices in an hyperedge must be >= 2.") + + # projections (num_nodes_in_edge,) contains a scalar value for each node in the hyperedge, + # indicating its projection on the random vector 'random_direction'. + # Key idea: If two points are very far apart in ℝᵈ, there is a high probability + # that a random projection will still separate them + projections = torch.matmul(x[edge], random_direction).squeeze() + + # The indices of the nodes that the farthest apart in the direction of 'random_direction' + node_max_proj_idx = torch.argmax(projections) + node_min_proj_idx = torch.argmin(projections) + + if not with_mediators: # Just connect the two farthest nodes + graph_edges.append([edge[node_min_proj_idx], edge[node_max_proj_idx]]) + continue + + for node_idx in range(num_nodes_in_edge): + if node_idx != node_max_proj_idx and node_idx != node_min_proj_idx: + graph_edges.append([edge[node_min_proj_idx], edge[node_idx]]) + graph_edges.append([edge[node_max_proj_idx], edge[node_idx]]) + + graph = Graph(edges=graph_edges) + if remove_selfloops: + graph.remove_self_loops() + + return graph.to_edge_index() + + +def smoothing_with_gcn_laplacian_matrix( + x: Tensor, + laplacian_matrix: Tensor, + drop_rate: float = 0.0, +) -> Tensor: + r""" + Return the feature matrix smoothed with GCN Laplacian matrix. + Reference implementation: `source `_. + + Args: + x: Node feature matrix. Size ``(|V|, C)``. + drop_rate: Randomly dropout the connections in adjacency matrix with probability ``drop_rate``. Default: ``0.0``. + + Returns: + The smoothed feature matrix. Size ``(|V|, C)``. + """ + if drop_rate > 0.0: + laplacian_matrix = sparse_dropout(laplacian_matrix, drop_rate) + return laplacian_matrix.matmul(x) + + +def to_undirected_edge_index( + edge_index: Tensor, with_self_loops: bool = False +) -> Tensor: + """ + Convert a directed edge index to an undirected edge index by adding reverse edges. + + Args: + edge_index: Edge index tensor of shape (2, |E|). + with_self_loops: Whether to add self-loops to each node. Defaults to ``False``. + + Returns: + The undirected edge index tensor of shape (2, |E'|). If ``with_self_loops`` is ``True``, self-loops are added. + """ + src, dest = edge_index[0], edge_index[1] + src, dest = torch.cat([src, dest]), torch.cat([dest, src]) + + # Example: edge_index = [[0, 1, 2], + # [1, 0, 3]] + # -> after torch.stack([...], dim=0): + # undirected_edge_index = [[0, 1, 2, 1, 0, 3], + # [1, 0, 3, 0, 1, 2]] + # -> after torch.unique(..., dim=1): + # undirected_edge_index = [[0, 1, 2, 3], + # [1, 0, 3, 2]] + undirected_edge_index = torch.stack([src, dest], dim=0) + undirected_edge_index = torch.unique(undirected_edge_index, dim=1) + + if with_self_loops: + # num_nodes assumes that the node indices in edge_index are in the range [0, num_nodes-1], + # as this is the default logic in the library dataset preprocessing. + num_nodes = int(undirected_edge_index.max().item()) + 1 + src, dest = undirected_edge_index[0], undirected_edge_index[1] + + # Add self-loops: A_hat = A + I (works as we assume node indices are in [0, num_nodes-1]) + self_loop_indices = torch.arange(num_nodes, device=edge_index.device) + src = torch.cat([src, self_loop_indices]) + dest = torch.cat([dest, self_loop_indices]) + undirected_edge_index = torch.stack([src, dest], dim=0) + + return undirected_edge_index From 517963187d211d950d38c3b60450c34896e2d95e Mon Sep 17 00:00:00 2001 From: Tiziano Date: Fri, 6 Feb 2026 12:03:22 +0100 Subject: [PATCH 20/24] feat: add unit tests for get_sparse_normalized_degree_matrix --- hyperbench/tests/utils/graph_utils_test.py | 110 ++++++++++++++++++++- hyperbench/utils/__init__.py | 4 + hyperbench/utils/graph_utils.py | 17 ++-- 3 files changed, 122 insertions(+), 9 deletions(-) diff --git a/hyperbench/tests/utils/graph_utils_test.py b/hyperbench/tests/utils/graph_utils_test.py index 6ba6c08..09eae69 100644 --- a/hyperbench/tests/utils/graph_utils_test.py +++ b/hyperbench/tests/utils/graph_utils_test.py @@ -1,8 +1,11 @@ import pytest import torch -from hyperbench.utils import reduce_to_graph_edge_index -from hyperbench.utils.graph_utils import get_sparse_adjacency_matrix +from hyperbench.utils import ( + get_sparse_adjacency_matrix, + get_sparse_normalized_degree_matrix, + reduce_to_graph_edge_index, +) @pytest.fixture(autouse=True) @@ -127,6 +130,109 @@ def test_get_sparse_adjacency_matrix_isolated_nodes( assert torch.all(dense[:, node] == 0) +def test_get_sparse_normalized_degree_matrix_returns_sparse_tensor(): + edge_index = torch.tensor([[0, 1], [1, 0]]) + result = get_sparse_normalized_degree_matrix(edge_index, num_nodes=2) + + assert result.is_sparse + + +@pytest.mark.parametrize( + "edge_index, num_nodes", + [ + pytest.param(torch.tensor([[0, 1], [1, 0]]), 2, id="2_nodes"), + pytest.param(torch.tensor([[0, 1, 2], [1, 2, 0]]), 4, id="4_nodes_3_edges"), + pytest.param( + torch.tensor([[], []], dtype=torch.long), 5, id="5_nodes_no_edges" + ), + ], +) +def test_get_sparse_normalized_degree_matrix_shape(edge_index, num_nodes): + result = get_sparse_normalized_degree_matrix(edge_index, num_nodes=num_nodes) + + assert result.shape == (num_nodes, num_nodes) + + +def test_get_sparse_normalized_degree_matrix_is_diagonal(): + """All non-zero entries are on the diagonal.""" + edge_index = torch.tensor([[0, 1, 1, 2], [1, 0, 2, 1]]) + + result = get_sparse_normalized_degree_matrix(edge_index, num_nodes=3) + dense = result.to_dense() + + # Off-diagonal entries should be zero + for i in range(3): + for j in range(3): + if i != j: + assert dense[i, j] == 0 + + +@pytest.mark.parametrize( + "edge_index, num_nodes, expected_diagonal", + [ + pytest.param( + torch.tensor([[0, 1], [1, 0]]), + 2, + [1.0, 1.0], # degree 1 -> 1^-0.5 = 1 + id="degree_1_each", + ), + pytest.param( + torch.tensor([[0, 0, 1], [1, 2, 0]]), + 3, + # degrees [2, 1, 0] -> [2**-0.5 == 1 / 2**0.5, 1.0, 0] -> [0.707, 1, 0] + [1 / (2**0.5), 1.0, 0.0], + id="mixed_degrees", + ), + pytest.param( + torch.tensor([[0, 0, 0, 0], [1, 2, 3, 4]]), + 5, + [0.5, 0.0, 0.0, 0.0, 0.0], # degree 4 -> 4^-0.5 = 0.5, others are isolated + id="single_hub_node", + ), + ], +) +def test_get_sparse_normalized_degree_matrix_diagonal_values( + edge_index, num_nodes, expected_diagonal +): + result = get_sparse_normalized_degree_matrix(edge_index, num_nodes=num_nodes) + dense = result.to_dense() + + for i, expected_val in enumerate(expected_diagonal): + assert torch.isclose(dense[i, i], torch.tensor(expected_val), atol=1e-6) + + +def test_get_sparse_normalized_degree_matrix_isolated_nodes_are_zero(): + """Isolated nodes (degree 0) have 0 on diagonal, not inf.""" + edge_index = torch.tensor([[0], [1]]) + + result = get_sparse_normalized_degree_matrix(edge_index, num_nodes=4) + dense = result.to_dense() + + # Nodes 2 and 3 are isolated + assert dense[2, 2] == 0 + assert dense[3, 3] == 0 + # No inf values + assert not torch.any(torch.isinf(dense)) + + +def test_get_sparse_normalized_degree_matrix_empty_edge_index(): + """Empty edge_index produces all-zero matrix (all nodes isolated).""" + edge_index = torch.tensor([[], []], dtype=torch.long) + + result = get_sparse_normalized_degree_matrix(edge_index, num_nodes=3) + dense = result.to_dense() + + assert torch.all(dense == 0) + + +def test_get_sparse_normalized_degree_matrix_preserves_device(): + edge_index = torch.tensor([[0], [1]], device="cpu") + + result = get_sparse_normalized_degree_matrix(edge_index, num_nodes=2) + + assert result.device == edge_index.device + + @pytest.mark.parametrize( "x, edge_index, with_mediators, expected_num_edges", [ diff --git a/hyperbench/utils/__init__.py b/hyperbench/utils/__init__.py index c5f314a..d376695 100644 --- a/hyperbench/utils/__init__.py +++ b/hyperbench/utils/__init__.py @@ -9,6 +9,8 @@ from .graph_utils import ( reduce_to_graph_edge_index, smoothing_with_gcn_laplacian_matrix, + get_sparse_adjacency_matrix, + get_sparse_normalized_degree_matrix, get_sparse_normalized_laplacian, ) from .hif_utils import validate_hif_json @@ -23,6 +25,8 @@ "reduce_to_graph_edge_index", "smoothing_with_gcn_laplacian_matrix", "sparse_dropout", + "get_sparse_adjacency_matrix", + "get_sparse_normalized_degree_matrix", "get_sparse_normalized_laplacian", "to_non_empty_edgeattr", "validate_hif_json", diff --git a/hyperbench/utils/graph_utils.py b/hyperbench/utils/graph_utils.py index fff5507..a41bf56 100644 --- a/hyperbench/utils/graph_utils.py +++ b/hyperbench/utils/graph_utils.py @@ -49,13 +49,16 @@ def get_sparse_normalized_degree_matrix(edge_index: Tensor, num_nodes: int) -> T # Compute degree for each node, initially degree matrix D has all zeros degrees: Tensor = torch.zeros(num_nodes, device=device) - # Example: src = [0, 1, 2, 1], degree_matrix = [0, 0, 0, 0] - # -> degree_matrix[0] += 1 = degree_matrix = [1,0,0,0] - # -> degree_matrix[1] += 1 = degree_matrix = [1,1,0,0] - # -> degree_matrix[2] += 1 = degree_matrix = [1,1,1,0] - # -> degree_matrix[1] += 1 = degree_matrix = [1,2,1,0] - # -> final degree_matrix = [1,2,1,0] - degrees.scatter_add_(dim=0, index=src, src=torch.ones(src.size(0), device=device)) + # Example: src = [0, 1, 2, 1], degrees = [0, 0, 0, 0] + # -> degrees[0] += 1 = degrees = [1,0,0,0] + # -> degrees[1] += 1 = degrees = [1,1,0,0] + # -> degrees[2] += 1 = degrees = [1,1,1,0] + # -> degrees[1] += 1 = degrees = [1,2,1,0] + # -> final degrees = [1,2,1,0] + degree_initial_values = torch.ones( + src.size(0), device=device + ) # Each edge contributes 1 to the degree of the source node + degrees.scatter_add_(dim=0, index=src, src=degree_initial_values) # Compute D^-1/2 == D^-0.5 degree_inv_sqrt: Tensor = degrees.pow(-0.5) From 5e3b560c7e09aeb930b8502cacaa16ead2b221ce Mon Sep 17 00:00:00 2001 From: Tiziano Date: Fri, 6 Feb 2026 12:51:06 +0100 Subject: [PATCH 21/24] feat: add unit tests for get_sparse_normalized_laplacian --- hyperbench/tests/utils/graph_utils_test.py | 130 +++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/hyperbench/tests/utils/graph_utils_test.py b/hyperbench/tests/utils/graph_utils_test.py index 09eae69..41862b8 100644 --- a/hyperbench/tests/utils/graph_utils_test.py +++ b/hyperbench/tests/utils/graph_utils_test.py @@ -1,13 +1,37 @@ import pytest import torch +import warnings from hyperbench.utils import ( get_sparse_adjacency_matrix, get_sparse_normalized_degree_matrix, + get_sparse_normalized_laplacian, reduce_to_graph_edge_index, ) +@pytest.fixture(autouse=True) +def suppress_sparse_csr_warning(): + """ + Suppress PyTorch sparse CSR beta warning. + It could be avoided by doing sparse @ dense, as it doesn't trigger CSR warning. + However, it's inefficient for large graphs. + + Example: + ``` + AD = torch.sparse.mm(A, D.to_dense()) + L = torch.sparse.mm(D, AD).to_sparse_coo() + ``` + """ + with warnings.catch_warnings(): + warnings.filterwarnings( + "ignore", + message="Sparse CSR tensor support is in beta state", + category=UserWarning, + ) + yield + + @pytest.fixture(autouse=True) def seed(): """Fix random seed for deterministic projections.""" @@ -233,6 +257,112 @@ def test_get_sparse_normalized_degree_matrix_preserves_device(): assert result.device == edge_index.device +def test_get_sparse_normalized_laplacian_returns_sparse_tensor(): + edge_index = torch.tensor([[0, 1], [1, 0]]) + + result = get_sparse_normalized_laplacian(edge_index) + + assert result.is_sparse + + +@pytest.mark.parametrize( + "edge_index, num_nodes", + [ + pytest.param(torch.tensor([[0, 1], [1, 0]]), 2, id="2_nodes"), + pytest.param(torch.tensor([[0, 1, 2], [1, 2, 0]]), 4, id="4_nodes"), + pytest.param(torch.tensor([[0, 1], [1, 0]]), None, id="2_nodes_inferred"), + ], +) +def test_get_sparse_normalized_laplacian_shape(edge_index, num_nodes): + result = get_sparse_normalized_laplacian(edge_index, num_nodes=num_nodes) + expected_num_nodes = num_nodes if num_nodes else edge_index.max().item() + 1 + + assert result.shape == (expected_num_nodes, expected_num_nodes) + + +def test_get_sparse_normalized_laplacian_is_symmetric(): + """GCN Laplacian L = D^-1/2 * A * D^-1/2 is symmetric.""" + edge_index = torch.tensor([[0, 1, 2], [1, 2, 0]]) + + result = get_sparse_normalized_laplacian(edge_index) + dense = result.to_dense() + + assert torch.allclose(dense, dense.T, atol=1e-6) + + +def test_get_sparse_normalized_laplacian_self_loop_diagonal(): + """Single node graph has diagonal value 1 (self-loop normalized).""" + edge_index = torch.tensor([[0], [0]]) + + result = get_sparse_normalized_laplacian(edge_index, num_nodes=1) + dense = result.to_dense() + + # Self-loop only: degree = 1, so D^-1/2 * A * D^-1/2 = 1 * 1 * 1 = 1 + assert torch.isclose(dense[0, 0], torch.tensor(1.0), atol=1e-6) + + +@pytest.mark.parametrize( + "edge_index, num_nodes, expected_row_sum", + [ + pytest.param( + torch.tensor([[0, 1], [1, 0]]), + 2, + 1.0, # Each node has degree 2 (edge + self-loop), diagonal = 1/2 each + id="connected_graph", + ), + pytest.param( + torch.tensor([[0, 1, 2], [1, 2, 0]]), + 3, + 1.0, # Triangle: each node degree 3 (2 edges + self-loop), diag = 1/3 each + id="triangle_graph", + ), + ], +) +def test_get_sparse_normalized_laplacian_row_sum( + edge_index, num_nodes, expected_row_sum +): + """ + For connected graphs with self-loops, GCN normalization makes the + laplacian matrix row-stochastic: every row sums to 1.0. + """ + result = get_sparse_normalized_laplacian(edge_index, num_nodes=num_nodes) + dense = result.to_dense() + + # Each row should sum to 1 for connected graphs with self-loops + for i in range(num_nodes): + assert torch.isclose(dense[i].sum(), torch.tensor(expected_row_sum), atol=1e-6) + + +def test_get_sparse_normalized_laplacian_preserves_device(): + edge_index = torch.tensor([[0, 1], [1, 0]], device="cpu") + + result = get_sparse_normalized_laplacian(edge_index) + + assert result.device == edge_index.device + + +def test_get_sparse_normalized_laplacian_no_nan_or_inf(): + edge_index = torch.tensor([[0, 1, 2], [1, 2, 0]]) + + result = get_sparse_normalized_laplacian(edge_index, num_nodes=4) + dense = result.to_dense() + + assert not torch.any(torch.isnan(dense)) + assert not torch.any(torch.isinf(dense)) + + +def test_get_sparse_normalized_laplacian_has_0_for_isolated_nodes(): + edge_index = torch.tensor([[0], [1]]) + + result = get_sparse_normalized_laplacian(edge_index, num_nodes=4) + dense = result.to_dense() + + assert torch.all(dense[2, :] == 0) + assert torch.all(dense[:, 2] == 0) + assert torch.all(dense[3, :] == 0) + assert torch.all(dense[:, 3] == 0) + + @pytest.mark.parametrize( "x, edge_index, with_mediators, expected_num_edges", [ From 48ddd6291870e872ef000a21400335a9f2dc90a7 Mon Sep 17 00:00:00 2001 From: Tiziano Date: Fri, 6 Feb 2026 14:42:55 +0100 Subject: [PATCH 22/24] feat: add unit tests for smoothing_with_gcn_laplacian_matrix --- hyperbench/tests/utils/graph_utils_test.py | 195 +++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/hyperbench/tests/utils/graph_utils_test.py b/hyperbench/tests/utils/graph_utils_test.py index 41862b8..5625486 100644 --- a/hyperbench/tests/utils/graph_utils_test.py +++ b/hyperbench/tests/utils/graph_utils_test.py @@ -7,6 +7,7 @@ get_sparse_normalized_degree_matrix, get_sparse_normalized_laplacian, reduce_to_graph_edge_index, + smoothing_with_gcn_laplacian_matrix, ) @@ -529,3 +530,197 @@ def test_reduce_to_graph_raises_on_single_node_hyperedge(): ValueError, match="The number of vertices in an hyperedge must be >= 2." ): reduce_to_graph_edge_index(x, edge_index) + + +@pytest.mark.parametrize( + "num_nodes, num_features", + [ + pytest.param(2, 2, id="2x2"), + pytest.param(3, 4, id="3x4"), + pytest.param(5, 1, id="5x1"), + pytest.param(10, 8, id="10x8"), + ], +) +def test_smoothing_with_gcn_laplacian_output_shape_matches_x_shape( + num_nodes, num_features +): + """Output shape should match input node feature matrix X shape (|V|, C).""" + x = torch.randn(num_nodes, num_features) + edge_index = torch.tensor([[i, (i + 1) % num_nodes] for i in range(num_nodes)]).T + + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=num_nodes) + + result = smoothing_with_gcn_laplacian_matrix(x, laplacian) + + assert result.shape == x.shape + + +def test_smoothing_with_gcn_laplacian_with_identity_laplacian_returns_original_x(): + """Smoothing with identity laplacian should return the original features.""" + num_nodes = 3 + x = torch.tensor([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]) + + # Create identity matrix as sparse tensor + indices = torch.arange(num_nodes).unsqueeze(0).repeat(2, 1) + values = torch.ones(num_nodes) + identity_laplacian = torch.sparse_coo_tensor( + indices, values, size=(num_nodes, num_nodes) + ) + + result = smoothing_with_gcn_laplacian_matrix(x, identity_laplacian) + + assert torch.allclose(result, x, atol=1e-6) + + +def test_smoothing_with_gcn_laplacian_zero_features(): + """Zero features should remain zero after smoothing.""" + x = torch.zeros(3, 2) + edge_index = torch.tensor([[0, 1, 2], [1, 2, 0]]) + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=3) + + result = smoothing_with_gcn_laplacian_matrix(x, laplacian) + print(result) + + assert torch.allclose(result, torch.zeros_like(x), atol=1e-6) + + +def test_smoothing_with_gcn_laplacian_single_node_returns_original_x(): + """Single node with self-loop should return the original features.""" + x = torch.tensor([[1.0, 2.0]]) + edge_index = torch.tensor([[0], [0]]) # Self-loop + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=1) + + result = smoothing_with_gcn_laplacian_matrix(x, laplacian) + print(laplacian.to_dense(), result) + + # Single node with self-loop has L[0,0] = 1, so result = 1 * x = x + # as the laplacian is [[1.0]], so: + # result = L @ x = [[1.0]] @ [[1.0, 2.0]] = [[1.0 * 1.0, 1.0 * 2.0]] = [[1.0, 2.0]] = x + assert torch.allclose(result, x, atol=1e-6) + + +def test_smoothing_with_gcn_laplacian_preserves_x_device(): + device = torch.device("cpu") + + x = torch.tensor([[1.0, 0.0], [0.0, 1.0]], device=device) + edge_index = torch.tensor([[0, 1], [1, 0]], device=device) + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=2) + + result = smoothing_with_gcn_laplacian_matrix(x, laplacian) + + assert result.device == x.device + + +def test_smoothing_with_gcn_laplacian_preserves_x_dtype(): + x = torch.tensor([[1.0, 0.0], [0.0, 1.0]], dtype=torch.float32) + edge_index = torch.tensor([[0, 1], [1, 0]]) + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=2) + + result = smoothing_with_gcn_laplacian_matrix(x, laplacian) + + assert result.dtype == x.dtype + + +def test_smoothing_with_gcn_laplacian_no_nan_or_inf(): + x = torch.randn(5, 3) + edge_index = torch.tensor([[0, 1, 2, 3], [1, 2, 3, 4]]) + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=5) + + result = smoothing_with_gcn_laplacian_matrix(x, laplacian) + + assert not torch.any(torch.isnan(result)) + assert not torch.any(torch.isinf(result)) + + +def test_smoothing_with_gcn_laplacian_returns_expected_x(): + x = torch.tensor([[1.0, 2.0], [3.0, 4.0]]) + edge_index = torch.tensor([[0, 1], [1, 0]]) + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=2) + + result = smoothing_with_gcn_laplacian_matrix(x, laplacian) + + # For 2 nodes with bidirectional edge, GCN adds self-loops, so each node has degree 2. + # The GCN Laplacian L = D^-1/2 * A_hat * D^-1/2 = [[0.5, 0.5], + # [0.5, 0.5]] + # L @ x = [[0.5*1 + 0.5*3, 0.5*2 + 0.5*4], + # [0.5*1 + 0.5*3, 0.5*2 + 0.5*4]] + # = [[2.0, 3.0], + # [2.0, 3.0]] + expected = torch.tensor([[2.0, 3.0], [2.0, 3.0]]) + + assert torch.allclose(result, expected, atol=1e-6) + + +def test_smoothing_with_gcn_laplacian_is_equal_for_zero_and_no_drop_rate(): + """drop_rate=0 should produce the same result as no dropout.""" + x = torch.tensor([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]) + edge_index = torch.tensor([[0, 1, 2], [1, 2, 0]]) + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=3) + + result_no_dropout = smoothing_with_gcn_laplacian_matrix(x, laplacian) + result_zero_dropout = smoothing_with_gcn_laplacian_matrix( + x, laplacian, drop_rate=0.0 + ) + + assert torch.allclose(result_no_dropout, result_zero_dropout, atol=1e-6) + + +def test_smoothing_with_gcn_laplacian_nonzero_drop_rate_changes_output(): + torch.manual_seed(123) + x = torch.tensor([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]) + edge_index = torch.tensor([[0, 1, 2], [1, 2, 0]]) + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=3) + + result_no_dropout = smoothing_with_gcn_laplacian_matrix( + x, laplacian.clone(), drop_rate=0.0 + ) + result_with_dropout = smoothing_with_gcn_laplacian_matrix( + x, laplacian.clone(), drop_rate=0.7 + ) + + assert not torch.allclose(result_no_dropout, result_with_dropout, atol=1e-6) + + +def test_smoothing_with_gcn_laplacian_drop_rate_stochastic(): + """Different seeds should produce different outputs with dropout.""" + x = torch.tensor([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]) + edge_index = torch.tensor([[0, 1, 2], [1, 2, 0]]) + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=3) + + torch.manual_seed(42) + result1 = smoothing_with_gcn_laplacian_matrix(x, laplacian.clone(), drop_rate=0.5) + + torch.manual_seed(99) + result2 = smoothing_with_gcn_laplacian_matrix(x, laplacian.clone(), drop_rate=0.5) + + # Different random seeds should produce different dropout masks + assert not torch.allclose(result1, result2, atol=1e-6) + + +def test_smoothing_with_gcn_laplacian_influences_connected_nodes(): + """ + Features of connected nodes should be aggregated. + For a connected graph with GCN normalization, smoothing should mix features from neighbors. + """ + # Two connected nodes with distinct features + x = torch.tensor([[1.0, 0.0], [0.0, 1.0]]) + edge_index = torch.tensor([[0, 1], [1, 0]]) # Bidirectional edge + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=2) + + result = smoothing_with_gcn_laplacian_matrix(x, laplacian) + + # After smoothing, node 0 should have some of node 1's features and vice versa + # Row sum of GCN laplacian is 1 for connected graphs, so features are mixed + assert result[0, 1] > 0 # Node 0 now has some of feature dimension 1 from node 1 + assert result[1, 0] > 0 # Node 1 now has some of feature dimension 0 from node 0 + + +def test_smoothing_with_gcn_laplacian_isolated_nodes_have_zero_features(): + x = torch.tensor([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]]) + edge_index = torch.tensor([[0], [1]]) # Only nodes 0 and 1 connected + laplacian = get_sparse_normalized_laplacian(edge_index, num_nodes=3) + + result = smoothing_with_gcn_laplacian_matrix(x, laplacian) + + # Node 2 is isolated, so its output should be zero + assert torch.allclose(result[2], torch.zeros(2), atol=1e-6) From 9ff08612a9d5e88a24aa9fa65e63ca8f1107c0f0 Mon Sep 17 00:00:00 2001 From: Tiziano Date: Fri, 6 Feb 2026 15:08:12 +0100 Subject: [PATCH 23/24] feat: add unit tests for to_undirected_edge_index --- hyperbench/tests/utils/graph_utils_test.py | 153 +++++++++++++++++++++ hyperbench/utils/__init__.py | 2 + hyperbench/utils/graph_utils.py | 10 +- 3 files changed, 160 insertions(+), 5 deletions(-) diff --git a/hyperbench/tests/utils/graph_utils_test.py b/hyperbench/tests/utils/graph_utils_test.py index 5625486..5645fb2 100644 --- a/hyperbench/tests/utils/graph_utils_test.py +++ b/hyperbench/tests/utils/graph_utils_test.py @@ -8,6 +8,7 @@ get_sparse_normalized_laplacian, reduce_to_graph_edge_index, smoothing_with_gcn_laplacian_matrix, + to_undirected_edge_index, ) @@ -724,3 +725,155 @@ def test_smoothing_with_gcn_laplacian_isolated_nodes_have_zero_features(): # Node 2 is isolated, so its output should be zero assert torch.allclose(result[2], torch.zeros(2), atol=1e-6) + + +def test_to_undirected_edge_index_single_directed_edge(): + """A single directed edge (0 -> 1) should produce bidirectional edges.""" + edge_index = torch.tensor([[0], [1]]) + + result = to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + # Should contain both (0, 1) and (1, 0) + assert (0, 1) in edges + assert (1, 0) in edges + assert len(edges) == 2 + + +def test_to_undirected_edge_index_already_undirected_does_not_create_duplicates(): + edge_index = torch.tensor([[0, 1], [1, 0]]) + + result = to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + assert edges == {(0, 1), (1, 0)} + + +def test_to_undirected_edge_index_removes_duplicate_edges(): + edge_index = torch.tensor([[0, 0, 1], [1, 1, 0]]) + + result = to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + assert edges == {(0, 1), (1, 0)} + + +def test_to_undirected_edge_index_triangle_directed(): + """ + A directed triangle should become a bidirectional triangle. + + Example: + Directed cycle: 0 -> 1 -> 2 -> 0 + Bidirectional traingle: 0 <-> 1 <-> 2 <-> 0 + """ + edge_index = torch.tensor([[0, 1, 2], [1, 2, 0]]) + + result = to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + bidirectional_triangle = {(0, 1), (1, 0), (1, 2), (2, 1), (2, 0), (0, 2)} + assert edges == bidirectional_triangle + + +def test_to_undirected_edge_index_preserves_self_loops_in_input(): + edge_index = torch.tensor([[0, 1, 1], [1, 0, 1]]) # (1, 1) is a self-loop + + result = to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + assert (1, 1) in edges + + +def test_to_undirected_edge_index_empty_edge_index_returns_empty_tensor(): + edge_index = torch.tensor([[], []]) + + result = to_undirected_edge_index(edge_index) + + assert result.shape == (2, 0) + + +def test_to_undirected_edge_index_with_self_loops_adds_all_self_loops(): + edge_index = torch.tensor([[0, 1], [1, 2]]) + + result = to_undirected_edge_index(edge_index, with_selfloops=True) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + # Should have self-loops for nodes 0, 1, 2 (inferred from max index) + assert (0, 0) in edges + assert (1, 1) in edges + assert (2, 2) in edges + + +def test_to_undirected_edge_index_with_self_loops_does_not_duplicate_self_loops(): + edge_index = torch.tensor([[0, 1], [1, 1]]) # (1, 1) is already a self-loop + + result = to_undirected_edge_index(edge_index, with_selfloops=True) + edges = list(zip(result[0].tolist(), result[1].tolist())) + + assert (0, 0) in edges + assert (1, 1) in edges + + +@pytest.mark.parametrize( + "with_self_loops", + [ + pytest.param(True, id="with_self_loops"), + pytest.param(False, id="without_self_loops"), + ], +) +def test_to_undirected_edge_index_preserves_device(with_self_loops): + edge_index = torch.tensor([[0], [1]], device="cpu") + + result = to_undirected_edge_index(edge_index, with_selfloops=with_self_loops) + + assert result.device == edge_index.device + + +def test_to_undirected_edge_index_disconnected_components(): + # Two disconnected components: (0, 1) and (2, 3) + edge_index = torch.tensor([[0, 2], [1, 3]]) + + result = to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + expected = {(0, 1), (1, 0), (2, 3), (3, 2)} + assert edges == expected + + +@pytest.mark.parametrize( + "edge_index, expected_num_undirected_edges", + [ + pytest.param( + torch.tensor([[0], [1]]), + 2, + id="single_edge_becomes_two", + ), + pytest.param( + torch.tensor([[0, 1], [1, 0]]), + 2, + id="bidirectional_stays_two", + ), + pytest.param( + torch.tensor([[0, 1, 2], [1, 2, 0]]), + 6, + id="directed_triangle_becomes_six", + ), + pytest.param( + torch.tensor([[0, 0], [1, 2]]), + 4, + id="star_two_edges_becomes_four", + ), + ], +) +def test_to_undirected_edge_index_edge_count(edge_index, expected_num_undirected_edges): + result = to_undirected_edge_index(edge_index) + + assert result.shape[1] == expected_num_undirected_edges + + +def test_to_undirected_edge_index_dtype_preserved(): + edge_index = torch.tensor([[0, 1], [1, 2]], dtype=torch.long) + + result = to_undirected_edge_index(edge_index) + + assert result.dtype == edge_index.dtype diff --git a/hyperbench/utils/__init__.py b/hyperbench/utils/__init__.py index d376695..cbaaae4 100644 --- a/hyperbench/utils/__init__.py +++ b/hyperbench/utils/__init__.py @@ -12,6 +12,7 @@ get_sparse_adjacency_matrix, get_sparse_normalized_degree_matrix, get_sparse_normalized_laplacian, + to_undirected_edge_index, ) from .hif_utils import validate_hif_json from .sparse_utils import sparse_dropout @@ -29,5 +30,6 @@ "get_sparse_normalized_degree_matrix", "get_sparse_normalized_laplacian", "to_non_empty_edgeattr", + "to_undirected_edge_index", "validate_hif_json", ] diff --git a/hyperbench/utils/graph_utils.py b/hyperbench/utils/graph_utils.py index a41bf56..70ae9f4 100644 --- a/hyperbench/utils/graph_utils.py +++ b/hyperbench/utils/graph_utils.py @@ -99,7 +99,7 @@ def get_sparse_normalized_laplacian( Returns: The sparse symmetrically normalized Laplacian matrix of shape (num_nodes, num_nodes). """ - undirected_edge_index = to_undirected_edge_index(edge_index, with_self_loops=True) + undirected_edge_index = to_undirected_edge_index(edge_index, with_selfloops=True) # num_nodes assumes that the node indices in edge_index are in the range [0, num_nodes-1], # as this is the default logic in the library dataset preprocessing. @@ -204,17 +204,17 @@ def smoothing_with_gcn_laplacian_matrix( def to_undirected_edge_index( - edge_index: Tensor, with_self_loops: bool = False + edge_index: Tensor, with_selfloops: bool = False ) -> Tensor: """ Convert a directed edge index to an undirected edge index by adding reverse edges. Args: edge_index: Edge index tensor of shape (2, |E|). - with_self_loops: Whether to add self-loops to each node. Defaults to ``False``. + with_selfloops: Whether to add self-loops to each node. Defaults to ``False``. Returns: - The undirected edge index tensor of shape (2, |E'|). If ``with_self_loops`` is ``True``, self-loops are added. + The undirected edge index tensor of shape (2, |E'|). If ``with_selfloops`` is ``True``, self-loops are added. """ src, dest = edge_index[0], edge_index[1] src, dest = torch.cat([src, dest]), torch.cat([dest, src]) @@ -230,7 +230,7 @@ def to_undirected_edge_index( undirected_edge_index = torch.stack([src, dest], dim=0) undirected_edge_index = torch.unique(undirected_edge_index, dim=1) - if with_self_loops: + if with_selfloops: # num_nodes assumes that the node indices in edge_index are in the range [0, num_nodes-1], # as this is the default logic in the library dataset preprocessing. num_nodes = int(undirected_edge_index.max().item()) + 1 From 98001325482c429de7cfab9a2bea43f4de338503 Mon Sep 17 00:00:00 2001 From: Tiziano Date: Fri, 6 Feb 2026 16:48:37 +0100 Subject: [PATCH 24/24] refactor: move methods to graph class --- hyperbench/tests/types/graph_test.py | 218 ++++++++++++++++++--- hyperbench/tests/utils/graph_utils_test.py | 173 ++-------------- hyperbench/types/graph.py | 65 +++++- hyperbench/utils/__init__.py | 6 +- hyperbench/utils/graph_utils.py | 68 ++----- 5 files changed, 283 insertions(+), 247 deletions(-) diff --git a/hyperbench/tests/types/graph_test.py b/hyperbench/tests/types/graph_test.py index 7808f21..2739584 100644 --- a/hyperbench/tests/types/graph_test.py +++ b/hyperbench/tests/types/graph_test.py @@ -16,12 +16,12 @@ def mock_linear_graph(): @pytest.fixture -def mock_graph_with_only_self_loops(): +def mock_graph_with_only_selfloops(): return Graph([[0, 0], [1, 1]]) @pytest.fixture -def mock_graph_with_one_self_loop(): +def mock_graph_with_one_selfloop(): return Graph([[0, 1], [1, 1], [2, 3]]) @@ -46,10 +46,10 @@ def test_init_edges(graph, expected_edges): [ pytest.param(Graph([]), 0, id="empty_graph"), pytest.param(Graph([[0, 1]]), 2, id="single_edge"), - pytest.param(Graph([[0, 0]]), 1, id="single_edge_self_loop"), + pytest.param(Graph([[0, 0]]), 1, id="single_edge_selfloop"), pytest.param(Graph([[0, 1], [1, 2], [2, 3]]), 4, id="linear_graph"), - pytest.param(Graph([[0, 0], [1, 1]]), 2, id="only_self_loops"), - pytest.param(Graph([[0, 1], [1, 1], [2, 3]]), 4, id="one_self_loop"), + pytest.param(Graph([[0, 0], [1, 1]]), 2, id="only_selfloops"), + pytest.param(Graph([[0, 1], [1, 1], [2, 3]]), 4, id="one_selfloop"), pytest.param(Graph([[0, 1], [2, 3]]), 4, id="disconnected_graph"), pytest.param( Graph([[0, 1], [0, 1], [1, 2]]), @@ -68,10 +68,10 @@ def test_num_nodes(graph, expected_num_nodes): [ pytest.param(Graph([]), 0, id="empty_graph"), pytest.param(Graph([[0, 1]]), 1, id="single_edge"), - pytest.param(Graph([[0, 0]]), 1, id="single_edge_self_loop"), + pytest.param(Graph([[0, 0]]), 1, id="single_edge_selfloop"), pytest.param(Graph([[0, 1], [1, 2], [2, 3]]), 3, id="linear_graph"), - pytest.param(Graph([[0, 0], [1, 1]]), 2, id="only_self_loops"), - pytest.param(Graph([[0, 1], [1, 1], [2, 3]]), 3, id="one_self_loop"), + pytest.param(Graph([[0, 0], [1, 1]]), 2, id="only_selfloops"), + pytest.param(Graph([[0, 1], [1, 1], [2, 3]]), 3, id="one_selfloop"), pytest.param(Graph([[0, 1], [2, 3]]), 2, id="disconnected_graph"), pytest.param( Graph([[0, 1], [0, 1], [1, 2]]), @@ -92,14 +92,14 @@ def test_num_edges(graph, expected_num_edges): pytest.param( Graph([[0, 1], [2, 3]]), [[0, 1], [2, 3]], - id="no_self_loops", + id="no_selfloops", ), - pytest.param(Graph([[0, 0]]), [], id="one_edge_one_self_loop"), - pytest.param(Graph([[0, 1], [1, 1]]), [[0, 1]], id="one_self_loop"), + pytest.param(Graph([[0, 0]]), [], id="one_edge_one_selfloop"), + pytest.param(Graph([[0, 1], [1, 1]]), [[0, 1]], id="one_selfloop"), pytest.param( Graph([[0, 0], [1, 1], [2, 2]]), [], - id="all_self_loops", + id="all_selfloops", ), pytest.param( Graph([[0, 1], [1, 2], [2, 2]]), @@ -109,24 +109,24 @@ def test_num_edges(graph, expected_num_edges): pytest.param( Graph([[0, 0], [0, 1], [1, 1], [1, 2]]), [[0, 1], [1, 2]], - id="mixed_edges_multiple_self_loops", + id="mixed_edges_multiple_selfloops", ), pytest.param( Graph([[0, 0], [1, 1], [2, 2], [3, 4]]), [[3, 4]], - id="multiple_consecutive_self_loops", + id="multiple_consecutive_selfloops", ), ], ) -def test_remove_self_loops(graph, expected_edges_after_removal): +def test_remove_selfloops(graph, expected_edges_after_removal): """Test removing self-loops for various graph configurations.""" - graph.remove_self_loops() + graph.remove_selfloops() assert graph.edges == expected_edges_after_removal -def test_remove_self_loops_preserves_order(): +def test_remove_selfloops_preserves_order(): graph = Graph([[0, 1], [1, 1], [2, 3], [3, 3], [4, 5]]) - graph.remove_self_loops() + graph.remove_selfloops() assert graph.edges == [[0, 1], [2, 3], [4, 5]] @@ -156,7 +156,7 @@ def test_remove_self_loops_preserves_order(): pytest.param( Graph([[0, 0], [1, 1]]), torch.tensor([[0, 1], [0, 1]], dtype=torch.long), - id="only_self_loops", + id="only_selfloops", ), pytest.param( Graph([[0, 1], [0, 1], [1, 2]]), @@ -199,14 +199,14 @@ def test_to_edge_index_is_contiguous(mock_single_edge_graph): assert edge_index.is_contiguous() -def test_to_edge_index_before_and_after_removal_all_self_loops( - mock_graph_with_only_self_loops, +def test_to_edge_index_before_and_after_removal_all_selfloops( + mock_graph_with_only_selfloops, ): - edge_index_before = mock_graph_with_only_self_loops.to_edge_index() + edge_index_before = mock_graph_with_only_selfloops.to_edge_index() assert edge_index_before.shape == (2, 2) - mock_graph_with_only_self_loops.remove_self_loops() - edge_index_after = mock_graph_with_only_self_loops.to_edge_index() + mock_graph_with_only_selfloops.remove_selfloops() + edge_index_after = mock_graph_with_only_selfloops.to_edge_index() expected = torch.tensor([], dtype=torch.long).reshape(2, 0) @@ -214,14 +214,14 @@ def test_to_edge_index_before_and_after_removal_all_self_loops( assert torch.equal(edge_index_after, expected) -def test_to_edge_index_before_and_after_removal_one_self_loops( - mock_graph_with_one_self_loop, +def test_to_edge_index_before_and_after_removal_one_selfloops( + mock_graph_with_one_selfloop, ): - edge_index_before = mock_graph_with_one_self_loop.to_edge_index() + edge_index_before = mock_graph_with_one_selfloop.to_edge_index() assert edge_index_before.shape == (2, 3) - mock_graph_with_one_self_loop.remove_self_loops() - edge_index_after = mock_graph_with_one_self_loop.to_edge_index() + mock_graph_with_one_selfloop.remove_selfloops() + edge_index_after = mock_graph_with_one_selfloop.to_edge_index() expected = torch.tensor([[0, 2], [1, 3]]) @@ -261,3 +261,163 @@ def test_cyclic_graph(): edge_index = graph.to_edge_index() assert edge_index.shape == (2, 4) + + +def test_from_directed_to_undirected_edge_index_single_directed_edge(): + """A single directed edge (0 -> 1) should produce bidirectional edges.""" + edge_index = torch.tensor([[0], [1]]) + + result = Graph.from_directed_to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + # Should contain both (0, 1) and (1, 0) + assert (0, 1) in edges + assert (1, 0) in edges + assert len(edges) == 2 + + +def test_from_directed_to_undirected_edge_index_already_undirected_does_not_create_duplicates(): + edge_index = torch.tensor([[0, 1], [1, 0]]) + + result = Graph.from_directed_to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + assert edges == {(0, 1), (1, 0)} + + +def test_from_directed_to_undirected_edge_index_removes_duplicate_edges(): + edge_index = torch.tensor([[0, 0, 1], [1, 1, 0]]) + + result = Graph.from_directed_to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + assert edges == {(0, 1), (1, 0)} + + +def test_from_directed_to_undirected_edge_index_triangle_directed(): + """ + A directed triangle should become a bidirectional triangle. + + Example: + Directed cycle: 0 -> 1 -> 2 -> 0 + Bidirectional traingle: 0 <-> 1 <-> 2 <-> 0 + """ + edge_index = torch.tensor([[0, 1, 2], [1, 2, 0]]) + + result = Graph.from_directed_to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + bidirectional_triangle = {(0, 1), (1, 0), (1, 2), (2, 1), (2, 0), (0, 2)} + assert edges == bidirectional_triangle + + +def test_from_directed_to_undirected_edge_index_preserves_selfloops_in_input(): + edge_index = torch.tensor([[0, 1, 1], [1, 0, 1]]) # (1, 1) is a self-loop + + result = Graph.from_directed_to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + assert (1, 1) in edges + + +def test_from_directed_to_undirected_edge_index_empty_edge_index_returns_empty_tensor(): + edge_index = torch.tensor([[], []]) + + result = Graph.from_directed_to_undirected_edge_index(edge_index) + + assert result.shape == (2, 0) + + +def test_from_directed_to_undirected_edge_index_with_selfloops_adds_all_selfloops(): + edge_index = torch.tensor([[0, 1], [1, 2]]) + + result = Graph.from_directed_to_undirected_edge_index( + edge_index, with_selfloops=True + ) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + # Should have self-loops for nodes 0, 1, 2 (inferred from max index) + assert (0, 0) in edges + assert (1, 1) in edges + assert (2, 2) in edges + + +def test_from_directed_to_undirected_edge_index_with_selfloops_does_not_duplicate_selfloops(): + edge_index = torch.tensor([[0, 1], [1, 1]]) # (1, 1) is already a self-loop + + result = Graph.from_directed_to_undirected_edge_index( + edge_index, with_selfloops=True + ) + edges = list(zip(result[0].tolist(), result[1].tolist())) + + assert (0, 0) in edges + assert (1, 1) in edges + + +@pytest.mark.parametrize( + "with_selfloops", + [ + pytest.param(True, id="with_selfloops"), + pytest.param(False, id="without_selfloops"), + ], +) +def test_from_directed_to_undirected_edge_index_preserves_device(with_selfloops): + edge_index = torch.tensor([[0], [1]], device="cpu") + + result = Graph.from_directed_to_undirected_edge_index( + edge_index, with_selfloops=with_selfloops + ) + + assert result.device == edge_index.device + + +def test_from_directed_to_undirected_edge_index_disconnected_components(): + # Two disconnected components: (0, 1) and (2, 3) + edge_index = torch.tensor([[0, 2], [1, 3]]) + + result = Graph.from_directed_to_undirected_edge_index(edge_index) + edges = set(zip(result[0].tolist(), result[1].tolist())) + + expected = {(0, 1), (1, 0), (2, 3), (3, 2)} + assert edges == expected + + +@pytest.mark.parametrize( + "edge_index, expected_num_undirected_edges", + [ + pytest.param( + torch.tensor([[0], [1]]), + 2, + id="single_edge_becomes_two", + ), + pytest.param( + torch.tensor([[0, 1], [1, 0]]), + 2, + id="bidirectional_stays_two", + ), + pytest.param( + torch.tensor([[0, 1, 2], [1, 2, 0]]), + 6, + id="directed_triangle_becomes_six", + ), + pytest.param( + torch.tensor([[0, 0], [1, 2]]), + 4, + id="star_two_edges_becomes_four", + ), + ], +) +def test_from_directed_to_undirected_edge_index_edge_count( + edge_index, expected_num_undirected_edges +): + result = Graph.from_directed_to_undirected_edge_index(edge_index) + + assert result.shape[1] == expected_num_undirected_edges + + +def test_from_directed_to_undirected_edge_index_dtype_preserved(): + edge_index = torch.tensor([[0, 1], [1, 2]], dtype=torch.long) + + result = Graph.from_directed_to_undirected_edge_index(edge_index) + + assert result.dtype == edge_index.dtype diff --git a/hyperbench/tests/utils/graph_utils_test.py b/hyperbench/tests/utils/graph_utils_test.py index 5645fb2..2f958ae 100644 --- a/hyperbench/tests/utils/graph_utils_test.py +++ b/hyperbench/tests/utils/graph_utils_test.py @@ -6,9 +6,8 @@ get_sparse_adjacency_matrix, get_sparse_normalized_degree_matrix, get_sparse_normalized_laplacian, - reduce_to_graph_edge_index, + reduce_to_graph_edge_index_on_random_direction, smoothing_with_gcn_laplacian_matrix, - to_undirected_edge_index, ) @@ -438,7 +437,7 @@ def test_get_sparse_normalized_laplacian_has_0_for_isolated_nodes(): ], ) def test_reduce_to_graph_edge_count(x, edge_index, with_mediators, expected_num_edges): - result = reduce_to_graph_edge_index( + result = reduce_to_graph_edge_index_on_random_direction( x, edge_index, with_mediators=with_mediators, remove_selfloops=False ) @@ -466,7 +465,7 @@ def test_reduce_to_graph_edge_count(x, edge_index, with_mediators, expected_num_ ], ) def test_reduce_to_graph_output_has_two_rows(x, edge_index): - result = reduce_to_graph_edge_index(x, edge_index) + result = reduce_to_graph_edge_index_on_random_direction(x, edge_index) assert result.shape[0] == 2 @@ -475,7 +474,7 @@ def test_reduce_to_graph_output_dtype_is_long(): x = torch.tensor([[1.0, 0.0], [0.0, 1.0]]) edge_index = torch.tensor([[0, 1], [0, 0]]) - result = reduce_to_graph_edge_index(x, edge_index) + result = reduce_to_graph_edge_index_on_random_direction(x, edge_index) assert result.dtype == torch.long @@ -487,7 +486,7 @@ def test_reduce_to_graph_output_nodes_are_within_bounds(): ) edge_index = torch.tensor([[0, 1, 2, 1, 2, 3], [0, 0, 0, 1, 1, 1]]) - result = reduce_to_graph_edge_index(x, edge_index) + result = reduce_to_graph_edge_index_on_random_direction(x, edge_index) num_nodes = x.shape[0] assert result.min() >= 0 @@ -500,7 +499,9 @@ def test_reduce_to_graph_removes_selfloops(): x = torch.tensor([[1.0, 0.0], [0.0, 1.0]]) edge_index = torch.tensor([[0, 0], [0, 0]]) - result = reduce_to_graph_edge_index(x, edge_index, remove_selfloops=True) + result = reduce_to_graph_edge_index_on_random_direction( + x, edge_index, remove_selfloops=True + ) # Either zero or one edge remains, the reason why one edge may remain is that # after removing self-loops, there could be multiple hyperedges projecting to @@ -517,7 +518,9 @@ def test_reduce_to_graph_keeps_selfloops_when_disabled(): x = torch.tensor([[1.0, 0.0], [0.0, 1.0]]) edge_index = torch.tensor([[0, 0], [0, 0]]) - result = reduce_to_graph_edge_index(x, edge_index, remove_selfloops=False) + result = reduce_to_graph_edge_index_on_random_direction( + x, edge_index, remove_selfloops=False + ) assert result.shape[1] == 1 # One node, one hyperedge assert result[0, 0] == result[1, 0] # Self-loop edge [0, 0] is preserved @@ -530,7 +533,7 @@ def test_reduce_to_graph_raises_on_single_node_hyperedge(): with pytest.raises( ValueError, match="The number of vertices in an hyperedge must be >= 2." ): - reduce_to_graph_edge_index(x, edge_index) + reduce_to_graph_edge_index_on_random_direction(x, edge_index) @pytest.mark.parametrize( @@ -725,155 +728,3 @@ def test_smoothing_with_gcn_laplacian_isolated_nodes_have_zero_features(): # Node 2 is isolated, so its output should be zero assert torch.allclose(result[2], torch.zeros(2), atol=1e-6) - - -def test_to_undirected_edge_index_single_directed_edge(): - """A single directed edge (0 -> 1) should produce bidirectional edges.""" - edge_index = torch.tensor([[0], [1]]) - - result = to_undirected_edge_index(edge_index) - edges = set(zip(result[0].tolist(), result[1].tolist())) - - # Should contain both (0, 1) and (1, 0) - assert (0, 1) in edges - assert (1, 0) in edges - assert len(edges) == 2 - - -def test_to_undirected_edge_index_already_undirected_does_not_create_duplicates(): - edge_index = torch.tensor([[0, 1], [1, 0]]) - - result = to_undirected_edge_index(edge_index) - edges = set(zip(result[0].tolist(), result[1].tolist())) - - assert edges == {(0, 1), (1, 0)} - - -def test_to_undirected_edge_index_removes_duplicate_edges(): - edge_index = torch.tensor([[0, 0, 1], [1, 1, 0]]) - - result = to_undirected_edge_index(edge_index) - edges = set(zip(result[0].tolist(), result[1].tolist())) - - assert edges == {(0, 1), (1, 0)} - - -def test_to_undirected_edge_index_triangle_directed(): - """ - A directed triangle should become a bidirectional triangle. - - Example: - Directed cycle: 0 -> 1 -> 2 -> 0 - Bidirectional traingle: 0 <-> 1 <-> 2 <-> 0 - """ - edge_index = torch.tensor([[0, 1, 2], [1, 2, 0]]) - - result = to_undirected_edge_index(edge_index) - edges = set(zip(result[0].tolist(), result[1].tolist())) - - bidirectional_triangle = {(0, 1), (1, 0), (1, 2), (2, 1), (2, 0), (0, 2)} - assert edges == bidirectional_triangle - - -def test_to_undirected_edge_index_preserves_self_loops_in_input(): - edge_index = torch.tensor([[0, 1, 1], [1, 0, 1]]) # (1, 1) is a self-loop - - result = to_undirected_edge_index(edge_index) - edges = set(zip(result[0].tolist(), result[1].tolist())) - - assert (1, 1) in edges - - -def test_to_undirected_edge_index_empty_edge_index_returns_empty_tensor(): - edge_index = torch.tensor([[], []]) - - result = to_undirected_edge_index(edge_index) - - assert result.shape == (2, 0) - - -def test_to_undirected_edge_index_with_self_loops_adds_all_self_loops(): - edge_index = torch.tensor([[0, 1], [1, 2]]) - - result = to_undirected_edge_index(edge_index, with_selfloops=True) - edges = set(zip(result[0].tolist(), result[1].tolist())) - - # Should have self-loops for nodes 0, 1, 2 (inferred from max index) - assert (0, 0) in edges - assert (1, 1) in edges - assert (2, 2) in edges - - -def test_to_undirected_edge_index_with_self_loops_does_not_duplicate_self_loops(): - edge_index = torch.tensor([[0, 1], [1, 1]]) # (1, 1) is already a self-loop - - result = to_undirected_edge_index(edge_index, with_selfloops=True) - edges = list(zip(result[0].tolist(), result[1].tolist())) - - assert (0, 0) in edges - assert (1, 1) in edges - - -@pytest.mark.parametrize( - "with_self_loops", - [ - pytest.param(True, id="with_self_loops"), - pytest.param(False, id="without_self_loops"), - ], -) -def test_to_undirected_edge_index_preserves_device(with_self_loops): - edge_index = torch.tensor([[0], [1]], device="cpu") - - result = to_undirected_edge_index(edge_index, with_selfloops=with_self_loops) - - assert result.device == edge_index.device - - -def test_to_undirected_edge_index_disconnected_components(): - # Two disconnected components: (0, 1) and (2, 3) - edge_index = torch.tensor([[0, 2], [1, 3]]) - - result = to_undirected_edge_index(edge_index) - edges = set(zip(result[0].tolist(), result[1].tolist())) - - expected = {(0, 1), (1, 0), (2, 3), (3, 2)} - assert edges == expected - - -@pytest.mark.parametrize( - "edge_index, expected_num_undirected_edges", - [ - pytest.param( - torch.tensor([[0], [1]]), - 2, - id="single_edge_becomes_two", - ), - pytest.param( - torch.tensor([[0, 1], [1, 0]]), - 2, - id="bidirectional_stays_two", - ), - pytest.param( - torch.tensor([[0, 1, 2], [1, 2, 0]]), - 6, - id="directed_triangle_becomes_six", - ), - pytest.param( - torch.tensor([[0, 0], [1, 2]]), - 4, - id="star_two_edges_becomes_four", - ), - ], -) -def test_to_undirected_edge_index_edge_count(edge_index, expected_num_undirected_edges): - result = to_undirected_edge_index(edge_index) - - assert result.shape[1] == expected_num_undirected_edges - - -def test_to_undirected_edge_index_dtype_preserved(): - edge_index = torch.tensor([[0, 1], [1, 2]], dtype=torch.long) - - result = to_undirected_edge_index(edge_index) - - assert result.dtype == edge_index.dtype diff --git a/hyperbench/types/graph.py b/hyperbench/types/graph.py index bbdd802..3d87ccb 100644 --- a/hyperbench/types/graph.py +++ b/hyperbench/types/graph.py @@ -23,7 +23,7 @@ def num_edges(self) -> int: """Return the number of edges in the graph.""" return len(self.edges) - def remove_self_loops(self): + def remove_selfloops(self): """ Remove self-loops from the graph. @@ -38,11 +38,11 @@ def remove_self_loops(self): # Example: edges = [[0, 1], # [1, 1], # [2, 3]] shape (|E|, 2) - # -> no_self_loop_mask = [True, False, True] + # -> no_selfloop_mask = [True, False, True] # -> edges without self-loops = [[0, 1], # [2, 3]] - no_self_loop_mask = graph_edges_tensor[:, 0] != graph_edges_tensor[:, 1] - self.edges = graph_edges_tensor[no_self_loop_mask].tolist() + no_selfloop_mask = graph_edges_tensor[:, 0] != graph_edges_tensor[:, 1] + self.edges = graph_edges_tensor[no_selfloop_mask].tolist() def to_edge_index(self) -> Tensor: """ @@ -61,3 +61,60 @@ def to_edge_index(self) -> Tensor: # [1, 2, 3]] shape (2, |E|) edge_index = torch.tensor(self.edges, dtype=torch.long).t() return edge_index + + @classmethod + def from_directed_to_undirected_edge_index( + cls, + edge_index: Tensor, + with_selfloops: bool = False, + ) -> Tensor: + """ + Convert a directed edge index to an undirected edge index by adding reverse edges. + + Args: + edge_index: Tensor of shape ``(2, |E|)`` representing directed edges. + with_selfloops: Whether to add self-loops to each node. Defaults to ``False``. + + Returns: + The undirected edge index tensor of shape ``(2, |E'|)``. If ``with_selfloops`` is ``True``, self-loops are added. + """ + src, dest = edge_index[0], edge_index[1] + src, dest = torch.cat([src, dest]), torch.cat([dest, src]) + + # Example: edge_index = [[0, 1, 2], + # [1, 0, 3]] + # -> after torch.stack([...], dim=0): + # undirected_edge_index = [[0, 1, 2, 1, 0, 3], + # [1, 0, 3, 0, 1, 2]] + # -> after torch.unique(..., dim=1): + # undirected_edge_index = [[0, 1, 2, 3], + # [1, 0, 3, 2]] + undirected_edge_index: Tensor = torch.stack([src, dest], dim=0).to( + edge_index.device + ) + undirected_edge_index = cls.__remove_duplicate_edges(undirected_edge_index) + + if with_selfloops: + # num_nodes assumes that the node indices in edge_index are in the range [0, num_nodes-1], + # as this is the default logic in the library dataset preprocessing. + num_nodes = int(undirected_edge_index.max().item()) + 1 + src, dest = undirected_edge_index[0], undirected_edge_index[1] + + # Add self-loops: A_hat = A + I (works as we assume node indices are in [0, num_nodes-1]) + selfloop_indices = torch.arange(num_nodes, device=edge_index.device) + src = torch.cat([src, selfloop_indices]) + dest = torch.cat([dest, selfloop_indices]) + undirected_edge_index = torch.stack([src, dest], dim=0) + undirected_edge_index = cls.__remove_duplicate_edges(undirected_edge_index) + + return undirected_edge_index + + @classmethod + def __remove_duplicate_edges(cls, edge_index: Tensor) -> Tensor: + """Remove duplicate edges from the edge index.""" + # Example: edge_index = [[0, 1, 2, 2, 0, 3, 2], + # [1, 0, 3, 2, 1, 2, 2]], shape (2, |E| = 7) + # -> after torch.unique(..., dim=1): + # edge_index = [[0, 1, 2, 2, 3], + # [1, 0, 3, 2, 2]], shape (2, |E'| = 5) + return torch.unique(edge_index, dim=1) diff --git a/hyperbench/utils/__init__.py b/hyperbench/utils/__init__.py index cbaaae4..7c9c09d 100644 --- a/hyperbench/utils/__init__.py +++ b/hyperbench/utils/__init__.py @@ -7,12 +7,11 @@ to_non_empty_edgeattr, ) from .graph_utils import ( - reduce_to_graph_edge_index, + reduce_to_graph_edge_index_on_random_direction, smoothing_with_gcn_laplacian_matrix, get_sparse_adjacency_matrix, get_sparse_normalized_degree_matrix, get_sparse_normalized_laplacian, - to_undirected_edge_index, ) from .hif_utils import validate_hif_json from .sparse_utils import sparse_dropout @@ -23,13 +22,12 @@ "empty_hdata", "empty_hifhypergraph", "empty_nodefeatures", - "reduce_to_graph_edge_index", + "reduce_to_graph_edge_index_on_random_direction", "smoothing_with_gcn_laplacian_matrix", "sparse_dropout", "get_sparse_adjacency_matrix", "get_sparse_normalized_degree_matrix", "get_sparse_normalized_laplacian", "to_non_empty_edgeattr", - "to_undirected_edge_index", "validate_hif_json", ] diff --git a/hyperbench/utils/graph_utils.py b/hyperbench/utils/graph_utils.py index 70ae9f4..1203790 100644 --- a/hyperbench/utils/graph_utils.py +++ b/hyperbench/utils/graph_utils.py @@ -14,11 +14,11 @@ def get_sparse_adjacency_matrix(edge_index: Tensor, num_nodes: int) -> Tensor: Args: - edge_index: Edge index tensor of shape (2, |E|). + edge_index: Edge index tensor of shape ``(2, |E|)``. num_nodes: The number of nodes in the graph. Returns: - The sparse adjacency matrix of shape (num_nodes, num_nodes). + The sparse adjacency matrix of shape ``(num_nodes, num_nodes)``. """ src, dest = edge_index @@ -43,6 +43,16 @@ def get_sparse_adjacency_matrix(edge_index: Tensor, num_nodes: int) -> Tensor: def get_sparse_normalized_degree_matrix(edge_index: Tensor, num_nodes: int) -> Tensor: + """ + Compute the sparse normalized degree matrix D^-1/2 from a graph edge index. + + Args: + edge_index: Edge index tensor of shape ``(2, |E|)``. + num_nodes: The number of nodes in the graph. + + Returns: + The sparse normalized degree matrix D^-1/2 of shape ``(num_nodes, num_nodes)``. + """ device = edge_index.device src, _ = edge_index @@ -92,14 +102,16 @@ def get_sparse_normalized_laplacian( where A_hat = A + I (adjacency with self-loops) and D_hat is the degree matrix of A_hat. Args: - edge_index: Edge index tensor of shape (2, |E|). + edge_index: Edge index tensor of shape ``(2, |E|)``. num_nodes: The number of nodes in the graph. If ``None``, it will be inferred from ``edge_index`` as ``edge_index.max().item() + 1`` Returns: - The sparse symmetrically normalized Laplacian matrix of shape (num_nodes, num_nodes). + The sparse symmetrically normalized Laplacian matrix of shape ``(num_nodes, num_nodes)``. """ - undirected_edge_index = to_undirected_edge_index(edge_index, with_selfloops=True) + undirected_edge_index = Graph.from_directed_to_undirected_edge_index( + edge_index=edge_index, with_selfloops=True + ) # num_nodes assumes that the node indices in edge_index are in the range [0, num_nodes-1], # as this is the default logic in the library dataset preprocessing. @@ -122,7 +134,7 @@ def get_sparse_normalized_laplacian( return normalized_laplacian_matrix.coalesce() -def reduce_to_graph_edge_index( +def reduce_to_graph_edge_index_on_random_direction( x: Tensor, edge_index: Tensor, with_mediators: bool = False, @@ -177,7 +189,7 @@ def reduce_to_graph_edge_index( graph = Graph(edges=graph_edges) if remove_selfloops: - graph.remove_self_loops() + graph.remove_selfloops() return graph.to_edge_index() @@ -201,45 +213,3 @@ def smoothing_with_gcn_laplacian_matrix( if drop_rate > 0.0: laplacian_matrix = sparse_dropout(laplacian_matrix, drop_rate) return laplacian_matrix.matmul(x) - - -def to_undirected_edge_index( - edge_index: Tensor, with_selfloops: bool = False -) -> Tensor: - """ - Convert a directed edge index to an undirected edge index by adding reverse edges. - - Args: - edge_index: Edge index tensor of shape (2, |E|). - with_selfloops: Whether to add self-loops to each node. Defaults to ``False``. - - Returns: - The undirected edge index tensor of shape (2, |E'|). If ``with_selfloops`` is ``True``, self-loops are added. - """ - src, dest = edge_index[0], edge_index[1] - src, dest = torch.cat([src, dest]), torch.cat([dest, src]) - - # Example: edge_index = [[0, 1, 2], - # [1, 0, 3]] - # -> after torch.stack([...], dim=0): - # undirected_edge_index = [[0, 1, 2, 1, 0, 3], - # [1, 0, 3, 0, 1, 2]] - # -> after torch.unique(..., dim=1): - # undirected_edge_index = [[0, 1, 2, 3], - # [1, 0, 3, 2]] - undirected_edge_index = torch.stack([src, dest], dim=0) - undirected_edge_index = torch.unique(undirected_edge_index, dim=1) - - if with_selfloops: - # num_nodes assumes that the node indices in edge_index are in the range [0, num_nodes-1], - # as this is the default logic in the library dataset preprocessing. - num_nodes = int(undirected_edge_index.max().item()) + 1 - src, dest = undirected_edge_index[0], undirected_edge_index[1] - - # Add self-loops: A_hat = A + I (works as we assume node indices are in [0, num_nodes-1]) - self_loop_indices = torch.arange(num_nodes, device=edge_index.device) - src = torch.cat([src, self_loop_indices]) - dest = torch.cat([dest, self_loop_indices]) - undirected_edge_index = torch.stack([src, dest], dim=0) - - return undirected_edge_index