connected.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. """Connected components."""
  2. import networkx as nx
  3. from networkx.utils.decorators import not_implemented_for
  4. from ...utils import arbitrary_element
  5. __all__ = [
  6. "number_connected_components",
  7. "connected_components",
  8. "is_connected",
  9. "node_connected_component",
  10. ]
  11. @not_implemented_for("directed")
  12. @nx._dispatchable
  13. def connected_components(G):
  14. """Generate connected components.
  15. The connected components of an undirected graph partition the graph into
  16. disjoint sets of nodes. Each of these sets induces a subgraph of graph
  17. `G` that is connected and not part of any larger connected subgraph.
  18. A graph is connected (:func:`is_connected`) if, for every pair of distinct
  19. nodes, there is a path between them. If there is a pair of nodes for
  20. which such path does not exist, the graph is not connected (also referred
  21. to as "disconnected").
  22. A graph consisting of a single node and no edges is connected.
  23. Connectivity is undefined for the null graph (graph with no nodes).
  24. Parameters
  25. ----------
  26. G : NetworkX graph
  27. An undirected graph
  28. Yields
  29. ------
  30. comp : set
  31. A set of nodes in one connected component of the graph.
  32. Raises
  33. ------
  34. NetworkXNotImplemented
  35. If G is directed.
  36. Examples
  37. --------
  38. Generate a sorted list of connected components, largest first.
  39. >>> G = nx.path_graph(4)
  40. >>> nx.add_path(G, [10, 11, 12])
  41. >>> [len(c) for c in sorted(nx.connected_components(G), key=len, reverse=True)]
  42. [4, 3]
  43. If you only want the largest connected component, it's more
  44. efficient to use max instead of sort.
  45. >>> largest_cc = max(nx.connected_components(G), key=len)
  46. To create the induced subgraph of each component use:
  47. >>> S = [G.subgraph(c).copy() for c in nx.connected_components(G)]
  48. See Also
  49. --------
  50. number_connected_components
  51. is_connected
  52. number_weakly_connected_components
  53. number_strongly_connected_components
  54. Notes
  55. -----
  56. This function is for undirected graphs only. For directed graphs, use
  57. :func:`strongly_connected_components` or
  58. :func:`weakly_connected_components`.
  59. The algorithm is based on a Breadth-First Search (BFS) traversal and its
  60. time complexity is $O(n + m)$, where $n$ is the number of nodes and $m$ the
  61. number of edges in the graph.
  62. """
  63. seen = set()
  64. n = len(G) # must be outside the loop to avoid performance hit with graph views
  65. for v in G:
  66. if v not in seen:
  67. c = _plain_bfs(G, n - len(seen), v)
  68. seen.update(c)
  69. yield c
  70. @not_implemented_for("directed")
  71. @nx._dispatchable
  72. def number_connected_components(G):
  73. """Returns the number of connected components.
  74. The connected components of an undirected graph partition the graph into
  75. disjoint sets of nodes. Each of these sets induces a subgraph of graph
  76. `G` that is connected and not part of any larger connected subgraph.
  77. A graph is connected (:func:`is_connected`) if, for every pair of distinct
  78. nodes, there is a path between them. If there is a pair of nodes for
  79. which such path does not exist, the graph is not connected (also referred
  80. to as "disconnected").
  81. A graph consisting of a single node and no edges is connected.
  82. Connectivity is undefined for the null graph (graph with no nodes).
  83. Parameters
  84. ----------
  85. G : NetworkX graph
  86. An undirected graph.
  87. Returns
  88. -------
  89. n : integer
  90. Number of connected components
  91. Raises
  92. ------
  93. NetworkXNotImplemented
  94. If G is directed.
  95. Examples
  96. --------
  97. >>> G = nx.Graph([(0, 1), (1, 2), (5, 6), (3, 4)])
  98. >>> nx.number_connected_components(G)
  99. 3
  100. See Also
  101. --------
  102. connected_components
  103. is_connected
  104. number_weakly_connected_components
  105. number_strongly_connected_components
  106. Notes
  107. -----
  108. This function is for undirected graphs only. For directed graphs, use
  109. :func:`number_strongly_connected_components` or
  110. :func:`number_weakly_connected_components`.
  111. The algorithm is based on a Breadth-First Search (BFS) traversal and its
  112. time complexity is $O(n + m)$, where $n$ is the number of nodes and $m$ the
  113. number of edges in the graph.
  114. """
  115. return sum(1 for _ in connected_components(G))
  116. @not_implemented_for("directed")
  117. @nx._dispatchable
  118. def is_connected(G):
  119. """Returns True if the graph is connected, False otherwise.
  120. A graph is connected if, for every pair of distinct nodes, there is a
  121. path between them. If there is a pair of nodes for which such path does
  122. not exist, the graph is not connected (also referred to as "disconnected").
  123. A graph consisting of a single node and no edges is connected.
  124. Connectivity is undefined for the null graph (graph with no nodes).
  125. Parameters
  126. ----------
  127. G : NetworkX Graph
  128. An undirected graph.
  129. Returns
  130. -------
  131. connected : bool
  132. True if the graph is connected, False otherwise.
  133. Raises
  134. ------
  135. NetworkXNotImplemented
  136. If G is directed.
  137. Examples
  138. --------
  139. >>> G = nx.path_graph(4)
  140. >>> print(nx.is_connected(G))
  141. True
  142. See Also
  143. --------
  144. is_strongly_connected
  145. is_weakly_connected
  146. is_semiconnected
  147. is_biconnected
  148. connected_components
  149. Notes
  150. -----
  151. This function is for undirected graphs only. For directed graphs, use
  152. :func:`is_strongly_connected` or :func:`is_weakly_connected`.
  153. The algorithm is based on a Breadth-First Search (BFS) traversal and its
  154. time complexity is $O(n + m)$, where $n$ is the number of nodes and $m$ the
  155. number of edges in the graph.
  156. """
  157. n = len(G)
  158. if n == 0:
  159. raise nx.NetworkXPointlessConcept(
  160. "Connectivity is undefined for the null graph."
  161. )
  162. return len(next(connected_components(G))) == n
  163. @not_implemented_for("directed")
  164. @nx._dispatchable
  165. def node_connected_component(G, n):
  166. """Returns the set of nodes in the component of graph containing node n.
  167. A connected component is a set of nodes that induces a subgraph of graph
  168. `G` that is connected and not part of any larger connected subgraph.
  169. A graph is connected (:func:`is_connected`) if, for every pair of distinct
  170. nodes, there is a path between them. If there is a pair of nodes for
  171. which such path does not exist, the graph is not connected (also referred
  172. to as "disconnected").
  173. A graph consisting of a single node and no edges is connected.
  174. Connectivity is undefined for the null graph (graph with no nodes).
  175. Parameters
  176. ----------
  177. G : NetworkX Graph
  178. An undirected graph.
  179. n : node label
  180. A node in G
  181. Returns
  182. -------
  183. comp : set
  184. A set of nodes in the component of G containing node n.
  185. Raises
  186. ------
  187. NetworkXNotImplemented
  188. If G is directed.
  189. Examples
  190. --------
  191. >>> G = nx.Graph([(0, 1), (1, 2), (5, 6), (3, 4)])
  192. >>> nx.node_connected_component(G, 0) # nodes of component that contains node 0
  193. {0, 1, 2}
  194. See Also
  195. --------
  196. connected_components
  197. Notes
  198. -----
  199. This function is for undirected graphs only.
  200. The algorithm is based on a Breadth-First Search (BFS) traversal and its
  201. time complexity is $O(n + m)$, where $n$ is the number of nodes and $m$ the
  202. number of edges in the graph.
  203. """
  204. return _plain_bfs(G, len(G), n)
  205. def _plain_bfs(G, n, source):
  206. """A fast BFS node generator"""
  207. adj = G._adj
  208. seen = {source}
  209. nextlevel = [source]
  210. while nextlevel:
  211. thislevel = nextlevel
  212. nextlevel = []
  213. for v in thislevel:
  214. for w in adj[v]:
  215. if w not in seen:
  216. seen.add(w)
  217. nextlevel.append(w)
  218. if len(seen) == n:
  219. return seen
  220. return seen