Skip to content

Commit 7dec533

Browse files
committed
Stabilize node mapping encoder order
1 parent 35331cb commit 7dec533

File tree

4 files changed

+30
-2
lines changed

4 files changed

+30
-2
lines changed

hypergraphx/core/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ def expose_attributes_for_hashing(self):
7878
}
7979

8080
def get_mapping(self):
81-
from hypergraphx.utils.labeling import LabelEncoder
81+
from hypergraphx.utils.labeling import fit_node_encoder
8282

83-
return LabelEncoder().fit(self.get_nodes())
83+
return fit_node_encoder(self.get_nodes())
8484

8585

8686
class BaseHypergraph(SerializationMixin):

hypergraphx/utils/labeling.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@ def inverse_transform(self, y: Iterable[int]) -> np.ndarray:
4343
return np.array([classes[int(i)] for i in y], dtype=object)
4444

4545

46+
def _stable_label_sort_key(value: Any) -> tuple[str, str]:
47+
return (type(value).__name__, repr(value))
48+
49+
50+
def fit_node_encoder(nodes: Iterable[Any]) -> LabelEncoder:
51+
"""
52+
Fit a LabelEncoder on a deterministic node order.
53+
54+
Nodes are sorted by type name and repr() so the mapping is stable even when
55+
the underlying node iteration order is not.
56+
"""
57+
return LabelEncoder().fit(sorted(nodes, key=_stable_label_sort_key))
58+
59+
4660
def relabel_edge(mapping: LabelEncoder, edge: Tuple):
4761
"""
4862
Relabel an edge using a mapping.

tests/core/hypergraphs/test_hypergraphs.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,13 @@ def test_get_mapping_roundtrip():
746746
assert set(encoder.inverse_transform(mapped)) == set(hg.get_nodes())
747747

748748

749+
def test_get_mapping_uses_deterministic_sorted_node_order():
750+
hg = Hypergraph(edge_list=[("b", "a"), ("c", "b")])
751+
encoder = hg.get_mapping()
752+
753+
assert list(encoder.classes_) == ["a", "b", "c"]
754+
755+
749756
def test_remove_node_keep_edges_updates_edges():
750757
hg = Hypergraph(weighted=True)
751758
hg.add_edge((1, 2, 3), weight=2.0, metadata={"kind": "tri"})

tests/utils/test_labeling.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
relabel_edges,
66
inverse_relabel_edge,
77
inverse_relabel_edges,
8+
fit_node_encoder,
89
map_node,
910
map_nodes,
1011
inverse_map_nodes,
@@ -58,3 +59,9 @@ def test_get_inverse_mapping():
5859

5960
assert inv[0] == "a"
6061
assert inv[2] == "c"
62+
63+
64+
def test_fit_node_encoder_sorts_deterministically():
65+
enc = fit_node_encoder(["b", "a", "c"])
66+
67+
assert list(enc.classes_) == ["a", "b", "c"]

0 commit comments

Comments
 (0)