use num_traits::{Float, Zero};
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use crate::error::{GraphError, Result};
use crate::graph::Graph;
pub fn all_pairs_shortest_paths<V, W>(graph: &Graph<V, W>) -> Result<HashMap<(V, V), Option<W>>>
where
V: Hash + Eq + Copy + Debug,
W: Float + Zero + Copy + Debug,
{
let mut distances = HashMap::new();
let vertices: Vec<_> = graph.vertices().copied().collect();
for u in &vertices {
for v in &vertices {
let dist = if u == v {
Some(W::zero())
} else {
let mut min_weight = graph.edge_weight(u, v);
for (src, dst, weight) in graph.edges() {
if u == src && v == dst && Some(weight) < min_weight {
min_weight = Some(weight);
}
}
min_weight
};
distances.insert((*u, *v), dist);
}
}
for k in &vertices {
for i in &vertices {
for j in &vertices {
if let (Some(dist_ik), Some(dist_kj)) = (distances[&(*i, *k)], distances[&(*k, *j)])
{
let new_dist = dist_ik + dist_kj;
let better = match distances[&(*i, *j)] {
None => true,
Some(current) => new_dist < current,
};
if better {
distances.insert((*i, *j), Some(new_dist));
}
}
}
}
}
for v in &vertices {
if let Some(dist) = distances[&(*v, *v)] {
if dist < W::zero() {
return Err(GraphError::NegativeCycle);
}
}
}
Ok(distances)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_floyd_warshall_simple_path() {
let mut graph: Graph<i32, f64> = Graph::new();
graph.add_vertex(0);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_edge(0, 1, 1.0);
graph.add_edge(1, 2, 2.0);
graph.add_edge(0, 2, 4.0);
let distances = all_pairs_shortest_paths(&graph).unwrap();
assert_eq!(distances[&(0, 0)], Some(0.0));
assert_eq!(distances[&(0, 1)], Some(1.0));
assert_eq!(distances[&(0, 2)], Some(3.0));
assert_eq!(distances[&(1, 2)], Some(2.0));
assert_eq!(distances[&(2, 1)], None);
}
#[test]
fn test_floyd_warshall_negative_weights() {
let mut graph: Graph<i32, f64> = Graph::new();
graph.add_vertex(0);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_edge(0, 1, 4.0);
graph.add_edge(0, 2, 2.0);
graph.add_edge(1, 3, -3.0);
graph.add_edge(2, 1, 1.0);
graph.add_edge(2, 3, 5.0);
let distances = all_pairs_shortest_paths(&graph).unwrap();
assert_eq!(distances[&(0, 0)], Some(0.0));
assert_eq!(distances[&(0, 1)], Some(3.0));
assert_eq!(distances[&(0, 2)], Some(2.0));
assert_eq!(distances[&(0, 3)], Some(0.0));
}
#[test]
fn test_floyd_warshall_negative_cycle() {
let mut graph: Graph<i32, f64> = Graph::new();
graph.add_vertex(0);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_vertex(3);
graph.add_edge(0, 1, 1.0);
graph.add_edge(1, 2, -1.0);
graph.add_edge(2, 3, -1.0);
graph.add_edge(3, 1, -1.0);
assert!(matches!(
all_pairs_shortest_paths(&graph),
Err(GraphError::NegativeCycle)
));
}
#[test]
fn test_floyd_warshall_unreachable_vertices() {
let mut graph: Graph<i32, f64> = Graph::new();
graph.add_vertex(0);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_edge(0, 1, 1.0);
let distances = all_pairs_shortest_paths(&graph).unwrap();
assert_eq!(distances[&(0, 0)], Some(0.0));
assert_eq!(distances[&(0, 1)], Some(1.0));
assert_eq!(distances[&(0, 2)], None);
assert_eq!(distances[&(1, 2)], None);
assert_eq!(distances[&(2, 0)], None);
}
#[test]
fn test_floyd_warshall_undirected_graph() {
let mut graph: Graph<i32, f64> = Graph::new_undirected();
graph.add_vertex(0);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_edge(0, 1, 1.0);
graph.add_edge(1, 2, 2.0);
let distances = all_pairs_shortest_paths(&graph).unwrap();
assert_eq!(distances[&(0, 2)], Some(3.0));
assert_eq!(distances[&(2, 0)], Some(3.0));
}
#[test]
fn test_floyd_warshall_cycle() {
let mut graph: Graph<i32, f64> = Graph::new();
graph.add_vertex(0);
graph.add_vertex(1);
graph.add_vertex(2);
graph.add_edge(0, 1, 1.0);
graph.add_edge(1, 2, 2.0);
graph.add_edge(2, 0, 3.0);
let distances = all_pairs_shortest_paths(&graph).unwrap();
assert_eq!(distances[&(0, 0)], Some(0.0));
assert_eq!(distances[&(0, 1)], Some(1.0));
assert_eq!(distances[&(0, 2)], Some(3.0));
assert_eq!(distances[&(1, 0)], Some(5.0));
}
#[test]
fn test_floyd_warshall_self_loop() {
let mut graph: Graph<i32, f64> = Graph::new();
graph.add_vertex(0);
graph.add_vertex(1);
graph.add_edge(0, 0, 1.0);
graph.add_edge(0, 1, 2.0);
let distances = all_pairs_shortest_paths(&graph).unwrap();
assert_eq!(distances[&(0, 0)], Some(0.0)); assert_eq!(distances[&(0, 1)], Some(2.0));
}
#[test]
fn test_floyd_warshall_parallel_edges() {
let mut graph: Graph<i32, f64> = Graph::new();
graph.add_vertex(0);
graph.add_vertex(1);
graph.add_edge(0, 1, 2.0);
graph.add_edge(0, 1, 1.0);
let distances = all_pairs_shortest_paths(&graph).unwrap();
assert_eq!(distances[&(0, 0)], Some(0.0));
assert_eq!(distances[&(0, 1)], Some(1.0)); }
#[test]
fn test_floyd_warshall_large_graph() {
let mut graph: Graph<i32, f64> = Graph::new();
for i in 0..100 {
graph.add_vertex(i);
if i > 0 {
graph.add_edge(i - 1, i, 1.0);
}
}
let distances = all_pairs_shortest_paths(&graph).unwrap();
assert_eq!(distances[&(0, 0)], Some(0.0));
assert_eq!(distances[&(0, 50)], Some(50.0));
assert_eq!(distances[&(0, 99)], Some(99.0));
}
}