1#![allow(unused_imports)]
2
3use std::{collections::BTreeSet, ops::Range};
4
5use rand::{
6 Rng, SeedableRng,
7 distributions::{Distribution, Uniform},
8};
9use rand_chacha::ChaCha20Rng;
10
11pub trait Gen {
12 type Output;
13 fn generate<R: Rng>(&self, rng: &mut R) -> Self::Output;
14}
15
16pub struct StrictAsc<B> {
17 bound: B,
18 len: usize,
19}
20
21pub struct Asc<B> {
22 bound: B,
23 len: usize,
24}
25
26impl Gen for Range<i32> {
27 type Output = i32;
28 fn generate<R: Rng>(&self, rng: &mut R) -> Self::Output {
29 let between = Uniform::from(self.clone());
30 between.sample(rng)
31 }
32}
33
34impl Gen for StrictAsc<Range<i32>> {
35 type Output = Vec<i32>;
36 fn generate<R: Rng>(&self, rng: &mut R) -> Self::Output {
37 let Self { bound: Range { start, end }, len } = self;
38
39 let dense = (2 * len) as i32 > (end - start) / 2;
41 let count = if dense { (end - start) as usize - len } else { *len };
42
43 let mut seen = BTreeSet::new();
44 while seen.len() < count {
45 seen.insert((*start..*end).generate(rng));
46 }
47
48 if dense {
49 (*start..*end).filter(|x| !seen.contains(x)).collect()
50 } else {
51 seen.into_iter().collect()
52 }
53 }
54}
55
56impl Gen for Asc<Range<i32>> {
57 type Output = Vec<i32>;
58 fn generate<R: Rng>(&self, rng: &mut R) -> Self::Output {
59 let Self { bound: Range { start, end }, len } = self;
60 let mut strict =
61 StrictAsc { bound: *start..end + *len as i32, len: *len }
62 .generate(rng);
63 for i in 0..*len {
64 strict[i] -= i as i32;
65 }
66 strict
67 }
68}
69
70#[test]
71fn uniformity() {
72 use std::collections::BTreeMap;
73
74 let mut rng = ChaCha20Rng::from_seed([0; 32]);
75 let n = 10_usize.pow(6);
76
77 let mut map = BTreeMap::new();
78 for _ in 0..n {
79 let tmp = StrictAsc { bound: 0..4, len: 3 }.generate(&mut rng);
80 *map.entry(tmp).or_insert(0) += 1;
81 }
82 let k = 4;
83 assert_eq!(map.len(), k);
84 for &v in map.values() {
85 assert!(v >= (n / k) * 99 / 100);
86 assert!(v <= (n / k) * 101 / 100);
87 }
88
89 let mut map = BTreeMap::new();
90 for _ in 0..n {
91 let tmp = Asc { bound: 0..4, len: 3 }.generate(&mut rng);
92 *map.entry(tmp).or_insert(0) += 1;
93 }
94 let k = 35;
95 assert_eq!(map.len(), k);
96 for &v in map.values() {
97 assert!(v >= (n / k) * 97 / 100);
98 assert!(v <= (n / k) * 103 / 100);
99 }
100}
101
102#[test]
103#[cfg(false)]
104fn macros() {
105 rand_gen! {
106 rng = _; n in 1_usize..10;
108 a in [0..10_i32.pow(9); n];
109 b in Asc { bound: 1..=5, len: 3 };
110 c in StrictAsc { bound: 1..=5, len: 3 };
111 }
112 let mut rng = ChaCha20Rng::from_seed([0; 32]);
113 rand_gen! {
114 rng = &mut rng;
115 n in 1_usize..10;
116 a in [0..10_i32.pow(9); n];
117 b in Asc { bound: 1..=5, len: 3 };
118 c in StrictAsc { bound: 1..=5, len: 3 };
119 }
120}