use std::iter::FromIterator;
pub fn fixed_sum_sequences(
caps: & Vec< usize >,
target_sum: usize
)
->
Vec< Vec< usize> >
{
let cap_aggregate = caps.iter().sum();
if target_sum > cap_aggregate { return Vec::with_capacity(0) }
else if caps.is_empty() { return vec![ vec![] ] }
let trunc_caps = Vec::from_iter( caps.iter().cloned().take( caps.len() -1 ) );
let trunc_cap_agg: usize = trunc_caps.iter().sum();
let last_min =
match trunc_cap_agg < target_sum {
true => target_sum - trunc_cap_agg,
false => 0
};
let mut last_cap = *caps.last().unwrap();
if target_sum < last_cap { last_cap = target_sum }
let mut sequences = Vec::new();
for last_val in last_min .. last_cap + 1 {
let trunc_target_sum = target_sum - last_val;
let mut trunc_sequences = fixed_sum_sequences(
& trunc_caps,
trunc_target_sum,
);
for trunc_seq in trunc_sequences.iter_mut() { trunc_seq.push( last_val ) } sequences.append( &mut trunc_sequences ) }
sequences
}
#[cfg(test)]
mod tests {
use super::*;
use rand::Rng;
use itertools::Itertools;
#[test]
fn test_fixed_sum_sequences() {
let max_seq_length = 4;
let max_capacity_param_ceiling = 4;
let mut rng = rand::thread_rng();
for seq_len in 0 .. max_seq_length {
for max_capacity in 0 .. max_capacity_param_ceiling{
let caps = Vec::from_iter( (0..seq_len).map(|_x| rng.gen_range( 0 .. max_capacity + 1 )) ); for target_sum in 0 .. caps.iter().sum() {
let mut a = Vec::from_iter(
caps.iter()
.map(|x| 0 .. x+1)
.multi_cartesian_product()
.filter(|x| x.iter().sum::<usize>() == target_sum )
);
let mut b = fixed_sum_sequences( & caps, target_sum );
a.sort();
b.sort();
assert_eq!( a, b );
}
}
}
}
}