uni_algo/algo/algorithms/
bellman_ford.rs1use crate::algo::GraphProjection;
11use crate::algo::algorithms::Algorithm;
12use uni_common::core::id::Vid;
13
14pub struct BellmanFord;
15
16#[derive(Debug, Clone)]
17pub struct BellmanFordConfig {
18 pub source: Vid,
19}
20
21impl Default for BellmanFordConfig {
22 fn default() -> Self {
23 Self {
24 source: Vid::from(0),
25 }
26 }
27}
28
29pub struct BellmanFordResult {
30 pub distances: Vec<(Vid, f64)>,
31 pub has_negative_cycle: bool,
32}
33
34impl Algorithm for BellmanFord {
35 type Config = BellmanFordConfig;
36 type Result = BellmanFordResult;
37
38 fn name() -> &'static str {
39 "bellman_ford"
40 }
41
42 fn run(graph: &GraphProjection, config: Self::Config) -> Self::Result {
43 let source_slot = match graph.to_slot(config.source) {
44 Some(slot) => slot,
45 None => {
46 return BellmanFordResult {
47 distances: Vec::new(),
48 has_negative_cycle: false,
49 };
50 }
51 };
52
53 let n = graph.vertex_count();
54 let mut dist = vec![f64::INFINITY; n];
55 dist[source_slot as usize] = 0.0;
56
57 for _ in 0..n - 1 {
59 let mut changed = false;
60 for u in 0..n {
61 if dist[u] == f64::INFINITY {
62 continue;
63 }
64
65 for (i, &v_slot) in graph.out_neighbors(u as u32).iter().enumerate() {
67 let v = v_slot as usize;
68 let weight = if graph.has_weights() {
69 graph.out_weight(u as u32, i)
70 } else {
71 1.0
72 };
73
74 if dist[u] + weight < dist[v] {
75 dist[v] = dist[u] + weight;
76 changed = true;
77 }
78 }
79 }
80 if !changed {
81 break;
82 }
83 }
84
85 let mut has_negative_cycle = false;
87 for u in 0..n {
88 if dist[u] == f64::INFINITY {
89 continue;
90 }
91 for (i, &v_slot) in graph.out_neighbors(u as u32).iter().enumerate() {
92 let v = v_slot as usize;
93 let weight = if graph.has_weights() {
94 graph.out_weight(u as u32, i)
95 } else {
96 1.0
97 };
98
99 if dist[u] + weight < dist[v] {
100 has_negative_cycle = true;
101 break;
102 }
103 }
104 if has_negative_cycle {
105 break;
106 }
107 }
108
109 if has_negative_cycle {
110 BellmanFordResult {
111 distances: Vec::new(),
112 has_negative_cycle: true,
113 }
114 } else {
115 let results = dist
116 .into_iter()
117 .enumerate()
118 .filter(|(_, d)| *d < f64::INFINITY)
119 .map(|(slot, d)| (graph.to_vid(slot as u32), d))
120 .collect();
121
122 BellmanFordResult {
123 distances: results,
124 has_negative_cycle: false,
125 }
126 }
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use crate::algo::test_utils::build_test_graph;
134
135 #[test]
136 fn test_bellman_ford_simple() {
137 let vids = vec![Vid::from(0), Vid::from(1), Vid::from(2)];
139 let edges = vec![(Vid::from(0), Vid::from(1)), (Vid::from(1), Vid::from(2))];
140 let graph = build_test_graph(vids, edges); let config = BellmanFordConfig {
143 source: Vid::from(0),
144 };
145 let result = BellmanFord::run(&graph, config);
146
147 assert!(!result.has_negative_cycle);
148 let dists: std::collections::HashMap<_, _> = result.distances.into_iter().collect();
149 assert_eq!(dists[&Vid::from(0)], 0.0);
150 assert_eq!(dists[&Vid::from(1)], 1.0);
151 assert_eq!(dists[&Vid::from(2)], 2.0);
152 }
153
154 }