1use itertools::{izip, Itertools};
4use mpi::{
5 collective::{SystemOperation, UserOperation},
6 datatype::{Partition, PartitionMut},
7 point_to_point as p2p,
8 traits::{CommunicatorCollectives, Destination, Equivalence, Root, Source},
9};
10use num::traits::Zero;
11use rand::{Rng, SeedableRng};
12use rand_chacha::ChaCha8Rng;
13
14use crate::{
15 constants::{DEEPEST_LEVEL, LEVEL_SIZE},
16 geometry::Point,
17 morton::MortonKey,
18};
19
20pub fn gather_to_all<T: Equivalence, C: CommunicatorCollectives>(arr: &[T], comm: &C) -> Vec<T> {
22 let size = comm.size();
25
26 let local_len = arr.len() as i32;
27
28 let mut sizes = vec![0; size as usize];
29
30 comm.all_gather_into(&local_len, &mut sizes);
31
32 let recv_len = sizes.iter().sum::<i32>() as usize;
33
34 let mut recvbuffer = Vec::<T>::with_capacity(recv_len);
38 let buf: &mut [T] = unsafe { std::mem::transmute(recvbuffer.spare_capacity_mut()) };
39
40 let recv_displs: Vec<i32> = sizes
41 .iter()
42 .scan(0, |acc, &x| {
43 let tmp = *acc;
44 *acc += x;
45 Some(tmp)
46 })
47 .collect();
48
49 let mut receiv_partition = PartitionMut::new(buf, sizes, &recv_displs[..]);
50
51 comm.all_gather_varcount_into(arr, &mut receiv_partition);
52
53 unsafe { recvbuffer.set_len(recv_len) };
54
55 recvbuffer
56}
57pub fn gather_to_root<T: Equivalence, C: CommunicatorCollectives>(
63 arr: &[T],
64 comm: &C,
65) -> Option<Vec<T>> {
66 let n = arr.len() as i32;
67 let rank = comm.rank();
68 let size = comm.size();
69 let root_process = comm.process_at_rank(0);
70
71 if rank == 0 {
74 let mut counts = vec![0_i32; size as usize];
77 root_process.gather_into_root(&n, &mut counts);
78
79 let nelements = counts.iter().sum::<i32>();
83 let mut new_arr = Vec::<T>::with_capacity(nelements as usize);
84 let new_arr_buf: &mut [T] = unsafe { std::mem::transmute(new_arr.spare_capacity_mut()) };
85
86 let displs = displacements(counts.as_slice());
87
88 let mut partition = PartitionMut::new(new_arr_buf, counts, &displs[..]);
89
90 root_process.gather_varcount_into_root(arr, &mut partition);
91
92 unsafe { new_arr.set_len(nelements as usize) };
93 Some(new_arr)
94 } else {
95 root_process.gather_into(&n);
96 root_process.gather_varcount_into(arr);
97 None
98 }
99}
100
101pub fn global_size<T, C: CommunicatorCollectives>(arr: &[T], comm: &C) -> usize {
105 let local_size = arr.len();
106 let mut global_size = 0;
107
108 comm.all_reduce_into(&local_size, &mut global_size, SystemOperation::sum());
109
110 global_size
111}
112
113pub fn global_max<T: Equivalence + Copy + Ord, C: CommunicatorCollectives>(
115 arr: &[T],
116 comm: &C,
117) -> T {
118 let local_max = arr.iter().max().unwrap();
119
120 let mut global_max = *local_max;
122
123 comm.all_reduce_into(
124 local_max,
125 &mut global_max,
126 &UserOperation::commutative(|x, y| {
127 let x: &[T] = x.downcast().unwrap();
128 let y: &mut [T] = y.downcast().unwrap();
129 for (&x_i, y_i) in x.iter().zip(y) {
130 *y_i = x_i.max(*y_i);
131 }
132 }),
133 );
134
135 global_max
136}
137
138pub fn global_min<T: Equivalence + Copy + Ord, C: CommunicatorCollectives>(
140 arr: &[T],
141 comm: &C,
142) -> T {
143 let local_min = *arr.iter().min().unwrap();
144
145 let mut global_min = local_min;
147
148 comm.all_reduce_into(
149 &local_min,
150 &mut global_min,
151 &UserOperation::commutative(|x, y| {
152 let x: &[T] = x.downcast().unwrap();
153 let y: &mut [T] = y.downcast().unwrap();
154 for (&x_i, y_i) in x.iter().zip(y) {
155 *y_i = x_i.min(*y_i);
156 }
157 }),
158 );
159
160 global_min
161}
162
163pub fn communicate_back<T: Equivalence, C: CommunicatorCollectives>(
165 arr: &[T],
166 comm: &C,
167) -> Option<T> {
168 let rank = comm.rank();
169 let size = comm.size();
170
171 if size == 1 {
172 return None;
173 }
174
175 if rank == size - 1 {
176 comm.process_at_rank(rank - 1).send(arr.first().unwrap());
177 None
178 } else {
179 let (new_last, _status) = if rank > 0 {
180 p2p::send_receive(
181 arr.first().unwrap(),
182 &comm.process_at_rank(rank - 1),
183 &comm.process_at_rank(rank + 1),
184 )
185 } else {
186 comm.process_at_rank(1).receive::<T>()
187 };
188 Some(new_last)
189 }
190}
191
192pub fn is_sorted_array<T: Equivalence + PartialOrd, C: CommunicatorCollectives>(
194 arr: &[T],
195 comm: &C,
196) -> bool {
197 let mut sorted = true;
198 for (elem1, elem2) in arr.iter().tuple_windows() {
199 if elem1 > elem2 {
200 sorted = false;
201 }
202 }
203
204 if comm.size() == 1 {
205 return sorted;
206 }
207
208 if let Some(next_first) = communicate_back(arr, comm) {
209 sorted = *arr.last().unwrap() <= next_first;
210 }
211
212 let mut global_sorted: bool = false;
213 comm.all_reduce_into(&sorted, &mut global_sorted, SystemOperation::logical_and());
214
215 global_sorted
216}
217
218pub fn redistribute<T: Equivalence, C: CommunicatorCollectives>(
220 arr: &[T],
221 counts: &[i32],
222 comm: &C,
223) -> Vec<T> {
224 assert_eq!(counts.len(), comm.size() as usize);
225
226 let mut recv_counts = vec![0; counts.len()];
229
230 comm.all_to_all_into(counts, &mut recv_counts);
231
232 let nelems = recv_counts.iter().sum::<i32>() as usize;
235
236 let mut output = Vec::<T>::with_capacity(nelems);
237 let out_buf: &mut [T] = unsafe { std::mem::transmute(output.spare_capacity_mut()) };
238
239 let send_partition = Partition::new(arr, counts, displacements(counts));
240 let mut recv_partition =
241 PartitionMut::new(out_buf, &recv_counts[..], displacements(&recv_counts));
242
243 comm.all_to_all_varcount_into(&send_partition, &mut recv_partition);
244
245 unsafe { output.set_len(nelems) };
246
247 output
248}
249
250pub fn global_inclusive_cumsum<T: Equivalence + Zero + Copy, C: CommunicatorCollectives>(
254 arr: &[T],
255 comm: &C,
256) -> Vec<T> {
257 let mut scan: Vec<T> = arr
258 .iter()
259 .scan(<T as Zero>::zero(), |state, x| {
260 *state = *x + *state;
261 Some(*state)
262 })
263 .collect_vec();
264 let scan_last = *scan.last().unwrap();
265 let mut scan_result = T::zero();
266 comm.exclusive_scan_into(&scan_last, &mut scan_result, SystemOperation::sum());
267 for elem in &mut scan {
268 *elem = *elem + scan_result;
269 }
270
271 scan
272}
273
274pub fn sort_to_bins<T: Ord>(sorted_keys: &[T], bins: &[T]) -> Vec<usize> {
284 let nbins = bins.len();
285
286 assert!(bins.first().unwrap() <= sorted_keys.first().unwrap());
288
289 if nbins == 1 {
292 return vec![sorted_keys.len(); 1];
293 }
294
295 let mut bin_counts = vec![0; nbins];
296
297 let mut bin_iter = izip!(
301 bin_counts.iter_mut(),
302 bins.iter().tuple_windows::<(&T, &T)>(),
303 );
304
305 let mut r: &mut usize;
308 let mut bin_start: &T;
309 let mut bin_end: &T;
310 (r, (bin_start, bin_end)) = bin_iter.next().unwrap();
311
312 let mut count = 0;
313 'outer: for key in sorted_keys.iter() {
314 if bin_start <= key && key < bin_end {
315 *r += 1;
316 count += 1;
317 } else {
318 loop {
320 if let Some((rn, (bsn, ben))) = bin_iter.next() {
321 if bsn <= key && key < ben {
322 *rn += 1;
325 r = rn;
326 bin_start = bsn;
327 bin_end = ben;
328 count += 1;
329 break;
330 }
331 } else {
332 break 'outer;
334 }
335 }
336 }
337 }
338
339 *bin_counts.last_mut().unwrap() = sorted_keys.len() - count;
342
343 bin_counts
344}
345
346pub fn redistribute_by_bins<T: Equivalence + Ord, C: CommunicatorCollectives>(
354 sorted_keys: &[T],
355 bins: &[T],
356 comm: &C,
357) -> Vec<T> {
358 let counts = sort_to_bins(sorted_keys, bins);
359 let counts = counts.iter().map(|elem| *elem as i32).collect_vec();
360 redistribute(sorted_keys, &counts, comm)
361}
362
363pub fn generate_random_keys<R: Rng>(nkeys: usize, rng: &mut R) -> Vec<MortonKey> {
365 let mut result = Vec::<MortonKey>::with_capacity(nkeys);
366
367 let xindices = rand::seq::index::sample(rng, LEVEL_SIZE as usize, nkeys);
368 let yindices = rand::seq::index::sample(rng, LEVEL_SIZE as usize, nkeys);
369 let zindices = rand::seq::index::sample(rng, LEVEL_SIZE as usize, nkeys);
370
371 for (xval, yval, zval) in izip!(xindices.iter(), yindices.iter(), zindices.iter()) {
372 result.push(MortonKey::from_index_and_level(
373 [xval, yval, zval],
374 DEEPEST_LEVEL as usize,
375 ));
376 }
377
378 result
379}
380
381pub fn generate_random_points<R: Rng, C: CommunicatorCollectives>(
383 npoints: usize,
384 rng: &mut R,
385 comm: &C,
386) -> Vec<Point> {
387 let mut points = Vec::<Point>::with_capacity(npoints);
388 let rank = comm.rank() as usize;
389
390 for index in 0..npoints {
391 points.push(Point::new(
392 [rng.gen(), rng.gen(), rng.gen()],
393 npoints * rank + index,
394 ));
395 }
396
397 points
398}
399
400pub fn seeded_rng(seed: usize) -> ChaCha8Rng {
402 ChaCha8Rng::seed_from_u64(seed as u64)
403}
404
405pub fn displacements(counts: &[i32]) -> Vec<i32> {
411 counts
412 .iter()
413 .scan(0, |acc, &x| {
414 let tmp = *acc;
415 *acc += x;
416 Some(tmp)
417 })
418 .collect()
419}
420
421#[cfg(test)]
422mod test {
423 use itertools::Itertools;
424
425 use super::sort_to_bins;
426
427 #[test]
428 fn test_sort_to_bins() {
429 let elems = (0..100).collect_vec();
430 let bins = [0, 17, 55];
431
432 let counts = sort_to_bins(&elems, &bins);
433
434 assert_eq!(counts[0], 17);
435 assert_eq!(counts[1], 38);
436 assert_eq!(counts[2], 45);
437 }
438}