@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
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {Graph} from "../../core/graph.js";
|
|
2
|
-
import type {NodeId} from "../../types/index.js";
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { NodeId } from "../../types/index.js";
|
|
3
|
+
import { bfsWithPathCounting } from "../traversal/bfs-variants.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Betweenness centrality implementation using Brandes' algorithm
|
|
@@ -20,151 +21,218 @@ export interface BetweennessCentralityOptions {
|
|
|
20
21
|
* Whether to use endpoints in path counting (default: false)
|
|
21
22
|
*/
|
|
22
23
|
endpoints?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Whether to use optimized BFS implementation for large graphs
|
|
26
|
+
*/
|
|
27
|
+
optimized?: boolean;
|
|
23
28
|
}
|
|
24
29
|
|
|
25
30
|
/**
|
|
26
|
-
*
|
|
31
|
+
* Result of Brandes algorithm computation for a single source
|
|
27
32
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
interface BrandesResult {
|
|
34
|
+
stack: NodeId[];
|
|
35
|
+
predecessors: Map<NodeId, NodeId[]>;
|
|
36
|
+
sigma: Map<NodeId, number>;
|
|
37
|
+
distance: Map<NodeId, number>;
|
|
38
|
+
}
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Run single-source shortest path computation using BFS
|
|
42
|
+
* @param graph - The input graph to analyze
|
|
43
|
+
* @param source - The source node for shortest path computation
|
|
44
|
+
* @param optimized - Whether to use optimized BFS implementation
|
|
45
|
+
* @returns The BFS result containing stack, predecessors, sigma, and distances
|
|
46
|
+
*/
|
|
47
|
+
function brandesSingleSource(graph: Graph, source: NodeId, optimized?: boolean): BrandesResult {
|
|
48
|
+
const result = bfsWithPathCounting(graph, source, optimized !== undefined ? { optimized } : {});
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
stack: result.stack,
|
|
52
|
+
predecessors: result.predecessors,
|
|
53
|
+
sigma: result.sigma,
|
|
54
|
+
distance: result.distances,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
39
57
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Accumulate betweenness contributions from a single source
|
|
60
|
+
* @param result - The BFS result from brandesSingleSource
|
|
61
|
+
* @param source - The source node used in BFS
|
|
62
|
+
* @param centrality - The centrality map to update
|
|
63
|
+
* @param options - Algorithm configuration options
|
|
64
|
+
*/
|
|
65
|
+
function accumulateBetweenness(
|
|
66
|
+
result: BrandesResult,
|
|
67
|
+
source: NodeId,
|
|
68
|
+
centrality: Record<string, number>,
|
|
69
|
+
options: BetweennessCentralityOptions,
|
|
70
|
+
): void {
|
|
71
|
+
const { stack, predecessors, sigma } = result;
|
|
72
|
+
const delta = new Map<NodeId, number>();
|
|
73
|
+
|
|
74
|
+
// Initialize delta
|
|
75
|
+
for (const node of stack) {
|
|
76
|
+
delta.set(node, 0);
|
|
77
|
+
}
|
|
47
78
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
79
|
+
// Accumulation - back-propagation of dependencies
|
|
80
|
+
// Process nodes in reverse BFS order
|
|
81
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
82
|
+
const w = stack[i];
|
|
83
|
+
if (!w) {
|
|
84
|
+
continue;
|
|
54
85
|
}
|
|
55
86
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const queue: NodeId[] = [source];
|
|
60
|
-
|
|
61
|
-
// BFS to find shortest paths
|
|
62
|
-
while (queue.length > 0) {
|
|
63
|
-
const current = queue.shift();
|
|
64
|
-
if (!current) {
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
87
|
+
const wPreds = predecessors.get(w) ?? [];
|
|
88
|
+
const wSigma = sigma.get(w) ?? 0;
|
|
89
|
+
const wDelta = delta.get(w) ?? 0;
|
|
67
90
|
|
|
68
|
-
|
|
91
|
+
for (const v of wPreds) {
|
|
92
|
+
const vSigma = sigma.get(v) ?? 0;
|
|
93
|
+
const vDelta = delta.get(v) ?? 0;
|
|
69
94
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
let neighborDistance = distance.get(neighbor);
|
|
95
|
+
if (vSigma > 0 && wSigma > 0) {
|
|
96
|
+
let contribution = (vSigma / wSigma) * (1 + wDelta);
|
|
73
97
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
queue.push(neighbor);
|
|
81
|
-
distance.set(neighbor, currentDistance + 1);
|
|
82
|
-
neighborDistance = currentDistance + 1; // Update local variable
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Shortest path to neighbor via current
|
|
86
|
-
if (neighborDistance === currentDistance + 1) {
|
|
87
|
-
const neighborSigma = sigma.get(neighbor) ?? 0;
|
|
88
|
-
const currentSigma = sigma.get(current) ?? 0;
|
|
89
|
-
sigma.set(neighbor, neighborSigma + currentSigma);
|
|
90
|
-
|
|
91
|
-
const preds = predecessors.get(neighbor);
|
|
92
|
-
if (preds) {
|
|
93
|
-
preds.push(current);
|
|
98
|
+
// Apply endpoints option: when false, exclude endpoint contributions
|
|
99
|
+
if (!options.endpoints) {
|
|
100
|
+
// For standard betweenness, don't count paths that only involve endpoints
|
|
101
|
+
const isTargetEndpoint = wPreds.length === 0 && w !== source;
|
|
102
|
+
if (isTargetEndpoint) {
|
|
103
|
+
contribution = 0; // Exclude endpoint contributions
|
|
94
104
|
}
|
|
95
105
|
}
|
|
106
|
+
|
|
107
|
+
delta.set(v, vDelta + contribution);
|
|
96
108
|
}
|
|
97
109
|
}
|
|
98
110
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
111
|
+
if (w !== source) {
|
|
112
|
+
const currentCentrality = centrality[String(w)] ?? 0;
|
|
113
|
+
centrality[String(w)] = currentCentrality + wDelta;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
105
117
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Accumulate edge betweenness contributions from a single source
|
|
120
|
+
* @param result - The BFS result from brandesSingleSource
|
|
121
|
+
* @param source - The source node used in BFS
|
|
122
|
+
* @param edgeCentrality - The edge centrality map to update
|
|
123
|
+
* @param options - Algorithm configuration options
|
|
124
|
+
*/
|
|
125
|
+
function accumulateEdgeBetweenness(
|
|
126
|
+
result: BrandesResult,
|
|
127
|
+
source: NodeId,
|
|
128
|
+
edgeCentrality: Map<string, number>,
|
|
129
|
+
options: BetweennessCentralityOptions,
|
|
130
|
+
): void {
|
|
131
|
+
const { stack, predecessors, sigma } = result;
|
|
132
|
+
const delta = new Map<NodeId, number>();
|
|
133
|
+
|
|
134
|
+
// Initialize delta
|
|
135
|
+
for (const node of stack) {
|
|
136
|
+
delta.set(node, 0);
|
|
137
|
+
}
|
|
109
138
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
139
|
+
// Accumulation for edges
|
|
140
|
+
// Process nodes in reverse BFS order
|
|
141
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
142
|
+
const w = stack[i];
|
|
143
|
+
if (!w) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
113
146
|
|
|
114
|
-
|
|
115
|
-
|
|
147
|
+
const wPreds = predecessors.get(w) ?? [];
|
|
148
|
+
const wSigma = sigma.get(w) ?? 0;
|
|
149
|
+
const wDelta = delta.get(w) ?? 0;
|
|
116
150
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
contribution = 0; // Exclude endpoint contributions
|
|
123
|
-
}
|
|
124
|
-
}
|
|
151
|
+
for (const v of wPreds) {
|
|
152
|
+
const vSigma = sigma.get(v) ?? 0;
|
|
153
|
+
|
|
154
|
+
if (vSigma > 0 && wSigma > 0) {
|
|
155
|
+
let edgeContribution = (vSigma / wSigma) * (1 + wDelta);
|
|
125
156
|
|
|
126
|
-
|
|
157
|
+
// Apply endpoints option for edge betweenness
|
|
158
|
+
if (!options.endpoints) {
|
|
159
|
+
const isTargetEndpoint = wPreds.length === 0 && w !== source;
|
|
160
|
+
if (isTargetEndpoint) {
|
|
161
|
+
edgeContribution = 0; // Exclude endpoint contributions
|
|
162
|
+
}
|
|
127
163
|
}
|
|
164
|
+
|
|
165
|
+
// Update edge centrality
|
|
166
|
+
const edgeKey = `${String(v)}-${String(w)}`;
|
|
167
|
+
const currentEdgeCentrality = edgeCentrality.get(edgeKey) ?? 0;
|
|
168
|
+
edgeCentrality.set(edgeKey, currentEdgeCentrality + edgeContribution);
|
|
169
|
+
|
|
170
|
+
// Update node delta
|
|
171
|
+
const vDelta = delta.get(v) ?? 0;
|
|
172
|
+
delta.set(v, vDelta + edgeContribution);
|
|
128
173
|
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
129
177
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Apply normalization to centrality values
|
|
180
|
+
* @param centrality - The centrality map to normalize in place
|
|
181
|
+
* @param nodeCount - Total number of nodes in the graph
|
|
182
|
+
* @param isDirected - Whether the graph is directed
|
|
183
|
+
*/
|
|
184
|
+
function normalizeCentrality(centrality: Record<string, number>, nodeCount: number, isDirected: boolean): void {
|
|
185
|
+
const n = nodeCount;
|
|
186
|
+
const normalizationFactor = isDirected ? (n - 1) * (n - 2) : ((n - 1) * (n - 2)) / 2;
|
|
187
|
+
|
|
188
|
+
if (normalizationFactor > 0) {
|
|
189
|
+
for (const key in centrality) {
|
|
190
|
+
const value = centrality[key];
|
|
191
|
+
if (value !== undefined) {
|
|
192
|
+
centrality[key] = value / normalizationFactor;
|
|
133
193
|
}
|
|
134
194
|
}
|
|
135
195
|
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Calculate betweenness centrality for all nodes using Brandes' algorithm
|
|
200
|
+
* @param graph - The input graph to analyze
|
|
201
|
+
* @param options - Algorithm configuration options
|
|
202
|
+
* @returns Centrality scores for each node keyed by node ID
|
|
203
|
+
*/
|
|
204
|
+
export function betweennessCentrality(
|
|
205
|
+
graph: Graph,
|
|
206
|
+
options: BetweennessCentralityOptions = {},
|
|
207
|
+
): Record<string, number> {
|
|
208
|
+
const nodes = Array.from(graph.nodes()).map((node) => node.id);
|
|
209
|
+
const centrality: Record<string, number> = {};
|
|
210
|
+
|
|
211
|
+
// Initialize centrality scores
|
|
212
|
+
for (const nodeId of nodes) {
|
|
213
|
+
centrality[String(nodeId)] = 0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Brandes' algorithm - run from each source
|
|
217
|
+
for (const source of nodes) {
|
|
218
|
+
const result = brandesSingleSource(graph, source, options.optimized);
|
|
219
|
+
accumulateBetweenness(result, source, centrality, options);
|
|
220
|
+
}
|
|
136
221
|
|
|
137
222
|
// For undirected graphs, divide by 2 (each shortest path is counted twice)
|
|
138
223
|
if (!graph.isDirected) {
|
|
139
224
|
for (const nodeId of nodes) {
|
|
140
225
|
const key = String(nodeId);
|
|
141
|
-
const
|
|
142
|
-
if (
|
|
143
|
-
centrality[key] =
|
|
226
|
+
const value = centrality[key];
|
|
227
|
+
if (value !== undefined) {
|
|
228
|
+
centrality[key] = value / 2;
|
|
144
229
|
}
|
|
145
230
|
}
|
|
146
231
|
}
|
|
147
232
|
|
|
148
233
|
// Normalization
|
|
149
234
|
if (options.normalized) {
|
|
150
|
-
|
|
151
|
-
let normalizationFactor: number;
|
|
152
|
-
|
|
153
|
-
if (graph.isDirected) {
|
|
154
|
-
normalizationFactor = (n - 1) * (n - 2);
|
|
155
|
-
} else {
|
|
156
|
-
normalizationFactor = ((n - 1) * (n - 2)) / 2;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
if (normalizationFactor > 0) {
|
|
160
|
-
for (const nodeId of nodes) {
|
|
161
|
-
const key = String(nodeId);
|
|
162
|
-
const currentValue = centrality[key];
|
|
163
|
-
if (currentValue !== undefined) {
|
|
164
|
-
centrality[key] = currentValue / normalizationFactor;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
235
|
+
normalizeCentrality(centrality, nodes.length, graph.isDirected);
|
|
168
236
|
}
|
|
169
237
|
|
|
170
238
|
return centrality;
|
|
@@ -172,6 +240,10 @@ export function betweennessCentrality(
|
|
|
172
240
|
|
|
173
241
|
/**
|
|
174
242
|
* Calculate betweenness centrality for a specific node
|
|
243
|
+
* @param graph - The input graph to analyze
|
|
244
|
+
* @param targetNode - The node to calculate centrality for
|
|
245
|
+
* @param options - Algorithm configuration options
|
|
246
|
+
* @returns The betweenness centrality score for the target node
|
|
175
247
|
*/
|
|
176
248
|
export function nodeBetweennessCentrality(
|
|
177
249
|
graph: Graph,
|
|
@@ -188,6 +260,9 @@ export function nodeBetweennessCentrality(
|
|
|
188
260
|
|
|
189
261
|
/**
|
|
190
262
|
* Calculate edge betweenness centrality
|
|
263
|
+
* @param graph - The input graph to analyze
|
|
264
|
+
* @param options - Algorithm configuration options
|
|
265
|
+
* @returns Edge centrality scores keyed by edge string representation
|
|
191
266
|
*/
|
|
192
267
|
export function edgeBetweennessCentrality(
|
|
193
268
|
graph: Graph,
|
|
@@ -204,97 +279,8 @@ export function edgeBetweennessCentrality(
|
|
|
204
279
|
|
|
205
280
|
// Modified Brandes' algorithm for edge betweenness
|
|
206
281
|
for (const source of nodes) {
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
const sigma = new Map<NodeId, number>();
|
|
210
|
-
const distance = new Map<NodeId, number>();
|
|
211
|
-
const delta = new Map<NodeId, number>();
|
|
212
|
-
|
|
213
|
-
// Initialize
|
|
214
|
-
for (const nodeId of nodes) {
|
|
215
|
-
predecessors.set(nodeId, []);
|
|
216
|
-
sigma.set(nodeId, 0);
|
|
217
|
-
distance.set(nodeId, -1);
|
|
218
|
-
delta.set(nodeId, 0);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
sigma.set(source, 1);
|
|
222
|
-
distance.set(source, 0);
|
|
223
|
-
|
|
224
|
-
const queue: NodeId[] = [source];
|
|
225
|
-
|
|
226
|
-
// BFS to find shortest paths
|
|
227
|
-
while (queue.length > 0) {
|
|
228
|
-
const current = queue.shift();
|
|
229
|
-
if (!current) {
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
stack.push(current);
|
|
234
|
-
|
|
235
|
-
for (const neighbor of Array.from(graph.neighbors(current))) {
|
|
236
|
-
const currentDistance = distance.get(current);
|
|
237
|
-
let neighborDistance = distance.get(neighbor);
|
|
238
|
-
|
|
239
|
-
if (currentDistance === undefined || neighborDistance === undefined) {
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
if (neighborDistance < 0) {
|
|
244
|
-
queue.push(neighbor);
|
|
245
|
-
distance.set(neighbor, currentDistance + 1);
|
|
246
|
-
neighborDistance = currentDistance + 1; // Update local variable
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (neighborDistance === currentDistance + 1) {
|
|
250
|
-
const neighborSigma = sigma.get(neighbor) ?? 0;
|
|
251
|
-
const currentSigma = sigma.get(current) ?? 0;
|
|
252
|
-
sigma.set(neighbor, neighborSigma + currentSigma);
|
|
253
|
-
|
|
254
|
-
const preds = predecessors.get(neighbor);
|
|
255
|
-
if (preds) {
|
|
256
|
-
preds.push(current);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Accumulation for edges
|
|
263
|
-
while (stack.length > 0) {
|
|
264
|
-
const w = stack.pop();
|
|
265
|
-
if (!w) {
|
|
266
|
-
break;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
const wPreds = predecessors.get(w) ?? [];
|
|
270
|
-
const wSigma = sigma.get(w) ?? 0;
|
|
271
|
-
const wDelta = delta.get(w) ?? 0;
|
|
272
|
-
|
|
273
|
-
for (const v of wPreds) {
|
|
274
|
-
const vSigma = sigma.get(v) ?? 0;
|
|
275
|
-
|
|
276
|
-
if (vSigma > 0 && wSigma > 0) {
|
|
277
|
-
let edgeContribution = vSigma / wSigma * (1 + wDelta);
|
|
278
|
-
|
|
279
|
-
// Apply endpoints option for edge betweenness
|
|
280
|
-
if (!options.endpoints) {
|
|
281
|
-
const isTargetEndpoint = predecessors.get(w)?.length === 0 && w !== source;
|
|
282
|
-
if (isTargetEndpoint) {
|
|
283
|
-
edgeContribution = 0; // Exclude endpoint contributions
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Update edge centrality
|
|
288
|
-
const edgeKey = `${String(v)}-${String(w)}`;
|
|
289
|
-
const currentEdgeCentrality = edgeCentrality.get(edgeKey) ?? 0;
|
|
290
|
-
edgeCentrality.set(edgeKey, currentEdgeCentrality + edgeContribution);
|
|
291
|
-
|
|
292
|
-
// Update node delta
|
|
293
|
-
const vDelta = delta.get(v) ?? 0;
|
|
294
|
-
delta.set(v, vDelta + edgeContribution);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
282
|
+
const result = brandesSingleSource(graph, source, options.optimized);
|
|
283
|
+
accumulateEdgeBetweenness(result, source, edgeCentrality, options);
|
|
298
284
|
}
|
|
299
285
|
|
|
300
286
|
// For undirected graphs, divide by 2 (each shortest path is counted twice)
|
|
@@ -318,4 +304,3 @@ export function edgeBetweennessCentrality(
|
|
|
318
304
|
|
|
319
305
|
return edgeCentrality;
|
|
320
306
|
}
|
|
321
|
-
|