test_dominance.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. import pytest
  2. import networkx as nx
  3. class TestImmediateDominators:
  4. def test_exceptions(self):
  5. G = nx.Graph()
  6. G.add_node(0)
  7. pytest.raises(nx.NetworkXNotImplemented, nx.immediate_dominators, G, 0)
  8. G = nx.MultiGraph(G)
  9. pytest.raises(nx.NetworkXNotImplemented, nx.immediate_dominators, G, 0)
  10. G = nx.DiGraph([[0, 0]])
  11. pytest.raises(nx.NetworkXError, nx.immediate_dominators, G, 1)
  12. def test_singleton(self):
  13. G = nx.DiGraph()
  14. G.add_node(0)
  15. assert nx.immediate_dominators(G, 0) == {0: 0}
  16. G.add_edge(0, 0)
  17. assert nx.immediate_dominators(G, 0) == {0: 0}
  18. def test_path(self):
  19. n = 5
  20. G = nx.path_graph(n, create_using=nx.DiGraph())
  21. assert nx.immediate_dominators(G, 0) == {i: max(i - 1, 0) for i in range(n)}
  22. def test_cycle(self):
  23. n = 5
  24. G = nx.cycle_graph(n, create_using=nx.DiGraph())
  25. assert nx.immediate_dominators(G, 0) == {i: max(i - 1, 0) for i in range(n)}
  26. def test_unreachable(self):
  27. n = 5
  28. assert n > 1
  29. G = nx.path_graph(n, create_using=nx.DiGraph())
  30. assert nx.immediate_dominators(G, n // 2) == {
  31. i: max(i - 1, n // 2) for i in range(n // 2, n)
  32. }
  33. def test_irreducible1(self):
  34. # Graph taken from Figure 2 of
  35. # K. D. Cooper, T. J. Harvey, and K. Kennedy.
  36. # A simple, fast dominance algorithm.
  37. # Software Practice & Experience, 4:110, 2001.
  38. edges = [(1, 2), (2, 1), (3, 2), (4, 1), (5, 3), (5, 4)]
  39. G = nx.DiGraph(edges)
  40. assert nx.immediate_dominators(G, 5) == {i: 5 for i in range(1, 6)}
  41. def test_irreducible2(self):
  42. # Graph taken from Figure 4 of
  43. # K. D. Cooper, T. J. Harvey, and K. Kennedy.
  44. # A simple, fast dominance algorithm.
  45. # Software Practice & Experience, 4:110, 2001.
  46. edges = [(1, 2), (2, 1), (2, 3), (3, 2), (4, 2), (4, 3), (5, 1), (6, 4), (6, 5)]
  47. G = nx.DiGraph(edges)
  48. result = nx.immediate_dominators(G, 6)
  49. assert result == {i: 6 for i in range(1, 7)}
  50. def test_domrel_png(self):
  51. # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png
  52. edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)]
  53. G = nx.DiGraph(edges)
  54. result = nx.immediate_dominators(G, 1)
  55. assert result == {1: 1, 2: 1, 3: 2, 4: 2, 5: 2, 6: 2}
  56. # Test postdominance.
  57. result = nx.immediate_dominators(G.reverse(copy=False), 6)
  58. assert result == {1: 2, 2: 6, 3: 5, 4: 5, 5: 2, 6: 6}
  59. def test_boost_example(self):
  60. # Graph taken from Figure 1 of
  61. # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm
  62. edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6), (5, 7), (6, 4)]
  63. G = nx.DiGraph(edges)
  64. result = nx.immediate_dominators(G, 0)
  65. assert result == {0: 0, 1: 0, 2: 1, 3: 1, 4: 3, 5: 4, 6: 4, 7: 1}
  66. # Test postdominance.
  67. result = nx.immediate_dominators(G.reverse(copy=False), 7)
  68. assert result == {0: 1, 1: 7, 2: 7, 3: 4, 4: 5, 5: 7, 6: 4, 7: 7}
  69. class TestDominanceFrontiers:
  70. def test_exceptions(self):
  71. G = nx.Graph()
  72. G.add_node(0)
  73. pytest.raises(nx.NetworkXNotImplemented, nx.dominance_frontiers, G, 0)
  74. G = nx.MultiGraph(G)
  75. pytest.raises(nx.NetworkXNotImplemented, nx.dominance_frontiers, G, 0)
  76. G = nx.DiGraph([[0, 0]])
  77. pytest.raises(nx.NetworkXError, nx.dominance_frontiers, G, 1)
  78. def test_singleton(self):
  79. G = nx.DiGraph()
  80. G.add_node(0)
  81. assert nx.dominance_frontiers(G, 0) == {0: set()}
  82. G.add_edge(0, 0)
  83. assert nx.dominance_frontiers(G, 0) == {0: set()}
  84. def test_path(self):
  85. n = 5
  86. G = nx.path_graph(n, create_using=nx.DiGraph())
  87. assert nx.dominance_frontiers(G, 0) == {i: set() for i in range(n)}
  88. def test_cycle(self):
  89. n = 5
  90. G = nx.cycle_graph(n, create_using=nx.DiGraph())
  91. assert nx.dominance_frontiers(G, 0) == {i: set() for i in range(n)}
  92. def test_unreachable(self):
  93. n = 5
  94. assert n > 1
  95. G = nx.path_graph(n, create_using=nx.DiGraph())
  96. assert nx.dominance_frontiers(G, n // 2) == {i: set() for i in range(n // 2, n)}
  97. def test_irreducible1(self):
  98. # Graph taken from Figure 2 of
  99. # K. D. Cooper, T. J. Harvey, and K. Kennedy.
  100. # A simple, fast dominance algorithm.
  101. # Software Practice & Experience, 4:110, 2001.
  102. edges = [(1, 2), (2, 1), (3, 2), (4, 1), (5, 3), (5, 4)]
  103. G = nx.DiGraph(edges)
  104. assert dict(nx.dominance_frontiers(G, 5).items()) == {
  105. 1: {2},
  106. 2: {1},
  107. 3: {2},
  108. 4: {1},
  109. 5: set(),
  110. }
  111. def test_irreducible2(self):
  112. # Graph taken from Figure 4 of
  113. # K. D. Cooper, T. J. Harvey, and K. Kennedy.
  114. # A simple, fast dominance algorithm.
  115. # Software Practice & Experience, 4:110, 2001.
  116. edges = [(1, 2), (2, 1), (2, 3), (3, 2), (4, 2), (4, 3), (5, 1), (6, 4), (6, 5)]
  117. G = nx.DiGraph(edges)
  118. assert nx.dominance_frontiers(G, 6) == {
  119. 1: {2},
  120. 2: {1, 3},
  121. 3: {2},
  122. 4: {2, 3},
  123. 5: {1},
  124. 6: set(),
  125. }
  126. def test_domrel_png(self):
  127. # Graph taken from https://commons.wikipedia.org/wiki/File:Domrel.png
  128. edges = [(1, 2), (2, 3), (2, 4), (2, 6), (3, 5), (4, 5), (5, 2)]
  129. G = nx.DiGraph(edges)
  130. assert nx.dominance_frontiers(G, 1) == {
  131. 1: set(),
  132. 2: {2},
  133. 3: {5},
  134. 4: {5},
  135. 5: {2},
  136. 6: set(),
  137. }
  138. # Test postdominance.
  139. result = nx.dominance_frontiers(G.reverse(copy=False), 6)
  140. assert result == {1: set(), 2: {2}, 3: {2}, 4: {2}, 5: {2}, 6: set()}
  141. def test_boost_example(self):
  142. # Graph taken from Figure 1 of
  143. # http://www.boost.org/doc/libs/1_56_0/libs/graph/doc/lengauer_tarjan_dominator.htm
  144. edges = [(0, 1), (1, 2), (1, 3), (2, 7), (3, 4), (4, 5), (4, 6), (5, 7), (6, 4)]
  145. G = nx.DiGraph(edges)
  146. assert nx.dominance_frontiers(G, 0) == {
  147. 0: set(),
  148. 1: set(),
  149. 2: {7},
  150. 3: {7},
  151. 4: {4, 7},
  152. 5: {7},
  153. 6: {4},
  154. 7: set(),
  155. }
  156. # Test postdominance.
  157. result = nx.dominance_frontiers(G.reverse(copy=False), 7)
  158. expected = {
  159. 0: set(),
  160. 1: set(),
  161. 2: {1},
  162. 3: {1},
  163. 4: {1, 4},
  164. 5: {1},
  165. 6: {4},
  166. 7: set(),
  167. }
  168. assert result == expected
  169. def test_discard_issue(self):
  170. # https://github.com/networkx/networkx/issues/2071
  171. g = nx.DiGraph()
  172. g.add_edges_from(
  173. [
  174. ("b0", "b1"),
  175. ("b1", "b2"),
  176. ("b2", "b3"),
  177. ("b3", "b1"),
  178. ("b1", "b5"),
  179. ("b5", "b6"),
  180. ("b5", "b8"),
  181. ("b6", "b7"),
  182. ("b8", "b7"),
  183. ("b7", "b3"),
  184. ("b3", "b4"),
  185. ]
  186. )
  187. df = nx.dominance_frontiers(g, "b0")
  188. assert df == {
  189. "b4": set(),
  190. "b5": {"b3"},
  191. "b6": {"b7"},
  192. "b7": {"b3"},
  193. "b0": set(),
  194. "b1": {"b1"},
  195. "b2": {"b3"},
  196. "b3": {"b1"},
  197. "b8": {"b7"},
  198. }
  199. def test_loop(self):
  200. g = nx.DiGraph()
  201. g.add_edges_from([("a", "b"), ("b", "c"), ("b", "a")])
  202. df = nx.dominance_frontiers(g, "a")
  203. assert df == {"a": set(), "b": set(), "c": set()}
  204. def test_missing_immediate_doms(self):
  205. # see https://github.com/networkx/networkx/issues/2070
  206. g = nx.DiGraph()
  207. edges = [
  208. ("entry_1", "b1"),
  209. ("b1", "b2"),
  210. ("b2", "b3"),
  211. ("b3", "exit"),
  212. ("entry_2", "b3"),
  213. ]
  214. # entry_1
  215. # |
  216. # b1
  217. # |
  218. # b2 entry_2
  219. # | /
  220. # b3
  221. # |
  222. # exit
  223. g.add_edges_from(edges)
  224. # formerly raised KeyError on entry_2 when parsing b3
  225. # because entry_2 does not have immediate doms (no path)
  226. nx.dominance_frontiers(g, "entry_1")
  227. def test_loops_larger(self):
  228. # from
  229. # http://ecee.colorado.edu/~waite/Darmstadt/motion.html
  230. g = nx.DiGraph()
  231. edges = [
  232. ("entry", "exit"),
  233. ("entry", "1"),
  234. ("1", "2"),
  235. ("2", "3"),
  236. ("3", "4"),
  237. ("4", "5"),
  238. ("5", "6"),
  239. ("6", "exit"),
  240. ("6", "2"),
  241. ("5", "3"),
  242. ("4", "4"),
  243. ]
  244. g.add_edges_from(edges)
  245. df = nx.dominance_frontiers(g, "entry")
  246. answer = {
  247. "entry": set(),
  248. "1": {"exit"},
  249. "2": {"exit", "2"},
  250. "3": {"exit", "3", "2"},
  251. "4": {"exit", "4", "3", "2"},
  252. "5": {"exit", "3", "2"},
  253. "6": {"exit", "2"},
  254. "exit": set(),
  255. }
  256. for n in df:
  257. assert set(df[n]) == set(answer[n])