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.
- scikit_network-0.28.3.dist-info/AUTHORS.rst +41 -0
- scikit_network-0.28.3.dist-info/LICENSE +34 -0
- scikit_network-0.28.3.dist-info/METADATA +457 -0
- scikit_network-0.28.3.dist-info/RECORD +240 -0
- scikit_network-0.28.3.dist-info/WHEEL +5 -0
- scikit_network-0.28.3.dist-info/top_level.txt +1 -0
- sknetwork/__init__.py +21 -0
- sknetwork/classification/__init__.py +8 -0
- sknetwork/classification/base.py +84 -0
- sknetwork/classification/base_rank.py +143 -0
- sknetwork/classification/diffusion.py +134 -0
- sknetwork/classification/knn.py +162 -0
- sknetwork/classification/metrics.py +205 -0
- sknetwork/classification/pagerank.py +66 -0
- sknetwork/classification/propagation.py +152 -0
- sknetwork/classification/tests/__init__.py +1 -0
- sknetwork/classification/tests/test_API.py +35 -0
- sknetwork/classification/tests/test_diffusion.py +37 -0
- sknetwork/classification/tests/test_knn.py +24 -0
- sknetwork/classification/tests/test_metrics.py +53 -0
- sknetwork/classification/tests/test_pagerank.py +20 -0
- sknetwork/classification/tests/test_propagation.py +24 -0
- sknetwork/classification/vote.cpython-39-darwin.so +0 -0
- sknetwork/classification/vote.pyx +58 -0
- sknetwork/clustering/__init__.py +7 -0
- sknetwork/clustering/base.py +102 -0
- sknetwork/clustering/kmeans.py +142 -0
- sknetwork/clustering/louvain.py +255 -0
- sknetwork/clustering/louvain_core.cpython-39-darwin.so +0 -0
- sknetwork/clustering/louvain_core.pyx +134 -0
- sknetwork/clustering/metrics.py +91 -0
- sknetwork/clustering/postprocess.py +66 -0
- sknetwork/clustering/propagation_clustering.py +108 -0
- sknetwork/clustering/tests/__init__.py +1 -0
- sknetwork/clustering/tests/test_API.py +37 -0
- sknetwork/clustering/tests/test_kmeans.py +47 -0
- sknetwork/clustering/tests/test_louvain.py +104 -0
- sknetwork/clustering/tests/test_metrics.py +50 -0
- sknetwork/clustering/tests/test_post_processing.py +23 -0
- sknetwork/clustering/tests/test_postprocess.py +39 -0
- sknetwork/data/__init__.py +5 -0
- sknetwork/data/load.py +408 -0
- sknetwork/data/models.py +459 -0
- sknetwork/data/parse.py +621 -0
- sknetwork/data/test_graphs.py +84 -0
- sknetwork/data/tests/__init__.py +1 -0
- sknetwork/data/tests/test_API.py +30 -0
- sknetwork/data/tests/test_load.py +95 -0
- sknetwork/data/tests/test_models.py +52 -0
- sknetwork/data/tests/test_parse.py +253 -0
- sknetwork/data/tests/test_test_graphs.py +30 -0
- sknetwork/data/tests/test_toy_graphs.py +68 -0
- sknetwork/data/toy_graphs.py +619 -0
- sknetwork/embedding/__init__.py +10 -0
- sknetwork/embedding/base.py +90 -0
- sknetwork/embedding/force_atlas.py +197 -0
- sknetwork/embedding/louvain_embedding.py +174 -0
- sknetwork/embedding/louvain_hierarchy.py +142 -0
- sknetwork/embedding/metrics.py +66 -0
- sknetwork/embedding/random_projection.py +133 -0
- sknetwork/embedding/spectral.py +214 -0
- sknetwork/embedding/spring.py +198 -0
- sknetwork/embedding/svd.py +363 -0
- sknetwork/embedding/tests/__init__.py +1 -0
- sknetwork/embedding/tests/test_API.py +73 -0
- sknetwork/embedding/tests/test_force_atlas.py +35 -0
- sknetwork/embedding/tests/test_louvain_embedding.py +33 -0
- sknetwork/embedding/tests/test_louvain_hierarchy.py +19 -0
- sknetwork/embedding/tests/test_metrics.py +29 -0
- sknetwork/embedding/tests/test_random_projection.py +28 -0
- sknetwork/embedding/tests/test_spectral.py +84 -0
- sknetwork/embedding/tests/test_spring.py +50 -0
- sknetwork/embedding/tests/test_svd.py +37 -0
- sknetwork/flow/__init__.py +3 -0
- sknetwork/flow/flow.py +73 -0
- sknetwork/flow/tests/__init__.py +1 -0
- sknetwork/flow/tests/test_flow.py +17 -0
- sknetwork/flow/tests/test_utils.py +69 -0
- sknetwork/flow/utils.py +91 -0
- sknetwork/gnn/__init__.py +10 -0
- sknetwork/gnn/activation.py +117 -0
- sknetwork/gnn/base.py +155 -0
- sknetwork/gnn/base_activation.py +89 -0
- sknetwork/gnn/base_layer.py +109 -0
- sknetwork/gnn/gnn_classifier.py +381 -0
- sknetwork/gnn/layer.py +153 -0
- sknetwork/gnn/layers.py +127 -0
- sknetwork/gnn/loss.py +180 -0
- sknetwork/gnn/neighbor_sampler.py +65 -0
- sknetwork/gnn/optimizer.py +163 -0
- sknetwork/gnn/tests/__init__.py +1 -0
- sknetwork/gnn/tests/test_activation.py +56 -0
- sknetwork/gnn/tests/test_base.py +79 -0
- sknetwork/gnn/tests/test_base_layer.py +37 -0
- sknetwork/gnn/tests/test_gnn_classifier.py +192 -0
- sknetwork/gnn/tests/test_layers.py +80 -0
- sknetwork/gnn/tests/test_loss.py +33 -0
- sknetwork/gnn/tests/test_neigh_sampler.py +23 -0
- sknetwork/gnn/tests/test_optimizer.py +43 -0
- sknetwork/gnn/tests/test_utils.py +93 -0
- sknetwork/gnn/utils.py +219 -0
- sknetwork/hierarchy/__init__.py +7 -0
- sknetwork/hierarchy/base.py +69 -0
- sknetwork/hierarchy/louvain_hierarchy.py +264 -0
- sknetwork/hierarchy/metrics.py +234 -0
- sknetwork/hierarchy/paris.cpython-39-darwin.so +0 -0
- sknetwork/hierarchy/paris.pyx +317 -0
- sknetwork/hierarchy/postprocess.py +350 -0
- sknetwork/hierarchy/tests/__init__.py +1 -0
- sknetwork/hierarchy/tests/test_API.py +25 -0
- sknetwork/hierarchy/tests/test_algos.py +29 -0
- sknetwork/hierarchy/tests/test_metrics.py +62 -0
- sknetwork/hierarchy/tests/test_postprocess.py +57 -0
- sknetwork/hierarchy/tests/test_ward.py +25 -0
- sknetwork/hierarchy/ward.py +94 -0
- sknetwork/linalg/__init__.py +9 -0
- sknetwork/linalg/basics.py +37 -0
- sknetwork/linalg/diteration.cpython-39-darwin.so +0 -0
- sknetwork/linalg/diteration.pyx +49 -0
- sknetwork/linalg/eig_solver.py +93 -0
- sknetwork/linalg/laplacian.py +15 -0
- sknetwork/linalg/normalization.py +66 -0
- sknetwork/linalg/operators.py +225 -0
- sknetwork/linalg/polynome.py +76 -0
- sknetwork/linalg/ppr_solver.py +170 -0
- sknetwork/linalg/push.cpython-39-darwin.so +0 -0
- sknetwork/linalg/push.pyx +73 -0
- sknetwork/linalg/sparse_lowrank.py +142 -0
- sknetwork/linalg/svd_solver.py +91 -0
- sknetwork/linalg/tests/__init__.py +1 -0
- sknetwork/linalg/tests/test_eig.py +44 -0
- sknetwork/linalg/tests/test_laplacian.py +18 -0
- sknetwork/linalg/tests/test_normalization.py +38 -0
- sknetwork/linalg/tests/test_operators.py +70 -0
- sknetwork/linalg/tests/test_polynome.py +38 -0
- sknetwork/linalg/tests/test_ppr.py +50 -0
- sknetwork/linalg/tests/test_sparse_lowrank.py +61 -0
- sknetwork/linalg/tests/test_svd.py +38 -0
- sknetwork/linkpred/__init__.py +4 -0
- sknetwork/linkpred/base.py +80 -0
- sknetwork/linkpred/first_order.py +508 -0
- sknetwork/linkpred/first_order_core.cpython-39-darwin.so +0 -0
- sknetwork/linkpred/first_order_core.pyx +315 -0
- sknetwork/linkpred/postprocessing.py +98 -0
- sknetwork/linkpred/tests/__init__.py +1 -0
- sknetwork/linkpred/tests/test_API.py +49 -0
- sknetwork/linkpred/tests/test_postprocessing.py +21 -0
- sknetwork/path/__init__.py +4 -0
- sknetwork/path/metrics.py +148 -0
- sknetwork/path/search.py +65 -0
- sknetwork/path/shortest_path.py +186 -0
- sknetwork/path/tests/__init__.py +1 -0
- sknetwork/path/tests/test_metrics.py +29 -0
- sknetwork/path/tests/test_search.py +25 -0
- sknetwork/path/tests/test_shortest_path.py +45 -0
- sknetwork/ranking/__init__.py +9 -0
- sknetwork/ranking/base.py +56 -0
- sknetwork/ranking/betweenness.cpython-39-darwin.so +0 -0
- sknetwork/ranking/betweenness.pyx +99 -0
- sknetwork/ranking/closeness.py +95 -0
- sknetwork/ranking/harmonic.py +82 -0
- sknetwork/ranking/hits.py +94 -0
- sknetwork/ranking/katz.py +81 -0
- sknetwork/ranking/pagerank.py +107 -0
- sknetwork/ranking/postprocess.py +25 -0
- sknetwork/ranking/tests/__init__.py +1 -0
- sknetwork/ranking/tests/test_API.py +34 -0
- sknetwork/ranking/tests/test_betweenness.py +38 -0
- sknetwork/ranking/tests/test_closeness.py +34 -0
- sknetwork/ranking/tests/test_hits.py +20 -0
- sknetwork/ranking/tests/test_pagerank.py +69 -0
- sknetwork/regression/__init__.py +4 -0
- sknetwork/regression/base.py +56 -0
- sknetwork/regression/diffusion.py +190 -0
- sknetwork/regression/tests/__init__.py +1 -0
- sknetwork/regression/tests/test_API.py +34 -0
- sknetwork/regression/tests/test_diffusion.py +48 -0
- sknetwork/sknetwork.py +3 -0
- sknetwork/topology/__init__.py +9 -0
- sknetwork/topology/dag.py +74 -0
- sknetwork/topology/dag_core.cpython-39-darwin.so +0 -0
- sknetwork/topology/dag_core.pyx +38 -0
- sknetwork/topology/kcliques.cpython-39-darwin.so +0 -0
- sknetwork/topology/kcliques.pyx +193 -0
- sknetwork/topology/kcore.cpython-39-darwin.so +0 -0
- sknetwork/topology/kcore.pyx +120 -0
- sknetwork/topology/structure.py +234 -0
- sknetwork/topology/tests/__init__.py +1 -0
- sknetwork/topology/tests/test_cliques.py +28 -0
- sknetwork/topology/tests/test_cores.py +21 -0
- sknetwork/topology/tests/test_dag.py +26 -0
- sknetwork/topology/tests/test_structure.py +99 -0
- sknetwork/topology/tests/test_triangles.py +42 -0
- sknetwork/topology/tests/test_wl_coloring.py +49 -0
- sknetwork/topology/tests/test_wl_kernel.py +31 -0
- sknetwork/topology/triangles.cpython-39-darwin.so +0 -0
- sknetwork/topology/triangles.pyx +166 -0
- sknetwork/topology/weisfeiler_lehman.py +163 -0
- sknetwork/topology/weisfeiler_lehman_core.cpython-39-darwin.so +0 -0
- sknetwork/topology/weisfeiler_lehman_core.pyx +116 -0
- sknetwork/utils/__init__.py +40 -0
- sknetwork/utils/base.py +35 -0
- sknetwork/utils/check.py +354 -0
- sknetwork/utils/co_neighbor.py +71 -0
- sknetwork/utils/format.py +219 -0
- sknetwork/utils/kmeans.py +89 -0
- sknetwork/utils/knn.py +166 -0
- sknetwork/utils/knn1d.cpython-39-darwin.so +0 -0
- sknetwork/utils/knn1d.pyx +80 -0
- sknetwork/utils/membership.py +82 -0
- sknetwork/utils/minheap.cpython-39-darwin.so +0 -0
- sknetwork/utils/minheap.pxd +22 -0
- sknetwork/utils/minheap.pyx +111 -0
- sknetwork/utils/neighbors.py +115 -0
- sknetwork/utils/seeds.py +75 -0
- sknetwork/utils/simplex.py +140 -0
- sknetwork/utils/tests/__init__.py +1 -0
- sknetwork/utils/tests/test_base.py +28 -0
- sknetwork/utils/tests/test_bunch.py +16 -0
- sknetwork/utils/tests/test_check.py +190 -0
- sknetwork/utils/tests/test_co_neighbor.py +43 -0
- sknetwork/utils/tests/test_format.py +61 -0
- sknetwork/utils/tests/test_kmeans.py +21 -0
- sknetwork/utils/tests/test_knn.py +32 -0
- sknetwork/utils/tests/test_membership.py +24 -0
- sknetwork/utils/tests/test_neighbors.py +41 -0
- sknetwork/utils/tests/test_projection_simplex.py +33 -0
- sknetwork/utils/tests/test_seeds.py +67 -0
- sknetwork/utils/tests/test_verbose.py +15 -0
- sknetwork/utils/tests/test_ward.py +20 -0
- sknetwork/utils/timeout.py +38 -0
- sknetwork/utils/verbose.py +37 -0
- sknetwork/utils/ward.py +60 -0
- sknetwork/visualization/__init__.py +4 -0
- sknetwork/visualization/colors.py +34 -0
- sknetwork/visualization/dendrograms.py +229 -0
- sknetwork/visualization/graphs.py +819 -0
- sknetwork/visualization/tests/__init__.py +1 -0
- sknetwork/visualization/tests/test_dendrograms.py +53 -0
- sknetwork/visualization/tests/test_graphs.py +167 -0
sknetwork/utils/seeds.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Created on Apr, 2019
|
|
5
|
+
@author: Nathan de Lara <nathan.delara@polytechnique.org>
|
|
6
|
+
"""
|
|
7
|
+
import warnings
|
|
8
|
+
from typing import Optional, Union
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_seeds(shape: tuple, seeds: Union[np.ndarray, dict], default_value: float = -1) -> np.ndarray:
|
|
14
|
+
"""Get seeds as array."""
|
|
15
|
+
n = shape[0]
|
|
16
|
+
if isinstance(seeds, np.ndarray):
|
|
17
|
+
if len(seeds) != n:
|
|
18
|
+
raise ValueError('Dimensions mismatch between adjacency and seeds vector.')
|
|
19
|
+
else:
|
|
20
|
+
seeds = seeds.astype(float)
|
|
21
|
+
elif isinstance(seeds, dict):
|
|
22
|
+
keys, values = np.array(list(seeds.keys())), np.array(list(seeds.values()))
|
|
23
|
+
if np.min(values) < 0:
|
|
24
|
+
warnings.warn(Warning("Negative values will not be taken into account."))
|
|
25
|
+
seeds = default_value * np.ones(n)
|
|
26
|
+
seeds[keys] = values
|
|
27
|
+
else:
|
|
28
|
+
seeds = np.ones(n)
|
|
29
|
+
return seeds
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def stack_seeds(shape: tuple, seeds_row: Optional[Union[np.ndarray, dict]],
|
|
33
|
+
seeds_col: Optional[Union[np.ndarray, dict]] = None, default_value: float = -1) -> np.ndarray:
|
|
34
|
+
"""Process seeds for rows and columns and stack the results into a single vector."""
|
|
35
|
+
n_row, n_col = shape
|
|
36
|
+
if seeds_row is None and seeds_col is None:
|
|
37
|
+
seeds_row = np.ones(n_row)
|
|
38
|
+
seeds_col = default_value * np.ones(n_col)
|
|
39
|
+
elif seeds_row is None:
|
|
40
|
+
seeds_row = default_value * np.ones(n_row)
|
|
41
|
+
elif seeds_col is None:
|
|
42
|
+
seeds_col = default_value * np.ones(n_col)
|
|
43
|
+
seeds_row = get_seeds(shape, seeds_row, default_value)
|
|
44
|
+
seeds_col = get_seeds((n_col,), seeds_col, default_value)
|
|
45
|
+
return np.hstack((seeds_row, seeds_col))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def seeds2probs(n: int, seeds: np.ndarray = None) -> np.ndarray:
|
|
49
|
+
"""Transform seed values into probability vector.
|
|
50
|
+
|
|
51
|
+
Parameters
|
|
52
|
+
----------
|
|
53
|
+
n : int
|
|
54
|
+
Number of nodes.
|
|
55
|
+
seeds :
|
|
56
|
+
If ``None``, the uniform distribution is used.
|
|
57
|
+
Otherwise, a non-negative, non-zero vector or a dictionary must be provided.
|
|
58
|
+
|
|
59
|
+
Returns
|
|
60
|
+
-------
|
|
61
|
+
probs: np.ndarray
|
|
62
|
+
A probability vector.
|
|
63
|
+
"""
|
|
64
|
+
if seeds is None:
|
|
65
|
+
return np.ones(n) / n
|
|
66
|
+
else:
|
|
67
|
+
seeds = get_seeds((n,), seeds)
|
|
68
|
+
probs = np.zeros_like(seeds, dtype=float)
|
|
69
|
+
ix = (seeds > 0)
|
|
70
|
+
probs[ix] = seeds[ix]
|
|
71
|
+
w: float = probs.sum()
|
|
72
|
+
if w > 0:
|
|
73
|
+
return probs / w
|
|
74
|
+
else:
|
|
75
|
+
raise ValueError('At least one seed must have a positive value.')
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Created on June 4 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
|
+
|
|
12
|
+
from sknetwork.linalg.normalization import normalize
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def projection_simplex_array(array: np.ndarray, scale: float = 1) -> np.ndarray:
|
|
16
|
+
"""Project each line of the input onto the Euclidean simplex i.e. solve
|
|
17
|
+
|
|
18
|
+
:math:`\\underset{w}{min} ||w - x_i||_2^2` s.t. :math:`\\sum w_j = z, w_j \\ge 0`.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
array: np.ndarray
|
|
23
|
+
Data to project. Either one or two dimensional.
|
|
24
|
+
scale: float
|
|
25
|
+
Scale of the simplex i.e. sums of the projected coefficients.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
projection : np.ndarray
|
|
30
|
+
Array with the same shape as the input.
|
|
31
|
+
|
|
32
|
+
Example
|
|
33
|
+
-------
|
|
34
|
+
>>> X = np.array([[2, 2], [-0.75, 0.25]])
|
|
35
|
+
>>> projection_simplex_array(X)
|
|
36
|
+
array([[0.5, 0.5],
|
|
37
|
+
[0. , 1. ]])
|
|
38
|
+
"""
|
|
39
|
+
if len(array.shape) == 1:
|
|
40
|
+
array = array.reshape(1, array.shape[0])
|
|
41
|
+
n_row, n_col = array.shape
|
|
42
|
+
|
|
43
|
+
sorted_array = -np.sort(-array)
|
|
44
|
+
cumsum_array = np.cumsum(sorted_array, axis=1) - scale
|
|
45
|
+
denom = 1 + np.arange(n_col)
|
|
46
|
+
condition = sorted_array - cumsum_array / denom > 0
|
|
47
|
+
max_index = np.argmax(condition / denom[::-1], axis=1)
|
|
48
|
+
threshold = (cumsum_array / denom)[np.arange(n_row), max_index]
|
|
49
|
+
|
|
50
|
+
return np.maximum(array - threshold[:, np.newaxis], 0)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def projection_simplex_csr(matrix: sparse.csr_matrix, scale: float = 1):
|
|
54
|
+
"""Project each line of the input onto the Euclidean simplex i.e. solve
|
|
55
|
+
|
|
56
|
+
:math:`\\underset{w}{min} ||w - x_i||_2^2` s.t. :math:`\\sum w_j = z, w_j \\ge 0`.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
matrix : sparse.csr_matrix
|
|
61
|
+
Matrix whose rows must be projected.
|
|
62
|
+
scale: float
|
|
63
|
+
Scale of the simplex i.e. sums of the projected coefficients.
|
|
64
|
+
|
|
65
|
+
Returns
|
|
66
|
+
-------
|
|
67
|
+
projection : sparse.csr_matrix
|
|
68
|
+
Matrix with the same shape as the input.
|
|
69
|
+
|
|
70
|
+
Examples
|
|
71
|
+
--------
|
|
72
|
+
>>> X = sparse.csr_matrix(np.array([[2, 2], [-0.75, 0.25]]))
|
|
73
|
+
>>> X_proj = projection_simplex_csr(X)
|
|
74
|
+
>>> X_proj.nnz
|
|
75
|
+
3
|
|
76
|
+
>>> X_proj.toarray()
|
|
77
|
+
array([[0.5, 0.5],
|
|
78
|
+
[0. , 1. ]])
|
|
79
|
+
"""
|
|
80
|
+
data = matrix.data
|
|
81
|
+
if data.dtype == bool or (data.min() == data.max()):
|
|
82
|
+
return normalize(matrix, p=1)
|
|
83
|
+
|
|
84
|
+
indptr = matrix.indptr
|
|
85
|
+
new_data = np.zeros_like(data)
|
|
86
|
+
|
|
87
|
+
for i in range(indptr.size-1):
|
|
88
|
+
j1 = indptr[i]
|
|
89
|
+
j2 = indptr[i+1]
|
|
90
|
+
new_data[j1:j2] = projection_simplex_array(data[j1:j2], scale=scale)
|
|
91
|
+
|
|
92
|
+
new_matrix = sparse.csr_matrix((new_data, matrix.indices, indptr), shape=matrix.shape)
|
|
93
|
+
new_matrix.eliminate_zeros()
|
|
94
|
+
return new_matrix
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def projection_simplex(x: Union[np.ndarray, sparse.csr_matrix], scale: float = 1.):
|
|
98
|
+
"""Project each line of the input onto the Euclidean simplex i.e. solve
|
|
99
|
+
|
|
100
|
+
:math:`\\underset{w}{min} ||w - x_i||_2^2` s.t. :math:`\\sum w_j = z, w_j \\ge 0`.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
x :
|
|
105
|
+
Data to project. Either one or two dimensional. Can be sparse or dense.
|
|
106
|
+
scale : float
|
|
107
|
+
Scale of the simplex i.e. sums of the projected coefficients.
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
projection : np.ndarray or sparse.csr_matrix
|
|
112
|
+
Array with the same type and shape as the input.
|
|
113
|
+
|
|
114
|
+
Example
|
|
115
|
+
-------
|
|
116
|
+
>>> X = np.array([[2, 2], [-0.75, 0.25]])
|
|
117
|
+
>>> projection_simplex(X)
|
|
118
|
+
array([[0.5, 0.5],
|
|
119
|
+
[0. , 1. ]])
|
|
120
|
+
>>> X_csr = sparse.csr_matrix(X)
|
|
121
|
+
>>> X_proj = projection_simplex(X_csr)
|
|
122
|
+
>>> X_proj.nnz
|
|
123
|
+
3
|
|
124
|
+
>>> X_proj.toarray()
|
|
125
|
+
array([[0.5, 0.5],
|
|
126
|
+
[0. , 1. ]])
|
|
127
|
+
|
|
128
|
+
References
|
|
129
|
+
----------
|
|
130
|
+
Duchi, J., Shalev-Shwartz, S., Singer, Y., & Chandra, T. (2008, July).
|
|
131
|
+
`Efficient projections onto the l 1-ball for learning in high dimensions.
|
|
132
|
+
<http://machinelearning.org/archive/icml2008/papers/361.pdf>`_
|
|
133
|
+
In Proceedings of the 25th international conference on Machine learning (pp. 272-279). ACM.
|
|
134
|
+
"""
|
|
135
|
+
if isinstance(x, np.ndarray):
|
|
136
|
+
return projection_simplex_array(x, scale)
|
|
137
|
+
elif isinstance(x, sparse.csr_matrix):
|
|
138
|
+
return projection_simplex_csr(x, scale)
|
|
139
|
+
else:
|
|
140
|
+
raise TypeError('Input must be a numpy array or a CSR matrix.')
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""tests for utils"""
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""tests for base.py"""
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
from sknetwork.utils.base import Algorithm
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class TestBase(unittest.TestCase):
|
|
10
|
+
|
|
11
|
+
def test_repr(self):
|
|
12
|
+
class Stub(Algorithm):
|
|
13
|
+
"""Docstring"""
|
|
14
|
+
def __init__(self, some_param: int, another_param: str, random_state: int, some_unused_param: int):
|
|
15
|
+
self.some_param = some_param
|
|
16
|
+
self.another_param = another_param
|
|
17
|
+
self.random_state = random_state
|
|
18
|
+
|
|
19
|
+
def fit(self):
|
|
20
|
+
"""Docstring"""
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
stub = Stub(1, 'abc', 3, 4)
|
|
24
|
+
self.assertEqual(repr(stub), "Stub(some_param=1, another_param='abc')")
|
|
25
|
+
|
|
26
|
+
def test_fit(self):
|
|
27
|
+
stub = Algorithm()
|
|
28
|
+
self.assertRaises(NotImplementedError, stub.fit, None)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""tests for bunch"""
|
|
4
|
+
|
|
5
|
+
import unittest
|
|
6
|
+
|
|
7
|
+
from sknetwork.utils import Bunch
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestBunch(unittest.TestCase):
|
|
11
|
+
|
|
12
|
+
def test_key_error(self):
|
|
13
|
+
bunch = Bunch(a=1, b=2)
|
|
14
|
+
with self.assertRaises(AttributeError):
|
|
15
|
+
# noinspection PyStatementEffect
|
|
16
|
+
bunch.c
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""tests for check.py"""
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
from sknetwork.data import cyclic_digraph
|
|
7
|
+
from sknetwork.data.test_graphs import test_graph_disconnect
|
|
8
|
+
from sknetwork.utils.check import *
|
|
9
|
+
from sknetwork.utils.format import check_csr_or_slr
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestChecks(unittest.TestCase):
|
|
13
|
+
|
|
14
|
+
def setUp(self):
|
|
15
|
+
"""Simple graphs for tests."""
|
|
16
|
+
self.adjacency = cyclic_digraph(3)
|
|
17
|
+
self.dense_mat = np.identity(3)
|
|
18
|
+
|
|
19
|
+
def test_check_csr_slr(self):
|
|
20
|
+
with self.assertRaises(TypeError):
|
|
21
|
+
check_csr_or_slr(np.ones(3))
|
|
22
|
+
|
|
23
|
+
def test_check_square(self):
|
|
24
|
+
with self.assertRaises(ValueError):
|
|
25
|
+
check_square(np.ones((3, 7)))
|
|
26
|
+
|
|
27
|
+
def test_check_connected(self):
|
|
28
|
+
with self.assertRaises(ValueError):
|
|
29
|
+
check_connected(test_graph_disconnect())
|
|
30
|
+
|
|
31
|
+
def test_check_symmetry(self):
|
|
32
|
+
with self.assertRaises(ValueError):
|
|
33
|
+
check_symmetry(self.adjacency)
|
|
34
|
+
|
|
35
|
+
def test_nonnegative_entries(self):
|
|
36
|
+
self.assertTrue(has_nonnegative_entries(self.adjacency))
|
|
37
|
+
self.assertTrue(has_nonnegative_entries(self.dense_mat))
|
|
38
|
+
|
|
39
|
+
def test_check_nonnegative(self):
|
|
40
|
+
with self.assertRaises(ValueError):
|
|
41
|
+
check_nonnegative(-self.dense_mat)
|
|
42
|
+
|
|
43
|
+
def test_positive_entries(self):
|
|
44
|
+
self.assertFalse(has_positive_entries(self.dense_mat))
|
|
45
|
+
with self.assertRaises(TypeError):
|
|
46
|
+
# noinspection PyTypeChecker
|
|
47
|
+
has_positive_entries(self.adjacency)
|
|
48
|
+
|
|
49
|
+
def test_check_positive(self):
|
|
50
|
+
check_positive(np.ones(3))
|
|
51
|
+
with self.assertRaises(ValueError):
|
|
52
|
+
check_positive(-self.dense_mat)
|
|
53
|
+
|
|
54
|
+
def test_probas(self):
|
|
55
|
+
self.assertTrue(is_proba_array(np.array([.5, .5])))
|
|
56
|
+
check_is_proba(0.5)
|
|
57
|
+
with self.assertRaises(TypeError):
|
|
58
|
+
is_proba_array(np.ones((2, 2, 2)))
|
|
59
|
+
self.assertRaises(TypeError, check_is_proba, 'toto')
|
|
60
|
+
with self.assertRaises(ValueError):
|
|
61
|
+
check_is_proba(2)
|
|
62
|
+
|
|
63
|
+
def test_damping(self):
|
|
64
|
+
with self.assertRaises(ValueError):
|
|
65
|
+
check_damping_factor(1)
|
|
66
|
+
|
|
67
|
+
def test_error_make_weights(self):
|
|
68
|
+
with self.assertRaises(ValueError):
|
|
69
|
+
make_weights(distribution='junk', adjacency=self.adjacency)
|
|
70
|
+
|
|
71
|
+
def test_error_check_is_proba(self):
|
|
72
|
+
with self.assertRaises(TypeError):
|
|
73
|
+
# noinspection PyTypeChecker
|
|
74
|
+
check_is_proba('junk')
|
|
75
|
+
with self.assertRaises(ValueError):
|
|
76
|
+
check_is_proba(2)
|
|
77
|
+
|
|
78
|
+
def test_error_check_weights(self):
|
|
79
|
+
with self.assertRaises(ValueError):
|
|
80
|
+
check_weights(np.zeros(4), self.adjacency)
|
|
81
|
+
with self.assertRaises(TypeError):
|
|
82
|
+
# noinspection PyTypeChecker
|
|
83
|
+
check_weights(2, self.adjacency)
|
|
84
|
+
with self.assertRaises(ValueError):
|
|
85
|
+
check_weights(np.zeros(3), self.adjacency, positive_entries=True)
|
|
86
|
+
with self.assertRaises(ValueError):
|
|
87
|
+
check_weights(-np.ones(3), self.adjacency)
|
|
88
|
+
|
|
89
|
+
def test_random_state(self):
|
|
90
|
+
random_state = np.random.RandomState(1)
|
|
91
|
+
self.assertEqual(type(check_random_state(random_state)), np.random.RandomState)
|
|
92
|
+
|
|
93
|
+
def test_error_random_state(self):
|
|
94
|
+
with self.assertRaises(TypeError):
|
|
95
|
+
# noinspection PyTypeChecker
|
|
96
|
+
check_random_state('junk')
|
|
97
|
+
|
|
98
|
+
def test_check_labels(self):
|
|
99
|
+
with self.assertRaises(ValueError):
|
|
100
|
+
check_labels(np.ones(3))
|
|
101
|
+
labels = np.ones(5)
|
|
102
|
+
labels[0] = 0
|
|
103
|
+
classes, n_classes = check_labels(labels)
|
|
104
|
+
self.assertTrue(np.equal(classes, np.arange(2)).all())
|
|
105
|
+
self.assertEqual(n_classes, 2)
|
|
106
|
+
|
|
107
|
+
def test_check_n_jobs(self):
|
|
108
|
+
self.assertEqual(check_n_jobs(None), 1)
|
|
109
|
+
self.assertEqual(check_n_jobs(-1), None)
|
|
110
|
+
self.assertEqual(check_n_jobs(8), 8)
|
|
111
|
+
|
|
112
|
+
def test_check_n_neighbors(self):
|
|
113
|
+
with self.assertWarns(Warning):
|
|
114
|
+
check_n_neighbors(10, 5)
|
|
115
|
+
|
|
116
|
+
def test_adj_vector(self):
|
|
117
|
+
n = 10
|
|
118
|
+
vector1 = np.random.rand(n)
|
|
119
|
+
vector2 = sparse.csr_matrix(vector1)
|
|
120
|
+
adj1 = check_adjacency_vector(vector1)
|
|
121
|
+
adj2 = check_adjacency_vector(vector2)
|
|
122
|
+
|
|
123
|
+
self.assertEqual((adj1 - adj2).nnz, 0)
|
|
124
|
+
self.assertEqual(adj1.shape, (1, n))
|
|
125
|
+
|
|
126
|
+
with self.assertRaises(ValueError):
|
|
127
|
+
check_adjacency_vector(vector1, 2 * n)
|
|
128
|
+
|
|
129
|
+
def test_check_n_clusters(self):
|
|
130
|
+
with self.assertRaises(ValueError):
|
|
131
|
+
check_n_clusters(3, 2)
|
|
132
|
+
with self.assertRaises(ValueError):
|
|
133
|
+
check_n_clusters(0, 2, 1)
|
|
134
|
+
|
|
135
|
+
def test_min_size(self):
|
|
136
|
+
with self.assertRaises(ValueError):
|
|
137
|
+
check_min_size(1, 3)
|
|
138
|
+
|
|
139
|
+
def test_min_nnz(self):
|
|
140
|
+
with self.assertRaises(ValueError):
|
|
141
|
+
check_min_nnz(1, 3)
|
|
142
|
+
|
|
143
|
+
def test_dendrogram(self):
|
|
144
|
+
with self.assertRaises(ValueError):
|
|
145
|
+
check_dendrogram(np.ones((3, 3)))
|
|
146
|
+
|
|
147
|
+
def test_n_components(self):
|
|
148
|
+
self.assertEqual(5, check_n_components(5, 10))
|
|
149
|
+
with self.assertWarns(Warning):
|
|
150
|
+
self.assertEqual(2, check_n_components(5, 2))
|
|
151
|
+
|
|
152
|
+
def test_scaling(self):
|
|
153
|
+
adjacency = cyclic_digraph(3)
|
|
154
|
+
with self.assertRaises(ValueError):
|
|
155
|
+
check_scaling(-1, adjacency, regularize=True)
|
|
156
|
+
adjacency = test_graph_disconnect()
|
|
157
|
+
with self.assertRaises(ValueError):
|
|
158
|
+
check_scaling(-1, adjacency, regularize=False)
|
|
159
|
+
|
|
160
|
+
def test_boolean_entries(self):
|
|
161
|
+
with self.assertRaises(TypeError):
|
|
162
|
+
has_boolean_entries([True, 0, 2])
|
|
163
|
+
self.assertFalse(has_boolean_entries(np.array([0, 1, True])))
|
|
164
|
+
|
|
165
|
+
def test_boolean(self):
|
|
166
|
+
check_boolean(np.array([True, False, True]))
|
|
167
|
+
with self.assertRaises(ValueError):
|
|
168
|
+
check_boolean(np.array([True, 0, 2]))
|
|
169
|
+
|
|
170
|
+
def test_check_vector_format(self):
|
|
171
|
+
check_vector_format(np.arange(4), np.ones(4))
|
|
172
|
+
with self.assertRaises(ValueError):
|
|
173
|
+
check_vector_format(np.arange(4), np.ones((4, 3)))
|
|
174
|
+
with self.assertRaises(ValueError):
|
|
175
|
+
check_vector_format(np.arange(4), np.ones(5))
|
|
176
|
+
|
|
177
|
+
def test_has_self_loops(self):
|
|
178
|
+
self.assertTrue(has_self_loops(sparse.csr_matrix(np.array([[1, 0], [1, 1]]))))
|
|
179
|
+
self.assertFalse(has_self_loops(sparse.csr_matrix(np.array([[0, 0], [1, 1]]))))
|
|
180
|
+
|
|
181
|
+
def test_add_self_loops(self):
|
|
182
|
+
# Square adjacency
|
|
183
|
+
adjacency = sparse.csr_matrix(np.array([[0, 0], [1, 1]]))
|
|
184
|
+
self.assertFalse(has_self_loops(adjacency))
|
|
185
|
+
adjacency = add_self_loops(adjacency)
|
|
186
|
+
self.assertTrue(has_self_loops(adjacency))
|
|
187
|
+
# Non square adjacency
|
|
188
|
+
adjacency = sparse.csr_matrix(np.array([[0, 0, 1], [1, 1, 1]]))
|
|
189
|
+
n_row, n_col = adjacency.shape
|
|
190
|
+
self.assertTrue(has_self_loops(add_self_loops(adjacency)[:, :n_row]))
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Created on October 2019
|
|
5
|
+
@author: Nathan de Lara <nathan.delara@polytechnique.org>
|
|
6
|
+
"""
|
|
7
|
+
import unittest
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from sknetwork.data import movie_actor
|
|
12
|
+
from sknetwork.linalg import CoNeighbor
|
|
13
|
+
from sknetwork.utils import co_neighbor_graph
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestCoNeighbors(unittest.TestCase):
|
|
17
|
+
|
|
18
|
+
def setUp(self):
|
|
19
|
+
"""Simple biadjacency for tests."""
|
|
20
|
+
self.biadjacency = movie_actor()
|
|
21
|
+
|
|
22
|
+
def test_exact(self):
|
|
23
|
+
n = self.biadjacency.shape[0]
|
|
24
|
+
adjacency = co_neighbor_graph(self.biadjacency, method='exact', normalized=False)
|
|
25
|
+
self.assertEqual(adjacency.shape, (n, n))
|
|
26
|
+
adjacency = co_neighbor_graph(self.biadjacency, method='exact')
|
|
27
|
+
self.assertEqual(adjacency.shape, (n, n))
|
|
28
|
+
|
|
29
|
+
operator = CoNeighbor(self.biadjacency)
|
|
30
|
+
x = np.random.randn(n)
|
|
31
|
+
y1 = adjacency.dot(x)
|
|
32
|
+
y2 = operator.dot(x)
|
|
33
|
+
self.assertAlmostEqual(np.linalg.norm(y1 - y2), 0)
|
|
34
|
+
|
|
35
|
+
def test_knn(self):
|
|
36
|
+
n = self.biadjacency.shape[0]
|
|
37
|
+
adjacency = co_neighbor_graph(self.biadjacency, method='knn')
|
|
38
|
+
self.assertEqual(adjacency.shape, (n, n))
|
|
39
|
+
adjacency = co_neighbor_graph(self.biadjacency, method='knn', normalized=False)
|
|
40
|
+
self.assertEqual(adjacency.shape, (n, n))
|
|
41
|
+
|
|
42
|
+
def test_invalid(self):
|
|
43
|
+
self.assertRaises(ValueError, co_neighbor_graph, self.biadjacency, method='toto')
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""Tests for format.py"""
|
|
4
|
+
import unittest
|
|
5
|
+
|
|
6
|
+
from sknetwork.data.test_graphs import *
|
|
7
|
+
from sknetwork.utils.format import *
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestFormats(unittest.TestCase):
|
|
11
|
+
|
|
12
|
+
def setUp(self):
|
|
13
|
+
"""Basic biadjacency for tests."""
|
|
14
|
+
self.biadjacency = test_bigraph()
|
|
15
|
+
|
|
16
|
+
def test_directed2undirected(self):
|
|
17
|
+
adjacency = test_digraph()
|
|
18
|
+
ref = directed2undirected(adjacency)
|
|
19
|
+
self.assertEqual(ref.shape, adjacency.shape)
|
|
20
|
+
self.assertTrue(is_symmetric(ref))
|
|
21
|
+
|
|
22
|
+
adjacency = test_graph().astype(bool)
|
|
23
|
+
n = adjacency.shape[0]
|
|
24
|
+
diff = directed2undirected(adjacency, weighted=False) - adjacency
|
|
25
|
+
self.assertEqual(diff.nnz, 0)
|
|
26
|
+
|
|
27
|
+
slr = SparseLR(adjacency, [(np.zeros(n), np.zeros(n))])
|
|
28
|
+
self.assertRaises(ValueError, directed2undirected, slr, weighted=False)
|
|
29
|
+
slr = 0.5 * directed2undirected(slr)
|
|
30
|
+
self.assertEqual(slr.shape, (n, n))
|
|
31
|
+
|
|
32
|
+
x = np.random.randn(n)
|
|
33
|
+
error = np.linalg.norm(slr.dot(x) - adjacency.dot(x))
|
|
34
|
+
self.assertAlmostEqual(error, 0)
|
|
35
|
+
|
|
36
|
+
def test_bipartite2directed(self):
|
|
37
|
+
n_row, n_col = self.biadjacency.shape
|
|
38
|
+
n = n_row + n_col
|
|
39
|
+
|
|
40
|
+
directed_graph = bipartite2directed(self.biadjacency)
|
|
41
|
+
self.assertEqual(directed_graph.shape, (n, n))
|
|
42
|
+
|
|
43
|
+
slr = SparseLR(self.biadjacency, [(np.ones(n_row), np.ones(n_col))])
|
|
44
|
+
directed_graph = bipartite2directed(slr)
|
|
45
|
+
self.assertTrue(type(directed_graph) == SparseLR)
|
|
46
|
+
|
|
47
|
+
def test_bipartite2undirected(self):
|
|
48
|
+
n_row, n_col = self.biadjacency.shape
|
|
49
|
+
n = n_row + n_col
|
|
50
|
+
|
|
51
|
+
undirected_graph = bipartite2undirected(self.biadjacency)
|
|
52
|
+
self.assertEqual(undirected_graph.shape, (n, n))
|
|
53
|
+
self.assertTrue(is_symmetric(undirected_graph))
|
|
54
|
+
|
|
55
|
+
slr = SparseLR(self.biadjacency, [(np.ones(n_row), np.ones(n_col))])
|
|
56
|
+
undirected_graph = bipartite2undirected(slr)
|
|
57
|
+
self.assertTrue(type(undirected_graph) == SparseLR)
|
|
58
|
+
|
|
59
|
+
def test_check(self):
|
|
60
|
+
with self.assertRaises(ValueError):
|
|
61
|
+
check_format(sparse.csr_matrix((3, 4)))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Created on October 2019
|
|
5
|
+
@author: Nathan de Lara <nathan.delara@polytechnique.org>
|
|
6
|
+
"""
|
|
7
|
+
import unittest
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from sknetwork.utils import KMeansDense
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestKMeans(unittest.TestCase):
|
|
15
|
+
|
|
16
|
+
def test_kmeans(self):
|
|
17
|
+
x = np.random.randn(10, 3)
|
|
18
|
+
kmeans = KMeansDense(n_clusters=2)
|
|
19
|
+
labels = kmeans.fit_transform(x)
|
|
20
|
+
self.assertEqual(labels.shape, (x.shape[0],))
|
|
21
|
+
self.assertEqual(kmeans.cluster_centers_.shape, (kmeans.n_clusters, x.shape[1]))
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Created on October 2019
|
|
5
|
+
@author: Nathan de Lara <nathan.delara@polytechnique.org>
|
|
6
|
+
"""
|
|
7
|
+
import unittest
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from scipy import sparse
|
|
11
|
+
from scipy.sparse.linalg import norm
|
|
12
|
+
|
|
13
|
+
from sknetwork.utils import KNNDense, CNNDense
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestKNN(unittest.TestCase):
|
|
17
|
+
|
|
18
|
+
def test_basics(self):
|
|
19
|
+
x = np.array([[-2, -1], [-2, 1], [2, 1], [2, -1]])
|
|
20
|
+
knn = KNNDense(n_neighbors=1)
|
|
21
|
+
knn.fit(x)
|
|
22
|
+
truth = np.zeros(16).reshape((4, 4))
|
|
23
|
+
truth[0, 1] = 1
|
|
24
|
+
truth[2, 3] = 1
|
|
25
|
+
truth = sparse.csr_matrix(truth + truth.T)
|
|
26
|
+
self.assertAlmostEqual(norm(truth - knn.adjacency_), 0)
|
|
27
|
+
|
|
28
|
+
def test_pknn(self):
|
|
29
|
+
x = np.array([(0, 4), (1, 0), (2, 1), (3, 2), (4, 3)])
|
|
30
|
+
pknn = CNNDense(n_neighbors=1)
|
|
31
|
+
adj = pknn.fit_transform(x)
|
|
32
|
+
self.assertEqual(adj.shape, (5, 5))
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
import unittest
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
from sknetwork.utils.membership import get_membership, from_membership
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TestMembership(unittest.TestCase):
|
|
15
|
+
|
|
16
|
+
def test_membership(self):
|
|
17
|
+
labels = np.array([0, 0, 1, 2, 1, 1])
|
|
18
|
+
membership = get_membership(labels)
|
|
19
|
+
self.assertEqual(membership.nnz, 6)
|
|
20
|
+
self.assertEqual(np.linalg.norm(labels - from_membership(membership)), 0)
|
|
21
|
+
labels = np.array([0, 0, 1, 2, 1, -1])
|
|
22
|
+
membership = get_membership(labels)
|
|
23
|
+
self.assertEqual(membership.nnz, 5)
|
|
24
|
+
self.assertEqual(np.linalg.norm(labels - from_membership(membership)), 0)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Created on December 2020
|
|
5
|
+
@author: Thomas Bonald <bonald@enst.fr>
|
|
6
|
+
"""
|
|
7
|
+
import unittest
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from numpy.linalg import norm
|
|
11
|
+
|
|
12
|
+
from sknetwork.data import karate_club, painters
|
|
13
|
+
from sknetwork.utils import get_neighbors, get_degrees, get_weights
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestNeighbors(unittest.TestCase):
|
|
17
|
+
|
|
18
|
+
def test_graph(self):
|
|
19
|
+
adjacency = karate_club()
|
|
20
|
+
neighbors = get_neighbors(adjacency, 5)
|
|
21
|
+
degrees = get_degrees(adjacency)
|
|
22
|
+
neighbors_true = np.array([0, 6, 10, 16])
|
|
23
|
+
self.assertEqual(norm(neighbors - neighbors_true), 0)
|
|
24
|
+
self.assertEqual(degrees[5], 4)
|
|
25
|
+
|
|
26
|
+
def test_digraph(self):
|
|
27
|
+
adjacency = painters()
|
|
28
|
+
neighbors = get_neighbors(adjacency, 0)
|
|
29
|
+
out_degrees = get_degrees(adjacency)
|
|
30
|
+
out_weights = get_weights(adjacency)
|
|
31
|
+
neighbors_true = np.array([3, 10])
|
|
32
|
+
self.assertEqual(norm(neighbors - neighbors_true), 0)
|
|
33
|
+
self.assertEqual(out_degrees[0], 2)
|
|
34
|
+
self.assertEqual(out_weights[0], 2)
|
|
35
|
+
neighbors = get_neighbors(adjacency, 0, transpose=True)
|
|
36
|
+
in_degrees = get_degrees(adjacency, transpose=True)
|
|
37
|
+
in_weights = get_weights(adjacency, transpose=True)
|
|
38
|
+
neighbors_true = np.array([3, 6, 8, 10, 11])
|
|
39
|
+
self.assertEqual(norm(neighbors - neighbors_true), 0)
|
|
40
|
+
self.assertEqual(in_degrees[0], 5)
|
|
41
|
+
self.assertEqual(in_weights[0], 5)
|