Common neighbors #9
+110
-19
@@ -84,37 +84,128 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::models::{FrozenGraph, Graph};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn petersen() {
|
fn petersen_append_graph() {
|
||||||
let mut graph = AppendGraph::new();
|
petersen_add::<AppendGraph>();
|
||||||
let (vertices, edges) = super::petersen(&mut graph);
|
}
|
||||||
assert_eq!(
|
|
||||||
graph.vertex_count(),
|
#[test]
|
||||||
10,
|
fn petersen_graph() {
|
||||||
"unexpected number of added vertices"
|
petersen_add::<Graph>();
|
||||||
);
|
}
|
||||||
assert_eq!(graph.edge_count(), 15, "unexpected number of added edges");
|
|
||||||
|
#[test]
|
||||||
|
fn petersen_frozen_graph() {
|
||||||
|
petersen_generate_as::<FrozenGraph>();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn petersen_generate_as<G: GraphTopologyConversion>()
|
||||||
|
where
|
||||||
|
G::Vertex: Debug,
|
||||||
|
G::Edge: Debug,
|
||||||
|
{
|
||||||
|
let (graph, vertices, edges) = generate_as::<G, _, _>(petersen);
|
||||||
|
assert_petersen(&graph, &vertices, &edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn petersen_add<G: GraphTopologyAddition>()
|
||||||
|
where
|
||||||
|
G::Vertex: Debug,
|
||||||
|
G::Edge: Debug,
|
||||||
|
{
|
||||||
|
let mut graph = G::default();
|
||||||
|
let (vertices, edges) = petersen(&mut graph);
|
||||||
|
assert_petersen(&graph, &vertices, &edges);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_petersen<G: GraphTopology>(graph: &G, vertices: &[G::Vertex], edges: &[G::Edge])
|
||||||
|
where
|
||||||
|
G::Vertex: Debug,
|
||||||
|
G::Edge: Debug,
|
||||||
|
{
|
||||||
|
assert_element_counts(graph, 10, 15);
|
||||||
|
assert_handles(graph.vertices(), vertices, "vertex");
|
||||||
|
assert_handles(graph.edges(), edges, "edge");
|
||||||
|
assert_no_loops_no_multi_edges(graph);
|
||||||
assert!(
|
assert!(
|
||||||
graph.vertices().all(|v| graph.degree(v) == 3),
|
graph.vertices().all(|v| graph.degree(v) == 3),
|
||||||
"all vertices should have degree 3"
|
"all vertices should have degree 3"
|
||||||
);
|
);
|
||||||
assert_handles_in_graph(&graph, &vertices, &edges);
|
// Checks that each pair of vertices (u, v) has no common neighbor if they are adjacent, and
|
||||||
|
// exactly one common neighbor otherwise.
|
||||||
|
for (i, &v) in vertices.iter().enumerate() {
|
||||||
|
for &u in &vertices[i + 1..] {
|
||||||
|
if graph.are_adjacent(v, u) {
|
||||||
|
assert!(
|
||||||
|
graph.common_neighbors(u, v).next().is_none(),
|
||||||
|
"adjacent vertices {u:?} and {v:?} should not have a common neighbor"
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
graph.common_neighbors(u, v).count(),
|
||||||
|
1,
|
||||||
|
"non-adjacent vertices {u:?} and {v:?} should have exactly one common neighbor"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_handles_in_graph<G: GraphTopology>(
|
fn assert_element_counts<G: GraphTopology>(
|
||||||
graph: &G,
|
graph: &G,
|
||||||
vertices: &[G::Vertex],
|
expected_vertex_count: usize,
|
||||||
edges: &[G::Edge],
|
expected_edge_count: usize,
|
||||||
) {
|
) {
|
||||||
assert!(
|
assert_eq!(
|
||||||
vertices.iter().all(|&v| graph.vertices().any(|u| u == v)),
|
graph.vertex_count(),
|
||||||
"all returned vertices should be in the graph"
|
expected_vertex_count,
|
||||||
|
"unexpected number of vertices"
|
||||||
);
|
);
|
||||||
assert!(
|
assert_eq!(
|
||||||
edges.iter().all(|&e| graph.edges().any(|f| f == e)),
|
graph.edge_count(),
|
||||||
"all returned edges should be in the graph"
|
expected_edge_count,
|
||||||
|
"unexpected number of edges"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Asserts that every handle in `returned` is unique and in `all`.
|
||||||
|
fn assert_handles<T: PartialEq + Debug>(
|
||||||
|
all: impl Iterator<Item = T>,
|
||||||
|
returned: &[T],
|
||||||
|
kind: &str,
|
||||||
|
) {
|
||||||
|
let mut remaining: Vec<T> = all.collect();
|
||||||
|
for e in returned {
|
||||||
|
let Some(position) = remaining.iter().position(|x| x == e) else {
|
||||||
|
panic!("returned {kind} {e:?} is not in the graph or appears more than once");
|
||||||
|
};
|
||||||
|
remaining.swap_remove(position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_no_loops_no_multi_edges<G: GraphTopology>(graph: &G)
|
||||||
|
where
|
||||||
|
G::Vertex: Debug,
|
||||||
|
G::Edge: Debug,
|
||||||
|
{
|
||||||
|
for e in graph.edges() {
|
||||||
|
let (u, v) = graph.incident_vertices(e);
|
||||||
|
assert_ne!(u, v, "unexpected loop edge {e:?}");
|
||||||
|
}
|
||||||
|
for v in graph.vertices() {
|
||||||
|
let mut neighbors = Vec::new();
|
||||||
|
for u in graph.adjacent_vertices(v) {
|
||||||
|
assert!(
|
||||||
|
!neighbors.contains(&u),
|
||||||
|
"unexpected multi-edge between {v:?} and {u:?}"
|
||||||
|
);
|
||||||
|
neighbors.push(u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user