algebraeon_sets/combinatorics/
subsets.rs1#[derive(Debug)]
3pub struct LexicographicSubsetsWithRemovals {
4 n: usize,
5 all_items_idx: Vec<Option<usize>>,
6 remaining_items: Vec<usize>,
7 subset: Vec<usize>,
8 finished: bool,
9}
10
11impl LexicographicSubsetsWithRemovals {
12 pub fn new(n: usize, k: usize) -> Self {
14 Self {
15 n,
16 all_items_idx: (0..n).map(Some).collect(),
17 remaining_items: (0..n).collect(),
18 subset: (0..k).collect(),
19 finished: k > n,
20 }
21 }
22
23 pub fn exclude(&mut self, a: usize) {
25 assert!(a < self.all_items_idx.len());
26 if self.all_items_idx[a].is_none() {
27 return;
29 }
30
31 while self.subset.iter().any(|x| self.remaining_items[*x] == a) {
32 match self.next() {
33 Some(_) => {}
34 None => {
35 break;
36 }
37 }
38 }
39
40 if !self.finished {
41 let a_idx = self.all_items_idx[a].unwrap();
42 self.remaining_items.remove(a_idx);
43 self.all_items_idx[a] = None;
44 for i in (a + 1)..self.all_items_idx.len() {
45 if let Some(idx) = self.all_items_idx[i].as_mut() {
46 *idx -= 1;
47 }
48 }
49 for x in &mut self.subset {
50 match (*x).cmp(&a_idx) {
51 std::cmp::Ordering::Less => {}
52 std::cmp::Ordering::Equal => {
53 unreachable!()
54 }
55 std::cmp::Ordering::Greater => {
56 *x -= 1;
57 }
58 }
59 }
60 self.n -= 1;
61 }
62 }
63}
64
65impl Iterator for LexicographicSubsetsWithRemovals {
66 type Item = Vec<usize>;
67
68 fn next(&mut self) -> Option<Self::Item> {
69 let next = if self.finished {
70 return None;
71 } else {
72 Some(
73 self.subset
74 .iter()
75 .map(|i| self.remaining_items[*i])
76 .collect(),
77 )
78 };
79
80 let k = self.subset.len();
81 let i = 'FIND_I: {
82 for (i, s) in self.subset.iter().rev().enumerate() {
83 if *s < self.n - i - 1 {
84 break 'FIND_I Some(i);
85 }
86 }
87 None
88 };
89 match i {
90 Some(i) => {
91 self.subset[k - 1 - i] += 1;
92 for j in 0..i {
93 self.subset[k - i + j] = self.subset[k - i - 1] + 1 + j;
94 }
95 }
96 None => {
97 self.finished = true;
98 }
99 }
100
101 next
102 }
103}
104
105pub fn subsets(n: usize, k: usize) -> impl Iterator<Item = Vec<usize>> {
122 LexicographicSubsetsWithRemovals::new(n, k)
123}
124
125pub fn all_subsets(n: usize) -> impl Iterator<Item = Vec<usize>> {
140 (0usize..(1 << n)).map(move |i| (0..n).filter(|j| i & (1 << j) != 0).collect())
141}
142
143pub fn subsets_of_vec<'a, T: 'a + Clone>(
153 items: Vec<T>,
154 k: usize,
155) -> impl 'a + Iterator<Item = Vec<T>> {
156 subsets(items.len(), k)
157 .map(move |subset| subset.into_iter().map(|idx| items[idx].clone()).collect())
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 pub fn lexicographic_subsets_with_removals_test_edge_cases() {
166 let x = subsets(0, 1).collect::<Vec<_>>();
167 println!("{:?}", x);
168 assert_eq!(x.len(), 0);
169
170 let x = subsets(3, 5).collect::<Vec<_>>();
171 println!("{:?}", x);
172 assert_eq!(x.len(), 0);
173
174 let x = subsets(3, 3).collect::<Vec<_>>();
175 println!("{:?}", x);
176 assert_eq!(x.len(), 1);
177 }
178
179 #[test]
180 pub fn lexicographic_subsets_with_removals_test_1() {
181 let mut c = LexicographicSubsetsWithRemovals::new(7, 3);
182 for _ in 0..19 {
183 let x = c.next().unwrap();
184 println!("{:?}", x);
185 }
186
187 println!("rm 4");
188 c.exclude(4);
189 println!("rm 5");
190 c.exclude(5);
191
192 for _ in 0..2 {
193 let x = c.next().unwrap();
194 println!("{:?}", x);
195 }
196
197 assert_eq!(c.next(), None);
198 }
199
200 #[test]
201 pub fn lexicographic_subsets_with_removals_test_2() {
202 let mut c = LexicographicSubsetsWithRemovals::new(7, 3);
203 c.exclude(0);
204 c.exclude(1);
205 c.exclude(2);
206 c.exclude(3);
207 c.exclude(4);
208 debug_assert_eq!(c.next(), None);
209 }
210
211 #[test]
212 pub fn run() {
213 println!("{:?}", subsets(5, 3).collect::<Vec<_>>());
214 assert_eq!(subsets(5, 3).collect::<Vec<_>>().len(), 10);
215 }
216}