11 Commits

17 changed files with 62 additions and 39 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "grapherity" name = "grapherity"
version = "0.1.0" version = "0.2.1"
authors = ["Stefan Müller"] authors = ["Stefan Müller"]
edition = "2024" edition = "2024"
rust-version = "1.85.0" rust-version = "1.85.0"
+3 -3
View File
@@ -261,14 +261,14 @@ where
(visited, None) (visited, None)
} }
pub fn find_path<G>(graph: &G, source: G::Vertex, target: G::Vertex) -> Option<Vec<G::Edge>> pub fn dfs_find_path<G>(graph: &G, source: G::Vertex, target: G::Vertex) -> Option<Vec<G::Edge>>
where where
G: GraphTopology, G: GraphTopology,
{ {
find_path_where(graph, source, |v| v == target) dfs_find_path_where(graph, source, |v| v == target)
} }
pub fn find_path_where<G, P>(graph: &G, source: G::Vertex, predicate: P) -> Option<Vec<G::Edge>> pub fn dfs_find_path_where<G, P>(graph: &G, source: G::Vertex, predicate: P) -> Option<Vec<G::Edge>>
where where
G: GraphTopology, G: GraphTopology,
P: Fn(G::Vertex) -> bool, P: Fn(G::Vertex) -> bool,
+4
View File
@@ -3,4 +3,8 @@ pub mod maps;
pub mod models; pub mod models;
pub mod traits; pub mod traits;
pub mod prelude {
pub use crate::traits::{GraphTopology, GraphTopologyDeletion};
}
mod testing; mod testing;
+3
View File
@@ -1,2 +1,5 @@
pub mod append_graph; pub mod append_graph;
pub mod graph; pub mod graph;
pub use append_graph::{AppendGraph, AppendGraphEdgeMap, AppendGraphVertexMap};
pub use graph::{Graph, GraphEdgeMap, GraphVertexMap};
+16 -13
View File
@@ -5,9 +5,12 @@ use crate::traits::{GraphTopology, IncidenceCursor};
pub struct Vertex(usize); pub struct Vertex(usize);
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Incidence(usize); pub struct Edge(usize);
impl Incidence { pub type AppendGraphVertexMap<T> = VertexMap<Vertex, T>;
pub type AppendGraphEdgeMap<T> = EdgeMap<Edge, T>;
impl Edge {
fn normalize(&self) -> Self { fn normalize(&self) -> Self {
Self(self.0 & !1) Self(self.0 & !1)
} }
@@ -15,22 +18,22 @@ impl Incidence {
struct VertexIncidenceHeader { struct VertexIncidenceHeader {
incidence_count: usize, incidence_count: usize,
first_incidence: Option<Incidence>, first_incidence: Option<Edge>,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct IncidenceEntry { struct IncidenceEntry {
next: Option<Incidence>, next: Option<Edge>,
adjacent: Vertex, adjacent: Vertex,
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
pub struct AppendGraphIncidenceCursor { pub struct AppendGraphIncidenceCursor {
incidence: Option<Incidence>, incidence: Option<Edge>,
} }
impl IncidenceCursor<AppendGraph> for AppendGraphIncidenceCursor { impl IncidenceCursor<AppendGraph> for AppendGraphIncidenceCursor {
fn next(&mut self, graph: &AppendGraph) -> Option<(Vertex, Incidence)> { fn next(&mut self, graph: &AppendGraph) -> Option<(Vertex, Edge)> {
graph.step_incidence(&mut self.incidence) graph.step_incidence(&mut self.incidence)
} }
} }
@@ -56,15 +59,15 @@ impl AppendGraph {
adjacent: v2, adjacent: v2,
}); });
self.vertices[v1.0].incidence_count += 1; self.vertices[v1.0].incidence_count += 1;
self.vertices[v1.0].first_incidence = Some(Incidence(self.incidences.len() - 1)); self.vertices[v1.0].first_incidence = Some(Edge(self.incidences.len() - 1));
} }
fn raw_incidences(&self, v: Vertex) -> impl Iterator<Item = (Vertex, Incidence)> { fn raw_incidences(&self, v: Vertex) -> impl Iterator<Item = (Vertex, Edge)> {
let mut incidence = self.vertices[v.0].first_incidence; let mut incidence = self.vertices[v.0].first_incidence;
std::iter::from_fn(move || self.step_incidence(&mut incidence)) std::iter::from_fn(move || self.step_incidence(&mut incidence))
} }
fn step_incidence(&self, incidence: &mut Option<Incidence>) -> Option<(Vertex, Incidence)> { fn step_incidence(&self, incidence: &mut Option<Edge>) -> Option<(Vertex, Edge)> {
let current = (*incidence)?; let current = (*incidence)?;
let entry = self.incidences[current.0]; let entry = self.incidences[current.0];
*incidence = entry.next; *incidence = entry.next;
@@ -80,7 +83,7 @@ impl Default for AppendGraph {
impl GraphTopology for AppendGraph { impl GraphTopology for AppendGraph {
type Vertex = Vertex; type Vertex = Vertex;
type Edge = Incidence; type Edge = Edge;
type IncidenceCursor = AppendGraphIncidenceCursor; type IncidenceCursor = AppendGraphIncidenceCursor;
fn vertex_count(&self) -> usize { fn vertex_count(&self) -> usize {
@@ -130,7 +133,7 @@ impl GraphTopology for AppendGraph {
} }
fn edges(&self) -> impl Iterator<Item = Self::Edge> { fn edges(&self) -> impl Iterator<Item = Self::Edge> {
(0..self.incidences.len()).step_by(2).map(Incidence) (0..self.incidences.len()).step_by(2).map(Edge)
} }
fn incident_edges(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Edge> { fn incident_edges(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Edge> {
@@ -158,7 +161,7 @@ impl GraphTopology for AppendGraph {
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); self.add_incidence(v1, v2);
self.add_incidence(v2, v1); self.add_incidence(v2, v1);
Incidence(self.incidences.len() - 2) Edge(self.incidences.len() - 2)
} }
} }
@@ -175,7 +178,7 @@ mod tests {
let v1 = graph.add_vertex(); let v1 = graph.add_vertex();
let v2 = graph.add_vertex(); let v2 = graph.add_vertex();
let e = graph.add_edge(v1, v2); let e = graph.add_edge(v1, v2);
let f = Incidence(e.0 + 1); let f = Edge(e.0 + 1);
let (u1, u2) = graph.incident_vertices(f); let (u1, u2) = graph.incident_vertices(f);
assert!( assert!(
(u1 == v1 && u2 == v2) || (u1 == v2 && u2 == v1), (u1 == v1 && u2 == v2) || (u1 == v2 && u2 == v1),
+4 -2
View File
@@ -3,9 +3,11 @@ use typed_generational_arena::{Arena, Index};
use crate::maps::{EdgeMap, VertexMap}; use crate::maps::{EdgeMap, VertexMap};
use crate::traits::{GraphTopology, GraphTopologyDeletion, IncidenceCursor}; use crate::traits::{GraphTopology, GraphTopologyDeletion, IncidenceCursor};
type Vertex = Index<VertexIncidenceHeader, usize, usize>; pub type Vertex = Index<VertexIncidenceHeader, usize, usize>;
pub type Edge = Index<IncidenceEntry, usize, usize>;
type Edge = Index<IncidenceEntry, usize, usize>; pub type GraphVertexMap<T> = VertexMap<Vertex, T>;
pub type GraphEdgeMap<T> = EdgeMap<Edge, T>;
#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct VertexSlot(usize); struct VertexSlot(usize);
+1
View File
@@ -1,3 +1,4 @@
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! bfs_tests { macro_rules! bfs_tests {
($T:ty) => { ($T:ty) => {
+1
View File
@@ -1,3 +1,4 @@
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! dfs_tests { macro_rules! dfs_tests {
($T:ty) => { ($T:ty) => {
+1
View File
@@ -1,3 +1,4 @@
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! dijkstra_tests { macro_rules! dijkstra_tests {
($T:ty) => { ($T:ty) => {
+9 -8
View File
@@ -1,3 +1,4 @@
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! find_path_tests { macro_rules! find_path_tests {
($T:ty) => { ($T:ty) => {
@@ -7,7 +8,7 @@ macro_rules! find_path_tests {
let mut graph = <$T>::new(); let mut graph = <$T>::new();
let v = graph.add_vertex(); let v = graph.add_vertex();
assert_eq!( assert_eq!(
$crate::algorithms::find_path(&graph, v, v), $crate::algorithms::dfs_find_path(&graph, v, v),
Some(vec![]), Some(vec![]),
"path from source to itself should be empty" "path from source to itself should be empty"
); );
@@ -17,7 +18,7 @@ macro_rules! find_path_tests {
fn find_path_disconnected() { fn find_path_disconnected() {
let (graph, vertices) = make_test_graph_disconnected(); let (graph, vertices) = make_test_graph_disconnected();
assert_eq!( assert_eq!(
$crate::algorithms::find_path(&graph, vertices[0], vertices[1]), $crate::algorithms::dfs_find_path(&graph, vertices[0], vertices[1]),
None, None,
"no path should exist to disconnected vertex" "no path should exist to disconnected vertex"
); );
@@ -30,7 +31,7 @@ macro_rules! find_path_tests {
let v1 = graph.add_vertex(); let v1 = graph.add_vertex();
let v2 = graph.add_vertex(); let v2 = graph.add_vertex();
let e = graph.add_edge(v1, v2); let e = graph.add_edge(v1, v2);
let path = $crate::algorithms::find_path(&graph, v1, v2) let path = $crate::algorithms::dfs_find_path(&graph, v1, v2)
.expect("path should exist between adjacent vertices"); .expect("path should exist between adjacent vertices");
assert_eq!( assert_eq!(
path.len(), path.len(),
@@ -43,7 +44,7 @@ macro_rules! find_path_tests {
#[test] #[test]
fn find_path() { fn find_path() {
let (graph, vertices, _, _) = make_test_graph(); let (graph, vertices, _, _) = make_test_graph();
let path = $crate::algorithms::find_path(&graph, vertices[0], vertices[9]) let path = $crate::algorithms::dfs_find_path(&graph, vertices[0], vertices[9])
.expect(&format!( .expect(&format!(
"path should exist between connected vertices {:?} and {:?}", "path should exist between connected vertices {:?} and {:?}",
vertices[0], vertices[9] vertices[0], vertices[9]
@@ -57,7 +58,7 @@ macro_rules! find_path_tests {
let mut graph = <$T>::new(); let mut graph = <$T>::new();
let v = graph.add_vertex(); let v = graph.add_vertex();
assert_eq!( assert_eq!(
$crate::algorithms::find_path_where(&graph, v, |u| u == v), $crate::algorithms::dfs_find_path_where(&graph, v, |u| u == v),
Some(vec![]), Some(vec![]),
"path from source to itself should be empty" "path from source to itself should be empty"
); );
@@ -67,7 +68,7 @@ macro_rules! find_path_tests {
fn find_path_where_disconnected() { fn find_path_where_disconnected() {
let (graph, vertices) = make_test_graph_disconnected(); let (graph, vertices) = make_test_graph_disconnected();
assert_eq!( assert_eq!(
$crate::algorithms::find_path_where(&graph, vertices[0], |v| v == vertices[1]), $crate::algorithms::dfs_find_path_where(&graph, vertices[0], |v| v == vertices[1]),
None, None,
"no path should exist to disconnected vertex" "no path should exist to disconnected vertex"
); );
@@ -77,7 +78,7 @@ macro_rules! find_path_tests {
fn find_path_where_no_match() { fn find_path_where_no_match() {
let (graph, vertices, _, _) = make_test_graph(); let (graph, vertices, _, _) = make_test_graph();
assert_eq!( assert_eq!(
$crate::algorithms::find_path_where(&graph, vertices[0], |_| false), $crate::algorithms::dfs_find_path_where(&graph, vertices[0], |_| false),
None, None,
"no path should exist when predicate never matches" "no path should exist when predicate never matches"
); );
@@ -87,7 +88,7 @@ macro_rules! find_path_tests {
fn find_path_where() { fn find_path_where() {
let (graph, vertices, _, _) = make_test_graph(); let (graph, vertices, _, _) = make_test_graph();
let path = let path =
$crate::algorithms::find_path_where(&graph, vertices[0], |v| v == vertices[9]) $crate::algorithms::dfs_find_path_where(&graph, vertices[0], |v| v == vertices[9])
.expect(&format!( .expect(&format!(
"path should exist between connected vertices {:?} and {:?}", "path should exist between connected vertices {:?} and {:?}",
vertices[0], vertices[9] vertices[0], vertices[9]
+3
View File
@@ -1,3 +1,4 @@
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! graph_topology_test_fixtures { macro_rules! graph_topology_test_fixtures {
($T:ty) => { ($T:ty) => {
@@ -101,6 +102,7 @@ macro_rules! graph_topology_test_fixtures {
}; };
} }
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! graph_topology_tests { macro_rules! graph_topology_tests {
($T:ty) => { ($T:ty) => {
@@ -748,6 +750,7 @@ macro_rules! graph_topology_tests {
}; };
} }
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! graph_topology_deletion_tests { macro_rules! graph_topology_deletion_tests {
($T:ty) => { ($T:ty) => {
+4
View File
@@ -1,3 +1,4 @@
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! vertex_map_tests { macro_rules! vertex_map_tests {
($T:ty) => { ($T:ty) => {
@@ -78,6 +79,7 @@ macro_rules! vertex_map_tests {
}; };
} }
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! vertex_map_deletion_tests { macro_rules! vertex_map_deletion_tests {
($T:ty) => { ($T:ty) => {
@@ -130,6 +132,7 @@ macro_rules! vertex_map_deletion_tests {
}; };
} }
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! edge_map_tests { macro_rules! edge_map_tests {
($T:ty) => { ($T:ty) => {
@@ -222,6 +225,7 @@ macro_rules! edge_map_tests {
}; };
} }
#[doc(hidden)]
#[macro_export] #[macro_export]
macro_rules! edge_map_deletion_tests { macro_rules! edge_map_deletion_tests {
($T:ty) => { ($T:ty) => {
+2 -2
View File
@@ -1,12 +1,12 @@
mod append_graph_tests { mod append_graph_tests {
use grapherity::models::append_graph::AppendGraph; use grapherity::models::AppendGraph;
grapherity::graph_topology_test_fixtures!(AppendGraph); grapherity::graph_topology_test_fixtures!(AppendGraph);
grapherity::bfs_tests!(AppendGraph); grapherity::bfs_tests!(AppendGraph);
} }
mod graph_tests { mod graph_tests {
use grapherity::models::graph::Graph; use grapherity::models::Graph;
grapherity::graph_topology_test_fixtures!(Graph); grapherity::graph_topology_test_fixtures!(Graph);
grapherity::bfs_tests!(Graph); grapherity::bfs_tests!(Graph);
+2 -2
View File
@@ -1,12 +1,12 @@
mod append_graph_tests { mod append_graph_tests {
use grapherity::models::append_graph::AppendGraph; use grapherity::models::AppendGraph;
grapherity::graph_topology_test_fixtures!(AppendGraph); grapherity::graph_topology_test_fixtures!(AppendGraph);
grapherity::dfs_tests!(AppendGraph); grapherity::dfs_tests!(AppendGraph);
} }
mod graph_tests { mod graph_tests {
use grapherity::models::graph::Graph; use grapherity::models::Graph;
grapherity::graph_topology_test_fixtures!(Graph); grapherity::graph_topology_test_fixtures!(Graph);
grapherity::dfs_tests!(Graph); grapherity::dfs_tests!(Graph);
+2 -2
View File
@@ -1,12 +1,12 @@
mod append_graph_tests { mod append_graph_tests {
use grapherity::models::append_graph::AppendGraph; use grapherity::models::AppendGraph;
grapherity::graph_topology_test_fixtures!(AppendGraph); grapherity::graph_topology_test_fixtures!(AppendGraph);
grapherity::dijkstra_tests!(AppendGraph); grapherity::dijkstra_tests!(AppendGraph);
} }
mod graph_tests { mod graph_tests {
use grapherity::models::graph::Graph; use grapherity::models::Graph;
grapherity::graph_topology_test_fixtures!(Graph); grapherity::graph_topology_test_fixtures!(Graph);
grapherity::dijkstra_tests!(Graph); grapherity::dijkstra_tests!(Graph);
+2 -2
View File
@@ -1,12 +1,12 @@
mod append_graph_tests { mod append_graph_tests {
use grapherity::models::append_graph::AppendGraph; use grapherity::models::AppendGraph;
grapherity::graph_topology_test_fixtures!(AppendGraph); grapherity::graph_topology_test_fixtures!(AppendGraph);
grapherity::find_path_tests!(AppendGraph); grapherity::find_path_tests!(AppendGraph);
} }
mod graph_tests { mod graph_tests {
use grapherity::models::graph::Graph; use grapherity::models::Graph;
grapherity::graph_topology_test_fixtures!(Graph); grapherity::graph_topology_test_fixtures!(Graph);
grapherity::find_path_tests!(Graph); grapherity::find_path_tests!(Graph);
+4 -4
View File
@@ -1,24 +1,24 @@
mod append_graph_vertex_map_tests { mod append_graph_vertex_map_tests {
use grapherity::models::append_graph::AppendGraph; use grapherity::models::AppendGraph;
grapherity::vertex_map_tests!(AppendGraph); grapherity::vertex_map_tests!(AppendGraph);
} }
mod append_graph_edge_map_tests { mod append_graph_edge_map_tests {
use grapherity::models::append_graph::AppendGraph; use grapherity::models::AppendGraph;
grapherity::edge_map_tests!(AppendGraph); grapherity::edge_map_tests!(AppendGraph);
} }
mod graph_vertex_map_tests { mod graph_vertex_map_tests {
use grapherity::models::graph::Graph; use grapherity::models::Graph;
grapherity::vertex_map_tests!(Graph); grapherity::vertex_map_tests!(Graph);
grapherity::vertex_map_deletion_tests!(Graph); grapherity::vertex_map_deletion_tests!(Graph);
} }
mod graph_edge_map_tests { mod graph_edge_map_tests {
use grapherity::models::graph::Graph; use grapherity::models::Graph;
grapherity::edge_map_tests!(Graph); grapherity::edge_map_tests!(Graph);
grapherity::edge_map_deletion_tests!(Graph); grapherity::edge_map_deletion_tests!(Graph);