use petgraph::algo::floyd_warshall; use petgraph::{prelude::*, Directed, Graph, Undirected}; use std::collections::HashMap; #[test] fn floyd_warshall_uniform_weight() { let mut graph: Graph<(), (), Directed> = Graph::new(); let a = graph.add_node(()); let b = graph.add_node(()); let c = graph.add_node(()); let d = graph.add_node(()); let e = graph.add_node(()); let f = graph.add_node(()); let g = graph.add_node(()); let h = graph.add_node(()); graph.extend_with_edges(&[ (a, b), (b, c), (c, d), (d, a), (e, f), (b, e), (f, g), (g, h), (h, e), ]); // a ----> b ----> e ----> f // ^ | ^ | // | v | v // d <---- c h <---- g let inf = std::i32::MAX; let expected_res: HashMap<(NodeIndex, NodeIndex), i32> = [ ((a, a), 0), ((a, b), 1), ((a, c), 2), ((a, d), 3), ((a, e), 2), ((a, f), 3), ((a, g), 4), ((a, h), 5), ((b, a), 3), ((b, b), 0), ((b, c), 1), ((b, d), 2), ((b, e), 1), ((b, f), 2), ((b, g), 3), ((b, h), 4), ((c, a), 2), ((c, b), 3), ((c, c), 0), ((c, d), 1), ((c, e), 4), ((c, f), 5), ((c, g), 6), ((c, h), 7), ((d, a), 1), ((d, b), 2), ((d, c), 3), ((d, d), 0), ((d, e), 3), ((d, f), 4), ((d, g), 5), ((d, h), 6), ((e, a), inf), ((e, b), inf), ((e, c), inf), ((e, d), inf), ((e, e), 0), ((e, f), 1), ((e, g), 2), ((e, h), 3), ((f, a), inf), ((f, b), inf), ((f, c), inf), ((f, d), inf), ((f, e), 3), ((f, f), 0), ((f, g), 1), ((f, h), 2), ((g, a), inf), ((g, b), inf), ((g, c), inf), ((g, d), inf), ((g, e), 2), ((g, f), 3), ((g, g), 0), ((g, h), 1), ((h, a), inf), ((h, b), inf), ((h, c), inf), ((h, d), inf), ((h, e), 1), ((h, f), 2), ((h, g), 3), ((h, h), 0), ] .iter() .cloned() .collect(); let res = floyd_warshall(&graph, |_| 1 as i32).unwrap(); let nodes = [a, b, c, d, e, f, g, h]; for node1 in &nodes { for node2 in &nodes { assert_eq!( res.get(&(*node1, *node2)).unwrap(), expected_res.get(&(*node1, *node2)).unwrap() ); } } } #[test] fn floyd_warshall_weighted() { let mut graph: Graph<(), (), Directed> = Graph::new(); let a = graph.add_node(()); let b = graph.add_node(()); let c = graph.add_node(()); let d = graph.add_node(()); graph.extend_with_edges(&[(a, b), (a, c), (a, d), (b, c), (b, d), (c, d)]); let inf = std::i32::MAX; let expected_res: HashMap<(NodeIndex, NodeIndex), i32> = [ ((a, a), 0), ((a, b), 1), ((a, c), 3), ((a, d), 3), ((b, a), inf), ((b, b), 0), ((b, c), 2), ((b, d), 2), ((c, a), inf), ((c, b), inf), ((c, c), 0), ((c, d), 2), ((d, a), inf), ((d, b), inf), ((d, c), inf), ((d, d), 0), ] .iter() .cloned() .collect(); let weight_map: HashMap<(NodeIndex, NodeIndex), i32> = [ ((a, a), 0), ((a, b), 1), ((a, c), 4), ((a, d), 10), ((b, b), 0), ((b, c), 2), ((b, d), 2), ((c, c), 0), ((c, d), 2), ] .iter() .cloned() .collect(); let res = floyd_warshall(&graph, |edge| { if let Some(weight) = weight_map.get(&(edge.source(), edge.target())) { *weight } else { inf } }) .unwrap(); let nodes = [a, b, c, d]; for node1 in &nodes { for node2 in &nodes { assert_eq!( res.get(&(*node1, *node2)).unwrap(), expected_res.get(&(*node1, *node2)).unwrap() ); } } } #[test] fn floyd_warshall_weighted_undirected() { let mut graph: Graph<(), (), Undirected> = Graph::new_undirected(); let a = graph.add_node(()); let b = graph.add_node(()); let c = graph.add_node(()); let d = graph.add_node(()); graph.extend_with_edges(&[(a, b), (a, c), (a, d), (b, d), (c, b), (c, d)]); let inf = std::i32::MAX; let expected_res: HashMap<(NodeIndex, NodeIndex), i32> = [ ((a, a), 0), ((a, b), 1), ((a, c), 3), ((a, d), 3), ((b, a), 1), ((b, b), 0), ((b, c), 2), ((b, d), 2), ((c, a), 3), ((c, b), 2), ((c, c), 0), ((c, d), 2), ((d, a), 3), ((d, b), 2), ((d, c), 2), ((d, d), 0), ] .iter() .cloned() .collect(); let weight_map: HashMap<(NodeIndex, NodeIndex), i32> = [ ((a, a), 0), ((a, b), 1), ((a, c), 4), ((a, d), 10), ((b, b), 0), ((b, d), 2), ((c, b), 2), ((c, c), 0), ((c, d), 2), ] .iter() .cloned() .collect(); let res = floyd_warshall(&graph, |edge| { if let Some(weight) = weight_map.get(&(edge.source(), edge.target())) { *weight } else { inf } }) .unwrap(); let nodes = [a, b, c, d]; for node1 in &nodes { for node2 in &nodes { assert_eq!( res.get(&(*node1, *node2)).unwrap(), expected_res.get(&(*node1, *node2)).unwrap() ); } } } #[test] fn floyd_warshall_negative_cycle() { let mut graph: Graph<(), (), Directed> = Graph::new(); let a = graph.add_node(()); let b = graph.add_node(()); let c = graph.add_node(()); graph.extend_with_edges(&[(a, b), (b, c), (c, a)]); let inf = std::i32::MAX; let weight_map: HashMap<(NodeIndex, NodeIndex), i32> = [ ((a, a), 0), ((a, b), 1), ((b, b), 0), ((b, c), -3), ((c, c), 0), ((c, a), 1), ] .iter() .cloned() .collect(); let res = floyd_warshall(&graph, |edge| { if let Some(weight) = weight_map.get(&(edge.source(), edge.target())) { *weight } else { inf } }); assert!(res.is_err()); }