| 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_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()); |
| } |