Files
grapherity/src/models/append_graph.rs
T
warrence f009a86f1e Add GraphTopology.incidence_cursor() for certain use-cases where the iterator is problematic
Also add raw_incidences() and step_incidence() to AppendGraph analogously to
Graph, which allows to remove RawIncidenceIterator and simplify its call sites.
2026-06-26 23:36:41 +02:00

186 lines
5.1 KiB
Rust

use crate::maps::{EdgeMap, VertexMap};
use crate::traits::{GraphTopology, IncidenceCursor};
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Vertex(usize);
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Incidence(usize);
impl Incidence {
fn normalize(&self) -> Self {
Self(self.0 & !1)
}
}
struct VertexIncidenceHeader {
incidence_count: usize,
first_incidence: Option<Incidence>,
}
#[derive(Copy, Clone)]
struct IncidenceEntry {
next: Option<Incidence>,
adjacent: Vertex,
}
#[derive(Copy, Clone)]
pub struct AppendGraphIncidenceCursor {
incidence: Option<Incidence>,
}
impl IncidenceCursor<AppendGraph> for AppendGraphIncidenceCursor {
fn next(&mut self, graph: &AppendGraph) -> Option<(Vertex, Incidence)> {
graph.step_incidence(&mut self.incidence)
}
}
pub struct AppendGraph {
vertices: Vec<VertexIncidenceHeader>,
incidences: Vec<IncidenceEntry>,
}
impl AppendGraph {
pub fn new() -> Self {
Self {
vertices: vec![],
incidences: vec![],
}
}
// Adds a single incidence of an edge, which is composed by two such incidences, to the
// incidences vector.
fn add_incidence(&mut self, v1: Vertex, v2: Vertex) {
self.incidences.push(IncidenceEntry {
next: self.vertices[v1.0].first_incidence.take(),
adjacent: v2,
});
self.vertices[v1.0].incidence_count += 1;
self.vertices[v1.0].first_incidence = Some(Incidence(self.incidences.len() - 1));
}
fn raw_incidences(&self, v: Vertex) -> impl Iterator<Item = (Vertex, Incidence)> {
let mut incidence = self.vertices[v.0].first_incidence;
std::iter::from_fn(move || self.step_incidence(&mut incidence))
}
fn step_incidence(&self, incidence: &mut Option<Incidence>) -> Option<(Vertex, Incidence)> {
let current = (*incidence)?;
let entry = self.incidences[current.0];
*incidence = entry.next;
Some((entry.adjacent, current))
}
}
impl Default for AppendGraph {
fn default() -> Self {
Self::new()
}
}
impl GraphTopology for AppendGraph {
type Vertex = Vertex;
type Edge = Incidence;
type IncidenceCursor = AppendGraphIncidenceCursor;
fn vertex_count(&self) -> usize {
self.vertices.len()
}
fn vertex_capacity(&self) -> usize {
self.vertices.len()
}
fn vertex_map<T: Clone>(&self, default: T) -> VertexMap<Self::Vertex, T> {
VertexMap::new(default, |v| v.0, self.vertex_capacity())
}
fn edge_count(&self) -> usize {
self.incidences.len() / 2
}
fn edge_capacity(&self) -> usize {
self.incidences.len() / 2
}
fn edge_map<T: Clone>(&self, default: T) -> EdgeMap<Self::Edge, T> {
EdgeMap::new(default, |e| e.0 / 2, self.edge_capacity())
}
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.adjacent_vertices(v1).any(|x| x == v2)
}
fn vertices(&self) -> impl Iterator<Item = Self::Vertex> {
(0..self.vertices.len()).map(Vertex)
}
fn adjacent_vertices(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Vertex> {
self.raw_incidences(v).map(|(v, _)| v)
}
fn incident_vertices(&self, e: Self::Edge) -> (Self::Vertex, Self::Vertex) {
let v2 = self.incidences[e.0].adjacent;
let v1 = self.incidences[e.0 ^ 1].adjacent;
(v1, v2)
}
fn edges(&self) -> impl Iterator<Item = Self::Edge> {
(0..self.incidences.len()).step_by(2).map(Incidence)
}
fn incident_edges(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Edge> {
self.raw_incidences(v).map(|(_, e)| e.normalize())
}
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)> {
self.raw_incidences(v).map(|(v, e)| (v, e.normalize()))
}
fn incidence_cursor(&self, v: Self::Vertex) -> Self::IncidenceCursor {
AppendGraphIncidenceCursor {
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::*;
crate::graph_topology_test_fixtures!(AppendGraph);
crate::graph_topology_tests!(AppendGraph);
#[test]
fn incident_vertices_paired_index() {
let mut graph = AppendGraph::new();
let v1 = graph.add_vertex();
let v2 = graph.add_vertex();
let e = graph.add_edge(v1, v2);
let f = Incidence(e.0 + 1);
let (u1, u2) = graph.incident_vertices(f);
assert!(
(u1 == v1 && u2 == v2) || (u1 == v2 && u2 == v1),
"unexpected incident vertices {u1:?} and {u2:?} for edge {f:?}"
);
}
}