Skip to content

Commit c360f9d

Browse files
FIX: Tests
1 parent c10936a commit c360f9d

File tree

3 files changed

+54
-46
lines changed

3 files changed

+54
-46
lines changed

modules/transforms/liftings/graph2simplicial/neighborhood_complex_lifting.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ def lift_topology(self, data: Data) -> dict:
4949
i: f for i, f in enumerate(data["x"])
5050
}
5151

52-
5352
simplicial_complex.set_simplex_attributes(feature_dict, name="features")
5453

5554
return self._get_lifted_topology(simplicial_complex, graph)
5655

5756
def _get_lifted_topology(self, simplicial_complex: SimplicialComplex, graph: nx.Graph) -> dict:
5857
data = super()._get_lifted_topology(simplicial_complex, graph)
5958

60-
for r in range(simplicial_complex.dim):
59+
60+
for r in range(simplicial_complex.dim+1):
6161
data[f"x_idx_{r}"] = torch.tensor(simplicial_complex.skeleton(r))
6262

6363
return data

test/transforms/liftings/graph2simplicial/test_neighborhood_complex_lifting.py

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import networkx as nx
22
import torch
3+
from typing import Tuple, Set, List
34
from torch_geometric.utils.convert import from_networkx
45

56
from modules.data.utils.utils import load_manual_graph
@@ -18,51 +19,72 @@ def setup_method(self):
1819
# Initialize the NeighborhoodComplexLifting class for dim=3
1920
self.lifting_signed = NeighborhoodComplexLifting(complex_dim=3, signed=True)
2021
self.lifting_unsigned = NeighborhoodComplexLifting(complex_dim=3, signed=False)
22+
self.lifting_high = NeighborhoodComplexLifting(complex_dim=7, signed=False)
2123

2224
# Intialize an empty graph for testing purpouses
2325
self.empty_graph = nx.empty_graph(10)
2426
self.empty_data = from_networkx(self.empty_graph)
2527
self.empty_data["x"] = torch.rand((10, 10))
2628

29+
# Intialize a start graph for testing
30+
self.star_graph = nx.star_graph(5)
31+
self.star_data = from_networkx(self.star_graph)
32+
self.star_data["x"] = torch.rand((6, 1))
33+
2734
# Intialize a random graph for testing purpouses
28-
self.random_graph = nx.fast_gnp_random_graph(10, 0.5)
35+
self.random_graph = nx.fast_gnp_random_graph(5, 0.5)
2936
self.random_data = from_networkx(self.random_graph)
30-
self.random_data["x"] = torch.rand((10, 10))
37+
self.random_data["x"] = torch.rand((5, 1))
38+
39+
40+
def has_neighbour(self, simplex_points: List[Set]) -> Tuple[bool, Set[int]]:
41+
""" Verifies that the maximal simplices
42+
of Data representation of a simplicial complex
43+
share a neighbour.
44+
"""
45+
for simplex_point_a in simplex_points:
46+
for simplex_point_b in simplex_points:
47+
# Same point
48+
if simplex_point_a == simplex_point_b:
49+
continue
50+
# Search all nodes to check if they are c such that a and b share c as a neighbour
51+
for node in self.random_graph.nodes:
52+
# They share a neighbour
53+
if self.random_graph.has_edge(simplex_point_a.item(), node) and self.random_graph.has_edge(simplex_point_b.item(), node):
54+
return True
55+
return False
3156

3257
def test_lift_topology_random_graph(self):
3358
""" Verifies that the lifting procedure works on
34-
random graphs, that is, checks that the simplices
59+
a random graph, that is, checks that the simplices
3560
generated share a neighbour.
3661
"""
37-
lifted_data = self.lifting_unsigned.forward(self.random_data)
62+
lifted_data = self.lifting_high.forward(self.random_data)
3863
# For each set of simplices
39-
for r in range(1, self.lifting_unsigned.complex_dim):
40-
idx_str = f"x_idx_{r}"
64+
r = max(int(key.split('_')[-1]) for key in list(lifted_data.keys()) if 'x_idx_' in key)
65+
idx_str = f"x_idx_{r}"
66+
67+
# Go over each (max_dim)-simplex
68+
for simplex_points in lifted_data[idx_str]:
69+
share_neighbour = self.has_neighbour(simplex_points)
70+
assert share_neighbour, f"The simplex {simplex_points} does not have a common neighbour with all the nodes."
71+
72+
def test_lift_topology_star_graph(self):
73+
""" Verifies that the lifting procedure works on
74+
a small star graph, that is, checks that the simplices
75+
generated share a neighbour.
76+
"""
77+
lifted_data = self.lifting_high.forward(self.star_data)
78+
# For each set of simplices
79+
r = max(int(key.split('_')[-1]) for key in list(lifted_data.keys()) if 'x_idx_' in key)
80+
idx_str = f"x_idx_{r}"
81+
82+
# Go over each (max_dim)-simplex
83+
for simplex_points in lifted_data[idx_str]:
84+
share_neighbour = self.has_neighbour(simplex_points)
85+
assert share_neighbour, f"The simplex {simplex_points} does not have a common neighbour with all the nodes."
4186

42-
# Found maximum dimension
43-
if idx_str not in lifted_data:
44-
break
4587

46-
# Iterate over the composing nodes of each simplex
47-
for simplex_points in lifted_data[idx_str]:
48-
share_neighbour = True
49-
# For each node in the graph
50-
for node in self.random_graph.nodes:
51-
# Not checking the nodes themselves
52-
if node in simplex_points:
53-
continue
54-
share_neighbour = True
55-
# For each node in the simplex
56-
for simplex_point in simplex_points:
57-
# If the node does not have a common neighbour
58-
if not self.random_graph.has_edge(node, simplex_point):
59-
share_neighbour = False
60-
break
61-
# There is at least 1 node that has a common neighbour
62-
# with the nodes in the simplex
63-
if share_neighbour:
64-
break
65-
assert share_neighbour, f"The simplex {simplex_points} does not have a common neighbour with all the nodes."
6688

6789
def test_lift_topology_empty_graph(self):
6890
""" Test the lift_topology method with an empty graph.

tutorials/graph2simplicial/neighborhood_complex_lifting.ipynb

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -189,21 +189,7 @@
189189
"In this section we instantiate the lifting technique. For this particular case we are using the *neighbourhood complex* lifting. Given a graph $G = (V, E)$ we denote the vertex of $G$ as $V(G)$. Then the *neighbourhood complex* (a simplicial complex) $N(G)$ has as vertex the set $V(G)$ and as simplices the subsets of $V(G)$ that have a common neighbour.\n",
190190
"Consequently, this lifts a graph to a simplicial complex of rank $k$ where the is the maximum amount of nodes with which it shares a neighbour. This definition follow from [[1]](https://www.sciencedirect.com/science/article/pii/0097316578900225). \n",
191191
"\n",
192-
"The maximum rank $r$ of the simplicial complex (denoting the simplex with highest cardinality) will be of the highest neighbourhood which will in turn, given the definition of a simplex include all of it's subsets as simples. Say, given a simplex $\\sigma$, then $\\forall \\tau \\prec \\sigma$ \n",
193-
"\n",
194-
"$$\n",
195-
"\\exists v,u \\in \\tau : v \\neq u \\; \\wedge \\; \\exists w: (v, w) \\in E(G) \\wedge (u, w) \\in E(G)\n",
196-
"$$\n",
197-
"\n",
198-
"The proof that this holds is simple. Given any simplex in $N(G)$ denoted by\n",
199-
" \n",
200-
"$$\n",
201-
"\\sigma_v = \\{u \\; | \\; \\exists w: (v, w) \\in E(G) \\wedge (u, w) \\in E(G)\\} \\cup \\{v\\}\n",
202-
"$$\n",
203-
"\n",
204-
"Take any subset $S$ of the combinatorial representation of $\\sigma_v$ with $|S| > 1$. By the above definition, we know that if we take any arbitrairy $u', v' \\in S$ then there is at least one $w'$ such that $(u', w') \\in E(G)$ and $(v', w') \\in E(G)$. This follows from the fact that the choice of $v$ is arbitraty, so if $x$ shares a neighbour with $y$ and $z$ then $y$ shares a neighbour with $z$.\n",
205-
"\n",
206-
"The algorithm to compute this will inspect all nodes, all of it's neighbours and then check which nodes share this neighbours. This naive implementation's complexity is $\\mathcal{O}(|V|^3)$, where the worst case is for complete graphs.\n",
192+
"The maximum rank $r$ of the simplicial complex (denoting the simplex with highest cardinality) will be of the highest neighbourhood. The algorithm to compute this will inspect all nodes, all of it's neighbours and then check which nodes share this neighbours. This naive implementation's complexity is $\\mathcal{O}(|V|^3)$, where the worst case is for complete graphs.\n",
207193
"\n",
208194
"\n",
209195
"Note that we can set the parameter `complex_dim` as high as we like to limit the size of the neighbourhood that is taken into account since for well connected graphs this will explode exponentially for the number of simplices created. \n",

0 commit comments

Comments
 (0)