use std::ops::ControlFlow;
use crate::combinadic::{BinomialTable, CofacetIter};
use crate::simplex::Simplex;
pub(crate) mod counters;
mod dense;
#[cfg(test)]
mod reference;
mod sparse;
pub(crate) struct Cofacet {
pub(crate) index: u64,
pub(crate) k: usize,
pub(crate) vertex: usize,
pub(crate) diameter: f64,
}
pub(super) const INLINE_VERTS: usize = 16;
pub(crate) trait Distances {
fn len(&self) -> usize;
fn get(&self, i: usize, j: usize) -> f64;
fn default_threshold(&self) -> f64;
fn max_distance(&self) -> f64 {
f64::INFINITY
}
fn for_each_edge(&self, f: impl FnMut(usize, usize, f64));
#[inline]
fn for_each_cofacet<T>(
&self,
bt: &BinomialTable,
simplex: Simplex,
verts: &[usize],
dim: usize,
upper_only: bool,
f: impl FnMut(Cofacet) -> ControlFlow<T>,
) -> Option<T> {
self.enumerate_cofacets::<false, T, _>(
bt,
simplex,
verts,
dim,
upper_only,
f64::INFINITY,
f,
)
}
#[inline]
#[allow(clippy::too_many_arguments)]
fn for_each_cofacet_bounded<T>(
&self,
bt: &BinomialTable,
simplex: Simplex,
verts: &[usize],
dim: usize,
upper_only: bool,
bound: f64,
f: impl FnMut(Cofacet) -> ControlFlow<T>,
) -> Option<T> {
debug_assert!(bound >= simplex.diameter);
let mut bound = bound;
if bound >= self.max_distance() {
counters::note_vacuous_bound();
bound = f64::INFINITY;
}
self.enumerate_cofacets::<true, T, _>(bt, simplex, verts, dim, upper_only, bound, f)
}
#[allow(clippy::too_many_arguments)]
fn enumerate_cofacets<const BOUNDED: bool, T, F>(
&self,
bt: &BinomialTable,
simplex: Simplex,
verts: &[usize],
dim: usize,
upper_only: bool,
bound: f64,
mut f: F,
) -> Option<T>
where
F: FnMut(Cofacet) -> ControlFlow<T>,
{
let cofacet_diameter = |added: usize| {
let mut d = simplex.diameter;
for &v in verts {
let x = self.get(added, v);
if BOUNDED && x > bound {
return None;
}
d = d.max(x);
}
Some(d)
};
let mut iter = CofacetIter::new(bt, simplex.index, dim, self.len());
if upper_only {
while let Some((index, vertex)) = iter.next_upper() {
let Some(diameter) = cofacet_diameter(vertex) else {
continue;
};
let cofacet = Cofacet {
index,
k: 0,
vertex,
diameter,
};
if let ControlFlow::Break(t) = f(cofacet) {
return Some(t);
}
}
} else {
while let Some((index, vertex, k)) = iter.next_all() {
let Some(diameter) = cofacet_diameter(vertex) else {
continue;
};
let cofacet = Cofacet {
index,
k,
vertex,
diameter,
};
if let ControlFlow::Break(t) = f(cofacet) {
return Some(t);
}
}
}
None
}
}