1use super::*;
10
11type NodeWrapperVistr<'a, 'b, T, M> = VistrMut<'a, NodeWrapper<'b, T, M>, PreOrder>;
12
13pub enum GravEnum<'a, T: Aabb, M> {
15 Mass(&'a mut M),
16 Bot(AabbPin<&'a mut [T]>),
17}
18
19pub trait Nbody {
21 type T: Aabb<Num = Self::N>;
22 type N: Num;
23 type Mass: Default + Copy + core::fmt::Debug;
24
25 fn compute_center_of_mass(&mut self, a: &[Self::T]) -> Self::Mass;
27
28 fn is_close(&self, a: &Self::Mass, line: Self::N, a: impl Axis) -> bool;
29
30 fn is_close_half(&self, a: &Self::Mass, line: Self::N, a: impl Axis) -> bool;
31
32 fn gravitate(&mut self, a: GravEnum<Self::T, Self::Mass>, b: GravEnum<Self::T, Self::Mass>);
33
34 fn gravitate_self(&mut self, a: AabbPin<&mut [Self::T]>);
35
36 fn apply_a_mass<'a>(
37 &'a mut self,
38 mass: Self::Mass,
39 i: impl Iterator<Item = AabbPin<&'a mut Self::T>>,
40 len: usize,
41 );
42
43 fn combine_two_masses(&mut self, a: &Self::Mass, b: &Self::Mass) -> Self::Mass;
44}
45
46use compt::dfs_order::PreOrder;
47use compt::dfs_order::VistrMut;
48
49struct NodeWrapper<'a, T: Aabb, M> {
50 node: Node<'a, T, T::Num>,
51 mass: M,
52}
53
54fn build_masses2<N: Nbody>(vistr: NodeWrapperVistr<N::T, N::Mass>, no: &mut N) -> N::Mass {
55 let (nn, rest) = vistr.next();
56 let mass = no.compute_center_of_mass(&nn.node.range);
57 let mass = if let Some([left, right]) = rest {
58 let a = build_masses2(left, no);
59 let b = build_masses2(right, no);
60 let m = no.combine_two_masses(&a, &b);
61 no.combine_two_masses(&m, &mass)
62 } else {
63 mass
64 };
65 nn.mass = mass;
66 mass
67}
68
69fn collect_masses<'a, 'b, N: Nbody>(
70 root_div: N::N,
71 root_axis: impl Axis,
72 vistr: NodeWrapperVistr<'b, 'a, N::T, N::Mass>,
73 no: &mut N,
74 func1: &mut impl FnMut(&'b mut NodeWrapper<'a, N::T, N::Mass>, &mut N),
75 func2: &mut impl FnMut(&'b mut AabbPin<&'a mut [N::T]>, &mut N),
76) {
77 let (nn, rest) = vistr.next();
78
79 if !no.is_close_half(&nn.mass, root_div, root_axis) {
80 func1(nn, no);
81 return;
82 }
83
84 func2(&mut nn.node.range, no);
85
86 if let Some([left, right]) = rest {
87 collect_masses(root_div, root_axis, left, no, func1, func2);
88 collect_masses(root_div, root_axis, right, no, func1, func2);
89 }
90}
91
92fn pre_recc<N: Nbody>(
93 root_div: N::N,
94 root_axis: impl Axis,
95 root: &mut NodeWrapper<N::T, N::Mass>,
96 vistr: NodeWrapperVistr<N::T, N::Mass>,
97 no: &mut N,
98) {
99 let (nn, rest) = vistr.next();
100
101 if !no.is_close(&nn.mass, root_div, root_axis) {
102 no.gravitate(
103 GravEnum::Bot(root.node.range.borrow_mut()),
104 GravEnum::Mass(&mut nn.mass),
105 );
106 return;
107 }
108
109 no.gravitate(
110 GravEnum::Bot(root.node.range.borrow_mut()),
111 GravEnum::Bot(nn.node.range.borrow_mut()),
112 );
113
114 if let Some([left, right]) = rest {
115 pre_recc(root_div, root_axis, root, left, no);
116 pre_recc(root_div, root_axis, root, right, no);
117 }
118}
119
120fn recc_common<'a, 'b, N: Nbody>(
121 axis: impl Axis,
122 vistr: NodeWrapperVistr<'a, 'b, N::T, N::Mass>,
123 no: &mut N,
124) -> Option<[NodeWrapperVistr<'a, 'b, N::T, N::Mass>; 2]> {
125 let (nn, rest) = vistr.next();
126
127 no.gravitate_self(nn.node.range.borrow_mut());
128
129 if let Some([mut left, mut right]) = rest {
130 if let Some(div) = nn.node.div {
131 pre_recc(div, axis, nn, left.borrow_mut(), no);
132 pre_recc(div, axis, nn, right.borrow_mut(), no);
133
134 let mut finished_masses = Vec::new();
135 let mut finished_bots = Vec::new();
136
137 collect_masses(
138 div,
139 axis,
140 left.borrow_mut(),
141 no,
142 &mut |a, _| finished_masses.push(a),
143 &mut |a, _| finished_bots.push(a),
144 );
145
146 let mut finished_masses2 = Vec::new();
147 let mut finished_bots2 = Vec::new();
148
149 collect_masses(
150 div,
151 axis,
152 right.borrow_mut(),
153 no,
154 &mut |a, _| finished_masses2.push(a),
155 &mut |a, _| finished_bots2.push(a),
156 );
157
158 for a in finished_masses.into_iter() {
162 for b in finished_masses2.iter_mut() {
163 no.gravitate(GravEnum::Mass(&mut a.mass), GravEnum::Mass(&mut b.mass));
164 }
165
166 for b in finished_bots2.iter_mut() {
167 no.gravitate(GravEnum::Mass(&mut a.mass), GravEnum::Bot(b.borrow_mut()));
168 }
169 }
170 for a in finished_bots.into_iter() {
171 for b in finished_masses2.iter_mut() {
172 no.gravitate(GravEnum::Bot(a.borrow_mut()), GravEnum::Mass(&mut b.mass));
173 }
174 for b in finished_bots2.iter_mut() {
175 no.gravitate(GravEnum::Bot(a.borrow_mut()), GravEnum::Bot(b.borrow_mut()));
176 }
177 }
178
179 Some([left, right])
181 } else {
182 None
183 }
184 } else {
185 None
186 }
187}
188
189fn recc<N: Nbody>(
190 axis: impl Axis,
191 vistr: VistrMut<NodeWrapper<N::T, N::Mass>, PreOrder>,
192 no: &mut N,
193) {
194 let keep_going = recc_common(axis, vistr, no);
195
196 if let Some([left, right]) = keep_going {
197 recc(axis.next(), left, no);
198 recc(axis.next(), right, no);
199 }
200}
201
202fn apply_tree<N: Nbody>(mut vistr: NodeWrapperVistr<N::T, N::Mass>, no: &mut N) {
203 {
204 let mass = vistr.borrow_mut().next().0.mass;
205
206 let len = vistr
207 .borrow_mut()
208 .dfs_preorder_iter()
209 .map(|x| x.node.range.borrow_mut().len())
210 .sum();
211
212 let it = vistr
213 .borrow_mut()
214 .dfs_preorder_iter()
215 .flat_map(|x| x.node.range.borrow_mut().iter_mut());
216
217 no.apply_a_mass(mass, it, len);
218 }
219
220 let (_, rest) = vistr.next();
221
222 if let Some([left, right]) = rest {
223 apply_tree(left, no);
224 apply_tree(right, no);
225 }
226}
227
228impl<'a, T: Aabb> crate::Tree<'a, T> {
229 pub fn handle_nbody<N: Nbody<T = T>>(&mut self, no: &mut N) {
230 pub fn nbody_mut<'a, N: Nbody<T = T>, T: Aabb>(
233 tree: Box<[Node<'a, T, T::Num>]>,
234 no: &mut N,
235 ) -> Box<[Node<'a, T, T::Num>]> {
236 let mut newnodes: Vec<_> = Vec::from(tree)
237 .into_iter()
238 .map(|x| NodeWrapper {
239 node: x,
240 mass: Default::default(),
241 })
242 .collect();
243
244 let tree = compt::dfs_order::CompleteTreeMut::from_preorder_mut(&mut newnodes).unwrap();
245 let mut vistr = tree.vistr_mut();
246
247 build_masses2(vistr.borrow_mut(), no);
249
250 recc(default_axis(), vistr.borrow_mut(), no);
251
252 apply_tree(vistr, no);
253
254 newnodes.into_iter().map(|x| x.node).collect()
255 }
256
257 let mut vvv = vec![].into_boxed_slice();
258 std::mem::swap(&mut self.nodes, &mut vvv);
259
260 let mut new = nbody_mut(vvv, no);
261 std::mem::swap(&mut self.nodes, &mut new);
262 }
263}
264
265mod assert {
266 use super::*;
267 impl<'a, T: Aabb> Naive<'a, T> {
268 pub fn handle_nbody<N: Nbody<T = T>>(&mut self, no: &mut N) {
269 pub fn naive_nbody_mut<T: Aabb>(
271 bots: AabbPin<&mut [T]>,
272 func: impl FnMut(AabbPin<&mut T>, AabbPin<&mut T>),
273 ) {
274 queries::for_every_pair(bots, func);
275 }
276
277 naive_nbody_mut(self.inner.borrow_mut(), |a, b| {
278 no.gravitate(GravEnum::Bot(a.into_slice()), GravEnum::Bot(b.into_slice()));
279 });
280 }
281 }
282}