@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 { bfsDistancesOnly, bfsWeightedDistances } from "../traversal/bfs-variants.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Closeness centrality implementation
|
|
@@ -25,39 +26,26 @@ export interface ClosenessCentralityOptions {
|
|
|
25
26
|
* Consider only nodes within this distance (default: undefined = all nodes)
|
|
26
27
|
*/
|
|
27
28
|
cutoff?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Whether to use optimized BFS implementation for large graphs
|
|
31
|
+
*/
|
|
32
|
+
optimized?: boolean;
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
/**
|
|
31
|
-
* Calculate closeness centrality
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const nodes = Array.from(graph.nodes()).map((node) => node.id);
|
|
38
|
-
const centrality: Record<string, number> = {};
|
|
39
|
-
|
|
40
|
-
for (const sourceNode of nodes) {
|
|
41
|
-
centrality[String(sourceNode)] = nodeClosenessCentrality(graph, sourceNode, options);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return centrality;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Calculate closeness centrality for a specific node
|
|
36
|
+
* Calculate closeness centrality from distances
|
|
37
|
+
* @param distances - Map of node IDs to their distances from source
|
|
38
|
+
* @param sourceNode - The source node for distance calculations
|
|
39
|
+
* @param totalNodes - Total number of nodes in the graph
|
|
40
|
+
* @param options - Algorithm configuration options
|
|
41
|
+
* @returns The closeness centrality score for the source node
|
|
49
42
|
*/
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
function calculateClosenessFromDistances(
|
|
44
|
+
distances: Map<NodeId, number>,
|
|
45
|
+
sourceNode: NodeId,
|
|
46
|
+
totalNodes: number,
|
|
47
|
+
options: ClosenessCentralityOptions,
|
|
54
48
|
): number {
|
|
55
|
-
if (!graph.hasNode(node)) {
|
|
56
|
-
throw new Error(`Node ${String(node)} not found in graph`);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const distances = singleSourceShortestPathLengths(graph, node, options.cutoff);
|
|
60
|
-
|
|
61
49
|
if (distances.size <= 1) {
|
|
62
50
|
return 0; // No other nodes reachable
|
|
63
51
|
}
|
|
@@ -66,18 +54,23 @@ export function nodeClosenessCentrality(
|
|
|
66
54
|
|
|
67
55
|
if (options.harmonic) {
|
|
68
56
|
// Harmonic centrality: sum of reciprocals of distances
|
|
69
|
-
for (const [targetNode, distance] of
|
|
70
|
-
if (targetNode !==
|
|
57
|
+
for (const [targetNode, distance] of distances) {
|
|
58
|
+
if (targetNode !== sourceNode && distance > 0 && distance < Infinity) {
|
|
71
59
|
centrality += 1 / distance;
|
|
72
60
|
}
|
|
73
61
|
}
|
|
62
|
+
|
|
63
|
+
// Normalization for harmonic centrality
|
|
64
|
+
if (options.normalized && totalNodes > 1) {
|
|
65
|
+
centrality = centrality / (totalNodes - 1);
|
|
66
|
+
}
|
|
74
67
|
} else {
|
|
75
68
|
// Standard closeness: reciprocal of sum of distances
|
|
76
69
|
let totalDistance = 0;
|
|
77
70
|
let reachableNodes = 0;
|
|
78
71
|
|
|
79
|
-
for (const [targetNode, distance] of
|
|
80
|
-
if (targetNode !==
|
|
72
|
+
for (const [targetNode, distance] of distances) {
|
|
73
|
+
if (targetNode !== sourceNode && distance < Infinity) {
|
|
81
74
|
totalDistance += distance;
|
|
82
75
|
reachableNodes++;
|
|
83
76
|
}
|
|
@@ -87,74 +80,77 @@ export function nodeClosenessCentrality(
|
|
|
87
80
|
centrality = 1 / totalDistance;
|
|
88
81
|
|
|
89
82
|
// Wasserman and Faust normalization for disconnected graphs
|
|
90
|
-
if (options.normalized) {
|
|
91
|
-
|
|
92
|
-
centrality = centrality * reachableNodes / (n - 1);
|
|
83
|
+
if (options.normalized && totalNodes > 1) {
|
|
84
|
+
centrality = (centrality * reachableNodes) / (totalNodes - 1);
|
|
93
85
|
}
|
|
94
86
|
}
|
|
95
87
|
}
|
|
96
88
|
|
|
97
|
-
// Normalization for harmonic centrality
|
|
98
|
-
if (options.harmonic && options.normalized) {
|
|
99
|
-
const n = Array.from(graph.nodes()).length;
|
|
100
|
-
if (n > 1) {
|
|
101
|
-
centrality = centrality / (n - 1);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
89
|
return centrality;
|
|
106
90
|
}
|
|
107
91
|
|
|
108
92
|
/**
|
|
109
|
-
*
|
|
93
|
+
* Calculate closeness centrality for all nodes in the graph
|
|
94
|
+
*
|
|
95
|
+
* Closeness centrality measures how close a node is to all other nodes
|
|
96
|
+
* in the graph. It is the reciprocal of the sum of the shortest path
|
|
97
|
+
* distances to all other reachable nodes.
|
|
98
|
+
* @param graph - The input graph
|
|
99
|
+
* @param options - Algorithm options
|
|
100
|
+
* @returns Centrality scores for each node
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const graph = new Graph();
|
|
104
|
+
* graph.addEdge("A", "B");
|
|
105
|
+
* graph.addEdge("B", "C");
|
|
106
|
+
*
|
|
107
|
+
* const centrality = closenessCentrality(graph);
|
|
108
|
+
* // { A: 0.5, B: 1.0, C: 0.5 }
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* Time Complexity: O(V * (V + E)) for unweighted graphs
|
|
112
|
+
* Space Complexity: O(V)
|
|
110
113
|
*/
|
|
111
|
-
function
|
|
112
|
-
graph
|
|
113
|
-
|
|
114
|
-
cutoff?: number,
|
|
115
|
-
): Map<NodeId, number> {
|
|
116
|
-
const distances = new Map<NodeId, number>();
|
|
117
|
-
const visited = new Set<NodeId>();
|
|
118
|
-
const queue: {node: NodeId, distance: number}[] = [];
|
|
119
|
-
|
|
120
|
-
// Initialize
|
|
121
|
-
queue.push({node: source, distance: 0});
|
|
122
|
-
visited.add(source);
|
|
123
|
-
distances.set(source, 0);
|
|
124
|
-
|
|
125
|
-
while (queue.length > 0) {
|
|
126
|
-
const current = queue.shift();
|
|
127
|
-
if (!current) {
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Skip if beyond cutoff
|
|
132
|
-
if (cutoff !== undefined && current.distance >= cutoff) {
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
114
|
+
export function closenessCentrality(graph: Graph, options: ClosenessCentralityOptions = {}): Record<string, number> {
|
|
115
|
+
const nodes = Array.from(graph.nodes()).map((node) => node.id);
|
|
116
|
+
const centrality: Record<string, number> = {};
|
|
135
117
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const newDistance = current.distance + 1;
|
|
118
|
+
for (const sourceNode of nodes) {
|
|
119
|
+
centrality[String(sourceNode)] = nodeClosenessCentrality(graph, sourceNode, options);
|
|
120
|
+
}
|
|
140
121
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
122
|
+
return centrality;
|
|
123
|
+
}
|
|
145
124
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Calculate closeness centrality for a specific node
|
|
127
|
+
* @param graph - The input graph to analyze
|
|
128
|
+
* @param node - The node to calculate centrality for
|
|
129
|
+
* @param options - Algorithm configuration options
|
|
130
|
+
* @returns The closeness centrality score for the node
|
|
131
|
+
*/
|
|
132
|
+
export function nodeClosenessCentrality(graph: Graph, node: NodeId, options: ClosenessCentralityOptions = {}): number {
|
|
133
|
+
if (!graph.hasNode(node)) {
|
|
134
|
+
throw new Error(`Node ${String(node)} not found in graph`);
|
|
151
135
|
}
|
|
152
136
|
|
|
153
|
-
|
|
137
|
+
// Use optimized BFS variant for unweighted graphs
|
|
138
|
+
const distances = bfsDistancesOnly(
|
|
139
|
+
graph,
|
|
140
|
+
node,
|
|
141
|
+
options.cutoff,
|
|
142
|
+
options.optimized !== undefined ? { optimized: options.optimized } : {},
|
|
143
|
+
);
|
|
144
|
+
const totalNodes = graph.nodeCount;
|
|
145
|
+
|
|
146
|
+
return calculateClosenessFromDistances(distances, node, totalNodes, options);
|
|
154
147
|
}
|
|
155
148
|
|
|
156
149
|
/**
|
|
157
150
|
* Calculate weighted closeness centrality using Dijkstra's algorithm
|
|
151
|
+
* @param graph - The input graph to analyze
|
|
152
|
+
* @param options - Algorithm configuration options
|
|
153
|
+
* @returns Centrality scores for each node keyed by node ID
|
|
158
154
|
*/
|
|
159
155
|
export function weightedClosenessCentrality(
|
|
160
156
|
graph: Graph,
|
|
@@ -172,6 +168,10 @@ export function weightedClosenessCentrality(
|
|
|
172
168
|
|
|
173
169
|
/**
|
|
174
170
|
* Calculate weighted closeness centrality for a specific node using Dijkstra
|
|
171
|
+
* @param graph - The input graph to analyze
|
|
172
|
+
* @param node - The node to calculate centrality for
|
|
173
|
+
* @param options - Algorithm configuration options
|
|
174
|
+
* @returns The weighted closeness centrality score for the node
|
|
175
175
|
*/
|
|
176
176
|
export function nodeWeightedClosenessCentrality(
|
|
177
177
|
graph: Graph,
|
|
@@ -182,115 +182,14 @@ export function nodeWeightedClosenessCentrality(
|
|
|
182
182
|
throw new Error(`Node ${String(node)} not found in graph`);
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if (options.harmonic) {
|
|
194
|
-
// Harmonic centrality: sum of reciprocals of distances
|
|
195
|
-
for (const [targetNode, distance] of Array.from(distances)) {
|
|
196
|
-
if (targetNode !== node && distance > 0 && distance < Infinity) {
|
|
197
|
-
centrality += 1 / distance;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
} else {
|
|
201
|
-
// Standard closeness: reciprocal of sum of distances
|
|
202
|
-
let totalDistance = 0;
|
|
203
|
-
let reachableNodes = 0;
|
|
204
|
-
|
|
205
|
-
for (const [targetNode, distance] of Array.from(distances)) {
|
|
206
|
-
if (targetNode !== node && distance < Infinity) {
|
|
207
|
-
totalDistance += distance;
|
|
208
|
-
reachableNodes++;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (totalDistance > 0) {
|
|
213
|
-
centrality = 1 / totalDistance;
|
|
214
|
-
|
|
215
|
-
// Wasserman and Faust normalization for disconnected graphs
|
|
216
|
-
if (options.normalized) {
|
|
217
|
-
const n = Array.from(graph.nodes()).length;
|
|
218
|
-
centrality = centrality * reachableNodes / (n - 1);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Normalization for harmonic centrality
|
|
224
|
-
if (options.harmonic && options.normalized) {
|
|
225
|
-
const n = Array.from(graph.nodes()).length;
|
|
226
|
-
if (n > 1) {
|
|
227
|
-
centrality = centrality / (n - 1);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return centrality;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Single-source shortest path distances using Dijkstra's algorithm
|
|
236
|
-
*/
|
|
237
|
-
function dijkstraDistances(
|
|
238
|
-
graph: Graph,
|
|
239
|
-
source: NodeId,
|
|
240
|
-
cutoff?: number,
|
|
241
|
-
): Map<NodeId, number> {
|
|
242
|
-
const distances = new Map<NodeId, number>();
|
|
243
|
-
const visited = new Set<NodeId>();
|
|
244
|
-
const pq: {node: NodeId, distance: number}[] = [];
|
|
245
|
-
|
|
246
|
-
// Initialize distances
|
|
247
|
-
for (const node of Array.from(graph.nodes())) {
|
|
248
|
-
distances.set(node.id, node.id === source ? 0 : Infinity);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
pq.push({node: source, distance: 0});
|
|
252
|
-
|
|
253
|
-
while (pq.length > 0) {
|
|
254
|
-
// Simple priority queue (could be optimized with a proper heap)
|
|
255
|
-
pq.sort((a, b) => a.distance - b.distance);
|
|
256
|
-
const current = pq.shift();
|
|
257
|
-
|
|
258
|
-
if (!current || visited.has(current.node)) {
|
|
259
|
-
continue;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
visited.add(current.node);
|
|
263
|
-
|
|
264
|
-
// Skip if beyond cutoff
|
|
265
|
-
if (cutoff !== undefined && current.distance > cutoff) {
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Explore neighbors
|
|
270
|
-
for (const neighbor of Array.from(graph.neighbors(current.node))) {
|
|
271
|
-
if (visited.has(neighbor)) {
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
const edge = graph.getEdge(current.node, neighbor);
|
|
276
|
-
if (!edge) {
|
|
277
|
-
continue;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const edgeWeight = edge.weight ?? 1;
|
|
281
|
-
const tentativeDistance = current.distance + edgeWeight;
|
|
282
|
-
const currentDistance = distances.get(neighbor) ?? Infinity;
|
|
283
|
-
|
|
284
|
-
if (tentativeDistance < currentDistance) {
|
|
285
|
-
distances.set(neighbor, tentativeDistance);
|
|
286
|
-
|
|
287
|
-
// Skip if beyond cutoff
|
|
288
|
-
if (cutoff === undefined || tentativeDistance <= cutoff) {
|
|
289
|
-
pq.push({node: neighbor, distance: tentativeDistance});
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
}
|
|
185
|
+
// Use optimized weighted BFS variant (simplified Dijkstra)
|
|
186
|
+
const distances = bfsWeightedDistances(
|
|
187
|
+
graph,
|
|
188
|
+
node,
|
|
189
|
+
options.cutoff,
|
|
190
|
+
options.optimized !== undefined ? { optimized: options.optimized } : {},
|
|
191
|
+
);
|
|
192
|
+
const totalNodes = graph.nodeCount;
|
|
294
193
|
|
|
295
|
-
return distances;
|
|
194
|
+
return calculateClosenessFromDistances(distances, node, totalNodes, options);
|
|
296
195
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {Graph} from "../../core/graph.js";
|
|
2
|
-
import type {CentralityOptions, CentralityResult} from "../../types/index.js";
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { CentralityOptions, CentralityResult } from "../../types/index.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Degree centrality implementation
|
|
@@ -10,18 +10,18 @@ import type {CentralityOptions, CentralityResult} from "../../types/index.js";
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Calculate degree centrality for all nodes in the graph
|
|
13
|
+
* @param graph - The input graph to analyze
|
|
14
|
+
* @param options - Algorithm configuration options
|
|
15
|
+
* @returns Centrality scores for each node keyed by node ID
|
|
13
16
|
*/
|
|
14
|
-
export function degreeCentrality(
|
|
15
|
-
graph: Graph,
|
|
16
|
-
options: CentralityOptions = {},
|
|
17
|
-
): CentralityResult {
|
|
17
|
+
export function degreeCentrality(graph: Graph, options: CentralityOptions = {}): CentralityResult {
|
|
18
18
|
const centrality: CentralityResult = {};
|
|
19
|
-
const {nodeCount} = graph;
|
|
19
|
+
const { nodeCount } = graph;
|
|
20
20
|
|
|
21
|
-
// Calculate normalization factor
|
|
22
|
-
const maxPossibleDegree =
|
|
21
|
+
// Calculate normalization factor (same for both directed and undirected graphs)
|
|
22
|
+
const maxPossibleDegree = nodeCount - 1;
|
|
23
23
|
|
|
24
|
-
for (const node of
|
|
24
|
+
for (const node of graph.nodes()) {
|
|
25
25
|
let degree: number;
|
|
26
26
|
|
|
27
27
|
if (graph.isDirected && options.mode) {
|
|
@@ -49,9 +49,7 @@ export function degreeCentrality(
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
// Apply normalization if requested
|
|
52
|
-
const normalizedDegree = options.normalized && maxPossibleDegree > 0 ?
|
|
53
|
-
degree / maxPossibleDegree :
|
|
54
|
-
degree;
|
|
52
|
+
const normalizedDegree = options.normalized && maxPossibleDegree > 0 ? degree / maxPossibleDegree : degree;
|
|
55
53
|
|
|
56
54
|
centrality[node.id.toString()] = normalizedDegree;
|
|
57
55
|
}
|
|
@@ -61,17 +59,17 @@ export function degreeCentrality(
|
|
|
61
59
|
|
|
62
60
|
/**
|
|
63
61
|
* Calculate degree centrality for a specific node
|
|
62
|
+
* @param graph - The input graph to analyze
|
|
63
|
+
* @param nodeId - The node to calculate centrality for
|
|
64
|
+
* @param options - Algorithm configuration options
|
|
65
|
+
* @returns The degree centrality score for the node
|
|
64
66
|
*/
|
|
65
|
-
export function nodeDegreeCentrality(
|
|
66
|
-
graph: Graph,
|
|
67
|
-
nodeId: string | number,
|
|
68
|
-
options: CentralityOptions = {},
|
|
69
|
-
): number {
|
|
67
|
+
export function nodeDegreeCentrality(graph: Graph, nodeId: string | number, options: CentralityOptions = {}): number {
|
|
70
68
|
if (!graph.hasNode(nodeId)) {
|
|
71
69
|
throw new Error(`Node ${String(nodeId)} not found in graph`);
|
|
72
70
|
}
|
|
73
71
|
|
|
74
|
-
const {nodeCount} = graph;
|
|
72
|
+
const { nodeCount } = graph;
|
|
75
73
|
let degree: number;
|
|
76
74
|
|
|
77
75
|
if (graph.isDirected && options.mode) {
|
|
@@ -99,7 +97,5 @@ export function nodeDegreeCentrality(
|
|
|
99
97
|
// Apply normalization if requested
|
|
100
98
|
const maxPossibleDegree = nodeCount - 1;
|
|
101
99
|
|
|
102
|
-
return options.normalized && maxPossibleDegree > 0 ?
|
|
103
|
-
degree / maxPossibleDegree :
|
|
104
|
-
degree;
|
|
100
|
+
return options.normalized && maxPossibleDegree > 0 ? degree / maxPossibleDegree : degree;
|
|
105
101
|
}
|