Initial release #1
+53
-17
@@ -82,16 +82,21 @@ impl Graph {
|
|||||||
edge
|
edge
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletes a single incidence "e" of an edge, which is composed of two such incidences, from the
|
// Updates the source vertex incidence list after the incidence "e" was deleted from the
|
||||||
// incidences arena. "next" is the next incidence after "e", both originating at the vertex
|
// incidences arena. "next" is the next incidence after "e" in the source vertex incidence list.
|
||||||
// "start".
|
fn update_incidence_list(
|
||||||
fn delete_incidence(&mut self, e: Edge, start: VertexSlot, next: Option<IncidenceSlot>) {
|
&mut self,
|
||||||
let start_vertex = self
|
e: Edge,
|
||||||
|
source: VertexSlot,
|
||||||
|
next: Option<IncidenceSlot>,
|
||||||
|
is_loop: bool,
|
||||||
|
) {
|
||||||
|
let source_vertex = self
|
||||||
.vertices
|
.vertices
|
||||||
.get_idx(start.0)
|
.get_idx(source.0)
|
||||||
.expect("missing incident neighbor, corrupt internal data state");
|
.expect("missing incident neighbor, corrupt internal data state");
|
||||||
let vertex_header = &mut self.vertices[start_vertex];
|
let vertex_header = &mut self.vertices[source_vertex];
|
||||||
vertex_header.incidence_count -= 1;
|
vertex_header.incidence_count -= if is_loop { 2 } else { 1 };
|
||||||
let first = vertex_header
|
let first = vertex_header
|
||||||
.first_incidence
|
.first_incidence
|
||||||
.expect("incident neighbor without incidences, corrupt internal data state");
|
.expect("incident neighbor without incidences, corrupt internal data state");
|
||||||
@@ -100,9 +105,9 @@ impl Graph {
|
|||||||
} else {
|
} else {
|
||||||
let previous = VertexIncidenceIterator {
|
let previous = VertexIncidenceIterator {
|
||||||
graph: self,
|
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");
|
.expect("cannot find previous incidence, corrupt internal data state");
|
||||||
self.incidences[previous].next = next;
|
self.incidences[previous].next = next;
|
||||||
}
|
}
|
||||||
@@ -167,15 +172,13 @@ impl GraphTopologyDeletion for Graph {
|
|||||||
todo!()
|
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
|
// 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
|
// update_incidence_list() searches by raw slot index (IncidenceSlot.0) and only dereferences
|
||||||
// predecessor node, never the removed entries themselves.
|
// the predecessor, never the removed entries themselves.
|
||||||
fn delete_edge(&mut self, e: Self::Edge) {
|
fn delete_edge(&mut self, e: Self::Edge) {
|
||||||
let f = self
|
let f = self
|
||||||
.incidences
|
.incidences
|
||||||
.get_idx(e.arr_idx() + 1)
|
.get_idx(e.arr_idx() ^ 1)
|
||||||
.expect("invalid paired incidence index, corrupt internal data state");
|
.expect("invalid paired incidence index, corrupt internal data state");
|
||||||
let e_entry = &self
|
let e_entry = &self
|
||||||
.incidences
|
.incidences
|
||||||
@@ -186,8 +189,14 @@ impl GraphTopologyDeletion for Graph {
|
|||||||
.remove(f)
|
.remove(f)
|
||||||
.expect("cannot read paired incidence, corrupt internal data state");
|
.expect("cannot read paired incidence, corrupt internal data state");
|
||||||
|
|
||||||
self.delete_incidence(f, e_entry.neighbor, f_entry.next);
|
if e_entry.neighbor != f_entry.neighbor {
|
||||||
self.delete_incidence(e, f_entry.neighbor, e_entry.next);
|
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]
|
#[test]
|
||||||
fn delete_edge_invalid_index() {
|
fn delete_edge_invalid_index() {
|
||||||
let mut graph = Graph::new();
|
let mut graph = Graph::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user