scikit-network 0.30.0__cp38-cp38-win_amd64.whl → 0.32.1__cp38-cp38-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of scikit-network might be problematic. Click here for more details.

Files changed (187) hide show
  1. {scikit_network-0.30.0.dist-info → scikit_network-0.32.1.dist-info}/AUTHORS.rst +3 -0
  2. {scikit_network-0.30.0.dist-info → scikit_network-0.32.1.dist-info}/METADATA +31 -3
  3. scikit_network-0.32.1.dist-info/RECORD +228 -0
  4. {scikit_network-0.30.0.dist-info → scikit_network-0.32.1.dist-info}/WHEEL +1 -1
  5. sknetwork/__init__.py +1 -1
  6. sknetwork/base.py +67 -0
  7. sknetwork/classification/base.py +24 -24
  8. sknetwork/classification/base_rank.py +17 -25
  9. sknetwork/classification/diffusion.py +35 -35
  10. sknetwork/classification/knn.py +24 -21
  11. sknetwork/classification/metrics.py +1 -1
  12. sknetwork/classification/pagerank.py +10 -10
  13. sknetwork/classification/propagation.py +23 -20
  14. sknetwork/classification/tests/test_diffusion.py +13 -3
  15. sknetwork/classification/vote.cp38-win_amd64.pyd +0 -0
  16. sknetwork/classification/vote.cpp +14482 -10351
  17. sknetwork/classification/vote.pyx +1 -3
  18. sknetwork/clustering/__init__.py +3 -1
  19. sknetwork/clustering/base.py +36 -40
  20. sknetwork/clustering/kcenters.py +253 -0
  21. sknetwork/clustering/leiden.py +241 -0
  22. sknetwork/clustering/leiden_core.cp38-win_amd64.pyd +0 -0
  23. sknetwork/clustering/leiden_core.cpp +31564 -0
  24. sknetwork/clustering/leiden_core.pyx +124 -0
  25. sknetwork/clustering/louvain.py +133 -102
  26. sknetwork/clustering/louvain_core.cp38-win_amd64.pyd +0 -0
  27. sknetwork/clustering/louvain_core.cpp +22457 -18792
  28. sknetwork/clustering/louvain_core.pyx +86 -96
  29. sknetwork/clustering/postprocess.py +2 -2
  30. sknetwork/clustering/propagation_clustering.py +15 -19
  31. sknetwork/clustering/tests/test_API.py +8 -4
  32. sknetwork/clustering/tests/test_kcenters.py +92 -0
  33. sknetwork/clustering/tests/test_leiden.py +34 -0
  34. sknetwork/clustering/tests/test_louvain.py +3 -4
  35. sknetwork/data/__init__.py +2 -1
  36. sknetwork/data/base.py +28 -0
  37. sknetwork/data/load.py +38 -37
  38. sknetwork/data/models.py +18 -18
  39. sknetwork/data/parse.py +54 -33
  40. sknetwork/data/test_graphs.py +2 -2
  41. sknetwork/data/tests/test_API.py +1 -1
  42. sknetwork/data/tests/test_base.py +14 -0
  43. sknetwork/data/tests/test_load.py +1 -1
  44. sknetwork/data/tests/test_parse.py +9 -12
  45. sknetwork/data/tests/test_test_graphs.py +1 -2
  46. sknetwork/data/toy_graphs.py +18 -18
  47. sknetwork/embedding/__init__.py +0 -1
  48. sknetwork/embedding/base.py +21 -20
  49. sknetwork/embedding/force_atlas.py +3 -2
  50. sknetwork/embedding/louvain_embedding.py +2 -2
  51. sknetwork/embedding/random_projection.py +5 -3
  52. sknetwork/embedding/spectral.py +0 -73
  53. sknetwork/embedding/tests/test_API.py +4 -28
  54. sknetwork/embedding/tests/test_louvain_embedding.py +4 -9
  55. sknetwork/embedding/tests/test_random_projection.py +2 -2
  56. sknetwork/embedding/tests/test_spectral.py +5 -8
  57. sknetwork/embedding/tests/test_svd.py +1 -1
  58. sknetwork/gnn/base.py +4 -4
  59. sknetwork/gnn/base_layer.py +3 -3
  60. sknetwork/gnn/gnn_classifier.py +45 -89
  61. sknetwork/gnn/layer.py +1 -1
  62. sknetwork/gnn/loss.py +1 -1
  63. sknetwork/gnn/optimizer.py +4 -3
  64. sknetwork/gnn/tests/test_base_layer.py +4 -4
  65. sknetwork/gnn/tests/test_gnn_classifier.py +12 -35
  66. sknetwork/gnn/utils.py +8 -8
  67. sknetwork/hierarchy/base.py +29 -2
  68. sknetwork/hierarchy/louvain_hierarchy.py +45 -41
  69. sknetwork/hierarchy/paris.cp38-win_amd64.pyd +0 -0
  70. sknetwork/hierarchy/paris.cpp +27371 -22844
  71. sknetwork/hierarchy/paris.pyx +7 -9
  72. sknetwork/hierarchy/postprocess.py +16 -16
  73. sknetwork/hierarchy/tests/test_API.py +1 -1
  74. sknetwork/hierarchy/tests/test_algos.py +5 -0
  75. sknetwork/hierarchy/tests/test_metrics.py +1 -1
  76. sknetwork/linalg/__init__.py +1 -1
  77. sknetwork/linalg/diteration.cp38-win_amd64.pyd +0 -0
  78. sknetwork/linalg/diteration.cpp +13474 -9454
  79. sknetwork/linalg/diteration.pyx +0 -2
  80. sknetwork/linalg/eig_solver.py +1 -1
  81. sknetwork/linalg/{normalization.py → normalizer.py} +18 -15
  82. sknetwork/linalg/operators.py +1 -1
  83. sknetwork/linalg/ppr_solver.py +1 -1
  84. sknetwork/linalg/push.cp38-win_amd64.pyd +0 -0
  85. sknetwork/linalg/push.cpp +23003 -18807
  86. sknetwork/linalg/push.pyx +0 -2
  87. sknetwork/linalg/svd_solver.py +1 -1
  88. sknetwork/linalg/tests/test_normalization.py +3 -7
  89. sknetwork/linalg/tests/test_operators.py +4 -8
  90. sknetwork/linalg/tests/test_ppr.py +1 -1
  91. sknetwork/linkpred/base.py +13 -2
  92. sknetwork/linkpred/nn.py +6 -6
  93. sknetwork/log.py +19 -0
  94. sknetwork/path/__init__.py +4 -3
  95. sknetwork/path/dag.py +54 -0
  96. sknetwork/path/distances.py +98 -0
  97. sknetwork/path/search.py +13 -47
  98. sknetwork/path/shortest_path.py +37 -162
  99. sknetwork/path/tests/test_dag.py +37 -0
  100. sknetwork/path/tests/test_distances.py +62 -0
  101. sknetwork/path/tests/test_search.py +26 -11
  102. sknetwork/path/tests/test_shortest_path.py +31 -36
  103. sknetwork/ranking/__init__.py +0 -1
  104. sknetwork/ranking/base.py +13 -8
  105. sknetwork/ranking/betweenness.cp38-win_amd64.pyd +0 -0
  106. sknetwork/ranking/betweenness.cpp +5709 -3017
  107. sknetwork/ranking/betweenness.pyx +0 -2
  108. sknetwork/ranking/closeness.py +7 -10
  109. sknetwork/ranking/pagerank.py +14 -14
  110. sknetwork/ranking/postprocess.py +12 -3
  111. sknetwork/ranking/tests/test_API.py +2 -4
  112. sknetwork/ranking/tests/test_betweenness.py +3 -3
  113. sknetwork/ranking/tests/test_closeness.py +3 -7
  114. sknetwork/ranking/tests/test_pagerank.py +11 -5
  115. sknetwork/ranking/tests/test_postprocess.py +5 -0
  116. sknetwork/regression/base.py +19 -2
  117. sknetwork/regression/diffusion.py +24 -10
  118. sknetwork/regression/tests/test_diffusion.py +8 -0
  119. sknetwork/test_base.py +35 -0
  120. sknetwork/test_log.py +15 -0
  121. sknetwork/topology/__init__.py +7 -8
  122. sknetwork/topology/cliques.cp38-win_amd64.pyd +0 -0
  123. sknetwork/topology/{kcliques.cpp → cliques.cpp} +23423 -20277
  124. sknetwork/topology/cliques.pyx +149 -0
  125. sknetwork/topology/core.cp38-win_amd64.pyd +0 -0
  126. sknetwork/topology/{kcore.cpp → core.cpp} +21637 -18762
  127. sknetwork/topology/core.pyx +90 -0
  128. sknetwork/topology/cycles.py +243 -0
  129. sknetwork/topology/minheap.cp38-win_amd64.pyd +0 -0
  130. sknetwork/{utils → topology}/minheap.cpp +19452 -15368
  131. sknetwork/{utils → topology}/minheap.pxd +1 -3
  132. sknetwork/{utils → topology}/minheap.pyx +1 -3
  133. sknetwork/topology/structure.py +3 -43
  134. sknetwork/topology/tests/test_cliques.py +11 -11
  135. sknetwork/topology/tests/test_core.py +19 -0
  136. sknetwork/topology/tests/test_cycles.py +65 -0
  137. sknetwork/topology/tests/test_structure.py +2 -16
  138. sknetwork/topology/tests/test_triangles.py +11 -15
  139. sknetwork/topology/tests/test_wl.py +72 -0
  140. sknetwork/topology/triangles.cp38-win_amd64.pyd +0 -0
  141. sknetwork/topology/triangles.cpp +5056 -2696
  142. sknetwork/topology/triangles.pyx +74 -89
  143. sknetwork/topology/weisfeiler_lehman.py +56 -86
  144. sknetwork/topology/weisfeiler_lehman_core.cp38-win_amd64.pyd +0 -0
  145. sknetwork/topology/weisfeiler_lehman_core.cpp +14727 -10622
  146. sknetwork/topology/weisfeiler_lehman_core.pyx +0 -2
  147. sknetwork/utils/__init__.py +1 -31
  148. sknetwork/utils/check.py +2 -2
  149. sknetwork/utils/format.py +5 -3
  150. sknetwork/utils/membership.py +2 -2
  151. sknetwork/utils/tests/test_check.py +3 -3
  152. sknetwork/utils/tests/test_format.py +3 -1
  153. sknetwork/utils/values.py +1 -1
  154. sknetwork/visualization/__init__.py +2 -2
  155. sknetwork/visualization/dendrograms.py +55 -7
  156. sknetwork/visualization/graphs.py +292 -72
  157. sknetwork/visualization/tests/test_dendrograms.py +9 -9
  158. sknetwork/visualization/tests/test_graphs.py +71 -62
  159. scikit_network-0.30.0.dist-info/RECORD +0 -227
  160. sknetwork/embedding/louvain_hierarchy.py +0 -142
  161. sknetwork/embedding/tests/test_louvain_hierarchy.py +0 -19
  162. sknetwork/path/metrics.py +0 -148
  163. sknetwork/path/tests/test_metrics.py +0 -29
  164. sknetwork/ranking/harmonic.py +0 -82
  165. sknetwork/topology/dag.py +0 -74
  166. sknetwork/topology/dag_core.cp38-win_amd64.pyd +0 -0
  167. sknetwork/topology/dag_core.cpp +0 -23350
  168. sknetwork/topology/dag_core.pyx +0 -38
  169. sknetwork/topology/kcliques.cp38-win_amd64.pyd +0 -0
  170. sknetwork/topology/kcliques.pyx +0 -193
  171. sknetwork/topology/kcore.cp38-win_amd64.pyd +0 -0
  172. sknetwork/topology/kcore.pyx +0 -120
  173. sknetwork/topology/tests/test_cores.py +0 -21
  174. sknetwork/topology/tests/test_dag.py +0 -26
  175. sknetwork/topology/tests/test_wl_coloring.py +0 -49
  176. sknetwork/topology/tests/test_wl_kernel.py +0 -31
  177. sknetwork/utils/base.py +0 -35
  178. sknetwork/utils/minheap.cp38-win_amd64.pyd +0 -0
  179. sknetwork/utils/simplex.py +0 -140
  180. sknetwork/utils/tests/test_base.py +0 -28
  181. sknetwork/utils/tests/test_bunch.py +0 -16
  182. sknetwork/utils/tests/test_projection_simplex.py +0 -33
  183. sknetwork/utils/tests/test_verbose.py +0 -15
  184. sknetwork/utils/verbose.py +0 -37
  185. {scikit_network-0.30.0.dist-info → scikit_network-0.32.1.dist-info}/LICENSE +0 -0
  186. {scikit_network-0.30.0.dist-info → scikit_network-0.32.1.dist-info}/top_level.txt +0 -0
  187. /sknetwork/{utils → data}/timeout.py +0 -0
@@ -1,9 +1,7 @@
1
1
  # distutils: language = c++
2
2
  # cython: language_level=3
3
- # cython: linetrace=True
4
- # distutils: define_macros=CYTHON_TRACE_NOGIL=1
5
3
  """
6
- Created on Jun 3, 2020
4
+ Created in June 2020
7
5
  @author: Julien Simonnet <julien.simonnet@etu.upmc.fr>
8
6
  @author: Yohann Robert <yohann.robert@etu.upmc.fr>
9
7
  """
@@ -1,9 +1,7 @@
1
1
  # distutils: language = c++
2
2
  # cython: language_level=3
3
- # cython: linetrace=True
4
- # distutils: define_macros=CYTHON_TRACE_NOGIL=1
5
3
  """
6
- Created on Jun 3, 2020
4
+ Created in June 2020
7
5
  @author: Julien Simonnet <julien.simonnet@etu.upmc.fr>
8
6
  @author: Yohann Robert <yohann.robert@etu.upmc.fr>
9
7
  """
@@ -1,18 +1,19 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
3
  """
4
- Created on July 24, 2019
4
+ Created in July 2019
5
5
  @author: Nathan de Lara <nathan.delara@polytechnique.org>
6
6
  @author: Quentin Lutz <qlutz@enst.fr>
7
7
  @author: Thomas Bonald <tbonald@enst.fr>
8
8
  """
9
- from typing import Tuple, Optional, Union
9
+ from typing import Tuple, Optional, Union, List
10
10
 
11
11
  import numpy as np
12
12
  from scipy import sparse
13
13
 
14
14
  from sknetwork.utils.check import is_symmetric, check_format
15
15
  from sknetwork.utils.format import get_adjacency
16
+ from sknetwork.path import get_distances
16
17
 
17
18
 
18
19
  def get_connected_components(input_matrix: sparse.csr_matrix, connection: str = 'weak', force_bipartite: bool = False) \
@@ -191,44 +192,3 @@ def is_bipartite(adjacency: sparse.csr_matrix, return_biadjacency: bool = False)
191
192
  return True
192
193
 
193
194
 
194
- def is_acyclic(adjacency: sparse.csr_matrix, directed: Optional[bool] = None) -> bool:
195
- """Check whether a graph has no cycle.
196
-
197
- Parameters
198
- ----------
199
- adjacency:
200
- Adjacency matrix of the graph.
201
- directed:
202
- Whether to consider the graph as directed (inferred if not specified).
203
- Returns
204
- -------
205
- is_acyclic : bool
206
- A boolean with value True if the graph has no cycle and False otherwise.
207
-
208
- Example
209
- -------
210
- >>> from sknetwork.topology import is_acyclic
211
- >>> from sknetwork.data import star, grid
212
- >>> is_acyclic(star())
213
- True
214
- >>> is_acyclic(grid())
215
- False
216
- """
217
- if directed is False:
218
- # the graph must be undirected
219
- if not is_symmetric(adjacency):
220
- raise ValueError("The adjacency matrix is not symmetric. The parameter 'directed' must be True.")
221
- elif directed is None:
222
- # if not specified, infer from the graph
223
- directed = not is_symmetric(adjacency)
224
- has_loops = (adjacency.diagonal() > 0).any()
225
- if has_loops:
226
- return False
227
- else:
228
- n_cc = sparse.csgraph.connected_components(adjacency, directed, connection='strong', return_labels=False)
229
- n_nodes = adjacency.shape[0]
230
- if directed:
231
- return n_cc == n_nodes
232
- else:
233
- n_edges = adjacency.nnz // 2
234
- return n_cc == n_nodes - n_edges
@@ -1,28 +1,28 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
- """Tests for k-cliques count"""
3
+ """Tests for cliques"""
4
4
  import unittest
5
5
 
6
6
  from scipy.special import comb
7
7
 
8
8
  from sknetwork.data.test_graphs import *
9
- from sknetwork.topology import Cliques
9
+ from sknetwork.topology.cliques import count_cliques
10
10
 
11
11
 
12
- class TestCliqueListing(unittest.TestCase):
12
+ class TestClique(unittest.TestCase):
13
13
 
14
14
  def test_empty(self):
15
15
  adjacency = test_graph_empty()
16
- self.assertEqual(Cliques(2).fit_transform(adjacency), 0)
17
- cliques = Cliques(1)
18
- self.assertRaises(ValueError, cliques.fit_transform, adjacency)
16
+ self.assertEqual(count_cliques(adjacency), 0)
17
+ with self.assertRaises(ValueError):
18
+ count_cliques(adjacency, 1)
19
19
 
20
20
  def test_disconnected(self):
21
- adjacency = test_graph_disconnect()
22
- self.assertEqual(Cliques(3).fit_transform(adjacency), 1)
21
+ adjacency = test_disconnected_graph()
22
+ self.assertEqual(count_cliques(adjacency), 1)
23
23
 
24
24
  def test_cliques(self):
25
- adjacency = test_graph_clique()
25
+ adjacency = test_clique()
26
26
  n = adjacency.shape[0]
27
- self.assertEqual(Cliques(3).fit_transform(adjacency), comb(n, 3, exact=True))
28
- self.assertEqual(Cliques(4).fit_transform(adjacency), comb(n, 4, exact=True))
27
+ self.assertEqual(count_cliques(adjacency), comb(n, 3, exact=True))
28
+ self.assertEqual(count_cliques(adjacency, 4), comb(n, 4, exact=True))
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Tests for k-core decomposition"""
4
+ import unittest
5
+
6
+ from sknetwork.data.test_graphs import *
7
+ from sknetwork.topology.core import get_core_decomposition
8
+
9
+
10
+ class TestCoreDecomposition(unittest.TestCase):
11
+
12
+ def test_empty(self):
13
+ adjacency = test_graph_empty()
14
+ self.assertEqual(max(get_core_decomposition(adjacency)), 0)
15
+
16
+ def test_cliques(self):
17
+ adjacency = test_clique()
18
+ n = adjacency.shape[0]
19
+ self.assertEqual(max(get_core_decomposition(adjacency)), n - 1)
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """"tests for cycles.py"""
4
+ import unittest
5
+
6
+ import numpy as np
7
+ from scipy import sparse
8
+
9
+ from sknetwork.data import star_wars, house, cyclic_digraph, cyclic_graph, linear_digraph, linear_graph
10
+ from sknetwork.topology import is_connected, is_acyclic, get_cycles, break_cycles
11
+ from sknetwork.utils.format import bipartite2undirected, directed2undirected
12
+
13
+
14
+ class TestCycle(unittest.TestCase):
15
+
16
+ def test_is_acyclic(self):
17
+ adjacency_with_self_loops = sparse.identity(2, format='csr')
18
+ self.assertFalse(is_acyclic(adjacency_with_self_loops))
19
+ self.assertFalse(is_acyclic(adjacency_with_self_loops, directed=True))
20
+ directed_cycle = cyclic_digraph(3)
21
+ self.assertFalse(is_acyclic(directed_cycle))
22
+ with self.assertRaises(ValueError):
23
+ is_acyclic(directed_cycle, directed=False)
24
+ undirected_line = linear_graph(2)
25
+ self.assertTrue(is_acyclic(undirected_line))
26
+ self.assertFalse(is_acyclic(undirected_line, directed=True))
27
+ acyclic_graph = linear_digraph(2)
28
+ self.assertTrue(is_acyclic(acyclic_graph))
29
+
30
+ def test_get_cycles(self):
31
+ adjacency_with_self_loops = sparse.identity(2, format='csr')
32
+ node_cycles = get_cycles(adjacency_with_self_loops, directed=True)
33
+ self.assertEqual(node_cycles, [[0], [1]])
34
+
35
+ cycle_adjacency = cyclic_digraph(4)
36
+ node_cycles = get_cycles(cycle_adjacency, directed=True)
37
+ self.assertEqual(sorted(node_cycles[0]), [0, 1, 2, 3])
38
+ adjacency_with_subcycles = cycle_adjacency + sparse.csr_matrix(([1], ([1], [3])), shape=cycle_adjacency.shape)
39
+ node_cycles = get_cycles(adjacency_with_subcycles, directed=True)
40
+ self.assertEqual(node_cycles, [[0, 1, 3], [0, 1, 2, 3]])
41
+
42
+ undirected_cycle = cyclic_graph(4)
43
+ node_cycles = get_cycles(undirected_cycle, directed=False)
44
+ self.assertEqual(sorted(node_cycles[0]), [0, 1, 2, 3])
45
+
46
+ disconnected_cycles = sparse.csr_matrix(([1, 1, 1], ([1, 2, 3], [2, 3, 1])), shape=(4, 4))
47
+ node_cycles = get_cycles(disconnected_cycles, directed=True)
48
+ self.assertEqual(sorted(node_cycles[0]), [1, 2, 3])
49
+
50
+ def test_break_cycles(self):
51
+ cycle_adjacency = cyclic_digraph(4)
52
+ acyclic_graph = break_cycles(cycle_adjacency, root=0, directed=True)
53
+ self.assertTrue(is_acyclic(acyclic_graph))
54
+ adjacency_with_subcycles = cycle_adjacency + sparse.csr_matrix(([1], ([1], [0])), shape=cycle_adjacency.shape)
55
+ acyclic_graph = break_cycles(adjacency_with_subcycles, root=0, directed=True)
56
+ self.assertTrue(is_acyclic(acyclic_graph))
57
+
58
+ undirected_cycle = house(metadata=False)
59
+ acyclic_graph = break_cycles(undirected_cycle, root=0, directed=False)
60
+ self.assertTrue(is_acyclic(acyclic_graph))
61
+
62
+ disconnected_cycles = sparse.csr_matrix(([1, 1, 1, 1, 1], ([0, 1, 2, 3, 4], [1, 0, 3, 4, 2])), shape=(5, 5))
63
+ self.assertFalse(is_connected(disconnected_cycles))
64
+ acyclic_graph = break_cycles(disconnected_cycles, root=[0, 2], directed=True)
65
+ self.assertTrue(is_acyclic(acyclic_graph))
@@ -6,9 +6,9 @@ import unittest
6
6
  import numpy as np
7
7
  from scipy import sparse
8
8
 
9
- from sknetwork.data import star_wars, cyclic_digraph, linear_digraph, linear_graph
9
+ from sknetwork.data import star_wars, house, cyclic_digraph, cyclic_graph, linear_digraph, linear_graph
10
10
  from sknetwork.topology import get_connected_components, get_largest_connected_component
11
- from sknetwork.topology import is_connected, is_bipartite, is_acyclic
11
+ from sknetwork.topology import is_connected, is_bipartite
12
12
  from sknetwork.utils.format import bipartite2undirected, directed2undirected
13
13
 
14
14
 
@@ -83,17 +83,3 @@ class TestStructure(unittest.TestCase):
83
83
  adjacency = directed2undirected(cyclic_digraph(3))
84
84
  bipartite = is_bipartite(adjacency, return_biadjacency=False)
85
85
  self.assertEqual(bipartite, False)
86
-
87
- def test_is_acyclic(self):
88
- adjacency_with_self_loops = sparse.identity(2, format='csr')
89
- self.assertFalse(is_acyclic(adjacency_with_self_loops))
90
- self.assertFalse(is_acyclic(adjacency_with_self_loops, directed=True))
91
- directed_cycle = cyclic_digraph(3)
92
- self.assertFalse(is_acyclic(directed_cycle))
93
- with self.assertRaises(ValueError):
94
- is_acyclic(directed_cycle, directed=False)
95
- undirected_line = linear_graph(2)
96
- self.assertTrue(is_acyclic(undirected_line))
97
- self.assertFalse(is_acyclic(undirected_line, directed=True))
98
- acyclic_graph = linear_digraph(2)
99
- self.assertTrue(is_acyclic(acyclic_graph))
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
- """Tests for label propagation"""
3
+ """Tests for triangle counting"""
4
4
 
5
5
  import unittest
6
6
 
@@ -9,34 +9,30 @@ from scipy.special import comb
9
9
  from sknetwork.data import karate_club
10
10
  from sknetwork.data.parse import from_edge_list
11
11
  from sknetwork.data.test_graphs import *
12
- from sknetwork.topology import Triangles
12
+ from sknetwork.topology.triangles import count_triangles, get_clustering_coefficient
13
13
 
14
14
 
15
- class TestTriangleListing(unittest.TestCase):
15
+ class TestTriangle(unittest.TestCase):
16
16
 
17
17
  def test_empty(self):
18
18
  adjacency = test_graph_empty()
19
- self.assertEqual(Triangles().fit_transform(adjacency), 0)
19
+ self.assertEqual(count_triangles(adjacency), 0)
20
20
 
21
21
  def test_disconnected(self):
22
- adjacency = test_graph_disconnect()
23
- self.assertEqual(Triangles().fit_transform(adjacency), 1)
22
+ adjacency = test_disconnected_graph()
23
+ self.assertEqual(count_triangles(adjacency), 1)
24
24
 
25
25
  def test_cliques(self):
26
- adjacency = test_graph_clique()
26
+ adjacency = test_clique()
27
27
  n = adjacency.shape[0]
28
- nb = Triangles().fit_transform(adjacency)
29
- self.assertEqual(nb, comb(n, 3, exact=True))
28
+ self.assertEqual(count_triangles(adjacency), comb(n, 3, exact=True))
30
29
 
31
30
  def test_clustering_coefficient(self):
32
31
  edges = [(0, 1), (1, 2), (2, 3), (3, 0), (0, 2)]
33
32
  adjacency = from_edge_list(edges, directed=False, matrix_only=True)
34
-
35
- triangles = Triangles().fit(adjacency)
36
- self.assertEqual(0.75, triangles.clustering_coef_)
33
+ self.assertEqual(0.75, get_clustering_coefficient(adjacency))
37
34
 
38
35
  def test_options(self):
39
36
  adjacency = karate_club()
40
-
41
- self.assertEqual(Triangles(parallelize=False).fit_transform(adjacency), 45)
42
- self.assertEqual(Triangles(parallelize=True).fit_transform(adjacency), 45)
37
+ self.assertEqual(count_triangles(adjacency, parallelize=False), 45)
38
+ self.assertEqual(count_triangles(adjacency, parallelize=True), 45)
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """Tests for Weisfeiler-Lehman"""
4
+ import unittest
5
+
6
+ import numpy as np
7
+
8
+ from sknetwork.data import house, bow_tie, linear_graph
9
+ from sknetwork.data.test_graphs import *
10
+ from sknetwork.topology import color_weisfeiler_lehman, are_isomorphic
11
+
12
+
13
+ class TestWLKernel(unittest.TestCase):
14
+
15
+ def test_isomorphism(self):
16
+ ref = house()
17
+ n = ref.shape[0]
18
+
19
+ adjacency = house()
20
+ reorder = list(range(n))
21
+ np.random.shuffle(reorder)
22
+ adjacency = adjacency[reorder][:, reorder]
23
+ self.assertTrue(are_isomorphic(ref, adjacency))
24
+
25
+ adjacency = bow_tie()
26
+ self.assertFalse(are_isomorphic(ref, adjacency))
27
+
28
+ adjacency = linear_graph(n)
29
+ self.assertFalse(are_isomorphic(ref, adjacency))
30
+
31
+ adjacency = linear_graph(n + 1)
32
+ self.assertFalse(are_isomorphic(ref, adjacency))
33
+
34
+
35
+ class TestWLColoring(unittest.TestCase):
36
+
37
+ def test_empty(self):
38
+ adjacency = test_graph_empty()
39
+ labels = color_weisfeiler_lehman(adjacency)
40
+ self.assertTrue((labels == np.zeros(10)).all())
41
+
42
+ def test_cliques(self):
43
+ adjacency = test_clique()
44
+ labels = color_weisfeiler_lehman(adjacency)
45
+ self.assertTrue((labels == np.zeros(10)).all())
46
+
47
+ def test_house(self):
48
+ adjacency = house()
49
+ labels = color_weisfeiler_lehman(adjacency)
50
+ self.assertTrue((labels == np.array([0, 2, 1, 1, 2])).all())
51
+
52
+ def test_bow_tie(self):
53
+ adjacency = bow_tie()
54
+ labels = color_weisfeiler_lehman(adjacency)
55
+ self.assertTrue((labels == np.array([1, 0, 0, 0, 0])).all())
56
+
57
+ def test_iso(self):
58
+ adjacency = house()
59
+ n = adjacency.indptr.shape[0] - 1
60
+ reorder = list(range(n))
61
+ np.random.shuffle(reorder)
62
+ adjacency2 = adjacency[reorder][:, reorder]
63
+ l1 = color_weisfeiler_lehman(adjacency)
64
+ l2 = color_weisfeiler_lehman(adjacency2)
65
+ l1.sort()
66
+ l2.sort()
67
+ self.assertTrue((l1 == l2).all())
68
+
69
+ def test_early_stop(self):
70
+ adjacency = house()
71
+ labels = color_weisfeiler_lehman(adjacency, max_iter=1)
72
+ self.assertTrue((labels == np.array([0, 1, 0, 0, 1])).all())