use std::fmt::Debug; use crate::testing::fixtures::MakeTestGraph; use crate::traits::{Incidence, IncidenceCursor}; #[doc(hidden)] #[macro_export] macro_rules! graph_topology_tests { ($T:ty) => { $crate::graph_topology_tests!(@wrap $T, vertex_count_empty, vertex_count, vertex_map, edge_count_empty, edge_count, edge_map, degree_zero, degree, loop_edge, multiple_edges, are_adjacent_vertex_self, are_adjacent_single_edge, are_adjacent, vertices_empty, vertices, adjacent_vertices_empty, adjacent_vertices, adjacent_vertices_loop_edge, adjacent_vertices_multiple_edges, incident_vertices_single_edge, incident_vertices_loop_edge, incident_vertices_multiple_edges, incident_vertices, edges_empty, edges, incident_edges_empty, incident_edges, incident_edges_loop_edge, incident_edges_multiple_edges, incidences_empty, incidences, incidences_edge_consistency, incidences_loop_edge, incidences_multiple_edges, incidence_cursor_empty, incidence_cursor, incidence_cursor_loop_edge, incidence_cursor_multiple_edges, incidence_cursor_copy, incident_vertices_incidences_consistency, incident_edges_incidences_consistency, common_neighbors, common_neighbors_same_vertex, common_neighbors_single, common_neighbors_disconnected, common_neighbors_multiple_edges, common_neighbors_loop_edge, ); }; (@wrap $T:ty, $($name:ident),* $(,)?) => { $( #[test] fn $name() { $crate::testing::graph_topology_testing::$name::<$T>(); } )* }; } pub fn vertex_count_empty() { let graph = G::empty(); assert_eq!(graph.vertex_count(), 0, "unexpected vertex count"); } pub fn vertex_count() { let (graph, _, _, _) = G::standard(); assert_eq!(graph.vertex_count(), 10, "unexpected vertex count"); } pub fn vertex_map() where G::Vertex: Debug, { let (graph, vertices, _, _) = G::standard(); let mut map = graph.vertex_map(88); for (i, &v) in vertices.iter().enumerate() { assert_eq!( map[v], 88, "unexpected value from default map read for vertex {v:?}" ); map[v] = i; } for (i, &v) in vertices.iter().enumerate() { assert_eq!(map[v], i, "unexpected value after write for vertex {v:?}"); } } pub fn edge_count_empty() { let graph = G::empty(); assert_eq!(graph.edge_count(), 0, "unexpected edge count"); } pub fn edge_count() { let (graph, _, _, _) = G::standard(); assert_eq!(graph.edge_count(), 18, "unexpected edge count"); } pub fn edge_map() where G::Edge: Debug, { let (graph, _, edges, _) = G::standard(); let mut map = graph.edge_map(99); for (i, &(e, _, _)) in edges.iter().enumerate() { assert_eq!( map[e], 99, "unexpected value from default map read for edge {e:?}" ); map[e] = i; } for (i, &(e, _, _)) in edges.iter().enumerate() { assert_eq!(map[e], i, "unexpected value after write for edge {e:?}"); } } pub fn degree_zero() { let (graph, v) = G::single_vertex(); assert_eq!(graph.degree(v), 0, "unexpected non-zero degree"); } pub fn degree() where G::Vertex: Debug, { let (graph, vertices, _, _) = G::standard(); let expected = [2, 5, 7, 2, 7, 2, 3, 3, 2, 3]; assert_eq!(vertices.len(), expected.len()); for (&v, &exp) in vertices.iter().zip(&expected) { assert_eq!(graph.degree(v), exp, "unexpected degree of {v:?}"); } } pub fn loop_edge() { let (graph, v, _) = G::loop_edge(); assert_eq!(graph.vertex_count(), 1, "unexpected vertex count"); assert_eq!(graph.edge_count(), 1, "unexpected edge count"); assert_eq!(graph.degree(v), 2, "unexpected degree"); assert!( graph.are_adjacent(v, v), "vertex with loop edge should be adjacent to itself" ); } pub fn multiple_edges() where G::Vertex: Debug, { const K: usize = 3; let (graph, [v0, v1], _) = G::multiple_edges::(); assert_eq!(graph.vertex_count(), 2, "unexpected vertex count"); assert_eq!(graph.edge_count(), K, "unexpected edge count"); assert_eq!(graph.degree(v0), K, "unexpected degree of vertex {v0:?}"); assert_eq!(graph.degree(v1), K, "unexpected degree of vertex {v1:?}",); assert!(graph.are_adjacent(v0, v1), "should be adjacent"); } pub fn are_adjacent_vertex_self() { let (graph, v) = G::single_vertex(); assert!( !graph.are_adjacent(v, v), "should not be adjacent to itself" ); } pub fn are_adjacent_single_edge() { let (graph, [v0, v1], _) = G::single_edge(); assert!(graph.are_adjacent(v0, v1), "should be adjacent"); assert!(graph.are_adjacent(v1, v0), "should be adjacent"); } pub fn are_adjacent() where G::Vertex: Debug, { let (graph, vertices, _, _) = G::standard(); assert!( graph.are_adjacent(vertices[0], vertices[1]), "expected {:?} and {:?} to be adjacent", vertices[0], vertices[1] ); assert!( graph.are_adjacent(vertices[9], vertices[5]), "expected {:?} and {:?} to be adjacent", vertices[9], vertices[5] ); assert!( !graph.are_adjacent(vertices[9], vertices[3]), "unexpected adjacency of {:?} and {:?}", vertices[9], vertices[3] ); for (i, &v) in vertices.iter().enumerate() { let exp = matches!(i, 1 | 2 | 4 | 5 | 6); assert_eq!( graph.are_adjacent(vertices[2], v), exp, "unexpected adjacency of {:?} and {v:?}", vertices[2] ); assert_eq!( graph.are_adjacent(v, vertices[2]), exp, "unexpected adjacency of {v:?} and {:?}", vertices[2] ); } } pub fn vertices_empty() { let graph = G::empty(); assert_eq!( graph.vertices().count(), 0, "vertex iterator of empty graph should have no elements" ); } pub fn vertices() where G::Vertex: Debug, { let (graph, vertices, _, _) = G::standard(); assert_eq!(graph.vertices().count(), 10, "unexpected vertex count"); for v in graph.vertices() { assert_eq!( vertices.iter().filter(|&x| *x == v).count(), 1, "unexpected vertex {v:?} from iterator" ); } } pub fn adjacent_vertices_empty() { let (graph, v) = G::single_vertex(); assert_eq!( graph.adjacent_vertices(v).count(), 0, "adjacent vertex iterator of vertex with degree 0 should have no elements" ); } pub fn adjacent_vertices() where G::Vertex: Debug, { let (graph, vertices, _, _) = G::standard(); assert_eq!( graph.adjacent_vertices(vertices[4]).count(), 7, "unexpected adjacency count" ); let mut expected_adjacency = vec![ vertices[1], vertices[2], vertices[2], vertices[4], vertices[4], vertices[7], vertices[8], ]; for v in graph.adjacent_vertices(vertices[4]) { let i = expected_adjacency .iter() .position(|w| *w == v) .unwrap_or_else(|| { panic!( "unexpected adjacent vertex {v:?} of {:?} from iterator", vertices[4] ) }); expected_adjacency.swap_remove(i); } assert_eq!( expected_adjacency.len(), 0, "expected adjacent vertices {expected_adjacency:?} of {:?} were not matched by iterator", vertices[4] ); } pub fn adjacent_vertices_loop_edge() where G::Vertex: Debug, { let (graph, v, _) = G::loop_edge(); let mut iter = graph.adjacent_vertices(v); assert_eq!(iter.next(), Some(v), "vertex should be adjacent to itself"); assert_eq!( iter.next(), Some(v), "vertex should be adjacent to itself twice" ); assert_eq!( iter.next(), None, "too many adjacent vertices from iterator" ); } pub fn adjacent_vertices_multiple_edges() where G::Vertex: Debug, { const K: usize = 3; let (graph, vertices, _) = G::multiple_edges::(); for (i, &v) in vertices.iter().enumerate() { let mut iter = graph.adjacent_vertices(v); for j in 0..K { assert_eq!( iter.next(), Some(vertices[1 - i]), "unexpected adjacent vertex {j} of vertex {v:?}" ); } assert_eq!( iter.next(), None, "too many adjacent vertices of vertex {v:?} from iterator" ); } } pub fn incident_vertices_single_edge() where G::Vertex: Debug, G::Edge: Debug, { let (graph, [v0, v1], e) = G::single_edge(); let (u0, u1) = graph.incident_vertices(e); assert!( (u0 == v0 && u1 == v1) || (u0 == v1 && u1 == v0), "unexpected incident vertices {u0:?} and {u1:?} for edge {e:?}" ); } pub fn incident_vertices_loop_edge() where G::Vertex: Debug, G::Edge: Debug, { let (graph, v, e) = G::loop_edge(); assert_eq!( graph.incident_vertices(e), (v, v), "unexpected incident vertices for loop edge {e:?}" ); } pub fn incident_vertices_multiple_edges() where G::Vertex: Debug, G::Edge: Debug, { let (graph, [v0, v1], edges) = G::multiple_edges::<2>(); assert_ne!(edges[0], edges[1], "edges should be distinct"); for (i, &e) in edges.iter().enumerate() { let (u0, u1) = graph.incident_vertices(e); assert!( (u0 == v0 && u1 == v1) || (u0 == v1 && u1 == v0), "unexpected incident vertices {u0:?} and {u1:?} for multi-edge {e:?} (index {i})" ); } } pub fn incident_vertices() where G::Vertex: Debug, G::Edge: Debug, { let (graph, _, edges, _) = G::standard(); for &(e, v0, v1) in edges.iter() { let (u0, u1) = graph.incident_vertices(e); assert!( (u0 == v0 && u1 == v1) || (u0 == v1 && u1 == v0), "unexpected incident vertices {u0:?} and {u1:?} for edge {e:?}" ); } } pub fn edges_empty() { let graph = G::empty(); assert_eq!( graph.edges().count(), 0, "edge iterator of empty graph should have no elements" ); } pub fn edges() where G::Edge: Debug, { let (graph, _, edges, _) = G::standard(); assert_eq!(graph.edges().count(), 18, "unexpected edge count"); for e in graph.edges() { assert_eq!( edges.iter().filter(|&&(f, _, _)| f == e).count(), 1, "unexpected edge {e:?} from iterator" ); } } pub fn incident_edges_empty() { let (graph, v) = G::single_vertex(); assert_eq!( graph.incident_edges(v).count(), 0, "incident edge iterator of vertex with degree 0 should have no elements" ); } pub fn incident_edges() where G::Vertex: Debug, G::Edge: Debug, { let (graph, vertices, _, incidences) = G::standard(); assert_eq!(vertices.len(), incidences.len()); for (&v, incs) in vertices.iter().zip(&incidences) { assert_eq!( graph.incident_edges(v).count(), incs.len(), "unexpected incident edge count for vertex {v:?}" ); let mut expected: Vec<_> = incs.iter().map(|x| x.edge).collect(); for e in graph.incident_edges(v) { let pos = expected.iter().position(|&f| f == e).unwrap_or_else(|| { panic!("unexpected incident edge {e:?} of vertex {v:?} from iterator") }); expected.swap_remove(pos); } assert!( expected.is_empty(), "expected incident edges {expected:?} of vertex {v:?} were not matched by iterator" ); } } pub fn incident_edges_loop_edge() where G::Edge: Debug, { let (graph, v, e) = G::loop_edge(); let mut iter = graph.incident_edges(v); assert_eq!( iter.next(), Some(e), "loop edge should appear in incident edges" ); assert_eq!( iter.next(), Some(e), "loop edge should appear twice in incident edges" ); assert_eq!(iter.next(), None, "too many incident edges from iterator"); } pub fn incident_edges_multiple_edges() where G::Vertex: Debug, G::Edge: Debug, { const K: usize = 3; let (graph, vertices, edges) = G::multiple_edges::(); for &v in &vertices { let mut expected = edges.to_vec(); for e in graph.incident_edges(v) { let pos = expected .iter() .position(|&f| f == e) .unwrap_or_else(|| panic!("unexpected incident edge {e:?} of vertex {v:?}")); expected.swap_remove(pos); } assert!( expected.is_empty(), "expected incident edges {expected:?} of vertex {v:?} were not matched by iterator" ); } } pub fn incidences_empty() { let (graph, v) = G::single_vertex(); assert_eq!( graph.incidences(v).count(), 0, "incidence iterator of vertex with degree 0 should have no elements" ); } pub fn incidences() where G::Vertex: Debug, G::Edge: Debug, { let (graph, vertices, _, incidences) = G::standard(); assert_eq!(vertices.len(), incidences.len()); for (&v, incs) in vertices.iter().zip(&incidences) { assert_eq!( graph.incidences(v).count(), incs.len(), "unexpected incidence count for vertex {v:?}" ); let mut expected = incs.clone(); for incidence in graph.incidences(v) { let pos = expected .iter() .position(|&x| x == incidence) .unwrap_or_else(|| { panic!("unexpected incidence {incidence:?} of vertex {v:?} from iterator") }); expected.swap_remove(pos); } assert!( expected.is_empty(), "expected incidences {expected:?} of vertex {v:?} were not matched by iterator" ); } } pub fn incidences_edge_consistency() where G::Vertex: Debug, G::Edge: Debug, { let (graph, _, _, _) = G::standard(); for u in graph.vertices() { for incidence in graph.incidences(u) { if u == incidence.vertex { assert_eq!( graph .incidences(u) .filter(|x| x.edge == incidence.edge) .count(), 2, "loop edge {:?} should appear exactly twice in incidences of vertex {u:?}", incidence.edge ); } else { assert!( graph .incidences(incidence.vertex) .any(|x| x.vertex == u && x.edge == incidence.edge), "edge {:?} from incidences of vertex {u:?} missing in incidences of \ adjacent vertex {:?}", incidence.edge, incidence.vertex ); } } } } pub fn incidences_loop_edge() where G::Vertex: Debug, G::Edge: Debug, { let (graph, v, e) = G::loop_edge(); let mut iter = graph.incidences(v); assert_eq!( iter.next(), Some(Incidence { vertex: v, edge: e }), "vertex should be adjacent to itself" ); assert_eq!( iter.next(), Some(Incidence { vertex: v, edge: e }), "vertex should be adjacent to itself twice" ); assert_eq!( iter.next(), None, "too many adjacent vertices from iterator" ); } pub fn incidences_multiple_edges() where G::Vertex: Debug, G::Edge: Debug, { const K: usize = 3; let (graph, vertices, edges) = G::multiple_edges::(); for (i, &v) in vertices.iter().enumerate() { let mut iter = graph.incidences(v); for j in 0..K { let current = iter.next().unwrap_or_else(|| { panic!("incidence {j} missing, expected {K} incidences for vertex {v:?}") }); assert_eq!( current.vertex, vertices[1 - i], "unexpected adjacent vertex of vertex {v:?} in incidence {j}" ); assert_eq!( edges.iter().filter(|&&e| e == current.edge).count(), 1, "unexpected incident edge {:?} of vertex {v:?}", current.edge ); } assert_eq!( iter.next(), None, "too many adjacent vertices of {v:?} from iterator" ); } } pub fn incidence_cursor_empty() where G::Vertex: Debug, G::Edge: Debug, { let (graph, v) = G::single_vertex(); let mut cursor = graph.incidence_cursor(v); assert_eq!( cursor.next(&graph), None, "incidence cursor of vertex with degree 0 should immediately be exhausted" ); } pub fn incidence_cursor() where G::Vertex: Debug, G::Edge: Debug, { let (graph, vertices, _, incidences) = G::standard(); assert_eq!(vertices.len(), incidences.len()); for (&v, incs) in vertices.iter().zip(&incidences) { let mut expected = incs.clone(); let mut cursor = graph.incidence_cursor(v); while let Some(incidence) = cursor.next(&graph) { let pos = expected .iter() .position(|&x| x == incidence) .unwrap_or_else(|| { panic!("unexpected incidence {incidence:?} of vertex {v:?} from cursor") }); expected.swap_remove(pos); } assert!( expected.is_empty(), "expected incidences {expected:?} of vertex {v:?} were not matched by cursor" ); } } pub fn incidence_cursor_loop_edge() where G::Vertex: Debug, G::Edge: Debug, { let (graph, v, e) = G::loop_edge(); let mut cursor = graph.incidence_cursor(v); assert_eq!( cursor.next(&graph), Some(Incidence { vertex: v, edge: e }), "vertex should be adjacent to itself" ); assert_eq!( cursor.next(&graph), Some(Incidence { vertex: v, edge: e }), "vertex should be adjacent to itself twice" ); assert_eq!(cursor.next(&graph), None, "too many incidences from cursor"); } pub fn incidence_cursor_multiple_edges() where G::Vertex: Debug, G::Edge: Debug, { const K: usize = 3; let (graph, vertices, edges) = G::multiple_edges::(); for (i, &v) in vertices.iter().enumerate() { let mut cursor = graph.incidence_cursor(v); for j in 0..K { let current = cursor.next(&graph).unwrap_or_else(|| { panic!("incidence {j} missing, expected {K} incidences for vertex {v:?}") }); assert_eq!( current.vertex, vertices[1 - i], "unexpected adjacent vertex of vertex {v:?} in incidence {j}" ); assert_eq!( edges.iter().filter(|&&e| e == current.edge).count(), 1, "unexpected incident edge {:?} of vertex {v:?}", current.edge ); } assert_eq!( cursor.next(&graph), None, "too many incidences of {v:?} from cursor" ); } } pub fn incidence_cursor_copy() { let (graph, [_, v, _], _) = G::two_edge_path(); let mut c1 = graph.incidence_cursor(v); assert!(c1.next(&graph).is_some(), "expected first incidence"); let mut c2 = c1; assert!( c1.next(&graph).is_some(), "expected second incidence from original cursor" ); assert!( c1.next(&graph).is_none(), "expected original cursor to be exhausted" ); assert!( c2.next(&graph).is_some(), "expected second incidence from copied cursor" ); assert!( c2.next(&graph).is_none(), "expected copied cursor to be exhausted" ); } pub fn incident_vertices_incidences_consistency() where G::Vertex: Debug, G::Edge: Debug, { let (graph, _, _, _) = G::standard(); for u in graph.vertices() { for incidence in graph.incidences(u) { let (w1, w2) = graph.incident_vertices(incidence.edge); assert!( (w1 == u && w2 == incidence.vertex) || (w1 == incidence.vertex && w2 == u), "edge endpoints {w1:?} and {w2:?} are inconsistent with incidence \ ({:?}, {:?}) of vertex {u:?}", incidence.vertex, incidence.edge ); } } } pub fn incident_edges_incidences_consistency() where G::Vertex: Debug, G::Edge: Debug, { let (graph, _, _, _) = G::standard(); for u in graph.vertices() { let mut expected: Vec<_> = graph.incidences(u).map(|x| x.edge).collect(); for e in graph.incident_edges(u) { let pos = expected.iter().position(|&f| f == e).unwrap_or_else(|| { panic!("incident edge {e:?} of vertex {u:?} missing from incidences") }); expected.swap_remove(pos); } assert!( expected.is_empty(), "incidence edges {expected:?} of vertex {u:?} not matched by incident_edges" ); } } pub fn common_neighbors() where G::Vertex: Debug, { let (graph, vertices, _, _) = G::standard(); // Pairs of vertex indices with the indices of their expected common neighbors. let cases: [(usize, usize, &[usize]); _] = [ (0, 3, &[1]), (1, 6, &[2, 3]), (5, 8, &[]), (2, 9, &[5, 6]), (7, 3, &[]), (0, 1, &[]), (6, 7, &[9]), // Loop only on one side, adjacent. (2, 6, &[2]), // Loop only on one side, not adjacent. (2, 7, &[4]), // Adjacent through a double edge, and both have a loop. (2, 4, &[1, 2, 4]), ]; for (i, j, expected) in cases { let expected: Vec<_> = expected.iter().map(|&k| vertices[k]).collect(); assert_common_neighbors(&graph, vertices[i], vertices[j], &expected); } } pub fn common_neighbors_same_vertex() where G::Vertex: Debug, { let (graph, vertices, _, _) = G::standard(); // Vertex 1 has a double edge to vertex 0, but no loop. assert_common_neighbors( &graph, vertices[1], vertices[1], &[vertices[0], vertices[2], vertices[3], vertices[4]], ); // Vertex 4 has a loop, and is therefore its own common neighbor with itself. assert_common_neighbors( &graph, vertices[4], vertices[4], &[ vertices[1], vertices[2], vertices[4], vertices[7], vertices[8], ], ); } pub fn common_neighbors_single() where G::Vertex: Debug, { let (graph, v) = G::single_vertex(); assert_common_neighbors(&graph, v, v, &[]); } pub fn common_neighbors_disconnected() where G::Vertex: Debug, { let (graph, v) = G::disconnected(); assert_common_neighbors(&graph, v[0], v[0], &[]); assert_common_neighbors(&graph, v[0], v[1], &[]); } pub fn common_neighbors_multiple_edges() where G::Vertex: Debug, { let (graph, [v0, v1], _) = G::multiple_edges::<3>(); assert_common_neighbors(&graph, v0, v1, &[]); assert_common_neighbors(&graph, v1, v1, &[v0]); } pub fn common_neighbors_loop_edge() where G::Vertex: Debug, { let (graph, v, _) = G::loop_edge(); assert_common_neighbors(&graph, v, v, &[v]); } /// Asserts that `u` and `v` have exactly the `expected` common neighbors, each yielded once, for /// both argument orders. fn assert_common_neighbors( graph: &G, u: G::Vertex, v: G::Vertex, expected: &[G::Vertex], ) where G::Vertex: Debug, { for (a, b) in [(u, v), (v, u)] { let mut remaining = expected.to_vec(); for w in graph.common_neighbors(a, b) { let pos = remaining.iter().position(|&x| x == w).unwrap_or_else(|| { panic!( "unexpected or repeated common neighbor {w:?} of vertices {a:?} and {b:?} from iterator" ) }); remaining.swap_remove(pos); } assert!( remaining.is_empty(), "expected common neighbors {remaining:?} of vertices {a:?} and {b:?} were not matched by iterator" ); } }