advanced_algorithms/graph/
floyd_warshall.rs1use crate::graph::Graph;
25use crate::{AlgorithmError, Result};
26
27#[derive(Debug, Clone)]
29pub struct AllPairsShortestPath {
30 distance: Vec<Vec<f64>>,
32 next: Vec<Vec<Option<usize>>>,
34 _n: usize,
36}
37
38impl AllPairsShortestPath {
39 pub fn distance(&self, u: usize, v: usize) -> f64 {
41 self.distance[u][v]
42 }
43
44 pub fn path(&self, u: usize, v: usize) -> Option<Vec<usize>> {
46 if self.distance[u][v].is_infinite() {
47 return None;
48 }
49
50 let mut path = vec![u];
51 let mut current = u;
52
53 while current != v {
54 current = self.next[current][v]?;
55 path.push(current);
56 }
57
58 Some(path)
59 }
60
61 pub fn distance_matrix(&self) -> &[Vec<f64>] {
63 &self.distance
64 }
65}
66
67pub fn all_pairs_shortest_path(graph: &Graph) -> Result<AllPairsShortestPath> {
81 let n = graph.n_nodes;
82
83 let mut distance = vec![vec![f64::INFINITY; n]; n];
85 let mut next = vec![vec![None; n]; n];
86
87 #[allow(clippy::needless_range_loop)]
89 for i in 0..n {
90 distance[i][i] = 0.0;
91 }
92
93 for u in 0..n {
95 for &(v, weight) in graph.neighbors(u) {
96 distance[u][v] = weight;
97 next[u][v] = Some(v);
98 }
99 }
100
101 for k in 0..n {
103 for i in 0..n {
104 for j in 0..n {
105 let new_distance = distance[i][k] + distance[k][j];
106
107 if new_distance < distance[i][j] {
108 distance[i][j] = new_distance;
109 next[i][j] = next[i][k];
110 }
111 }
112 }
113 }
114
115 #[allow(clippy::needless_range_loop)]
117 for i in 0..n {
118 if distance[i][i] < 0.0 {
119 return Err(AlgorithmError::InvalidInput(
120 "Graph contains a negative cycle".to_string()
121 ));
122 }
123 }
124
125 Ok(AllPairsShortestPath {
126 distance,
127 next,
128 _n: n,
129 })
130}
131
132pub fn transitive_closure(graph: &Graph) -> Vec<Vec<bool>> {
136 let n = graph.n_nodes;
137 let mut reachable = vec![vec![false; n]; n];
138
139 #[allow(clippy::needless_range_loop)]
141 for i in 0..n {
142 reachable[i][i] = true;
143 }
144
145 #[allow(clippy::needless_range_loop)]
147 for u in 0..n {
148 for &(v, _) in graph.neighbors(u) {
149 reachable[u][v] = true;
150 }
151 }
152
153 for k in 0..n {
155 for i in 0..n {
156 for j in 0..n {
157 reachable[i][j] = reachable[i][j] || (reachable[i][k] && reachable[k][j]);
158 }
159 }
160 }
161
162 reachable
163}
164
165pub fn diameter(graph: &Graph) -> Option<f64> {
171 match all_pairs_shortest_path(graph) {
172 Ok(apsp) => {
173 let mut max_distance: f64 = 0.0;
174
175 for i in 0..graph.n_nodes {
176 for j in 0..graph.n_nodes {
177 let d = apsp.distance(i, j);
178 if d.is_finite() {
179 max_distance = max_distance.max(d);
180 } else if i != j {
181 return None;
183 }
184 }
185 }
186
187 Some(max_distance)
188 }
189 Err(_) => None,
190 }
191}
192
193pub fn find_center(graph: &Graph) -> Option<Vec<usize>> {
197 let apsp = all_pairs_shortest_path(graph).ok()?;
198 let n = graph.n_nodes;
199
200 let mut eccentricities = Vec::with_capacity(n);
201
202 for i in 0..n {
203 let mut max_distance: f64 = 0.0;
204
205 for j in 0..n {
206 let d = apsp.distance(i, j);
207 if d.is_finite() {
208 max_distance = max_distance.max(d);
209 } else {
210 return None;
212 }
213 }
214
215 eccentricities.push(max_distance);
216 }
217
218 let min_eccentricity = eccentricities.iter()
219 .fold(f64::INFINITY, |a, &b| a.min(b));
220
221 let centers: Vec<usize> = eccentricities.iter()
222 .enumerate()
223 .filter(|(_, &e)| (e - min_eccentricity).abs() < 1e-10)
224 .map(|(i, _)| i)
225 .collect();
226
227 Some(centers)
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233
234 #[test]
235 fn test_simple_graph() {
236 let mut graph = Graph::new(4);
237 graph.add_edge(0, 1, 1.0);
238 graph.add_edge(1, 2, 2.0);
239 graph.add_edge(2, 3, 3.0);
240 graph.add_edge(0, 3, 10.0);
241
242 let result = all_pairs_shortest_path(&graph).unwrap();
243
244 assert_eq!(result.distance(0, 3), 6.0);
245 assert_eq!(result.distance(0, 2), 3.0);
246
247 let path = result.path(0, 3).unwrap();
248 assert_eq!(path, vec![0, 1, 2, 3]);
249 }
250
251 #[test]
252 fn test_all_pairs() {
253 let mut graph = Graph::new(3);
254 graph.add_edge(0, 1, 1.0);
255 graph.add_edge(1, 2, 2.0);
256 graph.add_edge(0, 2, 5.0);
257
258 let result = all_pairs_shortest_path(&graph).unwrap();
259
260 assert_eq!(result.distance(0, 1), 1.0);
261 assert_eq!(result.distance(0, 2), 3.0);
262 assert_eq!(result.distance(1, 2), 2.0);
263 }
264
265 #[test]
266 fn test_negative_cycle() {
267 let mut graph = Graph::new(3);
268 graph.add_edge(0, 1, 1.0);
269 graph.add_edge(1, 2, -3.0);
270 graph.add_edge(2, 0, 1.0);
271
272 let result = all_pairs_shortest_path(&graph);
273 assert!(result.is_err());
274 }
275
276 #[test]
277 fn test_transitive_closure() {
278 let mut graph = Graph::new(4);
279 graph.add_edge(0, 1, 1.0);
280 graph.add_edge(1, 2, 1.0);
281 graph.add_edge(2, 3, 1.0);
282
283 let closure = transitive_closure(&graph);
284
285 assert!(closure[0][3]); assert!(!closure[3][0]); }
288
289 #[test]
290 fn test_diameter() {
291 let mut graph = Graph::new(4);
292 graph.add_edge(0, 1, 1.0);
293 graph.add_edge(1, 2, 1.0);
294 graph.add_edge(2, 3, 1.0);
295 graph.add_undirected_edge(0, 3, 1.0);
296
297 let d = diameter(&graph);
298 assert!(d.is_some());
299 assert_eq!(d.unwrap(), 3.0);
301 }
302}