Skip to content

Commit 8386212

Browse files
committed
Merge branch 'Jonas-Verhellen-dnd-lifting'
2 parents a836af2 + a874954 commit 8386212

File tree

9 files changed

+987
-22
lines changed

9 files changed

+987
-22
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
transform_type: 'lifting'
2+
transform_name: "SimplicialDnDLifting"
3+
complex_dim: 6
4+
preserve_edge_attr: False
5+
signed: True
6+
feature_lifting: ProjectionSum

configs/transforms/liftings/graph2simplicial/eccentricity_lifting.yaml configs/transforms/liftings/graph2simplicial/eccentricity_lifting

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ transform_name: "SimplicialEccentricityLifting"
33
complex_dim: 3
44
preserve_edge_attr: False
55
signed: True
6-
feature_lifting: ProjectionSum
6+
feature_lifting: ProjectionSum

modules/transforms/data_transform.py

+4
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
from modules.transforms.liftings.graph2simplicial.clique_lifting import (
4545
SimplicialCliqueLifting,
4646
)
47+
from modules.transforms.liftings.graph2simplicial.dnd_lifting import (
48+
SimplicialDnDLifting,
49+
)
4750
from modules.transforms.liftings.graph2simplicial.eccentricity_lifting import (
4851
SimplicialEccentricityLifting,
4952
)
@@ -102,6 +105,7 @@
102105
"SimplicialLineLifting": SimplicialLineLifting,
103106
"SimplicialVietorisRipsLifting": SimplicialVietorisRipsLifting,
104107
"LatentCliqueLifting": LatentCliqueLifting,
108+
"SimplicialDnDLifting": SimplicialDnDLifting,
105109
# Graph -> Cell Complex
106110
"CellCycleLifting": CellCycleLifting,
107111
"DiscreteConfigurationComplexLifting": DiscreteConfigurationComplexLifting,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import random
2+
from itertools import combinations
3+
4+
import networkx as nx
5+
from toponetx.classes import SimplicialComplex
6+
from torch_geometric.data import Data
7+
8+
from modules.transforms.liftings.graph2simplicial.base import (
9+
Graph2SimplicialLifting,
10+
)
11+
12+
13+
class SimplicialDnDLifting(Graph2SimplicialLifting):
14+
r"""Lifts graphs to simplicial complex domain using a Dungeons & Dragons inspired system.
15+
16+
Parameters
17+
----------
18+
**kwargs : optional
19+
Additional arguments for the class.
20+
"""
21+
22+
def __init__(self, **kwargs):
23+
super().__init__(**kwargs)
24+
25+
def lift_topology(self, data: Data) -> dict:
26+
r"""Lifts the topology of a graph to a simplicial complex using Dungeons & Dragons (D&D) inspired mechanics.
27+
28+
Parameters
29+
----------
30+
data : Data
31+
The input data to be lifted.
32+
33+
Returns
34+
-------
35+
dict
36+
The lifted topology.
37+
"""
38+
graph = self._generate_graph_from_data(data)
39+
simplicial_complex = SimplicialComplex()
40+
41+
characters = self._assign_attributes(graph)
42+
simplices = [set() for _ in range(2, self.complex_dim + 1)]
43+
44+
for node in graph.nodes:
45+
simplicial_complex.add_node(node, features=data.x[node])
46+
47+
for node in graph.nodes:
48+
character = characters[node]
49+
for k in range(1, self.complex_dim):
50+
dice_roll = self._roll_dice(character, k)
51+
neighborhood = list(
52+
nx.single_source_shortest_path_length(
53+
graph, node, cutoff=dice_roll
54+
).keys()
55+
)
56+
for combination in combinations(neighborhood, k + 1):
57+
simplices[k - 1].add(tuple(sorted(combination)))
58+
59+
for set_k_simplices in simplices:
60+
simplicial_complex.add_simplices_from(list(set_k_simplices))
61+
62+
return self._get_lifted_topology(simplicial_complex, graph)
63+
64+
def _assign_attributes(self, graph):
65+
"""Assign D&D-inspired attributes based on node properties."""
66+
degrees = nx.degree_centrality(graph)
67+
clustering = nx.clustering(graph)
68+
closeness = nx.closeness_centrality(graph)
69+
eigenvector = nx.eigenvector_centrality(graph)
70+
betweenness = nx.betweenness_centrality(graph)
71+
pagerank = nx.pagerank(graph)
72+
73+
attributes = {}
74+
for node in graph.nodes:
75+
attributes[node] = {
76+
"Degree": degrees[node],
77+
"Clustering": clustering[node],
78+
"Closeness": closeness[node],
79+
"Eigenvector": eigenvector[node],
80+
"Betweenness": betweenness[node],
81+
"Pagerank": pagerank[node],
82+
}
83+
return attributes
84+
85+
def _roll_dice(self, attributes, k):
86+
"""Simulate a D20 dice roll influenced by node attributes where a different attribute is used based on the simplex level."""
87+
88+
attribute = None
89+
if k == 1:
90+
attribute = attributes["Degree"]
91+
elif k == 2:
92+
attribute = attributes["Clustering"]
93+
elif k == 3:
94+
attribute = attributes["Closeness"]
95+
elif k == 4:
96+
attribute = attributes["Eigenvector"]
97+
elif k == 5:
98+
attribute = attributes["Betweenness"]
99+
else:
100+
attribute = attributes["Pagerank"]
101+
102+
base_roll = random.randint(1, 20)
103+
modifier = int(attribute * 20)
104+
return base_roll + modifier

modules/transforms/liftings/graph2simplicial/eccentricity_lifting.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ def lift_topology(self, data: torch_geometric.data.Data) -> dict:
4444

4545
for node, ecc in eccentricities.items():
4646
neighborhood = list(
47-
nx.single_source_shortest_path_length(graph, node, cutoff=ecc).keys()
47+
nx.single_source_shortest_path_length(
48+
graph, node, cutoff=ecc
49+
).keys()
4850
)
4951
for k in range(1, self.complex_dim):
5052
for combination in combinations(neighborhood, k + 1):

0 commit comments

Comments
 (0)