use crate::inner_prelude::*;
pub use assert_invariants::assert_invariants;
pub trait Splitter: Sized {
fn div(&mut self) -> Self;
fn add(&mut self, b: Self);
fn node_start(&mut self);
fn node_end(&mut self);
}
pub struct SplitterEmpty;
impl Splitter for SplitterEmpty {
fn div(&mut self) -> Self {
SplitterEmpty
}
fn add(&mut self, _: Self) {}
fn node_start(&mut self) {}
fn node_end(&mut self) {}
}
pub trait DinoTreeRefTrait where Self::Item:HasAabb<Num=Self::Num>{
type Item:HasAabbMut<Inner=Self::Inner,Num=Self::Num>;
type Axis:AxisTrait;
type Num:NumTrait;
type Inner;
fn axis(&self)->Self::Axis;
fn vistr(&self)->Vistr<Self::Item>;
#[inline]
fn height(&self) -> usize;
#[inline]
fn num_nodes(&self) -> usize;
#[inline]
fn num_bots(&self) -> usize;
}
pub trait DinoTreeRefMutTrait:DinoTreeRefTrait{
fn vistr_mut(&mut self)->VistrMut<Self::Item>;
}
impl<K:DinoTreeRefTrait> DinoTreeRefTrait for &K{
type Item=K::Item;
type Axis=K::Axis;
type Num=K::Num;
type Inner=K::Inner;
fn axis(&self)->Self::Axis{
K::axis(self)
}
fn vistr(&self)->Vistr<Self::Item>{
K::vistr(self)
}
#[inline]
fn height(&self) -> usize
{
K::height(self)
}
#[inline]
fn num_nodes(&self) -> usize
{
K::num_nodes(self)
}
#[inline]
fn num_bots(&self) -> usize
{
K::num_bots(self)
}
}
impl<K:DinoTreeRefMutTrait> DinoTreeRefTrait for &mut K{
type Item=K::Item;
type Axis=K::Axis;
type Num=K::Num;
type Inner=K::Inner;
fn axis(&self)->Self::Axis{
K::axis(self)
}
fn vistr(&self)->Vistr<Self::Item>{
K::vistr(self)
}
#[inline]
fn height(&self) -> usize
{
K::height(self)
}
#[inline]
fn num_nodes(&self) -> usize
{
K::num_nodes(self)
}
#[inline]
fn num_bots(&self) -> usize
{
K::num_bots(self)
}
}
impl<K:DinoTreeRefMutTrait> DinoTreeRefMutTrait for &mut K{
fn vistr_mut(&mut self)->VistrMut<Self::Item>{
K::vistr_mut(self)
}
}
#[inline]
pub fn compute_tree_height_heuristic_debug(num_bots: usize, num_per_node: usize) -> usize {
if num_bots <= num_per_node {
1
} else {
let a=num_bots as f32 / num_per_node as f32;
let b=a.log2()/2.0;
let c=(b.ceil() as usize)*2+1;
c
}
}
#[inline]
pub fn default_level_switch_sequential() -> usize {
const DEPTH_SEQ: usize = 6;
DEPTH_SEQ
}
#[inline]
pub fn compute_default_level_switch_sequential(depth: usize, height: usize) -> par::Parallel {
let dd = depth;
let gg = if height <= dd { 0 } else { height - dd };
par::Parallel::new(Depth(gg))
}
#[inline]
pub fn compute_tree_height_heuristic(num_bots: usize) -> usize {
compute_tree_height_heuristic_debug(num_bots,128)
}
pub struct Vistr<'a, T: HasAabb> {
pub(crate) inner: compt::dfs_order::Vistr<'a, Node<T>, compt::dfs_order::PreOrder>,
}
impl<'a, T: HasAabbMut> Vistr<'a, T> {
#[inline]
pub fn create_wrap(&self) -> Vistr<T> {
Vistr {
inner: self.inner.create_wrap(),
}
}
#[inline]
pub fn height(&self) -> usize {
self.inner.level_remaining_hint().0
}
}
unsafe impl<'a, T: HasAabbMut> compt::FixedDepthVisitor for Vistr<'a, T> {}
impl<'a, T: HasAabbMut + 'a> Visitor for Vistr<'a, T> {
type Item = NodeRef<'a, T>;
#[inline]
fn next(self) -> (Self::Item, Option<[Self; 2]>) {
let (nn, rest) = self.inner.next();
let k = match rest {
Some([left, right]) => Some([Vistr { inner: left }, Vistr { inner: right }]),
None => None,
};
(nn.get(), k)
}
#[inline]
fn level_remaining_hint(&self) -> (usize, Option<usize>) {
self.inner.level_remaining_hint()
}
#[inline]
fn dfs_preorder(self,mut func:impl FnMut(Self::Item)){
self.inner.dfs_preorder(|a|{
func(a.get())
});
}
}
pub struct VistrMut<'a, T:HasAabbMut> {
pub(crate) inner: compt::dfs_order::VistrMut<'a, Node<T>, compt::dfs_order::PreOrder>,
}
impl<'a, T:HasAabbMut> VistrMut<'a, T> {
#[inline]
pub fn create_wrap_mut(&mut self) -> VistrMut<T> {
VistrMut {
inner: self.inner.create_wrap_mut(),
}
}
#[inline]
pub fn height(&self) -> usize {
self.inner.level_remaining_hint().0
}
}
impl<'a, T:HasAabbMut> core::ops::Deref for VistrMut<'a, T> {
type Target = Vistr<'a, T>;
#[inline]
fn deref(&self) -> &Vistr<'a, T> {
unsafe { &*(self as *const VistrMut<T> as *const Vistr<T>) }
}
}
unsafe impl<'a, T:HasAabbMut> compt::FixedDepthVisitor for VistrMut<'a, T> {}
impl<'a, T:HasAabbMut> Visitor for VistrMut<'a, T> {
type Item = NodeRefMut<'a, T>;
#[inline]
fn next(self) -> (Self::Item, Option<[Self; 2]>) {
let (nn, rest) = self.inner.next();
let k = match rest {
Some([left, right]) => Some([VistrMut { inner: left }, VistrMut { inner: right }]),
None => None,
};
(nn.get_mut(), k)
}
#[inline]
fn level_remaining_hint(&self) -> (usize, Option<usize>) {
self.inner.level_remaining_hint()
}
#[inline]
fn dfs_preorder(self,mut func:impl FnMut(Self::Item)){
self.inner.dfs_preorder(|a|{
func(a.get_mut())
});
}
}
pub(crate) struct Node<T: HasAabb> {
pub(crate) range: tools::Unique<ElemSlice<T>>,
pub(crate) cont: axgeom::Range<T::Num>,
pub(crate) div: Option<T::Num>,
}
pub struct NodeRefMut<'a, T:HasAabbMut> {
pub bots: ElemSliceMut<'a,T>,
pub cont: Option<&'a axgeom::Range<T::Num>>,
pub div: Option<&'a T::Num>,
}
pub struct NodeRef<'a, T:HasAabb> {
pub bots: &'a ElemSlice<T>,
pub cont: Option<&'a axgeom::Range<T::Num>>,
pub div: Option<&'a T::Num>,
}
impl<T: HasAabbMut> Node<T> {
#[inline]
pub fn get_mut(&mut self) -> NodeRefMut<T> {
let bots = unsafe { &mut *self.range.as_ptr() };
let cont = if bots.is_empty() {
None
} else {
Some(&self.cont)
};
NodeRefMut {
bots:ElemSliceMut::new(bots),
cont,
div: self.div.as_ref(),
}
}
#[inline]
pub fn get(&self) -> NodeRef<T> {
let bots = unsafe { &*self.range.as_ptr() };
let cont = if bots.is_empty() {
None
} else {
Some(&self.cont)
};
NodeRef {
bots,
cont,
div: self.div.as_ref(),
}
}
}
pub(crate) trait Sorter: Copy + Clone + Send + Sync {
fn sort(&self, axis: impl AxisTrait, bots: &mut [impl HasAabb]);
}
#[derive(Copy, Clone)]
pub(crate) struct DefaultSorter;
impl Sorter for DefaultSorter {
fn sort(&self, axis: impl AxisTrait, bots: &mut [impl HasAabb]) {
oned::sweeper_update(axis, bots);
}
}
#[derive(Copy, Clone)]
pub(crate) struct NoSorter;
impl Sorter for NoSorter {
fn sort(&self, _axis: impl AxisTrait, _bots: &mut [impl HasAabb]) {}
}
fn nodes_left(depth: usize, height: usize) -> usize {
let levels = height - depth;
2usize.rotate_left(levels as u32) - 1
}
pub(crate) use self::cont_tree::ContTree;
mod cont_tree {
use super::*;
pub(crate) struct ContTree<T: HasAabbMut> {
pub(crate) tree: compt::dfs_order::CompleteTreeContainer<Node<T>, compt::dfs_order::PreOrder>,
}
impl<T: HasAabbMut + Send + Sync> ContTree<T> {
pub fn new<A: AxisTrait, JJ: par::Joiner, K: Splitter + Send>(
div_axis: A,
dlevel: JJ,
rest: &mut [T],
sorter: impl Sorter,
splitter: &mut K,
height: usize,
binstrat: BinStrat,
) -> ContTree<T> {
let num_bots = rest.len();
let mut nodes = Vec::with_capacity(tree::nodes_left(0, height));
let r = Recurser {
height,
binstrat,
sorter,
_p: PhantomData,
};
r.recurse_preorder(div_axis, dlevel, rest, &mut nodes, splitter, 0);
let tree =
compt::dfs_order::CompleteTreeContainer::from_preorder(
nodes
)
.unwrap();
let k = tree
.get_nodes()
.iter()
.fold(0, |acc, a| acc + a.get().bots.len());
debug_assert_eq!(k, num_bots);
ContTree { tree }
}
}
struct Recurser<'a, T: HasAabbMut, K: Splitter + Send, S: Sorter> {
height: usize,
binstrat: BinStrat,
sorter: S,
_p :PhantomData<(tools::Syncer<K>,&'a T)>
}
impl<'a, T: HasAabbMut + Send + Sync, K: Splitter + Send, S: Sorter> Recurser<'a, T, K, S> {
fn recurse_preorder<A: AxisTrait, JJ: par::Joiner>(
&self,
axis: A,
dlevel: JJ,
rest: &'a mut [T],
nodes: &mut Vec<Node<T>>,
splitter: &mut K,
depth: usize,
) {
splitter.node_start();
if depth < self.height - 1 {
let (node, left, right) =
match construct_non_leaf(self.binstrat, self.sorter, axis, rest) {
ConstructResult::NonEmpty {
cont,
div,
mid,
left,
right,
} => (
Node {
range: tools::Unique::new(ElemSlice::from_slice_mut(mid) as *mut _).unwrap(),
cont,
div: Some(div),
},
left,
right,
),
ConstructResult::Empty(empty) => {
for _ in 0..compt::compute_num_nodes(self.height - depth) {
let a = tools::duplicate_empty_slice(empty);
let cont = unsafe { core::mem::uninitialized() };
let node = Node {
range: tools::Unique::new(ElemSlice::from_slice_mut(a) as *mut _).unwrap(),
cont,
div: None,
};
nodes.push(node);
}
return;
}
};
nodes.push(node);
let mut splitter2 = splitter.div();
let splitter = if !dlevel.should_switch_to_sequential(Depth(depth)) {
let splitter2 = &mut splitter2;
let ((splitter, nodes), mut nodes2) = rayon::join(
move || {
self.recurse_preorder(
axis.next(),
dlevel,
left,
nodes,
splitter,
depth + 1,
);
(splitter, nodes)
},
move || {
let mut nodes2: Vec<Node<T>> =
Vec::with_capacity(nodes_left(depth, self.height));
self.recurse_preorder(
axis.next(),
dlevel,
right,
&mut nodes2,
splitter2,
depth + 1,
);
nodes2
},
);
nodes.append(&mut nodes2);
splitter
} else {
self.recurse_preorder(
axis.next(),
dlevel.into_seq(),
left,
nodes,
splitter,
depth + 1,
);
self.recurse_preorder(
axis.next(),
dlevel.into_seq(),
right,
nodes,
&mut splitter2,
depth + 1,
);
splitter
};
splitter.add(splitter2);
} else {
let cont = if !rest.is_empty() {
self.sorter.sort(axis.next(), rest);
create_cont(axis, rest)
} else {
unsafe { core::mem::uninitialized() }
};
let node = Node {
range: tools::Unique::new(ElemSlice::from_slice_mut(rest) as *mut _).unwrap(),
cont,
div: None,
};
nodes.push(node);
splitter.node_end();
}
}
}
}
#[bench]
#[cfg(all(feature = "unstable", test))]
fn bench_cont(b: &mut test::Bencher) {
let grow = 2.0;
let s = dists::spiral::Spiral::new([400.0, 400.0], 17.0, grow);
fn aabb_create_isize(pos: [isize; 2], radius: isize) -> axgeom::Rect<isize> {
axgeom::Rect::new(
pos[0] - radius,
pos[0] + radius,
pos[1] - radius,
pos[1] + radius,
)
}
let bots: Vec<_> = s
.as_isize()
.take(100_000)
.map(|pos| BBox::new(aabb_create_isize(pos, 5), ()))
.collect();
b.iter(|| {
let k = create_cont(axgeom::XAXISS, &bots);
let _ = test::black_box(k);
});
}
#[bench]
#[cfg(all(feature = "unstable", test))]
fn bench_cont2(b: &mut test::Bencher) {
fn create_cont2<A: AxisTrait, T: HasAabb>(axis: A, middle: &[T]) -> axgeom::Range<T::Num> {
let left = middle
.iter()
.map(|a| a.get().get_range(axis).left)
.min()
.unwrap();
let right = middle
.iter()
.map(|a| a.get().get_range(axis).right)
.max()
.unwrap();
axgeom::Range { left, right }
}
let grow = 2.0;
let s = dists::spiral::Spiral::new([400.0, 400.0], 17.0, grow);
fn aabb_create_isize(pos: [isize; 2], radius: isize) -> axgeom::Rect<isize> {
axgeom::Rect::new(
pos[0] - radius,
pos[0] + radius,
pos[1] - radius,
pos[1] + radius,
)
}
let bots: Vec<_> = s
.as_isize()
.take(100_000)
.map(|pos| BBox::new(aabb_create_isize(pos, 5), ()) )
.collect();
b.iter(|| {
let k = create_cont2(axgeom::XAXISS, &bots);
let _ = test::black_box(k);
});
}
fn create_cont<A: AxisTrait, T: HasAabb>(axis: A, middle: &[T]) -> axgeom::Range<T::Num> {
let (first, rest) = middle.split_first().unwrap();
let mut min = first.get().rect.get_range(axis).left;
let mut max = first.get().rect.get_range(axis).right;
for a in rest.iter() {
let left = &a.get().rect.get_range(axis).left;
let right = &a.get().rect.get_range(axis).right;
if *left < min {
min = *left;
}
if *right > max {
max = *right;
}
}
axgeom::Range {
left: min,
right: max,
}
}
#[derive(Copy, Clone, Debug)]
pub enum BinStrat {
Checked,
NotChecked,
}
enum ConstructResult<'a, T: HasAabb> {
NonEmpty {
div: T::Num,
cont: axgeom::Range<T::Num>,
mid: &'a mut [T],
right: &'a mut [T],
left: &'a mut [T],
},
Empty(&'a mut [T]),
}
fn construct_non_leaf<T: HasAabb>(
bin_strat: BinStrat,
sorter: impl Sorter,
div_axis: impl AxisTrait,
bots: &mut [T],
) -> ConstructResult<T> {
let med = if bots.is_empty() {
return ConstructResult::Empty(bots);
} else {
let closure = |a: &T, b: &T| -> core::cmp::Ordering { oned::compare_bots(div_axis, a, b) };
let k = {
let mm = bots.len() / 2;
pdqselect::select_by(bots, mm, closure);
&bots[mm]
};
k.get().rect.get_range(div_axis).left
};
let binned = match bin_strat {
BinStrat::Checked => oned::bin_middle_left_right(div_axis, &med, bots),
BinStrat::NotChecked => unsafe {
oned::bin_middle_left_right_unchecked(div_axis, &med, bots)
},
};
debug_assert!(!binned.middle.is_empty());
sorter.sort(div_axis.next(), binned.middle);
let cont = create_cont(div_axis, binned.middle);
ConstructResult::NonEmpty {
mid: binned.middle,
cont,
div: med,
left: binned.left,
right: binned.right,
}
}