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,37 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Apr 2020
5
+ @author: Nathan de Lara <nathan.delara@polytechnique.org>
6
+ """
7
+
8
+ import numpy as np
9
+ from scipy import sparse
10
+ from scipy.sparse.linalg import LinearOperator
11
+
12
+
13
+ def safe_sparse_dot(a, b):
14
+ """Dot product with proper use of the sparse matrix format.
15
+ Use BLAS instead of numpy.dot when possible to avoid unnecessary copies.
16
+
17
+ Parameters
18
+ ----------
19
+ a : array, sparse matrix or LinearOperator
20
+ b : array, sparse matrix or LinearOperator
21
+ Returns
22
+ -------
23
+ dot_product : array or sparse matrix
24
+ sparse if ``a`` or ``b`` is sparse.
25
+ """
26
+ if type(a) == np.ndarray:
27
+ return b.T.dot(a.T).T
28
+ if isinstance(a, LinearOperator) and isinstance(b, LinearOperator):
29
+ raise NotImplementedError
30
+ if hasattr(a, 'right_sparse_dot') and type(b) == sparse.csr_matrix:
31
+ if callable(a.right_sparse_dot):
32
+ return a.right_sparse_dot(b)
33
+ if hasattr(b, 'left_sparse_dot') and type(a) == sparse.csr_matrix:
34
+ if callable(b.left_sparse_dot):
35
+ return b.left_sparse_dot(a)
36
+ else:
37
+ return a.dot(b)
@@ -0,0 +1,49 @@
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 Apr 2020
7
+ @author: Nathan de Lara <nathan.delara@polytechnique.org>
8
+ """
9
+ cimport cython
10
+ from cython.parallel import prange
11
+
12
+
13
+ @cython.boundscheck(False)
14
+ @cython.wraparound(False)
15
+ def diffusion(int[:] indptr, int[:] indices, float[:] data, float[:] scores, float[:] fluid,
16
+ float damping_factor, int n_iter, float tol):
17
+ """One loop of fluid diffusion."""
18
+ cdef int n = fluid.shape[0]
19
+ cdef int i
20
+ cdef int j
21
+ cdef int j1
22
+ cdef int j2
23
+ cdef int jj
24
+ cdef float sent
25
+ cdef float tmp
26
+ cdef float removed
27
+ cdef float restart_prob = 1 - damping_factor
28
+ cdef float residu = restart_prob
29
+
30
+ for k in range(n_iter):
31
+ for i in prange(n, nogil=True, schedule='guided'):
32
+ sent = fluid[i]
33
+ if sent > 0:
34
+ scores[i] += sent
35
+ fluid[i] = 0
36
+ j1 = indptr[i]
37
+ j2 = indptr[i+1]
38
+ tmp = sent * damping_factor
39
+ if j2 != j1:
40
+ for jj in range(j1, j2):
41
+ j = indices[jj]
42
+ fluid[j] += tmp * data[jj]
43
+ removed = sent * restart_prob
44
+ else:
45
+ removed = sent
46
+ residu -= removed
47
+ if residu < tol * restart_prob:
48
+ return
49
+ return
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env python3
2
+ # coding: utf-8
3
+ """
4
+ Created on July 9 2019
5
+ @author: Nathan De Lara <nathan.delara@polytechnique.org>
6
+ """
7
+ from abc import ABC
8
+ from typing import Union
9
+
10
+ import numpy as np
11
+ from scipy import sparse
12
+ from scipy.sparse.linalg import eigsh
13
+ from sknetwork.utils.base import Algorithm
14
+
15
+
16
+ class EigSolver(Algorithm, ABC):
17
+ """Generic class for eigensolvers.
18
+
19
+ Parameters
20
+ ----------
21
+ which: str
22
+ Which eigenvectors and eigenvalues to find:
23
+
24
+ * ``'LM'`` : Largest (in magnitude) eigenvalues.
25
+ * ``'SM'` : Smallest (in magnitude) eigenvalues.
26
+
27
+ Attributes
28
+ ----------
29
+ eigenvectors_: np.ndarray
30
+ Two-dimensional array, each column is an eigenvector of the input.
31
+ eigenvalues_: np.ndarray
32
+ Eigenvalues associated to each eigenvector.
33
+ """
34
+ def __init__(self, which='LM'):
35
+ self.which = which
36
+
37
+ self.eigenvectors_ = None
38
+ self.eigenvalues_ = None
39
+
40
+
41
+ class LanczosEig(EigSolver):
42
+ """Eigenvalue solver using Lanczos method.
43
+
44
+ Parameters
45
+ ----------
46
+ which : str
47
+ Which eigenvectors and eigenvalues to find:
48
+
49
+ * ``'LM'`` : Largest (in modulus) eigenvalues.
50
+ * ``'SM'`` : Smallest (in modulus) eigenvalues.
51
+ * ``'LA'`` : Largest (algebraic) eigenvalues.
52
+ * ``'SA'`` : Smallest (algebraic) eigenvalues.
53
+
54
+ n_iter : int
55
+ Maximum number of Arnoldi update iterations allowed.
56
+ Default = 10 * nb of rows.
57
+ tol : float
58
+ Relative accuracy for eigenvalues (stopping criterion).
59
+ Default = 0 (machine precision).
60
+ Attributes
61
+ ----------
62
+ eigenvectors_: np.ndarray
63
+ Two-dimensional array, each column is an eigenvector of the input.
64
+ eigenvalues_: np.ndarray
65
+ Eigenvalues associated to each eigenvector.
66
+
67
+ See Also
68
+ --------
69
+ scipy.sparse.linalg.eigsh
70
+ """
71
+ def __init__(self, which='LM', n_iter: int = None, tol: float = 0.):
72
+ super(LanczosEig, self).__init__(which=which)
73
+ self.n_iter = n_iter
74
+ self.tol = tol
75
+
76
+ def fit(self, matrix: Union[sparse.csr_matrix, sparse.linalg.LinearOperator], n_components: int = 2):
77
+ """Perform spectral decomposition on symmetric input matrix.
78
+
79
+ Parameters
80
+ ----------
81
+ matrix : sparse.csr_matrix or linear operator
82
+ Matrix to decompose.
83
+ n_components : int
84
+ Number of eigenvectors to compute
85
+
86
+ Returns
87
+ -------
88
+ self: :class:`EigSolver`
89
+ """
90
+ self.eigenvalues_, self.eigenvectors_ = eigsh(matrix.astype(float), n_components, which=self.which,
91
+ maxiter=self.n_iter, tol=self.tol)
92
+
93
+ return self
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created in July 2022
5
+ @author: Thomas Bonald <thomas.bonald@telecom-paris.fr>
6
+ """
7
+
8
+ import numpy as np
9
+ from scipy import sparse
10
+
11
+
12
+ def get_laplacian(adjacency: sparse.csr_matrix) -> sparse.csr_matrix:
13
+ """Return the Laplacian matrix of a graph."""
14
+ weights = adjacency.dot(np.ones(adjacency.shape[0]))
15
+ return sparse.diags(weights) - adjacency
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created in November 2019
5
+ @author: Nathan de Lara <nathan.delara@polytechnique.org>
6
+ """
7
+ from typing import Union
8
+
9
+ import numpy as np
10
+ from scipy import sparse
11
+ from scipy.sparse.linalg import LinearOperator
12
+
13
+
14
+ def diag_pinv(weights: np.ndarray) -> sparse.csr_matrix:
15
+ """Compute :math:`W^+ = \\text{diag}(w)^+`, the pseudo inverse of the diagonal matrix
16
+ with diagonal the weights :math:`w`.
17
+
18
+ Parameters
19
+ ----------
20
+ weights:
21
+ The weights to invert.
22
+
23
+ Returns
24
+ -------
25
+ sparse.csr_matrix
26
+ :math:`W^+`
27
+
28
+ """
29
+ diag: sparse.csr_matrix = sparse.diags(weights, format='csr')
30
+ diag.data = 1 / diag.data
31
+ return diag
32
+
33
+
34
+ def normalize(matrix: Union[sparse.csr_matrix, np.ndarray, LinearOperator], p=1):
35
+ """Normalize rows of a matrix. Null rows remain null.
36
+
37
+ Parameters
38
+ ----------
39
+ matrix :
40
+ Input matrix.
41
+ p :
42
+ Order of the norm.
43
+
44
+ Returns
45
+ -------
46
+ normalized matrix : same as input
47
+ """
48
+ if p == 1:
49
+ norm = matrix.dot(np.ones(matrix.shape[1]))
50
+ elif p == 2:
51
+ if isinstance(matrix, np.ndarray):
52
+ norm = np.linalg.norm(matrix, axis=1)
53
+ elif isinstance(matrix, sparse.csr_matrix):
54
+ data = matrix.data.copy()
55
+ matrix.data = data ** 2
56
+ norm = np.sqrt(matrix.dot(np.ones(matrix.shape[1])))
57
+ matrix.data = data
58
+ else:
59
+ raise NotImplementedError('Norm 2 is not available for LinearOperator.')
60
+ else:
61
+ raise NotImplementedError('Only norms 1 and 2 are available at the moment.')
62
+
63
+ diag = diag_pinv(norm)
64
+ if hasattr(matrix, 'left_sparse_dot') and callable(matrix.left_sparse_dot):
65
+ return matrix.left_sparse_dot(diag)
66
+ return diag.dot(matrix)
@@ -0,0 +1,225 @@
1
+ #!/usr/bin/env python3
2
+ # coding: utf-8
3
+ """
4
+ Created in April 2020
5
+ @author: Thomas Bonald <bonald@enst.fr>
6
+ @author: Nathan de Lara <nathan.delara@polytechnique.org>
7
+ """
8
+ from typing import Union
9
+
10
+ import numpy as np
11
+ from scipy import sparse
12
+ from scipy.sparse.linalg import LinearOperator
13
+
14
+ from sknetwork.linalg import diag_pinv
15
+ from sknetwork.linalg.normalization import normalize
16
+ from sknetwork.linalg.sparse_lowrank import SparseLR
17
+ from sknetwork.utils.check import check_format
18
+
19
+
20
+ class Regularizer(SparseLR):
21
+ """Regularized matrix as a Scipy LinearOperator.
22
+
23
+ Defined by :math:`A + \\alpha \\frac{11^T}n` where :math:`A` is the input matrix
24
+ and :math:`\\alpha` the regularization factor.
25
+
26
+ Parameters
27
+ ----------
28
+ input_matrix :
29
+ Input matrix.
30
+ regularization : float
31
+ Regularization factor.
32
+ Default value = 1.
33
+
34
+ Examples
35
+ --------
36
+ >>> from sknetwork.data import house
37
+ >>> adjacency = house()
38
+ >>> regularizer = Regularizer(adjacency)
39
+ >>> regularizer.dot(np.ones(5))
40
+ array([3., 4., 3., 3., 4.])
41
+ """
42
+ def __init__(self, input_matrix: Union[sparse.csr_matrix, np.ndarray], regularization: float = 1):
43
+ n_row, n_col = input_matrix.shape
44
+ u = regularization * np.ones(n_row)
45
+ v = np.ones(n_col) / n_col
46
+ super(Regularizer, self).__init__(input_matrix, (u, v))
47
+
48
+
49
+ class Normalizer(LinearOperator):
50
+ """Normalized matrix as a Scipy LinearOperator.
51
+
52
+ Defined by :math:`D^{-1}A` where :math:`A` is the regularized adjacency matrix and :math:`D` the corresponding
53
+ diagonal matrix of degrees (sums over rows).
54
+
55
+ Parameters
56
+ ----------
57
+ adjacency :
58
+ :term:`Adjacency <adjacency>` matrix of the graph.
59
+ regularization : float
60
+ Regularization factor.
61
+ Default value = 0.
62
+
63
+ Examples
64
+ --------
65
+ >>> from sknetwork.data import house
66
+ >>> adjacency = house()
67
+ >>> normalizer = Normalizer(adjacency)
68
+ >>> normalizer.dot(np.ones(5))
69
+ array([1., 1., 1., 1., 1.])
70
+ """
71
+ def __init__(self, adjacency: Union[sparse.csr_matrix, np.ndarray], regularization: float = 0):
72
+ if adjacency.ndim == 1:
73
+ adjacency = adjacency.reshape(1, -1)
74
+ super(Normalizer, self).__init__(dtype=float, shape=adjacency.shape)
75
+ n_col = adjacency.shape[1]
76
+ self.regularization = regularization
77
+ self.adjacency = adjacency
78
+ self.norm_diag = diag_pinv(adjacency.dot(np.ones(n_col)) + regularization)
79
+
80
+ def _matvec(self, matrix: np.ndarray):
81
+ prod = self.adjacency.dot(matrix)
82
+ if self.regularization > 0:
83
+ n_row = self.shape[0]
84
+ if matrix.ndim == 2:
85
+ prod += self.regularization * np.outer(np.ones(n_row), matrix.mean(axis=0))
86
+ else:
87
+ prod += self.regularization * matrix.mean() * np.ones(n_row)
88
+ return self.norm_diag.dot(prod)
89
+
90
+ def _transpose(self):
91
+ return self
92
+
93
+
94
+ class Laplacian(LinearOperator):
95
+ """Laplacian matrix as a Scipy LinearOperator.
96
+
97
+ Defined by :math:`L = D - A` where :math:`A` is the regularized adjacency matrix and :math:`D` the corresponding
98
+ diagonal matrix of degrees.
99
+
100
+ If normalized, defined by :math:`L = I - D^{-1/2}AD^{-1/2}`.
101
+
102
+ Parameters
103
+ ----------
104
+ adjacency :
105
+ :term:`Adjacency <adjacency>` matrix of the graph.
106
+ regularization : float
107
+ Regularization factor.
108
+ Default value = 0.
109
+ normalized_laplacian : bool
110
+ If ``True``, use normalized Laplacian.
111
+ Default value = ``False``.
112
+
113
+ Examples
114
+ --------
115
+ >>> from sknetwork.data import house
116
+ >>> adjacency = house()
117
+ >>> laplacian = Laplacian(adjacency)
118
+ >>> laplacian.dot(np.ones(5))
119
+ array([0., 0., 0., 0., 0.])
120
+ """
121
+ def __init__(self, adjacency: Union[sparse.csr_matrix, np.ndarray], regularization: float = 0,
122
+ normalized_laplacian: bool = False):
123
+ super(Laplacian, self).__init__(dtype=float, shape=adjacency.shape)
124
+ n = adjacency.shape[0]
125
+ self.regularization = regularization
126
+ self.normalized_laplacian = normalized_laplacian
127
+ self.weights = adjacency.dot(np.ones(n))
128
+ self.laplacian = sparse.diags(self.weights, format='csr') - adjacency
129
+ if self.normalized_laplacian:
130
+ self.norm_diag = diag_pinv(np.sqrt(self.weights + regularization))
131
+
132
+ def _matvec(self, matrix: np.ndarray):
133
+ if self.normalized_laplacian:
134
+ matrix = self.norm_diag.dot(matrix)
135
+ prod = self.laplacian.dot(matrix)
136
+ if self.regularization > 0:
137
+ n = self.shape[0]
138
+ if matrix.ndim == 2:
139
+ prod += self.regularization * (matrix - np.outer(np.ones(n), matrix.mean(axis=0)))
140
+ else:
141
+ prod += self.regularization * (matrix - matrix.mean())
142
+ if self.normalized_laplacian:
143
+ prod = self.norm_diag.dot(prod)
144
+ return prod
145
+
146
+ def _transpose(self):
147
+ return self
148
+
149
+ def astype(self, dtype: Union[str, np.dtype]):
150
+ """Change dtype of the object."""
151
+ self.dtype = np.dtype(dtype)
152
+ self.laplacian = self.laplacian.astype(self.dtype)
153
+ return self
154
+
155
+
156
+ class CoNeighbor(LinearOperator):
157
+ """Co-neighborhood adjacency as a LinearOperator.
158
+
159
+ :math:`\\tilde{A} = AF^{-1}A^T`, or :math:`\\tilde{B} = BF^{-1}B^T`.
160
+
161
+ where F is a weight matrix.
162
+
163
+ Parameters
164
+ ----------
165
+ adjacency:
166
+ Adjacency or biadjacency of the input graph.
167
+ normalized:
168
+ If ``True``, F is the diagonal in-degree matrix :math:`F = \\text{diag}(A^T1)`.
169
+ Otherwise, F is the identity matrix.
170
+
171
+ Examples
172
+ --------
173
+ >>> from sknetwork.data import star_wars
174
+ >>> biadjacency = star_wars(metadata=False)
175
+ >>> d_out = biadjacency.dot(np.ones(3))
176
+ >>> coneighbor = CoNeighbor(biadjacency)
177
+ >>> np.allclose(d_out, coneighbor.dot(np.ones(4)))
178
+ True
179
+ """
180
+ def __init__(self, adjacency: Union[sparse.csr_matrix, np.ndarray], normalized: bool = True):
181
+ adjacency = check_format(adjacency).astype(float)
182
+ n = adjacency.shape[0]
183
+ super(CoNeighbor, self).__init__(dtype=float, shape=(n, n))
184
+
185
+ if normalized:
186
+ self.forward = normalize(adjacency.T).tocsr()
187
+ else:
188
+ self.forward = adjacency.T
189
+
190
+ self.backward = adjacency
191
+
192
+ def __neg__(self):
193
+ self.backward *= -1
194
+ return self
195
+
196
+ def __mul__(self, other):
197
+ self.backward *= other
198
+ return self
199
+
200
+ def _matvec(self, matrix: np.ndarray):
201
+ return self.backward.dot(self.forward.dot(matrix))
202
+
203
+ def _transpose(self):
204
+ """Transposed operator"""
205
+ operator = CoNeighbor(self.backward)
206
+ operator.backward = self.forward.T.tocsr()
207
+ operator.forward = self.backward.T.tocsr()
208
+ return operator
209
+
210
+ def left_sparse_dot(self, matrix: sparse.csr_matrix):
211
+ """Left dot product with a sparse matrix"""
212
+ self.backward = matrix.dot(self.backward)
213
+ return self
214
+
215
+ def right_sparse_dot(self, matrix: sparse.csr_matrix):
216
+ """Right dot product with a sparse matrix"""
217
+ self.forward = self.forward.dot(matrix)
218
+ return self
219
+
220
+ def astype(self, dtype: Union[str, np.dtype]):
221
+ """Change dtype of the object."""
222
+ self.backward.astype(dtype)
223
+ self.forward.astype(dtype)
224
+ self.dtype = dtype
225
+ return self
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created in April 2020
5
+ @author: Nathan de Lara <nathan.delara@polytechnique.org>
6
+ """
7
+
8
+ from typing import Union
9
+
10
+ import numpy as np
11
+ from scipy import sparse
12
+ from scipy.sparse.linalg import LinearOperator
13
+
14
+ from sknetwork.utils.check import check_format, check_square
15
+
16
+
17
+ class Polynome(LinearOperator):
18
+ """Polynome of an adjacency matrix as a linear operator
19
+
20
+ :math:`P(A) = \\alpha_k A^k + ... + \\alpha_1 A + \\alpha_0`.
21
+
22
+ Parameters
23
+ ----------
24
+ adjacency :
25
+ Adjacency matrix of the graph
26
+ coeffs : np.ndarray
27
+ Coefficients of the polynome by increasing order of power.
28
+
29
+ Examples
30
+ --------
31
+ >>> from scipy import sparse
32
+ >>> from sknetwork.linalg import Polynome
33
+ >>> adjacency = sparse.eye(2, format='csr')
34
+ >>> polynome = Polynome(adjacency, np.arange(3))
35
+ >>> x = np.ones(2)
36
+ >>> polynome.dot(x)
37
+ array([3., 3.])
38
+ >>> polynome.T.dot(x)
39
+ array([3., 3.])
40
+
41
+ Notes
42
+ -----
43
+ The polynome is evaluated using the `Ruffini-Horner method
44
+ <https://en.wikipedia.org/wiki/Horner%27s_method>`_.
45
+ """
46
+
47
+ def __init__(self, adjacency: Union[sparse.csr_matrix, np.ndarray], coeffs: np.ndarray):
48
+ if coeffs.shape[0] == 0:
49
+ raise ValueError('A polynome requires at least one coefficient.')
50
+ if not isinstance(adjacency, LinearOperator):
51
+ adjacency = check_format(adjacency)
52
+ check_square(adjacency)
53
+ shape = adjacency.shape
54
+ dtype = adjacency.dtype
55
+ super(Polynome, self).__init__(dtype=dtype, shape=shape)
56
+
57
+ self.adjacency = adjacency
58
+ self.coeffs = coeffs
59
+
60
+ def __neg__(self):
61
+ return Polynome(self.adjacency, -self.coeffs)
62
+
63
+ def __mul__(self, other):
64
+ return Polynome(self.adjacency, other * self.coeffs)
65
+
66
+ def _matvec(self, matrix: np.ndarray):
67
+ """Right dot product with a dense matrix.
68
+ """
69
+ y = self.coeffs[-1] * matrix
70
+ for a in self.coeffs[::-1][1:]:
71
+ y = self.adjacency.dot(y) + a * matrix
72
+ return y
73
+
74
+ def _transpose(self):
75
+ """Transposed operator."""
76
+ return Polynome(self.adjacency.T.tocsr(), self.coeffs)