use std::cmp::min;
use std::convert::TryInto;
use std::iter::FusedIterator;
#[derive(Debug, Clone)]
pub struct IterCombinations<I, F, T>
where
I: Iterator + Clone,
I::Item: Clone,
F: FnMut(&[I::Item]) -> T,
{
base: std::iter::Peekable<std::iter::Enumerate<I>>,
iterators: Box<[std::iter::Peekable<std::iter::Enumerate<I>>]>,
done: bool,
converter: F,
buffer: Box<[I::Item]>,
}
impl<I, F, T> Iterator for IterCombinations<I, F, T>
where
I: Iterator + Clone,
I::Item: Clone,
F: FnMut(&[I::Item]) -> T,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
} else if self.iterators.is_empty() {
self.done = true;
return Some((self.converter)(&[]));
}
let result = (self.converter)(&self.buffer[..]);
for i in 0..self.iterators.len() - 1 {
let (its, next_its) = &mut self.iterators[i..i + 2].split_at_mut(1);
let (it, next_it) = (&mut its[0], &mut next_its[0]);
let can_forward = {
let (index, _) = it.peek().unwrap();
let (next_index, _) = next_it.peek().unwrap();
index + 1 < *next_index
};
if can_forward {
_ = it.next().unwrap();
self.buffer[i] = it.peek().unwrap().1.clone();
return Some(result);
} else {
*it = self.base.clone();
for _ in 0..i {
_ = it.next();
}
let (_, x) = it.peek().unwrap();
self.buffer[i] = x.clone();
}
}
if let Some(last_it) = self.iterators.last_mut() {
_ = last_it.next();
if let Some(x) = last_it.peek() {
*self.buffer.last_mut().unwrap() = x.1.clone();
} else {
self.done = true;
}
}
return Some(result);
}
}
impl<I, F, T> FusedIterator for IterCombinations<I, F, T>
where
I: Iterator + Clone,
I::Item: Clone,
F: FnMut(&[I::Item]) -> T,
{
}
pub fn combinations<I, F, T>(it: I, k: usize, converter: F) -> IterCombinations<I, F, T>
where
I: Iterator + Clone,
I::Item: Clone,
F: FnMut(&[I::Item]) -> T,
{
let enumerated_it = it.enumerate().peekable();
let mut start_iterators = Vec::with_capacity(k);
let mut buffer = Vec::with_capacity(k);
let mut start_it = enumerated_it.clone();
for _ in 0..k {
start_iterators.push(start_it.clone());
if start_it.peek().is_none() {
return IterCombinations {
base: enumerated_it,
iterators: start_iterators.into_boxed_slice(),
done: true,
converter,
buffer: buffer.into_boxed_slice(),
};
}
let (_, x) = start_it.next().unwrap();
buffer.push(x);
}
return IterCombinations {
base: enumerated_it,
iterators: start_iterators.into_boxed_slice(),
done: false,
converter,
buffer: buffer.into_boxed_slice(),
};
}
pub fn clone_slice<T>(slice: &[T]) -> Box<[T]>
where
T: Clone,
{
let vec: Vec<T> = slice.to_vec();
return vec.into_boxed_slice();
}
pub fn clone_array<T, const N: usize>(slice: &[T]) -> [T; N]
where
T: Copy,
{
slice.try_into().unwrap()
}
pub fn basic_combinations<I>(it: I, k: usize) -> impl Iterator<Item = Box<[I::Item]>>
where
I: Iterator + Clone,
I::Item: Clone,
{
combinations(it, k, clone_slice)
}
pub fn powerset<I, F, T>(it: I, converter: F) -> impl Iterator<Item = T>
where
I: Iterator + Clone,
I::Item: Clone,
F: Clone + FnMut(&[I::Item]) -> T,
{
let len = it.clone().count();
(0..=len).flat_map(move |i| combinations(it.clone(), i, converter.clone()))
}
pub fn basic_powerset<I>(it: I) -> impl Iterator<Item = Box<[I::Item]>>
where
I: Iterator + Clone,
I::Item: Clone,
{
powerset(it, clone_slice)
}
#[derive(Debug, Clone)]
pub struct MultisetCombinations<'a, F, T>
where
F: FnMut(&[usize]) -> T,
{
converter: F,
superset: &'a [usize],
current: Option<Box<[usize]>>,
last_moved: usize,
first_trailing_empty: usize,
}
impl<'a, F, T> Iterator for MultisetCombinations<'a, F, T>
where
F: FnMut(&[usize]) -> T,
{
type Item = T;
fn next(&mut self) -> Option<T> {
let current = self.current.as_mut()?;
let result = (self.converter)(current);
let mut removed = 0;
let mut found_empty_place = self.last_moved + 1 < self.first_trailing_empty;
while !found_empty_place || current[self.last_moved] == 0 {
found_empty_place |= current[self.last_moved] < self.superset[self.last_moved];
removed += current[self.last_moved];
current[self.last_moved] = 0;
if self.last_moved == 0 {
self.current = None;
return Some(result);
}
self.last_moved -= 1;
}
removed += 1;
current[self.last_moved] -= 1;
while removed > 0 {
self.last_moved += 1;
if current[self.last_moved] + removed > self.superset[self.last_moved] {
removed = current[self.last_moved] + removed - self.superset[self.last_moved];
current[self.last_moved] = self.superset[self.last_moved];
} else {
current[self.last_moved] += removed;
removed = 0;
}
}
return Some(result);
}
}
impl<'a, F, T> FusedIterator for MultisetCombinations<'a, F, T> where F: FnMut(&[usize]) -> T {}
pub fn multiset_combinations<'a, F, T>(
multiset: &'a [usize],
size: usize,
converter: F,
) -> MultisetCombinations<'a, F, T>
where
F: FnMut(&[usize]) -> T,
{
assert!(!multiset.is_empty());
if size > multiset.iter().copied().sum::<usize>() {
return MultisetCombinations {
converter,
superset: multiset,
first_trailing_empty: 0,
current: None,
last_moved: 0,
};
}
let mut start = (0..multiset.len()).map(|_| 0).collect::<Vec<_>>().into_boxed_slice();
let mut to_insert = size;
let mut last_moved = 0;
let mut i = 0;
while to_insert > 0 {
start[i] = min(multiset[i], to_insert);
last_moved = i;
to_insert -= start[i];
i += 1;
}
let mut trailing_empty_entries = 0;
while trailing_empty_entries < multiset.len() && multiset[multiset.len() - trailing_empty_entries - 1] == 0 {
trailing_empty_entries += 1;
}
return MultisetCombinations {
converter,
superset: multiset,
first_trailing_empty: multiset.len() - trailing_empty_entries,
current: Some(start),
last_moved,
};
}
#[derive(Debug)]
pub struct MultiProduct<I, F, G, T>
where
I: Iterator + Clone,
F: FnMut(&[I::Item]) -> T,
G: Clone + Fn(usize, &I::Item) -> I::Item,
{
base_iters: Vec<I>,
current_iters: Vec<I>,
current: Vec<I::Item>,
clone_el: G,
converter: F,
done: bool,
}
impl<I, F, G, T> Clone for MultiProduct<I, F, G, T>
where
I: Iterator + Clone,
F: Clone + FnMut(&[I::Item]) -> T,
G: Clone + Fn(usize, &I::Item) -> I::Item,
{
fn clone(&self) -> Self {
MultiProduct {
base_iters: self.base_iters.clone(),
current_iters: self.current_iters.clone(),
current: self
.current
.iter()
.enumerate()
.map(|(i, x)| (self.clone_el)(i, x))
.collect(),
clone_el: self.clone_el.clone(),
converter: self.converter.clone(),
done: self.done,
}
}
}
impl<I, F, G, T> Iterator for MultiProduct<I, F, G, T>
where
I: Iterator + Clone,
F: FnMut(&[I::Item]) -> T,
G: Clone + Fn(usize, &I::Item) -> I::Item,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let result = (self.converter)(&self.current[..]);
let mut i = self.base_iters.len();
self.done = true;
while i > 0 {
i -= 1;
if let Some(val) = self.current_iters[i].next() {
self.current[i] = val;
self.done = false;
for j in (i + 1)..self.base_iters.len() {
self.current_iters[j] = self.base_iters[j].clone();
self.current[j] = self.current_iters[j].next().unwrap();
}
break;
}
}
return Some(result);
}
}
impl<I, F, G, T> FusedIterator for MultiProduct<I, F, G, T>
where
I: Iterator + Clone,
F: Clone + FnMut(&[I::Item]) -> T,
G: Clone + Fn(usize, &I::Item) -> I::Item,
{
}
pub fn multi_cartesian_product<J, F, G, T>(iters: J, converter: F, clone_el: G) -> MultiProduct<J::Item, F, G, T>
where
J: Iterator,
J::Item: Iterator + Clone,
F: FnMut(&[<J::Item as Iterator>::Item]) -> T,
G: Clone + Fn(usize, &<J::Item as Iterator>::Item) -> <J::Item as Iterator>::Item,
{
let base_iters = iters.collect::<Vec<_>>();
let mut current_iters = base_iters.clone();
let mut current = Vec::with_capacity(current_iters.len());
for it in current_iters.iter_mut() {
if let Some(v) = it.next() {
current.push(v);
} else {
return MultiProduct {
done: true,
converter,
base_iters,
clone_el,
current_iters,
current,
};
}
}
return MultiProduct {
done: false,
converter,
base_iters,
current_iters,
clone_el,
current,
};
}
#[derive(Debug)]
pub struct CondenseIter<I, F, T>
where
I: Iterator,
F: FnMut(I::Item) -> Option<T>,
{
base_iter: I,
f: F,
}
impl<I, F, T> Iterator for CondenseIter<I, F, T>
where
I: Iterator,
F: FnMut(I::Item) -> Option<T>,
{
type Item = T;
fn next(&mut self) -> Option<T> {
for el in self.base_iter.by_ref() {
if let Some(result) = (self.f)(el) {
return Some(result);
}
}
return None;
}
}
impl<I, F, T> FusedIterator for CondenseIter<I, F, T>
where
I: FusedIterator,
F: FnMut(I::Item) -> Option<T>,
{
}
pub fn condense<I, F, T>(iter: I, f: F) -> CondenseIter<I, F, T>
where
I: Iterator,
F: FnMut(I::Item) -> Option<T>,
{
CondenseIter { base_iter: iter, f }
}
#[test]
fn test_converted_combinations() {
let a = [2, 3, 5, 7];
assert_eq!(1, combinations(a.iter(), 0, |_| 0).count());
assert_eq!(4, combinations(a.iter(), 1, |_| 0).count());
assert_eq!(6, combinations(a.iter(), 2, |_| 0).count());
assert_eq!(1, combinations(a.iter(), 4, |_| 0).count());
assert_eq!(0, combinations(a.iter(), 5, |_| 0).count());
}
#[test]
fn test_powerset() {
let a = [1, 2, 3, 4];
assert_eq!(16, basic_powerset(a.iter()).count());
let a = [2, 3];
assert_eq!(
vec![
vec![].into_boxed_slice(),
vec![2].into_boxed_slice(),
vec![3].into_boxed_slice(),
vec![2, 3].into_boxed_slice()
],
basic_powerset(a.iter().copied()).collect::<Vec<_>>()
);
let a = [1, 2, 3];
assert_eq!(
vec![
vec![].into_boxed_slice(),
vec![1].into_boxed_slice(),
vec![2].into_boxed_slice(),
vec![3].into_boxed_slice(),
vec![1, 2].into_boxed_slice(),
vec![1, 3].into_boxed_slice(),
vec![2, 3].into_boxed_slice(),
vec![1, 2, 3].into_boxed_slice()
],
basic_powerset(a.iter().copied()).collect::<Vec<_>>()
);
}
#[allow(deprecated)]
#[test]
fn test_multi_cartesian_product() {
let a = [0, 1];
let b = [0, 1];
let c = [-1, 1];
let all = [a, b, c];
let it = multi_cartesian_product(
all.iter().map(|l| l.iter().map(|x| *x)),
|x| [x[0], x[1], x[2]],
|_, x| *x,
);
let expected = vec![
[0, 0, -1],
[0, 0, 1],
[0, 1, -1],
[0, 1, 1],
[1, 0, -1],
[1, 0, 1],
[1, 1, -1],
[1, 1, 1],
];
assert_eq!(expected, it.collect::<Vec<_>>());
}
#[allow(trivial_casts)]
#[test]
fn test_multiset_combinations() {
let a = [1, 2, 3, 1];
let mut iter = multiset_combinations(&a, 3, clone_slice);
assert_eq!(&[1, 2, 0, 0][..], &*iter.next().unwrap());
assert_eq!(&[1, 1, 1, 0][..], &*iter.next().unwrap());
assert_eq!(&[1, 1, 0, 1][..], &*iter.next().unwrap());
assert_eq!(&[1, 0, 2, 0][..], &*iter.next().unwrap());
assert_eq!(&[1, 0, 1, 1][..], &*iter.next().unwrap());
assert_eq!(&[0, 2, 1, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 2, 0, 1][..], &*iter.next().unwrap());
assert_eq!(&[0, 1, 2, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 1, 1, 1][..], &*iter.next().unwrap());
assert_eq!(&[0, 0, 3, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 0, 2, 1][..], &*iter.next().unwrap());
assert_eq!(None, iter.next());
assert_eq!(
&([] as [[usize; 1]; 0]),
&multiset_combinations(&[0], 1, clone_array::<usize, 1>).collect::<Vec<_>>()[..]
);
assert_eq!(
&([[0]] as [[usize; 1]; 1]),
&multiset_combinations(&[0], 0, clone_array::<usize, 1>).collect::<Vec<_>>()[..]
);
let a = [0, 2, 0, 1];
let mut iter = multiset_combinations(&a, 2, clone_slice);
assert_eq!(&[0, 2, 0, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 1, 0, 1][..], &*iter.next().unwrap());
assert_eq!(None, iter.next());
let a = [0, 3, 0, 0, 2, 0];
let mut iter = multiset_combinations(&a, 3, clone_slice);
assert_eq!(&[0, 3, 0, 0, 0, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 2, 0, 0, 1, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 1, 0, 0, 2, 0][..], &*iter.next().unwrap());
assert_eq!(None, iter.next());
let a = [0, 3, 0, 0, 2, 2, 0];
let mut iter = multiset_combinations(&a, 3, clone_slice);
assert_eq!(&[0, 3, 0, 0, 0, 0, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 2, 0, 0, 1, 0, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 2, 0, 0, 0, 1, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 1, 0, 0, 2, 0, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 1, 0, 0, 1, 1, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 1, 0, 0, 0, 2, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 0, 0, 0, 2, 1, 0][..], &*iter.next().unwrap());
assert_eq!(&[0, 0, 0, 0, 1, 2, 0][..], &*iter.next().unwrap());
assert_eq!(None, iter.next());
let a = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0];
let mut iter = multiset_combinations(&a, 10, clone_slice);
assert_eq!(
&[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0][..],
&*iter.next().unwrap()
);
assert_eq!(1000, iter.count());
}
#[test]
fn test_multiset_combinations_k_unlimited() {
fn fac(n: usize) -> usize { if n == 0 { 1 } else { n * fac(n - 1) } }
let a = [10, 10, 10, 10, 10, 10];
assert_eq!(1, multiset_combinations(&a[..], 0, |_| ()).count());
assert_eq!(6, multiset_combinations(&a[..], 1, |_| ()).count());
assert_eq!(
fac(6 + 8 - 1) / fac(6 - 1) / fac(8),
multiset_combinations(&a[..], 8, |_| ()).count()
);
}