Add GraphTopology::incidences(), update and add related tests

This commit is contained in:
2026-05-08 13:12:23 +02:00
parent d3fcd690a5
commit 0bcd270d12
4 changed files with 378 additions and 63 deletions
+317 -61
View File
@@ -6,6 +6,10 @@ macro_rules! graph_topology_test_fixtures {
$T,
[<$T as $crate::traits::GraphTopology>::Vertex; 10],
[<$T as $crate::traits::GraphTopology>::Edge; 18],
[Vec<(
<$T as $crate::traits::GraphTopology>::Vertex,
<$T as $crate::traits::GraphTopology>::Edge,
)>; 10],
) {
let mut graph = <$T>::new();
let vertices: [<$T as $crate::traits::GraphTopology>::Vertex; 10] =
@@ -30,7 +34,53 @@ macro_rules! graph_topology_test_fixtures {
graph.add_edge(vertices[7], vertices[8]),
graph.add_edge(vertices[7], vertices[9]),
];
(graph, vertices, edges)
let incidences: [Vec<_>; 10] = [
vec![(vertices[1], edges[0]), (vertices[1], edges[1])],
vec![
(vertices[0], edges[0]),
(vertices[0], edges[1]),
(vertices[2], edges[2]),
(vertices[3], edges[3]),
(vertices[4], edges[4]),
],
vec![
(vertices[2], edges[5]),
(vertices[2], edges[5]),
(vertices[1], edges[2]),
(vertices[4], edges[6]),
(vertices[4], edges[7]),
(vertices[5], edges[8]),
(vertices[6], edges[9]),
],
vec![(vertices[1], edges[3]), (vertices[6], edges[10])],
vec![
(vertices[1], edges[4]),
(vertices[2], edges[6]),
(vertices[2], edges[7]),
(vertices[4], edges[11]),
(vertices[4], edges[11]),
(vertices[7], edges[12]),
(vertices[8], edges[13]),
],
vec![(vertices[2], edges[8]), (vertices[9], edges[14])],
vec![
(vertices[2], edges[9]),
(vertices[3], edges[10]),
(vertices[9], edges[15]),
],
vec![
(vertices[4], edges[12]),
(vertices[8], edges[16]),
(vertices[9], edges[17]),
],
vec![(vertices[4], edges[13]), (vertices[7], edges[16])],
vec![
(vertices[5], edges[14]),
(vertices[6], edges[15]),
(vertices[7], edges[17]),
],
];
(graph, vertices, edges, incidences)
}
};
}
@@ -54,7 +104,7 @@ macro_rules! graph_topology_tests {
#[test]
fn vertex_count() {
let (graph, _, _) = make_test_graph();
let (graph, _, _, _) = make_test_graph();
assert_eq!(graph.vertex_count(), 10, "unexpected vertex count");
}
@@ -75,7 +125,7 @@ macro_rules! graph_topology_tests {
#[test]
fn edge_count() {
let (graph, _, _) = make_test_graph();
let (graph, _, _, _) = make_test_graph();
assert_eq!(graph.edge_count(), 18, "unexpected edge count");
}
@@ -88,7 +138,7 @@ macro_rules! graph_topology_tests {
#[test]
fn degree() {
let (graph, vertices, _) = make_test_graph();
let (graph, vertices, _, _) = make_test_graph();
let expected_degrees = [2, 5, 7, 2, 7, 2, 3, 3, 2, 3];
for i in 0..graph.vertex_count() {
assert_eq!(
@@ -100,6 +150,36 @@ macro_rules! graph_topology_tests {
}
}
#[test]
fn loop_edge() {
let mut graph = <$T>::new();
let v = graph.add_vertex();
graph.add_edge(v, v);
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"
);
}
#[test]
fn multiple_edges() {
let k = 3;
let mut graph = <$T>::new();
let v1 = graph.add_vertex();
let v2 = graph.add_vertex();
for _ in 0..k {
graph.add_edge(v1, v2);
}
assert_eq!(graph.vertex_count(), 2, "unexpected vertex count");
assert_eq!(graph.edge_count(), k, "unexpected edge count");
assert_eq!(graph.degree(v1), k, "unexpected degree of vertex {v1:?}");
assert_eq!(graph.degree(v2), k, "unexpected degree of vertex {v2:?}");
assert!(graph.are_adjacent(v1, v2), "should be adjacent");
}
#[test]
fn are_adjacent_vertex_self() {
let mut graph = <$T>::new();
@@ -124,7 +204,7 @@ macro_rules! graph_topology_tests {
#[test]
fn are_adjacent() {
let (graph, vertices, _) = make_test_graph();
let (graph, vertices, _, _) = make_test_graph();
assert!(
graph.are_adjacent(vertices[0], vertices[1]),
"expected {:?} and {:?} to be adjacent",
@@ -178,7 +258,7 @@ macro_rules! graph_topology_tests {
#[test]
fn vertices() {
let (graph, vertices, _) = make_test_graph();
let (graph, vertices, _, _) = make_test_graph();
assert_eq!(graph.vertices().count(), 10, "unexpected vertex count");
// Expects each vertex to appear exactly once.
@@ -194,9 +274,9 @@ macro_rules! graph_topology_tests {
#[test]
fn adjacent_vertices_empty() {
let mut graph = <$T>::new();
let vertex = graph.add_vertex();
let v = graph.add_vertex();
assert_eq!(
graph.adjacent_vertices(vertex).count(),
graph.adjacent_vertices(v).count(),
0,
"adjacent vertex iterator of vertex with degree 0 should have no elements"
);
@@ -204,7 +284,7 @@ macro_rules! graph_topology_tests {
#[test]
fn adjacent_vertices() {
let (graph, vertices, _) = make_test_graph();
let (graph, vertices, _, _) = make_test_graph();
// Checks adjacency of vertex 4.
assert_eq!(
graph.adjacent_vertices(vertices[4]).count(),
@@ -240,42 +320,10 @@ macro_rules! graph_topology_tests {
}
#[test]
fn edges_empty() {
let graph = <$T>::new();
assert_eq!(
graph.edges().count(),
0,
"edge iterator of empty graph should have no elements"
);
}
#[test]
fn edges() {
let (graph, _, edges) = make_test_graph();
assert_eq!(graph.edges().count(), 18, "unexpected edge count");
// Expects each edge to appear exactly once.
for e in graph.edges() {
assert_eq!(
edges.iter().filter(|&x| *x == e).count(),
1,
"unexpected edge {e:?} from the iterator"
);
}
}
#[test]
fn loop_edge() {
fn adjacent_vertices_loop_edge() {
let mut graph = <$T>::new();
let v = graph.add_vertex();
graph.add_edge(v, v);
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"
);
let mut iter = graph.adjacent_vertices(v);
assert_eq!(iter.next(), Some(v), "vertex should be adjacent to itself");
assert_eq!(
@@ -291,35 +339,172 @@ macro_rules! graph_topology_tests {
}
#[test]
fn multiple_edges() {
fn adjacent_vertices_multiple_edges() {
let k = 3;
let mut graph = <$T>::new();
let vertices = [graph.add_vertex(), graph.add_vertex()];
for _ in 0..k {
graph.add_edge(vertices[0], vertices[1]);
}
assert_eq!(
graph.vertex_count(),
vertices.len(),
"unexpected vertex count"
);
assert_eq!(graph.edge_count(), k, "unexpected edge count");
for v in vertices {
assert_eq!(graph.degree(v), k, "unexpected degree of {v:?}");
}
assert!(
graph.are_adjacent(vertices[0], vertices[1]),
"should be adjacent"
);
for i in 0..2 {
let mut iter = graph.adjacent_vertices(vertices[i]);
for j in 0..k {
assert_eq!(
iter.next(),
Some(vertices[1 - i]),
"adjacent vertex {j} of vertex {:?} should be {:?}",
"unexpected adjacent vertex {j} of vertex {:?}",
vertices[i]
);
}
assert_eq!(
iter.next(),
None,
"too many adjacent vertices of vertex {:?} from iterator",
vertices[i]
);
}
}
#[test]
fn edges_empty() {
let graph = <$T>::new();
assert_eq!(
graph.edges().count(),
0,
"edge iterator of empty graph should have no elements"
);
}
#[test]
fn edges() {
let (graph, _, edges, _) = make_test_graph();
assert_eq!(graph.edges().count(), 18, "unexpected edge count");
// Expects each edge to appear exactly once.
for e in graph.edges() {
assert_eq!(
edges.iter().filter(|&x| *x == e).count(),
1,
"unexpected edge {e:?} from the iterator"
);
}
}
#[test]
fn incidences_empty() {
let mut graph = <$T>::new();
let v = graph.add_vertex();
assert_eq!(
graph.incidences(v).count(),
0,
"incidence iterator of vertex with degree 0 should have no elements"
);
}
#[test]
fn incidences() {
let (graph, vertices, _, incidences) = make_test_graph();
for i in 0..10 {
assert_eq!(
graph.incidences(vertices[i]).count(),
incidences[i].len(),
"unexpected incidence count for vertex {:?}",
vertices[i]
);
let mut remaining = incidences[i].clone();
for incidence in graph.incidences(vertices[i]) {
let pos = remaining
.iter()
.position(|(v, e)| *v == incidence.0 && *e == incidence.1)
.expect(&format!(
"unexpected incidence {incidence:?} of vertex {:?} from the iterator",
vertices[i]
));
remaining.swap_remove(pos);
}
assert!(
remaining.is_empty(),
"expected incidences {:?} of vertex {:?} were not matched by the iterator",
remaining,
vertices[i]
);
}
}
#[test]
fn incidences_edge_consistency() {
// For each incidence (v, e) of u, the same edge e must appear in the incidences of v.
// For loop edges (u == v), the edge must appear exactly twice in the incidences of u.
let (graph, _, _, _) = make_test_graph();
for u in graph.vertices() {
for (v, e) in graph.incidences(u) {
if u == v {
assert_eq!(
graph.incidences(u).filter(|(_, f)| *f == e).count(),
2,
"loop edge {e:?} should appear exactly twice in incidences of vertex {u:?}"
);
} else {
assert!(
graph.incidences(v).any(|(w, f)| w == u && f == e),
"edge {e:?} from incidences of vertex {u:?} missing in incidences of adjacent vertex {v:?}"
);
}
}
}
}
#[test]
fn incidences_loop_edge() {
let mut graph = <$T>::new();
let v = graph.add_vertex();
let e = graph.add_edge(v, v);
let mut iter = graph.incidences(v);
assert_eq!(
iter.next(),
Some((v, e)),
"vertex should be adjacent to itself"
);
assert_eq!(
iter.next(),
Some((v, e)),
"vertex should be adjacent to itself twice"
);
assert_eq!(
iter.next(),
None,
"too many adjacent vertices from iterator"
);
}
#[test]
fn incidences_multiple_edges() {
let k = 3;
let mut graph = <$T>::new();
let vertices = [graph.add_vertex(), graph.add_vertex()];
let mut edges = Vec::new();
for _ in 0..k {
edges.push(graph.add_edge(vertices[0], vertices[1]));
}
for i in 0..2 {
let mut iter = graph.incidences(vertices[i]);
for j in 0..k {
let current = iter.next().expect(&format!(
"incidence {j} missing, expected {k} incidences for vertex {:?}",
vertices[i]
));
assert_eq!(
current.0,
vertices[1 - i],
"unexpected adjacent vertex of vertex {:?} in incidence {j}",
vertices[i]
);
assert_eq!(
edges.iter().filter(|e| **e == current.1).count(),
1,
"unexpected incident edge {:?} of vertex {:?}",
current.1,
vertices[i],
vertices[1 - i]
);
}
assert_eq!(
@@ -400,7 +585,7 @@ macro_rules! graph_topology_deletion_tests {
#[test]
fn delete_vertex_connected() {
let (mut graph, vertices, _) = make_test_graph();
let (mut graph, vertices, _, _) = make_test_graph();
assert_eq!(
graph.vertex_count(),
10,
@@ -587,7 +772,7 @@ macro_rules! graph_topology_deletion_tests {
#[test]
fn vertices_after_delete() {
let (mut graph, vertices, _) = make_test_graph();
let (mut graph, vertices, _, _) = make_test_graph();
graph.delete_vertex(vertices[2]);
assert_eq!(
graph.vertex_count(),
@@ -617,7 +802,7 @@ macro_rules! graph_topology_deletion_tests {
#[test]
fn edges_after_delete() {
let (mut graph, vertices, edges) = make_test_graph();
let (mut graph, vertices, edges, _) = make_test_graph();
graph.delete_vertex(vertices[2]);
assert_eq!(graph.edge_count(), 12, "unexpected edge count after delete");
assert_eq!(
@@ -640,5 +825,76 @@ macro_rules! graph_topology_deletion_tests {
);
}
}
#[test]
fn incidences_after_delete_vertex() {
let (mut graph, vertices, _, incidences) = make_test_graph();
graph.delete_vertex(vertices[2]);
for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] {
let mut remaining: Vec<_> = incidences[i]
.iter()
.filter(|(v, _)| *v != vertices[2])
.cloned()
.collect();
assert_eq!(
graph.incidences(vertices[i]).count(),
remaining.len(),
"unexpected incidence count for vertex {:?} after delete",
vertices[i]
);
for incidence in graph.incidences(vertices[i]) {
let pos = remaining
.iter()
.position(|(v, e)| *v == incidence.0 && *e == incidence.1)
.expect(&format!(
"unexpected incidence {incidence:?} of vertex {:?} after delete",
vertices[i]
));
remaining.swap_remove(pos);
}
assert!(
remaining.is_empty(),
"expected incidences {:?} of vertex {:?} not matched after delete",
remaining,
vertices[i]
);
}
}
#[test]
fn incidences_after_delete_edge() {
let (mut graph, vertices, edges, incidences) = make_test_graph();
// Deletes the edge from vertices[1] to vertices[2].
graph.delete_edge(edges[2]);
for i in 0..10 {
let mut remaining: Vec<_> = incidences[i]
.iter()
.filter(|(_, e)| *e != edges[2])
.cloned()
.collect();
assert_eq!(
graph.incidences(vertices[i]).count(),
remaining.len(),
"unexpected incidence count for vertex {:?} after delete",
vertices[i]
);
for incidence in graph.incidences(vertices[i]) {
let pos = remaining
.iter()
.position(|(v, e)| *v == incidence.0 && *e == incidence.1)
.expect(&format!(
"unexpected incidence {incidence:?} of vertex {:?} after delete",
vertices[i]
));
remaining.swap_remove(pos);
}
assert!(
remaining.is_empty(),
"expected incidences {:?} of vertex {:?} not matched after delete",
remaining,
vertices[i]
);
}
}
};
}