diff --git a/src/models/graph.rs b/src/models/graph.rs index 33a7224..e13fff4 100644 --- a/src/models/graph.rs +++ b/src/models/graph.rs @@ -82,16 +82,21 @@ impl Graph { edge } - // Deletes a single incidence "e" of an edge, which is composed of two such incidences, from the - // incidences arena. "next" is the next incidence after "e", both originating at the vertex - // "start". - fn delete_incidence(&mut self, e: Edge, start: VertexSlot, next: Option) { - let start_vertex = self + // Updates the source vertex incidence list after the incidence "e" was deleted from the + // incidences arena. "next" is the next incidence after "e" in the source vertex incidence list. + fn update_incidence_list( + &mut self, + e: Edge, + source: VertexSlot, + next: Option, + is_loop: bool, + ) { + let source_vertex = self .vertices - .get_idx(start.0) + .get_idx(source.0) .expect("missing incident neighbor, corrupt internal data state"); - let vertex_header = &mut self.vertices[start_vertex]; - vertex_header.incidence_count -= 1; + let vertex_header = &mut self.vertices[source_vertex]; + vertex_header.incidence_count -= if is_loop { 2 } else { 1 }; let first = vertex_header .first_incidence .expect("incident neighbor without incidences, corrupt internal data state"); @@ -100,9 +105,9 @@ impl Graph { } else { let previous = VertexIncidenceIterator { graph: self, - incidence: self.vertices[start_vertex].first_incidence, + incidence: self.vertices[source_vertex].first_incidence, } - .find(|i| self.incidences[*i].next.is_some_and(|s| s.0 == e.arr_idx())) + .find(|f| self.incidences[*f].next.is_some_and(|i| i.0 == e.arr_idx())) .expect("cannot find previous incidence, corrupt internal data state"); self.incidences[previous].next = next; } @@ -167,15 +172,13 @@ impl GraphTopologyDeletion for Graph { todo!() } - // "e" must index the first of two paired incidences. We want to avoid the calculations required - // to allow either of the incidences to be specified, if possible. // The incidence entries are removed before patching the linked lists. This is safe because - // delete_incidence() searches by raw slot index (IncidenceSlot.0) and only dereferences the - // predecessor node, never the removed entries themselves. + // update_incidence_list() searches by raw slot index (IncidenceSlot.0) and only dereferences + // the predecessor, never the removed entries themselves. fn delete_edge(&mut self, e: Self::Edge) { let f = self .incidences - .get_idx(e.arr_idx() + 1) + .get_idx(e.arr_idx() ^ 1) .expect("invalid paired incidence index, corrupt internal data state"); let e_entry = &self .incidences @@ -186,8 +189,14 @@ impl GraphTopologyDeletion for Graph { .remove(f) .expect("cannot read paired incidence, corrupt internal data state"); - self.delete_incidence(f, e_entry.neighbor, f_entry.next); - self.delete_incidence(e, f_entry.neighbor, e_entry.next); + if e_entry.neighbor != f_entry.neighbor { + self.update_incidence_list(e, f_entry.neighbor, e_entry.next, false); + self.update_incidence_list(f, e_entry.neighbor, f_entry.next, false); + } else if f_entry.next.is_some_and(|i| e.arr_idx() == i.0) { + self.update_incidence_list(f, e_entry.neighbor, e_entry.next, true); + } else { + self.update_incidence_list(e, e_entry.neighbor, f_entry.next, true); + } } } @@ -654,6 +663,33 @@ mod tests { ); } + #[test] + fn delete_edge_paired_index() { + let mut graph = Graph::new(); + let v1 = graph.add_vertex(); + let v2 = graph.add_vertex(); + let e = graph.add_edge(v1, v2); + let f = graph + .incidences + .get_idx(e.arr_idx() + 1) + .expect("paired index should be valid"); + graph.delete_edge(f); + assert_eq!(graph.edge_count(), 0, "unexpected edge count after delete"); + } + + #[test] + fn delete_edge_loop_paired_index() { + let mut graph = Graph::new(); + let v = graph.add_vertex(); + let e = graph.add_edge(v, v); + let f = graph + .incidences + .get_idx(e.arr_idx() + 1) + .expect("paired index should be valid"); + graph.delete_edge(f); + assert_eq!(graph.edge_count(), 0, "unexpected edge count after delete"); + } + #[test] fn delete_edge_invalid_index() { let mut graph = Graph::new();