use crate::{Error, Result};
pub fn calculate_fair_division_equal_weights(values: &[i128], output: &mut [i128]) -> Result<()> {
if values.is_empty() || output.len() != values.len() {
return Err(Error::InvalidInput);
}
if values.len() < 2 {
return Err(Error::NotEnoughParticipants);
}
let n = values.len() as i128;
let sum_v: i128 = values.iter().sum();
let mut max_v = values[0];
let mut max_index = 0;
for (i, &v) in values.iter().enumerate() {
if v > max_v {
max_v = v;
max_index = i;
}
}
let delta = match (n.checked_mul(max_v), n.checked_mul(n)) {
(Some(n_max_v), Some(n_squared)) => match n_max_v.checked_sub(sum_v) {
Some(numerator) => numerator / n_squared,
None => return Err(Error::CalculationFailed),
},
_ => return Err(Error::CalculationFailed),
};
let mut sum_others = 0;
for (i, &v) in values.iter().enumerate() {
if i != max_index {
let share = v / n + delta;
output[i] = share;
sum_others += share;
} else {
output[i] = 0;
}
}
output[max_index] = -sum_others;
Ok(())
}
pub fn calculate_fair_division_weighted(
values: &[i128],
weights: &[i128],
output: &mut [i128],
) -> Result<()> {
if values.is_empty()
|| weights.is_empty()
|| values.len() != weights.len()
|| output.len() != values.len()
{
return Err(Error::InvalidInput);
}
if values.len() < 2 {
return Err(Error::NotEnoughParticipants);
}
for &weight in weights {
if weight <= 0 {
return Err(Error::InvalidInput);
}
}
let total_weight: i128 = weights.iter().sum();
let n = total_weight;
let sum_v: i128 = values
.iter()
.zip(weights.iter())
.map(|(&v, &w)| v * w)
.sum();
let mut max_v = values[0];
let mut max_index = 0;
for (i, &v) in values.iter().enumerate() {
if v > max_v {
max_v = v;
max_index = i;
}
}
let delta = match (n.checked_mul(max_v), n.checked_mul(n)) {
(Some(n_max_v), Some(n_squared)) => match n_max_v.checked_sub(sum_v) {
Some(numerator) => numerator / n_squared,
None => return Err(Error::CalculationFailed),
},
_ => return Err(Error::CalculationFailed),
};
let mut sum_others = 0;
for (i, (&v, &weight)) in values.iter().zip(weights.iter()).enumerate() {
if i != max_index {
let share = (v / n + delta) * weight;
output[i] = share;
sum_others += share;
} else {
output[i] = 0;
}
}
output[max_index] = -sum_others;
Ok(())
}
pub fn get_one_dd_rand_num(values: &[u128], n: usize, out: &mut u128) -> Result<()> {
if values.is_empty() || n == 0 {
return Err(Error::InvalidInput);
}
if values.len() != n {
return Err(Error::InvalidInput);
}
let mut sum = 0u128;
let n_u128 = n as u128;
for i in 0..n {
sum += values[i];
if sum >= n_u128 {
sum = sum % n_u128;
}
}
*out = sum;
Ok(())
}
pub fn get_k_dd_rand_num(
groups: &[&[u128]],
n: usize,
k: usize,
output: &mut [usize],
) -> Result<()> {
if groups.is_empty() || n == 0 || k == 0 {
return Err(Error::InvalidInput);
}
if n > 100_000 || k > 1_000 {
return Err(Error::InvalidInput);
}
if k > n {
return Err(Error::InvalidInput);
}
if groups.len() != n {
return Err(Error::InvalidInput);
}
if output.len() != k {
return Err(Error::InvalidInput);
}
for group in groups {
if group.len() != k {
return Err(Error::InvalidInput);
}
}
let n_u128 = n as u128;
let mut sum = 0u128;
for group in groups {
sum += group[0];
if sum >= n_u128 {
sum = sum % n_u128;
}
}
let first_offset = sum as usize;
output[0] = first_offset;
let mut used = [false; 1000];
if n <= 1000 {
used[first_offset] = true;
for i in 1..k {
let mut sum = 0u128;
for group in groups {
sum += group[i];
if sum >= n_u128 {
sum = sum % n_u128;
}
}
let mut off_t = sum as usize;
while used[off_t] {
off_t = (off_t + 1) % n;
}
used[off_t] = true;
output[i] = off_t;
}
} else {
for i in 1..k {
let mut sum = 0u128;
for group in groups {
sum += group[i];
if sum >= n_u128 {
sum = sum % n_u128;
}
}
let mut off_t = sum as usize;
loop {
let mut found = false;
for j in 0..i {
if output[j] == off_t {
found = true;
break;
}
}
if !found {
break; }
off_t = (off_t + 1) % n;
}
output[i] = off_t;
}
}
Ok(())
}