161 lines
3.5 KiB
Python
161 lines
3.5 KiB
Python
from easygraph.utils.decorators import *
|
|
|
|
|
|
__all__ = [
|
|
"is_connected",
|
|
"number_connected_components",
|
|
"connected_components",
|
|
"connected_components_directed",
|
|
"connected_component_of_node",
|
|
]
|
|
|
|
|
|
@not_implemented_for("multigraph")
|
|
def is_connected(G):
|
|
"""Returns whether the graph is connected or not.
|
|
|
|
Parameters
|
|
----------
|
|
G : easygraph.Graph or easygraph.DiGraph
|
|
|
|
Returns
|
|
-------
|
|
is_biconnected : boolean
|
|
`True` if the graph is connected.
|
|
|
|
Examples
|
|
--------
|
|
|
|
>>> is_connected(G)
|
|
|
|
"""
|
|
assert len(G) != 0, "No node in the graph."
|
|
arbitrary_node = next(iter(G)) # Pick an arbitrary node to run BFS
|
|
return len(G) == sum(1 for node in _plain_bfs(G, arbitrary_node))
|
|
|
|
|
|
@not_implemented_for("multigraph")
|
|
def number_connected_components(G):
|
|
"""Returns the number of connected components.
|
|
|
|
Parameters
|
|
----------
|
|
G : easygraph.Graph
|
|
|
|
Returns
|
|
-------
|
|
number_connected_components : int
|
|
The number of connected components.
|
|
|
|
Examples
|
|
--------
|
|
>>> number_connected_components(G)
|
|
|
|
"""
|
|
return sum(1 for component in _generator_connected_components(G))
|
|
|
|
|
|
@not_implemented_for("multigraph")
|
|
@hybrid("cpp_connected_components_undirected")
|
|
def connected_components(G):
|
|
"""Returns a list of connected components, each of which denotes the edges set of a connected component.
|
|
|
|
Parameters
|
|
----------
|
|
G : easygraph.Graph
|
|
Returns
|
|
-------
|
|
connected_components : list of list
|
|
Each element list is the edges set of a connected component.
|
|
|
|
Examples
|
|
--------
|
|
>>> connected_components(G)
|
|
|
|
"""
|
|
seen = set()
|
|
for v in G:
|
|
if v not in seen:
|
|
c = set(_plain_bfs(G, v))
|
|
seen.update(c)
|
|
yield c
|
|
|
|
|
|
@not_implemented_for("multigraph")
|
|
@hybrid("cpp_connected_components_directed")
|
|
def connected_components_directed(G):
|
|
"""Returns a list of connected components, each of which denotes the edges set of a connected component.
|
|
|
|
Parameters
|
|
----------
|
|
G : easygraph.DiGraph
|
|
Returns
|
|
-------
|
|
connected_components : list of list
|
|
Each element list is the edges set of a connected component.
|
|
|
|
Examples
|
|
--------
|
|
>>> connected_components(G)
|
|
|
|
"""
|
|
seen = set()
|
|
for v in G:
|
|
if v not in seen:
|
|
c = set(_plain_bfs(G, v))
|
|
seen.update(c)
|
|
yield c
|
|
|
|
|
|
def _generator_connected_components(G):
|
|
seen = set()
|
|
for v in G:
|
|
if v not in seen:
|
|
component = set(_plain_bfs(G, v))
|
|
yield component
|
|
seen.update(component)
|
|
|
|
|
|
@not_implemented_for("multigraph")
|
|
def connected_component_of_node(G, node):
|
|
"""Returns the connected component that *node* belongs to.
|
|
|
|
Parameters
|
|
----------
|
|
G : easygraph.Graph
|
|
|
|
node : object
|
|
The target node
|
|
|
|
Returns
|
|
-------
|
|
connected_component_of_node : set
|
|
The connected component that *node* belongs to.
|
|
|
|
Examples
|
|
--------
|
|
Returns the connected component of one node `Jack`.
|
|
|
|
>>> connected_component_of_node(G, node='Jack')
|
|
|
|
"""
|
|
return set(_plain_bfs(G, node))
|
|
|
|
|
|
@hybrid("cpp_plain_bfs")
|
|
def _plain_bfs(G, source):
|
|
"""
|
|
A fast BFS node generator
|
|
"""
|
|
G_adj = G.adj
|
|
seen = set()
|
|
nextlevel = {source}
|
|
while nextlevel:
|
|
thislevel = nextlevel
|
|
nextlevel = set()
|
|
for v in thislevel:
|
|
if v not in seen:
|
|
yield v
|
|
seen.add(v)
|
|
nextlevel.update(G_adj[v])
|