scikit-network 0.28.3__cp39-cp39-macosx_12_0_arm64.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 (240) hide show
  1. scikit_network-0.28.3.dist-info/AUTHORS.rst +41 -0
  2. scikit_network-0.28.3.dist-info/LICENSE +34 -0
  3. scikit_network-0.28.3.dist-info/METADATA +457 -0
  4. scikit_network-0.28.3.dist-info/RECORD +240 -0
  5. scikit_network-0.28.3.dist-info/WHEEL +5 -0
  6. scikit_network-0.28.3.dist-info/top_level.txt +1 -0
  7. sknetwork/__init__.py +21 -0
  8. sknetwork/classification/__init__.py +8 -0
  9. sknetwork/classification/base.py +84 -0
  10. sknetwork/classification/base_rank.py +143 -0
  11. sknetwork/classification/diffusion.py +134 -0
  12. sknetwork/classification/knn.py +162 -0
  13. sknetwork/classification/metrics.py +205 -0
  14. sknetwork/classification/pagerank.py +66 -0
  15. sknetwork/classification/propagation.py +152 -0
  16. sknetwork/classification/tests/__init__.py +1 -0
  17. sknetwork/classification/tests/test_API.py +35 -0
  18. sknetwork/classification/tests/test_diffusion.py +37 -0
  19. sknetwork/classification/tests/test_knn.py +24 -0
  20. sknetwork/classification/tests/test_metrics.py +53 -0
  21. sknetwork/classification/tests/test_pagerank.py +20 -0
  22. sknetwork/classification/tests/test_propagation.py +24 -0
  23. sknetwork/classification/vote.cpython-39-darwin.so +0 -0
  24. sknetwork/classification/vote.pyx +58 -0
  25. sknetwork/clustering/__init__.py +7 -0
  26. sknetwork/clustering/base.py +102 -0
  27. sknetwork/clustering/kmeans.py +142 -0
  28. sknetwork/clustering/louvain.py +255 -0
  29. sknetwork/clustering/louvain_core.cpython-39-darwin.so +0 -0
  30. sknetwork/clustering/louvain_core.pyx +134 -0
  31. sknetwork/clustering/metrics.py +91 -0
  32. sknetwork/clustering/postprocess.py +66 -0
  33. sknetwork/clustering/propagation_clustering.py +108 -0
  34. sknetwork/clustering/tests/__init__.py +1 -0
  35. sknetwork/clustering/tests/test_API.py +37 -0
  36. sknetwork/clustering/tests/test_kmeans.py +47 -0
  37. sknetwork/clustering/tests/test_louvain.py +104 -0
  38. sknetwork/clustering/tests/test_metrics.py +50 -0
  39. sknetwork/clustering/tests/test_post_processing.py +23 -0
  40. sknetwork/clustering/tests/test_postprocess.py +39 -0
  41. sknetwork/data/__init__.py +5 -0
  42. sknetwork/data/load.py +408 -0
  43. sknetwork/data/models.py +459 -0
  44. sknetwork/data/parse.py +621 -0
  45. sknetwork/data/test_graphs.py +84 -0
  46. sknetwork/data/tests/__init__.py +1 -0
  47. sknetwork/data/tests/test_API.py +30 -0
  48. sknetwork/data/tests/test_load.py +95 -0
  49. sknetwork/data/tests/test_models.py +52 -0
  50. sknetwork/data/tests/test_parse.py +253 -0
  51. sknetwork/data/tests/test_test_graphs.py +30 -0
  52. sknetwork/data/tests/test_toy_graphs.py +68 -0
  53. sknetwork/data/toy_graphs.py +619 -0
  54. sknetwork/embedding/__init__.py +10 -0
  55. sknetwork/embedding/base.py +90 -0
  56. sknetwork/embedding/force_atlas.py +197 -0
  57. sknetwork/embedding/louvain_embedding.py +174 -0
  58. sknetwork/embedding/louvain_hierarchy.py +142 -0
  59. sknetwork/embedding/metrics.py +66 -0
  60. sknetwork/embedding/random_projection.py +133 -0
  61. sknetwork/embedding/spectral.py +214 -0
  62. sknetwork/embedding/spring.py +198 -0
  63. sknetwork/embedding/svd.py +363 -0
  64. sknetwork/embedding/tests/__init__.py +1 -0
  65. sknetwork/embedding/tests/test_API.py +73 -0
  66. sknetwork/embedding/tests/test_force_atlas.py +35 -0
  67. sknetwork/embedding/tests/test_louvain_embedding.py +33 -0
  68. sknetwork/embedding/tests/test_louvain_hierarchy.py +19 -0
  69. sknetwork/embedding/tests/test_metrics.py +29 -0
  70. sknetwork/embedding/tests/test_random_projection.py +28 -0
  71. sknetwork/embedding/tests/test_spectral.py +84 -0
  72. sknetwork/embedding/tests/test_spring.py +50 -0
  73. sknetwork/embedding/tests/test_svd.py +37 -0
  74. sknetwork/flow/__init__.py +3 -0
  75. sknetwork/flow/flow.py +73 -0
  76. sknetwork/flow/tests/__init__.py +1 -0
  77. sknetwork/flow/tests/test_flow.py +17 -0
  78. sknetwork/flow/tests/test_utils.py +69 -0
  79. sknetwork/flow/utils.py +91 -0
  80. sknetwork/gnn/__init__.py +10 -0
  81. sknetwork/gnn/activation.py +117 -0
  82. sknetwork/gnn/base.py +155 -0
  83. sknetwork/gnn/base_activation.py +89 -0
  84. sknetwork/gnn/base_layer.py +109 -0
  85. sknetwork/gnn/gnn_classifier.py +381 -0
  86. sknetwork/gnn/layer.py +153 -0
  87. sknetwork/gnn/layers.py +127 -0
  88. sknetwork/gnn/loss.py +180 -0
  89. sknetwork/gnn/neighbor_sampler.py +65 -0
  90. sknetwork/gnn/optimizer.py +163 -0
  91. sknetwork/gnn/tests/__init__.py +1 -0
  92. sknetwork/gnn/tests/test_activation.py +56 -0
  93. sknetwork/gnn/tests/test_base.py +79 -0
  94. sknetwork/gnn/tests/test_base_layer.py +37 -0
  95. sknetwork/gnn/tests/test_gnn_classifier.py +192 -0
  96. sknetwork/gnn/tests/test_layers.py +80 -0
  97. sknetwork/gnn/tests/test_loss.py +33 -0
  98. sknetwork/gnn/tests/test_neigh_sampler.py +23 -0
  99. sknetwork/gnn/tests/test_optimizer.py +43 -0
  100. sknetwork/gnn/tests/test_utils.py +93 -0
  101. sknetwork/gnn/utils.py +219 -0
  102. sknetwork/hierarchy/__init__.py +7 -0
  103. sknetwork/hierarchy/base.py +69 -0
  104. sknetwork/hierarchy/louvain_hierarchy.py +264 -0
  105. sknetwork/hierarchy/metrics.py +234 -0
  106. sknetwork/hierarchy/paris.cpython-39-darwin.so +0 -0
  107. sknetwork/hierarchy/paris.pyx +317 -0
  108. sknetwork/hierarchy/postprocess.py +350 -0
  109. sknetwork/hierarchy/tests/__init__.py +1 -0
  110. sknetwork/hierarchy/tests/test_API.py +25 -0
  111. sknetwork/hierarchy/tests/test_algos.py +29 -0
  112. sknetwork/hierarchy/tests/test_metrics.py +62 -0
  113. sknetwork/hierarchy/tests/test_postprocess.py +57 -0
  114. sknetwork/hierarchy/tests/test_ward.py +25 -0
  115. sknetwork/hierarchy/ward.py +94 -0
  116. sknetwork/linalg/__init__.py +9 -0
  117. sknetwork/linalg/basics.py +37 -0
  118. sknetwork/linalg/diteration.cpython-39-darwin.so +0 -0
  119. sknetwork/linalg/diteration.pyx +49 -0
  120. sknetwork/linalg/eig_solver.py +93 -0
  121. sknetwork/linalg/laplacian.py +15 -0
  122. sknetwork/linalg/normalization.py +66 -0
  123. sknetwork/linalg/operators.py +225 -0
  124. sknetwork/linalg/polynome.py +76 -0
  125. sknetwork/linalg/ppr_solver.py +170 -0
  126. sknetwork/linalg/push.cpython-39-darwin.so +0 -0
  127. sknetwork/linalg/push.pyx +73 -0
  128. sknetwork/linalg/sparse_lowrank.py +142 -0
  129. sknetwork/linalg/svd_solver.py +91 -0
  130. sknetwork/linalg/tests/__init__.py +1 -0
  131. sknetwork/linalg/tests/test_eig.py +44 -0
  132. sknetwork/linalg/tests/test_laplacian.py +18 -0
  133. sknetwork/linalg/tests/test_normalization.py +38 -0
  134. sknetwork/linalg/tests/test_operators.py +70 -0
  135. sknetwork/linalg/tests/test_polynome.py +38 -0
  136. sknetwork/linalg/tests/test_ppr.py +50 -0
  137. sknetwork/linalg/tests/test_sparse_lowrank.py +61 -0
  138. sknetwork/linalg/tests/test_svd.py +38 -0
  139. sknetwork/linkpred/__init__.py +4 -0
  140. sknetwork/linkpred/base.py +80 -0
  141. sknetwork/linkpred/first_order.py +508 -0
  142. sknetwork/linkpred/first_order_core.cpython-39-darwin.so +0 -0
  143. sknetwork/linkpred/first_order_core.pyx +315 -0
  144. sknetwork/linkpred/postprocessing.py +98 -0
  145. sknetwork/linkpred/tests/__init__.py +1 -0
  146. sknetwork/linkpred/tests/test_API.py +49 -0
  147. sknetwork/linkpred/tests/test_postprocessing.py +21 -0
  148. sknetwork/path/__init__.py +4 -0
  149. sknetwork/path/metrics.py +148 -0
  150. sknetwork/path/search.py +65 -0
  151. sknetwork/path/shortest_path.py +186 -0
  152. sknetwork/path/tests/__init__.py +1 -0
  153. sknetwork/path/tests/test_metrics.py +29 -0
  154. sknetwork/path/tests/test_search.py +25 -0
  155. sknetwork/path/tests/test_shortest_path.py +45 -0
  156. sknetwork/ranking/__init__.py +9 -0
  157. sknetwork/ranking/base.py +56 -0
  158. sknetwork/ranking/betweenness.cpython-39-darwin.so +0 -0
  159. sknetwork/ranking/betweenness.pyx +99 -0
  160. sknetwork/ranking/closeness.py +95 -0
  161. sknetwork/ranking/harmonic.py +82 -0
  162. sknetwork/ranking/hits.py +94 -0
  163. sknetwork/ranking/katz.py +81 -0
  164. sknetwork/ranking/pagerank.py +107 -0
  165. sknetwork/ranking/postprocess.py +25 -0
  166. sknetwork/ranking/tests/__init__.py +1 -0
  167. sknetwork/ranking/tests/test_API.py +34 -0
  168. sknetwork/ranking/tests/test_betweenness.py +38 -0
  169. sknetwork/ranking/tests/test_closeness.py +34 -0
  170. sknetwork/ranking/tests/test_hits.py +20 -0
  171. sknetwork/ranking/tests/test_pagerank.py +69 -0
  172. sknetwork/regression/__init__.py +4 -0
  173. sknetwork/regression/base.py +56 -0
  174. sknetwork/regression/diffusion.py +190 -0
  175. sknetwork/regression/tests/__init__.py +1 -0
  176. sknetwork/regression/tests/test_API.py +34 -0
  177. sknetwork/regression/tests/test_diffusion.py +48 -0
  178. sknetwork/sknetwork.py +3 -0
  179. sknetwork/topology/__init__.py +9 -0
  180. sknetwork/topology/dag.py +74 -0
  181. sknetwork/topology/dag_core.cpython-39-darwin.so +0 -0
  182. sknetwork/topology/dag_core.pyx +38 -0
  183. sknetwork/topology/kcliques.cpython-39-darwin.so +0 -0
  184. sknetwork/topology/kcliques.pyx +193 -0
  185. sknetwork/topology/kcore.cpython-39-darwin.so +0 -0
  186. sknetwork/topology/kcore.pyx +120 -0
  187. sknetwork/topology/structure.py +234 -0
  188. sknetwork/topology/tests/__init__.py +1 -0
  189. sknetwork/topology/tests/test_cliques.py +28 -0
  190. sknetwork/topology/tests/test_cores.py +21 -0
  191. sknetwork/topology/tests/test_dag.py +26 -0
  192. sknetwork/topology/tests/test_structure.py +99 -0
  193. sknetwork/topology/tests/test_triangles.py +42 -0
  194. sknetwork/topology/tests/test_wl_coloring.py +49 -0
  195. sknetwork/topology/tests/test_wl_kernel.py +31 -0
  196. sknetwork/topology/triangles.cpython-39-darwin.so +0 -0
  197. sknetwork/topology/triangles.pyx +166 -0
  198. sknetwork/topology/weisfeiler_lehman.py +163 -0
  199. sknetwork/topology/weisfeiler_lehman_core.cpython-39-darwin.so +0 -0
  200. sknetwork/topology/weisfeiler_lehman_core.pyx +116 -0
  201. sknetwork/utils/__init__.py +40 -0
  202. sknetwork/utils/base.py +35 -0
  203. sknetwork/utils/check.py +354 -0
  204. sknetwork/utils/co_neighbor.py +71 -0
  205. sknetwork/utils/format.py +219 -0
  206. sknetwork/utils/kmeans.py +89 -0
  207. sknetwork/utils/knn.py +166 -0
  208. sknetwork/utils/knn1d.cpython-39-darwin.so +0 -0
  209. sknetwork/utils/knn1d.pyx +80 -0
  210. sknetwork/utils/membership.py +82 -0
  211. sknetwork/utils/minheap.cpython-39-darwin.so +0 -0
  212. sknetwork/utils/minheap.pxd +22 -0
  213. sknetwork/utils/minheap.pyx +111 -0
  214. sknetwork/utils/neighbors.py +115 -0
  215. sknetwork/utils/seeds.py +75 -0
  216. sknetwork/utils/simplex.py +140 -0
  217. sknetwork/utils/tests/__init__.py +1 -0
  218. sknetwork/utils/tests/test_base.py +28 -0
  219. sknetwork/utils/tests/test_bunch.py +16 -0
  220. sknetwork/utils/tests/test_check.py +190 -0
  221. sknetwork/utils/tests/test_co_neighbor.py +43 -0
  222. sknetwork/utils/tests/test_format.py +61 -0
  223. sknetwork/utils/tests/test_kmeans.py +21 -0
  224. sknetwork/utils/tests/test_knn.py +32 -0
  225. sknetwork/utils/tests/test_membership.py +24 -0
  226. sknetwork/utils/tests/test_neighbors.py +41 -0
  227. sknetwork/utils/tests/test_projection_simplex.py +33 -0
  228. sknetwork/utils/tests/test_seeds.py +67 -0
  229. sknetwork/utils/tests/test_verbose.py +15 -0
  230. sknetwork/utils/tests/test_ward.py +20 -0
  231. sknetwork/utils/timeout.py +38 -0
  232. sknetwork/utils/verbose.py +37 -0
  233. sknetwork/utils/ward.py +60 -0
  234. sknetwork/visualization/__init__.py +4 -0
  235. sknetwork/visualization/colors.py +34 -0
  236. sknetwork/visualization/dendrograms.py +229 -0
  237. sknetwork/visualization/graphs.py +819 -0
  238. sknetwork/visualization/tests/__init__.py +1 -0
  239. sknetwork/visualization/tests/test_dendrograms.py +53 -0
  240. sknetwork/visualization/tests/test_graphs.py +167 -0
@@ -0,0 +1,166 @@
1
+ # distutils: language = c++
2
+ # cython: language_level=3
3
+ # cython: linetrace=True
4
+ # distutils: define_macros=CYTHON_TRACE_NOGIL=1
5
+ """
6
+ Created on Jun 3, 2020
7
+ @author: Julien Simonnet <julien.simonnet@etu.upmc.fr>
8
+ @author: Yohann Robert <yohann.robert@etu.upmc.fr>
9
+ @author: Nathan de Lara <nathan.delara@polytechnique.org>
10
+ """
11
+ from libcpp.vector cimport vector
12
+ from scipy import sparse
13
+ from scipy.special import comb
14
+ from cython.parallel import prange
15
+
16
+ from sknetwork.topology.dag import DAG
17
+ from sknetwork.utils.base import Algorithm
18
+
19
+ cimport cython
20
+
21
+
22
+ @cython.boundscheck(False)
23
+ @cython.wraparound(False)
24
+ cdef long count_local_triangles(int source, vector[int] indptr, vector[int] indices) nogil:
25
+ """Counts the number of nodes in the intersection of a node and its neighbors in a DAG.
26
+
27
+ Parameters
28
+ ----------
29
+ source :
30
+ Index of the node to study.
31
+ indptr :
32
+ CSR format index pointer array of the normalized adjacency matrix of a DAG.
33
+ indices :
34
+ CSR format index array of the normalized adjacency matrix of a DAG.
35
+
36
+ Returns
37
+ -------
38
+ n_triangles :
39
+ Number of nodes in the intersection
40
+ """
41
+ cdef int i, j, k
42
+ cdef int v
43
+ cdef long n_triangles = 0 # number of nodes in the intersection
44
+
45
+ for k in range(indptr[source], indptr[source+1]):
46
+ v = indices[k]
47
+ i = indptr[source]
48
+ j = indptr[v]
49
+
50
+ # calculates the intersection of the neighbors of u and v
51
+ while (i < indptr[source+1]) and (j < indptr[v+1]):
52
+ if indices[i] == indices[j]:
53
+ i += 1
54
+ j += 1
55
+ n_triangles += 1
56
+ else :
57
+ if indices[i] < indices[j]:
58
+ i += 1
59
+ else :
60
+ j += 1
61
+
62
+ return n_triangles
63
+
64
+
65
+ @cython.boundscheck(False)
66
+ @cython.wraparound(False)
67
+ cdef long fit_core(vector[int] indptr, vector[int] indices, bint parallelize):
68
+ """Counts the number of triangles directly without exporting the graph.
69
+
70
+ Parameters
71
+ ----------
72
+ indptr :
73
+ CSR format index pointer array of the normalized adjacency matrix of a DAG.
74
+ indices :
75
+ CSR format index array of the normalized adjacency matrix of a DAG.
76
+ parallelize :
77
+ If ``True``, use a parallel range to count triangles.
78
+
79
+ Returns
80
+ -------
81
+ n_triangles :
82
+ Number of triangles in the graph
83
+ """
84
+ cdef int n = indptr.size() - 1
85
+ cdef int u
86
+ cdef long n_triangles = 0
87
+
88
+ if parallelize:
89
+ for u in prange(n, nogil=True):
90
+ n_triangles += count_local_triangles(u, indptr, indices)
91
+ else:
92
+ for u in range(n):
93
+ n_triangles += count_local_triangles(u, indptr, indices)
94
+
95
+ return n_triangles
96
+
97
+
98
+ class Triangles(Algorithm):
99
+ """Count the number of triangles in a graph, and evaluate the clustering coefficient.
100
+
101
+ * Graphs
102
+
103
+ Parameters
104
+ ----------
105
+ parallelize :
106
+ If ``True``, use a parallel range while listing the triangles.
107
+
108
+ Attributes
109
+ ----------
110
+ n_triangles_ : int
111
+ Number of triangles.
112
+ clustering_coef_ : float
113
+ Global clustering coefficient of the graph.
114
+
115
+ Example
116
+ -------
117
+ >>> from sknetwork.data import karate_club
118
+ >>> triangles = Triangles()
119
+ >>> adjacency = karate_club()
120
+ >>> triangles.fit_transform(adjacency)
121
+ 45
122
+ """
123
+ def __init__(self, parallelize : bool = False):
124
+ super(Triangles, self).__init__()
125
+ self.parallelize = parallelize
126
+ self.n_triangles_ = None
127
+ self.clustering_coef_ = None
128
+
129
+ def fit(self, adjacency: sparse.csr_matrix) -> 'Triangles':
130
+ """Count triangles.
131
+
132
+ Parameters
133
+ ----------
134
+ adjacency :
135
+ Adjacency matrix of the graph.
136
+
137
+ Returns
138
+ -------
139
+ self: :class:`Triangles`
140
+ """
141
+ degrees = adjacency.indptr[1:] - adjacency.indptr[:-1]
142
+ edge_pairs = comb(degrees, 2).sum()
143
+
144
+ dag = DAG(ordering='degree')
145
+ dag.fit(adjacency)
146
+ indptr = dag.indptr_
147
+ indices = dag.indices_
148
+
149
+ self.n_triangles_ = fit_core(indptr, indices, self.parallelize)
150
+ if edge_pairs > 0:
151
+ self.clustering_coef_ = 3 * self.n_triangles_ / edge_pairs
152
+ else:
153
+ self.clustering_coef_ = 0.
154
+
155
+ return self
156
+
157
+ def fit_transform(self, adjacency: sparse.csr_matrix) -> int:
158
+ """ Fit algorithm to the data and return the number of triangles. Same parameters as the ``fit`` method.
159
+
160
+ Returns
161
+ -------
162
+ n_triangles_ : int
163
+ Number of triangles.
164
+ """
165
+ self.fit(adjacency)
166
+ return self.n_triangles_
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on July 2, 2020
5
+ @author: Pierre Pebereau <pierre.pebereau@telecom-paris.fr>
6
+ @author: Alexis Barreaux <alexis.barreaux@telecom-paris.fr>
7
+ """
8
+ from typing import Union
9
+
10
+ import numpy as np
11
+ from scipy import sparse
12
+ from sknetwork.topology.weisfeiler_lehman_core import weisfeiler_lehman_coloring
13
+
14
+ from sknetwork.utils.base import Algorithm
15
+
16
+
17
+ class WeisfeilerLehman(Algorithm):
18
+ """Weisfeiler-Lehman algorithm for coloring/labeling graphs in order to check similarity.
19
+
20
+ Parameters
21
+ ----------
22
+ max_iter : int
23
+ Maximum number of iterations. Negative value means until convergence.
24
+
25
+ Attributes
26
+ ----------
27
+ labels_ : np.ndarray
28
+ Label of each node.
29
+
30
+ Example
31
+ -------
32
+ >>> from sknetwork.topology import WeisfeilerLehman
33
+ >>> from sknetwork.data import house
34
+ >>> weisfeiler_lehman = WeisfeilerLehman()
35
+ >>> adjacency = house()
36
+ >>> labels = weisfeiler_lehman.fit_transform(adjacency)
37
+ >>> labels
38
+ array([0, 2, 1, 1, 2], dtype=int32)
39
+
40
+ References
41
+ ----------
42
+ * Douglas, B. L. (2011).
43
+ `The Weisfeiler-Lehman Method and Graph Isomorphism Testing.
44
+ <https://arxiv.org/pdf/1101.5211.pdf>`_
45
+
46
+ * Shervashidze, N., Schweitzer, P., van Leeuwen, E. J., Melhorn, K., Borgwardt, K. M. (2011)
47
+ `Weisfeiler-Lehman graph kernels.
48
+ <http://www.jmlr.org/papers/volume12/shervashidze11a/shervashidze11a.pdf>`_
49
+ Journal of Machine Learning Research 12, 2011.
50
+ """
51
+ def __init__(self, max_iter: int = -1):
52
+ super(WeisfeilerLehman, self).__init__()
53
+ self.max_iter = max_iter
54
+ self.labels_ = None
55
+
56
+ def fit(self, adjacency: Union[sparse.csr_matrix, np.ndarray]) -> 'WeisfeilerLehman':
57
+ """Fit algorithm to the data.
58
+
59
+ Parameters
60
+ ----------
61
+ adjacency : Union[sparse.csr_matrix, np.ndarray]
62
+ Adjacency matrix of the graph.
63
+
64
+ Returns
65
+ -------
66
+ self: :class:`WeisfeilerLehman`
67
+ """
68
+ n: int = adjacency.shape[0]
69
+ if self.max_iter < 0 or self.max_iter > n:
70
+ max_iter = np.int32(n)
71
+ else:
72
+ max_iter = np.int32(self.max_iter)
73
+
74
+ labels = np.zeros(n, dtype=np.int32)
75
+ powers = (-np.pi / 3.15) ** np.arange(n, dtype=np.double)
76
+ indptr = adjacency.indptr.astype(np.int32)
77
+ indices = adjacency.indices.astype(np.int32)
78
+
79
+ labels, _ = weisfeiler_lehman_coloring(indptr, indices, labels, powers, max_iter)
80
+ self.labels_ = np.asarray(labels).astype(np.int32)
81
+ return self
82
+
83
+ def fit_transform(self, adjacency: Union[sparse.csr_matrix, np.ndarray]) -> np.ndarray:
84
+ """Fit algorithm to the data and return the labels. Same parameters as the ``fit`` method.
85
+
86
+ Returns
87
+ -------
88
+ labels : np.ndarray
89
+ Labels.
90
+ """
91
+ self.fit(adjacency)
92
+ return self.labels_
93
+
94
+
95
+ def are_isomorphic(adjacency1: sparse.csr_matrix,
96
+ adjacency2: sparse.csr_matrix, max_iter: int = -1) -> bool:
97
+ """Weisfeiler-Lehman isomorphism test. If the test is False, the graphs cannot be isomorphic,
98
+ otherwise, they might be.
99
+
100
+ Parameters
101
+ -----------
102
+ adjacency1 :
103
+ First adjacency matrix.
104
+ adjacency2 :
105
+ Second adjacency matrix.
106
+ max_iter : int
107
+ Maximum number of coloring iterations. Negative value means until convergence.
108
+
109
+ Returns
110
+ -------
111
+ test_result : bool
112
+
113
+ Example
114
+ -------
115
+ >>> from sknetwork.topology import are_isomorphic
116
+ >>> from sknetwork.data import house, bow_tie
117
+ >>> are_isomorphic(house(), bow_tie())
118
+ False
119
+
120
+ References
121
+ ----------
122
+ * Douglas, B. L. (2011).
123
+ `The Weisfeiler-Lehman Method and Graph Isomorphism Testing.
124
+ <https://arxiv.org/pdf/1101.5211.pdf>`_
125
+
126
+ * Shervashidze, N., Schweitzer, P., van Leeuwen, E. J., Melhorn, K., Borgwardt, K. M. (2011)
127
+ `Weisfeiler-Lehman graph kernels.
128
+ <http://www.jmlr.org/papers/volume12/shervashidze11a/shervashidze11a.pdf>`_
129
+ Journal of Machine Learning Research 12, 2011.
130
+ """
131
+ if (adjacency1.shape != adjacency2.shape) or (adjacency1.nnz != adjacency2.nnz):
132
+ return False
133
+
134
+ n = adjacency1.shape[0]
135
+
136
+ if max_iter < 0 or max_iter > n:
137
+ max_iter = n
138
+
139
+ indptr1 = adjacency1.indptr.astype(np.int32)
140
+ indptr2 = adjacency2.indptr.astype(np.int32)
141
+ indices1 = adjacency1.indices.astype(np.int32)
142
+ indices2 = adjacency2.indices.astype(np.int32)
143
+
144
+ labels_1 = np.zeros(n, dtype=np.int32)
145
+ labels_2 = np.zeros(n, dtype=np.int32)
146
+
147
+ powers = (- np.pi / 3.15) ** np.arange(n, dtype=np.double)
148
+
149
+ iteration = 0
150
+ has_changed_1, has_changed_2 = True, True
151
+ while iteration < max_iter and (has_changed_1 or has_changed_2):
152
+ labels_1, has_changed_1 = weisfeiler_lehman_coloring(indptr1, indices1, labels_1, powers, max_iter=1)
153
+ labels_2, has_changed_2 = weisfeiler_lehman_coloring(indptr2, indices2, labels_2, powers, max_iter=1)
154
+
155
+ colors_1, counts_1 = np.unique(np.asarray(labels_1), return_counts=True)
156
+ colors_2, counts_2 = np.unique(np.asarray(labels_2), return_counts=True)
157
+
158
+ if (colors_1.shape != colors_2.shape) or (counts_1 != counts_2).any():
159
+ return False
160
+
161
+ iteration += 1
162
+
163
+ return True
@@ -0,0 +1,116 @@
1
+ # distutils: language = c++
2
+ # cython: language_level=3
3
+ # cython: linetrace=True
4
+ # distutils: define_macros=CYTHON_TRACE_NOGIL=1
5
+ """
6
+ Created on July 1, 2020
7
+ @author: Pierre Pebereau <pierre.pebereau@telecom-paris.fr>
8
+ @author: Alexis Barreaux <alexis.barreaux@telecom-paris.fr>
9
+ """
10
+ from libcpp.vector cimport vector
11
+ from libc.math cimport pow
12
+ cimport cython
13
+
14
+ ctypedef (int, double, int) ctuple
15
+
16
+ cdef extern from "<algorithm>" namespace "std":
17
+ # fixed sort as per https://stackoverflow.com/questions/57584909/unable-to-use-cdef-function-in-stdsort-as-comparison-function
18
+ void sort(...)
19
+ void csort "sort"(...)
20
+
21
+ cdef bint is_lower(ctuple a, ctuple b) :
22
+ """Lexicographic comparison between triplets based on the first two values.
23
+
24
+ Parameters
25
+ ----------
26
+ a:
27
+ First triplet.
28
+ b:
29
+ Second triplet.
30
+
31
+ Returns
32
+ -------
33
+ ``True`` if a < b, and ``False`` otherwise.
34
+ """
35
+ cdef int a1, b1
36
+ cdef double a2, b2
37
+
38
+ a1, a2, _ = a
39
+ b1, b2, _ = b
40
+ if a1 == b1 :
41
+ return a2 < b2
42
+ return a1 < b1
43
+
44
+
45
+ @cython.boundscheck(False)
46
+ @cython.wraparound(False)
47
+ def weisfeiler_lehman_coloring(int[:] indptr, int[:] indices, int[:] labels, double [:] powers, int max_iter):
48
+ """Weisfeiler-Lehman coloring.
49
+
50
+ Parameters
51
+ ----------
52
+ indptr :
53
+ Indptr of the CSR.
54
+ indices :
55
+ Indices of the CSR.
56
+ labels : int[:]
57
+ Labels to be changed.
58
+ powers : double [:]
59
+ Powers being used as hash and put in a memory view to limit several identical calculations.
60
+ max_iter : int
61
+ Maximum number of iterations.
62
+
63
+ Returns
64
+ -------
65
+ labels : int[:]
66
+ Colors of the nodes.
67
+ has_changed : bint
68
+ True if the output labels are not the same as the input ones. False otherwise.
69
+ """
70
+ cdef int n = indptr.shape[0] -1
71
+ cdef int iteration = 0
72
+ cdef int i, j, j1, j2, jj, label
73
+
74
+ cdef double epsilon = pow(10, -10)
75
+
76
+ cdef vector[ctuple] new_labels
77
+ cdef ctuple tuple_ref, tuple_new
78
+ cdef double hash_ref, hash_new
79
+ cdef int label_ref, label_new
80
+
81
+ cdef bint has_changed = True
82
+
83
+ while iteration < max_iter and has_changed:
84
+ new_labels.clear()
85
+ has_changed = False
86
+
87
+ for i in range(n):
88
+ hash_ref = 0
89
+ j1 = indptr[i]
90
+ j2 = indptr[i + 1]
91
+
92
+ for jj in range(j1, j2):
93
+ j = indices[jj]
94
+ hash_ref += powers[labels[j]]
95
+
96
+ new_labels.push_back((labels[i], hash_ref, i))
97
+ csort(new_labels.begin(), new_labels.end(), is_lower)
98
+ label = 0
99
+ tuple_new = new_labels[0]
100
+ labels[tuple_new[2]] = label
101
+ for j in range(1, n):
102
+ tuple_ref = tuple_new
103
+ tuple_new = new_labels[j]
104
+ label_ref, hash_ref, _ = tuple_ref
105
+ label_new, hash_new, i = tuple_new
106
+
107
+ if abs(hash_new - hash_ref) > epsilon or label_new != label_ref :
108
+ label += 1
109
+
110
+ if labels[i] != label:
111
+ has_changed = True
112
+
113
+ labels[i] = label
114
+ iteration += 1
115
+
116
+ return labels, has_changed
@@ -0,0 +1,40 @@
1
+ """utils module"""
2
+ from sknetwork.utils.check import is_symmetric
3
+ from sknetwork.utils.co_neighbor import co_neighbor_graph
4
+ from sknetwork.utils.format import *
5
+ from sknetwork.utils.kmeans import KMeansDense
6
+ from sknetwork.utils.knn import KNNDense, CNNDense
7
+ from sknetwork.utils.membership import get_membership, from_membership
8
+ from sknetwork.utils.neighbors import get_neighbors, get_degrees, get_weights
9
+ from sknetwork.utils.simplex import projection_simplex, projection_simplex_array, projection_simplex_csr
10
+ from sknetwork.utils.ward import WardDense
11
+
12
+
13
+ class Bunch(dict):
14
+ """Container object for datasets.
15
+ Dictionary-like object that exposes its keys as attributes.
16
+
17
+ This code is taken from scikit-learn.
18
+ >>> bunch = Bunch(a=1, b=2)
19
+ >>> bunch['a']
20
+ 1
21
+ >>> bunch.a
22
+ 1
23
+ >>> bunch.b = 3
24
+ >>> bunch['b']
25
+ 3
26
+ >>> bunch.c = 4
27
+ >>> bunch['c']
28
+ 4
29
+ """
30
+ def __init__(self, **kwargs):
31
+ super().__init__(kwargs)
32
+
33
+ def __setattr__(self, key, value):
34
+ self[key] = value
35
+
36
+ def __getattr__(self, key):
37
+ try:
38
+ return self[key]
39
+ except KeyError:
40
+ raise AttributeError(key)
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Jun 28, 2019
5
+ @author: Quentin Lutz <qlutz@enst.fr>
6
+ """
7
+ import inspect
8
+
9
+
10
+ class Algorithm:
11
+ """Base class for all algorithms."""
12
+ def __repr__(self):
13
+ # parameters not to display
14
+ arg_black_list = ['self', 'random_state', 'verbose']
15
+ output = self.__class__.__name__ + '('
16
+ signature = inspect.signature(self.__class__.__init__)
17
+ arguments = [arg.name for arg in signature.parameters.values() if arg.name not in arg_black_list]
18
+ for p in arguments:
19
+ try:
20
+ val = self.__dict__[p]
21
+ except KeyError:
22
+ continue
23
+ if type(val) == str:
24
+ val = "'" + val + "'"
25
+ else:
26
+ val = str(val)
27
+ output += p + '=' + val + ', '
28
+ if output[-1] != '(':
29
+ return output[:-2] + ')'
30
+ else:
31
+ return output + ')'
32
+
33
+ def fit(self, *args, **kwargs):
34
+ """Fit Algorithm to the data."""
35
+ raise NotImplementedError