uni_algo/algo/algorithms/
dijkstra.rs1use crate::algo::GraphProjection;
7use crate::algo::algorithms::Algorithm;
8use std::cmp::Reverse;
9use std::collections::BinaryHeap;
10use uni_common::core::id::Vid;
11
12pub struct Dijkstra;
13
14#[derive(Debug, Clone)]
15pub struct DijkstraConfig {
16 pub source: Vid,
17 pub target: Option<Vid>,
18 pub max_distance: Option<f64>,
19}
20
21impl Default for DijkstraConfig {
22 fn default() -> Self {
23 Self {
24 source: Vid::from(0),
25 target: None,
26 max_distance: None,
27 }
28 }
29}
30
31pub struct DijkstraResult {
32 pub distances: Vec<(Vid, f64)>,
33 pub path: Option<Vec<Vid>>,
34}
35
36impl Algorithm for Dijkstra {
37 type Config = DijkstraConfig;
38 type Result = DijkstraResult;
39
40 fn name() -> &'static str {
41 "shortestPath"
42 }
43
44 fn run(graph: &GraphProjection, config: Self::Config) -> Self::Result {
45 let source_slot = match graph.to_slot(config.source) {
46 Some(slot) => slot,
47 None => {
48 return DijkstraResult {
49 distances: Vec::new(),
50 path: None,
51 };
52 }
53 };
54
55 let n = graph.vertex_count();
56 let mut dist = vec![f64::INFINITY; n];
57 let mut prev: Vec<Option<u32>> = vec![None; n];
58 let mut heap = BinaryHeap::new();
59
60 dist[source_slot as usize] = 0.0;
61 heap.push(Reverse((0.0f64.to_bits(), source_slot)));
62
63 let target_slot = config.target.and_then(|t| graph.to_slot(t));
64
65 while let Some(Reverse((d_bits, u))) = heap.pop() {
66 let d = f64::from_bits(d_bits);
67 if d > dist[u as usize] {
68 continue;
69 }
70
71 if target_slot == Some(u) {
73 break;
74 }
75
76 if let Some(max_d) = config.max_distance
78 && d > max_d
79 {
80 continue;
81 }
82
83 for (i, &v) in graph.out_neighbors(u).iter().enumerate() {
84 let weight = if graph.has_weights() {
85 graph.out_weight(u, i)
86 } else {
87 1.0
88 };
89 let new_dist = d + weight;
90
91 if new_dist < dist[v as usize] {
92 dist[v as usize] = new_dist;
93 prev[v as usize] = Some(u);
94 heap.push(Reverse((new_dist.to_bits(), v)));
95 }
96 }
97 }
98
99 let mut path = None;
101 if let Some(t_slot) = target_slot
102 && dist[t_slot as usize] < f64::INFINITY
103 {
104 let mut p = Vec::new();
105 let mut curr = Some(t_slot);
106 while let Some(slot) = curr {
107 p.push(graph.to_vid(slot));
108 if slot == source_slot {
109 break;
110 }
111 curr = prev[slot as usize];
112 }
113 p.reverse();
114 path = Some(p);
115 }
116
117 let results = dist
118 .into_iter()
119 .enumerate()
120 .filter(|(_, d)| *d < f64::INFINITY)
121 .map(|(slot, d)| (graph.to_vid(slot as u32), d))
122 .collect();
123
124 DijkstraResult {
125 distances: results,
126 path,
127 }
128 }
129}