weakly_connected.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. """Weakly connected components."""
  2. import networkx as nx
  3. from networkx.utils.decorators import not_implemented_for
  4. __all__ = [
  5. "number_weakly_connected_components",
  6. "weakly_connected_components",
  7. "is_weakly_connected",
  8. ]
  9. @nx._dispatch
  10. @not_implemented_for("undirected")
  11. def weakly_connected_components(G):
  12. """Generate weakly connected components of G.
  13. Parameters
  14. ----------
  15. G : NetworkX graph
  16. A directed graph
  17. Returns
  18. -------
  19. comp : generator of sets
  20. A generator of sets of nodes, one for each weakly connected
  21. component of G.
  22. Raises
  23. ------
  24. NetworkXNotImplemented
  25. If G is undirected.
  26. Examples
  27. --------
  28. Generate a sorted list of weakly connected components, largest first.
  29. >>> G = nx.path_graph(4, create_using=nx.DiGraph())
  30. >>> nx.add_path(G, [10, 11, 12])
  31. >>> [
  32. ... len(c)
  33. ... for c in sorted(nx.weakly_connected_components(G), key=len, reverse=True)
  34. ... ]
  35. [4, 3]
  36. If you only want the largest component, it's more efficient to
  37. use max instead of sort:
  38. >>> largest_cc = max(nx.weakly_connected_components(G), key=len)
  39. See Also
  40. --------
  41. connected_components
  42. strongly_connected_components
  43. Notes
  44. -----
  45. For directed graphs only.
  46. """
  47. seen = set()
  48. for v in G:
  49. if v not in seen:
  50. c = set(_plain_bfs(G, v))
  51. seen.update(c)
  52. yield c
  53. @not_implemented_for("undirected")
  54. def number_weakly_connected_components(G):
  55. """Returns the number of weakly connected components in G.
  56. Parameters
  57. ----------
  58. G : NetworkX graph
  59. A directed graph.
  60. Returns
  61. -------
  62. n : integer
  63. Number of weakly connected components
  64. Raises
  65. ------
  66. NetworkXNotImplemented
  67. If G is undirected.
  68. Examples
  69. --------
  70. >>> G = nx.DiGraph([(0, 1), (2, 1), (3, 4)])
  71. >>> nx.number_weakly_connected_components(G)
  72. 2
  73. See Also
  74. --------
  75. weakly_connected_components
  76. number_connected_components
  77. number_strongly_connected_components
  78. Notes
  79. -----
  80. For directed graphs only.
  81. """
  82. return sum(1 for wcc in weakly_connected_components(G))
  83. @nx._dispatch
  84. @not_implemented_for("undirected")
  85. def is_weakly_connected(G):
  86. """Test directed graph for weak connectivity.
  87. A directed graph is weakly connected if and only if the graph
  88. is connected when the direction of the edge between nodes is ignored.
  89. Note that if a graph is strongly connected (i.e. the graph is connected
  90. even when we account for directionality), it is by definition weakly
  91. connected as well.
  92. Parameters
  93. ----------
  94. G : NetworkX Graph
  95. A directed graph.
  96. Returns
  97. -------
  98. connected : bool
  99. True if the graph is weakly connected, False otherwise.
  100. Raises
  101. ------
  102. NetworkXNotImplemented
  103. If G is undirected.
  104. Examples
  105. --------
  106. >>> G = nx.DiGraph([(0, 1), (2, 1)])
  107. >>> G.add_node(3)
  108. >>> nx.is_weakly_connected(G) # node 3 is not connected to the graph
  109. False
  110. >>> G.add_edge(2, 3)
  111. >>> nx.is_weakly_connected(G)
  112. True
  113. See Also
  114. --------
  115. is_strongly_connected
  116. is_semiconnected
  117. is_connected
  118. is_biconnected
  119. weakly_connected_components
  120. Notes
  121. -----
  122. For directed graphs only.
  123. """
  124. if len(G) == 0:
  125. raise nx.NetworkXPointlessConcept(
  126. """Connectivity is undefined for the null graph."""
  127. )
  128. return len(next(weakly_connected_components(G))) == len(G)
  129. def _plain_bfs(G, source):
  130. """A fast BFS node generator
  131. The direction of the edge between nodes is ignored.
  132. For directed graphs only.
  133. """
  134. Gsucc = G.succ
  135. Gpred = G.pred
  136. seen = set()
  137. nextlevel = {source}
  138. while nextlevel:
  139. thislevel = nextlevel
  140. nextlevel = set()
  141. for v in thislevel:
  142. if v not in seen:
  143. seen.add(v)
  144. nextlevel.update(Gsucc[v])
  145. nextlevel.update(Gpred[v])
  146. yield v