1use std::collections::HashSet;
32
33use crate::error::{GraphalgError, GraphalgResult};
34use crate::repr::weighted_graph::WeightedGraph;
35
36#[derive(Debug, Clone)]
38pub struct DeltaSteppingOutput {
39 pub dist: Vec<f64>,
41 pub parent: Vec<usize>,
44}
45
46pub fn delta_stepping(
53 g: &WeightedGraph,
54 source: usize,
55 delta: f64,
56) -> GraphalgResult<DeltaSteppingOutput> {
57 if source >= g.n {
58 return Err(GraphalgError::SourceOutOfRange {
59 node: source,
60 n: g.n,
61 });
62 }
63 if !(delta.is_finite() && delta > 0.0) {
64 return Err(GraphalgError::InvalidParameter(format!(
65 "delta must be finite and > 0, got {delta}"
66 )));
67 }
68 for (u, adj) in g.edges.iter().enumerate() {
70 for &(v, w) in adj {
71 if w < 0.0 {
72 return Err(GraphalgError::NegativeWeight {
73 edge: (u, v),
74 weight: w,
75 });
76 }
77 }
78 }
79
80 let n = g.n;
81 let mut tent = vec![f64::INFINITY; n];
82 let mut parent = vec![usize::MAX; n];
83 let mut bucket_of = vec![usize::MAX; n];
85 let mut buckets: Vec<HashSet<usize>> = Vec::new();
87
88 fn relax(
91 v: usize,
92 x: f64,
93 p: usize,
94 delta: f64,
95 tent: &mut [f64],
96 parent: &mut [usize],
97 bucket_of: &mut [usize],
98 buckets: &mut Vec<HashSet<usize>>,
99 ) {
100 if x < tent[v] {
101 let old = bucket_of[v];
103 if old != usize::MAX {
104 if let Some(b) = buckets.get_mut(old) {
105 b.remove(&v);
106 }
107 }
108 let new_idx = (x / delta).floor() as usize;
109 if new_idx >= buckets.len() {
110 buckets.resize(new_idx + 1, HashSet::new());
111 }
112 buckets[new_idx].insert(v);
113 bucket_of[v] = new_idx;
114 tent[v] = x;
115 parent[v] = p;
116 }
117 }
118
119 relax(
122 source,
123 0.0,
124 source,
125 delta,
126 &mut tent,
127 &mut parent,
128 &mut bucket_of,
129 &mut buckets,
130 );
131
132 let mut i = 0usize;
133 while i < buckets.len() {
134 if buckets[i].is_empty() {
136 i += 1;
137 continue;
138 }
139
140 let mut settled: Vec<usize> = Vec::new();
143
144 while !buckets[i].is_empty() {
146 let current: Vec<usize> = buckets[i].drain().collect();
148 for &u in ¤t {
149 bucket_of[u] = usize::MAX;
151 settled.push(u);
152 }
153 for &u in ¤t {
155 let du = tent[u];
156 for &(v, w) in g.neighbors(u)? {
157 if w <= delta {
158 relax(
159 v,
160 du + w,
161 u,
162 delta,
163 &mut tent,
164 &mut parent,
165 &mut bucket_of,
166 &mut buckets,
167 );
168 }
169 }
170 }
171 }
172
173 for &u in &settled {
175 let du = tent[u];
176 for &(v, w) in g.neighbors(u)? {
177 if w > delta {
178 relax(
179 v,
180 du + w,
181 u,
182 delta,
183 &mut tent,
184 &mut parent,
185 &mut bucket_of,
186 &mut buckets,
187 );
188 }
189 }
190 }
191 if buckets[i].is_empty() {
195 i += 1;
196 }
197 }
198
199 Ok(DeltaSteppingOutput { dist: tent, parent })
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205 use crate::shortest_path::dijkstra::dijkstra;
206
207 #[test]
208 fn simple_chain() {
209 let mut g = WeightedGraph::new(4);
211 g.add_edge(0, 1, 1.0).expect("ok");
212 g.add_edge(1, 2, 1.0).expect("ok");
213 g.add_edge(2, 3, 1.0).expect("ok");
214 let out = delta_stepping(&g, 0, 1.0).expect("ok");
215 assert!((out.dist[3] - 3.0).abs() < 1e-12);
216 }
217
218 #[test]
219 fn matches_dijkstra_small() {
220 let mut g = WeightedGraph::new(4);
222 g.add_edge(0, 1, 1.0).expect("ok");
223 g.add_edge(0, 2, 4.0).expect("ok");
224 g.add_edge(1, 2, 2.0).expect("ok");
225 g.add_edge(1, 3, 5.0).expect("ok");
226 g.add_edge(2, 3, 1.0).expect("ok");
227 let dj = dijkstra(&g, 0).expect("ok");
228 for &delta in &[0.5_f64, 1.0, 2.0, 10.0] {
229 let ds = delta_stepping(&g, 0, delta).expect("ok");
230 for v in 0..g.n {
231 assert!(
232 (ds.dist[v] - dj.dist[v]).abs() < 1e-9,
233 "delta={delta} v={v}: {} vs {}",
234 ds.dist[v],
235 dj.dist[v]
236 );
237 }
238 }
239 }
240
241 #[test]
242 fn matches_dijkstra_undirected_grid() {
243 let mut g = WeightedGraph::new(6);
245 g.add_undirected_edge(0, 1, 0.3).expect("ok");
246 g.add_undirected_edge(1, 2, 2.5).expect("ok");
247 g.add_undirected_edge(0, 3, 1.0).expect("ok");
248 g.add_undirected_edge(3, 4, 0.7).expect("ok");
249 g.add_undirected_edge(4, 5, 3.2).expect("ok");
250 g.add_undirected_edge(2, 5, 0.4).expect("ok");
251 g.add_undirected_edge(1, 4, 1.1).expect("ok");
252 let dj = dijkstra(&g, 0).expect("ok");
253 let ds = delta_stepping(&g, 0, 1.0).expect("ok");
254 for v in 0..g.n {
255 assert!(
256 (ds.dist[v] - dj.dist[v]).abs() < 1e-9,
257 "v={v}: {} vs {}",
258 ds.dist[v],
259 dj.dist[v]
260 );
261 }
262 }
263
264 #[test]
265 fn source_distance_zero() {
266 let mut g = WeightedGraph::new(3);
267 g.add_edge(0, 1, 2.0).expect("ok");
268 let out = delta_stepping(&g, 0, 1.0).expect("ok");
269 assert!((out.dist[0] - 0.0).abs() < 1e-12);
270 assert_eq!(out.parent[0], 0);
271 }
272
273 #[test]
274 fn unreachable_is_infinity() {
275 let mut g = WeightedGraph::new(3);
276 g.add_edge(0, 1, 1.0).expect("ok");
277 let out = delta_stepping(&g, 0, 1.0).expect("ok");
279 assert!(out.dist[2].is_infinite());
280 assert_eq!(out.parent[2], usize::MAX);
281 }
282
283 #[test]
284 fn rejects_negative_weight() {
285 let mut g = WeightedGraph::new(2);
286 g.add_edge(0, 1, -1.0).expect("ok");
287 assert!(matches!(
288 delta_stepping(&g, 0, 1.0).unwrap_err(),
289 GraphalgError::NegativeWeight { .. }
290 ));
291 }
292
293 #[test]
294 fn rejects_bad_delta() {
295 let mut g = WeightedGraph::new(2);
296 g.add_edge(0, 1, 1.0).expect("ok");
297 assert!(delta_stepping(&g, 0, 0.0).is_err());
298 assert!(delta_stepping(&g, 0, -1.0).is_err());
299 assert!(delta_stepping(&g, 0, f64::INFINITY).is_err());
300 }
301
302 #[test]
303 fn source_out_of_range() {
304 let g = WeightedGraph::new(3);
305 assert!(matches!(
306 delta_stepping(&g, 5, 1.0).unwrap_err(),
307 GraphalgError::SourceOutOfRange { .. }
308 ));
309 }
310
311 #[test]
312 fn parent_pointers_form_tree() {
313 let mut g = WeightedGraph::new(5);
316 g.add_edge(0, 1, 2.0).expect("ok");
317 g.add_edge(0, 2, 5.0).expect("ok");
318 g.add_edge(1, 2, 1.0).expect("ok");
319 g.add_edge(2, 3, 2.0).expect("ok");
320 g.add_edge(1, 4, 7.0).expect("ok");
321 let out = delta_stepping(&g, 0, 1.5).expect("ok");
322 for v in 0..g.n {
323 if v == 0 || out.dist[v].is_infinite() {
324 continue;
325 }
326 let p = out.parent[v];
327 assert!(p != usize::MAX, "v={v} has no parent");
328 let w = g
330 .neighbors(p)
331 .expect("ok")
332 .iter()
333 .find(|&&(t, _)| t == v)
334 .map(|&(_, w)| w)
335 .expect("parent edge exists");
336 assert!(
337 (out.dist[p] + w - out.dist[v]).abs() < 1e-9,
338 "tree broken at v={v}"
339 );
340 }
341 }
342
343 #[test]
344 fn large_delta_acts_like_bellman_ford() {
345 let mut g = WeightedGraph::new(4);
348 g.add_edge(0, 1, 1.0).expect("ok");
349 g.add_edge(1, 2, 1.0).expect("ok");
350 g.add_edge(0, 2, 5.0).expect("ok");
351 g.add_edge(2, 3, 1.0).expect("ok");
352 let dj = dijkstra(&g, 0).expect("ok");
353 let ds = delta_stepping(&g, 0, 1000.0).expect("ok");
354 for v in 0..g.n {
355 assert!((ds.dist[v] - dj.dist[v]).abs() < 1e-9, "v={v}");
356 }
357 }
358
359 #[test]
360 fn small_delta_acts_like_dijkstra() {
361 let mut g = WeightedGraph::new(4);
363 g.add_edge(0, 1, 1.0).expect("ok");
364 g.add_edge(0, 2, 4.0).expect("ok");
365 g.add_edge(1, 2, 2.0).expect("ok");
366 g.add_edge(2, 3, 1.0).expect("ok");
367 let dj = dijkstra(&g, 0).expect("ok");
368 let ds = delta_stepping(&g, 0, 0.1).expect("ok");
369 for v in 0..g.n {
370 assert!((ds.dist[v] - dj.dist[v]).abs() < 1e-9, "v={v}");
371 }
372 }
373
374 #[test]
375 fn deterministic() {
376 let mut g = WeightedGraph::new(5);
377 g.add_undirected_edge(0, 1, 1.0).expect("ok");
378 g.add_undirected_edge(1, 2, 2.0).expect("ok");
379 g.add_undirected_edge(2, 3, 1.5).expect("ok");
380 g.add_undirected_edge(3, 4, 0.5).expect("ok");
381 let a = delta_stepping(&g, 0, 1.0).expect("ok");
382 let b = delta_stepping(&g, 0, 1.0).expect("ok");
383 assert_eq!(a.dist, b.dist);
384 }
385}