#![allow(dead_code)]
pub struct FwResult {
pub n: usize,
pub dist: Vec<Vec<f32>>,
pub next: Vec<Vec<usize>>,
}
impl FwResult {
pub fn get(&self, i: usize, j: usize) -> f32 {
self.dist[i][j]
}
pub fn path(&self, mut i: usize, j: usize) -> Option<Vec<usize>> {
if !self.dist[i][j].is_finite() {
return None;
}
let mut path = vec![i];
while i != j {
i = self.next[i][j];
if i == usize::MAX {
return None;
}
path.push(i);
}
Some(path)
}
}
pub fn new_fw_result(n: usize) -> FwResult {
let dist = (0..n)
.map(|i| {
(0..n)
.map(|j| if i == j { 0.0 } else { f32::INFINITY })
.collect()
})
.collect();
let next = vec![vec![usize::MAX; n]; n];
FwResult { n, dist, next }
}
pub fn fw_add_edge(fw: &mut FwResult, u: usize, v: usize, w: f32) {
if u < fw.n && v < fw.n && w < fw.dist[u][v] {
fw.dist[u][v] = w;
fw.next[u][v] = v;
}
}
pub fn floyd_warshall(fw: &mut FwResult) {
let n = fw.n;
for k in 0..n {
for i in 0..n {
for j in 0..n {
if fw.dist[i][k].is_finite() && fw.dist[k][j].is_finite() {
let new_d = fw.dist[i][k] + fw.dist[k][j];
if new_d < fw.dist[i][j] {
fw.dist[i][j] = new_d;
fw.next[i][j] = fw.next[i][k];
}
}
}
}
}
}
pub fn fw_solve(n: usize, edges: &[(usize, usize, f32)]) -> FwResult {
let mut fw = new_fw_result(n);
for &(u, v, w) in edges {
fw_add_edge(&mut fw, u, v, w);
}
floyd_warshall(&mut fw);
fw
}
pub fn fw_has_negative_cycle(fw: &FwResult) -> bool {
(0..fw.n).any(|i| fw.dist[i][i] < 0.0)
}
pub fn fw_distance(fw: &FwResult, i: usize, j: usize) -> Option<f32> {
if i < fw.n && j < fw.n && fw.dist[i][j].is_finite() {
Some(fw.dist[i][j])
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_triangle() {
let fw = fw_solve(3, &[(0, 1, 1.0), (1, 2, 2.0), (0, 2, 10.0)]);
assert!((fw.get(0, 2) - 3.0).abs() < 1e-6);
}
#[test]
fn test_unreachable() {
let fw = fw_solve(3, &[(0, 1, 1.0)]);
assert!(fw_distance(&fw, 0, 2).is_none());
}
#[test]
fn test_self_distance_zero() {
let fw = fw_solve(3, &[(0, 1, 5.0)]);
assert_eq!(fw.get(0, 0), 0.0);
}
#[test]
fn test_path_reconstruction() {
let fw = fw_solve(3, &[(0, 1, 1.0), (1, 2, 1.0)]);
let path = fw.path(0, 2).expect("should succeed");
assert_eq!(path, vec![0, 1, 2]);
}
#[test]
fn test_no_negative_cycle() {
let fw = fw_solve(3, &[(0, 1, 1.0), (1, 2, 1.0), (2, 0, 1.0)]);
assert!(!fw_has_negative_cycle(&fw));
}
#[test]
fn test_fw_distance_finite() {
let fw = fw_solve(4, &[(0, 1, 1.0), (1, 2, 1.0), (2, 3, 1.0)]);
assert_eq!(fw_distance(&fw, 0, 3), Some(3.0));
}
#[test]
fn test_symmetric_edges() {
let fw = fw_solve(3, &[(0, 1, 2.0), (1, 0, 2.0), (1, 2, 3.0), (2, 1, 3.0)]);
assert!((fw.get(0, 2) - 5.0).abs() < 1e-6);
assert!((fw.get(2, 0) - 5.0).abs() < 1e-6);
}
#[test]
fn test_new_fw_result_diagonal() {
let fw = new_fw_result(5);
for i in 0..5 {
assert_eq!(fw.dist[i][i], 0.0);
}
}
#[test]
fn test_large_graph_all_pairs() {
let edges: Vec<(usize, usize, f32)> = (1..5).map(|i| (0, i, 1.0)).collect();
let fw = fw_solve(5, &edges);
assert!(fw_distance(&fw, 0, 4).is_some());
}
}