#[doc(hidden)] #[macro_export] macro_rules! dijkstra_tests { ($T:ty) => { #[test] fn dijkstra_single_vertex() { use $crate::traits::GraphTopologyAddition; let mut graph = <$T>::new(); let v = graph.add_vertex(); let result = $crate::algorithms::dijkstra(&graph, v, |_| { panic!("unexpected call of weight functor") }); assert_single_vertex(&result, v); } #[test] fn dijkstra_disconnected() { let (graph, vertices) = make_test_graph_disconnected(); let result = $crate::algorithms::dijkstra(&graph, vertices[0], |_| { panic!("unexpected call of weight functor") }); assert_single_vertex(&result, vertices[0]); assert_disconnected(&result, &vertices[1..3]); } #[test] fn dijkstra_zero_weight_loop() { use $crate::traits::{GraphTopology, GraphTopologyAddition}; let mut graph = <$T>::new(); let vertices: [<$T as $crate::traits::GraphTopology>::Vertex; 3] = core::array::from_fn(|_| graph.add_vertex()); let e1 = graph.add_edge(vertices[0], vertices[0]); let e2 = graph.add_edge(vertices[1], vertices[1]); graph.add_edge(vertices[0], vertices[1]); graph.add_edge(vertices[1], vertices[2]); let mut weights = graph.edge_map(1); weights[e1] = 0; weights[e2] = 0; let result = $crate::algorithms::dijkstra(&graph, vertices[0], |e| weights[e]); assert_single_vertex(&result, vertices[0]); for i in 1..3 { assert_eq!( result.predecessors[vertices[i]], Some(vertices[i - 1]), "unexpected predecessor of vertex {:?}", vertices[i] ); assert_eq!( result.distances[vertices[i]], Some(i.try_into().unwrap()), "unexpected distance of vertex {:?}", vertices[i] ); } } #[test] fn dijkstra() { let (graph, vertices, edges, _, weights) = make_test_graph_weighted(); let result = $crate::algorithms::dijkstra(&graph, vertices[0], |e| weights[e]); assert_test_graph(&result, &vertices); } #[test] fn dijkstra_distances() { let (graph, vertices, edges, _, weights) = make_test_graph_weighted(); let distances = $crate::algorithms::dijkstra_distances(&graph, vertices[0], |e| weights[e]); assert_distances_test_graph(&distances, &vertices); } #[test] fn dijkstra_unweighted_single_vertex() { use $crate::traits::GraphTopologyAddition; let mut graph = <$T>::new(); let v = graph.add_vertex(); let result = $crate::algorithms::dijkstra_unweighted(&graph, v); assert_single_vertex(&result, v) } #[test] fn dijkstra_unweighted_disconnected() { let (graph, vertices) = make_test_graph_disconnected(); let result = $crate::algorithms::dijkstra_unweighted(&graph, vertices[0]); assert_single_vertex(&result, vertices[0]); assert_disconnected(&result, &vertices[1..3]); } #[test] fn dijkstra_unweighted() { let (graph, vertices, _, _) = make_test_graph(); let result = $crate::algorithms::dijkstra_unweighted(&graph, vertices[0]); assert_unweighted_test_graph(&result, &vertices); } #[test] fn dijkstra_distances_unweighted_single_vertex() { use $crate::traits::GraphTopologyAddition; let mut graph = <$T>::new(); let v = graph.add_vertex(); let distances = $crate::algorithms::dijkstra_distances_unweighted(&graph, v); assert_distances_single_vertex(&distances, v); } #[test] fn dijkstra_distances_unweighted_disconnected() { let (graph, vertices) = make_test_graph_disconnected(); let distances = $crate::algorithms::dijkstra_distances_unweighted(&graph, vertices[0]); assert_distances_single_vertex(&distances, vertices[0]); assert_distances_disconnected(&distances, &vertices[1..3]); } #[test] fn dijkstra_distances_unweighted() { let (graph, vertices, _, _) = make_test_graph(); let distances = $crate::algorithms::dijkstra_distances_unweighted(&graph, vertices[0]); assert_distances_unweighted_test_graph(&distances, &vertices); } fn assert_single_vertex( result: &$crate::algorithms::DijkstraResult< <$T as $crate::traits::GraphTopology>::Vertex, >, v: <$T as $crate::traits::GraphTopology>::Vertex, ) { assert_distances_single_vertex(&result.distances, v); assert_eq!( result.predecessors[v], None, "unexpected predecessor of source vertex", ); } fn assert_distances_single_vertex( distances: &$crate::maps::EntityMap< <$T as $crate::traits::GraphTopology>::Vertex, Option, >, v: <$T as $crate::traits::GraphTopology>::Vertex, ) { assert_eq!( distances[v], Some(0), "unexpected distance of source vertex" ); } fn assert_disconnected( result: &$crate::algorithms::DijkstraResult< <$T as $crate::traits::GraphTopology>::Vertex, >, vertices: &[<$T as $crate::traits::GraphTopology>::Vertex], ) { assert_distances_disconnected(&result.distances, &vertices); for &v in vertices { assert_eq!( result.predecessors[v], None, "unexpected predecessor of disconnected vertex {v:?}", ); } } fn assert_distances_disconnected( distances: &$crate::maps::EntityMap< <$T as $crate::traits::GraphTopology>::Vertex, Option, >, vertices: &[<$T as $crate::traits::GraphTopology>::Vertex], ) { for &v in vertices { assert_eq!( distances[v], None, "unexpected distance of disconnected vertex {v:?}", ); } } fn assert_test_graph( result: &$crate::algorithms::DijkstraResult< <$T as $crate::traits::GraphTopology>::Vertex, >, vertices: &[<$T as $crate::traits::GraphTopology>::Vertex], ) { assert_distances_test_graph(&result.distances, &vertices); let expected_predecessors_from_v0 = [ vec![None], vec![Some(vertices[0])], vec![Some(vertices[4])], vec![Some(vertices[1])], vec![Some(vertices[7])], vec![Some(vertices[9])], vec![Some(vertices[3])], vec![Some(vertices[9])], vec![Some(vertices[7])], vec![Some(vertices[6])], ]; for i in 0..10 { assert!( expected_predecessors_from_v0[i].contains(&result.predecessors[vertices[i]]), "unexpected predecessor {:?} of {:?}", result.predecessors[vertices[i]], vertices[i] ); } } fn assert_distances_test_graph( distances: &$crate::maps::EntityMap< <$T as $crate::traits::GraphTopology>::Vertex, Option, >, vertices: &[<$T as $crate::traits::GraphTopology>::Vertex], ) { let expected_distances_from_v0 = [ Some(0), Some(1), Some(65), Some(4), Some(58), Some(43), Some(14), Some(46), Some(145), Some(29), ]; for i in 0..10 { assert_eq!( distances[vertices[i]], expected_distances_from_v0[i], "unexpected distance from {:?} to {:?}", vertices[0], vertices[i] ); } } fn assert_unweighted_test_graph( result: &$crate::algorithms::DijkstraResult< <$T as $crate::traits::GraphTopology>::Vertex, >, vertices: &[<$T as $crate::traits::GraphTopology>::Vertex], ) { assert_distances_unweighted_test_graph(&result.distances, &vertices); let expected_predecessors_from_v0 = [ vec![None], vec![Some(vertices[0])], vec![Some(vertices[1])], vec![Some(vertices[1])], vec![Some(vertices[1])], vec![Some(vertices[2])], vec![Some(vertices[2]), Some(vertices[3])], vec![Some(vertices[4])], vec![Some(vertices[4])], vec![Some(vertices[5]), Some(vertices[6]), Some(vertices[7])], ]; for i in 0..10 { assert!( expected_predecessors_from_v0[i].contains(&result.predecessors[vertices[i]]), "unexpected predecessor {:?} of {:?}", result.predecessors[vertices[i]], vertices[i] ); } } fn assert_distances_unweighted_test_graph( distances: &$crate::maps::EntityMap< <$T as $crate::traits::GraphTopology>::Vertex, Option, >, vertices: &[<$T as $crate::traits::GraphTopology>::Vertex], ) { let expected_distances_from_v0 = [ Some(0), Some(1), Some(2), Some(2), Some(2), Some(3), Some(3), Some(3), Some(3), Some(4), ]; for i in 0..10 { assert_eq!( distances[vertices[i]], expected_distances_from_v0[i], "unexpected distance from {:?} to {:?}", vertices[0], vertices[i] ); } } fn make_test_graph_weighted() -> ( $T, [<$T as $crate::traits::GraphTopology>::Vertex; 10], [( <$T as $crate::traits::GraphTopology>::Edge, <$T as $crate::traits::GraphTopology>::Vertex, <$T as $crate::traits::GraphTopology>::Vertex, ); 18], [Vec< $crate::traits::Incidence< <$T as $crate::traits::GraphTopology>::Vertex, <$T as $crate::traits::GraphTopology>::Edge, >, >; 10], $crate::maps::EntityMap<<$T as $crate::traits::GraphTopology>::Edge, u32>, ) { use $crate::traits::GraphTopology; let (graph, vertices, edges, incidences) = make_test_graph(); let mut weights = graph.edge_map(99_u32); for i in [1, 3, 7, 10, 12, 14, 15, 17] { weights[edges[i].0] = i.try_into().unwrap(); } (graph, vertices, edges, incidences, weights) } }; }