@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,310 @@
|
|
|
1
|
+
import type { NodeId } from "../types/index.js";
|
|
2
|
+
import { CompactDistanceArray, GraphBitSet } from "./bit-packed.js";
|
|
3
|
+
import { CSRGraph } from "./csr-graph.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Options for Direction-Optimized BFS
|
|
7
|
+
*/
|
|
8
|
+
export interface DirectionOptimizedBFSOptions {
|
|
9
|
+
alpha?: number; // Default: 15 - Controls top-down to bottom-up switch
|
|
10
|
+
beta?: number; // Default: 18 - Controls bottom-up to top-down switch
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Result of BFS traversal
|
|
15
|
+
*/
|
|
16
|
+
export interface BFSResult<TNodeId> {
|
|
17
|
+
distances: Map<TNodeId, number>;
|
|
18
|
+
parents: Map<TNodeId, TNodeId | null>;
|
|
19
|
+
visitedCount: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Direction-Optimized Breadth-First Search
|
|
24
|
+
*
|
|
25
|
+
* Dynamically switches between top-down and bottom-up search strategies
|
|
26
|
+
* based on the size of the frontier. Particularly effective for low-diameter
|
|
27
|
+
* graphs like social networks.
|
|
28
|
+
*
|
|
29
|
+
* Based on: Beamer, S., Asanović, K., & Patterson, D. (2012).
|
|
30
|
+
* "Direction-optimizing breadth-first search." SC'12.
|
|
31
|
+
*/
|
|
32
|
+
export class DirectionOptimizedBFS<TNodeId = NodeId> {
|
|
33
|
+
private graph: CSRGraph<TNodeId>;
|
|
34
|
+
private alpha: number;
|
|
35
|
+
private beta: number;
|
|
36
|
+
|
|
37
|
+
// Data structures
|
|
38
|
+
private parent: Int32Array; // -1 = unvisited, -2 = source, else parent ID
|
|
39
|
+
private frontier: GraphBitSet; // Current frontier bitmap
|
|
40
|
+
private nextFrontier: GraphBitSet; // Next level frontier
|
|
41
|
+
private distances: CompactDistanceArray;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Creates a new DirectionOptimizedBFS instance.
|
|
45
|
+
* @param graph - The CSR graph to perform BFS on
|
|
46
|
+
* @param options - Optional configuration for switching thresholds
|
|
47
|
+
*/
|
|
48
|
+
constructor(graph: CSRGraph<TNodeId>, options?: DirectionOptimizedBFSOptions) {
|
|
49
|
+
this.graph = graph;
|
|
50
|
+
this.alpha = options?.alpha ?? 15;
|
|
51
|
+
this.beta = options?.beta ?? 18;
|
|
52
|
+
|
|
53
|
+
const nodeCount = graph.nodeCount();
|
|
54
|
+
this.parent = new Int32Array(nodeCount).fill(-1);
|
|
55
|
+
this.frontier = new GraphBitSet(nodeCount);
|
|
56
|
+
this.nextFrontier = new GraphBitSet(nodeCount);
|
|
57
|
+
this.distances = new CompactDistanceArray(nodeCount);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Perform BFS from a single source node.
|
|
62
|
+
* @param source - The source node ID to start the BFS from
|
|
63
|
+
* @returns The BFS result containing distances and parent pointers
|
|
64
|
+
*/
|
|
65
|
+
search(source: TNodeId): BFSResult<TNodeId> {
|
|
66
|
+
const sourceIndex = this.graph.nodeToIndex(source);
|
|
67
|
+
this.parent[sourceIndex] = -2; // Mark as source
|
|
68
|
+
this.frontier.add(sourceIndex);
|
|
69
|
+
this.distances.set(sourceIndex, 0);
|
|
70
|
+
|
|
71
|
+
// let currentDistance = 0; // Variable not used
|
|
72
|
+
// Initialize edgesToCheck to total edges to prevent immediate switch to bottom-up
|
|
73
|
+
let edgesToCheck = this.graph.edgeCount();
|
|
74
|
+
let scoutCount = 0; // Will be set after first top-down step
|
|
75
|
+
let awakeCount = 1; // Number of nodes in current frontier
|
|
76
|
+
let oldAwakeCount = 0;
|
|
77
|
+
|
|
78
|
+
// Direction tracking
|
|
79
|
+
let useBottomUp = false;
|
|
80
|
+
|
|
81
|
+
while (!this.frontier.isEmpty()) {
|
|
82
|
+
oldAwakeCount = awakeCount;
|
|
83
|
+
|
|
84
|
+
if (useBottomUp) {
|
|
85
|
+
// Check if we should switch back to top-down
|
|
86
|
+
if (awakeCount >= oldAwakeCount || awakeCount > this.graph.nodeCount() / this.beta) {
|
|
87
|
+
useBottomUp = false;
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
// Check if we should switch to bottom-up
|
|
91
|
+
if (scoutCount > edgesToCheck / this.alpha) {
|
|
92
|
+
useBottomUp = true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (useBottomUp) {
|
|
97
|
+
awakeCount = this.bottomUpStep();
|
|
98
|
+
} else {
|
|
99
|
+
scoutCount = this.topDownStep();
|
|
100
|
+
awakeCount = this.nextFrontier.size();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Swap frontiers
|
|
104
|
+
this.frontier.swap(this.nextFrontier);
|
|
105
|
+
this.nextFrontier.clear();
|
|
106
|
+
|
|
107
|
+
// currentDistance++; // Variable not used
|
|
108
|
+
edgesToCheck = this.calculateEdgesToCheck();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return this.buildResult();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Top-down BFS step - explore from frontier.
|
|
116
|
+
* @returns The scout count (total degree of newly discovered nodes)
|
|
117
|
+
*/
|
|
118
|
+
private topDownStep(): number {
|
|
119
|
+
let scoutCount = 0;
|
|
120
|
+
|
|
121
|
+
// Iterate through frontier nodes
|
|
122
|
+
for (const node of this.frontier) {
|
|
123
|
+
const currentDistance = this.distances.get(node);
|
|
124
|
+
|
|
125
|
+
for (const neighbor of this.graph.iterateNeighborIndices(node)) {
|
|
126
|
+
if (this.parent[neighbor] === -1) {
|
|
127
|
+
this.parent[neighbor] = node;
|
|
128
|
+
this.distances.set(neighbor, currentDistance + 1);
|
|
129
|
+
this.nextFrontier.add(neighbor);
|
|
130
|
+
scoutCount += this.graph.outDegreeByIndex(neighbor);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return scoutCount;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Bottom-up BFS step - check unvisited nodes for frontier neighbors.
|
|
140
|
+
* @returns The number of newly discovered nodes
|
|
141
|
+
*/
|
|
142
|
+
private bottomUpStep(): number {
|
|
143
|
+
const nodeCount = this.graph.nodeCount();
|
|
144
|
+
let awakeCount = 0;
|
|
145
|
+
|
|
146
|
+
// Check all unvisited nodes
|
|
147
|
+
for (let node = 0; node < nodeCount; node++) {
|
|
148
|
+
if (this.parent[node] === -1) {
|
|
149
|
+
// Use incoming edges for bottom-up traversal
|
|
150
|
+
for (const neighbor of this.graph.iterateIncomingNeighborIndices(node)) {
|
|
151
|
+
if (this.frontier.has(neighbor)) {
|
|
152
|
+
this.parent[node] = neighbor;
|
|
153
|
+
const neighborDist = this.distances.get(neighbor);
|
|
154
|
+
this.distances.set(node, neighborDist + 1);
|
|
155
|
+
this.nextFrontier.add(node);
|
|
156
|
+
awakeCount++;
|
|
157
|
+
break; // Found a parent, no need to check more
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return awakeCount;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Calculate edges to check for switching heuristic.
|
|
168
|
+
* @returns The total number of outgoing edges from frontier nodes
|
|
169
|
+
*/
|
|
170
|
+
private calculateEdgesToCheck(): number {
|
|
171
|
+
let count = 0;
|
|
172
|
+
for (const node of this.frontier) {
|
|
173
|
+
count += this.graph.outDegreeByIndex(node);
|
|
174
|
+
}
|
|
175
|
+
return count;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Build result map from internal data structures.
|
|
180
|
+
* @returns The BFS result containing distances and parent pointers
|
|
181
|
+
*/
|
|
182
|
+
private buildResult(): BFSResult<TNodeId> {
|
|
183
|
+
const distances = new Map<TNodeId, number>();
|
|
184
|
+
const parents = new Map<TNodeId, TNodeId | null>();
|
|
185
|
+
let visitedCount = 0;
|
|
186
|
+
|
|
187
|
+
for (let i = 0; i < this.graph.nodeCount(); i++) {
|
|
188
|
+
if (this.parent[i] !== -1) {
|
|
189
|
+
const nodeId = this.graph.indexToNodeId(i);
|
|
190
|
+
distances.set(nodeId, this.distances.get(i));
|
|
191
|
+
|
|
192
|
+
if (this.parent[i] === -2) {
|
|
193
|
+
// Source node
|
|
194
|
+
parents.set(nodeId, null);
|
|
195
|
+
} else {
|
|
196
|
+
// Regular node with parent
|
|
197
|
+
const parentIndex = this.parent[i];
|
|
198
|
+
if (parentIndex !== undefined && parentIndex >= 0) {
|
|
199
|
+
parents.set(nodeId, this.graph.indexToNodeId(parentIndex));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
visitedCount++;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return { distances, parents, visitedCount };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Perform multi-source BFS from multiple source nodes.
|
|
212
|
+
* @param sources - Array of source node IDs to start the BFS from
|
|
213
|
+
* @returns The BFS result containing distances and parent pointers
|
|
214
|
+
*/
|
|
215
|
+
searchMultiple(sources: TNodeId[]): BFSResult<TNodeId> {
|
|
216
|
+
// Initialize multiple sources
|
|
217
|
+
for (const source of sources) {
|
|
218
|
+
const sourceIndex = this.graph.nodeToIndex(source);
|
|
219
|
+
this.parent[sourceIndex] = -2; // Mark as source
|
|
220
|
+
this.frontier.add(sourceIndex);
|
|
221
|
+
this.distances.set(sourceIndex, 0);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// let currentDistance = 0; // Variable not used
|
|
225
|
+
let edgesToCheck = 0;
|
|
226
|
+
let scoutCount = 0;
|
|
227
|
+
|
|
228
|
+
// Calculate initial edges to check
|
|
229
|
+
for (const node of this.frontier) {
|
|
230
|
+
const degree = this.graph.outDegreeByIndex(node);
|
|
231
|
+
edgesToCheck += degree;
|
|
232
|
+
scoutCount += degree;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
let awakeCount = sources.length;
|
|
236
|
+
let oldAwakeCount = 0;
|
|
237
|
+
let useBottomUp = false;
|
|
238
|
+
|
|
239
|
+
while (!this.frontier.isEmpty()) {
|
|
240
|
+
oldAwakeCount = awakeCount;
|
|
241
|
+
|
|
242
|
+
if (useBottomUp) {
|
|
243
|
+
if (awakeCount >= oldAwakeCount || awakeCount > this.graph.nodeCount() / this.beta) {
|
|
244
|
+
useBottomUp = false;
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
if (scoutCount > edgesToCheck / this.alpha) {
|
|
248
|
+
useBottomUp = true;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (useBottomUp) {
|
|
253
|
+
awakeCount = this.bottomUpStep();
|
|
254
|
+
} else {
|
|
255
|
+
scoutCount = this.topDownStep();
|
|
256
|
+
awakeCount = this.nextFrontier.size();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
this.frontier.swap(this.nextFrontier);
|
|
260
|
+
this.nextFrontier.clear();
|
|
261
|
+
|
|
262
|
+
// currentDistance++; // Variable not used
|
|
263
|
+
edgesToCheck = this.calculateEdgesToCheck();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return this.buildResult();
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Reset internal state for reuse
|
|
271
|
+
*/
|
|
272
|
+
reset(): void {
|
|
273
|
+
this.parent.fill(-1);
|
|
274
|
+
this.frontier.clear();
|
|
275
|
+
this.nextFrontier.clear();
|
|
276
|
+
this.distances.clear();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Convenience function for single-source BFS.
|
|
282
|
+
* @param graph - The CSR graph to perform BFS on
|
|
283
|
+
* @param source - The source node ID to start the BFS from
|
|
284
|
+
* @param options - Optional configuration for switching thresholds
|
|
285
|
+
* @returns The BFS result containing distances and parent pointers
|
|
286
|
+
*/
|
|
287
|
+
export function directionOptimizedBFS<TNodeId = NodeId>(
|
|
288
|
+
graph: CSRGraph<TNodeId>,
|
|
289
|
+
source: TNodeId,
|
|
290
|
+
options?: DirectionOptimizedBFSOptions,
|
|
291
|
+
): BFSResult<TNodeId> {
|
|
292
|
+
const bfs = new DirectionOptimizedBFS(graph, options);
|
|
293
|
+
return bfs.search(source);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Convenience function for multi-source BFS.
|
|
298
|
+
* @param graph - The CSR graph to perform BFS on
|
|
299
|
+
* @param sources - Array of source node IDs to start the BFS from
|
|
300
|
+
* @param options - Optional configuration for switching thresholds
|
|
301
|
+
* @returns The BFS result containing distances and parent pointers
|
|
302
|
+
*/
|
|
303
|
+
export function directionOptimizedBFSMultiple<TNodeId = NodeId>(
|
|
304
|
+
graph: CSRGraph<TNodeId>,
|
|
305
|
+
sources: TNodeId[],
|
|
306
|
+
options?: DirectionOptimizedBFSOptions,
|
|
307
|
+
): BFSResult<TNodeId> {
|
|
308
|
+
const bfs = new DirectionOptimizedBFS(graph, options);
|
|
309
|
+
return bfs.searchMultiple(sources);
|
|
310
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import type { Graph } from "../core/graph.js";
|
|
2
|
+
import type { NodeId } from "../types/index.js";
|
|
3
|
+
import { CSRGraph, type ReadonlyGraph } from "./csr-graph.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Adapter to convert standard Graph to CSR format
|
|
7
|
+
*
|
|
8
|
+
* Provides transparent conversion while maintaining API compatibility
|
|
9
|
+
*/
|
|
10
|
+
export class GraphAdapter<TNodeId = NodeId> implements ReadonlyGraph<TNodeId> {
|
|
11
|
+
private csrGraph: CSRGraph<TNodeId>;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new GraphAdapter that wraps or converts a graph to CSR format.
|
|
15
|
+
* @param graph - The graph to adapt (either standard Graph or ReadonlyGraph)
|
|
16
|
+
*/
|
|
17
|
+
constructor(graph: Graph | ReadonlyGraph<TNodeId>) {
|
|
18
|
+
// Check if already a CSRGraph
|
|
19
|
+
if (graph instanceof CSRGraph) {
|
|
20
|
+
this.csrGraph = graph as CSRGraph<TNodeId>;
|
|
21
|
+
} else {
|
|
22
|
+
// Convert to CSR format
|
|
23
|
+
this.csrGraph = this.convertToCSR(graph);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Convert standard graph to CSR format.
|
|
29
|
+
* @param graph - The graph to convert
|
|
30
|
+
* @returns A new CSRGraph instance
|
|
31
|
+
*/
|
|
32
|
+
private convertToCSR(graph: Graph | ReadonlyGraph<TNodeId>): CSRGraph<TNodeId> {
|
|
33
|
+
const adjacencyList = new Map<TNodeId, TNodeId[]>();
|
|
34
|
+
const weights = new Map<string, number>();
|
|
35
|
+
|
|
36
|
+
// Handle both Graph and ReadonlyGraph interfaces
|
|
37
|
+
if ("nodes" in graph && typeof graph.nodes === "function") {
|
|
38
|
+
// Build adjacency list from Graph
|
|
39
|
+
for (const node of graph.nodes()) {
|
|
40
|
+
const nodeId = (node as { id: TNodeId }).id;
|
|
41
|
+
const neighbors: TNodeId[] = [];
|
|
42
|
+
|
|
43
|
+
const graphTyped = graph as Graph;
|
|
44
|
+
for (const neighborId of graphTyped.neighbors(nodeId as NodeId)) {
|
|
45
|
+
neighbors.push(neighborId as TNodeId);
|
|
46
|
+
|
|
47
|
+
// Get edge weight if available
|
|
48
|
+
if ("getEdge" in graph && typeof graph.getEdge === "function") {
|
|
49
|
+
const edge = graphTyped.getEdge(nodeId as NodeId, neighborId);
|
|
50
|
+
if (edge?.weight !== undefined) {
|
|
51
|
+
weights.set(`${String(nodeId)}-${String(neighborId)}`, edge.weight);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
adjacencyList.set(nodeId, neighbors);
|
|
57
|
+
}
|
|
58
|
+
} else if ("nodeIds" in graph && typeof graph.nodeIds === "function") {
|
|
59
|
+
// Handle ReadonlyGraph with nodeIds method
|
|
60
|
+
interface ReadonlyGraphWithNodeIds {
|
|
61
|
+
nodeIds(): Iterable<TNodeId>;
|
|
62
|
+
edges?(): Iterable<{ source: TNodeId; target: TNodeId; weight?: number }>;
|
|
63
|
+
}
|
|
64
|
+
const readonlyGraph = graph as ReadonlyGraphWithNodeIds;
|
|
65
|
+
for (const nodeId of readonlyGraph.nodeIds()) {
|
|
66
|
+
adjacencyList.set(nodeId, []);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Build adjacency from edges
|
|
70
|
+
if ("edges" in readonlyGraph && typeof readonlyGraph.edges === "function") {
|
|
71
|
+
for (const edge of readonlyGraph.edges()) {
|
|
72
|
+
const neighbors = adjacencyList.get(edge.source);
|
|
73
|
+
if (neighbors) {
|
|
74
|
+
neighbors.push(edge.target);
|
|
75
|
+
if (edge.weight !== undefined) {
|
|
76
|
+
weights.set(`${String(edge.source)}-${String(edge.target)}`, edge.weight);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return new CSRGraph(adjacencyList, weights.size > 0 ? weights : undefined);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Delegate all methods to CSR implementation
|
|
87
|
+
/**
|
|
88
|
+
* Get the total number of nodes in the graph.
|
|
89
|
+
* @returns The number of nodes
|
|
90
|
+
*/
|
|
91
|
+
nodeCount(): number {
|
|
92
|
+
return this.csrGraph.nodeCount();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get the total number of edges in the graph.
|
|
97
|
+
* @returns The number of edges
|
|
98
|
+
*/
|
|
99
|
+
edgeCount(): number {
|
|
100
|
+
return this.csrGraph.edgeCount();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if a node exists in the graph.
|
|
105
|
+
* @param nodeId - The node ID to check
|
|
106
|
+
* @returns True if the node exists, false otherwise
|
|
107
|
+
*/
|
|
108
|
+
hasNode(nodeId: TNodeId): boolean {
|
|
109
|
+
return this.csrGraph.hasNode(nodeId);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Check if an edge exists between two nodes.
|
|
114
|
+
* @param source - The source node ID
|
|
115
|
+
* @param target - The target node ID
|
|
116
|
+
* @returns True if the edge exists, false otherwise
|
|
117
|
+
*/
|
|
118
|
+
hasEdge(source: TNodeId, target: TNodeId): boolean {
|
|
119
|
+
return this.csrGraph.hasEdge(source, target);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get neighbors of a node as node IDs.
|
|
124
|
+
* @param nodeId - The node ID to get neighbors for
|
|
125
|
+
* @returns An iterator over neighbor node IDs
|
|
126
|
+
*/
|
|
127
|
+
neighbors(nodeId: TNodeId): IterableIterator<TNodeId> {
|
|
128
|
+
return this.csrGraph.neighbors(nodeId);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get the out-degree (number of outgoing edges) of a node.
|
|
133
|
+
* @param nodeId - The node ID to get the out-degree for
|
|
134
|
+
* @returns The number of outgoing edges from the node
|
|
135
|
+
*/
|
|
136
|
+
outDegree(nodeId: TNodeId): number {
|
|
137
|
+
return this.csrGraph.outDegree(nodeId);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Get all nodes in the graph.
|
|
142
|
+
* @returns An iterator over all node IDs
|
|
143
|
+
*/
|
|
144
|
+
nodes(): IterableIterator<TNodeId> {
|
|
145
|
+
return this.csrGraph.nodes();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Get the underlying CSR graph.
|
|
150
|
+
* @returns The CSRGraph instance used internally
|
|
151
|
+
*/
|
|
152
|
+
getCSRGraph(): CSRGraph<TNodeId> {
|
|
153
|
+
return this.csrGraph;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Configuration for graph algorithm optimizations
|
|
159
|
+
*/
|
|
160
|
+
export interface GraphAlgorithmConfig {
|
|
161
|
+
// Enable optimizations
|
|
162
|
+
useDirectionOptimizedBFS?: boolean;
|
|
163
|
+
useCSRFormat?: boolean;
|
|
164
|
+
useBitPackedStructures?: boolean;
|
|
165
|
+
|
|
166
|
+
// Algorithm-specific parameters
|
|
167
|
+
bfsAlpha?: number;
|
|
168
|
+
bfsBeta?: number;
|
|
169
|
+
|
|
170
|
+
// Memory vs speed tradeoffs
|
|
171
|
+
preallocateSize?: number;
|
|
172
|
+
enableCaching?: boolean;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Configure optimizations globally.
|
|
177
|
+
* @deprecated This function is a no-op and will be removed in a future version
|
|
178
|
+
* @param _config - The configuration object (ignored)
|
|
179
|
+
*/
|
|
180
|
+
export function configureOptimizations(_config: GraphAlgorithmConfig): void {
|
|
181
|
+
// No-op for backward compatibility
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Get current configuration.
|
|
186
|
+
* @deprecated This function returns empty config and will be removed in a future version
|
|
187
|
+
* @returns An empty configuration object
|
|
188
|
+
*/
|
|
189
|
+
export function getOptimizationConfig(): GraphAlgorithmConfig {
|
|
190
|
+
return {};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Check if a graph is already in CSR format.
|
|
195
|
+
* @param graph - The graph to check
|
|
196
|
+
* @returns True if the graph is a CSRGraph instance
|
|
197
|
+
*/
|
|
198
|
+
export function isCSRGraph<TNodeId = NodeId>(graph: unknown): graph is CSRGraph<TNodeId> {
|
|
199
|
+
return graph instanceof CSRGraph;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Convert any graph to CSR format.
|
|
204
|
+
* @param graph - The graph to convert
|
|
205
|
+
* @returns A CSRGraph instance (either the original if already CSR, or a new converted one)
|
|
206
|
+
*/
|
|
207
|
+
export function toCSRGraph<TNodeId = NodeId>(
|
|
208
|
+
graph: Graph | ReadonlyGraph<TNodeId> | CSRGraph<TNodeId>,
|
|
209
|
+
): CSRGraph<TNodeId> {
|
|
210
|
+
if (isCSRGraph<TNodeId>(graph)) {
|
|
211
|
+
return graph;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const adapter = new GraphAdapter<TNodeId>(graph);
|
|
215
|
+
return adapter.getCSRGraph();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Create an optimized graph from nodes and edges.
|
|
220
|
+
* @param nodes - Array of node IDs
|
|
221
|
+
* @param edges - Array of edge tuples [source, target, weight?]
|
|
222
|
+
* @returns A new CSRGraph instance
|
|
223
|
+
*/
|
|
224
|
+
export function createOptimizedGraph<TNodeId = NodeId>(
|
|
225
|
+
nodes: TNodeId[],
|
|
226
|
+
edges: [TNodeId, TNodeId, number?][],
|
|
227
|
+
): CSRGraph<TNodeId> {
|
|
228
|
+
const adjacencyList = new Map<TNodeId, TNodeId[]>();
|
|
229
|
+
const weights = new Map<string, number>();
|
|
230
|
+
|
|
231
|
+
// Initialize nodes
|
|
232
|
+
for (const node of nodes) {
|
|
233
|
+
adjacencyList.set(node, []);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Add edges
|
|
237
|
+
for (const [source, target, weight] of edges) {
|
|
238
|
+
const neighbors = adjacencyList.get(source);
|
|
239
|
+
if (neighbors) {
|
|
240
|
+
neighbors.push(target);
|
|
241
|
+
if (weight !== undefined) {
|
|
242
|
+
weights.set(`${String(source)}-${String(target)}`, weight);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return new CSRGraph(adjacencyList, weights.size > 0 ? weights : undefined);
|
|
248
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optimized graph algorithm implementations
|
|
3
|
+
*
|
|
4
|
+
* High-performance implementations using:
|
|
5
|
+
* - Direction-Optimized BFS
|
|
6
|
+
* - Compressed Sparse Row (CSR) format
|
|
7
|
+
* - Bit-packed data structures
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Configuration and optimization control
|
|
11
|
+
// These deprecated functions are intentionally re-exported for backward compatibility
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
13
|
+
export { configureOptimizations, getOptimizationConfig, type GraphAlgorithmConfig } from "./graph-adapter.js";
|
|
14
|
+
|
|
15
|
+
// Note: The main BFS functions in algorithms/traversal/bfs.ts automatically
|
|
16
|
+
// use these optimizations for large graphs (>10k nodes) when optimizations are enabled.
|
|
17
|
+
// No manual configuration needed - just use breadthFirstSearch, shortestPathBFS, etc.
|
|
18
|
+
//
|
|
19
|
+
// The previously exported bfsOptimized, shortestPathBFSOptimized, and
|
|
20
|
+
// singleSourceShortestPathBFSOptimized functions have been removed since they
|
|
21
|
+
// are no longer needed. All optimization happens automatically.
|
|
22
|
+
|
|
23
|
+
// BFS optimization functions have been removed. The main BFS functions
|
|
24
|
+
// (breadthFirstSearch, shortestPathBFS, singleSourceShortestPathBFS)
|
|
25
|
+
// in algorithms/traversal/bfs.ts now automatically use optimizations
|
|
26
|
+
// for large graphs without requiring manual configuration.
|
|
27
|
+
|
|
28
|
+
// Export data structures for advanced users
|
|
29
|
+
export { CompactDistanceArray, GraphBitSet, VisitedBitArray } from "./bit-packed.js";
|
|
30
|
+
export { CSRGraph } from "./csr-graph.js";
|
|
31
|
+
export { DirectionOptimizedBFS } from "./direction-optimized-bfs.js";
|
|
32
|
+
|
|
33
|
+
// Export utilities
|
|
34
|
+
export { createOptimizedGraph, isCSRGraph, toCSRGraph } from "./graph-adapter.js";
|