Source code for hypergraphx.utils.labeling

from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Iterable, List, Sequence, Tuple

import numpy as np


[docs] @dataclass class LabelEncoder: """ Minimal drop-in replacement for sklearn's LabelEncoder, used throughout HypergraphX to map arbitrary node labels to dense integer ids. This exists to avoid forcing scikit-learn as a hard dependency. """ classes_: List[Any] | None = None _to_int: dict[Any, int] | None = None
[docs] def fit(self, y: Sequence[Any]) -> "LabelEncoder": # Keep first-seen order to preserve a stable mapping based on the input. classes: List[Any] = [] to_int: dict[Any, int] = {} for item in y: if item in to_int: continue to_int[item] = len(classes) classes.append(item) self.classes_ = classes self._to_int = to_int return self
[docs] def transform(self, y: Iterable[Any]) -> np.ndarray: if self._to_int is None: raise ValueError("LabelEncoder is not fitted. Call fit() first.") return np.array([self._to_int[item] for item in y], dtype=int)
[docs] def inverse_transform(self, y: Iterable[int]) -> np.ndarray: if self.classes_ is None: raise ValueError("LabelEncoder is not fitted. Call fit() first.") classes = self.classes_ return np.array([classes[int(i)] for i in y], dtype=object)
def _stable_label_sort_key(value: Any) -> tuple[str, str]: return (type(value).__name__, repr(value))
[docs] def fit_node_encoder(nodes: Iterable[Any]) -> LabelEncoder: """ Fit a LabelEncoder on a deterministic node order. Nodes are sorted by type name and repr() so the mapping is stable even when the underlying node iteration order is not. """ return LabelEncoder().fit(sorted(nodes, key=_stable_label_sort_key))
[docs] def relabel_edge(mapping: LabelEncoder, edge: Tuple): """ Relabel an edge using a mapping. Parameters ---------- mapping: LabelEncoder The mapping to use edge: Tuple The edge to relabel Returns ------- Tuple The relabeled edge """ return tuple(mapping.transform(edge))
[docs] def relabel_edges(mapping: LabelEncoder, edges: List[Tuple]): """ Relabel a list of edges using a mapping. Parameters ---------- mapping: LabelEncoder The mapping to use edges: List[Tuple] The edges to relabel Returns ------- List[Tuple] The relabeled edges """ return [relabel_edge(mapping, edge) for edge in edges]
[docs] def inverse_relabel_edge(mapping: LabelEncoder, edge: Tuple): """ Revert edge relabeling using a mapping. Parameters ---------- mapping: LabelEncoder The mapping to use edge: Tuple The edge to relabel Returns ------- Tuple The relabeled edge """ return tuple(mapping.inverse_transform(edge))
[docs] def inverse_relabel_edges(mapping: LabelEncoder, edges: List[Tuple]): """ Revert edges relabeling using a mapping. Parameters ---------- mapping: LabelEncoder The mapping to use edges: List[Tuple] The edges to relabel Returns ------- List[Tuple] The relabeled edges """ return [inverse_relabel_edge(mapping, edge) for edge in edges]
[docs] def map_node(mapping: LabelEncoder, node): """ Map a node using a mapping. Parameters ---------- mapping: LabelEncoder The mapping to use node: Any The node to map Returns ------- Any The mapped node """ return mapping.transform([node])[0]
[docs] def map_nodes(mapping: LabelEncoder, nodes: List): """ Map a list of nodes using a mapping. Parameters ---------- mapping: LabelEncoder The mapping to use nodes: List The nodes to map Returns ------- List The mapped nodes """ return mapping.transform(nodes)
[docs] def inverse_map_nodes(mapping: LabelEncoder, nodes: List): """ Revert node mapping using a mapping. Parameters ---------- mapping: LabelEncoder The mapping to use nodes: List The nodes to map Returns ------- List The mapped nodes """ return mapping.inverse_transform(nodes)
[docs] def get_inverse_mapping(mapping: LabelEncoder): """ Get the inverse mapping of a LabelEncoder. Parameters ---------- mapping: LabelEncoder The mapping to invert Returns ------- dict The inverse mapping """ if mapping.classes_ is None: raise ValueError("LabelEncoder is not fitted. Call fit() first.") return {i: node for i, node in enumerate(mapping.classes_)}
[docs] def relabel_edges_with_mapping(edges: List[Tuple], mapping: dict): """ Relabel edges using a dictionary mapping old labels to new labels. Parameters ---------- edges: List[Tuple] The edges to relabel mapping: dict Mapping from old labels to new labels Returns ------- List[Tuple] The relabeled edges """ res = [] for edge in edges: new_edge = [mapping[v] for v in edge] res.append(tuple(sorted(new_edge))) return sorted(res)