use super::traversal::{Dir, Strategy};
use crate::algs::traversal_core as core;
use crate::mesh_error::MeshSieveError;
use crate::topology::bounds::PointLike;
use crate::topology::point::PointId;
use crate::topology::sieve::Sieve;
use crate::topology::sieve::SieveRef;
use crate::topology::sieve::strata::compute_strata;
use std::collections::{HashSet, VecDeque};
pub type Point = PointId;
struct RefNeigh<'a, S: Sieve<Point = Point> + SieveRef> {
sieve: &'a S,
}
impl<'a, S: Sieve<Point = Point> + SieveRef> core::Neigh<'a, Point> for RefNeigh<'a, S> {
type Iter = Box<dyn Iterator<Item = Point> + 'a>;
fn down(&'a self, p: Point) -> Self::Iter {
Box::new(SieveRef::cone_points(self.sieve, p))
}
fn up(&'a self, p: Point) -> Self::Iter {
Box::new(SieveRef::support_points(self.sieve, p))
}
}
#[inline]
pub fn closure_ref<S, I>(sieve: &S, seeds: I) -> Vec<Point>
where
S: Sieve<Point = Point> + SieveRef,
I: IntoIterator<Item = Point>,
{
core::traverse(
&RefNeigh { sieve },
seeds,
core::Opts {
dir: core::Dir::Down,
strat: core::Strategy::DFS,
max_depth: None,
deterministic: true,
early_stop: None,
},
)
}
#[inline]
pub fn star_ref<S, I>(sieve: &S, seeds: I) -> Vec<Point>
where
S: Sieve<Point = Point> + SieveRef,
I: IntoIterator<Item = Point>,
{
core::traverse(
&RefNeigh { sieve },
seeds,
core::Opts {
dir: core::Dir::Up,
strat: core::Strategy::DFS,
max_depth: None,
deterministic: true,
early_stop: None,
},
)
}
pub fn depth_map_ref<S>(sieve: &S, seed: Point) -> Vec<(Point, u32)>
where
S: Sieve<Point = Point> + SieveRef,
{
let mut depths = Vec::new();
let mut seen = HashSet::new();
let mut q = VecDeque::from([(seed, 0)]);
while let Some((p, d)) = q.pop_front() {
if seen.insert(p) {
depths.push((p, d));
for q_pt in SieveRef::cone_points(sieve, p) {
q.push_back((q_pt, d + 1));
}
}
}
depths.sort_by_key(|&(p, _)| p);
depths
}
pub struct OrderedTraversalBuilder<'a, S: Sieve + SieveRef> {
sieve: &'a mut S,
seeds: Vec<S::Point>,
dir: Dir,
strat: Strategy,
}
impl<'a, S> OrderedTraversalBuilder<'a, S>
where
S: Sieve + SieveRef,
S::Point: Copy + Ord,
{
pub fn new(sieve: &'a mut S) -> Self {
Self {
sieve,
seeds: Vec::new(),
dir: Dir::Down,
strat: Strategy::DFS,
}
}
pub fn seeds<I: IntoIterator<Item = S::Point>>(mut self, it: I) -> Self {
self.seeds = it.into_iter().collect();
self
}
pub fn dir(mut self, d: Dir) -> Self {
self.dir = d;
self
}
pub fn dfs(mut self) -> Self {
self.strat = Strategy::DFS;
self
}
pub fn bfs(mut self) -> Self {
self.strat = Strategy::BFS;
self
}
pub fn run(self) -> Result<Vec<S::Point>, MeshSieveError> {
match self.strat {
Strategy::DFS => self.run_dfs_ordered(),
Strategy::BFS => self.run_bfs_ordered(),
}
}
fn run_dfs_ordered(self) -> Result<Vec<S::Point>, MeshSieveError> {
let Self {
sieve, seeds, dir, ..
} = self;
let strata = compute_strata(&*sieve)?;
let chart = strata.chart_points;
let index = strata.chart_index;
let n = chart.len();
let mut seen = vec![false; n];
let mut stack: Vec<usize> = Vec::new();
stack.reserve(seeds.len().saturating_mul(2));
for p in seeds {
if let Some(i) = index.get(&p).copied()
&& !seen[i]
{
seen[i] = true;
stack.push(i);
}
}
while let Some(i) = stack.pop() {
let p = chart[i];
let mut nbrs: Vec<usize> = match dir {
Dir::Down => SieveRef::cone_points(&*sieve, p)
.filter_map(|q| index.get(&q).copied())
.collect(),
Dir::Up => SieveRef::support_points(&*sieve, p)
.filter_map(|q| index.get(&q).copied())
.collect(),
Dir::Both => SieveRef::cone_points(&*sieve, p)
.chain(SieveRef::support_points(&*sieve, p))
.filter_map(|q| index.get(&q).copied())
.collect(),
};
nbrs.sort_unstable();
nbrs.dedup();
for j in nbrs.into_iter().rev() {
if !seen[j] {
seen[j] = true;
stack.push(j);
}
}
}
let mut out = Vec::with_capacity(seen.iter().filter(|&&b| b).count());
for (i, &flag) in seen.iter().enumerate() {
if flag {
out.push(chart[i]);
}
}
Ok(out)
}
fn run_bfs_ordered(self) -> Result<Vec<S::Point>, MeshSieveError> {
let Self {
sieve, seeds, dir, ..
} = self;
let strata = compute_strata(&*sieve)?;
let chart = strata.chart_points;
let index = strata.chart_index;
let n = chart.len();
let mut seen = vec![false; n];
let mut q: VecDeque<usize> = VecDeque::new();
q.reserve(seeds.len().saturating_mul(2));
for p in seeds {
if let Some(i) = index.get(&p).copied()
&& !seen[i]
{
seen[i] = true;
q.push_back(i);
}
}
while let Some(i) = q.pop_front() {
let p = chart[i];
let mut nbrs: Vec<usize> = match dir {
Dir::Down => SieveRef::cone_points(&*sieve, p)
.filter_map(|q| index.get(&q).copied())
.collect(),
Dir::Up => SieveRef::support_points(&*sieve, p)
.filter_map(|q| index.get(&q).copied())
.collect(),
Dir::Both => SieveRef::cone_points(&*sieve, p)
.chain(SieveRef::support_points(&*sieve, p))
.filter_map(|q| index.get(&q).copied())
.collect(),
};
nbrs.sort_unstable();
nbrs.dedup();
for j in nbrs {
if !seen[j] {
seen[j] = true;
q.push_back(j);
}
}
}
let mut out = Vec::with_capacity(seen.iter().filter(|&&b| b).count());
for (i, &flag) in seen.iter().enumerate() {
if flag {
out.push(chart[i]);
}
}
Ok(out)
}
}
pub fn closure_ordered_ref<I, S>(sieve: &mut S, seeds: I) -> Result<Vec<S::Point>, MeshSieveError>
where
S: Sieve + SieveRef,
S::Point: PointLike,
I: IntoIterator<Item = S::Point>,
{
OrderedTraversalBuilder::new(sieve)
.dir(Dir::Down)
.dfs()
.seeds(seeds)
.run()
}
pub fn star_ordered_ref<I, S>(sieve: &mut S, seeds: I) -> Result<Vec<S::Point>, MeshSieveError>
where
S: Sieve + SieveRef,
S::Point: PointLike,
I: IntoIterator<Item = S::Point>,
{
OrderedTraversalBuilder::new(sieve)
.dir(Dir::Up)
.dfs()
.seeds(seeds)
.run()
}