@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
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import { PriorityQueue } from "../../data-structures/priority-queue.js";
|
|
3
|
+
import type { NodeId } from "../../types/index.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Delta-based PageRank implementation for faster convergence
|
|
7
|
+
*
|
|
8
|
+
* This algorithm tracks changes (deltas) between iterations and only processes
|
|
9
|
+
* nodes with significant changes, dramatically reducing computation for graphs
|
|
10
|
+
* where only some nodes are actively changing their PageRank values.
|
|
11
|
+
*
|
|
12
|
+
* Key optimizations:
|
|
13
|
+
* - Only active nodes (with significant deltas) are processed
|
|
14
|
+
* - Early termination for converged vertices
|
|
15
|
+
* - Priority queue processing for high-impact updates
|
|
16
|
+
* - Adaptive convergence detection per vertex
|
|
17
|
+
*
|
|
18
|
+
* Expected speedup: 10-100x for incremental updates on large graphs
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
export interface DeltaPageRankOptions {
|
|
22
|
+
/**
|
|
23
|
+
* Damping factor (probability of following a link) (default: 0.85)
|
|
24
|
+
*/
|
|
25
|
+
dampingFactor?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Convergence tolerance (default: 1e-6)
|
|
28
|
+
*/
|
|
29
|
+
tolerance?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Maximum number of iterations (default: 100)
|
|
32
|
+
*/
|
|
33
|
+
maxIterations?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Minimum delta to keep vertex active (default: tolerance / 10)
|
|
36
|
+
*/
|
|
37
|
+
deltaThreshold?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Personalization vector for Personalized PageRank (default: null)
|
|
40
|
+
*/
|
|
41
|
+
personalization?: Map<NodeId, number>;
|
|
42
|
+
/**
|
|
43
|
+
* Weight attribute for weighted PageRank (default: null = unweighted)
|
|
44
|
+
*/
|
|
45
|
+
weight?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Delta-based PageRank class that tracks changes between iterations
|
|
50
|
+
* and only processes nodes with significant changes for improved performance.
|
|
51
|
+
*/
|
|
52
|
+
export class DeltaPageRank {
|
|
53
|
+
private graph: Graph;
|
|
54
|
+
private scores: Map<NodeId, number>;
|
|
55
|
+
private deltas: Map<NodeId, number>;
|
|
56
|
+
private activeNodes: Set<NodeId>;
|
|
57
|
+
private outDegrees: Map<NodeId, number>;
|
|
58
|
+
private outWeights: Map<NodeId, number>;
|
|
59
|
+
private danglingNodes: Set<NodeId>;
|
|
60
|
+
private nodeCount: number;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Creates a new DeltaPageRank instance for the given graph.
|
|
64
|
+
* @param graph - The directed graph to compute PageRank on
|
|
65
|
+
*/
|
|
66
|
+
constructor(graph: Graph) {
|
|
67
|
+
if (!graph.isDirected) {
|
|
68
|
+
throw new Error("DeltaPageRank requires a directed graph");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this.graph = graph;
|
|
72
|
+
this.scores = new Map();
|
|
73
|
+
this.deltas = new Map();
|
|
74
|
+
this.activeNodes = new Set();
|
|
75
|
+
this.outDegrees = new Map();
|
|
76
|
+
this.outWeights = new Map();
|
|
77
|
+
this.danglingNodes = new Set();
|
|
78
|
+
this.nodeCount = graph.nodeCount;
|
|
79
|
+
|
|
80
|
+
this.initialize();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private initialize(): void {
|
|
84
|
+
const initialValue = 1.0 / this.nodeCount;
|
|
85
|
+
|
|
86
|
+
// Initialize data structures
|
|
87
|
+
for (const node of this.graph.nodes()) {
|
|
88
|
+
const nodeId = node.id;
|
|
89
|
+
this.scores.set(nodeId, 0); // Start with zero, will add initial value as delta
|
|
90
|
+
this.deltas.set(nodeId, initialValue);
|
|
91
|
+
this.activeNodes.add(nodeId);
|
|
92
|
+
|
|
93
|
+
// Precompute out-degrees and weights
|
|
94
|
+
let outDegree = 0;
|
|
95
|
+
let totalOutWeight = 0;
|
|
96
|
+
|
|
97
|
+
for (const neighbor of Array.from(this.graph.neighbors(nodeId))) {
|
|
98
|
+
outDegree++;
|
|
99
|
+
const edge = this.graph.getEdge(nodeId, neighbor);
|
|
100
|
+
totalOutWeight += edge?.weight ?? 1;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
this.outDegrees.set(nodeId, outDegree);
|
|
104
|
+
this.outWeights.set(nodeId, totalOutWeight);
|
|
105
|
+
|
|
106
|
+
if (outDegree === 0) {
|
|
107
|
+
this.danglingNodes.add(nodeId);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Computes PageRank scores using delta-based iteration for faster convergence.
|
|
114
|
+
* @param options - Configuration options for PageRank computation
|
|
115
|
+
* @returns Map of node IDs to their PageRank scores
|
|
116
|
+
*/
|
|
117
|
+
public compute(options: DeltaPageRankOptions = {}): Map<NodeId, number> {
|
|
118
|
+
const {
|
|
119
|
+
dampingFactor = 0.85,
|
|
120
|
+
tolerance = 1e-6,
|
|
121
|
+
maxIterations = 100,
|
|
122
|
+
deltaThreshold = tolerance / 10,
|
|
123
|
+
personalization,
|
|
124
|
+
weight,
|
|
125
|
+
} = options;
|
|
126
|
+
|
|
127
|
+
if (dampingFactor < 0 || dampingFactor > 1) {
|
|
128
|
+
throw new Error("Damping factor must be between 0 and 1");
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (this.nodeCount === 0) {
|
|
132
|
+
return new Map();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Normalize personalization vector if provided
|
|
136
|
+
let personalVector: Map<NodeId, number> | null = null;
|
|
137
|
+
if (personalization) {
|
|
138
|
+
personalVector = new Map(personalization);
|
|
139
|
+
this.normalizeMap(personalVector);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const randomJump = (1 - dampingFactor) / this.nodeCount;
|
|
143
|
+
let iteration = 0;
|
|
144
|
+
|
|
145
|
+
while (this.activeNodes.size > 0 && iteration < maxIterations) {
|
|
146
|
+
iteration++;
|
|
147
|
+
|
|
148
|
+
// Create next iteration's deltas
|
|
149
|
+
const nextDeltas = new Map<NodeId, number>();
|
|
150
|
+
|
|
151
|
+
// Initialize all nodes with zero delta
|
|
152
|
+
for (const node of this.graph.nodes()) {
|
|
153
|
+
nextDeltas.set(node.id, 0);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Handle dangling nodes contribution
|
|
157
|
+
let danglingSum = 0;
|
|
158
|
+
for (const danglingNode of this.danglingNodes) {
|
|
159
|
+
const currentScore = this.scores.get(danglingNode) ?? 0;
|
|
160
|
+
const delta = this.deltas.get(danglingNode) ?? 0;
|
|
161
|
+
danglingSum += currentScore + delta;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (danglingSum > 0) {
|
|
165
|
+
const danglingContribution = (dampingFactor * danglingSum) / this.nodeCount;
|
|
166
|
+
for (const node of this.graph.nodes()) {
|
|
167
|
+
const nodeId = node.id;
|
|
168
|
+
const currentDelta = nextDeltas.get(nodeId) ?? 0;
|
|
169
|
+
if (personalVector) {
|
|
170
|
+
const personalContrib = danglingContribution * (personalVector.get(nodeId) ?? 0);
|
|
171
|
+
nextDeltas.set(nodeId, currentDelta + personalContrib);
|
|
172
|
+
} else {
|
|
173
|
+
nextDeltas.set(nodeId, currentDelta + danglingContribution);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Process only active nodes
|
|
179
|
+
for (const nodeId of this.activeNodes) {
|
|
180
|
+
const delta = this.deltas.get(nodeId) ?? 0;
|
|
181
|
+
|
|
182
|
+
// Skip if delta is too small
|
|
183
|
+
if (Math.abs(delta) < deltaThreshold) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Apply delta to score
|
|
188
|
+
const currentScore = this.scores.get(nodeId) ?? 0;
|
|
189
|
+
this.scores.set(nodeId, currentScore + delta);
|
|
190
|
+
|
|
191
|
+
const outWeight = this.outWeights.get(nodeId) ?? 0;
|
|
192
|
+
if (outWeight > 0) {
|
|
193
|
+
// Distribute delta to neighbors
|
|
194
|
+
for (const neighbor of Array.from(this.graph.neighbors(nodeId))) {
|
|
195
|
+
let edgeWeight = 1;
|
|
196
|
+
if (weight) {
|
|
197
|
+
const edge = this.graph.getEdge(nodeId, neighbor);
|
|
198
|
+
edgeWeight = edge?.weight ?? 1;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const contribution = dampingFactor * delta * (edgeWeight / outWeight);
|
|
202
|
+
const currentDelta = nextDeltas.get(neighbor) ?? 0;
|
|
203
|
+
nextDeltas.set(neighbor, currentDelta + contribution);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Add teleportation probability as delta
|
|
209
|
+
for (const node of this.graph.nodes()) {
|
|
210
|
+
const nodeId = node.id;
|
|
211
|
+
const currentDelta = nextDeltas.get(nodeId) ?? 0;
|
|
212
|
+
if (personalVector) {
|
|
213
|
+
nextDeltas.set(nodeId, currentDelta + (1 - dampingFactor) * (personalVector.get(nodeId) ?? 0));
|
|
214
|
+
} else {
|
|
215
|
+
nextDeltas.set(nodeId, currentDelta + randomJump);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Find active nodes for next iteration
|
|
220
|
+
const nextActive = new Set<NodeId>();
|
|
221
|
+
let maxDelta = 0;
|
|
222
|
+
|
|
223
|
+
for (const [nodeId, delta] of nextDeltas) {
|
|
224
|
+
maxDelta = Math.max(maxDelta, Math.abs(delta));
|
|
225
|
+
if (Math.abs(delta) >= deltaThreshold) {
|
|
226
|
+
nextActive.add(nodeId);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Update for next iteration
|
|
231
|
+
this.deltas = nextDeltas;
|
|
232
|
+
this.activeNodes = nextActive;
|
|
233
|
+
|
|
234
|
+
// Global convergence check
|
|
235
|
+
if (maxDelta < tolerance) {
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Normalize final scores
|
|
241
|
+
this.normalizeMap(this.scores);
|
|
242
|
+
|
|
243
|
+
return new Map(this.scores);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Update PageRank scores after graph modification.
|
|
248
|
+
* This is where delta-based approach really shines.
|
|
249
|
+
* @param modifiedNodes - Set of nodes that were modified (edges added/removed)
|
|
250
|
+
* @param options - Configuration options for PageRank computation
|
|
251
|
+
* @returns Updated PageRank scores
|
|
252
|
+
*/
|
|
253
|
+
public update(modifiedNodes: Set<NodeId>, options: DeltaPageRankOptions = {}): Map<NodeId, number> {
|
|
254
|
+
// Mark modified nodes and their neighbors as active
|
|
255
|
+
this.activeNodes.clear();
|
|
256
|
+
|
|
257
|
+
for (const nodeId of modifiedNodes) {
|
|
258
|
+
this.activeNodes.add(nodeId);
|
|
259
|
+
|
|
260
|
+
// Add incoming neighbors
|
|
261
|
+
for (const neighbor of Array.from(this.graph.inNeighbors(nodeId))) {
|
|
262
|
+
this.activeNodes.add(neighbor);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Add outgoing neighbors
|
|
266
|
+
for (const neighbor of Array.from(this.graph.neighbors(nodeId))) {
|
|
267
|
+
this.activeNodes.add(neighbor);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Recompute only for active nodes
|
|
272
|
+
return this.compute(options);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
private normalizeMap(map: Map<NodeId, number>): void {
|
|
276
|
+
let sum = 0;
|
|
277
|
+
for (const value of map.values()) {
|
|
278
|
+
sum += value;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (sum > 0) {
|
|
282
|
+
for (const [key, value] of Array.from(map)) {
|
|
283
|
+
map.set(key, value / sum);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Priority queue based implementation for even better performance
|
|
291
|
+
* Processes nodes in order of their delta magnitude
|
|
292
|
+
*/
|
|
293
|
+
export class PriorityDeltaPageRank {
|
|
294
|
+
private graph: Graph;
|
|
295
|
+
private scores: Map<NodeId, number>;
|
|
296
|
+
private priorityQueue: PriorityQueue<NodeId>;
|
|
297
|
+
private nodeDeltas: Map<NodeId, number>;
|
|
298
|
+
private outWeights: Map<NodeId, number>;
|
|
299
|
+
private danglingNodes: Set<NodeId>;
|
|
300
|
+
private nodeCount: number;
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Creates a new PriorityDeltaPageRank instance for the given graph.
|
|
304
|
+
* @param graph - The directed graph to compute PageRank on
|
|
305
|
+
*/
|
|
306
|
+
constructor(graph: Graph) {
|
|
307
|
+
if (!graph.isDirected) {
|
|
308
|
+
throw new Error("PriorityDeltaPageRank requires a directed graph");
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
this.graph = graph;
|
|
312
|
+
this.scores = new Map();
|
|
313
|
+
this.nodeDeltas = new Map();
|
|
314
|
+
this.outWeights = new Map();
|
|
315
|
+
this.danglingNodes = new Set();
|
|
316
|
+
this.nodeCount = graph.nodeCount;
|
|
317
|
+
|
|
318
|
+
// Priority queue ordered by delta magnitude (larger deltas have higher priority)
|
|
319
|
+
this.priorityQueue = new PriorityQueue<NodeId>((a, b) => b - a);
|
|
320
|
+
|
|
321
|
+
this.initialize();
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
private initialize(): void {
|
|
325
|
+
const initialValue = 1.0 / this.nodeCount;
|
|
326
|
+
|
|
327
|
+
// Initialize all nodes with initial delta
|
|
328
|
+
for (const node of this.graph.nodes()) {
|
|
329
|
+
const nodeId = node.id;
|
|
330
|
+
this.scores.set(nodeId, 0); // Start with zero scores
|
|
331
|
+
this.nodeDeltas.set(nodeId, initialValue);
|
|
332
|
+
this.priorityQueue.enqueue(nodeId, initialValue);
|
|
333
|
+
|
|
334
|
+
// Precompute out-weights
|
|
335
|
+
let totalOutWeight = 0;
|
|
336
|
+
let outDegree = 0;
|
|
337
|
+
|
|
338
|
+
for (const neighbor of Array.from(this.graph.neighbors(nodeId))) {
|
|
339
|
+
outDegree++;
|
|
340
|
+
const edge = this.graph.getEdge(nodeId, neighbor);
|
|
341
|
+
totalOutWeight += edge?.weight ?? 1;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
this.outWeights.set(nodeId, totalOutWeight);
|
|
345
|
+
|
|
346
|
+
if (outDegree === 0) {
|
|
347
|
+
this.danglingNodes.add(nodeId);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Computes PageRank scores using priority queue-based delta iteration.
|
|
354
|
+
* Processes nodes in order of their delta magnitude for optimal convergence.
|
|
355
|
+
* @param options - Configuration options for PageRank computation
|
|
356
|
+
* @returns Map of node IDs to their PageRank scores
|
|
357
|
+
*/
|
|
358
|
+
public computeWithPriority(options: DeltaPageRankOptions = {}): Map<NodeId, number> {
|
|
359
|
+
const {
|
|
360
|
+
dampingFactor = 0.85,
|
|
361
|
+
tolerance = 1e-6,
|
|
362
|
+
maxIterations = 100,
|
|
363
|
+
deltaThreshold = tolerance / 10,
|
|
364
|
+
weight,
|
|
365
|
+
} = options;
|
|
366
|
+
|
|
367
|
+
let iteration = 0;
|
|
368
|
+
let processedCount = 0;
|
|
369
|
+
|
|
370
|
+
while (!this.priorityQueue.isEmpty() && iteration < maxIterations) {
|
|
371
|
+
const nodeId = this.priorityQueue.dequeue();
|
|
372
|
+
if (nodeId === undefined) {
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const delta = this.nodeDeltas.get(nodeId) ?? 0;
|
|
377
|
+
|
|
378
|
+
// Skip if delta is too small
|
|
379
|
+
if (Math.abs(delta) < deltaThreshold) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Apply delta to node's score
|
|
384
|
+
const currentScore = this.scores.get(nodeId) ?? 0;
|
|
385
|
+
this.scores.set(nodeId, currentScore + delta);
|
|
386
|
+
this.nodeDeltas.set(nodeId, 0);
|
|
387
|
+
|
|
388
|
+
// Distribute delta to neighbors
|
|
389
|
+
const outWeight = this.outWeights.get(nodeId) ?? 0;
|
|
390
|
+
if (outWeight > 0) {
|
|
391
|
+
for (const neighbor of Array.from(this.graph.neighbors(nodeId))) {
|
|
392
|
+
let edgeWeight = 1;
|
|
393
|
+
if (weight) {
|
|
394
|
+
const edge = this.graph.getEdge(nodeId, neighbor);
|
|
395
|
+
edgeWeight = edge?.weight ?? 1;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const contribution = dampingFactor * delta * (edgeWeight / outWeight);
|
|
399
|
+
const currentNeighborDelta = this.nodeDeltas.get(neighbor) ?? 0;
|
|
400
|
+
const newDelta = currentNeighborDelta + contribution;
|
|
401
|
+
this.nodeDeltas.set(neighbor, newDelta);
|
|
402
|
+
|
|
403
|
+
// Re-enqueue neighbor with updated priority
|
|
404
|
+
if (Math.abs(newDelta) >= deltaThreshold) {
|
|
405
|
+
this.priorityQueue.enqueue(neighbor, Math.abs(newDelta));
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
processedCount++;
|
|
411
|
+
|
|
412
|
+
// Periodic convergence check
|
|
413
|
+
if (processedCount % 1000 === 0) {
|
|
414
|
+
let maxDelta = 0;
|
|
415
|
+
for (const d of this.nodeDeltas.values()) {
|
|
416
|
+
maxDelta = Math.max(maxDelta, Math.abs(d));
|
|
417
|
+
}
|
|
418
|
+
if (maxDelta < tolerance) {
|
|
419
|
+
break;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
iteration++;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Apply any remaining deltas
|
|
427
|
+
for (const [nodeId, delta] of this.nodeDeltas) {
|
|
428
|
+
if (Math.abs(delta) >= deltaThreshold) {
|
|
429
|
+
const currentScore = this.scores.get(nodeId) ?? 0;
|
|
430
|
+
this.scores.set(nodeId, currentScore + delta);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Add teleportation probability
|
|
435
|
+
const teleport = (1 - dampingFactor) / this.nodeCount;
|
|
436
|
+
for (const [nodeId, score] of this.scores) {
|
|
437
|
+
this.scores.set(nodeId, score + teleport);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Normalize final scores
|
|
441
|
+
this.normalizeMap(this.scores);
|
|
442
|
+
|
|
443
|
+
return new Map(this.scores);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
private normalizeMap(map: Map<NodeId, number>): void {
|
|
447
|
+
let sum = 0;
|
|
448
|
+
for (const value of map.values()) {
|
|
449
|
+
sum += value;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (sum > 0) {
|
|
453
|
+
for (const [key, value] of Array.from(map)) {
|
|
454
|
+
map.set(key, value / sum);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
@@ -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
|
* Eigenvector centrality implementation
|
|
@@ -19,19 +19,14 @@ export interface EigenvectorCentralityOptions extends CentralityOptions {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Calculate eigenvector centrality for all nodes in the graph
|
|
23
|
-
* Uses the power iteration method to find the dominant eigenvector
|
|
22
|
+
* Calculate eigenvector centrality for all nodes in the graph.
|
|
23
|
+
* Uses the power iteration method to find the dominant eigenvector.
|
|
24
|
+
* @param graph - The graph to compute eigenvector centrality on
|
|
25
|
+
* @param options - Configuration options for the computation
|
|
26
|
+
* @returns Object mapping node IDs to their eigenvector centrality scores
|
|
24
27
|
*/
|
|
25
|
-
export function eigenvectorCentrality(
|
|
26
|
-
|
|
27
|
-
options: EigenvectorCentralityOptions = {},
|
|
28
|
-
): CentralityResult {
|
|
29
|
-
const {
|
|
30
|
-
maxIterations = 100,
|
|
31
|
-
tolerance = 1e-6,
|
|
32
|
-
normalized = true,
|
|
33
|
-
startVector,
|
|
34
|
-
} = options;
|
|
28
|
+
export function eigenvectorCentrality(graph: Graph, options: EigenvectorCentralityOptions = {}): CentralityResult {
|
|
29
|
+
const { maxIterations = 100, tolerance = 1e-6, normalized = true, startVector } = options;
|
|
35
30
|
|
|
36
31
|
const centrality: CentralityResult = {};
|
|
37
32
|
const nodes = Array.from(graph.nodes());
|
|
@@ -146,7 +141,11 @@ export function eigenvectorCentrality(
|
|
|
146
141
|
}
|
|
147
142
|
|
|
148
143
|
/**
|
|
149
|
-
* Calculate eigenvector centrality for a specific node
|
|
144
|
+
* Calculate eigenvector centrality for a specific node.
|
|
145
|
+
* @param graph - The graph to compute eigenvector centrality on
|
|
146
|
+
* @param nodeId - The ID of the node to calculate centrality for
|
|
147
|
+
* @param options - Configuration options for the computation
|
|
148
|
+
* @returns The eigenvector centrality score for the specified node
|
|
150
149
|
*/
|
|
151
150
|
export function nodeEigenvectorCentrality(
|
|
152
151
|
graph: Graph,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {Graph} from "../../core/graph.js";
|
|
2
|
-
import type {CentralityOptions} from "../../types/index.js";
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { CentralityOptions } from "../../types/index.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* HITS (Hyperlink-Induced Topic Search) algorithm implementation
|
|
@@ -25,18 +25,14 @@ export interface HITSOptions extends CentralityOptions {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Calculate HITS hub and authority scores for all nodes in the graph
|
|
29
|
-
* Uses iterative method with normalization
|
|
28
|
+
* Calculate HITS hub and authority scores for all nodes in the graph.
|
|
29
|
+
* Uses iterative method with normalization.
|
|
30
|
+
* @param graph - The graph to compute HITS scores on
|
|
31
|
+
* @param options - Configuration options for the computation
|
|
32
|
+
* @returns Object containing hub and authority scores for all nodes
|
|
30
33
|
*/
|
|
31
|
-
export function hits(
|
|
32
|
-
|
|
33
|
-
options: HITSOptions = {},
|
|
34
|
-
): HITSResult {
|
|
35
|
-
const {
|
|
36
|
-
maxIterations = 100,
|
|
37
|
-
tolerance = 1e-6,
|
|
38
|
-
normalized = true,
|
|
39
|
-
} = options;
|
|
34
|
+
export function hits(graph: Graph, options: HITSOptions = {}): HITSResult {
|
|
35
|
+
const { maxIterations = 100, tolerance = 1e-6, normalized = true } = options;
|
|
40
36
|
|
|
41
37
|
const hubs: Record<string, number> = {};
|
|
42
38
|
const authorities: Record<string, number> = {};
|
|
@@ -45,7 +41,7 @@ export function hits(
|
|
|
45
41
|
const nodeIds = nodes.map((node) => node.id);
|
|
46
42
|
|
|
47
43
|
if (nodeIds.length === 0) {
|
|
48
|
-
return {hubs, authorities};
|
|
44
|
+
return { hubs, authorities };
|
|
49
45
|
}
|
|
50
46
|
|
|
51
47
|
// Initialize scores
|
|
@@ -185,17 +181,21 @@ export function hits(
|
|
|
185
181
|
}
|
|
186
182
|
}
|
|
187
183
|
|
|
188
|
-
return {hubs, authorities};
|
|
184
|
+
return { hubs, authorities };
|
|
189
185
|
}
|
|
190
186
|
|
|
191
187
|
/**
|
|
192
|
-
* Calculate HITS scores for a specific node
|
|
188
|
+
* Calculate HITS scores for a specific node.
|
|
189
|
+
* @param graph - The graph to compute HITS scores on
|
|
190
|
+
* @param nodeId - The ID of the node to calculate scores for
|
|
191
|
+
* @param options - Configuration options for the computation
|
|
192
|
+
* @returns Object containing hub and authority scores for the specified node
|
|
193
193
|
*/
|
|
194
194
|
export function nodeHITS(
|
|
195
195
|
graph: Graph,
|
|
196
196
|
nodeId: string | number,
|
|
197
197
|
options: HITSOptions = {},
|
|
198
|
-
): {hub: number
|
|
198
|
+
): { hub: number; authority: number } {
|
|
199
199
|
if (!graph.hasNode(nodeId)) {
|
|
200
200
|
throw new Error(`Node ${String(nodeId)} not found in graph`);
|
|
201
201
|
}
|
|
@@ -2,16 +2,23 @@
|
|
|
2
2
|
* Centrality algorithms
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export type {BetweennessCentralityOptions} from "./betweenness.js";
|
|
6
|
-
export {betweennessCentrality, edgeBetweennessCentrality, nodeBetweennessCentrality} from "./betweenness.js";
|
|
7
|
-
export type {ClosenessCentralityOptions} from "./closeness.js";
|
|
8
|
-
export {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export
|
|
15
|
-
export {
|
|
16
|
-
export
|
|
17
|
-
export {
|
|
5
|
+
export type { BetweennessCentralityOptions } from "./betweenness.js";
|
|
6
|
+
export { betweennessCentrality, edgeBetweennessCentrality, nodeBetweennessCentrality } from "./betweenness.js";
|
|
7
|
+
export type { ClosenessCentralityOptions } from "./closeness.js";
|
|
8
|
+
export {
|
|
9
|
+
closenessCentrality,
|
|
10
|
+
nodeClosenessCentrality,
|
|
11
|
+
nodeWeightedClosenessCentrality,
|
|
12
|
+
weightedClosenessCentrality,
|
|
13
|
+
} from "./closeness.js";
|
|
14
|
+
export { degreeCentrality, nodeDegreeCentrality } from "./degree.js";
|
|
15
|
+
export type { DeltaPageRankOptions } from "./delta-pagerank.js";
|
|
16
|
+
export { DeltaPageRank, PriorityDeltaPageRank } from "./delta-pagerank.js";
|
|
17
|
+
export type { EigenvectorCentralityOptions } from "./eigenvector.js";
|
|
18
|
+
export { eigenvectorCentrality, nodeEigenvectorCentrality } from "./eigenvector.js";
|
|
19
|
+
export type { HITSOptions, HITSResult } from "./hits.js";
|
|
20
|
+
export { hits, nodeHITS } from "./hits.js";
|
|
21
|
+
export type { KatzCentralityOptions } from "./katz.js";
|
|
22
|
+
export { katzCentrality, nodeKatzCentrality } from "./katz.js";
|
|
23
|
+
export type { PageRankOptions, PageRankResult } from "./pagerank.js";
|
|
24
|
+
export { pageRank, pageRankCentrality, personalizedPageRank, topPageRankNodes } from "./pagerank.js";
|
|
@@ -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
|
* Katz centrality implementation
|
|
@@ -22,20 +22,14 @@ export interface KatzCentralityOptions extends CentralityOptions {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Calculate Katz centrality for all nodes in the graph
|
|
26
|
-
* Uses iterative method to compute centrality scores
|
|
25
|
+
* Calculate Katz centrality for all nodes in the graph.
|
|
26
|
+
* Uses iterative method to compute centrality scores.
|
|
27
|
+
* @param graph - The graph to compute Katz centrality on
|
|
28
|
+
* @param options - Configuration options for the computation
|
|
29
|
+
* @returns Object mapping node IDs to their Katz centrality scores
|
|
27
30
|
*/
|
|
28
|
-
export function katzCentrality(
|
|
29
|
-
|
|
30
|
-
options: KatzCentralityOptions = {},
|
|
31
|
-
): CentralityResult {
|
|
32
|
-
const {
|
|
33
|
-
alpha = 0.1,
|
|
34
|
-
beta = 1.0,
|
|
35
|
-
maxIterations = 100,
|
|
36
|
-
tolerance = 1e-6,
|
|
37
|
-
normalized = true,
|
|
38
|
-
} = options;
|
|
31
|
+
export function katzCentrality(graph: Graph, options: KatzCentralityOptions = {}): CentralityResult {
|
|
32
|
+
const { alpha = 0.1, beta = 1.0, maxIterations = 100, tolerance = 1e-6, normalized = true } = options;
|
|
39
33
|
|
|
40
34
|
const centrality: CentralityResult = {};
|
|
41
35
|
const nodes = Array.from(graph.nodes());
|
|
@@ -68,16 +62,14 @@ export function katzCentrality(
|
|
|
68
62
|
|
|
69
63
|
// For directed graphs, use in-neighbors
|
|
70
64
|
// For undirected graphs, use all neighbors
|
|
71
|
-
const neighbors = graph.isDirected ?
|
|
72
|
-
Array.from(graph.inNeighbors(nodeId)) :
|
|
73
|
-
graph.neighbors(nodeId);
|
|
65
|
+
const neighbors = graph.isDirected ? Array.from(graph.inNeighbors(nodeId)) : graph.neighbors(nodeId);
|
|
74
66
|
|
|
75
67
|
for (const neighbor of neighbors) {
|
|
76
68
|
const neighborKey = neighbor.toString();
|
|
77
69
|
sum += previousScores.get(neighborKey) ?? 0;
|
|
78
70
|
}
|
|
79
71
|
|
|
80
|
-
currentScores.set(nodeId.toString(),
|
|
72
|
+
currentScores.set(nodeId.toString(), alpha * sum + beta);
|
|
81
73
|
}
|
|
82
74
|
|
|
83
75
|
// Check for convergence
|
|
@@ -123,13 +115,13 @@ export function katzCentrality(
|
|
|
123
115
|
}
|
|
124
116
|
|
|
125
117
|
/**
|
|
126
|
-
* Calculate Katz centrality for a specific node
|
|
118
|
+
* Calculate Katz centrality for a specific node.
|
|
119
|
+
* @param graph - The graph to compute Katz centrality on
|
|
120
|
+
* @param nodeId - The ID of the node to calculate centrality for
|
|
121
|
+
* @param options - Configuration options for the computation
|
|
122
|
+
* @returns The Katz centrality score for the specified node
|
|
127
123
|
*/
|
|
128
|
-
export function nodeKatzCentrality(
|
|
129
|
-
graph: Graph,
|
|
130
|
-
nodeId: string | number,
|
|
131
|
-
options: KatzCentralityOptions = {},
|
|
132
|
-
): number {
|
|
124
|
+
export function nodeKatzCentrality(graph: Graph, nodeId: string | number, options: KatzCentralityOptions = {}): number {
|
|
133
125
|
if (!graph.hasNode(nodeId)) {
|
|
134
126
|
throw new Error(`Node ${String(nodeId)} not found in graph`);
|
|
135
127
|
}
|