test_cluster.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. import pytest
  2. import networkx as nx
  3. class TestTriangles:
  4. def test_empty(self):
  5. G = nx.Graph()
  6. assert list(nx.triangles(G).values()) == []
  7. def test_path(self):
  8. G = nx.path_graph(10)
  9. assert list(nx.triangles(G).values()) == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  10. assert nx.triangles(G) == {
  11. 0: 0,
  12. 1: 0,
  13. 2: 0,
  14. 3: 0,
  15. 4: 0,
  16. 5: 0,
  17. 6: 0,
  18. 7: 0,
  19. 8: 0,
  20. 9: 0,
  21. }
  22. def test_cubical(self):
  23. G = nx.cubical_graph()
  24. assert list(nx.triangles(G).values()) == [0, 0, 0, 0, 0, 0, 0, 0]
  25. assert nx.triangles(G, 1) == 0
  26. assert list(nx.triangles(G, [1, 2]).values()) == [0, 0]
  27. assert nx.triangles(G, 1) == 0
  28. assert nx.triangles(G, [1, 2]) == {1: 0, 2: 0}
  29. def test_k5(self):
  30. G = nx.complete_graph(5)
  31. assert list(nx.triangles(G).values()) == [6, 6, 6, 6, 6]
  32. assert sum(nx.triangles(G).values()) / 3 == 10
  33. assert nx.triangles(G, 1) == 6
  34. G.remove_edge(1, 2)
  35. assert list(nx.triangles(G).values()) == [5, 3, 3, 5, 5]
  36. assert nx.triangles(G, 1) == 3
  37. G.add_edge(3, 3) # ignore self-edges
  38. assert list(nx.triangles(G).values()) == [5, 3, 3, 5, 5]
  39. assert nx.triangles(G, 3) == 5
  40. class TestDirectedClustering:
  41. def test_clustering(self):
  42. G = nx.DiGraph()
  43. assert list(nx.clustering(G).values()) == []
  44. assert nx.clustering(G) == {}
  45. def test_path(self):
  46. G = nx.path_graph(10, create_using=nx.DiGraph())
  47. assert list(nx.clustering(G).values()) == [
  48. 0,
  49. 0,
  50. 0,
  51. 0,
  52. 0,
  53. 0,
  54. 0,
  55. 0,
  56. 0,
  57. 0,
  58. ]
  59. assert nx.clustering(G) == {
  60. 0: 0,
  61. 1: 0,
  62. 2: 0,
  63. 3: 0,
  64. 4: 0,
  65. 5: 0,
  66. 6: 0,
  67. 7: 0,
  68. 8: 0,
  69. 9: 0,
  70. }
  71. assert nx.clustering(G, 0) == 0
  72. def test_k5(self):
  73. G = nx.complete_graph(5, create_using=nx.DiGraph())
  74. assert list(nx.clustering(G).values()) == [1, 1, 1, 1, 1]
  75. assert nx.average_clustering(G) == 1
  76. G.remove_edge(1, 2)
  77. assert list(nx.clustering(G).values()) == [
  78. 11 / 12,
  79. 1,
  80. 1,
  81. 11 / 12,
  82. 11 / 12,
  83. ]
  84. assert nx.clustering(G, [1, 4]) == {1: 1, 4: 11 / 12}
  85. G.remove_edge(2, 1)
  86. assert list(nx.clustering(G).values()) == [
  87. 5 / 6,
  88. 1,
  89. 1,
  90. 5 / 6,
  91. 5 / 6,
  92. ]
  93. assert nx.clustering(G, [1, 4]) == {1: 1, 4: 0.83333333333333337}
  94. assert nx.clustering(G, 4) == 5 / 6
  95. def test_triangle_and_edge(self):
  96. G = nx.cycle_graph(3, create_using=nx.DiGraph())
  97. G.add_edge(0, 4)
  98. assert nx.clustering(G)[0] == 1 / 6
  99. class TestDirectedWeightedClustering:
  100. @classmethod
  101. def setup_class(cls):
  102. global np
  103. np = pytest.importorskip("numpy")
  104. def test_clustering(self):
  105. G = nx.DiGraph()
  106. assert list(nx.clustering(G, weight="weight").values()) == []
  107. assert nx.clustering(G) == {}
  108. def test_path(self):
  109. G = nx.path_graph(10, create_using=nx.DiGraph())
  110. assert list(nx.clustering(G, weight="weight").values()) == [
  111. 0,
  112. 0,
  113. 0,
  114. 0,
  115. 0,
  116. 0,
  117. 0,
  118. 0,
  119. 0,
  120. 0,
  121. ]
  122. assert nx.clustering(G, weight="weight") == {
  123. 0: 0,
  124. 1: 0,
  125. 2: 0,
  126. 3: 0,
  127. 4: 0,
  128. 5: 0,
  129. 6: 0,
  130. 7: 0,
  131. 8: 0,
  132. 9: 0,
  133. }
  134. def test_k5(self):
  135. G = nx.complete_graph(5, create_using=nx.DiGraph())
  136. assert list(nx.clustering(G, weight="weight").values()) == [1, 1, 1, 1, 1]
  137. assert nx.average_clustering(G, weight="weight") == 1
  138. G.remove_edge(1, 2)
  139. assert list(nx.clustering(G, weight="weight").values()) == [
  140. 11 / 12,
  141. 1,
  142. 1,
  143. 11 / 12,
  144. 11 / 12,
  145. ]
  146. assert nx.clustering(G, [1, 4], weight="weight") == {1: 1, 4: 11 / 12}
  147. G.remove_edge(2, 1)
  148. assert list(nx.clustering(G, weight="weight").values()) == [
  149. 5 / 6,
  150. 1,
  151. 1,
  152. 5 / 6,
  153. 5 / 6,
  154. ]
  155. assert nx.clustering(G, [1, 4], weight="weight") == {
  156. 1: 1,
  157. 4: 0.83333333333333337,
  158. }
  159. def test_triangle_and_edge(self):
  160. G = nx.cycle_graph(3, create_using=nx.DiGraph())
  161. G.add_edge(0, 4, weight=2)
  162. assert nx.clustering(G)[0] == 1 / 6
  163. # Relaxed comparisons to allow graphblas-algorithms to pass tests
  164. np.testing.assert_allclose(nx.clustering(G, weight="weight")[0], 1 / 12)
  165. np.testing.assert_allclose(nx.clustering(G, 0, weight="weight"), 1 / 12)
  166. class TestWeightedClustering:
  167. @classmethod
  168. def setup_class(cls):
  169. global np
  170. np = pytest.importorskip("numpy")
  171. def test_clustering(self):
  172. G = nx.Graph()
  173. assert list(nx.clustering(G, weight="weight").values()) == []
  174. assert nx.clustering(G) == {}
  175. def test_path(self):
  176. G = nx.path_graph(10)
  177. assert list(nx.clustering(G, weight="weight").values()) == [
  178. 0,
  179. 0,
  180. 0,
  181. 0,
  182. 0,
  183. 0,
  184. 0,
  185. 0,
  186. 0,
  187. 0,
  188. ]
  189. assert nx.clustering(G, weight="weight") == {
  190. 0: 0,
  191. 1: 0,
  192. 2: 0,
  193. 3: 0,
  194. 4: 0,
  195. 5: 0,
  196. 6: 0,
  197. 7: 0,
  198. 8: 0,
  199. 9: 0,
  200. }
  201. def test_cubical(self):
  202. G = nx.cubical_graph()
  203. assert list(nx.clustering(G, weight="weight").values()) == [
  204. 0,
  205. 0,
  206. 0,
  207. 0,
  208. 0,
  209. 0,
  210. 0,
  211. 0,
  212. ]
  213. assert nx.clustering(G, 1) == 0
  214. assert list(nx.clustering(G, [1, 2], weight="weight").values()) == [0, 0]
  215. assert nx.clustering(G, 1, weight="weight") == 0
  216. assert nx.clustering(G, [1, 2], weight="weight") == {1: 0, 2: 0}
  217. def test_k5(self):
  218. G = nx.complete_graph(5)
  219. assert list(nx.clustering(G, weight="weight").values()) == [1, 1, 1, 1, 1]
  220. assert nx.average_clustering(G, weight="weight") == 1
  221. G.remove_edge(1, 2)
  222. assert list(nx.clustering(G, weight="weight").values()) == [
  223. 5 / 6,
  224. 1,
  225. 1,
  226. 5 / 6,
  227. 5 / 6,
  228. ]
  229. assert nx.clustering(G, [1, 4], weight="weight") == {
  230. 1: 1,
  231. 4: 0.83333333333333337,
  232. }
  233. def test_triangle_and_edge(self):
  234. G = nx.cycle_graph(3)
  235. G.add_edge(0, 4, weight=2)
  236. assert nx.clustering(G)[0] == 1 / 3
  237. np.testing.assert_allclose(nx.clustering(G, weight="weight")[0], 1 / 6)
  238. np.testing.assert_allclose(nx.clustering(G, 0, weight="weight"), 1 / 6)
  239. def test_triangle_and_signed_edge(self):
  240. G = nx.cycle_graph(3)
  241. G.add_edge(0, 1, weight=-1)
  242. G.add_edge(3, 0, weight=0)
  243. assert nx.clustering(G)[0] == 1 / 3
  244. assert nx.clustering(G, weight="weight")[0] == -1 / 3
  245. class TestClustering:
  246. @classmethod
  247. def setup_class(cls):
  248. pytest.importorskip("numpy")
  249. def test_clustering(self):
  250. G = nx.Graph()
  251. assert list(nx.clustering(G).values()) == []
  252. assert nx.clustering(G) == {}
  253. def test_path(self):
  254. G = nx.path_graph(10)
  255. assert list(nx.clustering(G).values()) == [
  256. 0,
  257. 0,
  258. 0,
  259. 0,
  260. 0,
  261. 0,
  262. 0,
  263. 0,
  264. 0,
  265. 0,
  266. ]
  267. assert nx.clustering(G) == {
  268. 0: 0,
  269. 1: 0,
  270. 2: 0,
  271. 3: 0,
  272. 4: 0,
  273. 5: 0,
  274. 6: 0,
  275. 7: 0,
  276. 8: 0,
  277. 9: 0,
  278. }
  279. def test_cubical(self):
  280. G = nx.cubical_graph()
  281. assert list(nx.clustering(G).values()) == [0, 0, 0, 0, 0, 0, 0, 0]
  282. assert nx.clustering(G, 1) == 0
  283. assert list(nx.clustering(G, [1, 2]).values()) == [0, 0]
  284. assert nx.clustering(G, 1) == 0
  285. assert nx.clustering(G, [1, 2]) == {1: 0, 2: 0}
  286. def test_k5(self):
  287. G = nx.complete_graph(5)
  288. assert list(nx.clustering(G).values()) == [1, 1, 1, 1, 1]
  289. assert nx.average_clustering(G) == 1
  290. G.remove_edge(1, 2)
  291. assert list(nx.clustering(G).values()) == [
  292. 5 / 6,
  293. 1,
  294. 1,
  295. 5 / 6,
  296. 5 / 6,
  297. ]
  298. assert nx.clustering(G, [1, 4]) == {1: 1, 4: 0.83333333333333337}
  299. def test_k5_signed(self):
  300. G = nx.complete_graph(5)
  301. assert list(nx.clustering(G).values()) == [1, 1, 1, 1, 1]
  302. assert nx.average_clustering(G) == 1
  303. G.remove_edge(1, 2)
  304. G.add_edge(0, 1, weight=-1)
  305. assert list(nx.clustering(G, weight="weight").values()) == [
  306. 1 / 6,
  307. -1 / 3,
  308. 1,
  309. 3 / 6,
  310. 3 / 6,
  311. ]
  312. class TestTransitivity:
  313. def test_transitivity(self):
  314. G = nx.Graph()
  315. assert nx.transitivity(G) == 0
  316. def test_path(self):
  317. G = nx.path_graph(10)
  318. assert nx.transitivity(G) == 0
  319. def test_cubical(self):
  320. G = nx.cubical_graph()
  321. assert nx.transitivity(G) == 0
  322. def test_k5(self):
  323. G = nx.complete_graph(5)
  324. assert nx.transitivity(G) == 1
  325. G.remove_edge(1, 2)
  326. assert nx.transitivity(G) == 0.875
  327. class TestSquareClustering:
  328. def test_clustering(self):
  329. G = nx.Graph()
  330. assert list(nx.square_clustering(G).values()) == []
  331. assert nx.square_clustering(G) == {}
  332. def test_path(self):
  333. G = nx.path_graph(10)
  334. assert list(nx.square_clustering(G).values()) == [
  335. 0,
  336. 0,
  337. 0,
  338. 0,
  339. 0,
  340. 0,
  341. 0,
  342. 0,
  343. 0,
  344. 0,
  345. ]
  346. assert nx.square_clustering(G) == {
  347. 0: 0,
  348. 1: 0,
  349. 2: 0,
  350. 3: 0,
  351. 4: 0,
  352. 5: 0,
  353. 6: 0,
  354. 7: 0,
  355. 8: 0,
  356. 9: 0,
  357. }
  358. def test_cubical(self):
  359. G = nx.cubical_graph()
  360. assert list(nx.square_clustering(G).values()) == [
  361. 1 / 3,
  362. 1 / 3,
  363. 1 / 3,
  364. 1 / 3,
  365. 1 / 3,
  366. 1 / 3,
  367. 1 / 3,
  368. 1 / 3,
  369. ]
  370. assert list(nx.square_clustering(G, [1, 2]).values()) == [1 / 3, 1 / 3]
  371. assert nx.square_clustering(G, [1])[1] == 1 / 3
  372. assert nx.square_clustering(G, 1) == 1 / 3
  373. assert nx.square_clustering(G, [1, 2]) == {1: 1 / 3, 2: 1 / 3}
  374. def test_k5(self):
  375. G = nx.complete_graph(5)
  376. assert list(nx.square_clustering(G).values()) == [1, 1, 1, 1, 1]
  377. def test_bipartite_k5(self):
  378. G = nx.complete_bipartite_graph(5, 5)
  379. assert list(nx.square_clustering(G).values()) == [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  380. def test_lind_square_clustering(self):
  381. """Test C4 for figure 1 Lind et al (2005)"""
  382. G = nx.Graph(
  383. [
  384. (1, 2),
  385. (1, 3),
  386. (1, 6),
  387. (1, 7),
  388. (2, 4),
  389. (2, 5),
  390. (3, 4),
  391. (3, 5),
  392. (6, 7),
  393. (7, 8),
  394. (6, 8),
  395. (7, 9),
  396. (7, 10),
  397. (6, 11),
  398. (6, 12),
  399. (2, 13),
  400. (2, 14),
  401. (3, 15),
  402. (3, 16),
  403. ]
  404. )
  405. G1 = G.subgraph([1, 2, 3, 4, 5, 13, 14, 15, 16])
  406. G2 = G.subgraph([1, 6, 7, 8, 9, 10, 11, 12])
  407. assert nx.square_clustering(G, [1])[1] == 3 / 43
  408. assert nx.square_clustering(G1, [1])[1] == 2 / 6
  409. assert nx.square_clustering(G2, [1])[1] == 1 / 5
  410. def test_peng_square_clustering(self):
  411. """Test eq2 for figure 1 Peng et al (2008)"""
  412. G = nx.Graph([(1, 2), (1, 3), (2, 4), (3, 4), (3, 5), (3, 6)])
  413. assert nx.square_clustering(G, [1])[1] == 1 / 3
  414. class TestAverageClustering:
  415. @classmethod
  416. def setup_class(cls):
  417. pytest.importorskip("numpy")
  418. def test_empty(self):
  419. G = nx.Graph()
  420. with pytest.raises(ZeroDivisionError):
  421. nx.average_clustering(G)
  422. def test_average_clustering(self):
  423. G = nx.cycle_graph(3)
  424. G.add_edge(2, 3)
  425. assert nx.average_clustering(G) == (1 + 1 + 1 / 3) / 4
  426. assert nx.average_clustering(G, count_zeros=True) == (1 + 1 + 1 / 3) / 4
  427. assert nx.average_clustering(G, count_zeros=False) == (1 + 1 + 1 / 3) / 3
  428. assert nx.average_clustering(G, [1, 2, 3]) == (1 + 1 / 3) / 3
  429. assert nx.average_clustering(G, [1, 2, 3], count_zeros=True) == (1 + 1 / 3) / 3
  430. assert nx.average_clustering(G, [1, 2, 3], count_zeros=False) == (1 + 1 / 3) / 2
  431. def test_average_clustering_signed(self):
  432. G = nx.cycle_graph(3)
  433. G.add_edge(2, 3)
  434. G.add_edge(0, 1, weight=-1)
  435. assert nx.average_clustering(G, weight="weight") == (-1 - 1 - 1 / 3) / 4
  436. assert (
  437. nx.average_clustering(G, weight="weight", count_zeros=True)
  438. == (-1 - 1 - 1 / 3) / 4
  439. )
  440. assert (
  441. nx.average_clustering(G, weight="weight", count_zeros=False)
  442. == (-1 - 1 - 1 / 3) / 3
  443. )
  444. class TestDirectedAverageClustering:
  445. @classmethod
  446. def setup_class(cls):
  447. pytest.importorskip("numpy")
  448. def test_empty(self):
  449. G = nx.DiGraph()
  450. with pytest.raises(ZeroDivisionError):
  451. nx.average_clustering(G)
  452. def test_average_clustering(self):
  453. G = nx.cycle_graph(3, create_using=nx.DiGraph())
  454. G.add_edge(2, 3)
  455. assert nx.average_clustering(G) == (1 + 1 + 1 / 3) / 8
  456. assert nx.average_clustering(G, count_zeros=True) == (1 + 1 + 1 / 3) / 8
  457. assert nx.average_clustering(G, count_zeros=False) == (1 + 1 + 1 / 3) / 6
  458. assert nx.average_clustering(G, [1, 2, 3]) == (1 + 1 / 3) / 6
  459. assert nx.average_clustering(G, [1, 2, 3], count_zeros=True) == (1 + 1 / 3) / 6
  460. assert nx.average_clustering(G, [1, 2, 3], count_zeros=False) == (1 + 1 / 3) / 4
  461. class TestGeneralizedDegree:
  462. def test_generalized_degree(self):
  463. G = nx.Graph()
  464. assert nx.generalized_degree(G) == {}
  465. def test_path(self):
  466. G = nx.path_graph(5)
  467. assert nx.generalized_degree(G, 0) == {0: 1}
  468. assert nx.generalized_degree(G, 1) == {0: 2}
  469. def test_cubical(self):
  470. G = nx.cubical_graph()
  471. assert nx.generalized_degree(G, 0) == {0: 3}
  472. def test_k5(self):
  473. G = nx.complete_graph(5)
  474. assert nx.generalized_degree(G, 0) == {3: 4}
  475. G.remove_edge(0, 1)
  476. assert nx.generalized_degree(G, 0) == {2: 3}
  477. assert nx.generalized_degree(G, [1, 2]) == {1: {2: 3}, 2: {2: 2, 3: 2}}
  478. assert nx.generalized_degree(G) == {
  479. 0: {2: 3},
  480. 1: {2: 3},
  481. 2: {2: 2, 3: 2},
  482. 3: {2: 2, 3: 2},
  483. 4: {2: 2, 3: 2},
  484. }