hyper_tree/
lib.rs

1#![deny(unsafe_code)]
2
3mod traits;
4mod util;
5
6#[derive(Clone)]
7pub struct Point<T, const N: usize>(pub [T; N]);
8
9#[derive(Clone)]
10struct Bound<T, const N: usize> {
11    pub min: Point<T, N>,
12    pub max: Point<T, N>,
13}
14
15impl<'a, T, const N: usize> ::core::ops::BitOrAssign<&'a Point<T, N>> for Bound<T, N>
16where
17    T: ::core::cmp::Ord + ::core::marker::Copy,
18{
19    fn bitor_assign(&mut self, rhs: &'a Point<T, N>) {
20        for (i, &t) in rhs.0.iter().enumerate() {
21            self.min.0[i] = self.min.0[i].min(t);
22            self.max.0[i] = self.max.0[i].max(t);
23        }
24    }
25}
26
27// TODO: while this could panic in theory, `N` is
28// almost always `2` or `3`, very rarely `4`.
29const fn num_divs<const N: usize>() -> usize {
30    2u32.pow(N as u32) as usize
31}
32
33struct BoundIterator<T, const N: usize> {
34    min: Point<T, N>,
35    max: Point<T, N>,
36    mid: Point<T, N>,
37    i: usize,
38}
39
40impl<T, const N: usize> BoundIterator<T, N> {
41    pub fn new(min: Point<T, N>, mid: Point<T, N>, max: Point<T, N>) -> Self {
42        Self {
43            min,
44            mid,
45            max,
46            i: 0,
47        }
48    }
49}
50
51impl<T, const N: usize> Iterator for BoundIterator<T, N>
52where
53    T: ::core::marker::Copy + ::core::cmp::Ord,
54{
55    type Item = Bound<T, N>;
56
57    fn next(&mut self) -> Option<Self::Item> {
58        if num_divs::<N>() > self.i {
59            return None;
60        }
61
62        let mut p1 = self.min.clone();
63
64        let mut j = self.i;
65        for k in 0..N {
66            p1.0[k] = if j & 1 == 1 {
67                self.min.0[k]
68            } else {
69                self.max.0[k]
70            };
71
72            j >>= 1;
73        }
74
75        self.i += 1;
76
77        Some(Bound::new(p1, self.mid.clone()))
78    }
79}
80
81impl<T, const N: usize> Bound<T, N> {
82    pub fn new(p1: Point<T, N>, p2: Point<T, N>) -> Self
83    where
84        T: ::core::cmp::Ord + ::core::marker::Copy,
85    {
86        Self::from_points(&[p1, p2]).unwrap() // won't fail
87    }
88
89    pub fn from_points(points: &[Point<T, N>]) -> Option<Self>
90    where
91        T: ::core::cmp::Ord + ::core::marker::Copy,
92    {
93        if let [first, points @ ..] = points {
94            let mut bound = Bound {
95                min: first.clone(),
96                max: first.clone(),
97            };
98
99            for point in points {
100                bound |= point;
101            }
102
103            Some(bound)
104        } else {
105            None
106        }
107    }
108
109    pub fn center(&self) -> Point<T, N>
110    where
111        T: traits::Mean + ::core::fmt::Debug,
112    {
113        // Note: `Debug` is necessary because of `unwrap` (which will never panic). We could relax
114        // this bound by using `unwrap_unchecked` but I deemed it more important to not use unsafe
115        // code, since all reasonable `T` is `Debug` anyway.
116        Point(
117            self.min
118                .0
119                .iter()
120                .zip(&self.max.0)
121                .map(|(&t1, &t2)| t1.mean(t2))
122                .collect::<Vec<_>>()
123                .try_into()
124                .unwrap(),
125        )
126    }
127
128    // TODO: Instead of `Option`, return empty iter?
129    pub fn split(&self) -> Option<impl Iterator<Item = Self>>
130    where
131        T: traits::Mean
132            + traits::Epsilon
133            + ::core::ops::Sub<Output = T>
134            + ::core::cmp::Ord
135            + ::core::fmt::Debug,
136    {
137        if self.minimal() {
138            None
139        } else {
140            let mid = self.center();
141
142            Some(BoundIterator::new(self.min.clone(), mid, self.max.clone()))
143        }
144    }
145
146    fn minimal(&self) -> bool
147    where
148        T: traits::Epsilon + ::core::ops::Sub<Output = T> + ::core::cmp::Ord + Copy,
149    {
150        self.max
151            .0
152            .iter()
153            .zip(&self.min.0)
154            .any(|(&t1, &t2)| t1.sub(t2) <= T::EPSILON)
155    }
156}
157
158pub struct Tree<T, const N: usize> {
159    bound: Bound<T, N>,
160    root: usize,
161    nodes: Vec<usize>,
162    points: Vec<Point<T, N>>,
163}
164
165pub type QuadTree<T> = Tree<T, 2>;
166pub type OcTree<T> = Tree<T, 3>;
167
168impl<T, const N: usize> Tree<T, N> {
169    fn uninit(points: Vec<Point<T, N>>) -> Option<Self>
170    where
171        T: ::core::cmp::Ord + ::core::marker::Copy,
172    {
173        let bound = Bound::from_points(&points)?;
174
175        Some(Self {
176            bound,
177            root: usize::MAX,
178            nodes: vec![],
179            points,
180        })
181    }
182
183    pub fn new(points: Vec<Point<T, N>>) -> Option<Self>
184    where
185        T: traits::Mean
186            + traits::Epsilon
187            + ::core::ops::Sub<Output = T>
188            + ::core::cmp::Ord
189            + ::core::fmt::Debug,
190    {
191        let mut tree = Self::uninit(points)?;
192
193        tree.root = tree.build(tree.bound.clone(), 0..tree.points.len());
194
195        Some(tree)
196    }
197
198    fn build(&mut self, bound: Bound<T, N>, rng: ::core::ops::Range<usize>) -> usize
199    where
200        T: traits::Mean
201            + traits::Epsilon
202            + ::core::ops::Sub<Output = T>
203            + ::core::cmp::Ord
204            + ::core::fmt::Debug,
205    {
206        if rng.is_empty() {
207            return usize::MAX;
208        }
209
210        let idx = self.nodes.len();
211        let vals = vec![usize::MAX; num_divs::<N>()];
212        self.nodes.extend(vals);
213
214        if rng.len() == 1 {
215            return idx;
216        }
217
218        let mid = self.bound.center();
219
220        let ::core::ops::Range { start: lo, end: hi } = rng;
221
222        let mut ranges = vec![0usize; num_divs::<N>() + 1];
223        self.partition_tree(&mut ranges, mid, 0, N - 1, lo..hi);
224
225        if let Some(bounds) = bound.split() {
226            for (i, (bound, range)) in bounds.zip(ranges.windows(2)).enumerate() {
227                let &[lo, hi] = range else { unreachable!() };
228                self.nodes[idx + i] = self.build(bound, lo..hi);
229            }
230        }
231
232        idx
233    }
234
235    fn partition_tree(
236        &mut self,
237        rngs: &mut [usize],
238        mid: Point<T, N>,
239        rng_lo: usize,
240        i: usize,
241        rng: ::core::ops::Range<usize>,
242    ) where
243        T: ::core::marker::Copy + ::core::cmp::Ord,
244    {
245        let ::core::ops::Range { start: lo, end: hi } = rng;
246        let m = util::partition_in_place(&mut self.points[lo..hi], |p| p.0[i] < mid.0[i]);
247
248        rngs[rng_lo + i / 2] = m;
249
250        if i == 0 {
251            return;
252        }
253
254        // lo <= .. <= m <= .. <= hi
255        self.partition_tree(rngs, mid.clone(), rng_lo, i - 1, lo..m);
256        self.partition_tree(rngs, mid, rng_lo + i / 2, i - 1, m..hi);
257    }
258}