graaf/algo/dijkstra.rs
1//! Dijkstra's algorithm.
2//!
3//! Dijkstra's algorithm with binary heap finds the shortest path in an
4//! arc-weighted digraph.[^1]
5//!
6//! The time complexity is `O(v log v + a)`, where `v` is the digraph's order
7//! and `a` is the digraph's size.
8//!
9//! # Examples
10//!
11//! ## Single source
12//!
13//! The path from vertex `0` is red. `t` denotes the iteration indices.
14//!
15//! 
16//!
17//! ```
18//! use {
19//! graaf::{
20//! AddArcWeighted,
21//! AdjacencyListWeighted,
22//! Dijkstra,
23//! Empty,
24//! },
25//! std::iter::once,
26//! };
27//!
28//! let mut digraph = AdjacencyListWeighted::<usize>::empty(7);
29//!
30//! digraph.add_arc_weighted(0, 1, 1);
31//! digraph.add_arc_weighted(1, 2, 1);
32//! digraph.add_arc_weighted(1, 6, 6);
33//! digraph.add_arc_weighted(2, 4, 1);
34//! digraph.add_arc_weighted(3, 0, 2);
35//! digraph.add_arc_weighted(4, 5, 2);
36//! digraph.add_arc_weighted(5, 6, 1);
37//!
38//! let mut dijkstra = Dijkstra::new(&digraph, once(0));
39//!
40//! assert!(dijkstra.eq([0, 1, 2, 4, 5, 6]));
41//! ```
42//!
43//! ## Multiple sources
44//!
45//! The path from vertex `0` is red. The path from vertex `3` is blue.
46//!
47//! 
48//!
49//! ```
50//! use graaf::{
51//! AddArcWeighted,
52//! AdjacencyListWeighted,
53//! Dijkstra,
54//! Empty,
55//! };
56//!
57//! let mut digraph = AdjacencyListWeighted::<usize>::empty(7);
58//!
59//! digraph.add_arc_weighted(0, 1, 1);
60//! digraph.add_arc_weighted(1, 2, 1);
61//! digraph.add_arc_weighted(1, 6, 5);
62//! digraph.add_arc_weighted(2, 4, 1);
63//! digraph.add_arc_weighted(3, 0, 2);
64//! digraph.add_arc_weighted(3, 5, 1);
65//! digraph.add_arc_weighted(4, 5, 1);
66//! digraph.add_arc_weighted(5, 6, 3);
67//!
68//! let mut dijkstra = Dijkstra::new(&digraph, [0, 3].into_iter());
69//!
70//! assert!(dijkstra.eq([3, 0, 5, 1, 2, 4, 6]));
71//! ```
72//!
73//! [^1]: Edsger Wybe Dijkstra. 1959. A note on two problems in connexion with
74//! graphs. Numer. Math. 1, 1 (December 1959), 269–271.
75//! <https://doi.org/10.1007/BF01386390>
76
77use {
78 crate::{
79 Order,
80 OutNeighborsWeighted,
81 },
82 core::cmp::Reverse,
83 std::collections::BinaryHeap,
84};
85
86/// Dijkstra's algorithm.
87///
88/// # Examples
89///
90/// ## Single source
91///
92/// The path from vertex `0` is red. `t` denotes the iteration indices.
93///
94/// 
95///
96/// ```
97/// use {
98/// graaf::{
99/// AddArcWeighted,
100/// AdjacencyListWeighted,
101/// Dijkstra,
102/// Empty,
103/// },
104/// std::iter::once,
105/// };
106///
107/// let mut digraph = AdjacencyListWeighted::<usize>::empty(7);
108///
109/// digraph.add_arc_weighted(0, 1, 1);
110/// digraph.add_arc_weighted(1, 2, 1);
111/// digraph.add_arc_weighted(1, 6, 6);
112/// digraph.add_arc_weighted(2, 4, 1);
113/// digraph.add_arc_weighted(3, 0, 2);
114/// digraph.add_arc_weighted(4, 5, 2);
115/// digraph.add_arc_weighted(5, 6, 1);
116///
117/// let mut dijkstra = Dijkstra::new(&digraph, once(0));
118///
119/// assert!(dijkstra.eq([0, 1, 2, 4, 5, 6]));
120/// ```
121///
122/// ## Multiple sources
123///
124/// The path from vertex `0` is red. The path from vertex `3` is blue.
125///
126/// 
127///
128/// ```
129/// use graaf::{
130/// AddArcWeighted,
131/// AdjacencyListWeighted,
132/// Dijkstra,
133/// Empty,
134/// };
135///
136/// let mut digraph = AdjacencyListWeighted::<usize>::empty(7);
137///
138/// digraph.add_arc_weighted(0, 1, 1);
139/// digraph.add_arc_weighted(1, 2, 1);
140/// digraph.add_arc_weighted(1, 6, 5);
141/// digraph.add_arc_weighted(2, 4, 1);
142/// digraph.add_arc_weighted(3, 0, 2);
143/// digraph.add_arc_weighted(3, 5, 1);
144/// digraph.add_arc_weighted(4, 5, 1);
145/// digraph.add_arc_weighted(5, 6, 3);
146///
147/// let mut dijkstra = Dijkstra::new(&digraph, [0, 3].into_iter());
148///
149/// assert!(dijkstra.eq([3, 0, 5, 1, 2, 4, 6]));
150/// ```
151#[derive(Clone, Debug)]
152pub struct Dijkstra<'a, D> {
153 digraph: &'a D,
154 dist: Vec<usize>,
155 heap: BinaryHeap<(Reverse<usize>, usize)>,
156}
157
158impl<'a, D> Dijkstra<'a, D>
159where
160 D: Order,
161{
162 /// Initialize Dijkstra's algorithm.
163 ///
164 /// # Arguments
165 ///
166 /// * `digraph`: The digraph.
167 /// * `sources`: The source vertices.
168 #[must_use]
169 pub fn new<T>(digraph: &'a D, sources: T) -> Self
170 where
171 D: Order,
172 T: Iterator<Item = usize> + Clone,
173 {
174 let order = digraph.order();
175 let mut dist = vec![usize::MAX; order];
176 let mut heap = BinaryHeap::with_capacity(order);
177 let dist_ptr = dist.as_mut_ptr();
178
179 for u in sources {
180 unsafe { *dist_ptr.add(u) = 0 };
181
182 heap.push((Reverse(0), u));
183 }
184
185 Self {
186 digraph,
187 dist,
188 heap,
189 }
190 }
191}
192
193impl<D> Iterator for Dijkstra<'_, D>
194where
195 D: Order + OutNeighborsWeighted<Weight = usize>,
196{
197 type Item = usize;
198
199 fn next(&mut self) -> Option<Self::Item> {
200 let (Reverse(w_prev), u) = self.heap.pop()?;
201 let dist_ptr = self.dist.as_mut_ptr();
202
203 for (v, w) in self.digraph.out_neighbors_weighted(u) {
204 let w_next = w + w_prev;
205 let dist_v = unsafe { dist_ptr.add(v) };
206
207 unsafe {
208 if w_next < *dist_v {
209 *dist_v = w_next;
210
211 self.heap.push((Reverse(w_next), v));
212 }
213 }
214 }
215
216 if unsafe { *dist_ptr.add(u) } == w_prev {
217 return Some(u);
218 }
219
220 None
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use {
227 super::*,
228 crate::repr::adjacency_list_weighted::fixture::{
229 bang_jensen_94_usize,
230 bang_jensen_96_usize,
231 kattis_bryr_1_usize,
232 kattis_bryr_2_usize,
233 kattis_bryr_3_usize,
234 kattis_crosscountry_usize,
235 kattis_shortestpath1_usize,
236 },
237 std::iter::once,
238 };
239
240 #[test]
241 fn iter_bang_jensen_94() {
242 let digraph = bang_jensen_94_usize();
243
244 assert!(Dijkstra::new(&digraph, once(0)).eq([0, 2, 1, 5, 4, 3, 6]));
245 }
246
247 #[test]
248 fn iter_bang_jensen_96() {
249 let digraph = bang_jensen_96_usize();
250
251 assert!(Dijkstra::new(&digraph, once(0)).eq([0, 2, 4, 1, 3, 5]));
252 }
253
254 #[test]
255 fn iter_kattis_bryr_1() {
256 let digraph = kattis_bryr_1_usize();
257
258 assert!(Dijkstra::new(&digraph, once(0)).eq([0, 2, 1]));
259 }
260
261 #[test]
262 fn iter_kattis_bryr_2() {
263 let digraph = kattis_bryr_2_usize();
264
265 assert!(Dijkstra::new(&digraph, once(0)).eq([0, 3, 1, 4, 2, 5]));
266 }
267
268 #[test]
269 fn iter_kattis_bryr_3() {
270 let digraph = kattis_bryr_3_usize();
271
272 assert!(
273 Dijkstra::new(&digraph, once(0))
274 .eq([0, 3, 7, 5, 8, 4, 1, 9, 6, 2])
275 );
276 }
277
278 #[test]
279 fn iter_kattis_crosscountry() {
280 let digraph = kattis_crosscountry_usize();
281
282 assert!(Dijkstra::new(&digraph, once(0)).eq([0, 1, 2, 3]));
283 }
284
285 #[test]
286 fn iter_kattis_shortestpath1() {
287 let digraph = kattis_shortestpath1_usize();
288
289 assert!(Dijkstra::new(&digraph, once(0)).eq([0, 1, 2]));
290 }
291}