Change GraphTopology implementation for Graph with generational arena
This commit is contained in:
@@ -4,3 +4,4 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
typed-generational-arena = "0.2.9"
|
||||||
|
|||||||
+40
-39
@@ -1,67 +1,67 @@
|
|||||||
|
use typed_generational_arena::{Arena, Index};
|
||||||
|
|
||||||
use crate::traits::GraphTopology;
|
use crate::traits::GraphTopology;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
type Vertex = Index<VertexIncidenceHeader, usize, usize>;
|
||||||
pub struct Vertex(usize);
|
|
||||||
|
|
||||||
impl From<Vertex> for usize {
|
type Edge = Index<IncidenceEntry, usize, usize>;
|
||||||
fn from(v: Vertex) -> usize {
|
|
||||||
v.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
pub struct Incidence(usize);
|
struct VertexSlot(usize);
|
||||||
|
|
||||||
struct VertexIncidenceHeader {
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
struct IncidenceSlot(usize);
|
||||||
|
|
||||||
|
pub struct VertexIncidenceHeader {
|
||||||
incidence_count: usize,
|
incidence_count: usize,
|
||||||
first_incidence: Option<Incidence>,
|
first_incidence: Option<IncidenceSlot>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IncidenceEntry {
|
pub struct IncidenceEntry {
|
||||||
next: Option<Incidence>,
|
next: Option<IncidenceSlot>,
|
||||||
neighbor: Vertex,
|
neighbor: VertexSlot,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VertexNeighborIterator<'a> {
|
struct VertexNeighborIterator<'a> {
|
||||||
graph: &'a Graph,
|
graph: &'a Graph,
|
||||||
incidence: Option<Incidence>,
|
incidence: Option<IncidenceSlot>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for VertexNeighborIterator<'a> {
|
impl<'a> Iterator for VertexNeighborIterator<'a> {
|
||||||
type Item = Vertex;
|
type Item = Vertex;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
// TODO: Benchmark storing full Index (one read, larger entries) vs slot + get_idx() (two reads, smaller entries).
|
||||||
let incidence = self.incidence?;
|
let incidence = self.incidence?;
|
||||||
let entry = &self.graph.incidences[incidence.0];
|
let index = self.graph.incidences.get_idx(incidence.0)?;
|
||||||
|
let entry = &self.graph.incidences[index];
|
||||||
self.incidence = entry.next;
|
self.incidence = entry.next;
|
||||||
Some(entry.neighbor)
|
self.graph.vertices.get_idx(entry.neighbor.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Graph cannot support deleting vertices because of the external indices "Vertex". They could be made stable with e.g. slotmap or generational arena.
|
|
||||||
// TODO: Add function to delete vertices.
|
|
||||||
// TODO: Add function to delete edges.
|
|
||||||
pub struct Graph {
|
pub struct Graph {
|
||||||
// TODO: Index 'vertices' by a 'Vertex' instead of 'Vertex.0'?
|
// TODO: Arena index and generation types could be externalized to Graph.
|
||||||
vertices: Vec<VertexIncidenceHeader>,
|
vertices: Arena<VertexIncidenceHeader, usize, usize>,
|
||||||
incidences: Vec<IncidenceEntry>,
|
incidences: Arena<IncidenceEntry, usize, usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Graph {
|
impl Graph {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
vertices: vec![],
|
vertices: Arena::new(),
|
||||||
incidences: vec![],
|
incidences: Arena::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_incidence(&mut self, v1: Vertex, v2: Vertex) {
|
fn add_incidence(&mut self, v1: Vertex, v2: Vertex) -> Edge {
|
||||||
self.incidences.push(IncidenceEntry {
|
let edge = self.incidences.insert(IncidenceEntry {
|
||||||
next: self.vertices[v1.0].first_incidence.take(),
|
next: self.vertices[v1].first_incidence.take(),
|
||||||
neighbor: v2,
|
neighbor: VertexSlot(v2.arr_idx()),
|
||||||
});
|
});
|
||||||
self.vertices[v1.0].incidence_count += 1;
|
self.vertices[v1].incidence_count += 1;
|
||||||
self.vertices[v1.0].first_incidence = Some(Incidence(self.incidences.len() - 1));
|
self.vertices[v1].first_incidence = Some(IncidenceSlot(edge.arr_idx()));
|
||||||
|
edge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ impl Default for Graph {
|
|||||||
impl GraphTopology for Graph {
|
impl GraphTopology for Graph {
|
||||||
type Vertex = Vertex;
|
type Vertex = Vertex;
|
||||||
|
|
||||||
type Edge = Incidence;
|
type Edge = Edge;
|
||||||
|
|
||||||
fn vertex_count(&self) -> usize {
|
fn vertex_count(&self) -> usize {
|
||||||
self.vertices.len()
|
self.vertices.len()
|
||||||
@@ -85,7 +85,7 @@ impl GraphTopology for Graph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn degree(&self, v: Self::Vertex) -> usize {
|
fn degree(&self, v: Self::Vertex) -> usize {
|
||||||
self.vertices[v.0].incidence_count
|
self.vertices[v].incidence_count
|
||||||
}
|
}
|
||||||
|
|
||||||
fn are_adjacent(&self, v1: Self::Vertex, v2: Self::Vertex) -> bool {
|
fn are_adjacent(&self, v1: Self::Vertex, v2: Self::Vertex) -> bool {
|
||||||
@@ -93,31 +93,32 @@ impl GraphTopology for Graph {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn vertices(&self) -> impl Iterator<Item = Self::Vertex> {
|
fn vertices(&self) -> impl Iterator<Item = Self::Vertex> {
|
||||||
(0..self.vertices.len()).map(Vertex)
|
self.vertices.iter().map(|(i, _)| i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn neighbors(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Vertex> {
|
fn neighbors(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Vertex> {
|
||||||
VertexNeighborIterator {
|
VertexNeighborIterator {
|
||||||
graph: self,
|
graph: self,
|
||||||
incidence: self.vertices[v.0].first_incidence,
|
incidence: self.vertices[v].first_incidence,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_vertex(&mut self) -> Self::Vertex {
|
fn add_vertex(&mut self) -> Self::Vertex {
|
||||||
self.vertices.push(VertexIncidenceHeader {
|
self.vertices.insert(VertexIncidenceHeader {
|
||||||
incidence_count: 0,
|
incidence_count: 0,
|
||||||
first_incidence: None,
|
first_incidence: None,
|
||||||
});
|
})
|
||||||
Vertex(self.vertices.len() - 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_edge(&mut self, v1: Self::Vertex, v2: Self::Vertex) -> Self::Edge {
|
fn add_edge(&mut self, v1: Self::Vertex, v2: Self::Vertex) -> Self::Edge {
|
||||||
self.add_incidence(v1, v2);
|
let first = self.add_incidence(v1, v2);
|
||||||
self.add_incidence(v2, v1);
|
self.add_incidence(v2, v1);
|
||||||
Incidence(self.incidences.len() - 2)
|
first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: impl GraphTopologyDeletion for Graph.
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
Reference in New Issue
Block a user