From 6e9867a65ecfe1a2847284de1483a56680672c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Tue, 5 May 2026 22:54:33 +0200 Subject: [PATCH] Add GraphTopology::edges() and tests --- src/models/append_graph.rs | 4 + src/models/graph.rs | 7 ++ src/testing/graph_topology_testing.rs | 113 +++++++++++++++++++------- src/traits.rs | 2 +- 4 files changed, 97 insertions(+), 29 deletions(-) diff --git a/src/models/append_graph.rs b/src/models/append_graph.rs index 03e7904..7ee75c3 100644 --- a/src/models/append_graph.rs +++ b/src/models/append_graph.rs @@ -102,6 +102,10 @@ impl GraphTopology for AppendGraph { } } + fn edges(&self) -> impl Iterator { + (0..self.incidences.len()).step_by(2).map(Incidence) + } + fn add_vertex(&mut self) -> Self::Vertex { self.vertices.push(VertexIncidenceHeader { incidence_count: 0, diff --git a/src/models/graph.rs b/src/models/graph.rs index 6a69bca..d3110cf 100644 --- a/src/models/graph.rs +++ b/src/models/graph.rs @@ -181,6 +181,13 @@ impl GraphTopology for Graph { } } + fn edges(&self) -> impl Iterator { + self.incidences + .iter() + .filter(|(i, _)| i.arr_idx() % 2 == 0) + .map(|(i, _)| i) + } + fn add_vertex(&mut self) -> Self::Vertex { self.vertices.insert(VertexIncidenceHeader { incidence_count: 0, diff --git a/src/testing/graph_topology_testing.rs b/src/testing/graph_topology_testing.rs index bf864f0..51131ae 100644 --- a/src/testing/graph_topology_testing.rs +++ b/src/testing/graph_topology_testing.rs @@ -2,29 +2,35 @@ #[macro_export] macro_rules! graph_topology_test_fixtures { ($T:ty) => { - fn make_test_graph() -> ($T, [<$T as $crate::traits::GraphTopology>::Vertex; 10]) { + fn make_test_graph() -> ( + $T, + [<$T as $crate::traits::GraphTopology>::Vertex; 10], + [<$T as $crate::traits::GraphTopology>::Edge; 18], + ) { let mut graph = <$T>::new(); let vertices: [<$T as $crate::traits::GraphTopology>::Vertex; 10] = core::array::from_fn(|_| graph.add_vertex()); - graph.add_edge(vertices[0], vertices[1]); - graph.add_edge(vertices[0], vertices[1]); - graph.add_edge(vertices[1], vertices[2]); - graph.add_edge(vertices[1], vertices[3]); - graph.add_edge(vertices[1], vertices[4]); - graph.add_edge(vertices[2], vertices[2]); - graph.add_edge(vertices[2], vertices[4]); - graph.add_edge(vertices[2], vertices[4]); - graph.add_edge(vertices[2], vertices[5]); - graph.add_edge(vertices[2], vertices[6]); - graph.add_edge(vertices[3], vertices[6]); - graph.add_edge(vertices[4], vertices[4]); - graph.add_edge(vertices[4], vertices[7]); - graph.add_edge(vertices[4], vertices[8]); - graph.add_edge(vertices[5], vertices[9]); - graph.add_edge(vertices[6], vertices[9]); - graph.add_edge(vertices[7], vertices[8]); - graph.add_edge(vertices[7], vertices[9]); - (graph, vertices) + let edges = [ + graph.add_edge(vertices[0], vertices[1]), + graph.add_edge(vertices[0], vertices[1]), + graph.add_edge(vertices[1], vertices[2]), + graph.add_edge(vertices[1], vertices[3]), + graph.add_edge(vertices[1], vertices[4]), + graph.add_edge(vertices[2], vertices[2]), + graph.add_edge(vertices[2], vertices[4]), + graph.add_edge(vertices[2], vertices[4]), + graph.add_edge(vertices[2], vertices[5]), + graph.add_edge(vertices[2], vertices[6]), + graph.add_edge(vertices[3], vertices[6]), + graph.add_edge(vertices[4], vertices[4]), + graph.add_edge(vertices[4], vertices[7]), + graph.add_edge(vertices[4], vertices[8]), + graph.add_edge(vertices[5], vertices[9]), + graph.add_edge(vertices[6], vertices[9]), + graph.add_edge(vertices[7], vertices[8]), + graph.add_edge(vertices[7], vertices[9]), + ]; + (graph, vertices, edges) } }; } @@ -48,7 +54,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"); } @@ -69,7 +75,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"); } @@ -82,7 +88,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!( @@ -118,7 +124,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", @@ -172,7 +178,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. @@ -198,7 +204,7 @@ macro_rules! graph_topology_tests { #[test] fn neighbors() { - let (graph, vertices) = make_test_graph(); + let (graph, vertices, _) = make_test_graph(); // Checks neighbors of vertex 4. assert_eq!( graph.neighbors(vertices[4]).count(), @@ -233,6 +239,31 @@ 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() { let mut graph = <$T>::new(); @@ -369,7 +400,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, @@ -556,7 +587,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(), @@ -583,5 +614,31 @@ macro_rules! graph_topology_deletion_tests { ); } } + + #[test] + fn edges_after_delete() { + 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!( + graph.edges().count(), + 12, + "unexpected edge iterator count after delete" + ); + for i in [2, 5, 6, 7, 8, 9] { + assert!( + !graph.edges().any(|e| e == edges[i]), + "deleted edge {:?} appeared in iterator", + edges[i] + ); + } + for i in [0, 1, 3, 4, 10, 11, 12, 13, 14, 15, 16, 17] { + assert!( + graph.edges().any(|e| e == edges[i]), + "expected edge {:?} missing from iterator after delete", + edges[i] + ); + } + } }; } diff --git a/src/traits.rs b/src/traits.rs index a767df0..a1eb4f5 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,5 +1,4 @@ // TODO: Add functions to reserve memory for vertices and edges. -// TODO: Add iterator of all edges. // TODO: Add iterator of incident edges for a vertex. // TODO: Add finding incident vertices for an edge. // TODO: Split out GraphTopologyAddition trait. @@ -13,6 +12,7 @@ pub trait GraphTopology { fn are_adjacent(&self, v1: Self::Vertex, v2: Self::Vertex) -> bool; fn vertices(&self) -> impl Iterator; fn neighbors(&self, v: Self::Vertex) -> impl Iterator; + fn edges(&self) -> impl Iterator; fn add_vertex(&mut self) -> Self::Vertex; fn add_edge(&mut self, v1: Self::Vertex, v2: Self::Vertex) -> Self::Edge; }