6b7e6b44f1
gh-pages / build (push) Waiting to run
Python Publish (pypi) / Upload release to PyPI (push) Waiting to run
Spellcheck / spellcheck (push) Waiting to run
Python Build and Type Check / python-ci (ubuntu-latest, 3.11) (push) Has been cancelled
Python Build and Type Check / python-ci (ubuntu-latest, 3.13) (push) Has been cancelled
Python Build and Type Check / python-ci (windows-latest, 3.11) (push) Has been cancelled
Python Build and Type Check / python-ci (windows-latest, 3.13) (push) Has been cancelled
Python Integration Tests / python-ci (ubuntu-latest, 3.13) (push) Has been cancelled
Python Integration Tests / python-ci (windows-latest, 3.13) (push) Has been cancelled
Python Notebook Tests / python-ci (ubuntu-latest, 3.13) (push) Has been cancelled
Python Notebook Tests / python-ci (windows-latest, 3.13) (push) Has been cancelled
Python Smoke Tests / python-ci (ubuntu-latest, 3.13) (push) Has been cancelled
Python Smoke Tests / python-ci (windows-latest, 3.13) (push) Has been cancelled
Python Unit Tests / python-ci (ubuntu-latest, 3.13) (push) Has been cancelled
Python Unit Tests / python-ci (windows-latest, 3.13) (push) Has been cancelled
67 lines
2.2 KiB
Python
67 lines
2.2 KiB
Python
# Copyright (c) 2024 Microsoft Corporation.
|
|
# Licensed under the MIT License
|
|
|
|
"""NetworkX-based stable LCC utility, kept for side-by-side test comparisons.
|
|
|
|
This was originally at graphrag.index.utils.stable_lcc and has been moved here
|
|
because production code no longer uses it (superseded by the DataFrame-based
|
|
graphrag.graphs.stable_lcc).
|
|
"""
|
|
|
|
import html
|
|
from typing import Any, cast
|
|
|
|
import networkx as nx
|
|
|
|
|
|
def _largest_connected_component(graph: nx.Graph) -> nx.Graph:
|
|
"""Return the largest connected component of the graph (NX-based)."""
|
|
graph = graph.copy()
|
|
lcc_nodes = max(nx.connected_components(graph), key=len)
|
|
return graph.subgraph(lcc_nodes).copy()
|
|
|
|
|
|
def stable_largest_connected_component(graph: nx.Graph) -> nx.Graph:
|
|
"""Return the largest connected component of the graph, with nodes and edges sorted in a stable way."""
|
|
graph = graph.copy()
|
|
graph = cast("nx.Graph", _largest_connected_component(graph))
|
|
graph = normalize_node_names(graph)
|
|
return _stabilize_graph(graph)
|
|
|
|
|
|
def _stabilize_graph(graph: nx.Graph) -> nx.Graph:
|
|
"""Ensure an undirected graph with the same relationships will always be read the same way."""
|
|
fixed_graph = nx.DiGraph() if graph.is_directed() else nx.Graph()
|
|
|
|
sorted_nodes = graph.nodes(data=True)
|
|
sorted_nodes = sorted(sorted_nodes, key=lambda x: x[0])
|
|
|
|
fixed_graph.add_nodes_from(sorted_nodes)
|
|
edges = list(graph.edges(data=True))
|
|
|
|
if not graph.is_directed():
|
|
|
|
def _sort_source_target(edge):
|
|
source, target, edge_data = edge
|
|
if source > target:
|
|
temp = source
|
|
source = target
|
|
target = temp
|
|
return source, target, edge_data
|
|
|
|
edges = [_sort_source_target(edge) for edge in edges]
|
|
|
|
def _get_edge_key(source: Any, target: Any) -> str:
|
|
return f"{source} -> {target}"
|
|
|
|
edges = sorted(edges, key=lambda x: _get_edge_key(x[0], x[1]))
|
|
|
|
fixed_graph.add_edges_from(edges)
|
|
return fixed_graph
|
|
|
|
|
|
def normalize_node_names(graph: nx.Graph | nx.DiGraph) -> nx.Graph | nx.DiGraph:
|
|
"""Normalize node names."""
|
|
node_mapping = {node: html.unescape(node.upper().strip()) for node in graph.nodes()} # type: ignore
|
|
return nx.relabel_nodes(graph, node_mapping)
|