use crate::region::RegionSpec;
use crate::space::Space;
use indexmap::IndexSet;
pub fn assert_distance_reflexive(space: &dyn Space) {
for coord in space.canonical_ordering() {
let d = space.distance(&coord, &coord);
assert!(
(d - 0.0).abs() < f64::EPSILON,
"distance({coord:?}, {coord:?}) = {d}, expected 0.0"
);
}
}
pub fn assert_distance_symmetric(space: &dyn Space) {
let cells = space.canonical_ordering();
for a in &cells {
for b in &cells {
let dab = space.distance(a, b);
let dba = space.distance(b, a);
assert!(
(dab - dba).abs() < f64::EPSILON,
"distance({a:?}, {b:?}) = {dab} != distance({b:?}, {a:?}) = {dba}"
);
}
}
}
pub fn assert_distance_triangle_inequality(space: &dyn Space) {
let cells = space.canonical_ordering();
for a in &cells {
for b in &cells {
for c in &cells {
let dac = space.distance(a, c);
let dab = space.distance(a, b);
let dbc = space.distance(b, c);
assert!(
dac <= dab + dbc + f64::EPSILON,
"triangle inequality violated: d({a:?},{c:?})={dac} > d({a:?},{b:?})={dab} + d({b:?},{c:?})={dbc}"
);
}
}
}
}
pub fn assert_neighbours_symmetric(space: &dyn Space) {
for coord in space.canonical_ordering() {
for nb in space.neighbours(&coord) {
let nb_neighbours = space.neighbours(&nb);
assert!(
nb_neighbours.contains(&coord),
"neighbour symmetry violated: {nb:?} in N({coord:?}) but {coord:?} not in N({nb:?})"
);
}
}
}
pub fn assert_canonical_ordering_deterministic(space: &dyn Space) {
let a = space.canonical_ordering();
let b = space.canonical_ordering();
assert_eq!(a, b, "canonical_ordering is non-deterministic");
}
pub fn assert_canonical_ordering_complete(space: &dyn Space) {
let ordering = space.canonical_ordering();
assert_eq!(
ordering.len(),
space.cell_count(),
"canonical_ordering length ({}) != cell_count ({})",
ordering.len(),
space.cell_count()
);
let ordering_set: IndexSet<_> = ordering.iter().collect();
assert_eq!(
ordering_set.len(),
space.cell_count(),
"canonical_ordering has duplicates"
);
let all_plan = space
.compile_region(&RegionSpec::All)
.expect("compile_region(All) should succeed");
let region_set: IndexSet<_> = all_plan.coords.iter().collect();
assert_eq!(
ordering_set, region_set,
"canonical_ordering and compile_region(All) must cover the same cells"
);
}
pub fn assert_compile_region_all_valid_ratio(space: &dyn Space) {
let plan = space
.compile_region(&RegionSpec::All)
.expect("compile_region(All) should succeed");
let ratio = plan.valid_ratio();
assert!(
(ratio - 1.0).abs() < f64::EPSILON,
"valid_ratio for All region = {ratio}, expected 1.0"
);
}
pub fn assert_compile_region_all_covers_all(space: &dyn Space) {
let plan = space
.compile_region(&RegionSpec::All)
.expect("compile_region(All) should succeed");
assert_eq!(
plan.cell_count(),
space.cell_count(),
"compile_region(All).cell_count ({}) != space.cell_count ({})",
plan.cell_count(),
space.cell_count()
);
let region_set: IndexSet<_> = plan.coords.iter().collect();
assert_eq!(
region_set.len(),
space.cell_count(),
"compile_region(All) has duplicate coordinates"
);
}
pub fn run_full_compliance(space: &dyn Space) {
assert_distance_reflexive(space);
assert_distance_symmetric(space);
assert_distance_triangle_inequality(space);
assert_neighbours_symmetric(space);
assert_canonical_ordering_deterministic(space);
assert_canonical_ordering_complete(space);
assert_compile_region_all_valid_ratio(space);
assert_compile_region_all_covers_all(space);
}