attracting.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. """Attracting components."""
  2. import networkx as nx
  3. from networkx.utils.decorators import not_implemented_for
  4. __all__ = [
  5. "number_attracting_components",
  6. "attracting_components",
  7. "is_attracting_component",
  8. ]
  9. @not_implemented_for("undirected")
  10. def attracting_components(G):
  11. """Generates the attracting components in `G`.
  12. An attracting component in a directed graph `G` is a strongly connected
  13. component with the property that a random walker on the graph will never
  14. leave the component, once it enters the component.
  15. The nodes in attracting components can also be thought of as recurrent
  16. nodes. If a random walker enters the attractor containing the node, then
  17. the node will be visited infinitely often.
  18. To obtain induced subgraphs on each component use:
  19. ``(G.subgraph(c).copy() for c in attracting_components(G))``
  20. Parameters
  21. ----------
  22. G : DiGraph, MultiDiGraph
  23. The graph to be analyzed.
  24. Returns
  25. -------
  26. attractors : generator of sets
  27. A generator of sets of nodes, one for each attracting component of G.
  28. Raises
  29. ------
  30. NetworkXNotImplemented
  31. If the input graph is undirected.
  32. See Also
  33. --------
  34. number_attracting_components
  35. is_attracting_component
  36. """
  37. scc = list(nx.strongly_connected_components(G))
  38. cG = nx.condensation(G, scc)
  39. for n in cG:
  40. if cG.out_degree(n) == 0:
  41. yield scc[n]
  42. @not_implemented_for("undirected")
  43. def number_attracting_components(G):
  44. """Returns the number of attracting components in `G`.
  45. Parameters
  46. ----------
  47. G : DiGraph, MultiDiGraph
  48. The graph to be analyzed.
  49. Returns
  50. -------
  51. n : int
  52. The number of attracting components in G.
  53. Raises
  54. ------
  55. NetworkXNotImplemented
  56. If the input graph is undirected.
  57. See Also
  58. --------
  59. attracting_components
  60. is_attracting_component
  61. """
  62. return sum(1 for ac in attracting_components(G))
  63. @not_implemented_for("undirected")
  64. def is_attracting_component(G):
  65. """Returns True if `G` consists of a single attracting component.
  66. Parameters
  67. ----------
  68. G : DiGraph, MultiDiGraph
  69. The graph to be analyzed.
  70. Returns
  71. -------
  72. attracting : bool
  73. True if `G` has a single attracting component. Otherwise, False.
  74. Raises
  75. ------
  76. NetworkXNotImplemented
  77. If the input graph is undirected.
  78. See Also
  79. --------
  80. attracting_components
  81. number_attracting_components
  82. """
  83. ac = list(attracting_components(G))
  84. if len(ac) == 1:
  85. return len(ac[0]) == len(G)
  86. return False