Add GraphTopology::incident_edges() and tests
This commit is contained in:
@@ -130,6 +130,14 @@ impl GraphTopology for AppendGraph {
|
|||||||
(0..self.incidences.len()).step_by(2).map(Incidence)
|
(0..self.incidences.len()).step_by(2).map(Incidence)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn incident_edges(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Edge> {
|
||||||
|
RawIncidenceIterator {
|
||||||
|
graph: self,
|
||||||
|
incidence: self.vertices[v.0].first_incidence,
|
||||||
|
}
|
||||||
|
.map(|(_, e)| e.normalize())
|
||||||
|
}
|
||||||
|
|
||||||
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)> {
|
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)> {
|
||||||
RawIncidenceIterator {
|
RawIncidenceIterator {
|
||||||
graph: self,
|
graph: self,
|
||||||
|
|||||||
@@ -200,6 +200,10 @@ impl GraphTopology for Graph {
|
|||||||
.map(|(i, _)| i)
|
.map(|(i, _)| i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn incident_edges(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Edge> {
|
||||||
|
self.raw_incidences(v).map(|(_, e)| self.normalize_edge(e))
|
||||||
|
}
|
||||||
|
|
||||||
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)> {
|
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)> {
|
||||||
self.raw_incidences(v)
|
self.raw_incidences(v)
|
||||||
.map(|(vs, e)| (self.vertices.get_idx(vs.0).unwrap(), self.normalize_edge(e)))
|
.map(|(vs, e)| (self.vertices.get_idx(vs.0).unwrap(), self.normalize_edge(e)))
|
||||||
|
|||||||
@@ -452,6 +452,92 @@ macro_rules! graph_topology_tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn incident_edges_empty() {
|
||||||
|
let mut graph = <$T>::new();
|
||||||
|
let v = graph.add_vertex();
|
||||||
|
assert_eq!(
|
||||||
|
graph.incident_edges(v).count(),
|
||||||
|
0,
|
||||||
|
"incident edge iterator of vertex with degree 0 should have no elements"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn incident_edges() {
|
||||||
|
let (graph, vertices, _, incidences) = make_test_graph();
|
||||||
|
for i in 0..10 {
|
||||||
|
assert_eq!(
|
||||||
|
graph.incident_edges(vertices[i]).count(),
|
||||||
|
incidences[i].len(),
|
||||||
|
"unexpected incident edge count for vertex {:?}",
|
||||||
|
vertices[i]
|
||||||
|
);
|
||||||
|
let mut expected: Vec<_> = incidences[i].iter().map(|(_, e)| *e).collect();
|
||||||
|
for e in graph.incident_edges(vertices[i]) {
|
||||||
|
let pos = expected
|
||||||
|
.iter()
|
||||||
|
.position(|f| *f == e)
|
||||||
|
.expect(&format!(
|
||||||
|
"unexpected incident edge {e:?} of vertex {:?} from the iterator",
|
||||||
|
vertices[i]
|
||||||
|
));
|
||||||
|
expected.swap_remove(pos);
|
||||||
|
}
|
||||||
|
assert!(
|
||||||
|
expected.is_empty(),
|
||||||
|
"expected incident edges {:?} of vertex {:?} were not matched by the iterator",
|
||||||
|
expected,
|
||||||
|
vertices[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn incident_edges_loop_edge() {
|
||||||
|
let mut graph = <$T>::new();
|
||||||
|
let v = graph.add_vertex();
|
||||||
|
let e = graph.add_edge(v, v);
|
||||||
|
let mut iter = graph.incident_edges(v);
|
||||||
|
assert_eq!(iter.next(), Some(e), "loop edge should appear in incident edges");
|
||||||
|
assert_eq!(
|
||||||
|
iter.next(),
|
||||||
|
Some(e),
|
||||||
|
"loop edge should appear twice in incident edges"
|
||||||
|
);
|
||||||
|
assert_eq!(iter.next(), None, "too many incident edges from iterator");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn incident_edges_multiple_edges() {
|
||||||
|
let k = 3;
|
||||||
|
let mut graph = <$T>::new();
|
||||||
|
let vertices = [graph.add_vertex(), graph.add_vertex()];
|
||||||
|
let mut edges = Vec::new();
|
||||||
|
for _ in 0..k {
|
||||||
|
edges.push(graph.add_edge(vertices[0], vertices[1]));
|
||||||
|
}
|
||||||
|
for i in 0..2 {
|
||||||
|
let mut expected = edges.clone();
|
||||||
|
for e in graph.incident_edges(vertices[i]) {
|
||||||
|
let pos = expected
|
||||||
|
.iter()
|
||||||
|
.position(|f| *f == e)
|
||||||
|
.expect(&format!(
|
||||||
|
"unexpected incident edge {e:?} of vertex {:?}",
|
||||||
|
vertices[i]
|
||||||
|
));
|
||||||
|
expected.swap_remove(pos);
|
||||||
|
}
|
||||||
|
assert!(
|
||||||
|
expected.is_empty(),
|
||||||
|
"expected incident edges {:?} of vertex {:?} were not matched by the iterator",
|
||||||
|
expected,
|
||||||
|
vertices[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn incidences_empty() {
|
fn incidences_empty() {
|
||||||
let mut graph = <$T>::new();
|
let mut graph = <$T>::new();
|
||||||
@@ -591,6 +677,28 @@ macro_rules! graph_topology_tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn incident_edges_incidences_consistency() {
|
||||||
|
let (graph, _, _, _) = make_test_graph();
|
||||||
|
for u in graph.vertices() {
|
||||||
|
let mut expected: Vec<_> = graph.incidences(u).map(|(_, e)| e).collect();
|
||||||
|
for e in graph.incident_edges(u) {
|
||||||
|
let pos = expected
|
||||||
|
.iter()
|
||||||
|
.position(|f| *f == e)
|
||||||
|
.expect(&format!(
|
||||||
|
"incident edge {e:?} of vertex {u:?} missing from incidences"
|
||||||
|
));
|
||||||
|
expected.swap_remove(pos);
|
||||||
|
}
|
||||||
|
assert!(
|
||||||
|
expected.is_empty(),
|
||||||
|
"incidence edges {:?} of vertex {u:?} not matched by incident_edges",
|
||||||
|
expected
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -916,6 +1024,70 @@ macro_rules! graph_topology_deletion_tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn incident_edges_after_delete_edge() {
|
||||||
|
let (mut graph, vertices, edges, incidences) = make_test_graph();
|
||||||
|
graph.delete_edge(edges[2].0);
|
||||||
|
for i in 0..10 {
|
||||||
|
let mut expected: Vec<_> = incidences[i]
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, e)| *e != edges[2].0)
|
||||||
|
.map(|(_, e)| *e)
|
||||||
|
.collect();
|
||||||
|
assert_eq!(
|
||||||
|
graph.incident_edges(vertices[i]).count(),
|
||||||
|
expected.len(),
|
||||||
|
"unexpected incident edge count for vertex {:?} after delete",
|
||||||
|
vertices[i]
|
||||||
|
);
|
||||||
|
for e in graph.incident_edges(vertices[i]) {
|
||||||
|
let pos = expected.iter().position(|f| *f == e).expect(&format!(
|
||||||
|
"unexpected incident edge {e:?} of vertex {:?} after delete",
|
||||||
|
vertices[i]
|
||||||
|
));
|
||||||
|
expected.swap_remove(pos);
|
||||||
|
}
|
||||||
|
assert!(
|
||||||
|
expected.is_empty(),
|
||||||
|
"expected incident edges {:?} of vertex {:?} not matched after delete",
|
||||||
|
expected,
|
||||||
|
vertices[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn incident_edges_after_delete_vertex() {
|
||||||
|
let (mut graph, vertices, _, incidences) = make_test_graph();
|
||||||
|
graph.delete_vertex(vertices[2]);
|
||||||
|
for i in [0, 1, 3, 4, 5, 6, 7, 8, 9] {
|
||||||
|
let mut expected: Vec<_> = incidences[i]
|
||||||
|
.iter()
|
||||||
|
.filter(|(v, _)| *v != vertices[2])
|
||||||
|
.map(|(_, e)| *e)
|
||||||
|
.collect();
|
||||||
|
assert_eq!(
|
||||||
|
graph.incident_edges(vertices[i]).count(),
|
||||||
|
expected.len(),
|
||||||
|
"unexpected incident edge count for vertex {:?} after delete",
|
||||||
|
vertices[i]
|
||||||
|
);
|
||||||
|
for e in graph.incident_edges(vertices[i]) {
|
||||||
|
let pos = expected.iter().position(|f| *f == e).expect(&format!(
|
||||||
|
"unexpected incident edge {e:?} of vertex {:?} after delete",
|
||||||
|
vertices[i]
|
||||||
|
));
|
||||||
|
expected.swap_remove(pos);
|
||||||
|
}
|
||||||
|
assert!(
|
||||||
|
expected.is_empty(),
|
||||||
|
"expected incident edges {:?} of vertex {:?} not matched after delete",
|
||||||
|
expected,
|
||||||
|
vertices[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn incidences_after_delete_vertex() {
|
fn incidences_after_delete_vertex() {
|
||||||
let (mut graph, vertices, _, incidences) = make_test_graph();
|
let (mut graph, vertices, _, incidences) = make_test_graph();
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,6 @@
|
|||||||
use crate::maps::{EdgeMap, VertexMap};
|
use crate::maps::{EdgeMap, VertexMap};
|
||||||
|
|
||||||
// TODO: Add functions to reserve memory for vertices and edges.
|
// TODO: Add functions to reserve memory for vertices and edges.
|
||||||
// TODO: Add iterator of incident edges for a vertex.
|
|
||||||
// TODO: Split out GraphTopologyAddition trait.
|
// TODO: Split out GraphTopologyAddition trait.
|
||||||
pub trait GraphTopology {
|
pub trait GraphTopology {
|
||||||
type Vertex: Copy + Eq;
|
type Vertex: Copy + Eq;
|
||||||
@@ -19,6 +18,7 @@ pub trait GraphTopology {
|
|||||||
fn adjacent_vertices(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Vertex>;
|
fn adjacent_vertices(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Vertex>;
|
||||||
fn incident_vertices(&self, e: Self::Edge) -> (Self::Vertex, Self::Vertex);
|
fn incident_vertices(&self, e: Self::Edge) -> (Self::Vertex, Self::Vertex);
|
||||||
fn edges(&self) -> impl Iterator<Item = Self::Edge>;
|
fn edges(&self) -> impl Iterator<Item = Self::Edge>;
|
||||||
|
fn incident_edges(&self, v: Self::Vertex) -> impl Iterator<Item = Self::Edge>;
|
||||||
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)>;
|
fn incidences(&self, v: Self::Vertex) -> impl Iterator<Item = (Self::Vertex, Self::Edge)>;
|
||||||
fn add_vertex(&mut self) -> Self::Vertex;
|
fn add_vertex(&mut self) -> Self::Vertex;
|
||||||
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;
|
||||||
|
|||||||
Reference in New Issue
Block a user