From 8126352c9bd7e1739d8c2041bd91f6980afe4590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Wed, 22 Apr 2026 16:33:05 +0200 Subject: [PATCH] Add Graph as a straight copy of AppendGraph --- src/models.rs | 1 + src/models/graph.rs | 393 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 394 insertions(+) create mode 100644 src/models/graph.rs diff --git a/src/models.rs b/src/models.rs index e53138e..f1601bc 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1 +1,2 @@ pub mod append_graph; +pub mod graph; diff --git a/src/models/graph.rs b/src/models/graph.rs new file mode 100644 index 0000000..2a59bcc --- /dev/null +++ b/src/models/graph.rs @@ -0,0 +1,393 @@ +use crate::traits::GraphTopology; + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Vertex(usize); + +impl From for usize { + fn from(v: Vertex) -> usize { + v.0 + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Incidence(usize); + +struct VertexIncidenceHeader { + incidence_count: usize, + first_incidence: Option, +} + +struct IncidenceEntry { + next: Option, + neighbor: Vertex, +} +struct VertexNeighborIterator<'a> { + graph: &'a Graph, + incidence: Option, +} + +impl<'a> Iterator for VertexNeighborIterator<'a> { + type Item = Vertex; + + fn next(&mut self) -> Option { + let incidence = self.incidence?; + let entry = &self.graph.incidences[incidence.0]; + self.incidence = entry.next; + Some(entry.neighbor) + } +} + +// TODO: Graph cannot support deleting vertices because of the external indices "Vertex". They could be made stable with e.g. slotmap or generational arena. +// TODO: Add function to delete vertices. +// TODO: Add function to delete edges. +pub struct Graph { + // TODO: Index 'vertices' by a 'Vertex' instead of 'Vertex.0'? + vertices: Vec, + incidences: Vec, +} + +impl Graph { + pub fn new() -> Self { + Self { + vertices: vec![], + incidences: vec![], + } + } + + fn add_incidence(&mut self, v1: Vertex, v2: Vertex) { + self.incidences.push(IncidenceEntry { + next: self.vertices[v1.0].first_incidence.take(), + neighbor: v2, + }); + self.vertices[v1.0].incidence_count += 1; + self.vertices[v1.0].first_incidence = Some(Incidence(self.incidences.len() - 1)); + } +} + +impl GraphTopology for Graph { + type Vertex = Vertex; + + type Edge = Incidence; + + fn vertex_count(&self) -> usize { + self.vertices.len() + } + + fn edge_count(&self) -> usize { + self.incidences.len() / 2 + } + + fn degree(&self, v: Self::Vertex) -> usize { + self.vertices[v.0].incidence_count + } + + fn are_adjacent(&self, v1: Self::Vertex, v2: Self::Vertex) -> bool { + self.neighbors(v1).find(|&x| x == v2).is_some() + } + + fn vertices(&self) -> impl Iterator { + (0..self.vertices.len()).map(Vertex) + } + + fn neighbors(&self, v: Self::Vertex) -> impl Iterator { + VertexNeighborIterator { + graph: self, + incidence: self.vertices[v.0].first_incidence, + } + } + + fn add_vertex(&mut self) -> Self::Vertex { + self.vertices.push(VertexIncidenceHeader { + incidence_count: 0, + first_incidence: None, + }); + Vertex(self.vertices.len() - 1) + } + + fn add_edge(&mut self, v1: Self::Vertex, v2: Self::Vertex) -> Self::Edge { + self.add_incidence(v1, v2); + self.add_incidence(v2, v1); + Incidence(self.incidences.len() - 2) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn add_vertex() { + let mut graph = Graph::new(); + let v = graph.add_vertex(); + assert_ne!(graph.add_vertex(), v, "unexpected duplicate vertex"); + } + + #[test] + fn vertex_count_empty() { + let graph = Graph::new(); + assert_eq!(graph.vertex_count(), 0, "unexpected vertex count"); + } + + #[test] + fn vertex_count() { + let (graph, _) = make_test_graph(); + assert_eq!(graph.vertex_count(), 10, "unexpected vertex count"); + } + + #[test] + fn add_edge() { + let mut graph = Graph::new(); + let v1 = graph.add_vertex(); + let v2 = graph.add_vertex(); + let e = graph.add_edge(v1, v2); + assert_ne!(graph.add_edge(v1, v2), e, "unexpected duplicate edge"); + } + + #[test] + fn edge_count_empty() { + let graph = Graph::new(); + assert_eq!(graph.edge_count(), 0, "unexpected edge count"); + } + + #[test] + fn edge_count() { + let (graph, _) = make_test_graph(); + assert_eq!(graph.edge_count(), 14, "unexpected edge count"); + } + + #[test] + fn degree_zero() { + let mut graph = Graph::new(); + let v = graph.add_vertex(); + assert_eq!(graph.degree(v), 0, "unexpected non-zero degree"); + } + + #[test] + fn degree() { + let (graph, vertices) = make_test_graph(); + let expected_degrees = [1, 4, 4, 2, 4, 2, 3, 3, 2, 3]; + for i in 0..graph.vertex_count() { + assert_eq!( + graph.degree(vertices[i]), + expected_degrees[i], + "unexpected degree of {:?}", + vertices[i] + ); + } + } + + #[test] + fn are_adjacent_vertex_self() { + let mut graph = Graph::new(); + let v = graph.add_vertex(); + assert_eq!( + graph.are_adjacent(v, v), + false, + "should not be adjacent to itself" + ); + } + + #[test] + fn are_adjacent_single_edge() { + let mut graph = Graph::new(); + let v1 = graph.add_vertex(); + let v2 = graph.add_vertex(); + assert!(!graph.are_adjacent(v1, v2), "should not be adjacent"); + assert!(!graph.are_adjacent(v2, v1), "should not be adjacent"); + graph.add_edge(v1, v2); + assert!(graph.are_adjacent(v1, v2), "should be adjacent"); + assert!(graph.are_adjacent(v2, v1), "should be adjacent"); + } + + #[test] + fn are_adjacent() { + let (graph, vertices) = make_test_graph(); + 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[0], + vertices[5] + ); + assert!( + !graph.are_adjacent(vertices[9], vertices[3]), + "unexpected adjacency of {:?} and {:?}", + vertices[9], + vertices[3] + ); + + for i in 0..graph.vertex_count() { + let exp = match i { + 2 => continue, + 1 | 4 | 5 | 6 => true, + _ => false, + }; + assert_eq!( + graph.are_adjacent(vertices[2], vertices[i]), + exp, + "unexpected adjacency of {:?} and {:?}", + vertices[2], + vertices[i] + ); + assert_eq!( + graph.are_adjacent(vertices[i], vertices[2]), + exp, + "unexpected adjacency of {:?} and {:?}", + vertices[i], + vertices[2] + ); + } + } + + #[test] + fn vertices_empty() { + let graph = Graph::new(); + assert_eq!( + graph.vertices().count(), + 0, + "vertex iterator of empty graph should have no elements" + ); + } + + #[test] + fn vertices() { + let (graph, vertices) = make_test_graph(); + assert_eq!(graph.vertices().count(), 10, "unexpected vertex count"); + + // Expects each vertex to appear exactly once. + for v in graph.vertices() { + assert_eq!( + vertices.iter().filter(|&x| *x == v).count(), + 1, + "unexpected vertex {v:?} from the iterator" + ); + } + } + + #[test] + fn neighbors_empty() { + let mut graph = Graph::new(); + let vertex = graph.add_vertex(); + assert_eq!( + graph.neighbors(vertex).count(), + 0, + "neighbor iterator of vertex with degree 0 should have no elements" + ); + } + + #[test] + fn neighbors() { + let (graph, vertices) = make_test_graph(); + // Checks neighbors of vertex 4. + assert_eq!( + graph.neighbors(vertices[4]).count(), + 4, + "unexpected vertex count" + ); + + // Expects each neighbor to appear exactly once. This will not work if there are multiple edges. + let neighbors: Vec = vec![vertices[1], vertices[2], vertices[7], vertices[8]]; + for v in graph.neighbors(vertices[4]) { + assert_eq!( + neighbors.iter().filter(|&x| *x == v).count(), + 1, + "unexpected neighbor {v:?} of {:?} from the iterator", + vertices[4] + ); + } + } + + #[test] + fn loop_edge() { + let mut graph = Graph::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_eq!( + graph.are_adjacent(v, v), + true, + "vertex with loop edge should be adjacent to itself" + ); + let mut neighbors = graph.neighbors(v); + assert_eq!( + neighbors.next(), + Some(v), + "vertex should be neighbor of itself" + ); + assert_eq!( + neighbors.next(), + Some(v), + "vertex should be neighbor of itself twice" + ); + assert_eq!(neighbors.next(), None, "two many neighbors from iterator"); + } + + #[test] + fn multiple_edges() { + let mult = 3; + let mut graph = Graph::new(); + let vertices = [graph.add_vertex(), graph.add_vertex()]; + for _ in 0..mult { + graph.add_edge(vertices[0], vertices[1]); + } + assert_eq!( + graph.vertex_count(), + vertices.len(), + "unexpected vertex count" + ); + assert_eq!(graph.edge_count(), mult, "unexpected edge count"); + for v in vertices { + assert_eq!(graph.degree(v), mult, "unexpected degree of {v:?}"); + } + assert_eq!( + graph.are_adjacent(vertices[0], vertices[1]), + true, + "should be adjacent" + ); + for i in 0..2 { + let mut neighbors = graph.neighbors(vertices[i]); + for j in 0..mult { + assert_eq!( + neighbors.next(), + Some(vertices[1 - i]), + "neighbor {j} of vertex {:?} should be {:?}", + vertices[i], + vertices[1 - i] + ); + } + assert_eq!( + neighbors.next(), + None, + "two many neighbors of {:?} from iterator", + vertices[i] + ); + } + } + + fn make_test_graph() -> (Graph, [Vertex; 10]) { + let mut graph = Graph::new(); + let vertices: [Vertex; 10] = core::array::from_fn(|_| graph.add_vertex()); + 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[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[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) + } +}