use crate::fast_permutations;
use crate::fast_permutations::FastPermutations;
use itertools::Itertools;
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::iter::FusedIterator;
macro_rules! clone_fields { ($($field:ident),*) => {
#[inline]
fn clone(&self) -> Self {
Self {
$($field: self.$field.clone(),)*
}
}
}
}
macro_rules! debug_fmt_fields { ($tyname:ident, $($($field:tt).+),*) => {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
f.debug_struct(stringify!($tyname))
$(
.field(stringify!($($field).+), &self.$($field).+)
)*
.finish()
}
}
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct RestrictedPermutations<I: Iterator> {
permutations: FastPermutations<I>,
restrict: Vec<I::Item>,
}
impl<I> Clone for RestrictedPermutations<I>
where
I: Clone + Iterator,
I::Item: Clone,
{
clone_fields!(permutations, restrict);
}
impl<I> Debug for RestrictedPermutations<I>
where
I: Iterator + Debug,
I::Item: Debug,
{
debug_fmt_fields!(RestrictedPermutations, permutations, restrict);
}
pub fn restricted_permutations<I>(iter: I, k: usize, restrict: I) -> RestrictedPermutations<I>
where
I: Iterator,
I::Item: Clone + Ord,
{
RestrictedPermutations {
permutations: fast_permutations(iter, k),
restrict: restrict.collect_vec(),
}
}
pub fn restricted_permutations_by_self<I>(iter: I, k: usize) -> RestrictedPermutations<I>
where
I: Iterator + Clone,
I::Item: Clone + Ord,
{
let permutations = fast_permutations(iter.clone(), k);
let restrict = iter.collect_vec();
RestrictedPermutations {
permutations,
restrict,
}
}
impl<I> Iterator for RestrictedPermutations<I>
where
I: Iterator,
I::Item: Clone + Ord + Copy,
{
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
match self.permutations.next() {
None => return None,
Some(x) => {
if !x.iter().enumerate().any(|x| self.restrict[x.0] == *x.1) {
return Some(x);
}
}
};
self.next()
}
}
impl<I> FusedIterator for RestrictedPermutations<I>
where
I: Iterator,
I::Item: Clone + Ord + Copy + Debug,
{
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct RestrictedPermutationsByMapIndex<I: Iterator> {
permutations: FastPermutations<I>,
restrict: HashMap<usize, Vec<I::Item>>,
}
impl<I> Clone for RestrictedPermutationsByMapIndex<I>
where
I: Clone + Iterator,
I::Item: Clone,
{
clone_fields!(permutations, restrict);
}
impl<I> Debug for RestrictedPermutationsByMapIndex<I>
where
I: Iterator + Debug,
I::Item: Debug,
{
debug_fmt_fields!(RestrictedPermutationsByMapIndex, permutations, restrict);
}
pub fn restricted_permutations_by_map_index<I>(
iter: I,
k: usize,
restrict: HashMap<usize, Vec<I::Item>>,
) -> RestrictedPermutationsByMapIndex<I>
where
I: Iterator,
I::Item: Clone + Ord,
{
RestrictedPermutationsByMapIndex {
permutations: fast_permutations(iter, k),
restrict,
}
}
impl<I> Iterator for RestrictedPermutationsByMapIndex<I>
where
I: Iterator,
I::Item: Clone + Ord + Copy,
{
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
match self.permutations.next() {
None => return None,
Some(x) => {
if !x.iter().enumerate().any(|x| {
if self.restrict.contains_key(&x.0) {
self.restrict[&x.0].contains(x.1)
} else {
false
}
}) {
return Some(x);
}
}
};
self.next()
}
}
impl<I> FusedIterator for RestrictedPermutationsByMapIndex<I>
where
I: Iterator,
I::Item: Clone + Ord + Copy + Debug,
{
}
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct RestrictedPermutationsByMapValue<I: Iterator> {
permutations: FastPermutations<I>,
restrict: HashMap<I::Item, Vec<usize>>,
}
impl<I> Clone for RestrictedPermutationsByMapValue<I>
where
I: Clone + Iterator,
I::Item: Clone,
{
clone_fields!(permutations, restrict);
}
impl<I> Debug for RestrictedPermutationsByMapValue<I>
where
I: Iterator + Debug,
I::Item: Debug,
{
debug_fmt_fields!(RestrictedPermutationsByMapValue, permutations, restrict);
}
pub fn restricted_permutations_by_map_value<I>(
iter: I,
k: usize,
restrict: HashMap<I::Item, Vec<usize>>,
) -> RestrictedPermutationsByMapValue<I>
where
I: Iterator,
I::Item: Clone + Ord,
{
RestrictedPermutationsByMapValue {
permutations: fast_permutations(iter, k),
restrict,
}
}
impl<I> Iterator for RestrictedPermutationsByMapValue<I>
where
I: Iterator,
I::Item: Clone + Ord + Copy + Hash,
{
type Item = Vec<I::Item>;
fn next(&mut self) -> Option<Self::Item> {
match self.permutations.next() {
None => return None,
Some(x) => {
if !x.iter().enumerate().any(|x| {
if self.restrict.contains_key(x.1) {
self.restrict[x.1].contains(&x.0)
} else {
false
}
}) {
return Some(x);
}
}
};
self.next()
}
}
impl<I> FusedIterator for RestrictedPermutationsByMapValue<I>
where
I: Iterator,
I::Item: Clone + Ord + Copy + Debug + Hash,
{
}
#[cfg(test)]
mod tests {
use super::*;
use itertools::assert_equal;
#[test]
fn test_self_restricted_manual() {
assert_equal(
restricted_permutations_by_self(vec![1, 0].into_iter(), 2),
[[0, 1]],
);
assert_equal(
restricted_permutations_by_self(vec![1, 0, 2].into_iter(), 3),
[[0, 2, 1], [2, 1, 0]],
);
assert_equal(
restricted_permutations_by_self(vec![1, 0, 2].into_iter(), 2),
[[0, 1], [0, 2], [2, 1]],
);
}
#[test]
fn test_restricted() {
assert_equal(
restricted_permutations(vec![1usize, 0].into_iter(), 2, vec![1, 0].into_iter()),
[[0, 1]],
);
assert_equal(
restricted_permutations_by_self(vec![1, 0, 2].into_iter(), 3),
[[0, 2, 1], [2, 1, 0]],
);
assert_equal(
restricted_permutations_by_self(vec![1, 0, 2].into_iter(), 2),
[[0, 1], [0, 2], [2, 1]],
);
}
}