# -*- coding: utf-8 -*-
# Copyright (C) 2004-2019 by
# Aric Hagberg <hagberg@lanl.gov>
# Dan Schult <dschult@colgate.edu>
# Pieter Swart <swart@lanl.gov>
# All rights reserved.
# BSD license.
#
# Authors: Eben Kenah
# Aric Hagberg (hagberg@lanl.gov)
# Christopher Ellison
"""Connected components."""
import warnings as _warnings
import networkx as nx
from networkx.utils.decorators import not_implemented_for
from ...utils import arbitrary_element
__all__ = [
'number_connected_components',
'connected_components',
'connected_component_subgraphs',
'is_connected',
'node_connected_component',
]
[docs]@not_implemented_for('directed')
def connected_components(G):
"""Generate connected components.
Parameters
----------
G : NetworkX graph
An undirected graph
Returns
-------
comp : generator of sets
A generator of sets of nodes, one for each component of G.
Raises
------
NetworkXNotImplemented:
If G is directed.
Examples
--------
Generate a sorted list of connected components, largest first.
>>> G = nx.path_graph(4)
>>> nx.add_path(G, [10, 11, 12])
>>> [len(c) for c in sorted(nx.connected_components(G), key=len, reverse=True)]
[4, 3]
If you only want the largest connected component, it's more
efficient to use max instead of sort.
>>> largest_cc = max(nx.connected_components(G), key=len)
See Also
--------
strongly_connected_components
weakly_connected_components
Notes
-----
For undirected graphs only.
"""
seen = set()
for v in G:
if v not in seen:
c = set(_plain_bfs(G, v))
yield c
seen.update(c)
[docs]@not_implemented_for('directed')
def connected_component_subgraphs(G, copy=True):
"""DEPRECATED: Use ``(G.subgraph(c) for c in connected_components(G))``
Or ``(G.subgraph(c).copy() for c in connected_components(G))``
"""
msg = "connected_component_subgraphs is deprecated and will be removed" \
"in 2.2. Use (G.subgraph(c).copy() for c in connected_components(G))"
_warnings.warn(msg, DeprecationWarning)
for c in connected_components(G):
if copy:
yield G.subgraph(c).copy()
else:
yield G.subgraph(c)
[docs]def number_connected_components(G):
"""Returns the number of connected components.
Parameters
----------
G : NetworkX graph
An undirected graph.
Returns
-------
n : integer
Number of connected components
See Also
--------
connected_components
number_weakly_connected_components
number_strongly_connected_components
Notes
-----
For undirected graphs only.
"""
return sum(1 for cc in connected_components(G))
[docs]@not_implemented_for('directed')
def is_connected(G):
"""Returns True if the graph is connected, False otherwise.
Parameters
----------
G : NetworkX Graph
An undirected graph.
Returns
-------
connected : bool
True if the graph is connected, false otherwise.
Raises
------
NetworkXNotImplemented:
If G is directed.
Examples
--------
>>> G = nx.path_graph(4)
>>> print(nx.is_connected(G))
True
See Also
--------
is_strongly_connected
is_weakly_connected
is_semiconnected
is_biconnected
connected_components
Notes
-----
For undirected graphs only.
"""
if len(G) == 0:
raise nx.NetworkXPointlessConcept('Connectivity is undefined ',
'for the null graph.')
return sum(1 for node in _plain_bfs(G, arbitrary_element(G))) == len(G)
[docs]@not_implemented_for('directed')
def node_connected_component(G, n):
"""Returns the set of nodes in the component of graph containing node n.
Parameters
----------
G : NetworkX Graph
An undirected graph.
n : node label
A node in G
Returns
-------
comp : set
A set of nodes in the component of G containing node n.
Raises
------
NetworkXNotImplemented:
If G is directed.
See Also
--------
connected_components
Notes
-----
For undirected graphs only.
"""
return set(_plain_bfs(G, n))
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])