@graphty/algorithms 2.1.1 → 2.2.0
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 +139 -50
- package/dist/algorithms.js +15260 -10390
- package/dist/algorithms.js.map +1 -1
- package/dist/algorithms.standalone.js +26675 -21542
- package/dist/algorithms.standalone.js.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.d.ts +18 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +40 -1
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/centrality/closeness.d.ts +20 -0
- package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/closeness.js +93 -8
- package/dist/src/algorithms/centrality/closeness.js.map +1 -1
- package/dist/src/algorithms/centrality/degree.d.ts +9 -0
- package/dist/src/algorithms/centrality/degree.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/degree.js +18 -0
- package/dist/src/algorithms/centrality/degree.js.map +1 -1
- package/dist/src/algorithms/centrality/eigenvector.d.ts +10 -0
- package/dist/src/algorithms/centrality/eigenvector.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/eigenvector.js +29 -0
- package/dist/src/algorithms/centrality/eigenvector.js.map +1 -1
- package/dist/src/algorithms/centrality/hits.d.ts +9 -0
- package/dist/src/algorithms/centrality/hits.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/hits.js +23 -0
- package/dist/src/algorithms/centrality/hits.js.map +1 -1
- package/dist/src/algorithms/centrality/katz.d.ts +9 -0
- package/dist/src/algorithms/centrality/katz.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/katz.js +31 -0
- package/dist/src/algorithms/centrality/katz.js.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.d.ts +13 -13
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.js +47 -10
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman-legacy.d.ts +27 -0
- package/dist/src/algorithms/community/girvan-newman-legacy.d.ts.map +1 -0
- package/dist/src/algorithms/community/girvan-newman-legacy.js +335 -0
- package/dist/src/algorithms/community/girvan-newman-legacy.js.map +1 -0
- package/dist/src/algorithms/community/girvan-newman.d.ts +5 -3
- package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.js +34 -308
- package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
- package/dist/src/algorithms/community/label-propagation.d.ts +9 -6
- package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
- package/dist/src/algorithms/community/label-propagation.js +24 -110
- package/dist/src/algorithms/community/label-propagation.js.map +1 -1
- package/dist/src/algorithms/components/connected.d.ts.map +1 -1
- package/dist/src/algorithms/components/connected.js +28 -77
- package/dist/src/algorithms/components/connected.js.map +1 -1
- package/dist/src/algorithms/mst/kruskal.d.ts.map +1 -1
- package/dist/src/algorithms/mst/kruskal.js +59 -3
- package/dist/src/algorithms/mst/kruskal.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.js +46 -0
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +27 -0
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts +15 -5
- package/dist/src/algorithms/shortest-path/floyd-warshall.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/floyd-warshall.js +97 -107
- package/dist/src/algorithms/shortest-path/floyd-warshall.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.d.ts +2 -12
- package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.js +47 -308
- package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs-variants.js +5 -25
- package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs.d.ts +0 -3
- package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs.js +0 -4
- package/dist/src/algorithms/traversal/bfs.js.map +1 -1
- package/dist/src/algorithms/traversal/dfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/dfs.js +33 -154
- package/dist/src/algorithms/traversal/dfs.js.map +1 -1
- package/dist/src/clustering/hierarchical-legacy.d.ts +56 -0
- package/dist/src/clustering/hierarchical-legacy.d.ts.map +1 -0
- package/dist/src/clustering/hierarchical-legacy.js +441 -0
- package/dist/src/clustering/hierarchical-legacy.js.map +1 -0
- package/dist/src/clustering/hierarchical.d.ts +7 -39
- package/dist/src/clustering/hierarchical.d.ts.map +1 -1
- package/dist/src/clustering/hierarchical.js +56 -417
- package/dist/src/clustering/hierarchical.js.map +1 -1
- package/dist/src/clustering/k-core-legacy.d.ts +30 -0
- package/dist/src/clustering/k-core-legacy.d.ts.map +1 -0
- package/dist/src/clustering/k-core-legacy.js +191 -0
- package/dist/src/clustering/k-core-legacy.js.map +1 -0
- package/dist/src/clustering/k-core.d.ts +8 -7
- package/dist/src/clustering/k-core.d.ts.map +1 -1
- package/dist/src/clustering/k-core.js +33 -174
- package/dist/src/clustering/k-core.js.map +1 -1
- package/dist/src/clustering/mcl-legacy.d.ts +42 -0
- package/dist/src/clustering/mcl-legacy.d.ts.map +1 -0
- package/dist/src/clustering/mcl-legacy.js +386 -0
- package/dist/src/clustering/mcl-legacy.js.map +1 -0
- package/dist/src/clustering/mcl.d.ts +9 -32
- package/dist/src/clustering/mcl.d.ts.map +1 -1
- package/dist/src/clustering/mcl.js +48 -374
- package/dist/src/clustering/mcl.js.map +1 -1
- package/dist/src/index.d.ts +29 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/indexed/accelerator.d.ts +141 -11
- package/dist/src/indexed/accelerator.d.ts.map +1 -1
- package/dist/src/indexed/accelerator.js +319 -5
- package/dist/src/indexed/accelerator.js.map +1 -1
- package/dist/src/indexed/all-pairs.d.ts +59 -0
- package/dist/src/indexed/all-pairs.d.ts.map +1 -0
- package/dist/src/indexed/all-pairs.js +274 -0
- package/dist/src/indexed/all-pairs.js.map +1 -0
- package/dist/src/indexed/bellman-ford.d.ts +25 -0
- package/dist/src/indexed/bellman-ford.d.ts.map +1 -0
- package/dist/src/indexed/bellman-ford.js +59 -0
- package/dist/src/indexed/bellman-ford.js.map +1 -0
- package/dist/src/indexed/betweenness.d.ts +85 -0
- package/dist/src/indexed/betweenness.d.ts.map +1 -0
- package/dist/src/indexed/betweenness.js +188 -0
- package/dist/src/indexed/betweenness.js.map +1 -0
- package/dist/src/indexed/bfs.d.ts +69 -2
- package/dist/src/indexed/bfs.d.ts.map +1 -1
- package/dist/src/indexed/bfs.js +148 -1
- package/dist/src/indexed/bfs.js.map +1 -1
- package/dist/src/indexed/bipartite.d.ts +37 -0
- package/dist/src/indexed/bipartite.d.ts.map +1 -0
- package/dist/src/indexed/bipartite.js +54 -0
- package/dist/src/indexed/bipartite.js.map +1 -0
- package/dist/src/indexed/closeness.d.ts +49 -0
- package/dist/src/indexed/closeness.d.ts.map +1 -0
- package/dist/src/indexed/closeness.js +127 -0
- package/dist/src/indexed/closeness.js.map +1 -0
- package/dist/src/indexed/common-neighbors.d.ts +14 -1
- package/dist/src/indexed/common-neighbors.d.ts.map +1 -1
- package/dist/src/indexed/common-neighbors.js +24 -14
- package/dist/src/indexed/common-neighbors.js.map +1 -1
- package/dist/src/indexed/degree.d.ts +19 -0
- package/dist/src/indexed/degree.d.ts.map +1 -0
- package/dist/src/indexed/degree.js +45 -0
- package/dist/src/indexed/degree.js.map +1 -0
- package/dist/src/indexed/delta-pagerank.d.ts +145 -0
- package/dist/src/indexed/delta-pagerank.d.ts.map +1 -0
- package/dist/src/indexed/delta-pagerank.js +428 -0
- package/dist/src/indexed/delta-pagerank.js.map +1 -0
- package/dist/src/indexed/dfs.d.ts +55 -0
- package/dist/src/indexed/dfs.d.ts.map +1 -0
- package/dist/src/indexed/dfs.js +146 -0
- package/dist/src/indexed/dfs.js.map +1 -0
- package/dist/src/indexed/eigenvector.d.ts +48 -0
- package/dist/src/indexed/eigenvector.d.ts.map +1 -0
- package/dist/src/indexed/eigenvector.js +162 -0
- package/dist/src/indexed/eigenvector.js.map +1 -0
- package/dist/src/indexed/facade.d.ts +109 -0
- package/dist/src/indexed/facade.d.ts.map +1 -0
- package/dist/src/indexed/facade.js +204 -0
- package/dist/src/indexed/facade.js.map +1 -0
- package/dist/src/indexed/flow.d.ts +120 -0
- package/dist/src/indexed/flow.d.ts.map +1 -0
- package/dist/src/indexed/flow.js +377 -0
- package/dist/src/indexed/flow.js.map +1 -0
- package/dist/src/indexed/girvan-newman.d.ts +42 -0
- package/dist/src/indexed/girvan-newman.d.ts.map +1 -0
- package/dist/src/indexed/girvan-newman.js +90 -0
- package/dist/src/indexed/girvan-newman.js.map +1 -0
- package/dist/src/indexed/grsbm.d.ts +85 -0
- package/dist/src/indexed/grsbm.d.ts.map +1 -0
- package/dist/src/indexed/grsbm.js +287 -0
- package/dist/src/indexed/grsbm.js.map +1 -0
- package/dist/src/indexed/hierarchical.d.ts +69 -0
- package/dist/src/indexed/hierarchical.d.ts.map +1 -0
- package/dist/src/indexed/hierarchical.js +245 -0
- package/dist/src/indexed/hierarchical.js.map +1 -0
- package/dist/src/indexed/index.d.ts +29 -3
- package/dist/src/indexed/index.d.ts.map +1 -1
- package/dist/src/indexed/index.js +29 -3
- package/dist/src/indexed/index.js.map +1 -1
- package/dist/src/indexed/isomorphism.d.ts +42 -0
- package/dist/src/indexed/isomorphism.d.ts.map +1 -0
- package/dist/src/indexed/isomorphism.js +269 -0
- package/dist/src/indexed/isomorphism.js.map +1 -0
- package/dist/src/indexed/label-propagation.d.ts +134 -0
- package/dist/src/indexed/label-propagation.d.ts.map +1 -0
- package/dist/src/indexed/label-propagation.js +486 -0
- package/dist/src/indexed/label-propagation.js.map +1 -0
- package/dist/src/indexed/leiden.d.ts +52 -0
- package/dist/src/indexed/leiden.d.ts.map +1 -0
- package/dist/src/indexed/leiden.js +384 -0
- package/dist/src/indexed/leiden.js.map +1 -0
- package/dist/src/indexed/link-prediction.d.ts +147 -0
- package/dist/src/indexed/link-prediction.d.ts.map +1 -0
- package/dist/src/indexed/link-prediction.js +317 -0
- package/dist/src/indexed/link-prediction.js.map +1 -0
- package/dist/src/indexed/markov.d.ts +54 -0
- package/dist/src/indexed/markov.d.ts.map +1 -0
- package/dist/src/indexed/markov.js +284 -0
- package/dist/src/indexed/markov.js.map +1 -0
- package/dist/src/indexed/matching.d.ts +53 -0
- package/dist/src/indexed/matching.d.ts.map +1 -0
- package/dist/src/indexed/matching.js +139 -0
- package/dist/src/indexed/matching.js.map +1 -0
- package/dist/src/indexed/min-cut.d.ts +48 -0
- package/dist/src/indexed/min-cut.d.ts.map +1 -0
- package/dist/src/indexed/min-cut.js +175 -0
- package/dist/src/indexed/min-cut.js.map +1 -0
- package/dist/src/indexed/modularity.d.ts +34 -0
- package/dist/src/indexed/modularity.d.ts.map +1 -0
- package/dist/src/indexed/modularity.js +74 -0
- package/dist/src/indexed/modularity.js.map +1 -0
- package/dist/src/indexed/mst.d.ts +29 -1
- package/dist/src/indexed/mst.d.ts.map +1 -1
- package/dist/src/indexed/mst.js +62 -0
- package/dist/src/indexed/mst.js.map +1 -1
- package/dist/src/indexed/pagerank.d.ts +29 -6
- package/dist/src/indexed/pagerank.d.ts.map +1 -1
- package/dist/src/indexed/pagerank.js +107 -11
- package/dist/src/indexed/pagerank.js.map +1 -1
- package/dist/src/indexed/point-to-point.d.ts +53 -0
- package/dist/src/indexed/point-to-point.d.ts.map +1 -0
- package/dist/src/indexed/point-to-point.js +173 -0
- package/dist/src/indexed/point-to-point.js.map +1 -0
- package/dist/src/indexed/scc.d.ts +53 -0
- package/dist/src/indexed/scc.d.ts.map +1 -0
- package/dist/src/indexed/scc.js +110 -0
- package/dist/src/indexed/scc.js.map +1 -0
- package/dist/src/indexed/spectral.d.ts +61 -0
- package/dist/src/indexed/spectral.d.ts.map +1 -0
- package/dist/src/indexed/spectral.js +476 -0
- package/dist/src/indexed/spectral.js.map +1 -0
- package/dist/src/indexed/structures/bit-set.d.ts +45 -0
- package/dist/src/indexed/structures/bit-set.d.ts.map +1 -0
- package/dist/src/indexed/structures/bit-set.js +57 -0
- package/dist/src/indexed/structures/bit-set.js.map +1 -0
- package/dist/src/indexed/structures/max-heap.d.ts +52 -0
- package/dist/src/indexed/structures/max-heap.d.ts.map +1 -0
- package/dist/src/indexed/structures/max-heap.js +66 -0
- package/dist/src/indexed/structures/max-heap.js.map +1 -0
- package/dist/src/indexed/structures/min-heap.d.ts +30 -1
- package/dist/src/indexed/structures/min-heap.d.ts.map +1 -1
- package/dist/src/indexed/structures/min-heap.js +46 -6
- package/dist/src/indexed/structures/min-heap.js.map +1 -1
- package/dist/src/indexed/structures/ring-queue.d.ts +41 -0
- package/dist/src/indexed/structures/ring-queue.d.ts.map +1 -0
- package/dist/src/indexed/structures/ring-queue.js +64 -0
- package/dist/src/indexed/structures/ring-queue.js.map +1 -0
- package/dist/src/indexed/sync.d.ts +50 -0
- package/dist/src/indexed/sync.d.ts.map +1 -0
- package/dist/src/indexed/sync.js +175 -0
- package/dist/src/indexed/sync.js.map +1 -0
- package/dist/src/indexed/terahac.d.ts +58 -0
- package/dist/src/indexed/terahac.d.ts.map +1 -0
- package/dist/src/indexed/terahac.js +244 -0
- package/dist/src/indexed/terahac.js.map +1 -0
- package/dist/src/indexed/to-snapshot.d.ts +45 -2
- package/dist/src/indexed/to-snapshot.d.ts.map +1 -1
- package/dist/src/indexed/to-snapshot.js +140 -6
- package/dist/src/indexed/to-snapshot.js.map +1 -1
- package/dist/src/link-prediction/common-neighbors-legacy.d.ts +71 -0
- package/dist/src/link-prediction/common-neighbors-legacy.d.ts.map +1 -0
- package/dist/src/link-prediction/common-neighbors-legacy.js +172 -0
- package/dist/src/link-prediction/common-neighbors-legacy.js.map +1 -0
- package/dist/src/link-prediction/common-neighbors.d.ts +11 -19
- package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
- package/dist/src/link-prediction/common-neighbors.js +56 -123
- package/dist/src/link-prediction/common-neighbors.js.map +1 -1
- package/dist/src/optimized/direction-optimized-bfs.d.ts +6 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -1
- package/dist/src/optimized/direction-optimized-bfs.js +6 -0
- package/dist/src/optimized/direction-optimized-bfs.js.map +1 -1
- package/dist/src/research/grsbm-legacy.d.ts +82 -0
- package/dist/src/research/grsbm-legacy.d.ts.map +1 -0
- package/dist/src/research/grsbm-legacy.js +416 -0
- package/dist/src/research/grsbm-legacy.js.map +1 -0
- package/dist/src/research/grsbm.d.ts +9 -66
- package/dist/src/research/grsbm.d.ts.map +1 -1
- package/dist/src/research/grsbm.js +67 -391
- package/dist/src/research/grsbm.js.map +1 -1
- package/dist/src/research/sync-legacy.d.ts +48 -0
- package/dist/src/research/sync-legacy.d.ts.map +1 -0
- package/dist/src/research/sync-legacy.js +337 -0
- package/dist/src/research/sync-legacy.js.map +1 -0
- package/dist/src/research/sync.d.ts +10 -32
- package/dist/src/research/sync.d.ts.map +1 -1
- package/dist/src/research/sync.js +28 -316
- package/dist/src/research/sync.js.map +1 -1
- package/package.json +4 -3
- package/src/algorithms/centrality/betweenness.ts +51 -1
- package/src/algorithms/centrality/closeness.ts +112 -12
- package/src/algorithms/centrality/degree.ts +19 -0
- package/src/algorithms/centrality/eigenvector.ts +34 -0
- package/src/algorithms/centrality/hits.ts +24 -0
- package/src/algorithms/centrality/katz.ts +32 -0
- package/src/algorithms/centrality/pagerank.ts +53 -13
- package/src/algorithms/community/girvan-newman-legacy.ts +414 -0
- package/src/algorithms/community/girvan-newman.ts +36 -386
- package/src/algorithms/community/label-propagation.ts +24 -133
- package/src/algorithms/components/connected.ts +28 -95
- package/src/algorithms/mst/kruskal.ts +65 -4
- package/src/algorithms/shortest-path/bellman-ford.ts +49 -0
- package/src/algorithms/shortest-path/dijkstra.ts +29 -0
- package/src/algorithms/shortest-path/floyd-warshall.ts +106 -136
- package/src/algorithms/traversal/bfs-unified.ts +52 -366
- package/src/algorithms/traversal/bfs-variants.ts +5 -28
- package/src/algorithms/traversal/bfs.ts +0 -4
- package/src/algorithms/traversal/dfs.ts +39 -182
- package/src/clustering/hierarchical-legacy.ts +551 -0
- package/src/clustering/hierarchical.ts +64 -520
- package/src/clustering/k-core-legacy.ts +229 -0
- package/src/clustering/k-core.ts +38 -209
- package/src/clustering/mcl-legacy.ts +498 -0
- package/src/clustering/mcl.ts +46 -479
- package/src/index.ts +90 -3
- package/src/indexed/accelerator.ts +502 -16
- package/src/indexed/all-pairs.ts +342 -0
- package/src/indexed/bellman-ford.ts +72 -0
- package/src/indexed/betweenness.ts +258 -0
- package/src/indexed/bfs.ts +189 -3
- package/src/indexed/bipartite.ts +77 -0
- package/src/indexed/closeness.ts +160 -0
- package/src/indexed/common-neighbors.ts +31 -14
- package/src/indexed/degree.ts +55 -0
- package/src/indexed/delta-pagerank.ts +513 -0
- package/src/indexed/dfs.ts +189 -0
- package/src/indexed/eigenvector.ts +202 -0
- package/src/indexed/facade.ts +229 -0
- package/src/indexed/flow.ts +500 -0
- package/src/indexed/girvan-newman.ts +120 -0
- package/src/indexed/grsbm.ts +390 -0
- package/src/indexed/hierarchical.ts +295 -0
- package/src/indexed/index.ts +94 -3
- package/src/indexed/isomorphism.ts +305 -0
- package/src/indexed/label-propagation.ts +582 -0
- package/src/indexed/leiden.ts +436 -0
- package/src/indexed/link-prediction.ts +399 -0
- package/src/indexed/markov.ts +324 -0
- package/src/indexed/matching.ts +192 -0
- package/src/indexed/min-cut.ts +201 -0
- package/src/indexed/modularity.ts +81 -0
- package/src/indexed/mst.ts +79 -1
- package/src/indexed/pagerank.ts +128 -15
- package/src/indexed/point-to-point.ts +220 -0
- package/src/indexed/scc.ts +132 -0
- package/src/indexed/spectral.ts +550 -0
- package/src/indexed/structures/bit-set.ts +65 -0
- package/src/indexed/structures/max-heap.ts +74 -0
- package/src/indexed/structures/min-heap.ts +51 -6
- package/src/indexed/structures/ring-queue.ts +70 -0
- package/src/indexed/sync.ts +229 -0
- package/src/indexed/terahac.ts +290 -0
- package/src/indexed/to-snapshot.ts +156 -6
- package/src/link-prediction/common-neighbors-legacy.ts +252 -0
- package/src/link-prediction/common-neighbors.ts +65 -168
- package/src/optimized/direction-optimized-bfs.ts +6 -1
- package/src/research/grsbm-legacy.ts +586 -0
- package/src/research/grsbm.ts +76 -555
- package/src/research/sync-legacy.ts +456 -0
- package/src/research/sync.ts +30 -431
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The k-core decomposition as it was before `kCoreDecomposition` delegated to
|
|
3
|
+
* `indexed.kCoreDecomposition`, unchanged. The facade in `k-core.ts` still calls it for the graphs
|
|
4
|
+
* the port cannot answer the same way (a directed graph, a self-loop, a NaN weight, ids spelled alike), its facade
|
|
5
|
+
* test uses it as the oracle, and the other k-core functions read the graph through
|
|
6
|
+
* `graphToAdjacencySet`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { Graph } from "../core/graph.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Convert Graph to adjacency set representation
|
|
13
|
+
* @param graph - The input graph to convert
|
|
14
|
+
* @returns Map of node IDs to sets of neighbor node IDs
|
|
15
|
+
*/
|
|
16
|
+
export function graphToAdjacencySet(graph: Graph): Map<string, Set<string>> {
|
|
17
|
+
const adjacency = new Map<string, Set<string>>();
|
|
18
|
+
|
|
19
|
+
// Initialize all nodes
|
|
20
|
+
for (const node of graph.nodes()) {
|
|
21
|
+
adjacency.set(String(node.id), new Set());
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Add edges
|
|
25
|
+
for (const edge of graph.edges()) {
|
|
26
|
+
const source = String(edge.source);
|
|
27
|
+
const target = String(edge.target);
|
|
28
|
+
|
|
29
|
+
const sourceSet = adjacency.get(source);
|
|
30
|
+
if (sourceSet) {
|
|
31
|
+
sourceSet.add(target);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// For undirected graphs, add reverse edge
|
|
35
|
+
if (!graph.isDirected) {
|
|
36
|
+
const targetSet = adjacency.get(target);
|
|
37
|
+
if (targetSet) {
|
|
38
|
+
targetSet.add(source);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return adjacency;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface KCoreResult<T> {
|
|
47
|
+
cores: Map<number, Set<T>>;
|
|
48
|
+
coreness: Map<T, number>;
|
|
49
|
+
maxCore: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Internal implementation of K-Core decomposition algorithm
|
|
54
|
+
* @param graph - Adjacency map representation of the graph
|
|
55
|
+
* @returns K-core decomposition result with cores, coreness values, and maximum core number
|
|
56
|
+
*/
|
|
57
|
+
function kCoreDecompositionImpl<T>(graph: Map<T, Set<T>>): KCoreResult<T> {
|
|
58
|
+
if (graph.size === 0) {
|
|
59
|
+
return { cores: new Map(), coreness: new Map(), maxCore: 0 };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const n = graph.size;
|
|
63
|
+
const nodes = Array.from(graph.keys());
|
|
64
|
+
const nodeToIndex = new Map<T, number>();
|
|
65
|
+
nodes.forEach((node, i) => nodeToIndex.set(node, i));
|
|
66
|
+
|
|
67
|
+
// Initialize data structures
|
|
68
|
+
const degree = new Array<number>(n).fill(0);
|
|
69
|
+
const pos = new Array<number>(n).fill(0);
|
|
70
|
+
const vert = new Array<number>(n).fill(0);
|
|
71
|
+
const coreness = new Map<T, number>();
|
|
72
|
+
|
|
73
|
+
// Initialize coreness for all nodes to 0
|
|
74
|
+
for (let i = 0; i < n; i++) {
|
|
75
|
+
const node = nodes[i];
|
|
76
|
+
if (node !== undefined) {
|
|
77
|
+
coreness.set(node, 0);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Compute initial degrees
|
|
82
|
+
let maxDegree = 0;
|
|
83
|
+
for (let i = 0; i < n; i++) {
|
|
84
|
+
const node = nodes[i];
|
|
85
|
+
if (!node) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const neighbors = graph.get(node);
|
|
90
|
+
const nodeSize = neighbors ? neighbors.size : 0;
|
|
91
|
+
|
|
92
|
+
degree[i] = nodeSize;
|
|
93
|
+
maxDegree = Math.max(maxDegree, nodeSize);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Count nodes of each degree
|
|
97
|
+
const bin = new Array<number>(maxDegree + 1).fill(0);
|
|
98
|
+
for (let i = 0; i < n; i++) {
|
|
99
|
+
const deg = degree[i];
|
|
100
|
+
if (deg !== undefined && deg >= 0 && deg < bin.length) {
|
|
101
|
+
const currentCount = bin[deg];
|
|
102
|
+
if (currentCount !== undefined) {
|
|
103
|
+
bin[deg] = currentCount + 1;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Starting position of each degree in sorted array
|
|
109
|
+
let start = 0;
|
|
110
|
+
for (let d = 0; d <= maxDegree; d++) {
|
|
111
|
+
const temp = bin[d] ?? 0;
|
|
112
|
+
bin[d] = start;
|
|
113
|
+
start += temp;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Sort nodes by degree
|
|
117
|
+
for (let i = 0; i < n; i++) {
|
|
118
|
+
const deg = degree[i];
|
|
119
|
+
if (deg !== undefined && deg >= 0 && deg < bin.length) {
|
|
120
|
+
const posIndex = bin[deg] ?? 0;
|
|
121
|
+
pos[i] = posIndex;
|
|
122
|
+
vert[posIndex] = i;
|
|
123
|
+
const currentBin = bin[deg];
|
|
124
|
+
if (currentBin !== undefined) {
|
|
125
|
+
bin[deg] = currentBin + 1;
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
// If we can't properly place the node in vert, set its position to -1
|
|
129
|
+
// This shouldn't happen with our fixes, but just in case
|
|
130
|
+
pos[i] = -1;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Recover starting positions
|
|
135
|
+
for (let d = maxDegree; d > 0; d--) {
|
|
136
|
+
bin[d] = bin[d - 1] ?? 0;
|
|
137
|
+
}
|
|
138
|
+
bin[0] = 0;
|
|
139
|
+
|
|
140
|
+
// Main algorithm
|
|
141
|
+
for (let i = 0; i < n; i++) {
|
|
142
|
+
const v = vert[i];
|
|
143
|
+
if (v === undefined) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const node = nodes[v];
|
|
148
|
+
if (node === undefined) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const degreeV = degree[v];
|
|
153
|
+
if (degreeV !== undefined) {
|
|
154
|
+
coreness.set(node, degreeV);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Process neighbors
|
|
158
|
+
const neighbors = graph.get(node);
|
|
159
|
+
if (!neighbors) {
|
|
160
|
+
// Node has no neighbors, skip neighbor processing but coreness is already set
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
for (const neighbor of neighbors) {
|
|
165
|
+
const u = nodeToIndex.get(neighbor);
|
|
166
|
+
if (u === undefined) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const degreeU = degree[u];
|
|
171
|
+
const degreeV = degree[v];
|
|
172
|
+
if (degreeU !== undefined && degreeV !== undefined && degreeU > degreeV) {
|
|
173
|
+
const du = degreeU;
|
|
174
|
+
const pu = pos[u];
|
|
175
|
+
const pw = bin[du] ?? 0;
|
|
176
|
+
const w = vert[pw];
|
|
177
|
+
|
|
178
|
+
if (u !== w && w !== undefined && pw < n && pu !== undefined) {
|
|
179
|
+
// Swap u and w in the sorted order
|
|
180
|
+
vert[pu] = w;
|
|
181
|
+
vert[pw] = u;
|
|
182
|
+
pos[u] = pw;
|
|
183
|
+
pos[w] = pu;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const currentBin = bin[du];
|
|
187
|
+
if (currentBin !== undefined) {
|
|
188
|
+
bin[du] = currentBin + 1;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
degree[u] = degreeU - 1;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Build cores map
|
|
197
|
+
const cores = new Map<number, Set<T>>();
|
|
198
|
+
let maxCore = 0;
|
|
199
|
+
|
|
200
|
+
for (const [node, core] of coreness) {
|
|
201
|
+
if (!cores.has(core)) {
|
|
202
|
+
cores.set(core, new Set());
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const coreSet = cores.get(core);
|
|
206
|
+
if (coreSet) {
|
|
207
|
+
coreSet.add(node);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
maxCore = Math.max(maxCore, core);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return { cores, coreness, maxCore };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* K-Core decomposition algorithm
|
|
218
|
+
* Finds all k-cores in the graph and assigns coreness values to nodes
|
|
219
|
+
* @param graph - Undirected graph - accepts Graph class or Map<T, Set<T>>
|
|
220
|
+
* @returns K-core decomposition results
|
|
221
|
+
*
|
|
222
|
+
* Time Complexity: O(V + E)
|
|
223
|
+
* Space Complexity: O(V)
|
|
224
|
+
*/
|
|
225
|
+
export function kCoreDecomposition(graph: Graph): KCoreResult<string> {
|
|
226
|
+
// Convert Graph to adjacency set representation
|
|
227
|
+
const adjacencySet = graphToAdjacencySet(graph);
|
|
228
|
+
return kCoreDecompositionImpl(adjacencySet);
|
|
229
|
+
}
|
package/src/clustering/k-core.ts
CHANGED
|
@@ -4,214 +4,21 @@
|
|
|
4
4
|
* Finds the k-core subgraph where each node has at least k neighbors
|
|
5
5
|
* within the subgraph. Used for identifying cohesive groups and
|
|
6
6
|
* understanding graph structure.
|
|
7
|
+
*
|
|
8
|
+
* `kCoreDecomposition` (and `getKCore` through it) delegates to `indexed.kCoreDecomposition` on an
|
|
9
|
+
* undirected graph; the result equals the pre-migration implementation in `k-core-legacy.ts`.
|
|
7
10
|
*/
|
|
8
11
|
|
|
9
12
|
import type { Graph } from "../core/graph.js";
|
|
13
|
+
import { kCoreDecomposition as indexedKCoreDecomposition } from "../indexed/k-core.js";
|
|
14
|
+
import { needsLegacyCode, toSnapshot } from "../indexed/to-snapshot.js";
|
|
15
|
+
import {
|
|
16
|
+
graphToAdjacencySet,
|
|
17
|
+
kCoreDecomposition as legacyKCoreDecomposition,
|
|
18
|
+
type KCoreResult,
|
|
19
|
+
} from "./k-core-legacy.js";
|
|
10
20
|
|
|
11
|
-
|
|
12
|
-
* Convert Graph to adjacency set representation
|
|
13
|
-
* @param graph - The input graph to convert
|
|
14
|
-
* @returns Map of node IDs to sets of neighbor node IDs
|
|
15
|
-
*/
|
|
16
|
-
function graphToAdjacencySet(graph: Graph): Map<string, Set<string>> {
|
|
17
|
-
const adjacency = new Map<string, Set<string>>();
|
|
18
|
-
|
|
19
|
-
// Initialize all nodes
|
|
20
|
-
for (const node of graph.nodes()) {
|
|
21
|
-
adjacency.set(String(node.id), new Set());
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Add edges
|
|
25
|
-
for (const edge of graph.edges()) {
|
|
26
|
-
const source = String(edge.source);
|
|
27
|
-
const target = String(edge.target);
|
|
28
|
-
|
|
29
|
-
const sourceSet = adjacency.get(source);
|
|
30
|
-
if (sourceSet) {
|
|
31
|
-
sourceSet.add(target);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// For undirected graphs, add reverse edge
|
|
35
|
-
if (!graph.isDirected) {
|
|
36
|
-
const targetSet = adjacency.get(target);
|
|
37
|
-
if (targetSet) {
|
|
38
|
-
targetSet.add(source);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return adjacency;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface KCoreResult<T> {
|
|
47
|
-
cores: Map<number, Set<T>>;
|
|
48
|
-
coreness: Map<T, number>;
|
|
49
|
-
maxCore: number;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Internal implementation of K-Core decomposition algorithm
|
|
54
|
-
* @param graph - Adjacency map representation of the graph
|
|
55
|
-
* @returns K-core decomposition result with cores, coreness values, and maximum core number
|
|
56
|
-
*/
|
|
57
|
-
function kCoreDecompositionImpl<T>(graph: Map<T, Set<T>>): KCoreResult<T> {
|
|
58
|
-
if (graph.size === 0) {
|
|
59
|
-
return { cores: new Map(), coreness: new Map(), maxCore: 0 };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const n = graph.size;
|
|
63
|
-
const nodes = Array.from(graph.keys());
|
|
64
|
-
const nodeToIndex = new Map<T, number>();
|
|
65
|
-
nodes.forEach((node, i) => nodeToIndex.set(node, i));
|
|
66
|
-
|
|
67
|
-
// Initialize data structures
|
|
68
|
-
const degree = new Array<number>(n).fill(0);
|
|
69
|
-
const pos = new Array<number>(n).fill(0);
|
|
70
|
-
const vert = new Array<number>(n).fill(0);
|
|
71
|
-
const coreness = new Map<T, number>();
|
|
72
|
-
|
|
73
|
-
// Initialize coreness for all nodes to 0
|
|
74
|
-
for (let i = 0; i < n; i++) {
|
|
75
|
-
const node = nodes[i];
|
|
76
|
-
if (node !== undefined) {
|
|
77
|
-
coreness.set(node, 0);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Compute initial degrees
|
|
82
|
-
let maxDegree = 0;
|
|
83
|
-
for (let i = 0; i < n; i++) {
|
|
84
|
-
const node = nodes[i];
|
|
85
|
-
if (!node) {
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const neighbors = graph.get(node);
|
|
90
|
-
const nodeSize = neighbors ? neighbors.size : 0;
|
|
91
|
-
|
|
92
|
-
degree[i] = nodeSize;
|
|
93
|
-
maxDegree = Math.max(maxDegree, nodeSize);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Count nodes of each degree
|
|
97
|
-
const bin = new Array<number>(maxDegree + 1).fill(0);
|
|
98
|
-
for (let i = 0; i < n; i++) {
|
|
99
|
-
const deg = degree[i];
|
|
100
|
-
if (deg !== undefined && deg >= 0 && deg < bin.length) {
|
|
101
|
-
const currentCount = bin[deg];
|
|
102
|
-
if (currentCount !== undefined) {
|
|
103
|
-
bin[deg] = currentCount + 1;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Starting position of each degree in sorted array
|
|
109
|
-
let start = 0;
|
|
110
|
-
for (let d = 0; d <= maxDegree; d++) {
|
|
111
|
-
const temp = bin[d] ?? 0;
|
|
112
|
-
bin[d] = start;
|
|
113
|
-
start += temp;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Sort nodes by degree
|
|
117
|
-
for (let i = 0; i < n; i++) {
|
|
118
|
-
const deg = degree[i];
|
|
119
|
-
if (deg !== undefined && deg >= 0 && deg < bin.length) {
|
|
120
|
-
const posIndex = bin[deg] ?? 0;
|
|
121
|
-
pos[i] = posIndex;
|
|
122
|
-
vert[posIndex] = i;
|
|
123
|
-
const currentBin = bin[deg];
|
|
124
|
-
if (currentBin !== undefined) {
|
|
125
|
-
bin[deg] = currentBin + 1;
|
|
126
|
-
}
|
|
127
|
-
} else {
|
|
128
|
-
// If we can't properly place the node in vert, set its position to -1
|
|
129
|
-
// This shouldn't happen with our fixes, but just in case
|
|
130
|
-
pos[i] = -1;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Recover starting positions
|
|
135
|
-
for (let d = maxDegree; d > 0; d--) {
|
|
136
|
-
bin[d] = bin[d - 1] ?? 0;
|
|
137
|
-
}
|
|
138
|
-
bin[0] = 0;
|
|
139
|
-
|
|
140
|
-
// Main algorithm
|
|
141
|
-
for (let i = 0; i < n; i++) {
|
|
142
|
-
const v = vert[i];
|
|
143
|
-
if (v === undefined) {
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const node = nodes[v];
|
|
148
|
-
if (node === undefined) {
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const degreeV = degree[v];
|
|
153
|
-
if (degreeV !== undefined) {
|
|
154
|
-
coreness.set(node, degreeV);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Process neighbors
|
|
158
|
-
const neighbors = graph.get(node);
|
|
159
|
-
if (!neighbors) {
|
|
160
|
-
// Node has no neighbors, skip neighbor processing but coreness is already set
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
for (const neighbor of neighbors) {
|
|
165
|
-
const u = nodeToIndex.get(neighbor);
|
|
166
|
-
if (u === undefined) {
|
|
167
|
-
continue;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const degreeU = degree[u];
|
|
171
|
-
const degreeV = degree[v];
|
|
172
|
-
if (degreeU !== undefined && degreeV !== undefined && degreeU > degreeV) {
|
|
173
|
-
const du = degreeU;
|
|
174
|
-
const pu = pos[u];
|
|
175
|
-
const pw = bin[du] ?? 0;
|
|
176
|
-
const w = vert[pw];
|
|
177
|
-
|
|
178
|
-
if (u !== w && w !== undefined && pw < n && pu !== undefined) {
|
|
179
|
-
// Swap u and w in the sorted order
|
|
180
|
-
vert[pu] = w;
|
|
181
|
-
vert[pw] = u;
|
|
182
|
-
pos[u] = pw;
|
|
183
|
-
pos[w] = pu;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const currentBin = bin[du];
|
|
187
|
-
if (currentBin !== undefined) {
|
|
188
|
-
bin[du] = currentBin + 1;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
degree[u] = degreeU - 1;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Build cores map
|
|
197
|
-
const cores = new Map<number, Set<T>>();
|
|
198
|
-
let maxCore = 0;
|
|
199
|
-
|
|
200
|
-
for (const [node, core] of coreness) {
|
|
201
|
-
if (!cores.has(core)) {
|
|
202
|
-
cores.set(core, new Set());
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const coreSet = cores.get(core);
|
|
206
|
-
if (coreSet) {
|
|
207
|
-
coreSet.add(node);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
maxCore = Math.max(maxCore, core);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return { cores, coreness, maxCore };
|
|
214
|
-
}
|
|
21
|
+
export type { KCoreResult } from "./k-core-legacy.js";
|
|
215
22
|
|
|
216
23
|
/**
|
|
217
24
|
* Extract the k-core subgraph
|
|
@@ -479,14 +286,36 @@ export function toUndirected<T>(directedGraph: Map<T, Map<T, number>>): Map<T, S
|
|
|
479
286
|
/**
|
|
480
287
|
* K-Core decomposition algorithm
|
|
481
288
|
* Finds all k-cores in the graph and assigns coreness values to nodes
|
|
482
|
-
* @param graph - Undirected graph
|
|
483
|
-
*
|
|
289
|
+
* @param graph - Undirected graph. A directed graph is peeled over out-neighbours only, as it
|
|
290
|
+
* always was.
|
|
291
|
+
* @returns K-core decomposition results, keyed by `String(id)` in node order
|
|
484
292
|
*
|
|
485
293
|
* Time Complexity: O(V + E)
|
|
486
294
|
* Space Complexity: O(V)
|
|
487
295
|
*/
|
|
488
296
|
export function kCoreDecomposition(graph: Graph): KCoreResult<string> {
|
|
489
|
-
//
|
|
490
|
-
|
|
491
|
-
|
|
297
|
+
// The port refuses a directed graph and does not count a self-loop as a neighbour, where the old
|
|
298
|
+
// code counts one towards the node's degree; ids spelled alike are one key of the result.
|
|
299
|
+
if (graph.isDirected || needsLegacyCode(graph)) {
|
|
300
|
+
return legacyKCoreDecomposition(graph);
|
|
301
|
+
}
|
|
302
|
+
const s = toSnapshot(graph);
|
|
303
|
+
if (s.flags.hasSelfLoops) {
|
|
304
|
+
return legacyKCoreDecomposition(graph);
|
|
305
|
+
}
|
|
306
|
+
const { coreness, maxCore } = indexedKCoreDecomposition(s);
|
|
307
|
+
const byNode = new Map<string, number>();
|
|
308
|
+
const cores = new Map<number, Set<string>>();
|
|
309
|
+
for (let u = 0; u < s.nodeCount; u++) {
|
|
310
|
+
const id = String(s.ids.idOf(u));
|
|
311
|
+
const k = coreness[u];
|
|
312
|
+
byNode.set(id, k);
|
|
313
|
+
let members = cores.get(k);
|
|
314
|
+
if (members === undefined) {
|
|
315
|
+
members = new Set();
|
|
316
|
+
cores.set(k, members);
|
|
317
|
+
}
|
|
318
|
+
members.add(id);
|
|
319
|
+
}
|
|
320
|
+
return { cores, coreness: byNode, maxCore };
|
|
492
321
|
}
|