@graphty/algorithms 1.1.0 → 1.3.1
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 +820 -235
- package/dist/algorithms.d.ts +42 -2
- package/dist/algorithms.js +11099 -2
- package/dist/algorithms.js.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.d.ts +4 -0
- package/dist/src/algorithms/centrality/betweenness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/betweenness.js +124 -170
- package/dist/src/algorithms/centrality/betweenness.js.map +1 -1
- package/dist/src/algorithms/centrality/closeness.d.ts +26 -1
- package/dist/src/algorithms/centrality/closeness.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/closeness.js +56 -149
- package/dist/src/algorithms/centrality/closeness.js.map +1 -1
- package/dist/src/algorithms/centrality/degree.js +3 -3
- package/dist/src/algorithms/centrality/degree.js.map +1 -1
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts +39 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js +286 -0
- package/dist/src/algorithms/centrality/delta-pagerank-simple.js.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts +80 -0
- package/dist/src/algorithms/centrality/delta-pagerank.d.ts.map +1 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js +294 -0
- package/dist/src/algorithms/centrality/delta-pagerank.js.map +1 -0
- package/dist/src/algorithms/centrality/index.d.ts +2 -0
- package/dist/src/algorithms/centrality/index.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/index.js +1 -0
- package/dist/src/algorithms/centrality/index.js.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.d.ts +17 -0
- package/dist/src/algorithms/centrality/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/centrality/pagerank.js +45 -0
- package/dist/src/algorithms/centrality/pagerank.js.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.d.ts.map +1 -1
- package/dist/src/algorithms/community/girvan-newman.js +47 -54
- 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 +13 -3
- package/dist/src/algorithms/community/label-propagation.d.ts.map +1 -1
- package/dist/src/algorithms/community/label-propagation.js +50 -35
- package/dist/src/algorithms/community/label-propagation.js.map +1 -1
- package/dist/src/algorithms/community/leiden.d.ts +3 -2
- package/dist/src/algorithms/community/leiden.d.ts.map +1 -1
- package/dist/src/algorithms/community/leiden.js +34 -39
- package/dist/src/algorithms/community/leiden.js.map +1 -1
- package/dist/src/algorithms/community/louvain-optimized.d.ts +112 -0
- package/dist/src/algorithms/community/louvain-optimized.d.ts.map +1 -0
- package/dist/src/algorithms/community/louvain-optimized.js +303 -0
- package/dist/src/algorithms/community/louvain-optimized.js.map +1 -0
- package/dist/src/algorithms/community/louvain.d.ts.map +1 -1
- package/dist/src/algorithms/community/louvain.js +17 -76
- package/dist/src/algorithms/community/louvain.js.map +1 -1
- package/dist/src/algorithms/community/modularity-utils.d.ts +59 -0
- package/dist/src/algorithms/community/modularity-utils.d.ts.map +1 -0
- package/dist/src/algorithms/community/modularity-utils.js +112 -0
- package/dist/src/algorithms/community/modularity-utils.js.map +1 -0
- package/dist/src/algorithms/matching/bipartite.d.ts.map +1 -1
- package/dist/src/algorithms/matching/bipartite.js +8 -40
- package/dist/src/algorithms/matching/bipartite.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/bellman-ford.js +1 -12
- package/dist/src/algorithms/shortest-path/bellman-ford.js.map +1 -1
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts +37 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.d.ts.map +1 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js +193 -0
- package/dist/src/algorithms/shortest-path/bidirectional-dijkstra.js.map +1 -0
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts +5 -2
- package/dist/src/algorithms/shortest-path/dijkstra.d.ts.map +1 -1
- package/dist/src/algorithms/shortest-path/dijkstra.js +15 -14
- package/dist/src/algorithms/shortest-path/dijkstra.js.map +1 -1
- package/dist/src/algorithms/traversal/bfs-unified.d.ts +29 -0
- package/dist/src/algorithms/traversal/bfs-unified.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-unified.js +333 -0
- package/dist/src/algorithms/traversal/bfs-unified.js.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts +54 -0
- package/dist/src/algorithms/traversal/bfs-variants.d.ts.map +1 -0
- package/dist/src/algorithms/traversal/bfs-variants.js +368 -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/benchmark-all-algorithms.d.ts +23 -0
- package/dist/src/benchmark-all-algorithms.d.ts.map +1 -0
- package/dist/src/benchmark-all-algorithms.js +462 -0
- package/dist/src/benchmark-all-algorithms.js.map +1 -0
- package/dist/src/clustering/hierarchical.d.ts +16 -15
- package/dist/src/clustering/hierarchical.d.ts.map +1 -1
- package/dist/src/clustering/hierarchical.js +209 -223
- 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 +16 -15
- package/dist/src/clustering/k-core.d.ts.map +1 -1
- package/dist/src/clustering/k-core.js +57 -21
- package/dist/src/clustering/k-core.js.map +1 -1
- package/dist/src/clustering/spectral.d.ts +8 -0
- package/dist/src/clustering/spectral.d.ts.map +1 -1
- package/dist/src/clustering/spectral.js +158 -35
- package/dist/src/clustering/spectral.js.map +1 -1
- package/dist/src/core/graph.js +4 -4
- package/dist/src/core/graph.js.map +1 -1
- package/dist/src/flow/ford-fulkerson.d.ts +17 -11
- package/dist/src/flow/ford-fulkerson.d.ts.map +1 -1
- package/dist/src/flow/ford-fulkerson.js +141 -217
- package/dist/src/flow/ford-fulkerson.js.map +1 -1
- package/dist/src/flow/min-cut.d.ts +6 -5
- package/dist/src/flow/min-cut.d.ts.map +1 -1
- package/dist/src/flow/min-cut.js +17 -8
- package/dist/src/flow/min-cut.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/link-prediction/adamic-adar.d.ts.map +1 -1
- package/dist/src/link-prediction/adamic-adar.js +17 -26
- package/dist/src/link-prediction/adamic-adar.js.map +1 -1
- package/dist/src/link-prediction/common-neighbors.d.ts.map +1 -1
- package/dist/src/link-prediction/common-neighbors.js +7 -11
- package/dist/src/link-prediction/common-neighbors.js.map +1 -1
- package/dist/src/optimized/bit-packed.d.ts +143 -0
- package/dist/src/optimized/bit-packed.d.ts.map +1 -0
- package/dist/src/optimized/bit-packed.js +292 -0
- package/dist/src/optimized/bit-packed.js.map +1 -0
- package/dist/src/optimized/csr-graph.d.ts +86 -0
- package/dist/src/optimized/csr-graph.d.ts.map +1 -0
- package/dist/src/optimized/csr-graph.js +341 -0
- package/dist/src/optimized/csr-graph.js.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts +74 -0
- package/dist/src/optimized/direction-optimized-bfs.d.ts.map +1 -0
- package/dist/src/optimized/direction-optimized-bfs.js +223 -0
- package/dist/src/optimized/direction-optimized-bfs.js.map +1 -0
- package/dist/src/optimized/graph-adapter.d.ts +62 -0
- package/dist/src/optimized/graph-adapter.d.ts.map +1 -0
- package/dist/src/optimized/graph-adapter.js +146 -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 +28 -0
- package/dist/src/optimized/index.js.map +1 -0
- package/dist/src/research/grsbm.d.ts +83 -0
- package/dist/src/research/grsbm.d.ts.map +1 -0
- package/dist/src/research/grsbm.js +403 -0
- package/dist/src/research/grsbm.js.map +1 -0
- package/dist/src/research/index.d.ts +12 -0
- package/dist/src/research/index.d.ts.map +1 -0
- package/dist/src/research/index.js +14 -0
- package/dist/src/research/index.js.map +1 -0
- package/dist/src/research/sync.d.ts +49 -0
- package/dist/src/research/sync.d.ts.map +1 -0
- package/dist/src/research/sync.js +316 -0
- package/dist/src/research/sync.js.map +1 -0
- package/dist/src/research/terahac.d.ts +65 -0
- package/dist/src/research/terahac.d.ts.map +1 -0
- package/dist/src/research/terahac.js +379 -0
- package/dist/src/research/terahac.js.map +1 -0
- 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 +79 -0
- package/dist/src/utils/graph-converters.d.ts.map +1 -0
- package/dist/src/utils/graph-converters.js +196 -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 +52 -0
- package/dist/src/utils/math-utilities.d.ts.map +1 -0
- package/dist/src/utils/math-utilities.js +123 -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 +33 -0
- package/dist/src/utils/optimization-helpers.d.ts.map +1 -0
- package/dist/src/utils/optimization-helpers.js +47 -0
- package/dist/src/utils/optimization-helpers.js.map +1 -0
- package/package.json +28 -4
- package/src/algorithms/centrality/betweenness.ts +167 -199
- package/src/algorithms/centrality/closeness.ts +73 -191
- package/src/algorithms/centrality/degree.ts +3 -3
- package/src/algorithms/centrality/delta-pagerank-simple.ts +366 -0
- package/src/algorithms/centrality/delta-pagerank.ts +435 -0
- package/src/algorithms/centrality/index.ts +2 -0
- package/src/algorithms/centrality/pagerank.ts +66 -0
- package/src/algorithms/community/girvan-newman.ts +52 -59
- package/src/algorithms/community/index.ts +2 -0
- package/src/algorithms/community/label-propagation.ts +64 -35
- package/src/algorithms/community/leiden.ts +40 -41
- package/src/algorithms/community/louvain-optimized.ts +445 -0
- package/src/algorithms/community/louvain.ts +24 -104
- package/src/algorithms/community/modularity-utils.ts +146 -0
- package/src/algorithms/matching/bipartite.ts +8 -44
- package/src/algorithms/shortest-path/bellman-ford.ts +1 -14
- package/src/algorithms/shortest-path/bidirectional-dijkstra.ts +248 -0
- package/src/algorithms/shortest-path/dijkstra.ts +17 -15
- package/src/algorithms/traversal/bfs-unified.ts +433 -0
- package/src/algorithms/traversal/bfs-variants.ts +496 -0
- package/src/algorithms/traversal/bfs.ts +10 -228
- package/src/benchmark-all-algorithms.ts +548 -0
- package/src/clustering/hierarchical.ts +241 -251
- package/src/clustering/index.ts +4 -2
- package/src/clustering/k-core.ts +87 -39
- package/src/clustering/spectral.ts +185 -34
- package/src/core/graph.ts +4 -4
- package/src/flow/ford-fulkerson.ts +186 -254
- package/src/flow/min-cut.ts +21 -11
- package/src/index.ts +9 -0
- package/src/link-prediction/adamic-adar.ts +17 -30
- package/src/link-prediction/common-neighbors.ts +7 -16
- package/src/optimized/bit-packed.ts +340 -0
- package/src/optimized/csr-graph.ts +455 -0
- package/src/optimized/direction-optimized-bfs.ts +291 -0
- package/src/optimized/graph-adapter.ts +200 -0
- package/src/optimized/index.ts +36 -0
- package/src/research/grsbm.ts +580 -0
- package/src/research/index.ts +17 -0
- package/src/research/sync.ts +440 -0
- package/src/research/terahac.ts +514 -0
- package/src/types/index.ts +8 -0
- package/src/utils/algorithm-utilities.ts +2 -0
- package/src/utils/graph-converters.ts +241 -0
- package/src/utils/graph-utilities.ts +199 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/math-utilities.ts +140 -0
- package/src/utils/matrix-utilities.ts +2 -0
- package/src/utils/optimization-helpers.ts +81 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { PriorityQueue } from "../../data-structures/priority-queue.js";
|
|
2
|
+
/**
|
|
3
|
+
* Bidirectional Dijkstra's algorithm implementation
|
|
4
|
+
*
|
|
5
|
+
* Performs simultaneous forward and backward searches to find shortest paths
|
|
6
|
+
* more efficiently than standard Dijkstra for point-to-point queries.
|
|
7
|
+
*
|
|
8
|
+
* Time Complexity: O(2 * sqrt(V + E) log V) expected for random graphs
|
|
9
|
+
* Space Complexity: O(V)
|
|
10
|
+
*
|
|
11
|
+
* Key optimizations:
|
|
12
|
+
* - Alternating expansion based on frontier size
|
|
13
|
+
* - Early termination when searches meet
|
|
14
|
+
* - Efficient meeting point detection
|
|
15
|
+
*/
|
|
16
|
+
export class BidirectionalDijkstra {
|
|
17
|
+
constructor(graph) {
|
|
18
|
+
this.meetingNode = null;
|
|
19
|
+
this.shortestDistance = Infinity;
|
|
20
|
+
this.graph = graph;
|
|
21
|
+
this.forwardSearch = this.initSearchState();
|
|
22
|
+
this.backwardSearch = this.initSearchState();
|
|
23
|
+
}
|
|
24
|
+
initSearchState() {
|
|
25
|
+
return {
|
|
26
|
+
distances: new Map(),
|
|
27
|
+
previous: new Map(),
|
|
28
|
+
visited: new Set(),
|
|
29
|
+
frontier: new PriorityQueue(),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Find shortest path between source and target nodes
|
|
34
|
+
*/
|
|
35
|
+
findShortestPath(source, target) {
|
|
36
|
+
// Reset state for new search
|
|
37
|
+
this.reset();
|
|
38
|
+
if (!this.graph.hasNode(source)) {
|
|
39
|
+
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
40
|
+
}
|
|
41
|
+
if (!this.graph.hasNode(target)) {
|
|
42
|
+
throw new Error(`Target node ${String(target)} not found in graph`);
|
|
43
|
+
}
|
|
44
|
+
// Special case: source equals target
|
|
45
|
+
if (source === target) {
|
|
46
|
+
return {
|
|
47
|
+
distance: 0,
|
|
48
|
+
path: [source],
|
|
49
|
+
predecessor: new Map([[source, null]]),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// Initialize forward search from source
|
|
53
|
+
this.forwardSearch.distances.set(source, 0);
|
|
54
|
+
this.forwardSearch.previous.set(source, null);
|
|
55
|
+
this.forwardSearch.frontier.enqueue(source, 0);
|
|
56
|
+
// Initialize backward search from target
|
|
57
|
+
this.backwardSearch.distances.set(target, 0);
|
|
58
|
+
this.backwardSearch.previous.set(target, null);
|
|
59
|
+
this.backwardSearch.frontier.enqueue(target, 0);
|
|
60
|
+
// Main search loop
|
|
61
|
+
while (!this.forwardSearch.frontier.isEmpty() ||
|
|
62
|
+
!this.backwardSearch.frontier.isEmpty()) {
|
|
63
|
+
// Alternate between forward and backward search
|
|
64
|
+
// Choose the search with smaller frontier for better performance
|
|
65
|
+
let searchExpanded = false;
|
|
66
|
+
if (!this.forwardSearch.frontier.isEmpty() &&
|
|
67
|
+
(this.backwardSearch.frontier.isEmpty() ||
|
|
68
|
+
this.forwardSearch.frontier.size() <= this.backwardSearch.frontier.size())) {
|
|
69
|
+
if (this.expandSearch(this.forwardSearch, this.backwardSearch, true)) {
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
searchExpanded = true;
|
|
73
|
+
}
|
|
74
|
+
if (!this.backwardSearch.frontier.isEmpty() && !searchExpanded) {
|
|
75
|
+
if (this.expandSearch(this.backwardSearch, this.forwardSearch, false)) {
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Continue until both frontiers are empty or we've found an optimal path
|
|
80
|
+
if (this.forwardSearch.frontier.isEmpty() &&
|
|
81
|
+
this.backwardSearch.frontier.isEmpty()) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (this.meetingNode === null) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
distance: this.shortestDistance,
|
|
90
|
+
path: this.reconstructPath(),
|
|
91
|
+
predecessor: new Map(), // Combined from both searches
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
expandSearch(search, oppositeSearch, isForward) {
|
|
95
|
+
const current = search.frontier.dequeue();
|
|
96
|
+
if (current === undefined) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
const distance = search.distances.get(current);
|
|
100
|
+
if (distance === undefined) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
if (search.visited.has(current)) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
search.visited.add(current);
|
|
107
|
+
// Check if we've met the opposite search
|
|
108
|
+
if (oppositeSearch.distances.has(current)) {
|
|
109
|
+
const totalDistance = distance + (oppositeSearch.distances.get(current) ?? 0);
|
|
110
|
+
if (totalDistance < this.shortestDistance) {
|
|
111
|
+
this.shortestDistance = totalDistance;
|
|
112
|
+
this.meetingNode = current;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Explore neighbors
|
|
116
|
+
const neighbors = isForward ?
|
|
117
|
+
Array.from(this.graph.neighbors(current)) :
|
|
118
|
+
Array.from(this.graph.inNeighbors(current));
|
|
119
|
+
for (const neighbor of neighbors) {
|
|
120
|
+
if (search.visited.has(neighbor)) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const edge = isForward ?
|
|
124
|
+
this.graph.getEdge(current, neighbor) :
|
|
125
|
+
this.graph.getEdge(neighbor, current);
|
|
126
|
+
if (!edge) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const edgeWeight = edge.weight ?? 1;
|
|
130
|
+
if (edgeWeight < 0) {
|
|
131
|
+
throw new Error("Bidirectional Dijkstra does not support negative edge weights");
|
|
132
|
+
}
|
|
133
|
+
const newDistance = distance + edgeWeight;
|
|
134
|
+
const currentNeighborDistance = search.distances.get(neighbor);
|
|
135
|
+
if (!search.distances.has(neighbor) ||
|
|
136
|
+
newDistance < (currentNeighborDistance ?? Infinity)) {
|
|
137
|
+
search.distances.set(neighbor, newDistance);
|
|
138
|
+
search.previous.set(neighbor, current);
|
|
139
|
+
search.frontier.enqueue(neighbor, newDistance);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
getMinDistance(frontier) {
|
|
145
|
+
if (frontier.isEmpty()) {
|
|
146
|
+
return Infinity;
|
|
147
|
+
}
|
|
148
|
+
// Since we can't peek at priority directly, we estimate based on the smallest known distance
|
|
149
|
+
const minDist = Infinity;
|
|
150
|
+
// For a more accurate implementation, we'd need to track the minimum distance
|
|
151
|
+
// For now, we'll use a simple heuristic
|
|
152
|
+
return minDist;
|
|
153
|
+
}
|
|
154
|
+
reconstructPath() {
|
|
155
|
+
if (!this.meetingNode) {
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
const path = [];
|
|
159
|
+
// Reconstruct forward path
|
|
160
|
+
let current = this.meetingNode;
|
|
161
|
+
const forwardPath = [];
|
|
162
|
+
while (current !== null) {
|
|
163
|
+
forwardPath.push(current);
|
|
164
|
+
current = this.forwardSearch.previous.get(current) ?? null;
|
|
165
|
+
}
|
|
166
|
+
// Add forward path in reverse order (except meeting node)
|
|
167
|
+
for (let i = forwardPath.length - 1; i > 0; i--) {
|
|
168
|
+
const node = forwardPath[i];
|
|
169
|
+
if (node !== undefined) {
|
|
170
|
+
path.push(node);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Add meeting node
|
|
174
|
+
path.push(this.meetingNode);
|
|
175
|
+
// Reconstruct and add backward path
|
|
176
|
+
current = this.backwardSearch.previous.get(this.meetingNode) ?? null;
|
|
177
|
+
while (current !== null) {
|
|
178
|
+
path.push(current);
|
|
179
|
+
current = this.backwardSearch.previous.get(current) ?? null;
|
|
180
|
+
}
|
|
181
|
+
return path;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Reset the search state for reuse
|
|
185
|
+
*/
|
|
186
|
+
reset() {
|
|
187
|
+
this.forwardSearch = this.initSearchState();
|
|
188
|
+
this.backwardSearch = this.initSearchState();
|
|
189
|
+
this.meetingNode = null;
|
|
190
|
+
this.shortestDistance = Infinity;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=bidirectional-dijkstra.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bidirectional-dijkstra.js","sourceRoot":"","sources":["../../../../src/algorithms/shortest-path/bidirectional-dijkstra.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,9 +11,12 @@ import type { DijkstraOptions, NodeId, ShortestPathResult } from "../../types/in
|
|
|
11
11
|
*/
|
|
12
12
|
export declare function dijkstra(graph: Graph, source: NodeId, options?: DijkstraOptions): Map<NodeId, ShortestPathResult>;
|
|
13
13
|
/**
|
|
14
|
-
* Find shortest path between two specific nodes using Dijkstra's algorithm
|
|
14
|
+
* Find shortest path between two specific nodes using optimized Dijkstra's algorithm
|
|
15
|
+
*
|
|
16
|
+
* Uses bidirectional search by default for improved performance on point-to-point queries.
|
|
17
|
+
* Automatically falls back to standard Dijkstra for very small graphs or when explicitly disabled.
|
|
15
18
|
*/
|
|
16
|
-
export declare function dijkstraPath(graph: Graph, source: NodeId, target: NodeId): ShortestPathResult | null;
|
|
19
|
+
export declare function dijkstraPath(graph: Graph, source: NodeId, target: NodeId, options?: DijkstraOptions): ShortestPathResult | null;
|
|
17
20
|
/**
|
|
18
21
|
* Single-source shortest paths with early termination optimization
|
|
19
22
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dijkstra.d.ts","sourceRoot":"","sources":["../../../../src/algorithms/shortest-path/dijkstra.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAE/C,OAAO,KAAK,EAAC,eAAe,EAAE,MAAM,EAAE,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"dijkstra.d.ts","sourceRoot":"","sources":["../../../../src/algorithms/shortest-path/dijkstra.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAE/C,OAAO,KAAK,EAAC,eAAe,EAAE,MAAM,EAAE,kBAAkB,EAAC,MAAM,sBAAsB,CAAC;AAItF;;;;;GAKG;AAEH;;GAEG;AACH,wBAAgB,QAAQ,CACpB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,eAAoB,GAC9B,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CA8FjC;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CACxB,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,eAAoB,GAC9B,kBAAkB,GAAG,IAAI,CA8B3B;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACpC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,GAChB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA2ErB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,KAAK,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CASnF"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { PriorityQueue } from "../../data-structures/priority-queue.js";
|
|
2
|
+
import { reconstructPath } from "../../utils/graph-utilities.js";
|
|
3
|
+
import { BidirectionalDijkstra } from "./bidirectional-dijkstra.js";
|
|
2
4
|
/**
|
|
3
5
|
* Dijkstra's algorithm implementation for single-source shortest paths
|
|
4
6
|
*
|
|
@@ -87,9 +89,12 @@ export function dijkstra(graph, source, options = {}) {
|
|
|
87
89
|
return results;
|
|
88
90
|
}
|
|
89
91
|
/**
|
|
90
|
-
* Find shortest path between two specific nodes using Dijkstra's algorithm
|
|
92
|
+
* Find shortest path between two specific nodes using optimized Dijkstra's algorithm
|
|
93
|
+
*
|
|
94
|
+
* Uses bidirectional search by default for improved performance on point-to-point queries.
|
|
95
|
+
* Automatically falls back to standard Dijkstra for very small graphs or when explicitly disabled.
|
|
91
96
|
*/
|
|
92
|
-
export function dijkstraPath(graph, source, target) {
|
|
97
|
+
export function dijkstraPath(graph, source, target, options = {}) {
|
|
93
98
|
if (!graph.hasNode(source)) {
|
|
94
99
|
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
95
100
|
}
|
|
@@ -104,6 +109,14 @@ export function dijkstraPath(graph, source, target) {
|
|
|
104
109
|
predecessor: new Map([[source, null]]),
|
|
105
110
|
};
|
|
106
111
|
}
|
|
112
|
+
// Use bidirectional search by default for point-to-point queries
|
|
113
|
+
// Only disable if explicitly requested or graph is very small (overhead dominates)
|
|
114
|
+
const useBidirectional = options.bidirectional !== false && graph.nodeCount > 10;
|
|
115
|
+
if (useBidirectional) {
|
|
116
|
+
const biDijkstra = new BidirectionalDijkstra(graph);
|
|
117
|
+
return biDijkstra.findShortestPath(source, target);
|
|
118
|
+
}
|
|
119
|
+
// Fallback to standard dijkstra
|
|
107
120
|
const results = dijkstra(graph, source, { target });
|
|
108
121
|
return results.get(target) ?? null;
|
|
109
122
|
}
|
|
@@ -184,16 +197,4 @@ export function allPairsShortestPath(graph) {
|
|
|
184
197
|
}
|
|
185
198
|
return results;
|
|
186
199
|
}
|
|
187
|
-
/**
|
|
188
|
-
* Reconstruct path from predecessor map
|
|
189
|
-
*/
|
|
190
|
-
function reconstructPath(target, previous) {
|
|
191
|
-
const path = [];
|
|
192
|
-
let current = target;
|
|
193
|
-
while (current !== null) {
|
|
194
|
-
path.unshift(current);
|
|
195
|
-
current = previous.get(current) ?? null;
|
|
196
|
-
}
|
|
197
|
-
return path;
|
|
198
|
-
}
|
|
199
200
|
//# sourceMappingURL=dijkstra.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dijkstra.js","sourceRoot":"","sources":["../../../../src/algorithms/shortest-path/dijkstra.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,aAAa,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"dijkstra.js","sourceRoot":"","sources":["../../../../src/algorithms/shortest-path/dijkstra.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Graph } from "../../core/graph.js";
|
|
2
|
+
import type { NodeId, ShortestPathResult, TraversalOptions, TraversalResult } from "../../types/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Perform breadth-first search starting from a given node
|
|
5
|
+
*
|
|
6
|
+
* Automatically uses the most optimized implementation based on graph size.
|
|
7
|
+
* No configuration needed - just call this function for the best performance.
|
|
8
|
+
*/
|
|
9
|
+
export declare function breadthFirstSearch(graph: Graph, startNode: NodeId, options?: TraversalOptions): TraversalResult;
|
|
10
|
+
/**
|
|
11
|
+
* Find shortest path between two nodes using BFS
|
|
12
|
+
*
|
|
13
|
+
* Automatically optimized for large graphs. Returns null if no path exists.
|
|
14
|
+
*/
|
|
15
|
+
export declare function shortestPathBFS(graph: Graph, source: NodeId, target: NodeId): ShortestPathResult | null;
|
|
16
|
+
/**
|
|
17
|
+
* Find shortest paths from source to all reachable nodes
|
|
18
|
+
*
|
|
19
|
+
* Automatically optimized for large graphs.
|
|
20
|
+
*/
|
|
21
|
+
export declare function singleSourceShortestPathBFS(graph: Graph, source: NodeId): Map<NodeId, ShortestPathResult>;
|
|
22
|
+
/**
|
|
23
|
+
* Check if the graph is bipartite using BFS coloring
|
|
24
|
+
*
|
|
25
|
+
* Note: This function does not use Direction-Optimized BFS as the
|
|
26
|
+
* coloring logic is specific and doesn't benefit from the optimization.
|
|
27
|
+
*/
|
|
28
|
+
export declare function isBipartite(graph: Graph): boolean;
|
|
29
|
+
//# sourceMappingURL=bfs-unified.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bfs-unified.d.ts","sourceRoot":"","sources":["../../../../src/algorithms/traversal/bfs-unified.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,qBAAqB,CAAC;AAI/C,OAAO,KAAK,EAAC,MAAM,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAC,MAAM,sBAAsB,CAAC;AA6BxG;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,KAAK,EACZ,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,gBAAqB,GAC/B,eAAe,CAYjB;AA2GD;;;;GAIG;AACH,wBAAgB,eAAe,CAC3B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACf,kBAAkB,GAAG,IAAI,CAyB3B;AAmFD;;;;GAIG;AACH,wBAAgB,2BAA2B,CACvC,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,GACf,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAYjC;AAqFD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CA0CjD"}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { DirectionOptimizedBFS } from "../../optimized/direction-optimized-bfs.js";
|
|
2
|
+
import { toCSRGraph } from "../../optimized/graph-adapter.js";
|
|
3
|
+
import { reconstructPath } from "../../utils/graph-utilities.js";
|
|
4
|
+
/**
|
|
5
|
+
* Unified BFS implementation that automatically optimizes for large graphs
|
|
6
|
+
*
|
|
7
|
+
* This module provides a single, user-friendly BFS implementation that:
|
|
8
|
+
* - Automatically uses Direction-Optimized BFS for large graphs (>10k nodes)
|
|
9
|
+
* - Maintains backward compatibility with existing APIs
|
|
10
|
+
* - Requires no configuration or understanding of optimization thresholds
|
|
11
|
+
* - Provides the best performance by default
|
|
12
|
+
*/
|
|
13
|
+
// Cache for CSR conversions to avoid repeated conversions
|
|
14
|
+
const csrCache = new WeakMap();
|
|
15
|
+
/**
|
|
16
|
+
* Get or create CSR representation of a graph
|
|
17
|
+
*/
|
|
18
|
+
function getCSRGraph(graph) {
|
|
19
|
+
let csrGraph = csrCache.get(graph);
|
|
20
|
+
if (!csrGraph) {
|
|
21
|
+
csrGraph = toCSRGraph(graph);
|
|
22
|
+
csrCache.set(graph, csrGraph);
|
|
23
|
+
}
|
|
24
|
+
return csrGraph;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Perform breadth-first search starting from a given node
|
|
28
|
+
*
|
|
29
|
+
* Automatically uses the most optimized implementation based on graph size.
|
|
30
|
+
* No configuration needed - just call this function for the best performance.
|
|
31
|
+
*/
|
|
32
|
+
export function breadthFirstSearch(graph, startNode, options = {}) {
|
|
33
|
+
if (!graph.hasNode(startNode)) {
|
|
34
|
+
throw new Error(`Start node ${String(startNode)} not found in graph`);
|
|
35
|
+
}
|
|
36
|
+
// Automatically use optimized implementation for large graphs
|
|
37
|
+
if (graph.nodeCount > 10000) {
|
|
38
|
+
return breadthFirstSearchOptimized(graph, startNode, options);
|
|
39
|
+
}
|
|
40
|
+
// Standard implementation for smaller graphs
|
|
41
|
+
return breadthFirstSearchStandard(graph, startNode, options);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Standard BFS implementation for smaller graphs
|
|
45
|
+
*/
|
|
46
|
+
function breadthFirstSearchStandard(graph, startNode, options = {}) {
|
|
47
|
+
const visited = new Set();
|
|
48
|
+
const queue = [];
|
|
49
|
+
const order = [];
|
|
50
|
+
const tree = new Map();
|
|
51
|
+
// Initialize with start node
|
|
52
|
+
queue.push({ node: startNode, level: 0 });
|
|
53
|
+
visited.add(startNode);
|
|
54
|
+
tree.set(startNode, null);
|
|
55
|
+
while (queue.length > 0) {
|
|
56
|
+
const current = queue.shift();
|
|
57
|
+
if (!current) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
order.push(current.node);
|
|
61
|
+
// Call visitor callback if provided
|
|
62
|
+
if (options.visitCallback) {
|
|
63
|
+
options.visitCallback(current.node, current.level);
|
|
64
|
+
}
|
|
65
|
+
// Early termination if target found
|
|
66
|
+
if (options.targetNode && current.node === options.targetNode) {
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
// Explore neighbors
|
|
70
|
+
for (const neighbor of graph.neighbors(current.node)) {
|
|
71
|
+
if (!visited.has(neighbor)) {
|
|
72
|
+
visited.add(neighbor);
|
|
73
|
+
tree.set(neighbor, current.node);
|
|
74
|
+
queue.push({ node: neighbor, level: current.level + 1 });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return { visited, order, tree };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Optimized BFS implementation using Direction-Optimized BFS
|
|
82
|
+
*/
|
|
83
|
+
function breadthFirstSearchOptimized(graph, startNode, options = {}) {
|
|
84
|
+
const csrGraph = getCSRGraph(graph);
|
|
85
|
+
const dobfs = new DirectionOptimizedBFS(csrGraph, {
|
|
86
|
+
alpha: 15.0,
|
|
87
|
+
beta: 20.0,
|
|
88
|
+
});
|
|
89
|
+
const result = dobfs.search(startNode);
|
|
90
|
+
// Convert result to TraversalResult format
|
|
91
|
+
const visited = new Set();
|
|
92
|
+
const order = [];
|
|
93
|
+
const tree = new Map();
|
|
94
|
+
// Build traversal order using BFS from distances
|
|
95
|
+
const nodesByDistance = new Map();
|
|
96
|
+
let maxDistance = 0;
|
|
97
|
+
for (const [nodeId, distance] of result.distances) {
|
|
98
|
+
visited.add(nodeId);
|
|
99
|
+
tree.set(nodeId, result.parents.get(nodeId) ?? null);
|
|
100
|
+
if (!nodesByDistance.has(distance)) {
|
|
101
|
+
nodesByDistance.set(distance, []);
|
|
102
|
+
}
|
|
103
|
+
nodesByDistance.get(distance)?.push(nodeId);
|
|
104
|
+
maxDistance = Math.max(maxDistance, distance);
|
|
105
|
+
}
|
|
106
|
+
// Reconstruct BFS order
|
|
107
|
+
for (let d = 0; d <= maxDistance; d++) {
|
|
108
|
+
const nodes = nodesByDistance.get(d);
|
|
109
|
+
if (nodes) {
|
|
110
|
+
order.push(...nodes);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Handle visit callback if provided
|
|
114
|
+
if (options.visitCallback) {
|
|
115
|
+
for (const [nodeId, distance] of result.distances) {
|
|
116
|
+
options.visitCallback(nodeId, distance);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return { visited, order, tree };
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Find shortest path between two nodes using BFS
|
|
123
|
+
*
|
|
124
|
+
* Automatically optimized for large graphs. Returns null if no path exists.
|
|
125
|
+
*/
|
|
126
|
+
export function shortestPathBFS(graph, source, target) {
|
|
127
|
+
if (!graph.hasNode(source)) {
|
|
128
|
+
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
129
|
+
}
|
|
130
|
+
if (!graph.hasNode(target)) {
|
|
131
|
+
throw new Error(`Target node ${String(target)} not found in graph`);
|
|
132
|
+
}
|
|
133
|
+
// Special case: source equals target
|
|
134
|
+
if (source === target) {
|
|
135
|
+
return {
|
|
136
|
+
distance: 0,
|
|
137
|
+
path: [source],
|
|
138
|
+
predecessor: new Map([[source, null]]),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
// Use optimized implementation for large graphs
|
|
142
|
+
if (graph.nodeCount > 10000) {
|
|
143
|
+
return shortestPathBFSOptimized(graph, source, target);
|
|
144
|
+
}
|
|
145
|
+
// Standard implementation
|
|
146
|
+
return shortestPathBFSStandard(graph, source, target);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Standard shortest path BFS
|
|
150
|
+
*/
|
|
151
|
+
function shortestPathBFSStandard(graph, source, target) {
|
|
152
|
+
const visited = new Set();
|
|
153
|
+
const queue = [];
|
|
154
|
+
const predecessor = new Map();
|
|
155
|
+
// Initialize BFS
|
|
156
|
+
queue.push({ node: source, distance: 0 });
|
|
157
|
+
visited.add(source);
|
|
158
|
+
predecessor.set(source, null);
|
|
159
|
+
while (queue.length > 0) {
|
|
160
|
+
const current = queue.shift();
|
|
161
|
+
if (!current) {
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
// Target found
|
|
165
|
+
if (current.node === target) {
|
|
166
|
+
const path = reconstructPath(target, predecessor);
|
|
167
|
+
return {
|
|
168
|
+
distance: current.distance,
|
|
169
|
+
path,
|
|
170
|
+
predecessor,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// Explore neighbors
|
|
174
|
+
for (const neighbor of graph.neighbors(current.node)) {
|
|
175
|
+
if (!visited.has(neighbor)) {
|
|
176
|
+
visited.add(neighbor);
|
|
177
|
+
predecessor.set(neighbor, current.node);
|
|
178
|
+
queue.push({ node: neighbor, distance: current.distance + 1 });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// No path found
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Optimized shortest path using Direction-Optimized BFS
|
|
187
|
+
*/
|
|
188
|
+
function shortestPathBFSOptimized(graph, source, target) {
|
|
189
|
+
const csrGraph = getCSRGraph(graph);
|
|
190
|
+
const dobfs = new DirectionOptimizedBFS(csrGraph, {
|
|
191
|
+
alpha: 15.0,
|
|
192
|
+
beta: 20.0,
|
|
193
|
+
});
|
|
194
|
+
// Perform BFS
|
|
195
|
+
const result = dobfs.search(source);
|
|
196
|
+
// Check if target was reached
|
|
197
|
+
const distance = result.distances.get(target);
|
|
198
|
+
if (distance === undefined) {
|
|
199
|
+
return null; // No path found
|
|
200
|
+
}
|
|
201
|
+
// Reconstruct path
|
|
202
|
+
const path = reconstructPath(target, result.parents);
|
|
203
|
+
return {
|
|
204
|
+
distance,
|
|
205
|
+
path,
|
|
206
|
+
predecessor: result.parents,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Find shortest paths from source to all reachable nodes
|
|
211
|
+
*
|
|
212
|
+
* Automatically optimized for large graphs.
|
|
213
|
+
*/
|
|
214
|
+
export function singleSourceShortestPathBFS(graph, source) {
|
|
215
|
+
if (!graph.hasNode(source)) {
|
|
216
|
+
throw new Error(`Source node ${String(source)} not found in graph`);
|
|
217
|
+
}
|
|
218
|
+
// Use optimized implementation for large graphs
|
|
219
|
+
if (graph.nodeCount > 10000) {
|
|
220
|
+
return singleSourceShortestPathBFSOptimized(graph, source);
|
|
221
|
+
}
|
|
222
|
+
// Standard implementation
|
|
223
|
+
return singleSourceShortestPathBFSStandard(graph, source);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Standard single-source shortest paths
|
|
227
|
+
*/
|
|
228
|
+
function singleSourceShortestPathBFSStandard(graph, source) {
|
|
229
|
+
const results = new Map();
|
|
230
|
+
const visited = new Set();
|
|
231
|
+
const queue = [];
|
|
232
|
+
const predecessor = new Map();
|
|
233
|
+
const distances = new Map();
|
|
234
|
+
// Initialize BFS
|
|
235
|
+
queue.push({ node: source, distance: 0 });
|
|
236
|
+
visited.add(source);
|
|
237
|
+
predecessor.set(source, null);
|
|
238
|
+
distances.set(source, 0);
|
|
239
|
+
while (queue.length > 0) {
|
|
240
|
+
const current = queue.shift();
|
|
241
|
+
if (!current) {
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
// Explore neighbors
|
|
245
|
+
for (const neighbor of graph.neighbors(current.node)) {
|
|
246
|
+
if (!visited.has(neighbor)) {
|
|
247
|
+
visited.add(neighbor);
|
|
248
|
+
predecessor.set(neighbor, current.node);
|
|
249
|
+
distances.set(neighbor, current.distance + 1);
|
|
250
|
+
queue.push({ node: neighbor, distance: current.distance + 1 });
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Build results after BFS completes
|
|
255
|
+
// This avoids copying the predecessor map for each node
|
|
256
|
+
for (const [node, distance] of distances) {
|
|
257
|
+
const path = reconstructPath(node, predecessor);
|
|
258
|
+
results.set(node, {
|
|
259
|
+
distance,
|
|
260
|
+
path,
|
|
261
|
+
predecessor, // Share the same predecessor map
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
return results;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Optimized single-source shortest paths
|
|
268
|
+
*/
|
|
269
|
+
function singleSourceShortestPathBFSOptimized(graph, source) {
|
|
270
|
+
const csrGraph = getCSRGraph(graph);
|
|
271
|
+
const dobfs = new DirectionOptimizedBFS(csrGraph, {
|
|
272
|
+
alpha: 15.0,
|
|
273
|
+
beta: 20.0,
|
|
274
|
+
});
|
|
275
|
+
const bfsResult = dobfs.search(source);
|
|
276
|
+
// Convert to expected format
|
|
277
|
+
const results = new Map();
|
|
278
|
+
for (const [nodeId, distance] of bfsResult.distances) {
|
|
279
|
+
// Reconstruct path for each node
|
|
280
|
+
const path = reconstructPath(nodeId, bfsResult.parents);
|
|
281
|
+
results.set(nodeId, {
|
|
282
|
+
distance,
|
|
283
|
+
path,
|
|
284
|
+
predecessor: bfsResult.parents, // Share the same predecessor map
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
return results;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Check if the graph is bipartite using BFS coloring
|
|
291
|
+
*
|
|
292
|
+
* Note: This function does not use Direction-Optimized BFS as the
|
|
293
|
+
* coloring logic is specific and doesn't benefit from the optimization.
|
|
294
|
+
*/
|
|
295
|
+
export function isBipartite(graph) {
|
|
296
|
+
if (graph.isDirected) {
|
|
297
|
+
throw new Error("Bipartite test requires an undirected graph");
|
|
298
|
+
}
|
|
299
|
+
const color = new Map();
|
|
300
|
+
const visited = new Set();
|
|
301
|
+
// Check each connected component
|
|
302
|
+
for (const node of Array.from(graph.nodes())) {
|
|
303
|
+
if (!visited.has(node.id)) {
|
|
304
|
+
const queue = [node.id];
|
|
305
|
+
color.set(node.id, 0);
|
|
306
|
+
visited.add(node.id);
|
|
307
|
+
while (queue.length > 0) {
|
|
308
|
+
const current = queue.shift();
|
|
309
|
+
if (!current) {
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
const currentColor = color.get(current);
|
|
313
|
+
if (currentColor === undefined) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
for (const neighbor of Array.from(graph.neighbors(current))) {
|
|
317
|
+
if (!visited.has(neighbor)) {
|
|
318
|
+
// Color with opposite color
|
|
319
|
+
color.set(neighbor, currentColor === 0 ? 1 : 0);
|
|
320
|
+
visited.add(neighbor);
|
|
321
|
+
queue.push(neighbor);
|
|
322
|
+
}
|
|
323
|
+
else if (color.get(neighbor) === currentColor) {
|
|
324
|
+
// Same color as current node - not bipartite
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=bfs-unified.js.map
|