// Copyright © 2024 Mikhail Hogrefe
//
// This file is part of Malachite.
//
// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
// 3 of the License, or (at your option) any later version. See .
use core::hash::Hash;
use itertools::{chain, Itertools};
use malachite_base::iterators::bit_distributor::BitDistributorOutputType;
use malachite_base::num::exhaustive::exhaustive_positive_primitive_ints;
use malachite_base::num::iterators::{bit_distributor_sequence, ruler_sequence};
use malachite_base::tuples::exhaustive::{
exhaustive_dependent_pairs, exhaustive_dependent_pairs_stop_after_empty_ys,
ExhaustiveDependentPairsYsGenerator,
};
use std::collections::HashMap;
use std::fmt::Debug;
use std::iter::{once, repeat, Cloned};
use std::slice::Iter;
#[derive(Clone, Debug)]
struct ExhaustiveGeneratorFromMap {
map: HashMap,
}
impl
ExhaustiveDependentPairsYsGenerator>>
for ExhaustiveGeneratorFromMap
{
#[inline]
fn get_ys(&self, x: &X) -> Cloned> {
self.map[x].iter().cloned()
}
}
fn exhaustive_dependent_pairs_finite_ys_helper(
xs: I,
map: HashMap,
out_ruler: &[(I::Item, Y)],
out_normal_normal: &[(I::Item, Y)],
out_tiny_normal: &[(I::Item, Y)],
) where
I::Item: Clone + Debug + Eq + Hash,
Y: Clone + Debug + Eq,
{
let xss_ruler = exhaustive_dependent_pairs(
ruler_sequence(),
xs.clone(),
ExhaustiveGeneratorFromMap { map: map.clone() },
)
.take(20)
.collect_vec();
assert_eq!(xss_ruler.as_slice(), out_ruler);
let xss_normal_normal = exhaustive_dependent_pairs(
bit_distributor_sequence(
BitDistributorOutputType::normal(1),
BitDistributorOutputType::normal(1),
),
xs.clone(),
ExhaustiveGeneratorFromMap { map: map.clone() },
)
.take(20)
.collect_vec();
assert_eq!(xss_normal_normal.as_slice(), out_normal_normal);
let xss_tiny_normal = exhaustive_dependent_pairs(
bit_distributor_sequence(
BitDistributorOutputType::tiny(),
BitDistributorOutputType::normal(1),
),
xs,
ExhaustiveGeneratorFromMap { map },
)
.take(20)
.collect_vec();
assert_eq!(xss_tiny_normal.as_slice(), out_tiny_normal);
}
#[test]
fn test_exhaustive_dependent_pairs() {
exhaustive_dependent_pairs_finite_ys_helper(
[1, 2, 3].iter().copied(),
hashmap! {
1 => &[100, 101, 102][..],
2 => &[200, 201, 202][..],
3 => &[300, 301, 302][..]
},
&[(1, 100), (2, 200), (1, 101), (3, 300), (1, 102), (2, 201), (2, 202), (3, 301), (3, 302)],
&[(1, 100), (2, 200), (1, 101), (2, 201), (3, 300), (1, 102), (3, 301), (3, 302), (2, 202)],
&[(1, 100), (2, 200), (3, 300), (1, 101), (1, 102), (2, 201), (3, 301), (3, 302), (2, 202)],
);
exhaustive_dependent_pairs_finite_ys_helper(
["cat", "dog", "mouse", "dog", "cat"].iter().copied(),
hashmap! { "cat" => &[2, 3, 4][..], "dog" => &[20][..], "mouse" => &[30, 40][..] },
&[
("cat", 2),
("dog", 20),
("cat", 3),
("mouse", 30),
("cat", 4),
("mouse", 40),
("dog", 20),
("cat", 2),
("cat", 3),
("cat", 4),
],
&[
("cat", 2),
("dog", 20),
("cat", 3),
("mouse", 30),
("dog", 20),
("cat", 2),
("cat", 3),
("cat", 4),
("mouse", 40),
("cat", 4),
],
&[
("cat", 2),
("dog", 20),
("mouse", 30),
("dog", 20),
("cat", 3),
("mouse", 40),
("cat", 2),
("cat", 4),
("cat", 3),
("cat", 4),
],
);
exhaustive_dependent_pairs_finite_ys_helper(
[1, 2, 3, 2, 3, 2, 2].iter().copied(),
hashmap! { 1 => &[100, 101, 102][..], 2 => &[][..], 3 => &[300, 301, 302][..] },
&[(1, 100), (3, 300), (1, 101), (3, 300), (1, 102), (3, 301), (3, 302), (3, 301), (3, 302)],
&[(1, 100), (3, 300), (1, 101), (3, 301), (3, 300), (1, 102), (3, 301), (3, 302), (3, 302)],
&[(1, 100), (3, 300), (3, 300), (1, 101), (1, 102), (3, 301), (3, 301), (3, 302), (3, 302)],
);
exhaustive_dependent_pairs_finite_ys_helper(
[].iter().copied(),
hashmap! { 1 => &[100, 101, 102][..], 2 => &[][..], 3 => &[300, 301, 302][..] },
&[],
&[],
&[],
);
exhaustive_dependent_pairs_finite_ys_helper(
[2, 2, 2, 2, 2].iter().copied(),
hashmap! { 1 => &[100, 101, 102][..], 2 => &[][..], 3 => &[300, 301, 302][..] },
&[],
&[],
&[],
);
}
fn exhaustive_dependent_pairs_finite_ys_stop_after_empty_ys_helper(
xs: I,
map: HashMap,
out_ruler: &[(I::Item, Y)],
out_normal_normal: &[(I::Item, Y)],
out_tiny_normal: &[(I::Item, Y)],
) where
I::Item: Clone + Debug + Eq + Hash,
Y: Clone + Debug + Eq,
{
let xss_ruler = exhaustive_dependent_pairs_stop_after_empty_ys(
ruler_sequence(),
xs.clone(),
ExhaustiveGeneratorFromMap { map: map.clone() },
)
.take(20)
.collect_vec();
assert_eq!(xss_ruler.as_slice(), out_ruler);
let xss_normal_normal = exhaustive_dependent_pairs_stop_after_empty_ys(
bit_distributor_sequence(
BitDistributorOutputType::normal(1),
BitDistributorOutputType::normal(1),
),
xs.clone(),
ExhaustiveGeneratorFromMap { map: map.clone() },
)
.take(20)
.collect_vec();
assert_eq!(xss_normal_normal.as_slice(), out_normal_normal);
let xss_tiny_normal = exhaustive_dependent_pairs_stop_after_empty_ys(
bit_distributor_sequence(
BitDistributorOutputType::tiny(),
BitDistributorOutputType::normal(1),
),
xs,
ExhaustiveGeneratorFromMap { map },
)
.take(20)
.collect_vec();
assert_eq!(xss_tiny_normal.as_slice(), out_tiny_normal);
}
#[test]
fn test_exhaustive_dependent_pairs_stop_after_empty_ys() {
exhaustive_dependent_pairs_finite_ys_stop_after_empty_ys_helper(
[1, 2, 3].iter().copied(),
hashmap! {
1 => &[100, 101, 102][..],
2 => &[200, 201, 202][..],
3 => &[300, 301, 302][..]
},
&[(1, 100), (2, 200), (1, 101), (3, 300), (1, 102), (2, 201), (2, 202), (3, 301), (3, 302)],
&[(1, 100), (2, 200), (1, 101), (2, 201), (3, 300), (1, 102), (3, 301), (3, 302), (2, 202)],
&[(1, 100), (2, 200), (3, 300), (1, 101), (1, 102), (2, 201), (3, 301), (3, 302), (2, 202)],
);
exhaustive_dependent_pairs_finite_ys_stop_after_empty_ys_helper(
["cat", "dog", "mouse", "dog", "cat"].iter().copied(),
hashmap! { "cat" => &[2, 3, 4][..], "dog" => &[20][..], "mouse" => &[30, 40][..] },
&[
("cat", 2),
("dog", 20),
("cat", 3),
("mouse", 30),
("cat", 4),
("mouse", 40),
("dog", 20),
("cat", 2),
("cat", 3),
("cat", 4),
],
&[
("cat", 2),
("dog", 20),
("cat", 3),
("mouse", 30),
("dog", 20),
("cat", 2),
("cat", 3),
("cat", 4),
("mouse", 40),
("cat", 4),
],
&[
("cat", 2),
("dog", 20),
("mouse", 30),
("dog", 20),
("cat", 3),
("mouse", 40),
("cat", 2),
("cat", 4),
("cat", 3),
("cat", 4),
],
);
// Notice difference from `exhaustive_dependent_pairs`
exhaustive_dependent_pairs_finite_ys_stop_after_empty_ys_helper(
[1, 2, 3, 2, 3, 2, 2].iter().copied(),
hashmap! { 1 => &[100, 101, 102][..], 2 => &[][..], 3 => &[300, 301, 302][..] },
&[(1, 100)],
&[(1, 100)],
&[(1, 100)],
);
exhaustive_dependent_pairs_finite_ys_stop_after_empty_ys_helper(
[].iter().copied(),
hashmap! { 1 => &[100, 101, 102][..], 2 => &[][..], 3 => &[300, 301, 302][..] },
&[],
&[],
&[],
);
exhaustive_dependent_pairs_finite_ys_stop_after_empty_ys_helper(
[2, 2, 2, 2, 2].iter().copied(),
hashmap! { 1 => &[100, 101, 102][..], 2 => &[][..], 3 => &[300, 301, 302][..] },
&[],
&[],
&[],
);
// With `exhaustive_dependent_pairs` this would hang
exhaustive_dependent_pairs_finite_ys_stop_after_empty_ys_helper(
chain(once(3), repeat(2)),
hashmap! { 1 => &[100, 101, 102][..], 2 => &[][..], 3 => &[300, 301, 302][..] },
&[(3, 300)],
&[(3, 300)],
&[(3, 300)],
);
}
#[derive(Clone, Debug)]
struct MultiplesGeneratorHelper {
u: u64,
step: u64,
}
impl Iterator for MultiplesGeneratorHelper {
type Item = u64;
fn next(&mut self) -> Option {
let next = self.u;
self.u += self.step;
Some(next)
}
}
#[derive(Clone, Debug)]
struct MultiplesGenerator {}
impl ExhaustiveDependentPairsYsGenerator
for MultiplesGenerator
{
#[inline]
fn get_ys(&self, x: &u64) -> MultiplesGeneratorHelper {
MultiplesGeneratorHelper { u: *x, step: *x }
}
}
#[test]
fn test_exhaustive_dependent_pairs_infinite() {
let xs = exhaustive_positive_primitive_ints::();
let xss_ruler = exhaustive_dependent_pairs(ruler_sequence(), xs.clone(), MultiplesGenerator {})
.take(50)
.collect_vec();
assert_eq!(
xss_ruler.as_slice(),
&[
(1, 1),
(2, 2),
(1, 2),
(3, 3),
(1, 3),
(2, 4),
(1, 4),
(4, 4),
(1, 5),
(2, 6),
(1, 6),
(3, 6),
(1, 7),
(2, 8),
(1, 8),
(5, 5),
(1, 9),
(2, 10),
(1, 10),
(3, 9),
(1, 11),
(2, 12),
(1, 12),
(4, 8),
(1, 13),
(2, 14),
(1, 14),
(3, 12),
(1, 15),
(2, 16),
(1, 16),
(6, 6),
(1, 17),
(2, 18),
(1, 18),
(3, 15),
(1, 19),
(2, 20),
(1, 20),
(4, 12),
(1, 21),
(2, 22),
(1, 22),
(3, 18),
(1, 23),
(2, 24),
(1, 24),
(5, 10),
(1, 25),
(2, 26)
]
);
let xss_normal_normal = exhaustive_dependent_pairs(
bit_distributor_sequence(
BitDistributorOutputType::normal(1),
BitDistributorOutputType::normal(1),
),
xs.clone(),
MultiplesGenerator {},
)
.take(50)
.collect_vec();
assert_eq!(
xss_normal_normal.as_slice(),
&[
(1, 1),
(2, 2),
(1, 2),
(2, 4),
(3, 3),
(4, 4),
(3, 6),
(4, 8),
(1, 3),
(2, 6),
(1, 4),
(2, 8),
(3, 9),
(4, 12),
(3, 12),
(4, 16),
(5, 5),
(6, 6),
(5, 10),
(6, 12),
(7, 7),
(8, 8),
(7, 14),
(8, 16),
(5, 15),
(6, 18),
(5, 20),
(6, 24),
(7, 21),
(8, 24),
(7, 28),
(8, 32),
(1, 5),
(2, 10),
(1, 6),
(2, 12),
(3, 15),
(4, 20),
(3, 18),
(4, 24),
(1, 7),
(2, 14),
(1, 8),
(2, 16),
(3, 21),
(4, 28),
(3, 24),
(4, 32),
(5, 25),
(6, 30)
]
);
let xss_tiny_normal = exhaustive_dependent_pairs(
bit_distributor_sequence(
BitDistributorOutputType::tiny(),
BitDistributorOutputType::normal(1),
),
xs,
MultiplesGenerator {},
)
.take(50)
.collect_vec();
assert_eq!(
xss_tiny_normal.as_slice(),
&[
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(1, 2),
(2, 4),
(3, 6),
(4, 8),
(5, 5),
(6, 6),
(7, 7),
(8, 8),
(5, 10),
(6, 12),
(7, 14),
(8, 16),
(1, 3),
(2, 6),
(3, 9),
(4, 12),
(1, 4),
(2, 8),
(3, 12),
(4, 16),
(5, 15),
(6, 18),
(7, 21),
(8, 24),
(5, 20),
(6, 24),
(7, 28),
(8, 32),
(1, 5),
(2, 10),
(3, 15),
(4, 20),
(1, 6),
(2, 12),
(3, 18),
(4, 24),
(5, 25),
(6, 30),
(7, 35),
(8, 40),
(5, 30),
(6, 36),
(7, 42),
(8, 48),
(1, 7),
(2, 14)
]
);
}