hybrid.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. """
  2. Provides functions for finding and testing for locally `(k, l)`-connected
  3. graphs.
  4. """
  5. import copy
  6. import networkx as nx
  7. __all__ = ["kl_connected_subgraph", "is_kl_connected"]
  8. def kl_connected_subgraph(G, k, l, low_memory=False, same_as_graph=False):
  9. """Returns the maximum locally `(k, l)`-connected subgraph of `G`.
  10. A graph is locally `(k, l)`-connected if for each edge `(u, v)` in the
  11. graph there are at least `l` edge-disjoint paths of length at most `k`
  12. joining `u` to `v`.
  13. Parameters
  14. ----------
  15. G : NetworkX graph
  16. The graph in which to find a maximum locally `(k, l)`-connected
  17. subgraph.
  18. k : integer
  19. The maximum length of paths to consider. A higher number means a looser
  20. connectivity requirement.
  21. l : integer
  22. The number of edge-disjoint paths. A higher number means a stricter
  23. connectivity requirement.
  24. low_memory : bool
  25. If this is True, this function uses an algorithm that uses slightly
  26. more time but less memory.
  27. same_as_graph : bool
  28. If True then return a tuple of the form `(H, is_same)`,
  29. where `H` is the maximum locally `(k, l)`-connected subgraph and
  30. `is_same` is a Boolean representing whether `G` is locally `(k,
  31. l)`-connected (and hence, whether `H` is simply a copy of the input
  32. graph `G`).
  33. Returns
  34. -------
  35. NetworkX graph or two-tuple
  36. If `same_as_graph` is True, then this function returns a
  37. two-tuple as described above. Otherwise, it returns only the maximum
  38. locally `(k, l)`-connected subgraph.
  39. See also
  40. --------
  41. is_kl_connected
  42. References
  43. ----------
  44. .. [1] Chung, Fan and Linyuan Lu. "The Small World Phenomenon in Hybrid
  45. Power Law Graphs." *Complex Networks*. Springer Berlin Heidelberg,
  46. 2004. 89--104.
  47. """
  48. H = copy.deepcopy(G) # subgraph we construct by removing from G
  49. graphOK = True
  50. deleted_some = True # hack to start off the while loop
  51. while deleted_some:
  52. deleted_some = False
  53. # We use `for edge in list(H.edges()):` instead of
  54. # `for edge in H.edges():` because we edit the graph `H` in
  55. # the loop. Hence using an iterator will result in
  56. # `RuntimeError: dictionary changed size during iteration`
  57. for edge in list(H.edges()):
  58. (u, v) = edge
  59. # Get copy of graph needed for this search
  60. if low_memory:
  61. verts = {u, v}
  62. for i in range(k):
  63. for w in verts.copy():
  64. verts.update(G[w])
  65. G2 = G.subgraph(verts).copy()
  66. else:
  67. G2 = copy.deepcopy(G)
  68. ###
  69. path = [u, v]
  70. cnt = 0
  71. accept = 0
  72. while path:
  73. cnt += 1 # Found a path
  74. if cnt >= l:
  75. accept = 1
  76. break
  77. # record edges along this graph
  78. prev = u
  79. for w in path:
  80. if prev != w:
  81. G2.remove_edge(prev, w)
  82. prev = w
  83. # path = shortest_path(G2, u, v, k) # ??? should "Cutoff" be k+1?
  84. try:
  85. path = nx.shortest_path(G2, u, v) # ??? should "Cutoff" be k+1?
  86. except nx.NetworkXNoPath:
  87. path = False
  88. # No Other Paths
  89. if accept == 0:
  90. H.remove_edge(u, v)
  91. deleted_some = True
  92. if graphOK:
  93. graphOK = False
  94. # We looked through all edges and removed none of them.
  95. # So, H is the maximal (k,l)-connected subgraph of G
  96. if same_as_graph:
  97. return (H, graphOK)
  98. return H
  99. def is_kl_connected(G, k, l, low_memory=False):
  100. """Returns True if and only if `G` is locally `(k, l)`-connected.
  101. A graph is locally `(k, l)`-connected if for each edge `(u, v)` in the
  102. graph there are at least `l` edge-disjoint paths of length at most `k`
  103. joining `u` to `v`.
  104. Parameters
  105. ----------
  106. G : NetworkX graph
  107. The graph to test for local `(k, l)`-connectedness.
  108. k : integer
  109. The maximum length of paths to consider. A higher number means a looser
  110. connectivity requirement.
  111. l : integer
  112. The number of edge-disjoint paths. A higher number means a stricter
  113. connectivity requirement.
  114. low_memory : bool
  115. If this is True, this function uses an algorithm that uses slightly
  116. more time but less memory.
  117. Returns
  118. -------
  119. bool
  120. Whether the graph is locally `(k, l)`-connected subgraph.
  121. See also
  122. --------
  123. kl_connected_subgraph
  124. References
  125. ----------
  126. .. [1] Chung, Fan and Linyuan Lu. "The Small World Phenomenon in Hybrid
  127. Power Law Graphs." *Complex Networks*. Springer Berlin Heidelberg,
  128. 2004. 89--104.
  129. """
  130. graphOK = True
  131. for edge in G.edges():
  132. (u, v) = edge
  133. # Get copy of graph needed for this search
  134. if low_memory:
  135. verts = {u, v}
  136. for i in range(k):
  137. [verts.update(G.neighbors(w)) for w in verts.copy()]
  138. G2 = G.subgraph(verts)
  139. else:
  140. G2 = copy.deepcopy(G)
  141. ###
  142. path = [u, v]
  143. cnt = 0
  144. accept = 0
  145. while path:
  146. cnt += 1 # Found a path
  147. if cnt >= l:
  148. accept = 1
  149. break
  150. # record edges along this graph
  151. prev = u
  152. for w in path:
  153. if w != prev:
  154. G2.remove_edge(prev, w)
  155. prev = w
  156. # path = shortest_path(G2, u, v, k) # ??? should "Cutoff" be k+1?
  157. try:
  158. path = nx.shortest_path(G2, u, v) # ??? should "Cutoff" be k+1?
  159. except nx.NetworkXNoPath:
  160. path = False
  161. # No Other Paths
  162. if accept == 0:
  163. graphOK = False
  164. break
  165. # return status
  166. return graphOK