From 2793f8af8adbbb5467c1e793c3c4ca4e92c0a077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20M=C3=BCller?= Date: Tue, 28 Apr 2026 17:39:32 +0200 Subject: [PATCH] Add Graph::delete_edge() implementation --- src/models/graph.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/models/graph.rs b/src/models/graph.rs index d934124..33a7224 100644 --- a/src/models/graph.rs +++ b/src/models/graph.rs @@ -40,6 +40,22 @@ impl<'a> Iterator for VertexNeighborIterator<'a> { } } +struct VertexIncidenceIterator<'a> { + graph: &'a Graph, + incidence: Option, +} + +impl<'a> Iterator for VertexIncidenceIterator<'a> { + type Item = Edge; + + fn next(&mut self) -> Option { + let current = self.incidence?; + let index = self.graph.incidences.get_idx(current.0)?; + self.incidence = self.graph.incidences[index].next; + Some(index) + } +} + pub struct Graph { // TODO: Arena index and generation types could be externalized to Graph. vertices: Arena, @@ -65,6 +81,32 @@ impl Graph { self.vertices[v1].first_incidence = Some(IncidenceSlot(edge.arr_idx())); 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 + .vertices + .get_idx(start.0) + .expect("missing incident neighbor, corrupt internal data state"); + let vertex_header = &mut self.vertices[start_vertex]; + vertex_header.incidence_count -= 1; + let first = vertex_header + .first_incidence + .expect("incident neighbor without incidences, corrupt internal data state"); + if first.0 == e.arr_idx() { + vertex_header.first_incidence = next; + } else { + let previous = VertexIncidenceIterator { + graph: self, + incidence: self.vertices[start_vertex].first_incidence, + } + .find(|i| self.incidences[*i].next.is_some_and(|s| s.0 == e.arr_idx())) + .expect("cannot find previous incidence, corrupt internal data state"); + self.incidences[previous].next = next; + } + } } impl Default for Graph { @@ -125,8 +167,27 @@ 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. fn delete_edge(&mut self, e: Self::Edge) { - todo!() + let f = self + .incidences + .get_idx(e.arr_idx() + 1) + .expect("invalid paired incidence index, corrupt internal data state"); + let e_entry = &self + .incidences + .remove(e) + .expect("attempt to delete an invalid edge"); + let f_entry = &self + .incidences + .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); } }