use typed_generational_arena::{Arena, Index}; use crate::traits::{GraphTopology, GraphTopologyDeletion}; type Vertex = Index; type Edge = Index; #[derive(Copy, Clone, PartialEq, Eq, Debug)] struct VertexSlot(usize); #[derive(Copy, Clone, PartialEq, Eq, Debug)] struct IncidenceSlot(usize); pub struct VertexIncidenceHeader { incidence_count: usize, first_incidence: Option, } pub struct IncidenceEntry { next: Option, neighbor: VertexSlot, } struct VertexNeighborIterator<'a> { graph: &'a Graph, incidence: Option, } impl<'a> Iterator for VertexNeighborIterator<'a> { type Item = Vertex; fn next(&mut self) -> Option { // TODO: Benchmark storing full Index (one read, larger entries) vs. slot + get_idx() (two reads, smaller entries). let incidence = self.incidence?; let index = self.graph.incidences.get_idx(incidence.0)?; let entry = &self.graph.incidences[index]; self.incidence = entry.next; self.graph.vertices.get_idx(entry.neighbor.0) } } pub struct Graph { // TODO: Arena index and generation types could be externalized to Graph. vertices: Arena, incidences: Arena, } impl Graph { pub fn new() -> Self { Self { vertices: Arena::new(), incidences: Arena::new(), } } // Adds a single incidence of an edge, which is composed by two such incidences, to the // incidences arena, and returns its index. fn add_incidence(&mut self, v1: Vertex, v2: Vertex) -> Edge { let edge = self.incidences.insert(IncidenceEntry { next: self.vertices[v1].first_incidence.take(), neighbor: VertexSlot(v2.arr_idx()), }); self.vertices[v1].incidence_count += 1; self.vertices[v1].first_incidence = Some(IncidenceSlot(edge.arr_idx())); edge } } impl Default for Graph { fn default() -> Self { Self::new() } } impl GraphTopology for Graph { type Vertex = Vertex; type Edge = Edge; 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].incidence_count } fn are_adjacent(&self, v1: Self::Vertex, v2: Self::Vertex) -> bool { self.neighbors(v1).any(|x| x == v2) } fn vertices(&self) -> impl Iterator { self.vertices.iter().map(|(i, _)| i) } fn neighbors(&self, v: Self::Vertex) -> impl Iterator { VertexNeighborIterator { graph: self, incidence: self.vertices[v].first_incidence, } } fn add_vertex(&mut self) -> Self::Vertex { self.vertices.insert(VertexIncidenceHeader { incidence_count: 0, first_incidence: None, }) } fn add_edge(&mut self, v1: Self::Vertex, v2: Self::Vertex) -> Self::Edge { let first = self.add_incidence(v1, v2); self.add_incidence(v2, v1); first } } // TODO: Benchmark delete with storing "previous" in O(1) vs. linear lookup in O(degree). impl GraphTopologyDeletion for Graph { fn delete_vertex(&mut self, v: Self::Vertex) { todo!() } fn delete_edge(&mut self, e: Self::Edge) { todo!() } } #[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!( !graph.are_adjacent(v, v), "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[9], 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 neighbor count" ); // Expects each neighbor to appear exactly once. This will not work if there are multiple edges. let neighbors = 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!( graph.are_adjacent(v, v), "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, "too many neighbors from iterator"); } #[test] fn multiple_edges() { let k = 3; let mut graph = Graph::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 neighbors = graph.neighbors(vertices[i]); for j in 0..k { assert_eq!( neighbors.next(), Some(vertices[1 - i]), "neighbor {j} of vertex {:?} should be {:?}", vertices[i], vertices[1 - i] ); } assert_eq!( neighbors.next(), None, "too many neighbors of {:?} from iterator", vertices[i] ); } } #[test] fn delete_vertex() { let mut graph = Graph::new(); let v = graph.add_vertex(); assert_eq!( graph.vertex_count(), 1, "unexpected vertex count before delete" ); graph.delete_vertex(v); assert_eq!( graph.vertex_count(), 0, "unexpected vertex count after delete" ); assert_ne!( graph.add_vertex(), v, "unexpected duplicate vertex after delete" ); } #[test] fn delete_vertex_invalid_index() { let mut graph = Graph::new(); let v = graph.add_vertex(); graph.delete_vertex(v); let result = std::panic::catch_unwind(move || graph.delete_vertex(v)); assert!(result.is_err(), "second deletion should panic"); } #[test] fn delete_vertex_connected() { let (mut graph, vertices) = make_test_graph(); assert_eq!( graph.vertex_count(), 10, "unexpected vertex count before delete" ); assert_eq!( graph.edge_count(), 14, "unexpected edge count before delete" ); graph.delete_vertex(vertices[2]); assert_eq!( graph.vertex_count(), 9, "unexpected vertex count after delete" ); assert_eq!(graph.edge_count(), 10, "unexpected edge count after delete"); } #[test] fn delete_edge() { let mut graph = Graph::new(); let v1 = graph.add_vertex(); let v2 = graph.add_vertex(); let e = graph.add_edge(v1, v2); assert_eq!( graph.vertex_count(), 2, "unexpected vertex count before delete" ); assert_eq!(graph.edge_count(), 1, "unexpected edge count before delete"); graph.delete_edge(e); assert_eq!( graph.vertex_count(), 2, "unexpected vertex count after delete" ); assert_eq!(graph.edge_count(), 0, "unexpected edge count after delete"); assert_ne!( graph.add_edge(v1, v2), e, "unexpected duplicate edge after delete" ); } #[test] fn delete_edge_invalid_index() { let mut graph = Graph::new(); let v1 = graph.add_vertex(); let v2 = graph.add_vertex(); let e = graph.add_edge(v1, v2); graph.delete_edge(e); let result = std::panic::catch_unwind(move || graph.delete_edge(e)); assert!(result.is_err(), "second deletion should panic"); } 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) } }