1use crate::dijkstra::epoch_array_dijkstra_node_weight_array::EpochNodeWeightArray;
2use crate::dijkstra::performance_counters::DijkstraPerformanceData;
3use std::collections::BinaryHeap;
4use std::fmt::Debug;
5use std::marker::PhantomData;
6use std::ops::Add;
7use traitgraph::index::{GraphIndex, NodeIndex};
8use traitgraph::interface::{GraphBase, StaticGraph};
9
10mod dijkstra_weight_implementations;
11
12pub mod epoch_array_dijkstra_node_weight_array;
14#[cfg(feature = "hashbrown_dijkstra_node_weight_array")]
16pub mod hashbrown_dijkstra_node_weight_array;
17
18pub mod performance_counters;
20
21pub type DefaultDijkstra<Graph, WeightType> = Dijkstra<
23 Graph,
24 WeightType,
25 EpochNodeWeightArray<WeightType>,
26 BinaryHeap<std::cmp::Reverse<(WeightType, <Graph as GraphBase>::NodeIndex)>>,
27>;
28
29pub trait DijkstraWeight: Ord + Add<Output = Self> + Sized + Clone {
31 fn infinity() -> Self;
33
34 fn zero() -> Self;
36}
37
38pub trait DijkstraWeightedEdgeData<WeightType: DijkstraWeight> {
40 fn weight(&self) -> WeightType;
42}
43
44impl<WeightType: DijkstraWeight + Copy> DijkstraWeightedEdgeData<WeightType> for WeightType {
45 #[inline]
46 fn weight(&self) -> WeightType {
47 *self
48 }
49}
50
51pub trait NodeWeightArray<WeightType> {
53 fn new(size: usize) -> Self;
55
56 fn get(&self, node_index: usize) -> WeightType;
58
59 fn get_mut<'this: 'result, 'result>(
61 &'this mut self,
62 node_index: usize,
63 ) -> &'result mut WeightType;
64
65 fn set(&mut self, node_index: usize, weight: WeightType);
67
68 fn clear(&mut self);
70
71 fn size(&self) -> usize;
73}
74
75impl<WeightType: DijkstraWeight + Copy> NodeWeightArray<WeightType> for Vec<WeightType> {
76 fn new(size: usize) -> Self {
77 vec![WeightType::infinity(); size]
78 }
79
80 #[inline]
81 fn get(&self, node_index: usize) -> WeightType {
82 self[node_index]
83 }
84
85 #[inline]
86 fn get_mut<'this: 'result, 'result>(
87 &'this mut self,
88 node_index: usize,
89 ) -> &'result mut WeightType {
90 &mut self[node_index]
91 }
92
93 #[inline]
94 fn set(&mut self, node_index: usize, weight: WeightType) {
95 self[node_index] = weight;
96 }
97
98 fn clear(&mut self) {
99 for entry in self.iter_mut() {
100 *entry = WeightType::infinity();
101 }
102 }
103
104 #[inline]
105 fn size(&self) -> usize {
106 self.len()
107 }
108}
109
110pub trait DijkstraTargetMap<Graph: GraphBase> {
112 fn is_target(&self, node_index: Graph::NodeIndex) -> bool;
114}
115
116impl<Graph: GraphBase> DijkstraTargetMap<Graph> for Vec<bool> {
117 fn is_target(&self, node_index: Graph::NodeIndex) -> bool {
118 self[node_index.as_usize()]
119 }
120}
121
122impl<IndexType: Sized + Eq, Graph: GraphBase<NodeIndex = NodeIndex<IndexType>>>
123 DijkstraTargetMap<Graph> for NodeIndex<IndexType>
124{
125 fn is_target(&self, node_index: Graph::NodeIndex) -> bool {
126 *self == node_index
127 }
128}
129
130pub trait DijkstraHeap<WeightType, IndexType>: Default {
132 fn insert(&mut self, weight: WeightType, index: IndexType);
134
135 fn remove_min(&mut self) -> Option<(WeightType, IndexType)>;
137
138 fn clear(&mut self);
140
141 fn size(&mut self) -> usize;
143}
144
145impl<WeightType: Ord, IndexType: Ord> DijkstraHeap<WeightType, IndexType>
146 for BinaryHeap<std::cmp::Reverse<(WeightType, IndexType)>>
147{
148 fn insert(&mut self, weight: WeightType, index: IndexType) {
149 self.push(std::cmp::Reverse((weight, index)));
150 }
151
152 fn remove_min(&mut self) -> Option<(WeightType, IndexType)> {
153 self.pop().map(|packed| packed.0)
154 }
155
156 fn clear(&mut self) {
157 self.clear()
158 }
159
160 fn size(&mut self) -> usize {
161 self.len()
162 }
163}
164
165#[derive(Debug, Clone, Eq, PartialEq)]
170pub enum DijkstraExhaustiveness {
171 Complete,
173 PartialNodeWeights,
175 PartialHeap,
177}
178
179#[derive(Debug, Clone, Eq, PartialEq)]
181pub struct DijkstraStatus<DijkstraPerformance: DijkstraPerformanceData> {
182 pub exhaustiveness: DijkstraExhaustiveness,
184 pub performance_data: DijkstraPerformance,
186}
187
188pub struct Dijkstra<
193 Graph: GraphBase,
194 WeightType: DijkstraWeight,
195 NodeWeights: NodeWeightArray<WeightType>,
196 Heap: DijkstraHeap<WeightType, Graph::NodeIndex>,
197> {
198 heap: Heap,
199 node_weights: NodeWeights,
201 graph: PhantomData<Graph>,
202 _weight_type_phantom: PhantomData<WeightType>,
203}
204
205impl<
206 WeightType: DijkstraWeight + Eq + Debug,
207 EdgeData: DijkstraWeightedEdgeData<WeightType>,
208 Graph: StaticGraph<EdgeData = EdgeData>,
209 NodeWeights: NodeWeightArray<WeightType>,
210 Heap: DijkstraHeap<WeightType, Graph::NodeIndex>,
211 > Dijkstra<Graph, WeightType, NodeWeights, Heap>
212{
213 pub fn new(graph: &Graph) -> Self {
215 Self {
216 heap: Default::default(),
217 node_weights: NodeWeights::new(graph.node_count()),
219 graph: Default::default(),
220 _weight_type_phantom: Default::default(),
221 }
222 }
223
224 #[inline(never)]
228 #[allow(clippy::too_many_arguments)]
229 pub fn shortest_path_lens<
230 TargetMap: DijkstraTargetMap<Graph>,
231 DijkstraPerformance: DijkstraPerformanceData,
232 >(
233 &mut self,
234 graph: &Graph,
235 source: Graph::NodeIndex,
236 targets: &TargetMap,
237 target_amount: usize,
238 max_weight: WeightType,
239 forbid_source_target: bool,
240 distances: &mut Vec<(Graph::NodeIndex, WeightType)>,
241 max_node_weight_data_size: usize,
242 max_heap_data_size: usize,
243 mut performance_data: DijkstraPerformance,
244 ) -> DijkstraStatus<DijkstraPerformance> {
245 self.heap.insert(WeightType::zero(), source);
247 self.node_weights.set(source.as_usize(), WeightType::zero());
249 distances.clear();
250 let mut exhaustiveness = DijkstraExhaustiveness::Complete;
251
252 while let Some((weight, node_index)) = self.heap.remove_min() {
254 performance_data.add_iteration();
255 let actual_weight = self.node_weights.get(node_index.as_usize());
258 if actual_weight < weight {
259 performance_data.add_unnecessary_heap_element();
260 continue;
261 }
262 debug_assert_eq!(actual_weight, weight);
263
264 if weight > max_weight {
266 break;
268 }
269
270 if targets.is_target(node_index) && (!forbid_source_target || node_index != source) {
272 distances.push((node_index, weight.clone()));
273
274 if distances.len() == target_amount {
276 break;
278 }
279 }
280
281 for out_neighbor in graph.out_neighbors(node_index) {
283 let new_neighbor_weight =
284 weight.clone() + graph.edge_data(out_neighbor.edge_id).weight();
285 let neighbor_weight = self.node_weights.get_mut(out_neighbor.node_id.as_usize());
286 if new_neighbor_weight < *neighbor_weight {
287 *neighbor_weight = new_neighbor_weight.clone();
288 self.heap.insert(new_neighbor_weight, out_neighbor.node_id);
289 }
291 }
292
293 performance_data.record_heap_size(self.heap.size());
294 performance_data.record_distance_array_size(self.node_weights.size());
295
296 if self.node_weights.size() > max_node_weight_data_size {
297 exhaustiveness = DijkstraExhaustiveness::PartialNodeWeights;
298 break;
299 } else if self.heap.size() > max_heap_data_size {
300 exhaustiveness = DijkstraExhaustiveness::PartialHeap;
301 break;
302 }
303 }
304
305 self.heap.clear();
306 self.node_weights.clear();
310 performance_data.finish_dijkstra();
311 DijkstraStatus {
312 exhaustiveness,
313 performance_data,
314 }
315 }
316}
317
318#[cfg(test)]
319mod tests {
320 use crate::dijkstra::performance_counters::NoopDijkstraPerformanceCounter;
321 use crate::dijkstra::DefaultDijkstra;
322 use traitgraph::implementation::petgraph_impl::PetGraph;
323 use traitgraph::interface::MutableGraphContainer;
324
325 #[test]
326 fn test_dijkstra_simple() {
327 let mut graph = PetGraph::new();
328 let n1 = graph.add_node(());
329 let n2 = graph.add_node(());
330 let n3 = graph.add_node(());
331 graph.add_edge(n1, n2, 2);
332 graph.add_edge(n2, n3, 2);
333 graph.add_edge(n1, n3, 5);
334
335 let mut dijkstra = DefaultDijkstra::new(&graph);
336 let mut distances = Vec::new();
337 let mut targets = vec![false, false, true];
338 dijkstra.shortest_path_lens(
339 &graph,
340 n1,
341 &targets,
342 1,
343 6,
344 false,
345 &mut distances,
346 usize::MAX,
347 usize::MAX,
348 NoopDijkstraPerformanceCounter,
349 );
350 debug_assert_eq!(distances, vec![(n3, 4)]);
351
352 dijkstra.shortest_path_lens(
353 &graph,
354 n1,
355 &targets,
356 1,
357 6,
358 false,
359 &mut distances,
360 usize::MAX,
361 usize::MAX,
362 NoopDijkstraPerformanceCounter,
363 );
364 debug_assert_eq!(distances, vec![(n3, 4)]);
365
366 dijkstra.shortest_path_lens(
367 &graph,
368 n2,
369 &targets,
370 1,
371 6,
372 false,
373 &mut distances,
374 usize::MAX,
375 usize::MAX,
376 NoopDijkstraPerformanceCounter,
377 );
378 debug_assert_eq!(distances, vec![(n3, 2)]);
379
380 dijkstra.shortest_path_lens(
381 &graph,
382 n3,
383 &targets,
384 1,
385 6,
386 false,
387 &mut distances,
388 usize::MAX,
389 usize::MAX,
390 NoopDijkstraPerformanceCounter,
391 );
392 debug_assert_eq!(distances, vec![(n3, 0)]);
393
394 targets = vec![false, true, false];
395 dijkstra.shortest_path_lens(
396 &graph,
397 n3,
398 &targets,
399 1,
400 6,
401 false,
402 &mut distances,
403 usize::MAX,
404 usize::MAX,
405 NoopDijkstraPerformanceCounter,
406 );
407 debug_assert_eq!(distances, vec![]);
408 }
409
410 #[test]
411 fn test_dijkstra_cycle() {
412 let mut graph = PetGraph::new();
413 let n1 = graph.add_node(());
414 let n2 = graph.add_node(());
415 let n3 = graph.add_node(());
416 graph.add_edge(n1, n2, 2);
417 graph.add_edge(n2, n3, 2);
418 graph.add_edge(n3, n1, 5);
419
420 let mut dijkstra = DefaultDijkstra::new(&graph);
421 let mut distances = Vec::new();
422 let targets = vec![false, false, true];
423 dijkstra.shortest_path_lens(
424 &graph,
425 n1,
426 &targets,
427 1,
428 6,
429 false,
430 &mut distances,
431 usize::MAX,
432 usize::MAX,
433 NoopDijkstraPerformanceCounter,
434 );
435 debug_assert_eq!(distances, vec![(n3, 4)]);
436 }
437}