use std::cmp::Ordering;
use crate::prelude::*;
pub fn weighted_merge_sort_mut<T>(data: &mut [T], weights: &mut [f64]) -> Result<f64, ImgalError>
where
T: AsNumeric,
{
let dl = data.len();
let wl = weights.len();
if dl != wl {
return Err(ImgalError::MismatchedArrayLengths {
a_arr_name: "data",
a_arr_len: dl,
b_arr_name: "weights",
b_arr_len: wl,
});
};
let mut swap = 0.0;
let mut swap_temp: f64;
let mut step: usize = 1;
let mut left: usize;
let mut right: usize;
let mut end: usize;
let mut k: usize;
let mut data_buf = vec![T::default(); dl];
let mut weights_buf = vec![0.0; dl];
let mut cum_weights_buf = vec![0.0; dl];
let mut data_from = data;
let mut data_to: &mut [T] = data_buf.as_mut();
let mut weights_from = weights;
let mut weights_to: &mut [f64] = weights_buf.as_mut();
let mut data_in_buffer = false;
while step < dl {
left = 0;
k = 0;
let mut cw_acc = weights_from[0];
cum_weights_buf[0] = weights_from[0];
cum_weights_buf
.iter_mut()
.zip(weights_from.iter())
.skip(1)
.for_each(|(cw, w)| {
*cw = cw_acc + w;
cw_acc = *cw;
});
loop {
right = left + step;
end = right + step;
if end > dl {
if right > dl {
break;
}
end = dl;
}
let mut l = left;
let mut r = right;
while l < right && r < end {
match data_from[l].partial_cmp(&data_from[r]) {
Some(Ordering::Greater) => {
if l == 0 {
swap_temp = weights_from[r] * cum_weights_buf[right - 1];
} else {
swap_temp = weights_from[r]
* (cum_weights_buf[right - 1] - cum_weights_buf[l - 1]);
}
swap += swap_temp;
data_to[k] = data_from[r];
weights_to[k] = weights_from[r];
k += 1;
r += 1;
}
_ => {
data_to[k] = data_from[l];
weights_to[k] = weights_from[l];
k += 1;
l += 1;
}
}
}
if l < right {
while l < right {
data_to[k] = data_from[l];
weights_to[k] = weights_from[l];
k += 1;
l += 1;
}
} else {
while r < end {
data_to[k] = data_from[r];
weights_to[k] = weights_from[r];
k += 1;
r += 1;
}
}
left = end;
}
if k < dl {
while k < dl {
data_to[k] = data_from[k];
weights_to[k] = weights_from[k];
k += 1;
}
}
std::mem::swap(&mut data_from, &mut data_to);
std::mem::swap(&mut weights_from, &mut weights_to);
data_in_buffer = !data_in_buffer;
step *= 2;
}
if data_in_buffer {
data_to.clone_from_slice(data_from);
weights_to.clone_from_slice(weights_from);
}
Ok(swap)
}