@graphty/algorithms 1.2.0 → 1.4.2
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.
- package/README.md +375 -276
- package/dist/algorithms.d.ts +42 -2
- package/dist/algorithms.js +11402 -2
- package/dist/algorithms.js.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.d.ts +14 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +144 -169
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/centrality/closeness.d.ts +35 -1
- package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/closeness.js +70 -149
- package/dist/src/algorithms/centrality/closeness.js.map +1 -1
- package/dist/src/algorithms/centrality/degree.d.ts +7 -0
- package/dist/src/algorithms/centrality/degree.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/degree.js +12 -9
- package/dist/src/algorithms/centrality/degree.js.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +57 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js +304 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts +106 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js +320 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
- package/dist/src/algorithms/centrality/eigenvector.d.ts +10 -3
- package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/eigenvector.js +11 -4
- package/dist/src/algorithms/centrality/eigenvector.js.map +1 -1
- package/dist/src/algorithms/centrality/hits.d.ts +10 -3
- package/dist/src/algorithms/centrality/hits.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/hits.js +11 -4
- package/dist/src/algorithms/centrality/hits.js.map +1 -1
- package/dist/src/algorithms/centrality/index.d.ts +3 -1
- package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/index.js +2 -1
- package/dist/src/algorithms/centrality/index.js.map +1 -1
- package/dist/src/algorithms/centrality/katz.d.ts +10 -3
- package/dist/src/algorithms/centrality/katz.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/katz.js +13 -8
- package/dist/src/algorithms/centrality/katz.js.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.d.ts +31 -0
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.js +61 -1
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.d.ts +2 -3
- package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.js +67 -57
- package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
- package/dist/src/algorithms/community/index.d.ts +2 -0
- package/dist/src/algorithms/community/index.d.ts.map +1 -1
- package/dist/src/algorithms/community/index.js.map +1 -1
- package/dist/src/algorithms/community/label-propagation.d.ts +11 -4
- package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
- package/dist/src/algorithms/community/label-propagation.js +60 -38
- package/dist/src/algorithms/community/label-propagation.js.map +1 -1
- package/dist/src/algorithms/community/leiden.d.ts +3 -3
- package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
- package/dist/src/algorithms/community/leiden.js +70 -44
- package/dist/src/algorithms/community/leiden.js.map +1 -1
- package/dist/src/algorithms/community/louvain-optimized.d.ts +149 -0
- package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
- package/dist/src/algorithms/community/louvain-optimized.js +338 -0
- package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
- package/dist/src/algorithms/community/louvain.d.ts +2 -3
- package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
- package/dist/src/algorithms/community/louvain.js +35 -81
- package/dist/src/algorithms/community/louvain.js.map +1 -1
- package/dist/src/algorithms/community/modularity-utils.d.ts +55 -0
- package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
- package/dist/src/algorithms/community/modularity-utils.js +108 -0
- package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
- package/dist/src/algorithms/components/connected.d.ts +23 -0
- package/dist/src/algorithms/components/connected.d.ts.map +1 -1
- package/dist/src/algorithms/components/connected.js +29 -3
- package/dist/src/algorithms/components/connected.js.map +1 -1
- package/dist/src/algorithms/matching/bipartite.d.ts +10 -0
- package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
- package/dist/src/algorithms/matching/bipartite.js +18 -40
- package/dist/src/algorithms/matching/bipartite.js.map +1 -1
- package/dist/src/algorithms/matching/index.d.ts.map +1 -1
- package/dist/src/algorithms/matching/index.js.map +1 -1
- package/dist/src/algorithms/matching/isomorphism.d.ts +8 -0
- package/dist/src/algorithms/matching/isomorphism.d.ts.map +1 -1
- package/dist/src/algorithms/matching/isomorphism.js +36 -2
- package/dist/src/algorithms/matching/isomorphism.js.map +1 -1
- package/dist/src/algorithms/mst/index.d.ts.map +1 -1
- package/dist/src/algorithms/mst/index.js.map +1 -1
- package/dist/src/algorithms/mst/kruskal.d.ts +14 -0
- package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -1
- package/dist/src/algorithms/mst/kruskal.js +17 -3
- package/dist/src/algorithms/mst/kruskal.js.map +1 -1
- package/dist/src/algorithms/mst/prim.d.ts +9 -0
- package/dist/src/algorithms/mst/prim.d.ts.map +1 -1
- package/dist/src/algorithms/mst/prim.js +9 -0
- package/dist/src/algorithms/mst/prim.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts +10 -0
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.js +11 -12
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +44 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +195 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts +20 -2
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +30 -14
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +17 -0
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/floyd-warshall.js +17 -0
- package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -1
- package/dist/src/algorithms/shortest-path/index.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/index.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.d.ts +42 -0
- package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-unified.js +370 -0
- package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts +77 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.js +402 -0
- package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs.d.ts +4 -18
- package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs.js +5 -182
- package/dist/src/algorithms/traversal/bfs.js.map +1 -1
- package/dist/src/algorithms/traversal/dfs.d.ts +10 -0
- package/dist/src/algorithms/traversal/dfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/dfs.js +48 -0
- package/dist/src/algorithms/traversal/dfs.js.map +1 -1
- package/dist/src/algorithms/traversal/index.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/index.js.map +1 -1
- package/dist/src/benchmark-all-algorithms.d.ts +25 -0
- package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
- package/dist/src/benchmark-all-algorithms.js +491 -0
- package/dist/src/benchmark-all-algorithms.js.map +1 -0
- package/dist/src/clustering/hierarchical.d.ts +23 -15
- package/dist/src/clustering/hierarchical.d.ts.map +1 -1
- package/dist/src/clustering/hierarchical.js +226 -224
- package/dist/src/clustering/hierarchical.js.map +1 -1
- package/dist/src/clustering/index.d.ts +4 -2
- package/dist/src/clustering/index.d.ts.map +1 -1
- package/dist/src/clustering/index.js +2 -2
- package/dist/src/clustering/index.js.map +1 -1
- package/dist/src/clustering/k-core.d.ts +17 -19
- package/dist/src/clustering/k-core.d.ts.map +1 -1
- package/dist/src/clustering/k-core.js +68 -30
- package/dist/src/clustering/k-core.js.map +1 -1
- package/dist/src/clustering/mcl.d.ts +6 -0
- package/dist/src/clustering/mcl.d.ts.map +1 -1
- package/dist/src/clustering/mcl.js +34 -3
- package/dist/src/clustering/mcl.js.map +1 -1
- package/dist/src/clustering/spectral.d.ts +11 -0
- package/dist/src/clustering/spectral.d.ts.map +1 -1
- package/dist/src/clustering/spectral.js +99 -47
- package/dist/src/clustering/spectral.js.map +1 -1
- package/dist/src/core/graph.d.ts +45 -0
- package/dist/src/core/graph.d.ts.map +1 -1
- package/dist/src/core/graph.js +49 -5
- package/dist/src/core/graph.js.map +1 -1
- package/dist/src/data-structures/index.d.ts.map +1 -1
- package/dist/src/data-structures/index.js.map +1 -1
- package/dist/src/data-structures/priority-queue.d.ts +18 -1
- package/dist/src/data-structures/priority-queue.d.ts.map +1 -1
- package/dist/src/data-structures/priority-queue.js +26 -5
- package/dist/src/data-structures/priority-queue.js.map +1 -1
- package/dist/src/data-structures/union-find.d.ts +21 -0
- package/dist/src/data-structures/union-find.d.ts.map +1 -1
- package/dist/src/data-structures/union-find.js +21 -0
- package/dist/src/data-structures/union-find.js.map +1 -1
- package/dist/src/flow/ford-fulkerson.d.ts +20 -12
- package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
- package/dist/src/flow/ford-fulkerson.js +170 -217
- package/dist/src/flow/ford-fulkerson.js.map +1 -1
- package/dist/src/flow/min-cut.d.ts +6 -8
- package/dist/src/flow/min-cut.d.ts.map +1 -1
- package/dist/src/flow/min-cut.js +34 -12
- package/dist/src/flow/min-cut.js.map +1 -1
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/link-prediction/adamic-adar.d.ts +26 -0
- package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
- package/dist/src/link-prediction/adamic-adar.js +47 -30
- package/dist/src/link-prediction/adamic-adar.js.map +1 -1
- package/dist/src/link-prediction/common-neighbors.d.ts +21 -0
- package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
- package/dist/src/link-prediction/common-neighbors.js +31 -14
- package/dist/src/link-prediction/common-neighbors.js.map +1 -1
- package/dist/src/link-prediction/index.d.ts.map +1 -1
- package/dist/src/optimized/bit-packed.d.ts +193 -0
- package/dist/src/optimized/bit-packed.d.ts.map +1 -0
- package/dist/src/optimized/bit-packed.js +342 -0
- package/dist/src/optimized/bit-packed.js.map +1 -0
- package/dist/src/optimized/csr-graph.d.ts +149 -0
- package/dist/src/optimized/csr-graph.d.ts.map +1 -0
- package/dist/src/optimized/csr-graph.js +404 -0
- package/dist/src/optimized/csr-graph.js.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts +95 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.js +242 -0
- package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
- package/dist/src/optimized/graph-adapter.d.ts +111 -0
- package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
- package/dist/src/optimized/graph-adapter.js +194 -0
- package/dist/src/optimized/graph-adapter.js.map +1 -0
- package/dist/src/optimized/index.d.ts +14 -0
- package/dist/src/optimized/index.d.ts.map +1 -0
- package/dist/src/optimized/index.js +30 -0
- package/dist/src/optimized/index.js.map +1 -0
- package/dist/src/pathfinding/astar.d.ts +25 -9
- package/dist/src/pathfinding/astar.d.ts.map +1 -1
- package/dist/src/pathfinding/astar.js +25 -10
- package/dist/src/pathfinding/astar.js.map +1 -1
- package/dist/src/pathfinding/utils.d.ts +15 -6
- package/dist/src/pathfinding/utils.d.ts.map +1 -1
- package/dist/src/pathfinding/utils.js +19 -7
- package/dist/src/pathfinding/utils.js.map +1 -1
- package/dist/src/research/grsbm.d.ts +0 -1
- package/dist/src/research/grsbm.d.ts.map +1 -1
- package/dist/src/research/grsbm.js +28 -23
- package/dist/src/research/grsbm.js.map +1 -1
- package/dist/src/research/index.d.ts.map +1 -1
- package/dist/src/research/index.js.map +1 -1
- package/dist/src/research/sync.d.ts +0 -1
- package/dist/src/research/sync.d.ts.map +1 -1
- package/dist/src/research/sync.js +31 -36
- package/dist/src/research/sync.js.map +1 -1
- package/dist/src/research/terahac.d.ts +2 -1
- package/dist/src/research/terahac.d.ts.map +1 -1
- package/dist/src/research/terahac.js +39 -7
- package/dist/src/research/terahac.js.map +1 -1
- package/dist/src/types/index.d.ts +8 -0
- package/dist/src/types/index.d.ts.map +1 -1
- package/dist/src/utils/algorithm-utilities.d.ts +2 -0
- package/dist/src/utils/algorithm-utilities.d.ts.map +1 -0
- package/dist/src/utils/algorithm-utilities.js +2 -0
- package/dist/src/utils/algorithm-utilities.js.map +1 -0
- package/dist/src/utils/graph-converters.d.ts +110 -0
- package/dist/src/utils/graph-converters.d.ts.map +1 -0
- package/dist/src/utils/graph-converters.js +227 -0
- package/dist/src/utils/graph-converters.js.map +1 -0
- package/dist/src/utils/graph-utilities.d.ts +62 -0
- package/dist/src/utils/graph-utilities.d.ts.map +1 -0
- package/dist/src/utils/graph-utilities.js +148 -0
- package/dist/src/utils/graph-utilities.js.map +1 -0
- package/dist/src/utils/index.d.ts +5 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +5 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/math-utilities.d.ts +63 -0
- package/dist/src/utils/math-utilities.d.ts.map +1 -0
- package/dist/src/utils/math-utilities.js +132 -0
- package/dist/src/utils/math-utilities.js.map +1 -0
- package/dist/src/utils/matrix-utilities.d.ts +2 -0
- package/dist/src/utils/matrix-utilities.d.ts.map +1 -0
- package/dist/src/utils/matrix-utilities.js +2 -0
- package/dist/src/utils/matrix-utilities.js.map +1 -0
- package/dist/src/utils/optimization-helpers.d.ts +42 -0
- package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
- package/dist/src/utils/optimization-helpers.js +59 -0
- package/dist/src/utils/optimization-helpers.js.map +1 -0
- package/dist/src/utils/priorityQueue.d.ts +24 -0
- package/dist/src/utils/priorityQueue.d.ts.map +1 -1
- package/dist/src/utils/priorityQueue.js +34 -4
- package/dist/src/utils/priorityQueue.js.map +1 -1
- package/package.json +58 -39
- package/src/algorithms/centrality/betweenness.ts +185 -200
- package/src/algorithms/centrality/closeness.ts +93 -194
- package/src/algorithms/centrality/degree.ts +18 -22
- package/src/algorithms/centrality/delta-pagerank-simple.ts +374 -0
- package/src/algorithms/centrality/delta-pagerank.ts +458 -0
- package/src/algorithms/centrality/eigenvector.ts +14 -15
- package/src/algorithms/centrality/hits.ts +17 -17
- package/src/algorithms/centrality/index.ts +20 -13
- package/src/algorithms/centrality/katz.ts +17 -25
- package/src/algorithms/centrality/pagerank.ts +91 -16
- package/src/algorithms/community/girvan-newman.ts +90 -86
- package/src/algorithms/community/index.ts +6 -5
- package/src/algorithms/community/label-propagation.ts +69 -48
- package/src/algorithms/community/leiden.ts +88 -65
- package/src/algorithms/community/louvain-optimized.ts +474 -0
- package/src/algorithms/community/louvain.ts +52 -122
- package/src/algorithms/community/modularity-utils.ts +134 -0
- package/src/algorithms/components/connected.ts +40 -17
- package/src/algorithms/matching/bipartite.ts +24 -53
- package/src/algorithms/matching/index.ts +4 -4
- package/src/algorithms/matching/isomorphism.ts +53 -23
- package/src/algorithms/mst/index.ts +3 -4
- package/src/algorithms/mst/kruskal.ts +21 -6
- package/src/algorithms/mst/prim.ts +13 -4
- package/src/algorithms/shortest-path/bellman-ford.ts +16 -28
- package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
- package/src/algorithms/shortest-path/dijkstra.ts +38 -30
- package/src/algorithms/shortest-path/floyd-warshall.ts +21 -4
- package/src/algorithms/shortest-path/index.ts +5 -5
- package/src/algorithms/traversal/bfs-unified.ts +437 -0
- package/src/algorithms/traversal/bfs-variants.ts +520 -0
- package/src/algorithms/traversal/bfs.ts +5 -229
- package/src/algorithms/traversal/dfs.ts +61 -42
- package/src/algorithms/traversal/index.ts +3 -3
- package/src/benchmark-all-algorithms.ts +580 -0
- package/src/clustering/hierarchical.ts +268 -272
- package/src/clustering/index.ts +8 -6
- package/src/clustering/k-core.ts +93 -61
- package/src/clustering/mcl.ts +53 -23
- package/src/clustering/spectral.ts +130 -72
- package/src/core/graph.ts +58 -18
- package/src/data-structures/index.ts +2 -2
- package/src/data-structures/priority-queue.ts +36 -11
- package/src/data-structures/union-find.ts +22 -1
- package/src/flow/ford-fulkerson.ts +221 -262
- package/src/flow/min-cut.ts +59 -51
- package/src/index.ts +9 -2
- package/src/link-prediction/adamic-adar.ts +75 -74
- package/src/link-prediction/common-neighbors.ts +49 -49
- package/src/link-prediction/index.ts +1 -1
- package/src/optimized/bit-packed.ts +390 -0
- package/src/optimized/csr-graph.ts +518 -0
- package/src/optimized/direction-optimized-bfs.ts +310 -0
- package/src/optimized/graph-adapter.ts +248 -0
- package/src/optimized/index.ts +34 -0
- package/src/pathfinding/astar.ts +40 -25
- package/src/pathfinding/utils.ts +20 -13
- package/src/research/grsbm.ts +36 -39
- package/src/research/index.ts +4 -4
- package/src/research/sync.ts +41 -54
- package/src/research/terahac.ts +63 -21
- package/src/types/index.ts +8 -0
- package/src/utils/algorithm-utilities.ts +2 -0
- package/src/utils/graph-converters.ts +269 -0
- package/src/utils/graph-utilities.ts +173 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/math-utilities.ts +149 -0
- package/src/utils/matrix-utilities.ts +2 -0
- package/src/utils/optimization-helpers.ts +87 -0
- package/src/utils/priorityQueue.ts +40 -6
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
* detect community structures in large-scale networks"
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import type { Graph } from "../../core/graph.js";
|
|
13
|
+
import { graphToMap } from "../../utils/graph-converters.js";
|
|
14
|
+
import { SeededRandom, shuffle } from "../../utils/math-utilities.js";
|
|
15
|
+
|
|
12
16
|
export interface LabelPropagationOptions {
|
|
13
17
|
maxIterations?: number;
|
|
14
18
|
randomSeed?: number;
|
|
@@ -21,24 +25,16 @@ export interface LabelPropagationResult {
|
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
/**
|
|
24
|
-
* Label Propagation Algorithm
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* @
|
|
28
|
-
* @param options - Algorithm options
|
|
29
|
-
* @returns Community assignments
|
|
30
|
-
*
|
|
31
|
-
* Time Complexity: O(m) per iteration, typically O(km) for k iterations
|
|
32
|
-
* Space Complexity: O(n)
|
|
28
|
+
* Internal implementation of Label Propagation Algorithm
|
|
29
|
+
* @param graph - Map representation of the graph (node to neighbors with weights)
|
|
30
|
+
* @param options - Algorithm configuration options
|
|
31
|
+
* @returns Community assignments, iteration count, and convergence status
|
|
33
32
|
*/
|
|
34
|
-
|
|
33
|
+
function labelPropagationImpl(
|
|
35
34
|
graph: Map<string, Map<string, number>>,
|
|
36
35
|
options: LabelPropagationOptions = {},
|
|
37
36
|
): LabelPropagationResult {
|
|
38
|
-
const {
|
|
39
|
-
maxIterations = 100,
|
|
40
|
-
randomSeed = 42,
|
|
41
|
-
} = options;
|
|
37
|
+
const { maxIterations = 100, randomSeed = 42 } = options;
|
|
42
38
|
|
|
43
39
|
if (graph.size === 0) {
|
|
44
40
|
return {
|
|
@@ -49,11 +45,7 @@ export function labelPropagation(
|
|
|
49
45
|
}
|
|
50
46
|
|
|
51
47
|
// Initialize random number generator
|
|
52
|
-
|
|
53
|
-
const random = (): number => {
|
|
54
|
-
seed = ((seed * 1664525) + 1013904223) % 2147483647;
|
|
55
|
-
return seed / 2147483647;
|
|
56
|
-
};
|
|
48
|
+
const random = SeededRandom.createGenerator(randomSeed);
|
|
57
49
|
|
|
58
50
|
// Initialize labels - each node gets its own label
|
|
59
51
|
const labels = new Map<string, number>();
|
|
@@ -69,7 +61,7 @@ export function labelPropagation(
|
|
|
69
61
|
converged = true;
|
|
70
62
|
|
|
71
63
|
// Create random order for node updates
|
|
72
|
-
const nodeOrder = [...
|
|
64
|
+
const nodeOrder = [...nodes];
|
|
73
65
|
shuffle(nodeOrder, random);
|
|
74
66
|
|
|
75
67
|
// Update each node's label
|
|
@@ -157,16 +149,17 @@ export function labelPropagation(
|
|
|
157
149
|
}
|
|
158
150
|
|
|
159
151
|
/**
|
|
160
|
-
* Asynchronous Label Propagation
|
|
152
|
+
* Internal implementation of Asynchronous Label Propagation
|
|
161
153
|
* Updates all nodes simultaneously (can lead to oscillations)
|
|
154
|
+
* @param graph - Map representation of the graph (node to neighbors with weights)
|
|
155
|
+
* @param options - Algorithm configuration options
|
|
156
|
+
* @returns Community assignments, iteration count, and convergence status
|
|
162
157
|
*/
|
|
163
|
-
|
|
158
|
+
function labelPropagationAsyncImpl(
|
|
164
159
|
graph: Map<string, Map<string, number>>,
|
|
165
160
|
options: LabelPropagationOptions = {},
|
|
166
161
|
): LabelPropagationResult {
|
|
167
|
-
const {
|
|
168
|
-
maxIterations = 100,
|
|
169
|
-
} = options;
|
|
162
|
+
const { maxIterations = 100 } = options;
|
|
170
163
|
|
|
171
164
|
if (graph.size === 0) {
|
|
172
165
|
return {
|
|
@@ -267,30 +260,27 @@ export function labelPropagationAsync(
|
|
|
267
260
|
}
|
|
268
261
|
|
|
269
262
|
/**
|
|
270
|
-
* Semi-supervised Label Propagation
|
|
263
|
+
* Internal implementation of Semi-supervised Label Propagation
|
|
271
264
|
* Some nodes have fixed labels that don't change
|
|
265
|
+
* @param graph - Map representation of the graph (node to neighbors with weights)
|
|
266
|
+
* @param seedLabels - Map of node IDs to their fixed community labels
|
|
267
|
+
* @param options - Algorithm configuration options
|
|
268
|
+
* @returns Community assignments, iteration count, and convergence status
|
|
272
269
|
*/
|
|
273
|
-
|
|
270
|
+
function labelPropagationSemiSupervisedImpl(
|
|
274
271
|
graph: Map<string, Map<string, number>>,
|
|
275
272
|
seedLabels: Map<string, number>,
|
|
276
273
|
options: LabelPropagationOptions = {},
|
|
277
274
|
): LabelPropagationResult {
|
|
278
|
-
const {
|
|
279
|
-
maxIterations = 100,
|
|
280
|
-
randomSeed = 42,
|
|
281
|
-
} = options;
|
|
275
|
+
const { maxIterations = 100, randomSeed = 42 } = options;
|
|
282
276
|
|
|
283
277
|
// Initialize random number generator
|
|
284
|
-
|
|
285
|
-
const random = (): number => {
|
|
286
|
-
seed = ((seed * 1664525) + 1013904223) % 2147483647;
|
|
287
|
-
return seed / 2147483647;
|
|
288
|
-
};
|
|
278
|
+
const random = SeededRandom.createGenerator(randomSeed);
|
|
289
279
|
|
|
290
280
|
// Initialize labels
|
|
291
281
|
const labels = new Map<string, number>();
|
|
292
282
|
const nodes = Array.from(graph.keys());
|
|
293
|
-
let labelCounter = Math.max(...
|
|
283
|
+
let labelCounter = Math.max(...Array.from(seedLabels.values())) + 1;
|
|
294
284
|
|
|
295
285
|
for (const node of nodes) {
|
|
296
286
|
if (seedLabels.has(node)) {
|
|
@@ -376,17 +366,48 @@ export function labelPropagationSemiSupervised(
|
|
|
376
366
|
}
|
|
377
367
|
|
|
378
368
|
/**
|
|
379
|
-
*
|
|
369
|
+
* Label Propagation Algorithm
|
|
370
|
+
* Each node adopts the most frequent label among its neighbors
|
|
371
|
+
* @param graph - Undirected graph (can be weighted)
|
|
372
|
+
* @param options - Algorithm options
|
|
373
|
+
* @returns Community assignments
|
|
374
|
+
*
|
|
375
|
+
* Time Complexity: O(m) per iteration, typically O(km) for k iterations
|
|
376
|
+
* Space Complexity: O(n)
|
|
377
|
+
*/
|
|
378
|
+
export function labelPropagation(graph: Graph, options: LabelPropagationOptions = {}): LabelPropagationResult {
|
|
379
|
+
// Convert Graph to Map representation
|
|
380
|
+
const graphMap = graphToMap(graph);
|
|
381
|
+
return labelPropagationImpl(graphMap, options);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Asynchronous Label Propagation
|
|
386
|
+
* Updates all nodes simultaneously (can lead to oscillations)
|
|
387
|
+
* @param graph - Undirected graph (can be weighted)
|
|
388
|
+
* @param options - Algorithm options
|
|
389
|
+
* @returns Community assignments
|
|
380
390
|
*/
|
|
381
|
-
function
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
const swapItem = array[j];
|
|
386
|
-
if (temp !== undefined && swapItem !== undefined) {
|
|
387
|
-
array[i] = swapItem;
|
|
388
|
-
array[j] = temp;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
+
export function labelPropagationAsync(graph: Graph, options: LabelPropagationOptions = {}): LabelPropagationResult {
|
|
392
|
+
// Convert Graph to Map representation
|
|
393
|
+
const graphMap = graphToMap(graph);
|
|
394
|
+
return labelPropagationAsyncImpl(graphMap, options);
|
|
391
395
|
}
|
|
392
396
|
|
|
397
|
+
/**
|
|
398
|
+
* Semi-supervised Label Propagation
|
|
399
|
+
* Some nodes have fixed labels that don't change
|
|
400
|
+
* @param graph - Undirected graph (can be weighted)
|
|
401
|
+
* @param seedLabels - Initial fixed labels for some nodes
|
|
402
|
+
* @param options - Algorithm options
|
|
403
|
+
* @returns Community assignments
|
|
404
|
+
*/
|
|
405
|
+
export function labelPropagationSemiSupervised(
|
|
406
|
+
graph: Graph,
|
|
407
|
+
seedLabels: Map<string, number>,
|
|
408
|
+
options: LabelPropagationOptions = {},
|
|
409
|
+
): LabelPropagationResult {
|
|
410
|
+
// Convert Graph to Map representation
|
|
411
|
+
const graphMap = graphToMap(graph);
|
|
412
|
+
return labelPropagationSemiSupervisedImpl(graphMap, seedLabels, options);
|
|
413
|
+
}
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* "From Louvain to Leiden: guaranteeing well-connected communities"
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
import type { Graph } from "../../core/graph.js";
|
|
12
|
+
import { graphToMap } from "../../utils/graph-converters.js";
|
|
13
|
+
import { SeededRandom, shuffle } from "../../utils/math-utilities.js";
|
|
12
14
|
|
|
13
15
|
export interface LeidenOptions {
|
|
14
16
|
resolution?: number;
|
|
@@ -24,29 +26,17 @@ export interface LeidenResult {
|
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
|
-
* Leiden algorithm for community detection
|
|
29
|
+
* Internal implementation of Leiden algorithm for community detection
|
|
28
30
|
* Improves upon Louvain by ensuring well-connected communities
|
|
29
|
-
*
|
|
30
|
-
* @param
|
|
31
|
-
* @
|
|
32
|
-
* @returns Community assignments and modularity
|
|
33
|
-
*
|
|
34
|
-
* Time Complexity: O(m) per iteration, typically O(m log m) total
|
|
35
|
-
* Space Complexity: O(n + m)
|
|
31
|
+
* @param inputGraph - Map representation of the graph (node to neighbors with weights)
|
|
32
|
+
* @param options - Algorithm configuration options
|
|
33
|
+
* @returns Community assignments, modularity score, and iteration count
|
|
36
34
|
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
options: LeidenOptions = {},
|
|
40
|
-
): LeidenResult {
|
|
41
|
-
const {
|
|
42
|
-
resolution = 1.0,
|
|
43
|
-
randomSeed = 42,
|
|
44
|
-
maxIterations = 100,
|
|
45
|
-
threshold = 1e-7,
|
|
46
|
-
} = options;
|
|
35
|
+
function leidenImpl(inputGraph: Map<string, Map<string, number>>, options: LeidenOptions = {}): LeidenResult {
|
|
36
|
+
const { resolution = 1.0, randomSeed = 42, maxIterations = 100, threshold = 1e-7 } = options;
|
|
47
37
|
|
|
48
38
|
// Handle empty graph
|
|
49
|
-
if (
|
|
39
|
+
if (inputGraph.size === 0) {
|
|
50
40
|
return {
|
|
51
41
|
communities: new Map(),
|
|
52
42
|
modularity: 0,
|
|
@@ -54,18 +44,17 @@ export function leiden(
|
|
|
54
44
|
};
|
|
55
45
|
}
|
|
56
46
|
|
|
47
|
+
// Use a mutable variable for the current graph state
|
|
48
|
+
let currentGraph = inputGraph;
|
|
49
|
+
|
|
57
50
|
// Initialize random number generator
|
|
58
|
-
|
|
59
|
-
const random = (): number => {
|
|
60
|
-
seed = ((seed * 1664525) + 1013904223) % 2147483647;
|
|
61
|
-
return seed / 2147483647;
|
|
62
|
-
};
|
|
51
|
+
const random = SeededRandom.createGenerator(randomSeed);
|
|
63
52
|
|
|
64
53
|
// Calculate total weight
|
|
65
54
|
let totalWeight = 0;
|
|
66
55
|
const degrees = new Map<string, number>();
|
|
67
56
|
|
|
68
|
-
for (const [node, neighbors] of
|
|
57
|
+
for (const [node, neighbors] of currentGraph) {
|
|
69
58
|
let degree = 0;
|
|
70
59
|
for (const weight of neighbors.values()) {
|
|
71
60
|
degree += weight;
|
|
@@ -77,10 +66,10 @@ export function leiden(
|
|
|
77
66
|
|
|
78
67
|
// Initialize communities - each node in its own community
|
|
79
68
|
const communities = new Map<string, number>();
|
|
80
|
-
const nodes = Array.from(
|
|
69
|
+
const nodes = Array.from(currentGraph.keys());
|
|
81
70
|
nodes.forEach((node, i) => communities.set(node, i));
|
|
82
71
|
|
|
83
|
-
let modularity = calculateModularity(
|
|
72
|
+
let modularity = calculateModularity(currentGraph, communities, degrees, totalWeight, resolution);
|
|
84
73
|
let bestModularity = modularity;
|
|
85
74
|
let bestCommunities = new Map(communities);
|
|
86
75
|
let iterations = 0;
|
|
@@ -91,7 +80,7 @@ export function leiden(
|
|
|
91
80
|
let improved = false;
|
|
92
81
|
|
|
93
82
|
// Phase 1: Local moving of nodes (fast)
|
|
94
|
-
const nodeOrder = [...
|
|
83
|
+
const nodeOrder = [...nodes];
|
|
95
84
|
shuffle(nodeOrder, random);
|
|
96
85
|
|
|
97
86
|
for (const node of nodeOrder) {
|
|
@@ -100,7 +89,7 @@ export function leiden(
|
|
|
100
89
|
continue;
|
|
101
90
|
}
|
|
102
91
|
|
|
103
|
-
const neighborCommunities = getNeighborCommunities(node,
|
|
92
|
+
const neighborCommunities = getNeighborCommunities(node, currentGraph, communities);
|
|
104
93
|
|
|
105
94
|
let bestCommunity = currentCommunity;
|
|
106
95
|
let bestGain = 0;
|
|
@@ -112,7 +101,13 @@ export function leiden(
|
|
|
112
101
|
}
|
|
113
102
|
|
|
114
103
|
const gain = calculateModularityGain(
|
|
115
|
-
node,
|
|
104
|
+
node,
|
|
105
|
+
community,
|
|
106
|
+
currentGraph,
|
|
107
|
+
communities,
|
|
108
|
+
degrees,
|
|
109
|
+
totalWeight,
|
|
110
|
+
resolution,
|
|
116
111
|
);
|
|
117
112
|
|
|
118
113
|
if (gain > bestGain) {
|
|
@@ -131,12 +126,10 @@ export function leiden(
|
|
|
131
126
|
|
|
132
127
|
// Phase 2: Refinement (Leiden improvement over Louvain)
|
|
133
128
|
// Create aggregate network based on current partition
|
|
134
|
-
createAggregateNetwork(
|
|
129
|
+
createAggregateNetwork(currentGraph, communities);
|
|
135
130
|
|
|
136
131
|
// Refine partition using aggregate network
|
|
137
|
-
const subsetPartition = refinePartition(
|
|
138
|
-
graph, communities,
|
|
139
|
-
);
|
|
132
|
+
const subsetPartition = refinePartition(currentGraph, communities);
|
|
140
133
|
|
|
141
134
|
// Apply refined partition
|
|
142
135
|
for (const [node, newCommunity] of subsetPartition) {
|
|
@@ -144,7 +137,7 @@ export function leiden(
|
|
|
144
137
|
}
|
|
145
138
|
|
|
146
139
|
// Recalculate modularity
|
|
147
|
-
modularity = calculateModularity(
|
|
140
|
+
modularity = calculateModularity(currentGraph, communities, degrees, totalWeight, resolution);
|
|
148
141
|
|
|
149
142
|
// Check if we've improved
|
|
150
143
|
if (modularity > bestModularity + threshold) {
|
|
@@ -158,17 +151,17 @@ export function leiden(
|
|
|
158
151
|
}
|
|
159
152
|
|
|
160
153
|
// Phase 3: Aggregate network (create super-nodes)
|
|
161
|
-
const aggregated = aggregateCommunities(
|
|
162
|
-
if (aggregated.graph.size ===
|
|
154
|
+
const aggregated = aggregateCommunities(currentGraph, communities);
|
|
155
|
+
if (aggregated.graph.size === currentGraph.size) {
|
|
163
156
|
break;
|
|
164
157
|
} // No aggregation possible
|
|
165
158
|
|
|
166
159
|
// Continue with aggregated network
|
|
167
|
-
const {graph:
|
|
168
|
-
|
|
160
|
+
const { graph: aggregatedGraph } = aggregated;
|
|
161
|
+
currentGraph = aggregatedGraph;
|
|
169
162
|
communities.clear();
|
|
170
163
|
let communityId = 0;
|
|
171
|
-
for (const node of
|
|
164
|
+
for (const node of currentGraph.keys()) {
|
|
172
165
|
communities.set(node, communityId++);
|
|
173
166
|
}
|
|
174
167
|
}
|
|
@@ -201,6 +194,12 @@ export function leiden(
|
|
|
201
194
|
|
|
202
195
|
/**
|
|
203
196
|
* Calculate modularity of a partition
|
|
197
|
+
* @param graph - Map representation of the graph
|
|
198
|
+
* @param communities - Map of node IDs to community IDs
|
|
199
|
+
* @param degrees - Map of node IDs to their weighted degrees
|
|
200
|
+
* @param totalWeight - Total weight of all edges in the graph
|
|
201
|
+
* @param resolution - Resolution parameter for modularity calculation
|
|
202
|
+
* @returns The modularity score of the partition
|
|
204
203
|
*/
|
|
205
204
|
function calculateModularity(
|
|
206
205
|
graph: Map<string, Map<string, number>>,
|
|
@@ -242,11 +241,11 @@ function calculateModularity(
|
|
|
242
241
|
}
|
|
243
242
|
|
|
244
243
|
// Normalize and apply resolution
|
|
245
|
-
modularity /=
|
|
244
|
+
modularity /= 2 * totalWeight;
|
|
246
245
|
|
|
247
246
|
// Subtract expected edges
|
|
248
247
|
for (const weight of communityWeights.values()) {
|
|
249
|
-
modularity -= resolution * (
|
|
248
|
+
modularity -= resolution * (weight / (2 * totalWeight)) ** 2;
|
|
250
249
|
}
|
|
251
250
|
|
|
252
251
|
return modularity;
|
|
@@ -254,6 +253,10 @@ function calculateModularity(
|
|
|
254
253
|
|
|
255
254
|
/**
|
|
256
255
|
* Get communities of neighbors
|
|
256
|
+
* @param node - The node ID to get neighbor communities for
|
|
257
|
+
* @param graph - Map representation of the graph
|
|
258
|
+
* @param communities - Map of node IDs to community IDs
|
|
259
|
+
* @returns Map of community IDs to total edge weight connecting to that community
|
|
257
260
|
*/
|
|
258
261
|
function getNeighborCommunities(
|
|
259
262
|
node: string,
|
|
@@ -277,6 +280,14 @@ function getNeighborCommunities(
|
|
|
277
280
|
|
|
278
281
|
/**
|
|
279
282
|
* Calculate modularity gain from moving a node to a community
|
|
283
|
+
* @param node - The node ID to move
|
|
284
|
+
* @param targetCommunity - The target community ID
|
|
285
|
+
* @param graph - Map representation of the graph
|
|
286
|
+
* @param communities - Map of node IDs to community IDs
|
|
287
|
+
* @param degrees - Map of node IDs to their weighted degrees
|
|
288
|
+
* @param totalWeight - Total weight of all edges in the graph
|
|
289
|
+
* @param resolution - Resolution parameter for modularity calculation
|
|
290
|
+
* @returns The modularity gain from moving the node to the target community
|
|
280
291
|
*/
|
|
281
292
|
function calculateModularityGain(
|
|
282
293
|
node: string,
|
|
@@ -333,22 +344,26 @@ function calculateModularityGain(
|
|
|
333
344
|
|
|
334
345
|
// Modularity gain calculation
|
|
335
346
|
const m2 = 2 * totalWeight;
|
|
336
|
-
const gain =
|
|
337
|
-
|
|
347
|
+
const gain =
|
|
348
|
+
(weightToTarget - weightToCurrent) / totalWeight -
|
|
349
|
+
(resolution * nodeDegree * (targetDegree - currentDegree)) / (m2 * m2);
|
|
338
350
|
|
|
339
351
|
return gain;
|
|
340
352
|
}
|
|
341
353
|
|
|
342
354
|
/**
|
|
343
355
|
* Create aggregate network where each community becomes a super-node
|
|
356
|
+
* @param graph - Map representation of the graph
|
|
357
|
+
* @param communities - Map of node IDs to community IDs
|
|
358
|
+
* @returns Object with aggregate graph and node-to-community mapping
|
|
344
359
|
*/
|
|
345
360
|
function createAggregateNetwork(
|
|
346
361
|
graph: Map<string, Map<string, number>>,
|
|
347
362
|
communities: Map<string, number>,
|
|
348
363
|
): {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
364
|
+
aggregateGraph: Map<number, Map<number, number>>;
|
|
365
|
+
nodeMapping: Map<string, number>;
|
|
366
|
+
} {
|
|
352
367
|
const aggregateGraph = new Map<number, Map<number, number>>();
|
|
353
368
|
const nodeMapping = new Map<string, number>();
|
|
354
369
|
|
|
@@ -381,12 +396,15 @@ function createAggregateNetwork(
|
|
|
381
396
|
}
|
|
382
397
|
}
|
|
383
398
|
|
|
384
|
-
return {aggregateGraph, nodeMapping};
|
|
399
|
+
return { aggregateGraph, nodeMapping };
|
|
385
400
|
}
|
|
386
401
|
|
|
387
402
|
/**
|
|
388
403
|
* Refine partition (Leiden-specific improvement)
|
|
389
404
|
* Ensures well-connected communities by considering subsets
|
|
405
|
+
* @param originalGraph - Map representation of the original graph
|
|
406
|
+
* @param communities - Map of node IDs to community IDs
|
|
407
|
+
* @returns Refined community assignments with well-connected communities
|
|
390
408
|
*/
|
|
391
409
|
function refinePartition(
|
|
392
410
|
originalGraph: Map<string, Map<string, number>>,
|
|
@@ -454,6 +472,8 @@ function refinePartition(
|
|
|
454
472
|
|
|
455
473
|
/**
|
|
456
474
|
* Find connected components in undirected graph
|
|
475
|
+
* @param graph - Map representation of the graph (node to set of neighbors)
|
|
476
|
+
* @returns Array of connected components (each is a set of node IDs)
|
|
457
477
|
*/
|
|
458
478
|
function findConnectedComponents(graph: Map<string, Set<string>>): Set<string>[] {
|
|
459
479
|
const visited = new Set<string>();
|
|
@@ -492,14 +512,17 @@ function findConnectedComponents(graph: Map<string, Set<string>>): Set<string>[]
|
|
|
492
512
|
|
|
493
513
|
/**
|
|
494
514
|
* Aggregate communities into super-nodes
|
|
515
|
+
* @param graph - Map representation of the graph
|
|
516
|
+
* @param communities - Map of node IDs to community IDs
|
|
517
|
+
* @returns Object with aggregated graph and node-to-supernode mapping
|
|
495
518
|
*/
|
|
496
519
|
function aggregateCommunities(
|
|
497
520
|
graph: Map<string, Map<string, number>>,
|
|
498
521
|
communities: Map<string, number>,
|
|
499
522
|
): {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
523
|
+
graph: Map<string, Map<string, number>>;
|
|
524
|
+
mapping: Map<string, string>;
|
|
525
|
+
} {
|
|
503
526
|
const aggregated = new Map<string, Map<string, number>>();
|
|
504
527
|
const mapping = new Map<string, string>();
|
|
505
528
|
|
|
@@ -552,21 +575,21 @@ function aggregateCommunities(
|
|
|
552
575
|
}
|
|
553
576
|
}
|
|
554
577
|
|
|
555
|
-
return {graph: aggregated, mapping};
|
|
578
|
+
return { graph: aggregated, mapping };
|
|
556
579
|
}
|
|
557
580
|
|
|
558
581
|
/**
|
|
559
|
-
*
|
|
582
|
+
* Leiden algorithm for community detection
|
|
583
|
+
* Improves upon Louvain by ensuring well-connected communities
|
|
584
|
+
* @param graph - Undirected weighted graph - accepts Graph class or Map representation
|
|
585
|
+
* @param options - Algorithm options
|
|
586
|
+
* @returns Community assignments and modularity
|
|
587
|
+
*
|
|
588
|
+
* Time Complexity: O(m) per iteration, typically O(m log m) total
|
|
589
|
+
* Space Complexity: O(n + m)
|
|
560
590
|
*/
|
|
561
|
-
function
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
const swapItem = array[j];
|
|
566
|
-
if (temp !== undefined && swapItem !== undefined) {
|
|
567
|
-
array[i] = swapItem;
|
|
568
|
-
array[j] = temp;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
591
|
+
export function leiden(graph: Graph, options: LeidenOptions = {}): LeidenResult {
|
|
592
|
+
// Convert Graph to Map representation
|
|
593
|
+
const graphMap = graphToMap(graph);
|
|
594
|
+
return leidenImpl(graphMap, options);
|
|
571
595
|
}
|
|
572
|
-
|