use std::fmt::Display;
use itertools::Itertools;
use mpi::traits::CommunicatorCollectives;
use mpi::traits::Equivalence;
use rand::{seq::SliceRandom, Rng};
use crate::morton::MortonKey;
use crate::tools::{gather_to_all, global_max, global_min, redistribute_by_bins};
const OVERSAMPLING: usize = 8;
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Equivalence)]
struct UniqueItem {
pub value: MortonKey,
pub rank: usize,
pub index: usize,
}
impl Display for UniqueItem {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"(value: {}, rank: {}, index: {})",
self.value, self.rank, self.index
)
}
}
impl UniqueItem {
pub fn new(value: MortonKey, rank: usize, index: usize) -> Self {
Self { value, rank, index }
}
}
fn to_unique_item(arr: &[MortonKey], rank: usize) -> Vec<UniqueItem> {
arr.iter()
.enumerate()
.map(|(index, &item)| UniqueItem::new(item, rank, index))
.collect()
}
fn get_buckets<C, R>(arr: &[UniqueItem], comm: &C, rng: &mut R) -> Vec<UniqueItem>
where
C: CommunicatorCollectives,
R: Rng + ?Sized,
{
let size = comm.size() as usize;
let oversampling = if arr.len() < OVERSAMPLING {
arr.len()
} else {
OVERSAMPLING
};
let global_min_elem = global_min(arr, comm);
let global_max_elem = global_max(arr, comm);
let splitters = arr
.choose_multiple(rng, oversampling)
.copied()
.collect::<Vec<_>>();
let mut all_splitters = gather_to_all(&splitters, comm);
all_splitters.sort_unstable();
if *all_splitters.first().unwrap() != global_min_elem {
all_splitters.insert(0, global_min_elem)
}
if *all_splitters.last().unwrap() != global_max_elem {
all_splitters.push(global_max_elem);
}
all_splitters = split(&all_splitters, size)
.map(|slice| slice.first().unwrap())
.copied()
.collect::<Vec<_>>();
all_splitters
}
pub fn parsort<C: CommunicatorCollectives, R: Rng + ?Sized>(
arr: &[MortonKey],
comm: &C,
rng: &mut R,
) -> Vec<MortonKey> {
let size = comm.size() as usize;
let rank = comm.rank() as usize;
let mut arr = arr.to_vec();
if size == 1 {
arr.sort_unstable();
return arr;
}
let mut arr = to_unique_item(&arr, rank);
arr.sort_unstable();
let buckets = get_buckets(&arr, comm, rng);
let mut recvbuffer = redistribute_by_bins(&arr, &buckets, comm);
recvbuffer.sort_unstable();
recvbuffer.iter().map(|&elem| elem.value).collect_vec()
}
fn split<T>(slice: &[T], n: usize) -> impl Iterator<Item = &[T]> {
let len = slice.len() / n;
let rem = slice.len() % n;
Split { slice, len, rem }
}
struct Split<'a, T> {
slice: &'a [T],
len: usize,
rem: usize,
}
impl<'a, T> Iterator for Split<'a, T> {
type Item = &'a [T];
fn next(&mut self) -> Option<Self::Item> {
if self.slice.is_empty() {
return None;
}
let mut len = self.len;
if self.rem > 0 {
len += 1;
self.rem -= 1;
}
let (chunk, rest) = self.slice.split_at(len);
self.slice = rest;
Some(chunk)
}
}