scikit-network 0.33.4__cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.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.
Files changed (229) hide show
  1. scikit_network-0.33.4.dist-info/METADATA +122 -0
  2. scikit_network-0.33.4.dist-info/RECORD +229 -0
  3. scikit_network-0.33.4.dist-info/WHEEL +6 -0
  4. scikit_network-0.33.4.dist-info/licenses/AUTHORS.rst +43 -0
  5. scikit_network-0.33.4.dist-info/licenses/LICENSE +34 -0
  6. scikit_network-0.33.4.dist-info/top_level.txt +1 -0
  7. scikit_network.libs/libgomp-a34b3233.so.1.0.0 +0 -0
  8. sknetwork/__init__.py +21 -0
  9. sknetwork/base.py +67 -0
  10. sknetwork/classification/__init__.py +8 -0
  11. sknetwork/classification/base.py +138 -0
  12. sknetwork/classification/base_rank.py +129 -0
  13. sknetwork/classification/diffusion.py +127 -0
  14. sknetwork/classification/knn.py +131 -0
  15. sknetwork/classification/metrics.py +205 -0
  16. sknetwork/classification/pagerank.py +58 -0
  17. sknetwork/classification/propagation.py +144 -0
  18. sknetwork/classification/tests/__init__.py +1 -0
  19. sknetwork/classification/tests/test_API.py +30 -0
  20. sknetwork/classification/tests/test_diffusion.py +77 -0
  21. sknetwork/classification/tests/test_knn.py +23 -0
  22. sknetwork/classification/tests/test_metrics.py +53 -0
  23. sknetwork/classification/tests/test_pagerank.py +20 -0
  24. sknetwork/classification/tests/test_propagation.py +24 -0
  25. sknetwork/classification/vote.cpp +27593 -0
  26. sknetwork/classification/vote.cpython-312-x86_64-linux-gnu.so +0 -0
  27. sknetwork/classification/vote.pyx +56 -0
  28. sknetwork/clustering/__init__.py +8 -0
  29. sknetwork/clustering/base.py +168 -0
  30. sknetwork/clustering/kcenters.py +251 -0
  31. sknetwork/clustering/leiden.py +238 -0
  32. sknetwork/clustering/leiden_core.cpp +31928 -0
  33. sknetwork/clustering/leiden_core.cpython-312-x86_64-linux-gnu.so +0 -0
  34. sknetwork/clustering/leiden_core.pyx +124 -0
  35. sknetwork/clustering/louvain.py +282 -0
  36. sknetwork/clustering/louvain_core.cpp +31573 -0
  37. sknetwork/clustering/louvain_core.cpython-312-x86_64-linux-gnu.so +0 -0
  38. sknetwork/clustering/louvain_core.pyx +124 -0
  39. sknetwork/clustering/metrics.py +91 -0
  40. sknetwork/clustering/postprocess.py +66 -0
  41. sknetwork/clustering/propagation_clustering.py +100 -0
  42. sknetwork/clustering/tests/__init__.py +1 -0
  43. sknetwork/clustering/tests/test_API.py +38 -0
  44. sknetwork/clustering/tests/test_kcenters.py +60 -0
  45. sknetwork/clustering/tests/test_leiden.py +34 -0
  46. sknetwork/clustering/tests/test_louvain.py +135 -0
  47. sknetwork/clustering/tests/test_metrics.py +50 -0
  48. sknetwork/clustering/tests/test_postprocess.py +39 -0
  49. sknetwork/data/__init__.py +6 -0
  50. sknetwork/data/base.py +33 -0
  51. sknetwork/data/load.py +292 -0
  52. sknetwork/data/models.py +459 -0
  53. sknetwork/data/parse.py +644 -0
  54. sknetwork/data/test_graphs.py +93 -0
  55. sknetwork/data/tests/__init__.py +1 -0
  56. sknetwork/data/tests/test_API.py +30 -0
  57. sknetwork/data/tests/test_base.py +14 -0
  58. sknetwork/data/tests/test_load.py +61 -0
  59. sknetwork/data/tests/test_models.py +52 -0
  60. sknetwork/data/tests/test_parse.py +250 -0
  61. sknetwork/data/tests/test_test_graphs.py +29 -0
  62. sknetwork/data/tests/test_toy_graphs.py +68 -0
  63. sknetwork/data/timeout.py +38 -0
  64. sknetwork/data/toy_graphs.py +611 -0
  65. sknetwork/embedding/__init__.py +8 -0
  66. sknetwork/embedding/base.py +90 -0
  67. sknetwork/embedding/force_atlas.py +198 -0
  68. sknetwork/embedding/louvain_embedding.py +142 -0
  69. sknetwork/embedding/random_projection.py +131 -0
  70. sknetwork/embedding/spectral.py +137 -0
  71. sknetwork/embedding/spring.py +198 -0
  72. sknetwork/embedding/svd.py +351 -0
  73. sknetwork/embedding/tests/__init__.py +1 -0
  74. sknetwork/embedding/tests/test_API.py +49 -0
  75. sknetwork/embedding/tests/test_force_atlas.py +35 -0
  76. sknetwork/embedding/tests/test_louvain_embedding.py +33 -0
  77. sknetwork/embedding/tests/test_random_projection.py +28 -0
  78. sknetwork/embedding/tests/test_spectral.py +81 -0
  79. sknetwork/embedding/tests/test_spring.py +50 -0
  80. sknetwork/embedding/tests/test_svd.py +43 -0
  81. sknetwork/gnn/__init__.py +10 -0
  82. sknetwork/gnn/activation.py +117 -0
  83. sknetwork/gnn/base.py +181 -0
  84. sknetwork/gnn/base_activation.py +90 -0
  85. sknetwork/gnn/base_layer.py +109 -0
  86. sknetwork/gnn/gnn_classifier.py +305 -0
  87. sknetwork/gnn/layer.py +153 -0
  88. sknetwork/gnn/loss.py +180 -0
  89. sknetwork/gnn/neighbor_sampler.py +65 -0
  90. sknetwork/gnn/optimizer.py +164 -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 +75 -0
  94. sknetwork/gnn/tests/test_base_layer.py +37 -0
  95. sknetwork/gnn/tests/test_gnn_classifier.py +130 -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 +41 -0
  101. sknetwork/gnn/utils.py +127 -0
  102. sknetwork/hierarchy/__init__.py +6 -0
  103. sknetwork/hierarchy/base.py +90 -0
  104. sknetwork/hierarchy/louvain_hierarchy.py +260 -0
  105. sknetwork/hierarchy/metrics.py +234 -0
  106. sknetwork/hierarchy/paris.cpp +37877 -0
  107. sknetwork/hierarchy/paris.cpython-312-x86_64-linux-gnu.so +0 -0
  108. sknetwork/hierarchy/paris.pyx +310 -0
  109. sknetwork/hierarchy/postprocess.py +350 -0
  110. sknetwork/hierarchy/tests/__init__.py +1 -0
  111. sknetwork/hierarchy/tests/test_API.py +24 -0
  112. sknetwork/hierarchy/tests/test_algos.py +34 -0
  113. sknetwork/hierarchy/tests/test_metrics.py +62 -0
  114. sknetwork/hierarchy/tests/test_postprocess.py +57 -0
  115. sknetwork/linalg/__init__.py +9 -0
  116. sknetwork/linalg/basics.py +37 -0
  117. sknetwork/linalg/diteration.cpp +27409 -0
  118. sknetwork/linalg/diteration.cpython-312-x86_64-linux-gnu.so +0 -0
  119. sknetwork/linalg/diteration.pyx +47 -0
  120. sknetwork/linalg/eig_solver.py +93 -0
  121. sknetwork/linalg/laplacian.py +15 -0
  122. sknetwork/linalg/normalizer.py +86 -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.cpp +31081 -0
  127. sknetwork/linalg/push.cpython-312-x86_64-linux-gnu.so +0 -0
  128. sknetwork/linalg/push.pyx +71 -0
  129. sknetwork/linalg/sparse_lowrank.py +142 -0
  130. sknetwork/linalg/svd_solver.py +91 -0
  131. sknetwork/linalg/tests/__init__.py +1 -0
  132. sknetwork/linalg/tests/test_eig.py +44 -0
  133. sknetwork/linalg/tests/test_laplacian.py +18 -0
  134. sknetwork/linalg/tests/test_normalization.py +34 -0
  135. sknetwork/linalg/tests/test_operators.py +66 -0
  136. sknetwork/linalg/tests/test_polynome.py +38 -0
  137. sknetwork/linalg/tests/test_ppr.py +50 -0
  138. sknetwork/linalg/tests/test_sparse_lowrank.py +61 -0
  139. sknetwork/linalg/tests/test_svd.py +38 -0
  140. sknetwork/linkpred/__init__.py +2 -0
  141. sknetwork/linkpred/base.py +46 -0
  142. sknetwork/linkpred/nn.py +126 -0
  143. sknetwork/linkpred/tests/__init__.py +1 -0
  144. sknetwork/linkpred/tests/test_nn.py +26 -0
  145. sknetwork/log.py +19 -0
  146. sknetwork/path/__init__.py +5 -0
  147. sknetwork/path/dag.py +54 -0
  148. sknetwork/path/distances.py +98 -0
  149. sknetwork/path/search.py +31 -0
  150. sknetwork/path/shortest_path.py +61 -0
  151. sknetwork/path/tests/__init__.py +1 -0
  152. sknetwork/path/tests/test_dag.py +37 -0
  153. sknetwork/path/tests/test_distances.py +62 -0
  154. sknetwork/path/tests/test_search.py +40 -0
  155. sknetwork/path/tests/test_shortest_path.py +40 -0
  156. sknetwork/ranking/__init__.py +8 -0
  157. sknetwork/ranking/base.py +57 -0
  158. sknetwork/ranking/betweenness.cpp +9716 -0
  159. sknetwork/ranking/betweenness.cpython-312-x86_64-linux-gnu.so +0 -0
  160. sknetwork/ranking/betweenness.pyx +97 -0
  161. sknetwork/ranking/closeness.py +92 -0
  162. sknetwork/ranking/hits.py +90 -0
  163. sknetwork/ranking/katz.py +79 -0
  164. sknetwork/ranking/pagerank.py +106 -0
  165. sknetwork/ranking/postprocess.py +37 -0
  166. sknetwork/ranking/tests/__init__.py +1 -0
  167. sknetwork/ranking/tests/test_API.py +32 -0
  168. sknetwork/ranking/tests/test_betweenness.py +38 -0
  169. sknetwork/ranking/tests/test_closeness.py +30 -0
  170. sknetwork/ranking/tests/test_hits.py +20 -0
  171. sknetwork/ranking/tests/test_pagerank.py +62 -0
  172. sknetwork/ranking/tests/test_postprocess.py +26 -0
  173. sknetwork/regression/__init__.py +4 -0
  174. sknetwork/regression/base.py +57 -0
  175. sknetwork/regression/diffusion.py +204 -0
  176. sknetwork/regression/tests/__init__.py +1 -0
  177. sknetwork/regression/tests/test_API.py +32 -0
  178. sknetwork/regression/tests/test_diffusion.py +56 -0
  179. sknetwork/sknetwork.py +3 -0
  180. sknetwork/test_base.py +35 -0
  181. sknetwork/test_log.py +15 -0
  182. sknetwork/topology/__init__.py +8 -0
  183. sknetwork/topology/cliques.cpp +32574 -0
  184. sknetwork/topology/cliques.cpython-312-x86_64-linux-gnu.so +0 -0
  185. sknetwork/topology/cliques.pyx +149 -0
  186. sknetwork/topology/core.cpp +30660 -0
  187. sknetwork/topology/core.cpython-312-x86_64-linux-gnu.so +0 -0
  188. sknetwork/topology/core.pyx +90 -0
  189. sknetwork/topology/cycles.py +243 -0
  190. sknetwork/topology/minheap.cpp +27341 -0
  191. sknetwork/topology/minheap.cpython-312-x86_64-linux-gnu.so +0 -0
  192. sknetwork/topology/minheap.pxd +20 -0
  193. sknetwork/topology/minheap.pyx +109 -0
  194. sknetwork/topology/structure.py +194 -0
  195. sknetwork/topology/tests/__init__.py +1 -0
  196. sknetwork/topology/tests/test_cliques.py +28 -0
  197. sknetwork/topology/tests/test_core.py +19 -0
  198. sknetwork/topology/tests/test_cycles.py +65 -0
  199. sknetwork/topology/tests/test_structure.py +85 -0
  200. sknetwork/topology/tests/test_triangles.py +38 -0
  201. sknetwork/topology/tests/test_wl.py +72 -0
  202. sknetwork/topology/triangles.cpp +8903 -0
  203. sknetwork/topology/triangles.cpython-312-x86_64-linux-gnu.so +0 -0
  204. sknetwork/topology/triangles.pyx +151 -0
  205. sknetwork/topology/weisfeiler_lehman.py +133 -0
  206. sknetwork/topology/weisfeiler_lehman_core.cpp +27644 -0
  207. sknetwork/topology/weisfeiler_lehman_core.cpython-312-x86_64-linux-gnu.so +0 -0
  208. sknetwork/topology/weisfeiler_lehman_core.pyx +114 -0
  209. sknetwork/utils/__init__.py +7 -0
  210. sknetwork/utils/check.py +355 -0
  211. sknetwork/utils/format.py +221 -0
  212. sknetwork/utils/membership.py +82 -0
  213. sknetwork/utils/neighbors.py +115 -0
  214. sknetwork/utils/tests/__init__.py +1 -0
  215. sknetwork/utils/tests/test_check.py +190 -0
  216. sknetwork/utils/tests/test_format.py +63 -0
  217. sknetwork/utils/tests/test_membership.py +24 -0
  218. sknetwork/utils/tests/test_neighbors.py +41 -0
  219. sknetwork/utils/tests/test_tfidf.py +18 -0
  220. sknetwork/utils/tests/test_values.py +66 -0
  221. sknetwork/utils/tfidf.py +37 -0
  222. sknetwork/utils/values.py +76 -0
  223. sknetwork/visualization/__init__.py +4 -0
  224. sknetwork/visualization/colors.py +34 -0
  225. sknetwork/visualization/dendrograms.py +277 -0
  226. sknetwork/visualization/graphs.py +1039 -0
  227. sknetwork/visualization/tests/__init__.py +1 -0
  228. sknetwork/visualization/tests/test_dendrograms.py +53 -0
  229. sknetwork/visualization/tests/test_graphs.py +176 -0
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created in March 2024
5
+ @author: Thomas Bonald <bonald@enst.fr>
6
+ @author: Ahmed Zaiou <ahmed.zaiou@capgemini.com>
7
+ """
8
+ from typing import Union, Optional
9
+
10
+ import numpy as np
11
+ from scipy import sparse
12
+
13
+ from sknetwork.clustering import Louvain
14
+ from sknetwork.clustering.louvain_core import optimize_core
15
+ from sknetwork.clustering.leiden_core import optimize_refine_core
16
+ from sknetwork.utils.membership import get_membership
17
+ from sknetwork.utils.check import check_random_state
18
+ from sknetwork.log import Log
19
+
20
+
21
+ class Leiden(Louvain):
22
+ """Leiden algorithm for clustering graphs by maximization of modularity.
23
+ Compared to the Louvain algorithm, the partition is refined before each aggregation.
24
+
25
+ For bipartite graphs, the algorithm maximizes Barber's modularity by default.
26
+
27
+ Parameters
28
+ ----------
29
+ resolution :
30
+ Resolution parameter.
31
+ modularity : str
32
+ Type of modularity to maximize. Can be ``'Dugue'``, ``'Newman'`` or ``'Potts'`` (default = ``'dugue'``).
33
+ tol_optimization :
34
+ Minimum increase in modularity to enter a new optimization pass in the local search.
35
+ tol_aggregation :
36
+ Minimum increase in modularity to enter a new aggregation pass.
37
+ n_aggregations :
38
+ Maximum number of aggregations.
39
+ A negative value is interpreted as no limit.
40
+ shuffle_nodes :
41
+ Enables node shuffling before optimization.
42
+ sort_clusters :
43
+ If ``True``, sort labels in decreasing order of cluster size.
44
+ return_probs :
45
+ If ``True``, return the probability distribution over clusters (soft clustering).
46
+ return_aggregate :
47
+ If ``True``, return the adjacency matrix of the graph between clusters.
48
+ random_state :
49
+ Random number generator or random seed. If None, numpy.random is used.
50
+ verbose :
51
+ Verbose mode.
52
+
53
+ Attributes
54
+ ----------
55
+ labels\_ : np.ndarray, shape (n_nodes,)
56
+ Label of each node.
57
+ probs\_ : sparse.csr_matrix, shape (n_nodes, n_labels)
58
+ Probability distribution over labels.
59
+ aggregate\_ : sparse.csr_matrix
60
+ Aggregate adjacency matrix or biadjacency matrix between clusters.
61
+
62
+ Example
63
+ -------
64
+ >>> from sknetwork.clustering import Leiden
65
+ >>> from sknetwork.data import karate_club
66
+ >>> leiden = Leiden()
67
+ >>> adjacency = karate_club()
68
+ >>> labels = leiden.fit_predict(adjacency)
69
+ >>> len(set(labels))
70
+ 4
71
+
72
+ References
73
+ ----------
74
+ * Traag, V. A., Waltman, L., & Van Eck, N. J. (2019).
75
+ `From Louvain to Leiden: guaranteeing well-connected communities`, Scientific reports.
76
+
77
+ """
78
+
79
+ def __init__(self, resolution: float = 1, modularity: str = 'dugue', tol_optimization: float = 1e-3,
80
+ tol_aggregation: float = 1e-3, n_aggregations: int = -1, shuffle_nodes: bool = False,
81
+ sort_clusters: bool = True, return_probs: bool = True, return_aggregate: bool = True,
82
+ random_state: Optional[Union[np.random.RandomState, int]] = None, verbose: bool = False):
83
+ super(Leiden, self).__init__(sort_clusters=sort_clusters, return_probs=return_probs,
84
+ return_aggregate=return_aggregate)
85
+ Log.__init__(self, verbose)
86
+
87
+ self.labels_ = None
88
+ self.resolution = resolution
89
+ self.modularity = modularity.lower()
90
+ self.tol_optimization = tol_optimization
91
+ self.tol_aggregation = tol_aggregation
92
+ self.n_aggregations = n_aggregations
93
+ self.shuffle_nodes = shuffle_nodes
94
+ self.random_state = check_random_state(random_state)
95
+ self.bipartite = None
96
+
97
+ def _optimize(self, labels, adjacency, out_weights, in_weights):
98
+ """One optimization pass of the Leiden algorithm.
99
+
100
+ Parameters
101
+ ----------
102
+ labels :
103
+ Labels of nodes.
104
+ adjacency :
105
+ Adjacency matrix.
106
+ out_weights :
107
+ Out-weights of nodes.
108
+ in_weights :
109
+ In-weights of nodes
110
+
111
+ Returns
112
+ -------
113
+ labels :
114
+ Labels of nodes after optimization.
115
+ increase :
116
+ Gain in modularity after optimization.
117
+ """
118
+ indices = adjacency.indices
119
+ indptr = adjacency.indptr
120
+ data = adjacency.data.astype(np.float32)
121
+ out_weights = out_weights.astype(np.float32)
122
+ in_weights = in_weights.astype(np.float32)
123
+ membership = get_membership(labels)
124
+ out_cluster_weights = membership.T.dot(out_weights)
125
+ in_cluster_weights = membership.T.dot(in_weights)
126
+ cluster_weights = np.zeros_like(out_cluster_weights).astype(np.float32)
127
+ labels = labels.astype(np.int32)
128
+ self_loops = adjacency.diagonal().astype(np.float32)
129
+ return optimize_core(labels, indices, indptr, data, out_weights, in_weights, out_cluster_weights,
130
+ in_cluster_weights, cluster_weights, self_loops, self.resolution, self.tol_optimization)
131
+
132
+ def _optimize_refine(self, labels, labels_refined, adjacency, out_weights, in_weights):
133
+ """Get the refined partition optimizing modularity.
134
+
135
+ Parameters
136
+ ----------
137
+ labels :
138
+ Labels of nodes.
139
+ labels_refined :
140
+ Refined labels of nodes.
141
+ adjacency :
142
+ Adjacency matrix.
143
+ out_weights :
144
+ Out-weights of nodes.
145
+ in_weights :
146
+ In-weights of nodes
147
+
148
+ Returns
149
+ -------
150
+ labels_refined :
151
+ Refined labels of nodes.
152
+ """
153
+ indices = adjacency.indices
154
+ indptr = adjacency.indptr
155
+ data = adjacency.data.astype(np.float32)
156
+ out_weights = out_weights.astype(np.float32)
157
+ in_weights = in_weights.astype(np.float32)
158
+ membership = get_membership(labels_refined)
159
+ out_cluster_weights = membership.T.dot(out_weights)
160
+ in_cluster_weights = membership.T.dot(in_weights)
161
+ cluster_weights = np.zeros_like(out_cluster_weights).astype(np.float32)
162
+ self_loops = adjacency.diagonal().astype(np.float32)
163
+ labels = labels.astype(np.int32)
164
+ labels_refined = labels_refined.astype(np.int32)
165
+ return optimize_refine_core(labels, labels_refined, indices, indptr, data, out_weights, in_weights,
166
+ out_cluster_weights, in_cluster_weights, cluster_weights, self_loops,
167
+ self.resolution)
168
+
169
+ @staticmethod
170
+ def _aggregate_refine(labels, labels_refined, adjacency, out_weights, in_weights):
171
+ """Aggregate nodes according to refined labels.
172
+
173
+ Parameters
174
+ ----------
175
+ labels :
176
+ Labels of nodes.
177
+ labels_refined :
178
+ Refined labels of nodes.
179
+ adjacency :
180
+ Adjacency matrix.
181
+ out_weights :
182
+ Out-weights of nodes.
183
+ in_weights :
184
+ In-weights of nodes.
185
+
186
+ Returns
187
+ -------
188
+ Aggregate graph (labels, adjacency matrix, out-weights, in-weights).
189
+ """
190
+ membership = get_membership(labels)
191
+ membership_refined = get_membership(labels_refined)
192
+ adjacency_ = membership_refined.T.tocsr().dot(adjacency.dot(membership_refined))
193
+ out_weights_ = membership_refined.T.dot(out_weights)
194
+ in_weights_ = membership_refined.T.dot(in_weights)
195
+ labels_ = membership_refined.T.tocsr().dot(membership).indices
196
+ return labels_, adjacency_, out_weights_, in_weights_
197
+
198
+ def fit(self, input_matrix: Union[sparse.csr_matrix, np.ndarray], force_bipartite: bool = False) -> 'Leiden':
199
+ """Fit algorithm to data.
200
+
201
+ Parameters
202
+ ----------
203
+ input_matrix :
204
+ Adjacency matrix or biadjacency matrix of the graph.
205
+ force_bipartite :
206
+ If ``True``, force the input matrix to be considered as a biadjacency matrix even if square.
207
+
208
+ Returns
209
+ -------
210
+ self : :class:`Leiden`
211
+ """
212
+ adjacency, out_weights, in_weights, membership, index = self._pre_processing(input_matrix, force_bipartite)
213
+ n = adjacency.shape[0]
214
+ labels = np.arange(n)
215
+ count = 0
216
+ stop = False
217
+ while not stop:
218
+ count += 1
219
+ labels, increase = self._optimize(labels, adjacency, out_weights, in_weights)
220
+ _, labels = np.unique(labels, return_inverse=True)
221
+ labels_original = labels.copy()
222
+ labels_refined = np.arange(len(labels))
223
+ labels_refined = self._optimize_refine(labels, labels_refined, adjacency, out_weights, in_weights)
224
+ _, labels_refined = np.unique(labels_refined, return_inverse=True)
225
+ labels, adjacency, out_weights, in_weights = self._aggregate_refine(labels, labels_refined, adjacency,
226
+ out_weights, in_weights)
227
+ n = adjacency.shape[0]
228
+ stop = n == 1
229
+ stop |= increase <= self.tol_aggregation
230
+ stop |= count == self.n_aggregations
231
+ if stop:
232
+ membership = membership.dot(get_membership(labels_original))
233
+ else:
234
+ membership = membership.dot(get_membership(labels_refined))
235
+ self.print_log("Aggregation:", count, " Clusters:", n, " Increase:", increase)
236
+
237
+ self._post_processing(input_matrix, membership, index)
238
+ return self