test_clique.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. import pytest
  2. import networkx as nx
  3. from networkx import convert_node_labels_to_integers as cnlti
  4. class TestCliques:
  5. def setup_method(self):
  6. z = [3, 4, 3, 4, 2, 4, 2, 1, 1, 1, 1]
  7. self.G = cnlti(nx.generators.havel_hakimi_graph(z), first_label=1)
  8. self.cl = list(nx.find_cliques(self.G))
  9. H = nx.complete_graph(6)
  10. H = nx.relabel_nodes(H, {i: i + 1 for i in range(6)})
  11. H.remove_edges_from([(2, 6), (2, 5), (2, 4), (1, 3), (5, 3)])
  12. self.H = H
  13. def test_find_cliques1(self):
  14. cl = list(nx.find_cliques(self.G))
  15. rcl = nx.find_cliques_recursive(self.G)
  16. expected = [[2, 6, 1, 3], [2, 6, 4], [5, 4, 7], [8, 9], [10, 11]]
  17. assert sorted(map(sorted, cl)) == sorted(map(sorted, rcl))
  18. assert sorted(map(sorted, cl)) == sorted(map(sorted, expected))
  19. def test_selfloops(self):
  20. self.G.add_edge(1, 1)
  21. cl = list(nx.find_cliques(self.G))
  22. rcl = list(nx.find_cliques_recursive(self.G))
  23. assert set(map(frozenset, cl)) == set(map(frozenset, rcl))
  24. answer = [{2, 6, 1, 3}, {2, 6, 4}, {5, 4, 7}, {8, 9}, {10, 11}]
  25. assert len(answer) == len(cl)
  26. assert all(set(c) in answer for c in cl)
  27. def test_find_cliques2(self):
  28. hcl = list(nx.find_cliques(self.H))
  29. assert sorted(map(sorted, hcl)) == [[1, 2], [1, 4, 5, 6], [2, 3], [3, 4, 6]]
  30. def test_find_cliques3(self):
  31. # all cliques are [[2, 6, 1, 3], [2, 6, 4], [5, 4, 7], [8, 9], [10, 11]]
  32. cl = list(nx.find_cliques(self.G, [2]))
  33. rcl = nx.find_cliques_recursive(self.G, [2])
  34. expected = [[2, 6, 1, 3], [2, 6, 4]]
  35. assert sorted(map(sorted, rcl)) == sorted(map(sorted, expected))
  36. assert sorted(map(sorted, cl)) == sorted(map(sorted, expected))
  37. cl = list(nx.find_cliques(self.G, [2, 3]))
  38. rcl = nx.find_cliques_recursive(self.G, [2, 3])
  39. expected = [[2, 6, 1, 3]]
  40. assert sorted(map(sorted, rcl)) == sorted(map(sorted, expected))
  41. assert sorted(map(sorted, cl)) == sorted(map(sorted, expected))
  42. cl = list(nx.find_cliques(self.G, [2, 6, 4]))
  43. rcl = nx.find_cliques_recursive(self.G, [2, 6, 4])
  44. expected = [[2, 6, 4]]
  45. assert sorted(map(sorted, rcl)) == sorted(map(sorted, expected))
  46. assert sorted(map(sorted, cl)) == sorted(map(sorted, expected))
  47. cl = list(nx.find_cliques(self.G, [2, 6, 4]))
  48. rcl = nx.find_cliques_recursive(self.G, [2, 6, 4])
  49. expected = [[2, 6, 4]]
  50. assert sorted(map(sorted, rcl)) == sorted(map(sorted, expected))
  51. assert sorted(map(sorted, cl)) == sorted(map(sorted, expected))
  52. with pytest.raises(ValueError):
  53. list(nx.find_cliques(self.G, [2, 6, 4, 1]))
  54. with pytest.raises(ValueError):
  55. list(nx.find_cliques_recursive(self.G, [2, 6, 4, 1]))
  56. def test_clique_number(self):
  57. G = self.G
  58. with pytest.deprecated_call():
  59. assert nx.graph_clique_number(G) == 4
  60. with pytest.deprecated_call():
  61. assert nx.graph_clique_number(G, cliques=self.cl) == 4
  62. def test_clique_number2(self):
  63. G = nx.Graph()
  64. G.add_nodes_from([1, 2, 3])
  65. with pytest.deprecated_call():
  66. assert nx.graph_clique_number(G) == 1
  67. def test_clique_number3(self):
  68. G = nx.Graph()
  69. with pytest.deprecated_call():
  70. assert nx.graph_clique_number(G) == 0
  71. def test_number_of_cliques(self):
  72. G = self.G
  73. with pytest.deprecated_call():
  74. assert nx.graph_number_of_cliques(G) == 5
  75. with pytest.deprecated_call():
  76. assert nx.graph_number_of_cliques(G, cliques=self.cl) == 5
  77. with pytest.deprecated_call():
  78. assert nx.number_of_cliques(G, 1) == 1
  79. with pytest.deprecated_call():
  80. assert list(nx.number_of_cliques(G, [1]).values()) == [1]
  81. with pytest.deprecated_call():
  82. assert list(nx.number_of_cliques(G, [1, 2]).values()) == [1, 2]
  83. with pytest.deprecated_call():
  84. assert nx.number_of_cliques(G, [1, 2]) == {1: 1, 2: 2}
  85. with pytest.deprecated_call():
  86. assert nx.number_of_cliques(G, 2) == 2
  87. with pytest.deprecated_call():
  88. assert nx.number_of_cliques(G) == {
  89. 1: 1,
  90. 2: 2,
  91. 3: 1,
  92. 4: 2,
  93. 5: 1,
  94. 6: 2,
  95. 7: 1,
  96. 8: 1,
  97. 9: 1,
  98. 10: 1,
  99. 11: 1,
  100. }
  101. with pytest.deprecated_call():
  102. assert nx.number_of_cliques(G, nodes=list(G)) == {
  103. 1: 1,
  104. 2: 2,
  105. 3: 1,
  106. 4: 2,
  107. 5: 1,
  108. 6: 2,
  109. 7: 1,
  110. 8: 1,
  111. 9: 1,
  112. 10: 1,
  113. 11: 1,
  114. }
  115. with pytest.deprecated_call():
  116. assert nx.number_of_cliques(G, nodes=[2, 3, 4]) == {2: 2, 3: 1, 4: 2}
  117. with pytest.deprecated_call():
  118. assert nx.number_of_cliques(G, cliques=self.cl) == {
  119. 1: 1,
  120. 2: 2,
  121. 3: 1,
  122. 4: 2,
  123. 5: 1,
  124. 6: 2,
  125. 7: 1,
  126. 8: 1,
  127. 9: 1,
  128. 10: 1,
  129. 11: 1,
  130. }
  131. with pytest.deprecated_call():
  132. assert nx.number_of_cliques(G, list(G), cliques=self.cl) == {
  133. 1: 1,
  134. 2: 2,
  135. 3: 1,
  136. 4: 2,
  137. 5: 1,
  138. 6: 2,
  139. 7: 1,
  140. 8: 1,
  141. 9: 1,
  142. 10: 1,
  143. 11: 1,
  144. }
  145. def test_node_clique_number(self):
  146. G = self.G
  147. assert nx.node_clique_number(G, 1) == 4
  148. assert list(nx.node_clique_number(G, [1]).values()) == [4]
  149. assert list(nx.node_clique_number(G, [1, 2]).values()) == [4, 4]
  150. assert nx.node_clique_number(G, [1, 2]) == {1: 4, 2: 4}
  151. assert nx.node_clique_number(G, 1) == 4
  152. assert nx.node_clique_number(G) == {
  153. 1: 4,
  154. 2: 4,
  155. 3: 4,
  156. 4: 3,
  157. 5: 3,
  158. 6: 4,
  159. 7: 3,
  160. 8: 2,
  161. 9: 2,
  162. 10: 2,
  163. 11: 2,
  164. }
  165. assert nx.node_clique_number(G, cliques=self.cl) == {
  166. 1: 4,
  167. 2: 4,
  168. 3: 4,
  169. 4: 3,
  170. 5: 3,
  171. 6: 4,
  172. 7: 3,
  173. 8: 2,
  174. 9: 2,
  175. 10: 2,
  176. 11: 2,
  177. }
  178. assert nx.node_clique_number(G, [1, 2], cliques=self.cl) == {1: 4, 2: 4}
  179. assert nx.node_clique_number(G, 1, cliques=self.cl) == 4
  180. def test_cliques_containing_node(self):
  181. G = self.G
  182. with pytest.deprecated_call():
  183. assert nx.cliques_containing_node(G, 1) == [[2, 6, 1, 3]]
  184. with pytest.deprecated_call():
  185. assert list(nx.cliques_containing_node(G, [1]).values()) == [[[2, 6, 1, 3]]]
  186. with pytest.deprecated_call():
  187. assert [
  188. sorted(c) for c in list(nx.cliques_containing_node(G, [1, 2]).values())
  189. ] == [[[2, 6, 1, 3]], [[2, 6, 1, 3], [2, 6, 4]]]
  190. with pytest.deprecated_call():
  191. result = nx.cliques_containing_node(G, [1, 2])
  192. for k, v in result.items():
  193. result[k] = sorted(v)
  194. assert result == {1: [[2, 6, 1, 3]], 2: [[2, 6, 1, 3], [2, 6, 4]]}
  195. with pytest.deprecated_call():
  196. assert nx.cliques_containing_node(G, 1) == [[2, 6, 1, 3]]
  197. expected = [{2, 6, 1, 3}, {2, 6, 4}]
  198. with pytest.deprecated_call():
  199. answer = [set(c) for c in nx.cliques_containing_node(G, 2)]
  200. assert answer in (expected, list(reversed(expected)))
  201. with pytest.deprecated_call():
  202. answer = [set(c) for c in nx.cliques_containing_node(G, 2, cliques=self.cl)]
  203. assert answer in (expected, list(reversed(expected)))
  204. with pytest.deprecated_call():
  205. assert len(nx.cliques_containing_node(G)) == 11
  206. def test_make_clique_bipartite(self):
  207. G = self.G
  208. B = nx.make_clique_bipartite(G)
  209. assert sorted(B) == [-5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
  210. # Project onto the nodes of the original graph.
  211. H = nx.projected_graph(B, range(1, 12))
  212. assert H.adj == G.adj
  213. # Project onto the nodes representing the cliques.
  214. H1 = nx.projected_graph(B, range(-5, 0))
  215. # Relabel the negative numbers as positive ones.
  216. H1 = nx.relabel_nodes(H1, {-v: v for v in range(1, 6)})
  217. assert sorted(H1) == [1, 2, 3, 4, 5]
  218. def test_make_max_clique_graph(self):
  219. """Tests that the maximal clique graph is the same as the bipartite
  220. clique graph after being projected onto the nodes representing the
  221. cliques.
  222. """
  223. G = self.G
  224. B = nx.make_clique_bipartite(G)
  225. # Project onto the nodes representing the cliques.
  226. H1 = nx.projected_graph(B, range(-5, 0))
  227. # Relabel the negative numbers as nonnegative ones, starting at
  228. # 0.
  229. H1 = nx.relabel_nodes(H1, {-v: v - 1 for v in range(1, 6)})
  230. H2 = nx.make_max_clique_graph(G)
  231. assert H1.adj == H2.adj
  232. def test_directed(self):
  233. with pytest.raises(nx.NetworkXNotImplemented):
  234. next(nx.find_cliques(nx.DiGraph()))
  235. def test_find_cliques_trivial(self):
  236. G = nx.Graph()
  237. assert sorted(nx.find_cliques(G)) == []
  238. assert sorted(nx.find_cliques_recursive(G)) == []
  239. def test_make_max_clique_graph_create_using(self):
  240. G = nx.Graph([(1, 2), (3, 1), (4, 1), (5, 6)])
  241. E = nx.Graph([(0, 1), (0, 2), (1, 2)])
  242. E.add_node(3)
  243. assert nx.is_isomorphic(nx.make_max_clique_graph(G, create_using=nx.Graph), E)
  244. class TestEnumerateAllCliques:
  245. def test_paper_figure_4(self):
  246. # Same graph as given in Fig. 4 of paper enumerate_all_cliques is
  247. # based on.
  248. # http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=1559964&isnumber=33129
  249. G = nx.Graph()
  250. edges_fig_4 = [
  251. ("a", "b"),
  252. ("a", "c"),
  253. ("a", "d"),
  254. ("a", "e"),
  255. ("b", "c"),
  256. ("b", "d"),
  257. ("b", "e"),
  258. ("c", "d"),
  259. ("c", "e"),
  260. ("d", "e"),
  261. ("f", "b"),
  262. ("f", "c"),
  263. ("f", "g"),
  264. ("g", "f"),
  265. ("g", "c"),
  266. ("g", "d"),
  267. ("g", "e"),
  268. ]
  269. G.add_edges_from(edges_fig_4)
  270. cliques = list(nx.enumerate_all_cliques(G))
  271. clique_sizes = list(map(len, cliques))
  272. assert sorted(clique_sizes) == clique_sizes
  273. expected_cliques = [
  274. ["a"],
  275. ["b"],
  276. ["c"],
  277. ["d"],
  278. ["e"],
  279. ["f"],
  280. ["g"],
  281. ["a", "b"],
  282. ["a", "b", "d"],
  283. ["a", "b", "d", "e"],
  284. ["a", "b", "e"],
  285. ["a", "c"],
  286. ["a", "c", "d"],
  287. ["a", "c", "d", "e"],
  288. ["a", "c", "e"],
  289. ["a", "d"],
  290. ["a", "d", "e"],
  291. ["a", "e"],
  292. ["b", "c"],
  293. ["b", "c", "d"],
  294. ["b", "c", "d", "e"],
  295. ["b", "c", "e"],
  296. ["b", "c", "f"],
  297. ["b", "d"],
  298. ["b", "d", "e"],
  299. ["b", "e"],
  300. ["b", "f"],
  301. ["c", "d"],
  302. ["c", "d", "e"],
  303. ["c", "d", "e", "g"],
  304. ["c", "d", "g"],
  305. ["c", "e"],
  306. ["c", "e", "g"],
  307. ["c", "f"],
  308. ["c", "f", "g"],
  309. ["c", "g"],
  310. ["d", "e"],
  311. ["d", "e", "g"],
  312. ["d", "g"],
  313. ["e", "g"],
  314. ["f", "g"],
  315. ["a", "b", "c"],
  316. ["a", "b", "c", "d"],
  317. ["a", "b", "c", "d", "e"],
  318. ["a", "b", "c", "e"],
  319. ]
  320. assert sorted(map(sorted, cliques)) == sorted(map(sorted, expected_cliques))