test_line.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. import pytest
  2. import networkx as nx
  3. from networkx.generators import line
  4. from networkx.utils import edges_equal
  5. class TestGeneratorLine:
  6. def test_star(self):
  7. G = nx.star_graph(5)
  8. L = nx.line_graph(G)
  9. assert nx.is_isomorphic(L, nx.complete_graph(5))
  10. def test_path(self):
  11. G = nx.path_graph(5)
  12. L = nx.line_graph(G)
  13. assert nx.is_isomorphic(L, nx.path_graph(4))
  14. def test_cycle(self):
  15. G = nx.cycle_graph(5)
  16. L = nx.line_graph(G)
  17. assert nx.is_isomorphic(L, G)
  18. def test_digraph1(self):
  19. G = nx.DiGraph([(0, 1), (0, 2), (0, 3)])
  20. L = nx.line_graph(G)
  21. # no edge graph, but with nodes
  22. assert L.adj == {(0, 1): {}, (0, 2): {}, (0, 3): {}}
  23. def test_multigraph1(self):
  24. G = nx.MultiGraph([(0, 1), (0, 1), (1, 0), (0, 2), (2, 0), (0, 3)])
  25. L = nx.line_graph(G)
  26. # no edge graph, but with nodes
  27. assert edges_equal(
  28. L.edges(),
  29. [
  30. ((0, 3, 0), (0, 1, 0)),
  31. ((0, 3, 0), (0, 2, 0)),
  32. ((0, 3, 0), (0, 2, 1)),
  33. ((0, 3, 0), (0, 1, 1)),
  34. ((0, 3, 0), (0, 1, 2)),
  35. ((0, 1, 0), (0, 1, 1)),
  36. ((0, 1, 0), (0, 2, 0)),
  37. ((0, 1, 0), (0, 1, 2)),
  38. ((0, 1, 0), (0, 2, 1)),
  39. ((0, 1, 1), (0, 1, 2)),
  40. ((0, 1, 1), (0, 2, 0)),
  41. ((0, 1, 1), (0, 2, 1)),
  42. ((0, 1, 2), (0, 2, 0)),
  43. ((0, 1, 2), (0, 2, 1)),
  44. ((0, 2, 0), (0, 2, 1)),
  45. ],
  46. )
  47. def test_multigraph2(self):
  48. G = nx.MultiGraph([(1, 2), (2, 1)])
  49. L = nx.line_graph(G)
  50. assert edges_equal(L.edges(), [((1, 2, 0), (1, 2, 1))])
  51. def test_multidigraph1(self):
  52. G = nx.MultiDiGraph([(1, 2), (2, 1)])
  53. L = nx.line_graph(G)
  54. assert edges_equal(L.edges(), [((1, 2, 0), (2, 1, 0)), ((2, 1, 0), (1, 2, 0))])
  55. def test_multidigraph2(self):
  56. G = nx.MultiDiGraph([(0, 1), (0, 1), (0, 1), (1, 2)])
  57. L = nx.line_graph(G)
  58. assert edges_equal(
  59. L.edges(),
  60. [((0, 1, 0), (1, 2, 0)), ((0, 1, 1), (1, 2, 0)), ((0, 1, 2), (1, 2, 0))],
  61. )
  62. def test_digraph2(self):
  63. G = nx.DiGraph([(0, 1), (1, 2), (2, 3)])
  64. L = nx.line_graph(G)
  65. assert edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))])
  66. def test_create1(self):
  67. G = nx.DiGraph([(0, 1), (1, 2), (2, 3)])
  68. L = nx.line_graph(G, create_using=nx.Graph())
  69. assert edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))])
  70. def test_create2(self):
  71. G = nx.Graph([(0, 1), (1, 2), (2, 3)])
  72. L = nx.line_graph(G, create_using=nx.DiGraph())
  73. assert edges_equal(L.edges(), [((0, 1), (1, 2)), ((1, 2), (2, 3))])
  74. class TestGeneratorInverseLine:
  75. def test_example(self):
  76. G = nx.Graph()
  77. G_edges = [
  78. [1, 2],
  79. [1, 3],
  80. [1, 4],
  81. [1, 5],
  82. [2, 3],
  83. [2, 5],
  84. [2, 6],
  85. [2, 7],
  86. [3, 4],
  87. [3, 5],
  88. [6, 7],
  89. [6, 8],
  90. [7, 8],
  91. ]
  92. G.add_edges_from(G_edges)
  93. H = nx.inverse_line_graph(G)
  94. solution = nx.Graph()
  95. solution_edges = [
  96. ("a", "b"),
  97. ("a", "c"),
  98. ("a", "d"),
  99. ("a", "e"),
  100. ("c", "d"),
  101. ("e", "f"),
  102. ("e", "g"),
  103. ("f", "g"),
  104. ]
  105. solution.add_edges_from(solution_edges)
  106. assert nx.is_isomorphic(H, solution)
  107. def test_example_2(self):
  108. G = nx.Graph()
  109. G_edges = [[1, 2], [1, 3], [2, 3], [3, 4], [3, 5], [4, 5]]
  110. G.add_edges_from(G_edges)
  111. H = nx.inverse_line_graph(G)
  112. solution = nx.Graph()
  113. solution_edges = [("a", "c"), ("b", "c"), ("c", "d"), ("d", "e"), ("d", "f")]
  114. solution.add_edges_from(solution_edges)
  115. assert nx.is_isomorphic(H, solution)
  116. def test_pair(self):
  117. G = nx.path_graph(2)
  118. H = nx.inverse_line_graph(G)
  119. solution = nx.path_graph(3)
  120. assert nx.is_isomorphic(H, solution)
  121. def test_line(self):
  122. G = nx.path_graph(5)
  123. solution = nx.path_graph(6)
  124. H = nx.inverse_line_graph(G)
  125. assert nx.is_isomorphic(H, solution)
  126. def test_triangle_graph(self):
  127. G = nx.complete_graph(3)
  128. H = nx.inverse_line_graph(G)
  129. alternative_solution = nx.Graph()
  130. alternative_solution.add_edges_from([[0, 1], [0, 2], [0, 3]])
  131. # there are two alternative inverse line graphs for this case
  132. # so long as we get one of them the test should pass
  133. assert nx.is_isomorphic(H, G) or nx.is_isomorphic(H, alternative_solution)
  134. def test_cycle(self):
  135. G = nx.cycle_graph(5)
  136. H = nx.inverse_line_graph(G)
  137. assert nx.is_isomorphic(H, G)
  138. def test_empty(self):
  139. G = nx.Graph()
  140. H = nx.inverse_line_graph(G)
  141. assert nx.is_isomorphic(H, nx.complete_graph(1))
  142. def test_K1(self):
  143. G = nx.complete_graph(1)
  144. H = nx.inverse_line_graph(G)
  145. solution = nx.path_graph(2)
  146. assert nx.is_isomorphic(H, solution)
  147. def test_edgeless_graph(self):
  148. G = nx.empty_graph(5)
  149. with pytest.raises(nx.NetworkXError, match="edgeless graph"):
  150. nx.inverse_line_graph(G)
  151. def test_selfloops_error(self):
  152. G = nx.cycle_graph(4)
  153. G.add_edge(0, 0)
  154. pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
  155. def test_non_line_graphs(self):
  156. # Tests several known non-line graphs for impossibility
  157. # Adapted from L.W.Beineke, "Characterizations of derived graphs"
  158. # claw graph
  159. claw = nx.star_graph(3)
  160. pytest.raises(nx.NetworkXError, nx.inverse_line_graph, claw)
  161. # wheel graph with 6 nodes
  162. wheel = nx.wheel_graph(6)
  163. pytest.raises(nx.NetworkXError, nx.inverse_line_graph, wheel)
  164. # K5 with one edge remove
  165. K5m = nx.complete_graph(5)
  166. K5m.remove_edge(0, 1)
  167. pytest.raises(nx.NetworkXError, nx.inverse_line_graph, K5m)
  168. # graph without any odd triangles (contains claw as induced subgraph)
  169. G = nx.compose(nx.path_graph(2), nx.complete_bipartite_graph(2, 3))
  170. pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
  171. ## Variations on a diamond graph
  172. # Diamond + 2 edges (+ "roof")
  173. G = nx.diamond_graph()
  174. G.add_edges_from([(4, 0), (5, 3)])
  175. pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
  176. G.add_edge(4, 5)
  177. pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
  178. # Diamond + 2 connected edges
  179. G = nx.diamond_graph()
  180. G.add_edges_from([(4, 0), (4, 3)])
  181. pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
  182. # Diamond + K3 + one edge (+ 2*K3)
  183. G = nx.diamond_graph()
  184. G.add_edges_from([(4, 0), (4, 1), (4, 2), (5, 3)])
  185. pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
  186. G.add_edges_from([(5, 1), (5, 2)])
  187. pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
  188. # 4 triangles
  189. G = nx.diamond_graph()
  190. G.add_edges_from([(4, 0), (4, 1), (5, 2), (5, 3)])
  191. pytest.raises(nx.NetworkXError, nx.inverse_line_graph, G)
  192. def test_wrong_graph_type(self):
  193. G = nx.DiGraph()
  194. G_edges = [[0, 1], [0, 2], [0, 3]]
  195. G.add_edges_from(G_edges)
  196. pytest.raises(nx.NetworkXNotImplemented, nx.inverse_line_graph, G)
  197. G = nx.MultiGraph()
  198. G_edges = [[0, 1], [0, 2], [0, 3]]
  199. G.add_edges_from(G_edges)
  200. pytest.raises(nx.NetworkXNotImplemented, nx.inverse_line_graph, G)
  201. def test_line_inverse_line_complete(self):
  202. G = nx.complete_graph(10)
  203. H = nx.line_graph(G)
  204. J = nx.inverse_line_graph(H)
  205. assert nx.is_isomorphic(G, J)
  206. def test_line_inverse_line_path(self):
  207. G = nx.path_graph(10)
  208. H = nx.line_graph(G)
  209. J = nx.inverse_line_graph(H)
  210. assert nx.is_isomorphic(G, J)
  211. def test_line_inverse_line_hypercube(self):
  212. G = nx.hypercube_graph(5)
  213. H = nx.line_graph(G)
  214. J = nx.inverse_line_graph(H)
  215. assert nx.is_isomorphic(G, J)
  216. def test_line_inverse_line_cycle(self):
  217. G = nx.cycle_graph(10)
  218. H = nx.line_graph(G)
  219. J = nx.inverse_line_graph(H)
  220. assert nx.is_isomorphic(G, J)
  221. def test_line_inverse_line_star(self):
  222. G = nx.star_graph(20)
  223. H = nx.line_graph(G)
  224. J = nx.inverse_line_graph(H)
  225. assert nx.is_isomorphic(G, J)
  226. def test_line_inverse_line_multipartite(self):
  227. G = nx.complete_multipartite_graph(3, 4, 5)
  228. H = nx.line_graph(G)
  229. J = nx.inverse_line_graph(H)
  230. assert nx.is_isomorphic(G, J)
  231. def test_line_inverse_line_dgm(self):
  232. G = nx.dorogovtsev_goltsev_mendes_graph(4)
  233. H = nx.line_graph(G)
  234. J = nx.inverse_line_graph(H)
  235. assert nx.is_isomorphic(G, J)
  236. def test_line_different_node_types(self):
  237. G = nx.path_graph([1, 2, 3, "a", "b", "c"])
  238. H = nx.line_graph(G)
  239. J = nx.inverse_line_graph(H)
  240. assert nx.is_isomorphic(G, J)
  241. class TestGeneratorPrivateFunctions:
  242. def test_triangles_error(self):
  243. G = nx.diamond_graph()
  244. pytest.raises(nx.NetworkXError, line._triangles, G, (4, 0))
  245. pytest.raises(nx.NetworkXError, line._triangles, G, (0, 3))
  246. def test_odd_triangles_error(self):
  247. G = nx.diamond_graph()
  248. pytest.raises(nx.NetworkXError, line._odd_triangle, G, (0, 1, 4))
  249. pytest.raises(nx.NetworkXError, line._odd_triangle, G, (0, 1, 3))
  250. def test_select_starting_cell_error(self):
  251. G = nx.diamond_graph()
  252. pytest.raises(nx.NetworkXError, line._select_starting_cell, G, (4, 0))
  253. pytest.raises(nx.NetworkXError, line._select_starting_cell, G, (0, 3))
  254. def test_diamond_graph(self):
  255. G = nx.diamond_graph()
  256. for edge in G.edges:
  257. cell = line._select_starting_cell(G, starting_edge=edge)
  258. # Starting cell should always be one of the two triangles
  259. assert len(cell) == 3
  260. assert all(v in G[u] for u in cell for v in cell if u != v)