1use petgraph::algo::FloatMeasure;
4#[allow(unused_imports)]
5use petgraph::graph::NodeIndex;
6use petgraph::visit::{
7 EdgeRef, IntoEdges, IntoNodeIdentifiers, NodeCount, NodeIndexable, VisitMap, Visitable,
8};
9use std::cmp::Ordering;
10use std::collections::BinaryHeap;
11
12#[derive(Debug, Clone)]
17pub struct DijkstraResult<NodeId, EdgeWeight> {
18 pub distances: Vec<EdgeWeight>,
19 pub predecessors: Vec<Option<NodeId>>,
20}
21
22#[derive(Clone, Debug)]
25struct State<NodeId, Cost> {
26 node: NodeId,
27 cost: Cost,
28}
29
30impl<NodeId: PartialEq, Cost: PartialEq> PartialEq for State<NodeId, Cost> {
31 fn eq(&self, other: &Self) -> bool {
32 self.node == other.node && self.cost == other.cost
33 }
34}
35
36impl<NodeId: PartialEq, Cost: PartialEq> Eq for State<NodeId, Cost> {}
37
38impl<NodeId: PartialEq, Cost: FloatMeasure> Ord for State<NodeId, Cost> {
39 fn cmp(&self, other: &Self) -> Ordering {
40 other
42 .cost
43 .partial_cmp(&self.cost)
44 .unwrap_or(Ordering::Equal)
45 }
46}
47
48impl<NodeId: PartialEq, Cost: FloatMeasure> PartialOrd for State<NodeId, Cost> {
49 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
50 Some(self.cmp(other))
51 }
52}
53
54pub fn dijkstra<G>(
96 g: G,
97 source: G::NodeId,
98) -> Result<DijkstraResult<G::NodeId, G::EdgeWeight>, String>
99where
100 G: NodeCount + IntoNodeIdentifiers + IntoEdges + NodeIndexable + Visitable,
101 G::EdgeWeight: FloatMeasure,
102{
103 let ix = |i| g.to_index(i);
104 let node_count = g.node_count();
105
106 let mut distances = vec![<_>::infinite(); node_count];
107 let mut predecessors = vec![None; node_count];
108 let mut visited = g.visit_map();
109
110 distances[ix(source)] = <_>::zero();
111
112 let mut heap = BinaryHeap::new();
113 heap.push(State {
114 node: source,
115 cost: <_>::zero(),
116 });
117
118 while let Some(State { node, cost }) = heap.pop() {
119 if visited.is_visited(&node) {
120 continue;
121 }
122
123 visited.visit(node);
124
125 for edge in g.edges(node) {
126 let target = edge.target();
127 let weight = *edge.weight();
128
129 if weight < <_>::zero() {
130 return Err("Dijkstra's algorithm requires non-negative edge weights".to_string());
131 }
132
133 let new_cost = cost + weight;
134 if new_cost < distances[ix(target)] {
135 distances[ix(target)] = new_cost;
136 predecessors[ix(target)] = Some(node);
137 heap.push(State {
138 node: target,
139 cost: new_cost,
140 });
141 }
142 }
143 }
144
145 Ok(DijkstraResult {
146 distances,
147 predecessors,
148 })
149}
150
151pub fn dijkstra_path<G>(g: G, source: G::NodeId, target: G::NodeId) -> Option<Vec<G::NodeId>>
180where
181 G: NodeCount + IntoNodeIdentifiers + IntoEdges + NodeIndexable + Visitable,
182 G::EdgeWeight: FloatMeasure,
183 G::NodeId: PartialEq,
184{
185 let ix = |i| g.to_index(i);
186
187 let result = dijkstra(g, source).ok()?;
188
189 if result.predecessors[ix(target)].is_none() && source != target {
190 return None;
191 }
192
193 let mut path = vec![target];
194 let mut current = target;
195
196 while current != source {
197 let pred = result.predecessors[ix(current)]?;
198 path.push(pred);
199 current = pred;
200 }
201
202 path.reverse();
203 Some(path)
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209 use petgraph::Graph;
210
211 #[test]
212 fn test_dijkstra_simple() {
213 let mut g = Graph::new();
214 let a = g.add_node(());
215 let _b = g.add_node(());
216 let _c = g.add_node(());
217 let _d = g.add_node(());
218 g.extend_with_edges([(0, 1, 2.0), (0, 3, 4.0), (1, 2, 1.0), (3, 4, 1.0)]);
219
220 let result = dijkstra(&g, a);
221 assert!(result.is_ok());
222 let paths = result.unwrap();
223 assert_eq!(paths.distances[0], 0.0);
224 assert_eq!(paths.distances[1], 2.0);
225 assert_eq!(paths.distances[2], 3.0);
226 assert_eq!(paths.distances[3], 4.0);
227 }
228
229 #[test]
230 fn test_dijkstra_negative_weight() {
231 let g: Graph<(), f32> = Graph::<(), f32>::from_edges([(0, 1, -1.0)]);
232 let result = dijkstra(&g, NodeIndex::new(0));
233 assert!(result.is_err());
234 }
235
236 #[test]
237 fn test_dijkstra_path() {
238 let mut g = Graph::new();
239 let a = g.add_node(());
240 let b = g.add_node(());
241 let c = g.add_node(());
242 g.extend_with_edges([(0, 1, 2.0), (1, 2, 3.0)]);
243
244 let path = dijkstra_path(&g, a, c);
245 assert_eq!(path, Some(vec![a, b, c]));
246 }
247
248 #[test]
249 fn test_dijkstra_path_no_path() {
250 let mut g = Graph::new();
251 let a = g.add_node(());
252 let b = g.add_node(());
253 let c = g.add_node(());
254 g.add_edge(a, b, 1.0);
255
256 let path = dijkstra_path(&g, a, c);
257 assert_eq!(path, None);
258 }
259
260 #[test]
261 fn test_dijkstra_disconnected() {
262 let mut g: Graph<(), f64> = Graph::new();
263 let a = g.add_node(());
264 let b = g.add_node(());
265 let c = g.add_node(());
266 g.add_edge(a, b, 1.0);
267
268 let result = dijkstra(&g, a);
269 assert!(result.is_ok());
270 let paths = result.unwrap();
271 assert_eq!(paths.distances[a.index()], 0.0);
272 assert_eq!(paths.distances[b.index()], 1.0);
273 assert!(paths.distances[c.index()].is_infinite());
274 }
275
276 #[test]
277 fn test_dijkstra_same_node() {
278 let mut g: Graph<(), f64> = Graph::new();
279 let a = g.add_node(());
280
281 let result = dijkstra(&g, a);
282 assert!(result.is_ok());
283 let paths = result.unwrap();
284 assert_eq!(paths.distances[a.index()], 0.0);
285 }
286
287 #[test]
288 fn test_dijkstra_path_same_node() {
289 let mut g: Graph<(), f64> = Graph::new();
290 let a = g.add_node(());
291
292 let path = dijkstra_path(&g, a, a);
293 assert_eq!(path, Some(vec![a]));
294 }
295}