Add Incidence struct for GraphTopology to use
This commit is contained in:
+11
-8
@@ -34,7 +34,7 @@ use std::collections::VecDeque;
|
||||
use std::hash::Hash;
|
||||
|
||||
use crate::maps::EntityMap;
|
||||
use crate::traits::{GraphTopology, IncidenceCursor};
|
||||
use crate::traits::{GraphTopology, Incidence, IncidenceCursor};
|
||||
|
||||
/// Return data type for [`dijkstra`] and [`dijkstra_unweighted`].
|
||||
pub struct DijkstraResult<V: Copy> {
|
||||
@@ -236,16 +236,16 @@ where
|
||||
heap.push(source, Reverse(0u32));
|
||||
|
||||
while let Some((v, Reverse(v_distance))) = heap.pop() {
|
||||
for incidence in graph.incidences(v) {
|
||||
let new_distance = v_distance + weights(incidence.1);
|
||||
if match distances[incidence.0] {
|
||||
for Incidence { vertex: u, edge: e } in graph.incidences(v) {
|
||||
let new_distance = v_distance + weights(e);
|
||||
if match distances[u] {
|
||||
None => true,
|
||||
Some(old_distance) if old_distance > new_distance => true,
|
||||
_ => false,
|
||||
} {
|
||||
distances[incidence.0] = Some(new_distance);
|
||||
on_relax(incidence.0, v);
|
||||
heap.push_increase(incidence.0, Reverse(new_distance));
|
||||
distances[u] = Some(new_distance);
|
||||
on_relax(u, v);
|
||||
heap.push_increase(u, Reverse(new_distance));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -741,7 +741,10 @@ where
|
||||
None => {
|
||||
stack.pop();
|
||||
}
|
||||
Some((neighbor, edge)) => {
|
||||
Some(Incidence {
|
||||
vertex: neighbor,
|
||||
edge,
|
||||
}) => {
|
||||
if predicate(neighbor) {
|
||||
let mut path: Vec<G::Edge> =
|
||||
stack.iter().filter_map(|f| f.arrival_edge).collect();
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ pub mod traits;
|
||||
|
||||
/// Convenience re-exports of graph topology traits for common use.
|
||||
pub mod prelude {
|
||||
pub use crate::traits::{GraphTopology, GraphTopologyDeletion, IncidenceCursor};
|
||||
pub use crate::traits::{GraphTopology, GraphTopologyDeletion, Incidence, IncidenceCursor};
|
||||
}
|
||||
|
||||
mod testing;
|
||||
|
||||
+4
-2
@@ -5,5 +5,7 @@ pub mod graph;
|
||||
|
||||
// TODO: Compressed-sparse-row graph model.
|
||||
|
||||
pub use append_graph::{AppendGraph, AppendGraphEdgeMap, AppendGraphVertexMap};
|
||||
pub use graph::{Graph, GraphEdgeMap, GraphVertexMap};
|
||||
pub use append_graph::{
|
||||
AppendGraph, AppendGraphEdgeMap, AppendGraphIncidence, AppendGraphVertexMap,
|
||||
};
|
||||
pub use graph::{Graph, GraphEdgeMap, GraphIncidence, GraphVertexMap};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! [`AppendGraph`], an undirected graph topology supporting addition only.
|
||||
|
||||
use crate::maps::EntityMap;
|
||||
use crate::traits::{GraphTopology, IncidenceCursor};
|
||||
use crate::traits::{GraphTopology, Incidence, IncidenceCursor};
|
||||
|
||||
/// An opaque handle identifying a vertex in an [`AppendGraph`].
|
||||
///
|
||||
@@ -23,6 +23,9 @@ pub type AppendGraphVertexMap<T> = EntityMap<Vertex, T>;
|
||||
/// An [`EntityMap`] for [`AppendGraph`] edges.
|
||||
pub type AppendGraphEdgeMap<T> = EntityMap<Edge, T>;
|
||||
|
||||
/// An [`Incidence`] for [`AppendGraph`].
|
||||
pub type AppendGraphIncidence = Incidence<Vertex, Edge>;
|
||||
|
||||
impl Edge {
|
||||
fn normalize(&self) -> Self {
|
||||
Self(self.0 & !1)
|
||||
@@ -50,10 +53,13 @@ pub struct AppendGraphIncidenceCursor {
|
||||
}
|
||||
|
||||
impl IncidenceCursor<AppendGraph> for AppendGraphIncidenceCursor {
|
||||
fn next(&mut self, graph: &AppendGraph) -> Option<(Vertex, Edge)> {
|
||||
fn next(&mut self, graph: &AppendGraph) -> Option<AppendGraphIncidence> {
|
||||
graph
|
||||
.step_incidence(&mut self.incidence)
|
||||
.map(|(v, e)| (v, e.normalize()))
|
||||
.map(|(v, e)| Incidence {
|
||||
vertex: v,
|
||||
edge: e.normalize(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,8 +197,11 @@ impl GraphTopology for AppendGraph {
|
||||
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 incidences(&self, v: Self::Vertex) -> impl Iterator<Item = AppendGraphIncidence> {
|
||||
self.raw_incidences(v).map(|(v, e)| Incidence {
|
||||
vertex: v,
|
||||
edge: e.normalize(),
|
||||
})
|
||||
}
|
||||
|
||||
fn incidence_cursor(&self, v: Self::Vertex) -> Self::IncidenceCursor {
|
||||
|
||||
+15
-10
@@ -3,7 +3,7 @@
|
||||
use typed_generational_arena::{Arena, Index};
|
||||
|
||||
use crate::maps::EntityMap;
|
||||
use crate::traits::{GraphTopology, GraphTopologyDeletion, IncidenceCursor};
|
||||
use crate::traits::{GraphTopology, GraphTopologyDeletion, Incidence, IncidenceCursor};
|
||||
|
||||
/// An opaque handle identifying a vertex in a [`Graph`].
|
||||
///
|
||||
@@ -23,6 +23,9 @@ pub type GraphVertexMap<T> = EntityMap<Vertex, T>;
|
||||
/// An [`EntityMap`] for [`Graph`] edges.
|
||||
pub type GraphEdgeMap<T> = EntityMap<Edge, T>;
|
||||
|
||||
/// An [`Incidence`] for [`Graph`].
|
||||
pub type GraphIncidence = Incidence<Vertex, Edge>;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
struct VertexSlot(usize);
|
||||
|
||||
@@ -66,12 +69,12 @@ pub struct GraphIncidenceCursor {
|
||||
}
|
||||
|
||||
impl IncidenceCursor<Graph> for GraphIncidenceCursor {
|
||||
fn next(&mut self, graph: &Graph) -> Option<(Vertex, Edge)> {
|
||||
graph.step_incidence(&mut self.incidence).map(|(vs, e)| {
|
||||
(
|
||||
graph.vertices.get_idx(vs.0).unwrap(),
|
||||
graph.normalize_edge(e),
|
||||
)
|
||||
fn next(&mut self, graph: &Graph) -> Option<GraphIncidence> {
|
||||
graph
|
||||
.step_incidence(&mut self.incidence)
|
||||
.map(|(vs, e)| Incidence {
|
||||
vertex: graph.vertices.get_idx(vs.0).unwrap(),
|
||||
edge: graph.normalize_edge(e),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -297,9 +300,11 @@ impl GraphTopology for Graph {
|
||||
self.raw_incidences(v).map(|(_, e)| self.normalize_edge(e))
|
||||
}
|
||||
|
||||
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)> {
|
||||
self.raw_incidences(v)
|
||||
.map(|(vs, e)| (self.vertices.get_idx(vs.0).unwrap(), self.normalize_edge(e)))
|
||||
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = GraphIncidence> {
|
||||
self.raw_incidences(v).map(|(vs, e)| Incidence {
|
||||
vertex: self.vertices.get_idx(vs.0).unwrap(),
|
||||
edge: self.normalize_edge(e),
|
||||
})
|
||||
}
|
||||
|
||||
fn incidence_cursor(&self, v: Self::Vertex) -> Self::IncidenceCursor {
|
||||
|
||||
@@ -296,10 +296,12 @@ macro_rules! dijkstra_tests {
|
||||
<$T as $crate::traits::GraphTopology>::Vertex,
|
||||
<$T as $crate::traits::GraphTopology>::Vertex,
|
||||
); 18],
|
||||
[Vec<(
|
||||
[Vec<
|
||||
$crate::traits::Incidence<
|
||||
<$T as $crate::traits::GraphTopology>::Vertex,
|
||||
<$T as $crate::traits::GraphTopology>::Edge,
|
||||
)>; 10],
|
||||
>,
|
||||
>; 10],
|
||||
$crate::maps::EntityMap<<$T as $crate::traits::GraphTopology>::Edge, u32>,
|
||||
) {
|
||||
use $crate::traits::GraphTopology;
|
||||
|
||||
@@ -10,12 +10,12 @@ macro_rules! graph_topology_test_fixtures {
|
||||
<$T as $crate::traits::GraphTopology>::Vertex,
|
||||
<$T as $crate::traits::GraphTopology>::Vertex,
|
||||
); 18],
|
||||
[Vec<(
|
||||
[Vec<$crate::traits::Incidence<
|
||||
<$T as $crate::traits::GraphTopology>::Vertex,
|
||||
<$T as $crate::traits::GraphTopology>::Edge,
|
||||
)>; 10],
|
||||
>>; 10],
|
||||
) {
|
||||
use $crate::traits::GraphTopology;
|
||||
use $crate::traits::{GraphTopology, Incidence};
|
||||
let mut graph = <$T>::new();
|
||||
let vertices: [<$T as $crate::traits::GraphTopology>::Vertex; 10] =
|
||||
core::array::from_fn(|_| graph.add_vertex());
|
||||
@@ -40,50 +40,54 @@ macro_rules! graph_topology_test_fixtures {
|
||||
(vertices[7], vertices[9]),
|
||||
]
|
||||
.map(|(v1, v2)| (graph.add_edge(v1, v2), v1, v2));
|
||||
let incidences: [Vec<_>; 10] = [
|
||||
vec![(vertices[1], edges[0].0), (vertices[1], edges[1].0)],
|
||||
let i = |vertex, edge| Incidence { vertex, edge };
|
||||
let incidences: [Vec<Incidence<
|
||||
<$T as GraphTopology>::Vertex,
|
||||
<$T as GraphTopology>::Edge,
|
||||
>>; 10] = [
|
||||
vec![i(vertices[1], edges[0].0), i(vertices[1], edges[1].0)],
|
||||
vec![
|
||||
(vertices[0], edges[0].0),
|
||||
(vertices[0], edges[1].0),
|
||||
(vertices[2], edges[2].0),
|
||||
(vertices[3], edges[3].0),
|
||||
(vertices[4], edges[4].0),
|
||||
i(vertices[0], edges[0].0),
|
||||
i(vertices[0], edges[1].0),
|
||||
i(vertices[2], edges[2].0),
|
||||
i(vertices[3], edges[3].0),
|
||||
i(vertices[4], edges[4].0),
|
||||
],
|
||||
vec![
|
||||
(vertices[2], edges[5].0),
|
||||
(vertices[2], edges[5].0),
|
||||
(vertices[1], edges[2].0),
|
||||
(vertices[4], edges[6].0),
|
||||
(vertices[4], edges[7].0),
|
||||
(vertices[5], edges[8].0),
|
||||
(vertices[6], edges[9].0),
|
||||
i(vertices[2], edges[5].0),
|
||||
i(vertices[2], edges[5].0),
|
||||
i(vertices[1], edges[2].0),
|
||||
i(vertices[4], edges[6].0),
|
||||
i(vertices[4], edges[7].0),
|
||||
i(vertices[5], edges[8].0),
|
||||
i(vertices[6], edges[9].0),
|
||||
],
|
||||
vec![(vertices[1], edges[3].0), (vertices[6], edges[10].0)],
|
||||
vec![i(vertices[1], edges[3].0), i(vertices[6], edges[10].0)],
|
||||
vec![
|
||||
(vertices[1], edges[4].0),
|
||||
(vertices[2], edges[6].0),
|
||||
(vertices[2], edges[7].0),
|
||||
(vertices[4], edges[11].0),
|
||||
(vertices[4], edges[11].0),
|
||||
(vertices[7], edges[12].0),
|
||||
(vertices[8], edges[13].0),
|
||||
i(vertices[1], edges[4].0),
|
||||
i(vertices[2], edges[6].0),
|
||||
i(vertices[2], edges[7].0),
|
||||
i(vertices[4], edges[11].0),
|
||||
i(vertices[4], edges[11].0),
|
||||
i(vertices[7], edges[12].0),
|
||||
i(vertices[8], edges[13].0),
|
||||
],
|
||||
vec![(vertices[2], edges[8].0), (vertices[9], edges[14].0)],
|
||||
vec![i(vertices[2], edges[8].0), i(vertices[9], edges[14].0)],
|
||||
vec![
|
||||
(vertices[2], edges[9].0),
|
||||
(vertices[3], edges[10].0),
|
||||
(vertices[9], edges[15].0),
|
||||
i(vertices[2], edges[9].0),
|
||||
i(vertices[3], edges[10].0),
|
||||
i(vertices[9], edges[15].0),
|
||||
],
|
||||
vec![
|
||||
(vertices[4], edges[12].0),
|
||||
(vertices[8], edges[16].0),
|
||||
(vertices[9], edges[17].0),
|
||||
i(vertices[4], edges[12].0),
|
||||
i(vertices[8], edges[16].0),
|
||||
i(vertices[9], edges[17].0),
|
||||
],
|
||||
vec![(vertices[4], edges[13].0), (vertices[7], edges[16].0)],
|
||||
vec![i(vertices[4], edges[13].0), i(vertices[7], edges[16].0)],
|
||||
vec![
|
||||
(vertices[5], edges[14].0),
|
||||
(vertices[6], edges[15].0),
|
||||
(vertices[7], edges[17].0),
|
||||
i(vertices[5], edges[14].0),
|
||||
i(vertices[6], edges[15].0),
|
||||
i(vertices[7], edges[17].0),
|
||||
],
|
||||
];
|
||||
(graph, vertices, edges, incidences)
|
||||
@@ -540,7 +544,7 @@ macro_rules! graph_topology_tests {
|
||||
"unexpected incident edge count for vertex {:?}",
|
||||
vertices[i]
|
||||
);
|
||||
let mut expected: Vec<_> = incidences[i].iter().map(|(_, e)| *e).collect();
|
||||
let mut expected: Vec<_> = incidences[i].iter().map(|x| x.edge).collect();
|
||||
for e in graph.incident_edges(vertices[i]) {
|
||||
let pos = expected
|
||||
.iter()
|
||||
@@ -634,7 +638,7 @@ macro_rules! graph_topology_tests {
|
||||
for incidence in graph.incidences(vertices[i]) {
|
||||
let pos = expected
|
||||
.iter()
|
||||
.position(|(v, e)| *v == incidence.0 && *e == incidence.1)
|
||||
.position(|x| *x == incidence)
|
||||
.expect(&format!(
|
||||
"unexpected incidence {incidence:?} of vertex {:?} from iterator",
|
||||
vertices[i]
|
||||
@@ -657,17 +661,21 @@ macro_rules! graph_topology_tests {
|
||||
// For loop edges (u == v), the edge must appear exactly twice in the incidences of u.
|
||||
let (graph, _, _, _) = make_test_graph();
|
||||
for u in graph.vertices() {
|
||||
for (v, e) in graph.incidences(u) {
|
||||
if u == v {
|
||||
for incidence in graph.incidences(u) {
|
||||
if u == incidence.vertex {
|
||||
assert_eq!(
|
||||
graph.incidences(u).filter(|(_, f)| *f == e).count(),
|
||||
graph.incidences(u).filter(|x| x.edge == incidence.edge).count(),
|
||||
2,
|
||||
"loop edge {e:?} should appear exactly twice in incidences of vertex {u:?}"
|
||||
"loop edge {:?} should appear exactly twice in incidences of vertex {u:?}",
|
||||
incidence.edge
|
||||
);
|
||||
} else {
|
||||
assert!(
|
||||
graph.incidences(v).any(|(w, f)| w == u && f == e),
|
||||
"edge {e:?} from incidences of vertex {u:?} missing in incidences of adjacent vertex {v:?}"
|
||||
graph
|
||||
.incidences(incidence.vertex)
|
||||
.any(|x| x.vertex == u && x.edge == incidence.edge),
|
||||
"edge {:?} from incidences of vertex {u:?} missing in incidences of adjacent vertex {:?}",
|
||||
incidence.edge, incidence.vertex
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -676,19 +684,19 @@ macro_rules! graph_topology_tests {
|
||||
|
||||
#[test]
|
||||
fn incidences_loop_edge() {
|
||||
use $crate::traits::GraphTopology;
|
||||
use $crate::traits::{GraphTopology, Incidence};
|
||||
let mut graph = <$T>::new();
|
||||
let v = graph.add_vertex();
|
||||
let e = graph.add_edge(v, v);
|
||||
let mut iter = graph.incidences(v);
|
||||
assert_eq!(
|
||||
iter.next(),
|
||||
Some((v, e)),
|
||||
Some(Incidence { vertex: v, edge: e }),
|
||||
"vertex should be adjacent to itself"
|
||||
);
|
||||
assert_eq!(
|
||||
iter.next(),
|
||||
Some((v, e)),
|
||||
Some(Incidence { vertex: v, edge: e }),
|
||||
"vertex should be adjacent to itself twice"
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -716,16 +724,16 @@ macro_rules! graph_topology_tests {
|
||||
vertices[i]
|
||||
));
|
||||
assert_eq!(
|
||||
current.0,
|
||||
current.vertex,
|
||||
vertices[1 - i],
|
||||
"unexpected adjacent vertex of vertex {:?} in incidence {j}",
|
||||
vertices[i]
|
||||
);
|
||||
assert_eq!(
|
||||
edges.iter().filter(|e| **e == current.1).count(),
|
||||
edges.iter().filter(|e| **e == current.edge).count(),
|
||||
1,
|
||||
"unexpected incident edge {:?} of vertex {:?}",
|
||||
current.1,
|
||||
current.edge,
|
||||
vertices[i],
|
||||
);
|
||||
}
|
||||
@@ -761,7 +769,7 @@ macro_rules! graph_topology_tests {
|
||||
while let Some(incidence) = cursor.next(&graph) {
|
||||
let pos = expected
|
||||
.iter()
|
||||
.position(|(v, e)| *v == incidence.0 && *e == incidence.1)
|
||||
.position(|x| *x == incidence)
|
||||
.expect(&format!(
|
||||
"unexpected incidence {incidence:?} of vertex {:?} from cursor",
|
||||
vertices[i]
|
||||
@@ -779,19 +787,19 @@ macro_rules! graph_topology_tests {
|
||||
|
||||
#[test]
|
||||
fn incidence_cursor_loop_edge() {
|
||||
use $crate::traits::{GraphTopology, IncidenceCursor};
|
||||
use $crate::traits::{GraphTopology, Incidence, IncidenceCursor};
|
||||
let mut graph = <$T>::new();
|
||||
let v = graph.add_vertex();
|
||||
let e = graph.add_edge(v, v);
|
||||
let mut cursor = graph.incidence_cursor(v);
|
||||
assert_eq!(
|
||||
cursor.next(&graph),
|
||||
Some((v, e)),
|
||||
Some(Incidence { vertex: v, edge: e }),
|
||||
"vertex should be adjacent to itself"
|
||||
);
|
||||
assert_eq!(
|
||||
cursor.next(&graph),
|
||||
Some((v, e)),
|
||||
Some(Incidence { vertex: v, edge: e }),
|
||||
"vertex should be adjacent to itself twice"
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -819,16 +827,16 @@ macro_rules! graph_topology_tests {
|
||||
vertices[i]
|
||||
));
|
||||
assert_eq!(
|
||||
current.0,
|
||||
current.vertex,
|
||||
vertices[1 - i],
|
||||
"unexpected adjacent vertex of vertex {:?} in incidence {j}",
|
||||
vertices[i]
|
||||
);
|
||||
assert_eq!(
|
||||
edges.iter().filter(|e| **e == current.1).count(),
|
||||
edges.iter().filter(|e| **e == current.edge).count(),
|
||||
1,
|
||||
"unexpected incident edge {:?} of vertex {:?}",
|
||||
current.1,
|
||||
current.edge,
|
||||
vertices[i],
|
||||
);
|
||||
}
|
||||
@@ -868,11 +876,12 @@ macro_rules! graph_topology_tests {
|
||||
use $crate::traits::GraphTopology;
|
||||
let (graph, _, _, _) = make_test_graph();
|
||||
for u in graph.vertices() {
|
||||
for (v, e) in graph.incidences(u) {
|
||||
let (w1, w2) = graph.incident_vertices(e);
|
||||
for incidence in graph.incidences(u) {
|
||||
let (w1, w2) = graph.incident_vertices(incidence.edge);
|
||||
assert!(
|
||||
(w1 == u && w2 == v) || (w1 == v && w2 == u),
|
||||
"incident vertices {w1:?} and {w2:?} of edge {e:?} are inconsistent with incidence ({v:?}, {e:?}) of vertex {u:?}"
|
||||
(w1 == u && w2 == incidence.vertex) || (w1 == incidence.vertex && w2 == u),
|
||||
"edge endpoints {w1:?} and {w2:?} are inconsistent with incidence ({:?}, {:?}) of vertex {u:?}",
|
||||
incidence.vertex, incidence.edge
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -883,7 +892,7 @@ macro_rules! graph_topology_tests {
|
||||
use $crate::traits::GraphTopology;
|
||||
let (graph, _, _, _) = make_test_graph();
|
||||
for u in graph.vertices() {
|
||||
let mut expected: Vec<_> = graph.incidences(u).map(|(_, e)| e).collect();
|
||||
let mut expected: Vec<_> = graph.incidences(u).map(|x| x.edge).collect();
|
||||
for e in graph.incident_edges(u) {
|
||||
let pos = expected
|
||||
.iter()
|
||||
@@ -1256,7 +1265,7 @@ macro_rules! graph_topology_deletion_tests {
|
||||
for i in 0..10 {
|
||||
let mut expected: Vec<_> = incidences[i]
|
||||
.iter()
|
||||
.filter_map(|(_, e)| (*e != edges[2].0).then_some(*e))
|
||||
.filter_map(|x| (x.edge != edges[2].0).then_some(x.edge))
|
||||
.collect();
|
||||
assert_eq!(
|
||||
graph.incident_edges(vertices[i]).count(),
|
||||
@@ -1289,7 +1298,7 @@ macro_rules! graph_topology_deletion_tests {
|
||||
for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] {
|
||||
let mut expected: Vec<_> = incidences[i]
|
||||
.iter()
|
||||
.filter_map(|(v, e)| (*v != vertices[2]).then_some(*e))
|
||||
.filter_map(|x| (x.vertex != vertices[2]).then_some(x.edge))
|
||||
.collect();
|
||||
assert_eq!(
|
||||
graph.incident_edges(vertices[i]).count(),
|
||||
@@ -1321,7 +1330,7 @@ macro_rules! graph_topology_deletion_tests {
|
||||
for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] {
|
||||
let remaining = incidences[i]
|
||||
.iter()
|
||||
.filter(|(v, _)| *v != vertices[2])
|
||||
.filter(|x| x.vertex != vertices[2])
|
||||
.cloned()
|
||||
.collect();
|
||||
assert_vertex_incidences(&graph, vertices[i], remaining);
|
||||
@@ -1337,7 +1346,7 @@ macro_rules! graph_topology_deletion_tests {
|
||||
for i in 0..10 {
|
||||
let remaining = incidences[i]
|
||||
.iter()
|
||||
.filter(|(_, e)| *e != edges[2].0)
|
||||
.filter(|x| x.edge != edges[2].0)
|
||||
.cloned()
|
||||
.collect();
|
||||
assert_vertex_incidences(&graph, vertices[i], remaining);
|
||||
@@ -1347,10 +1356,10 @@ macro_rules! graph_topology_deletion_tests {
|
||||
fn assert_vertex_incidences(
|
||||
graph: &$T,
|
||||
v: <$T as $crate::traits::GraphTopology>::Vertex,
|
||||
mut expected: Vec<(
|
||||
mut expected: Vec<$crate::traits::Incidence<
|
||||
<$T as $crate::traits::GraphTopology>::Vertex,
|
||||
<$T as $crate::traits::GraphTopology>::Edge,
|
||||
)>,
|
||||
>>,
|
||||
) {
|
||||
use $crate::traits::GraphTopology;
|
||||
assert_eq!(
|
||||
@@ -1362,7 +1371,7 @@ macro_rules! graph_topology_deletion_tests {
|
||||
for incidence in graph.incidences(v) {
|
||||
let pos = expected
|
||||
.iter()
|
||||
.position(|(u, e)| *u == incidence.0 && *e == incidence.1)
|
||||
.position(|x| *x == incidence)
|
||||
.expect(&format!(
|
||||
"unexpected incidence {incidence:?} of vertex {:?} from iterator after delete",
|
||||
v
|
||||
@@ -1385,7 +1394,7 @@ macro_rules! graph_topology_deletion_tests {
|
||||
for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] {
|
||||
let remaining = incidences[i]
|
||||
.iter()
|
||||
.filter(|(v, _)| *v != vertices[2])
|
||||
.filter(|x| x.vertex != vertices[2])
|
||||
.cloned()
|
||||
.collect();
|
||||
assert_vertex_incidence_cursor(&graph, vertices[i], remaining);
|
||||
@@ -1401,7 +1410,7 @@ macro_rules! graph_topology_deletion_tests {
|
||||
for i in 0..10 {
|
||||
let remaining = incidences[i]
|
||||
.iter()
|
||||
.filter(|(_, e)| *e != edges[2].0)
|
||||
.filter(|x| x.edge != edges[2].0)
|
||||
.cloned()
|
||||
.collect();
|
||||
assert_vertex_incidence_cursor(&graph, vertices[i], remaining);
|
||||
@@ -1411,17 +1420,17 @@ macro_rules! graph_topology_deletion_tests {
|
||||
fn assert_vertex_incidence_cursor(
|
||||
graph: &$T,
|
||||
v: <$T as $crate::traits::GraphTopology>::Vertex,
|
||||
mut expected: Vec<(
|
||||
mut expected: Vec<$crate::traits::Incidence<
|
||||
<$T as $crate::traits::GraphTopology>::Vertex,
|
||||
<$T as $crate::traits::GraphTopology>::Edge,
|
||||
)>,
|
||||
>>,
|
||||
) {
|
||||
use $crate::traits::IncidenceCursor;
|
||||
let mut cursor = graph.incidence_cursor(v);
|
||||
while let Some(incidence) = cursor.next(graph) {
|
||||
let pos = expected
|
||||
.iter()
|
||||
.position(|(u, e)| *u == incidence.0 && *e == incidence.1)
|
||||
.position(|x| *x == incidence)
|
||||
.expect(&format!(
|
||||
"unexpected incidence {incidence:?} of vertex {:?} from cursor after delete",
|
||||
v
|
||||
|
||||
+19
-5
@@ -4,7 +4,6 @@ use crate::maps::EntityMap;
|
||||
|
||||
// TODO: Add functions to reserve memory for vertices and edges.
|
||||
// TODO: Split out GraphTopologyAddition trait.
|
||||
// TODO: Introduce an Incidence struct.
|
||||
/// A trait representing an undirected graph topology.
|
||||
///
|
||||
/// An undirected graph is a set of vertices and undirected edges, where each edge connects either
|
||||
@@ -165,7 +164,10 @@ pub trait GraphTopology {
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `v` is not a valid vertex of this graph.
|
||||
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)>;
|
||||
fn incidences(
|
||||
&self,
|
||||
v: Self::Vertex,
|
||||
) -> impl Iterator<Item = Incidence<Self::Vertex, Self::Edge>>;
|
||||
|
||||
/// Returns a cursor over all incidences of `v`, analogously to
|
||||
/// [`incidences`](Self::incidences), initially positioned before the first one.
|
||||
@@ -221,8 +223,8 @@ pub trait GraphTopologyDeletion: GraphTopology {
|
||||
/// [`GraphTopology::IncidenceCursor`] for guidance on when to prefer a cursor over
|
||||
/// [`GraphTopology::incidences`].
|
||||
pub trait IncidenceCursor<G: GraphTopology + ?Sized>: Copy {
|
||||
/// Advances the cursor and returns the next incidence as `Some((u, e))`, or `None` if the
|
||||
/// traversal is exhausted.
|
||||
/// Advances the cursor and returns the next incidence, or `None` if the traversal is
|
||||
/// exhausted.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@@ -248,5 +250,17 @@ pub trait IncidenceCursor<G: GraphTopology + ?Sized>: Copy {
|
||||
/// assert!(c2.next(&graph).is_some());
|
||||
/// assert!(c2.next(&graph).is_none());
|
||||
/// ```
|
||||
fn next(&mut self, graph: &G) -> Option<(G::Vertex, G::Edge)>;
|
||||
fn next(&mut self, graph: &G) -> Option<Incidence<G::Vertex, G::Edge>>;
|
||||
}
|
||||
|
||||
/// An incidence of some vertex *v* in a graph, i.e. a vertex-edge pair *(u, e)* such that *u* is
|
||||
/// adjacent to *v* and *e* is an edge between them.
|
||||
///
|
||||
/// Return type of [`GraphTopology::incidences`] and [`IncidenceCursor::next`].
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Incidence<V, E> {
|
||||
/// The vertex adjacent to *v*.
|
||||
pub vertex: V,
|
||||
/// The edge between *v* and [`vertex`](Self::vertex).
|
||||
pub edge: E,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user