@graphty/algorithms 1.3.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +368 -422
- package/dist/algorithms.js +567 -264
- package/dist/algorithms.js.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.d.ts +10 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +27 -6
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/centrality/closeness.d.ts +11 -2
- package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/closeness.js +17 -3
- 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 +9 -6
- package/dist/src/algorithms/centrality/degree.js.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +21 -3
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js +25 -7
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts +28 -2
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank.js +30 -4
- package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -1
- 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 +1 -1
- package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/index.js +1 -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 +14 -0
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.js +16 -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 +21 -4
- package/dist/src/algorithms/community/girvan-newman.js.map +1 -1
- 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 +0 -3
- package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
- package/dist/src/algorithms/community/label-propagation.js +13 -6
- package/dist/src/algorithms/community/label-propagation.js.map +1 -1
- package/dist/src/algorithms/community/leiden.d.ts +0 -1
- package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
- package/dist/src/algorithms/community/leiden.js +37 -6
- package/dist/src/algorithms/community/leiden.js.map +1 -1
- package/dist/src/algorithms/community/louvain-optimized.d.ts +37 -0
- package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -1
- package/dist/src/algorithms/community/louvain-optimized.js +42 -7
- package/dist/src/algorithms/community/louvain-optimized.js.map +1 -1
- 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 +19 -6
- package/dist/src/algorithms/community/louvain.js.map +1 -1
- package/dist/src/algorithms/community/modularity-utils.d.ts +0 -4
- package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -1
- package/dist/src/algorithms/community/modularity-utils.js +1 -5
- package/dist/src/algorithms/community/modularity-utils.js.map +1 -1
- 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 +10 -0
- 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 +10 -0
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +12 -5
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +19 -17
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts +15 -0
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +15 -0
- 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 +13 -0
- package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.js +37 -0
- package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-variants.d.ts +23 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs-variants.js +34 -0
- package/dist/src/algorithms/traversal/bfs-variants.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs.d.ts +1 -1
- package/dist/src/algorithms/traversal/bfs.d.ts.map +1 -1
- package/dist/src/algorithms/traversal/bfs.js +1 -1
- 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 +2 -0
- package/dist/src/benchmark-all-algorithms.d.ts.map +1 -1
- package/dist/src/benchmark-all-algorithms.js +32 -3
- package/dist/src/benchmark-all-algorithms.js.map +1 -1
- package/dist/src/clustering/hierarchical.d.ts +8 -1
- package/dist/src/clustering/hierarchical.d.ts.map +1 -1
- package/dist/src/clustering/hierarchical.js +22 -6
- package/dist/src/clustering/hierarchical.js.map +1 -1
- package/dist/src/clustering/index.d.ts.map +1 -1
- package/dist/src/clustering/index.js.map +1 -1
- package/dist/src/clustering/k-core.d.ts +2 -5
- package/dist/src/clustering/k-core.d.ts.map +1 -1
- package/dist/src/clustering/k-core.js +14 -12
- 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 +4 -1
- package/dist/src/clustering/spectral.d.ts.map +1 -1
- package/dist/src/clustering/spectral.js +61 -28
- 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 +45 -1
- 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 +4 -2
- package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
- package/dist/src/flow/ford-fulkerson.js +31 -2
- package/dist/src/flow/ford-fulkerson.js.map +1 -1
- package/dist/src/flow/min-cut.d.ts +0 -3
- package/dist/src/flow/min-cut.d.ts.map +1 -1
- package/dist/src/flow/min-cut.js +17 -4
- package/dist/src/flow/min-cut.js.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/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 +36 -10
- 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 +27 -6
- 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 +103 -53
- package/dist/src/optimized/bit-packed.d.ts.map +1 -1
- package/dist/src/optimized/bit-packed.js +104 -54
- package/dist/src/optimized/bit-packed.js.map +1 -1
- package/dist/src/optimized/csr-graph.d.ts +87 -24
- package/dist/src/optimized/csr-graph.d.ts.map +1 -1
- package/dist/src/optimized/csr-graph.js +87 -24
- package/dist/src/optimized/csr-graph.js.map +1 -1
- package/dist/src/optimized/direction-optimized-bfs.d.ts +37 -16
- package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -1
- package/dist/src/optimized/direction-optimized-bfs.js +39 -20
- package/dist/src/optimized/direction-optimized-bfs.js.map +1 -1
- package/dist/src/optimized/graph-adapter.d.ts +58 -9
- package/dist/src/optimized/graph-adapter.d.ts.map +1 -1
- package/dist/src/optimized/graph-adapter.js +58 -10
- package/dist/src/optimized/graph-adapter.js.map +1 -1
- package/dist/src/optimized/index.d.ts +1 -1
- package/dist/src/optimized/index.d.ts.map +1 -1
- package/dist/src/optimized/index.js +3 -1
- package/dist/src/optimized/index.js.map +1 -1
- 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 +23 -10
- 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 +29 -8
- package/dist/src/research/sync.js.map +1 -1
- package/dist/src/research/terahac.d.ts +0 -1
- package/dist/src/research/terahac.d.ts.map +1 -1
- package/dist/src/research/terahac.js +32 -4
- package/dist/src/research/terahac.js.map +1 -1
- package/dist/src/utils/graph-converters.d.ts +31 -0
- package/dist/src/utils/graph-converters.d.ts.map +1 -1
- package/dist/src/utils/graph-converters.js +31 -0
- package/dist/src/utils/graph-converters.js.map +1 -1
- package/dist/src/utils/graph-utilities.d.ts.map +1 -1
- package/dist/src/utils/graph-utilities.js.map +1 -1
- package/dist/src/utils/math-utilities.d.ts +11 -0
- package/dist/src/utils/math-utilities.d.ts.map +1 -1
- package/dist/src/utils/math-utilities.js +14 -5
- package/dist/src/utils/math-utilities.js.map +1 -1
- package/dist/src/utils/optimization-helpers.d.ts +9 -0
- package/dist/src/utils/optimization-helpers.d.ts.map +1 -1
- package/dist/src/utils/optimization-helpers.js +12 -0
- package/dist/src/utils/optimization-helpers.js.map +1 -1
- 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/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +56 -65
- package/src/algorithms/centrality/betweenness.ts +34 -17
- package/src/algorithms/centrality/closeness.ts +34 -17
- package/src/algorithms/centrality/degree.ts +15 -19
- package/src/algorithms/centrality/delta-pagerank-simple.ts +36 -28
- package/src/algorithms/centrality/delta-pagerank.ts +34 -11
- package/src/algorithms/centrality/eigenvector.ts +14 -15
- package/src/algorithms/centrality/hits.ts +17 -17
- package/src/algorithms/centrality/index.ts +20 -15
- package/src/algorithms/centrality/katz.ts +17 -25
- package/src/algorithms/centrality/pagerank.ts +26 -17
- package/src/algorithms/community/girvan-newman.ts +39 -28
- package/src/algorithms/community/index.ts +6 -7
- package/src/algorithms/community/label-propagation.ts +20 -28
- package/src/algorithms/community/leiden.ts +61 -37
- package/src/algorithms/community/louvain-optimized.ts +49 -20
- package/src/algorithms/community/louvain.ts +35 -25
- package/src/algorithms/community/modularity-utils.ts +5 -17
- package/src/algorithms/components/connected.ts +40 -17
- package/src/algorithms/matching/bipartite.ts +17 -10
- 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 -15
- package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +29 -29
- package/src/algorithms/shortest-path/dijkstra.ts +23 -17
- 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 +64 -60
- package/src/algorithms/traversal/bfs-variants.ts +61 -37
- package/src/algorithms/traversal/bfs.ts +1 -7
- package/src/algorithms/traversal/dfs.ts +61 -42
- package/src/algorithms/traversal/index.ts +3 -3
- package/src/benchmark-all-algorithms.ts +57 -25
- package/src/clustering/hierarchical.ts +40 -34
- package/src/clustering/index.ts +8 -8
- package/src/clustering/k-core.ts +26 -42
- package/src/clustering/mcl.ts +53 -23
- package/src/clustering/spectral.ts +91 -57
- package/src/core/graph.ts +54 -14
- 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 +62 -35
- package/src/flow/min-cut.ts +43 -45
- package/src/index.ts +3 -2
- package/src/link-prediction/adamic-adar.ts +65 -51
- package/src/link-prediction/common-neighbors.ts +45 -36
- package/src/link-prediction/index.ts +1 -1
- package/src/optimized/bit-packed.ts +106 -56
- package/src/optimized/csr-graph.ts +93 -30
- package/src/optimized/direction-optimized-bfs.ts +44 -25
- package/src/optimized/graph-adapter.ts +64 -16
- package/src/optimized/index.ts +7 -9
- package/src/pathfinding/astar.ts +40 -25
- package/src/pathfinding/utils.ts +20 -13
- package/src/research/grsbm.ts +31 -25
- package/src/research/index.ts +4 -4
- package/src/research/sync.ts +40 -24
- package/src/research/terahac.ts +54 -20
- package/src/utils/graph-converters.ts +42 -14
- package/src/utils/graph-utilities.ts +11 -37
- package/src/utils/math-utilities.ts +17 -8
- package/src/utils/optimization-helpers.ts +27 -21
- package/src/utils/priorityQueue.ts +40 -6
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {Graph} from "../../core/graph.js";
|
|
2
|
-
import {CSRGraph} from "../../optimized/csr-graph.js";
|
|
3
|
-
import {DirectionOptimizedBFS} from "../../optimized/direction-optimized-bfs.js";
|
|
4
|
-
import {toCSRGraph} from "../../optimized/graph-adapter.js";
|
|
5
|
-
import type {NodeId, ShortestPathResult, TraversalOptions, TraversalResult} from "../../types/index.js";
|
|
6
|
-
import {reconstructPath} from "../../utils/graph-utilities.js";
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import { CSRGraph } from "../../optimized/csr-graph.js";
|
|
3
|
+
import { DirectionOptimizedBFS } from "../../optimized/direction-optimized-bfs.js";
|
|
4
|
+
import { toCSRGraph } from "../../optimized/graph-adapter.js";
|
|
5
|
+
import type { NodeId, ShortestPathResult, TraversalOptions, TraversalResult } from "../../types/index.js";
|
|
6
|
+
import { reconstructPath } from "../../utils/graph-utilities.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Unified BFS implementation that automatically optimizes for large graphs
|
|
@@ -20,6 +20,8 @@ const csrCache = new WeakMap<Graph, CSRGraph>();
|
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Get or create CSR representation of a graph
|
|
23
|
+
* @param graph - The input graph to convert
|
|
24
|
+
* @returns CSR graph representation (cached for efficiency)
|
|
23
25
|
*/
|
|
24
26
|
function getCSRGraph(graph: Graph): CSRGraph {
|
|
25
27
|
let csrGraph = csrCache.get(graph);
|
|
@@ -36,12 +38,12 @@ function getCSRGraph(graph: Graph): CSRGraph {
|
|
|
36
38
|
*
|
|
37
39
|
* Automatically uses the most optimized implementation based on graph size.
|
|
38
40
|
* No configuration needed - just call this function for the best performance.
|
|
41
|
+
* @param graph - The input graph to traverse
|
|
42
|
+
* @param startNode - The node to start the BFS from
|
|
43
|
+
* @param options - Traversal options (callbacks, target node, etc.)
|
|
44
|
+
* @returns Traversal result with visited nodes, order, and tree structure
|
|
39
45
|
*/
|
|
40
|
-
export function breadthFirstSearch(
|
|
41
|
-
graph: Graph,
|
|
42
|
-
startNode: NodeId,
|
|
43
|
-
options: TraversalOptions = {},
|
|
44
|
-
): TraversalResult {
|
|
46
|
+
export function breadthFirstSearch(graph: Graph, startNode: NodeId, options: TraversalOptions = {}): TraversalResult {
|
|
45
47
|
if (!graph.hasNode(startNode)) {
|
|
46
48
|
throw new Error(`Start node ${String(startNode)} not found in graph`);
|
|
47
49
|
}
|
|
@@ -57,19 +59,19 @@ export function breadthFirstSearch(
|
|
|
57
59
|
|
|
58
60
|
/**
|
|
59
61
|
* Standard BFS implementation for smaller graphs
|
|
62
|
+
* @param graph - The input graph to traverse
|
|
63
|
+
* @param startNode - The node to start the BFS from
|
|
64
|
+
* @param options - Traversal options (callbacks, target node, etc.)
|
|
65
|
+
* @returns Traversal result with visited nodes, order, and tree structure
|
|
60
66
|
*/
|
|
61
|
-
function breadthFirstSearchStandard(
|
|
62
|
-
graph: Graph,
|
|
63
|
-
startNode: NodeId,
|
|
64
|
-
options: TraversalOptions = {},
|
|
65
|
-
): TraversalResult {
|
|
67
|
+
function breadthFirstSearchStandard(graph: Graph, startNode: NodeId, options: TraversalOptions = {}): TraversalResult {
|
|
66
68
|
const visited = new Set<NodeId>();
|
|
67
|
-
const queue: {node: NodeId
|
|
69
|
+
const queue: { node: NodeId; level: number }[] = [];
|
|
68
70
|
const order: NodeId[] = [];
|
|
69
71
|
const tree = new Map<NodeId, NodeId | null>();
|
|
70
72
|
|
|
71
73
|
// Initialize with start node
|
|
72
|
-
queue.push({node: startNode, level: 0});
|
|
74
|
+
queue.push({ node: startNode, level: 0 });
|
|
73
75
|
visited.add(startNode);
|
|
74
76
|
tree.set(startNode, null);
|
|
75
77
|
|
|
@@ -96,22 +98,22 @@ function breadthFirstSearchStandard(
|
|
|
96
98
|
if (!visited.has(neighbor)) {
|
|
97
99
|
visited.add(neighbor);
|
|
98
100
|
tree.set(neighbor, current.node);
|
|
99
|
-
queue.push({node: neighbor, level: current.level + 1});
|
|
101
|
+
queue.push({ node: neighbor, level: current.level + 1 });
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
return {visited, order, tree};
|
|
106
|
+
return { visited, order, tree };
|
|
105
107
|
}
|
|
106
108
|
|
|
107
109
|
/**
|
|
108
110
|
* Optimized BFS implementation using Direction-Optimized BFS
|
|
111
|
+
* @param graph - The input graph to traverse
|
|
112
|
+
* @param startNode - The node to start the BFS from
|
|
113
|
+
* @param options - Traversal options (callbacks, target node, etc.)
|
|
114
|
+
* @returns Traversal result with visited nodes, order, and tree structure
|
|
109
115
|
*/
|
|
110
|
-
function breadthFirstSearchOptimized(
|
|
111
|
-
graph: Graph,
|
|
112
|
-
startNode: NodeId,
|
|
113
|
-
options: TraversalOptions = {},
|
|
114
|
-
): TraversalResult {
|
|
116
|
+
function breadthFirstSearchOptimized(graph: Graph, startNode: NodeId, options: TraversalOptions = {}): TraversalResult {
|
|
115
117
|
const csrGraph = getCSRGraph(graph);
|
|
116
118
|
|
|
117
119
|
const dobfs = new DirectionOptimizedBFS(csrGraph, {
|
|
@@ -146,7 +148,7 @@ function breadthFirstSearchOptimized(
|
|
|
146
148
|
for (let d = 0; d <= maxDistance; d++) {
|
|
147
149
|
const nodes = nodesByDistance.get(d);
|
|
148
150
|
if (nodes) {
|
|
149
|
-
order.push(...
|
|
151
|
+
order.push(...nodes);
|
|
150
152
|
}
|
|
151
153
|
}
|
|
152
154
|
|
|
@@ -157,19 +159,19 @@ function breadthFirstSearchOptimized(
|
|
|
157
159
|
}
|
|
158
160
|
}
|
|
159
161
|
|
|
160
|
-
return {visited, order, tree};
|
|
162
|
+
return { visited, order, tree };
|
|
161
163
|
}
|
|
162
164
|
|
|
163
165
|
/**
|
|
164
166
|
* Find shortest path between two nodes using BFS
|
|
165
167
|
*
|
|
166
168
|
* Automatically optimized for large graphs. Returns null if no path exists.
|
|
169
|
+
* @param graph - The input graph to search
|
|
170
|
+
* @param source - The source node ID
|
|
171
|
+
* @param target - The target node ID
|
|
172
|
+
* @returns Shortest path result or null if no path exists
|
|
167
173
|
*/
|
|
168
|
-
export function shortestPathBFS(
|
|
169
|
-
graph: Graph,
|
|
170
|
-
source: NodeId,
|
|
171
|
-
target: NodeId,
|
|
172
|
-
): ShortestPathResult | null {
|
|
174
|
+
export function shortestPathBFS(graph: Graph, source: NodeId, target: NodeId): ShortestPathResult | null {
|
|
173
175
|
if (!graph.hasNode(source)) {
|
|
174
176
|
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
175
177
|
}
|
|
@@ -198,18 +200,18 @@ export function shortestPathBFS(
|
|
|
198
200
|
|
|
199
201
|
/**
|
|
200
202
|
* Standard shortest path BFS
|
|
203
|
+
* @param graph - The input graph to search
|
|
204
|
+
* @param source - The source node ID
|
|
205
|
+
* @param target - The target node ID
|
|
206
|
+
* @returns Shortest path result or null if no path exists
|
|
201
207
|
*/
|
|
202
|
-
function shortestPathBFSStandard(
|
|
203
|
-
graph: Graph,
|
|
204
|
-
source: NodeId,
|
|
205
|
-
target: NodeId,
|
|
206
|
-
): ShortestPathResult | null {
|
|
208
|
+
function shortestPathBFSStandard(graph: Graph, source: NodeId, target: NodeId): ShortestPathResult | null {
|
|
207
209
|
const visited = new Set<NodeId>();
|
|
208
|
-
const queue: {node: NodeId
|
|
210
|
+
const queue: { node: NodeId; distance: number }[] = [];
|
|
209
211
|
const predecessor = new Map<NodeId, NodeId | null>();
|
|
210
212
|
|
|
211
213
|
// Initialize BFS
|
|
212
|
-
queue.push({node: source, distance: 0});
|
|
214
|
+
queue.push({ node: source, distance: 0 });
|
|
213
215
|
visited.add(source);
|
|
214
216
|
predecessor.set(source, null);
|
|
215
217
|
|
|
@@ -234,7 +236,7 @@ function shortestPathBFSStandard(
|
|
|
234
236
|
if (!visited.has(neighbor)) {
|
|
235
237
|
visited.add(neighbor);
|
|
236
238
|
predecessor.set(neighbor, current.node);
|
|
237
|
-
queue.push({node: neighbor, distance: current.distance + 1});
|
|
239
|
+
queue.push({ node: neighbor, distance: current.distance + 1 });
|
|
238
240
|
}
|
|
239
241
|
}
|
|
240
242
|
}
|
|
@@ -245,12 +247,12 @@ function shortestPathBFSStandard(
|
|
|
245
247
|
|
|
246
248
|
/**
|
|
247
249
|
* Optimized shortest path using Direction-Optimized BFS
|
|
250
|
+
* @param graph - The input graph to search
|
|
251
|
+
* @param source - The source node ID
|
|
252
|
+
* @param target - The target node ID
|
|
253
|
+
* @returns Shortest path result or null if no path exists
|
|
248
254
|
*/
|
|
249
|
-
function shortestPathBFSOptimized(
|
|
250
|
-
graph: Graph,
|
|
251
|
-
source: NodeId,
|
|
252
|
-
target: NodeId,
|
|
253
|
-
): ShortestPathResult | null {
|
|
255
|
+
function shortestPathBFSOptimized(graph: Graph, source: NodeId, target: NodeId): ShortestPathResult | null {
|
|
254
256
|
const csrGraph = getCSRGraph(graph);
|
|
255
257
|
|
|
256
258
|
const dobfs = new DirectionOptimizedBFS(csrGraph, {
|
|
@@ -281,11 +283,11 @@ function shortestPathBFSOptimized(
|
|
|
281
283
|
* Find shortest paths from source to all reachable nodes
|
|
282
284
|
*
|
|
283
285
|
* Automatically optimized for large graphs.
|
|
286
|
+
* @param graph - The input graph to search
|
|
287
|
+
* @param source - The source node ID to compute shortest paths from
|
|
288
|
+
* @returns Map of node IDs to their shortest path results
|
|
284
289
|
*/
|
|
285
|
-
export function singleSourceShortestPathBFS(
|
|
286
|
-
graph: Graph,
|
|
287
|
-
source: NodeId,
|
|
288
|
-
): Map<NodeId, ShortestPathResult> {
|
|
290
|
+
export function singleSourceShortestPathBFS(graph: Graph, source: NodeId): Map<NodeId, ShortestPathResult> {
|
|
289
291
|
if (!graph.hasNode(source)) {
|
|
290
292
|
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
291
293
|
}
|
|
@@ -301,19 +303,19 @@ export function singleSourceShortestPathBFS(
|
|
|
301
303
|
|
|
302
304
|
/**
|
|
303
305
|
* Standard single-source shortest paths
|
|
306
|
+
* @param graph - The input graph to search
|
|
307
|
+
* @param source - The source node ID to compute shortest paths from
|
|
308
|
+
* @returns Map of node IDs to their shortest path results
|
|
304
309
|
*/
|
|
305
|
-
function singleSourceShortestPathBFSStandard(
|
|
306
|
-
graph: Graph,
|
|
307
|
-
source: NodeId,
|
|
308
|
-
): Map<NodeId, ShortestPathResult> {
|
|
310
|
+
function singleSourceShortestPathBFSStandard(graph: Graph, source: NodeId): Map<NodeId, ShortestPathResult> {
|
|
309
311
|
const results = new Map<NodeId, ShortestPathResult>();
|
|
310
312
|
const visited = new Set<NodeId>();
|
|
311
|
-
const queue: {node: NodeId
|
|
313
|
+
const queue: { node: NodeId; distance: number }[] = [];
|
|
312
314
|
const predecessor = new Map<NodeId, NodeId | null>();
|
|
313
315
|
const distances = new Map<NodeId, number>();
|
|
314
316
|
|
|
315
317
|
// Initialize BFS
|
|
316
|
-
queue.push({node: source, distance: 0});
|
|
318
|
+
queue.push({ node: source, distance: 0 });
|
|
317
319
|
visited.add(source);
|
|
318
320
|
predecessor.set(source, null);
|
|
319
321
|
distances.set(source, 0);
|
|
@@ -330,7 +332,7 @@ function singleSourceShortestPathBFSStandard(
|
|
|
330
332
|
visited.add(neighbor);
|
|
331
333
|
predecessor.set(neighbor, current.node);
|
|
332
334
|
distances.set(neighbor, current.distance + 1);
|
|
333
|
-
queue.push({node: neighbor, distance: current.distance + 1});
|
|
335
|
+
queue.push({ node: neighbor, distance: current.distance + 1 });
|
|
334
336
|
}
|
|
335
337
|
}
|
|
336
338
|
}
|
|
@@ -351,11 +353,11 @@ function singleSourceShortestPathBFSStandard(
|
|
|
351
353
|
|
|
352
354
|
/**
|
|
353
355
|
* Optimized single-source shortest paths
|
|
356
|
+
* @param graph - The input graph to search
|
|
357
|
+
* @param source - The source node ID to compute shortest paths from
|
|
358
|
+
* @returns Map of node IDs to their shortest path results
|
|
354
359
|
*/
|
|
355
|
-
function singleSourceShortestPathBFSOptimized(
|
|
356
|
-
graph: Graph,
|
|
357
|
-
source: NodeId,
|
|
358
|
-
): Map<NodeId, ShortestPathResult> {
|
|
360
|
+
function singleSourceShortestPathBFSOptimized(graph: Graph, source: NodeId): Map<NodeId, ShortestPathResult> {
|
|
359
361
|
const csrGraph = getCSRGraph(graph);
|
|
360
362
|
|
|
361
363
|
const dobfs = new DirectionOptimizedBFS(csrGraph, {
|
|
@@ -387,6 +389,8 @@ function singleSourceShortestPathBFSOptimized(
|
|
|
387
389
|
*
|
|
388
390
|
* Note: This function does not use Direction-Optimized BFS as the
|
|
389
391
|
* coloring logic is specific and doesn't benefit from the optimization.
|
|
392
|
+
* @param graph - The undirected graph to check
|
|
393
|
+
* @returns True if the graph is bipartite, false otherwise
|
|
390
394
|
*/
|
|
391
395
|
export function isBipartite(graph: Graph): boolean {
|
|
392
396
|
if (graph.isDirected) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {Graph} from "../../core/graph.js";
|
|
2
|
-
import {PriorityQueue} from "../../data-structures/priority-queue.js";
|
|
3
|
-
import {CSRGraph} from "../../optimized/csr-graph.js";
|
|
4
|
-
import {DirectionOptimizedBFS} from "../../optimized/direction-optimized-bfs.js";
|
|
5
|
-
import {toCSRGraph} from "../../optimized/graph-adapter.js";
|
|
6
|
-
import type {NodeId} from "../../types/index.js";
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import { PriorityQueue } from "../../data-structures/priority-queue.js";
|
|
3
|
+
import { CSRGraph } from "../../optimized/csr-graph.js";
|
|
4
|
+
import { DirectionOptimizedBFS } from "../../optimized/direction-optimized-bfs.js";
|
|
5
|
+
import { toCSRGraph } from "../../optimized/graph-adapter.js";
|
|
6
|
+
import type { NodeId } from "../../types/index.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Threshold for switching to CSR-optimized implementations.
|
|
@@ -20,17 +20,22 @@ const LARGE_GRAPH_THRESHOLD = 10000;
|
|
|
20
20
|
* - All predecessors on shortest paths
|
|
21
21
|
* - Number of shortest paths (sigma)
|
|
22
22
|
* - Stack of nodes in reverse BFS order
|
|
23
|
+
* @param graph - The input graph to traverse
|
|
24
|
+
* @param source - The source node to start BFS from
|
|
25
|
+
* @param options - Configuration options
|
|
26
|
+
* @param options.optimized - Whether to use CSR-optimized implementation for large graphs
|
|
27
|
+
* @returns Object containing distances, predecessors, path counts (sigma), and traversal stack
|
|
23
28
|
*/
|
|
24
29
|
export function bfsWithPathCounting(
|
|
25
30
|
graph: Graph,
|
|
26
31
|
source: NodeId,
|
|
27
|
-
options: {optimized?: boolean} = {},
|
|
32
|
+
options: { optimized?: boolean } = {},
|
|
28
33
|
): {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
distances: Map<NodeId, number>;
|
|
35
|
+
predecessors: Map<NodeId, NodeId[]>;
|
|
36
|
+
sigma: Map<NodeId, number>;
|
|
37
|
+
stack: NodeId[];
|
|
38
|
+
} {
|
|
34
39
|
const useOptimized = options.optimized ?? false;
|
|
35
40
|
|
|
36
41
|
// Use CSR format for large graphs
|
|
@@ -94,12 +99,18 @@ export function bfsWithPathCounting(
|
|
|
94
99
|
* BFS that only returns distances (for closeness centrality)
|
|
95
100
|
*
|
|
96
101
|
* Optimized variant that skips predecessor tracking
|
|
102
|
+
* @param graph - The input graph to traverse
|
|
103
|
+
* @param source - The source node to start BFS from
|
|
104
|
+
* @param cutoff - Maximum distance to explore (optional)
|
|
105
|
+
* @param options - Configuration options
|
|
106
|
+
* @param options.optimized - Whether to use CSR-optimized implementation for large graphs
|
|
107
|
+
* @returns Map of node IDs to their shortest distances from the source
|
|
97
108
|
*/
|
|
98
109
|
export function bfsDistancesOnly(
|
|
99
110
|
graph: Graph,
|
|
100
111
|
source: NodeId,
|
|
101
112
|
cutoff?: number,
|
|
102
|
-
options: {optimized?: boolean} = {},
|
|
113
|
+
options: { optimized?: boolean } = {},
|
|
103
114
|
): Map<NodeId, number> {
|
|
104
115
|
const useOptimized = options.optimized ?? false;
|
|
105
116
|
|
|
@@ -144,13 +155,13 @@ export function bfsDistancesOnly(
|
|
|
144
155
|
* BFS for bipartite checking with partition sets
|
|
145
156
|
*
|
|
146
157
|
* Returns whether the graph is bipartite and the two partitions if it is
|
|
158
|
+
* @param graph - The input graph to check for bipartiteness
|
|
159
|
+
* @returns Object with bipartite status and optional partition sets
|
|
147
160
|
*/
|
|
148
|
-
export function bfsColoringWithPartitions(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
partitions?: [Set<NodeId>, Set<NodeId>];
|
|
153
|
-
} {
|
|
161
|
+
export function bfsColoringWithPartitions(graph: Graph): {
|
|
162
|
+
isBipartite: boolean;
|
|
163
|
+
partitions?: [Set<NodeId>, Set<NodeId>];
|
|
164
|
+
} {
|
|
154
165
|
const colors = new Map<NodeId, number>();
|
|
155
166
|
const partitionA = new Set<NodeId>();
|
|
156
167
|
const partitionB = new Set<NodeId>();
|
|
@@ -183,7 +194,7 @@ export function bfsColoringWithPartitions(
|
|
|
183
194
|
}
|
|
184
195
|
} else if (colors.get(neighbor) === currentColor) {
|
|
185
196
|
// Same color as current node - not bipartite
|
|
186
|
-
return {isBipartite: false};
|
|
197
|
+
return { isBipartite: false };
|
|
187
198
|
}
|
|
188
199
|
}
|
|
189
200
|
}
|
|
@@ -200,6 +211,10 @@ export function bfsColoringWithPartitions(
|
|
|
200
211
|
* BFS for finding augmenting paths (for flow algorithms)
|
|
201
212
|
*
|
|
202
213
|
* Finds a path from source to sink in a residual graph with positive capacity
|
|
214
|
+
* @param residualGraph - Map representing the residual graph with capacities
|
|
215
|
+
* @param source - The source node ID
|
|
216
|
+
* @param sink - The sink node ID
|
|
217
|
+
* @returns Object with path and capacity, or null if no path exists
|
|
203
218
|
*/
|
|
204
219
|
export function bfsAugmentingPath(
|
|
205
220
|
residualGraph: Map<string, Map<string, number>>,
|
|
@@ -239,7 +254,7 @@ export function bfsAugmentingPath(
|
|
|
239
254
|
node = parentNode ?? null;
|
|
240
255
|
}
|
|
241
256
|
|
|
242
|
-
return {path, pathCapacity};
|
|
257
|
+
return { path, pathCapacity };
|
|
243
258
|
}
|
|
244
259
|
|
|
245
260
|
const neighbors = residualGraph.get(current);
|
|
@@ -260,12 +275,18 @@ export function bfsAugmentingPath(
|
|
|
260
275
|
* BFS for weighted graphs using priority queue (simplified Dijkstra)
|
|
261
276
|
*
|
|
262
277
|
* Returns distances from source using edge weights
|
|
278
|
+
* @param graph - The input weighted graph to traverse
|
|
279
|
+
* @param source - The source node to start BFS from
|
|
280
|
+
* @param cutoff - Maximum distance to explore (optional)
|
|
281
|
+
* @param options - Configuration options
|
|
282
|
+
* @param options.optimized - Whether to use CSR-optimized implementation for large graphs
|
|
283
|
+
* @returns Map of node IDs to their shortest weighted distances from the source
|
|
263
284
|
*/
|
|
264
285
|
export function bfsWeightedDistances(
|
|
265
286
|
graph: Graph,
|
|
266
287
|
source: NodeId,
|
|
267
288
|
cutoff?: number,
|
|
268
|
-
options: {optimized?: boolean} = {},
|
|
289
|
+
options: { optimized?: boolean } = {},
|
|
269
290
|
): Map<NodeId, number> {
|
|
270
291
|
const useOptimized = options.optimized ?? false;
|
|
271
292
|
|
|
@@ -323,16 +344,19 @@ export function bfsWeightedDistances(
|
|
|
323
344
|
|
|
324
345
|
/**
|
|
325
346
|
* CSR-optimized version of bfsWithPathCounting
|
|
347
|
+
* @param graph - The CSR graph representation
|
|
348
|
+
* @param source - The source node to start BFS from
|
|
349
|
+
* @returns Object containing distances, predecessors, path counts (sigma), and traversal stack
|
|
326
350
|
*/
|
|
327
351
|
function bfsWithPathCountingCSR(
|
|
328
352
|
graph: CSRGraph,
|
|
329
353
|
source: NodeId,
|
|
330
354
|
): {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
355
|
+
distances: Map<NodeId, number>;
|
|
356
|
+
predecessors: Map<NodeId, NodeId[]>;
|
|
357
|
+
sigma: Map<NodeId, number>;
|
|
358
|
+
stack: NodeId[];
|
|
359
|
+
} {
|
|
336
360
|
const distances = new Map<NodeId, number>();
|
|
337
361
|
const predecessors = new Map<NodeId, NodeId[]>();
|
|
338
362
|
const sigma = new Map<NodeId, number>();
|
|
@@ -385,12 +409,12 @@ function bfsWithPathCountingCSR(
|
|
|
385
409
|
|
|
386
410
|
/**
|
|
387
411
|
* CSR-optimized version of bfsDistancesOnly
|
|
412
|
+
* @param graph - The CSR graph representation
|
|
413
|
+
* @param source - The source node to start BFS from
|
|
414
|
+
* @param cutoff - Maximum distance to explore (optional)
|
|
415
|
+
* @returns Map of node IDs to their shortest distances from the source
|
|
388
416
|
*/
|
|
389
|
-
function bfsDistancesOnlyCSR(
|
|
390
|
-
graph: CSRGraph,
|
|
391
|
-
source: NodeId,
|
|
392
|
-
cutoff?: number,
|
|
393
|
-
): Map<NodeId, number> {
|
|
417
|
+
function bfsDistancesOnlyCSR(graph: CSRGraph, source: NodeId, cutoff?: number): Map<NodeId, number> {
|
|
394
418
|
// Use Direction-Optimized BFS for best performance
|
|
395
419
|
if (graph.nodeCount() > LARGE_GRAPH_THRESHOLD) {
|
|
396
420
|
const dobfs = new DirectionOptimizedBFS(graph);
|
|
@@ -443,12 +467,12 @@ function bfsDistancesOnlyCSR(
|
|
|
443
467
|
|
|
444
468
|
/**
|
|
445
469
|
* CSR-optimized version of bfsWeightedDistances
|
|
470
|
+
* @param graph - The CSR graph representation
|
|
471
|
+
* @param source - The source node to start BFS from
|
|
472
|
+
* @param cutoff - Maximum distance to explore (optional)
|
|
473
|
+
* @returns Map of node IDs to their shortest weighted distances from the source
|
|
446
474
|
*/
|
|
447
|
-
function bfsWeightedDistancesCSR(
|
|
448
|
-
graph: CSRGraph,
|
|
449
|
-
source: NodeId,
|
|
450
|
-
cutoff?: number,
|
|
451
|
-
): Map<NodeId, number> {
|
|
475
|
+
function bfsWeightedDistancesCSR(graph: CSRGraph, source: NodeId, cutoff?: number): Map<NodeId, number> {
|
|
452
476
|
const distances = new Map<NodeId, number>();
|
|
453
477
|
const visited = new Set<NodeId>();
|
|
454
478
|
|
|
@@ -9,10 +9,4 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
// Re-export unified implementations that automatically optimize for large graphs
|
|
12
|
-
export {
|
|
13
|
-
breadthFirstSearch,
|
|
14
|
-
isBipartite,
|
|
15
|
-
shortestPathBFS,
|
|
16
|
-
singleSourceShortestPathBFS,
|
|
17
|
-
} from "./bfs-unified.js";
|
|
18
|
-
|
|
12
|
+
export { breadthFirstSearch, isBipartite, shortestPathBFS, singleSourceShortestPathBFS } from "./bfs-unified.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {Graph} from "../../core/graph.js";
|
|
2
|
-
import type {NodeId, TraversalOptions, TraversalResult} from "../../types/index.js";
|
|
1
|
+
import { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { NodeId, TraversalOptions, TraversalResult } from "../../types/index.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Depth-First Search (DFS) implementation
|
|
@@ -18,12 +18,12 @@ export interface DFSOptions extends TraversalOptions {
|
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Perform depth-first search starting from a given node
|
|
21
|
+
* @param graph - The input graph to traverse
|
|
22
|
+
* @param startNode - The node to start the DFS from
|
|
23
|
+
* @param options - DFS options (recursive mode, pre/post order, etc.)
|
|
24
|
+
* @returns Traversal result with visited nodes, order, and tree structure
|
|
21
25
|
*/
|
|
22
|
-
export function depthFirstSearch(
|
|
23
|
-
graph: Graph,
|
|
24
|
-
startNode: NodeId,
|
|
25
|
-
options: DFSOptions = {},
|
|
26
|
-
): TraversalResult {
|
|
26
|
+
export function depthFirstSearch(graph: Graph, startNode: NodeId, options: DFSOptions = {}): TraversalResult {
|
|
27
27
|
if (!graph.hasNode(startNode)) {
|
|
28
28
|
throw new Error(`Start node ${String(startNode)} not found in graph`);
|
|
29
29
|
}
|
|
@@ -38,11 +38,17 @@ export function depthFirstSearch(
|
|
|
38
38
|
dfsIterative(graph, startNode, visited, order, tree, options);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
return {visited, order, tree};
|
|
41
|
+
return { visited, order, tree };
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* Iterative DFS implementation (safer for browsers)
|
|
46
|
+
* @param graph - The input graph to traverse
|
|
47
|
+
* @param startNode - The node to start the DFS from
|
|
48
|
+
* @param visited - Set to track visited nodes
|
|
49
|
+
* @param order - Array to store traversal order
|
|
50
|
+
* @param tree - Map to store parent relationships
|
|
51
|
+
* @param options - DFS options (recursive mode, pre/post order, etc.)
|
|
46
52
|
*/
|
|
47
53
|
function dfsIterative(
|
|
48
54
|
graph: Graph,
|
|
@@ -58,8 +64,8 @@ function dfsIterative(
|
|
|
58
64
|
return;
|
|
59
65
|
}
|
|
60
66
|
|
|
61
|
-
const stack: {node: NodeId
|
|
62
|
-
stack.push({node: startNode, parent: null, depth: 0});
|
|
67
|
+
const stack: { node: NodeId; parent: NodeId | null; depth: number }[] = [];
|
|
68
|
+
stack.push({ node: startNode, parent: null, depth: 0 });
|
|
63
69
|
|
|
64
70
|
while (stack.length > 0) {
|
|
65
71
|
const current = stack.pop();
|
|
@@ -89,7 +95,7 @@ function dfsIterative(
|
|
|
89
95
|
for (let i = neighbors.length - 1; i >= 0; i--) {
|
|
90
96
|
const neighbor = neighbors[i];
|
|
91
97
|
if (neighbor !== undefined && !visited.has(neighbor)) {
|
|
92
|
-
stack.push({node: neighbor, parent: current.node, depth: current.depth + 1});
|
|
98
|
+
stack.push({ node: neighbor, parent: current.node, depth: current.depth + 1 });
|
|
93
99
|
}
|
|
94
100
|
}
|
|
95
101
|
}
|
|
@@ -98,6 +104,14 @@ function dfsIterative(
|
|
|
98
104
|
|
|
99
105
|
/**
|
|
100
106
|
* Recursive DFS implementation
|
|
107
|
+
* @param graph - The input graph to traverse
|
|
108
|
+
* @param node - Current node being visited
|
|
109
|
+
* @param visited - Set to track visited nodes
|
|
110
|
+
* @param order - Array to store traversal order
|
|
111
|
+
* @param tree - Map to store parent relationships
|
|
112
|
+
* @param options - DFS options (recursive mode, pre/post order, etc.)
|
|
113
|
+
* @param depth - Current depth in the traversal tree
|
|
114
|
+
* @param parent - Parent node of the current node
|
|
101
115
|
*/
|
|
102
116
|
function dfsRecursive(
|
|
103
117
|
graph: Graph,
|
|
@@ -145,6 +159,8 @@ function dfsRecursive(
|
|
|
145
159
|
|
|
146
160
|
/**
|
|
147
161
|
* Detect cycles in a graph using DFS
|
|
162
|
+
* @param graph - The input graph to check for cycles
|
|
163
|
+
* @returns True if the graph contains a cycle, false otherwise
|
|
148
164
|
*/
|
|
149
165
|
export function hasCycleDFS(graph: Graph): boolean {
|
|
150
166
|
const visited = new Set<NodeId>();
|
|
@@ -170,13 +186,13 @@ export function hasCycleDFS(graph: Graph): boolean {
|
|
|
170
186
|
|
|
171
187
|
/**
|
|
172
188
|
* Utility function for cycle detection in directed graphs
|
|
189
|
+
* @param graph - The directed graph to check
|
|
190
|
+
* @param node - Current node being visited
|
|
191
|
+
* @param visited - Set of all visited nodes
|
|
192
|
+
* @param recursionStack - Set of nodes in the current recursion path
|
|
193
|
+
* @returns True if a cycle is found, false otherwise
|
|
173
194
|
*/
|
|
174
|
-
function hasCycleUtilDirected(
|
|
175
|
-
graph: Graph,
|
|
176
|
-
node: NodeId,
|
|
177
|
-
visited: Set<NodeId>,
|
|
178
|
-
recursionStack: Set<NodeId>,
|
|
179
|
-
): boolean {
|
|
195
|
+
function hasCycleUtilDirected(graph: Graph, node: NodeId, visited: Set<NodeId>, recursionStack: Set<NodeId>): boolean {
|
|
180
196
|
visited.add(node);
|
|
181
197
|
recursionStack.add(node);
|
|
182
198
|
|
|
@@ -198,13 +214,13 @@ function hasCycleUtilDirected(
|
|
|
198
214
|
|
|
199
215
|
/**
|
|
200
216
|
* Utility function for cycle detection in undirected graphs
|
|
217
|
+
* @param graph - The undirected graph to check
|
|
218
|
+
* @param node - Current node being visited
|
|
219
|
+
* @param visited - Set of all visited nodes
|
|
220
|
+
* @param parent - Parent node of the current node
|
|
221
|
+
* @returns True if a cycle is found, false otherwise
|
|
201
222
|
*/
|
|
202
|
-
function hasCycleUtilUndirected(
|
|
203
|
-
graph: Graph,
|
|
204
|
-
node: NodeId,
|
|
205
|
-
visited: Set<NodeId>,
|
|
206
|
-
parent: NodeId | null,
|
|
207
|
-
): boolean {
|
|
223
|
+
function hasCycleUtilUndirected(graph: Graph, node: NodeId, visited: Set<NodeId>, parent: NodeId | null): boolean {
|
|
208
224
|
visited.add(node);
|
|
209
225
|
|
|
210
226
|
// Check all neighbors
|
|
@@ -224,6 +240,8 @@ function hasCycleUtilUndirected(
|
|
|
224
240
|
|
|
225
241
|
/**
|
|
226
242
|
* Topological sorting using DFS (for directed acyclic graphs)
|
|
243
|
+
* @param graph - The directed acyclic graph to sort
|
|
244
|
+
* @returns Array of node IDs in topological order, or null if graph has cycles
|
|
227
245
|
*/
|
|
228
246
|
export function topologicalSort(graph: Graph): NodeId[] | null {
|
|
229
247
|
if (!graph.isDirected) {
|
|
@@ -251,13 +269,12 @@ export function topologicalSort(graph: Graph): NodeId[] | null {
|
|
|
251
269
|
|
|
252
270
|
/**
|
|
253
271
|
* Utility function for topological sorting
|
|
272
|
+
* @param graph - The directed graph being sorted
|
|
273
|
+
* @param node - Current node being visited
|
|
274
|
+
* @param visited - Set of visited nodes
|
|
275
|
+
* @param stack - Stack to store nodes in reverse topological order
|
|
254
276
|
*/
|
|
255
|
-
function topologicalSortUtil(
|
|
256
|
-
graph: Graph,
|
|
257
|
-
node: NodeId,
|
|
258
|
-
visited: Set<NodeId>,
|
|
259
|
-
stack: NodeId[],
|
|
260
|
-
): void {
|
|
277
|
+
function topologicalSortUtil(graph: Graph, node: NodeId, visited: Set<NodeId>, stack: NodeId[]): void {
|
|
261
278
|
visited.add(node);
|
|
262
279
|
|
|
263
280
|
// Visit all neighbors first
|
|
@@ -273,6 +290,8 @@ function topologicalSortUtil(
|
|
|
273
290
|
|
|
274
291
|
/**
|
|
275
292
|
* Find strongly connected components using DFS (for directed graphs)
|
|
293
|
+
* @param graph - The directed graph to analyze
|
|
294
|
+
* @returns Array of strongly connected components (each is an array of node IDs)
|
|
276
295
|
*/
|
|
277
296
|
export function findStronglyConnectedComponents(graph: Graph): NodeId[][] {
|
|
278
297
|
if (!graph.isDirected) {
|
|
@@ -310,13 +329,12 @@ export function findStronglyConnectedComponents(graph: Graph): NodeId[][] {
|
|
|
310
329
|
|
|
311
330
|
/**
|
|
312
331
|
* DFS to record finish order
|
|
332
|
+
* @param graph - The graph being traversed
|
|
333
|
+
* @param node - Current node being visited
|
|
334
|
+
* @param visited - Set of visited nodes
|
|
335
|
+
* @param finishOrder - Array to store nodes in order of completion
|
|
313
336
|
*/
|
|
314
|
-
function dfsFinishOrder(
|
|
315
|
-
graph: Graph,
|
|
316
|
-
node: NodeId,
|
|
317
|
-
visited: Set<NodeId>,
|
|
318
|
-
finishOrder: NodeId[],
|
|
319
|
-
): void {
|
|
337
|
+
function dfsFinishOrder(graph: Graph, node: NodeId, visited: Set<NodeId>, finishOrder: NodeId[]): void {
|
|
320
338
|
visited.add(node);
|
|
321
339
|
|
|
322
340
|
for (const neighbor of Array.from(graph.neighbors(node))) {
|
|
@@ -330,13 +348,12 @@ function dfsFinishOrder(
|
|
|
330
348
|
|
|
331
349
|
/**
|
|
332
350
|
* DFS to collect nodes in a component
|
|
351
|
+
* @param graph - The graph being traversed
|
|
352
|
+
* @param node - Current node being visited
|
|
353
|
+
* @param visited - Set of visited nodes
|
|
354
|
+
* @param component - Array to collect nodes in the current component
|
|
333
355
|
*/
|
|
334
|
-
function dfsCollectComponent(
|
|
335
|
-
graph: Graph,
|
|
336
|
-
node: NodeId,
|
|
337
|
-
visited: Set<NodeId>,
|
|
338
|
-
component: NodeId[],
|
|
339
|
-
): void {
|
|
356
|
+
function dfsCollectComponent(graph: Graph, node: NodeId, visited: Set<NodeId>, component: NodeId[]): void {
|
|
340
357
|
visited.add(node);
|
|
341
358
|
component.push(node);
|
|
342
359
|
|
|
@@ -349,9 +366,11 @@ function dfsCollectComponent(
|
|
|
349
366
|
|
|
350
367
|
/**
|
|
351
368
|
* Create transpose (reverse) of a directed graph
|
|
369
|
+
* @param graph - The directed graph to transpose
|
|
370
|
+
* @returns A new graph with all edges reversed
|
|
352
371
|
*/
|
|
353
372
|
function createTransposeGraph(graph: Graph): Graph {
|
|
354
|
-
const transpose = new Graph({directed: true});
|
|
373
|
+
const transpose = new Graph({ directed: true });
|
|
355
374
|
|
|
356
375
|
// Add all nodes
|
|
357
376
|
for (const node of Array.from(graph.nodes())) {
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* Graph traversal algorithms
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export {breadthFirstSearch, isBipartite, shortestPathBFS, singleSourceShortestPathBFS} from "./bfs.js";
|
|
6
|
-
export type {DFSOptions} from "./dfs.js";
|
|
7
|
-
export {depthFirstSearch, findStronglyConnectedComponents, hasCycleDFS, topologicalSort} from "./dfs.js";
|
|
5
|
+
export { breadthFirstSearch, isBipartite, shortestPathBFS, singleSourceShortestPathBFS } from "./bfs.js";
|
|
6
|
+
export type { DFSOptions } from "./dfs.js";
|
|
7
|
+
export { depthFirstSearch, findStronglyConnectedComponents, hasCycleDFS, topologicalSort } from "./dfs.js";
|