test_bridges.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. """Unit tests for bridge-finding algorithms."""
  2. import pytest
  3. import networkx as nx
  4. class TestBridges:
  5. """Unit tests for the bridge-finding function."""
  6. def test_single_bridge(self):
  7. edges = [
  8. # DFS tree edges.
  9. (1, 2),
  10. (2, 3),
  11. (3, 4),
  12. (3, 5),
  13. (5, 6),
  14. (6, 7),
  15. (7, 8),
  16. (5, 9),
  17. (9, 10),
  18. # Nontree edges.
  19. (1, 3),
  20. (1, 4),
  21. (2, 5),
  22. (5, 10),
  23. (6, 8),
  24. ]
  25. G = nx.Graph(edges)
  26. source = 1
  27. bridges = list(nx.bridges(G, source))
  28. assert bridges == [(5, 6)]
  29. def test_barbell_graph(self):
  30. # The (3, 0) barbell graph has two triangles joined by a single edge.
  31. G = nx.barbell_graph(3, 0)
  32. source = 0
  33. bridges = list(nx.bridges(G, source))
  34. assert bridges == [(2, 3)]
  35. def test_multiedge_bridge(self):
  36. edges = [
  37. (0, 1),
  38. (0, 2),
  39. (1, 2),
  40. (1, 2),
  41. (2, 3),
  42. (3, 4),
  43. (3, 4),
  44. ]
  45. G = nx.MultiGraph(edges)
  46. assert list(nx.bridges(G)) == [(2, 3)]
  47. class TestHasBridges:
  48. """Unit tests for the has bridges function."""
  49. def test_single_bridge(self):
  50. edges = [
  51. # DFS tree edges.
  52. (1, 2),
  53. (2, 3),
  54. (3, 4),
  55. (3, 5),
  56. (5, 6), # The only bridge edge
  57. (6, 7),
  58. (7, 8),
  59. (5, 9),
  60. (9, 10),
  61. # Nontree edges.
  62. (1, 3),
  63. (1, 4),
  64. (2, 5),
  65. (5, 10),
  66. (6, 8),
  67. ]
  68. G = nx.Graph(edges)
  69. assert nx.has_bridges(G) # Default root
  70. assert nx.has_bridges(G, root=1) # arbitrary root in G
  71. def test_has_bridges_raises_root_not_in_G(self):
  72. G = nx.Graph()
  73. G.add_nodes_from([1, 2, 3])
  74. with pytest.raises(nx.NodeNotFound):
  75. nx.has_bridges(G, root=6)
  76. def test_multiedge_bridge(self):
  77. edges = [
  78. (0, 1),
  79. (0, 2),
  80. (1, 2),
  81. (1, 2),
  82. (2, 3),
  83. (3, 4),
  84. (3, 4),
  85. ]
  86. G = nx.MultiGraph(edges)
  87. assert nx.has_bridges(G)
  88. # Make every edge a multiedge
  89. G.add_edges_from([(0, 1), (0, 2), (2, 3)])
  90. assert not nx.has_bridges(G)
  91. def test_bridges_multiple_components(self):
  92. G = nx.Graph()
  93. nx.add_path(G, [0, 1, 2]) # One connected component
  94. nx.add_path(G, [4, 5, 6]) # Another connected component
  95. assert list(nx.bridges(G, root=4)) == [(4, 5), (5, 6)]
  96. class TestLocalBridges:
  97. """Unit tests for the local_bridge function."""
  98. @classmethod
  99. def setup_class(cls):
  100. cls.BB = nx.barbell_graph(4, 0)
  101. cls.square = nx.cycle_graph(4)
  102. cls.tri = nx.cycle_graph(3)
  103. def test_nospan(self):
  104. expected = {(3, 4), (4, 3)}
  105. assert next(nx.local_bridges(self.BB, with_span=False)) in expected
  106. assert set(nx.local_bridges(self.square, with_span=False)) == self.square.edges
  107. assert list(nx.local_bridges(self.tri, with_span=False)) == []
  108. def test_no_weight(self):
  109. inf = float("inf")
  110. expected = {(3, 4, inf), (4, 3, inf)}
  111. assert next(nx.local_bridges(self.BB)) in expected
  112. expected = {(u, v, 3) for u, v, in self.square.edges}
  113. assert set(nx.local_bridges(self.square)) == expected
  114. assert list(nx.local_bridges(self.tri)) == []
  115. def test_weight(self):
  116. inf = float("inf")
  117. G = self.square.copy()
  118. G.edges[1, 2]["weight"] = 2
  119. expected = {(u, v, 5 - wt) for u, v, wt in G.edges(data="weight", default=1)}
  120. assert set(nx.local_bridges(G, weight="weight")) == expected
  121. expected = {(u, v, 6) for u, v in G.edges}
  122. lb = nx.local_bridges(G, weight=lambda u, v, d: 2)
  123. assert set(lb) == expected