test_threshold.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. """
  2. Threshold Graphs
  3. ================
  4. """
  5. import pytest
  6. import networkx as nx
  7. import networkx.algorithms.threshold as nxt
  8. from networkx.algorithms.isomorphism.isomorph import graph_could_be_isomorphic
  9. cnlti = nx.convert_node_labels_to_integers
  10. class TestGeneratorThreshold:
  11. def test_threshold_sequence_graph_test(self):
  12. G = nx.star_graph(10)
  13. assert nxt.is_threshold_graph(G)
  14. assert nxt.is_threshold_sequence([d for n, d in G.degree()])
  15. G = nx.complete_graph(10)
  16. assert nxt.is_threshold_graph(G)
  17. assert nxt.is_threshold_sequence([d for n, d in G.degree()])
  18. deg = [3, 2, 2, 1, 1, 1]
  19. assert not nxt.is_threshold_sequence(deg)
  20. deg = [3, 2, 2, 1]
  21. assert nxt.is_threshold_sequence(deg)
  22. G = nx.generators.havel_hakimi_graph(deg)
  23. assert nxt.is_threshold_graph(G)
  24. def test_creation_sequences(self):
  25. deg = [3, 2, 2, 1]
  26. G = nx.generators.havel_hakimi_graph(deg)
  27. with pytest.raises(ValueError):
  28. nxt.creation_sequence(deg, with_labels=True, compact=True)
  29. cs0 = nxt.creation_sequence(deg)
  30. H0 = nxt.threshold_graph(cs0)
  31. assert "".join(cs0) == "ddid"
  32. cs1 = nxt.creation_sequence(deg, with_labels=True)
  33. H1 = nxt.threshold_graph(cs1)
  34. assert cs1 == [(1, "d"), (2, "d"), (3, "i"), (0, "d")]
  35. cs2 = nxt.creation_sequence(deg, compact=True)
  36. H2 = nxt.threshold_graph(cs2)
  37. assert cs2 == [2, 1, 1]
  38. assert "".join(nxt.uncompact(cs2)) == "ddid"
  39. assert graph_could_be_isomorphic(H0, G)
  40. assert graph_could_be_isomorphic(H0, H1)
  41. assert graph_could_be_isomorphic(H0, H2)
  42. def test_make_compact(self):
  43. assert nxt.make_compact(["d", "d", "d", "i", "d", "d"]) == [3, 1, 2]
  44. assert nxt.make_compact([3, 1, 2]) == [3, 1, 2]
  45. assert pytest.raises(TypeError, nxt.make_compact, [3.0, 1.0, 2.0])
  46. def test_uncompact(self):
  47. assert nxt.uncompact([3, 1, 2]) == ["d", "d", "d", "i", "d", "d"]
  48. assert nxt.uncompact(["d", "d", "i", "d"]) == ["d", "d", "i", "d"]
  49. assert nxt.uncompact(
  50. nxt.uncompact([(1, "d"), (2, "d"), (3, "i"), (0, "d")])
  51. ) == nxt.uncompact([(1, "d"), (2, "d"), (3, "i"), (0, "d")])
  52. assert pytest.raises(TypeError, nxt.uncompact, [3.0, 1.0, 2.0])
  53. def test_creation_sequence_to_weights(self):
  54. assert nxt.creation_sequence_to_weights([3, 1, 2]) == [
  55. 0.5,
  56. 0.5,
  57. 0.5,
  58. 0.25,
  59. 0.75,
  60. 0.75,
  61. ]
  62. assert pytest.raises(
  63. TypeError, nxt.creation_sequence_to_weights, [3.0, 1.0, 2.0]
  64. )
  65. def test_weights_to_creation_sequence(self):
  66. deg = [3, 2, 2, 1]
  67. with pytest.raises(ValueError):
  68. nxt.weights_to_creation_sequence(deg, with_labels=True, compact=True)
  69. assert nxt.weights_to_creation_sequence(deg, with_labels=True) == [
  70. (3, "d"),
  71. (1, "d"),
  72. (2, "d"),
  73. (0, "d"),
  74. ]
  75. assert nxt.weights_to_creation_sequence(deg, compact=True) == [4]
  76. def test_find_alternating_4_cycle(self):
  77. G = nx.Graph()
  78. G.add_edge(1, 2)
  79. assert not nxt.find_alternating_4_cycle(G)
  80. def test_shortest_path(self):
  81. deg = [3, 2, 2, 1]
  82. G = nx.generators.havel_hakimi_graph(deg)
  83. cs1 = nxt.creation_sequence(deg, with_labels=True)
  84. for n, m in [(3, 0), (0, 3), (0, 2), (0, 1), (1, 3), (3, 1), (1, 2), (2, 3)]:
  85. assert nxt.shortest_path(cs1, n, m) == nx.shortest_path(G, n, m)
  86. spl = nxt.shortest_path_length(cs1, 3)
  87. spl2 = nxt.shortest_path_length([t for v, t in cs1], 2)
  88. assert spl == spl2
  89. spld = {}
  90. for j, pl in enumerate(spl):
  91. n = cs1[j][0]
  92. spld[n] = pl
  93. assert spld == nx.single_source_shortest_path_length(G, 3)
  94. assert nxt.shortest_path(["d", "d", "d", "i", "d", "d"], 1, 2) == [1, 2]
  95. assert nxt.shortest_path([3, 1, 2], 1, 2) == [1, 2]
  96. assert pytest.raises(TypeError, nxt.shortest_path, [3.0, 1.0, 2.0], 1, 2)
  97. assert pytest.raises(ValueError, nxt.shortest_path, [3, 1, 2], "a", 2)
  98. assert pytest.raises(ValueError, nxt.shortest_path, [3, 1, 2], 1, "b")
  99. assert nxt.shortest_path([3, 1, 2], 1, 1) == [1]
  100. def test_shortest_path_length(self):
  101. assert nxt.shortest_path_length([3, 1, 2], 1) == [1, 0, 1, 2, 1, 1]
  102. assert nxt.shortest_path_length(["d", "d", "d", "i", "d", "d"], 1) == [
  103. 1,
  104. 0,
  105. 1,
  106. 2,
  107. 1,
  108. 1,
  109. ]
  110. assert nxt.shortest_path_length(("d", "d", "d", "i", "d", "d"), 1) == [
  111. 1,
  112. 0,
  113. 1,
  114. 2,
  115. 1,
  116. 1,
  117. ]
  118. assert pytest.raises(TypeError, nxt.shortest_path, [3.0, 1.0, 2.0], 1)
  119. def test_random_threshold_sequence(self):
  120. assert len(nxt.random_threshold_sequence(10, 0.5)) == 10
  121. assert nxt.random_threshold_sequence(10, 0.5, seed=42) == [
  122. "d",
  123. "i",
  124. "d",
  125. "d",
  126. "d",
  127. "i",
  128. "i",
  129. "i",
  130. "d",
  131. "d",
  132. ]
  133. assert pytest.raises(ValueError, nxt.random_threshold_sequence, 10, 1.5)
  134. def test_right_d_threshold_sequence(self):
  135. assert nxt.right_d_threshold_sequence(3, 2) == ["d", "i", "d"]
  136. assert pytest.raises(ValueError, nxt.right_d_threshold_sequence, 2, 3)
  137. def test_left_d_threshold_sequence(self):
  138. assert nxt.left_d_threshold_sequence(3, 2) == ["d", "i", "d"]
  139. assert pytest.raises(ValueError, nxt.left_d_threshold_sequence, 2, 3)
  140. def test_weights_thresholds(self):
  141. wseq = [3, 4, 3, 3, 5, 6, 5, 4, 5, 6]
  142. cs = nxt.weights_to_creation_sequence(wseq, threshold=10)
  143. wseq = nxt.creation_sequence_to_weights(cs)
  144. cs2 = nxt.weights_to_creation_sequence(wseq)
  145. assert cs == cs2
  146. wseq = nxt.creation_sequence_to_weights(nxt.uncompact([3, 1, 2, 3, 3, 2, 3]))
  147. assert wseq == [
  148. s * 0.125 for s in [4, 4, 4, 3, 5, 5, 2, 2, 2, 6, 6, 6, 1, 1, 7, 7, 7]
  149. ]
  150. wseq = nxt.creation_sequence_to_weights([3, 1, 2, 3, 3, 2, 3])
  151. assert wseq == [
  152. s * 0.125 for s in [4, 4, 4, 3, 5, 5, 2, 2, 2, 6, 6, 6, 1, 1, 7, 7, 7]
  153. ]
  154. wseq = nxt.creation_sequence_to_weights(list(enumerate("ddidiiidididi")))
  155. assert wseq == [s * 0.1 for s in [5, 5, 4, 6, 3, 3, 3, 7, 2, 8, 1, 9, 0]]
  156. wseq = nxt.creation_sequence_to_weights("ddidiiidididi")
  157. assert wseq == [s * 0.1 for s in [5, 5, 4, 6, 3, 3, 3, 7, 2, 8, 1, 9, 0]]
  158. wseq = nxt.creation_sequence_to_weights("ddidiiidididid")
  159. ws = [s / 12 for s in [6, 6, 5, 7, 4, 4, 4, 8, 3, 9, 2, 10, 1, 11]]
  160. assert sum(abs(c - d) for c, d in zip(wseq, ws)) < 1e-14
  161. def test_finding_routines(self):
  162. G = nx.Graph({1: [2], 2: [3], 3: [4], 4: [5], 5: [6]})
  163. G.add_edge(2, 4)
  164. G.add_edge(2, 5)
  165. G.add_edge(2, 7)
  166. G.add_edge(3, 6)
  167. G.add_edge(4, 6)
  168. # Alternating 4 cycle
  169. assert nxt.find_alternating_4_cycle(G) == [1, 2, 3, 6]
  170. # Threshold graph
  171. TG = nxt.find_threshold_graph(G)
  172. assert nxt.is_threshold_graph(TG)
  173. assert sorted(TG.nodes()) == [1, 2, 3, 4, 5, 7]
  174. cs = nxt.creation_sequence(dict(TG.degree()), with_labels=True)
  175. assert nxt.find_creation_sequence(G) == cs
  176. def test_fast_versions_properties_threshold_graphs(self):
  177. cs = "ddiiddid"
  178. G = nxt.threshold_graph(cs)
  179. assert nxt.density("ddiiddid") == nx.density(G)
  180. assert sorted(nxt.degree_sequence(cs)) == sorted(d for n, d in G.degree())
  181. ts = nxt.triangle_sequence(cs)
  182. assert ts == list(nx.triangles(G).values())
  183. assert sum(ts) // 3 == nxt.triangles(cs)
  184. c1 = nxt.cluster_sequence(cs)
  185. c2 = list(nx.clustering(G).values())
  186. assert sum(abs(c - d) for c, d in zip(c1, c2)) == pytest.approx(0, abs=1e-7)
  187. b1 = nx.betweenness_centrality(G).values()
  188. b2 = nxt.betweenness_sequence(cs)
  189. assert sum(abs(c - d) for c, d in zip(b1, b2)) < 1e-14
  190. assert nxt.eigenvalues(cs) == [0, 1, 3, 3, 5, 7, 7, 8]
  191. # Degree Correlation
  192. assert abs(nxt.degree_correlation(cs) + 0.593038821954) < 1e-12
  193. assert nxt.degree_correlation("diiiddi") == -0.8
  194. assert nxt.degree_correlation("did") == -1.0
  195. assert nxt.degree_correlation("ddd") == 1.0
  196. assert nxt.eigenvalues("dddiii") == [0, 0, 0, 0, 3, 3]
  197. assert nxt.eigenvalues("dddiiid") == [0, 1, 1, 1, 4, 4, 7]
  198. def test_tg_creation_routines(self):
  199. s = nxt.left_d_threshold_sequence(5, 7)
  200. s = nxt.right_d_threshold_sequence(5, 7)
  201. s1 = nxt.swap_d(s, 1.0, 1.0)
  202. s1 = nxt.swap_d(s, 1.0, 1.0, seed=1)
  203. def test_eigenvectors(self):
  204. np = pytest.importorskip("numpy")
  205. eigenval = np.linalg.eigvals
  206. pytest.importorskip("scipy")
  207. cs = "ddiiddid"
  208. G = nxt.threshold_graph(cs)
  209. (tgeval, tgevec) = nxt.eigenvectors(cs)
  210. np.testing.assert_allclose([np.dot(lv, lv) for lv in tgevec], 1.0, rtol=1e-9)
  211. lapl = nx.laplacian_matrix(G)
  212. def test_create_using(self):
  213. cs = "ddiiddid"
  214. G = nxt.threshold_graph(cs)
  215. assert pytest.raises(
  216. nx.exception.NetworkXError,
  217. nxt.threshold_graph,
  218. cs,
  219. create_using=nx.DiGraph(),
  220. )
  221. MG = nxt.threshold_graph(cs, create_using=nx.MultiGraph())
  222. assert sorted(MG.edges()) == sorted(G.edges())