1pub struct ConfigIterator {
8 num_variables: usize,
9 num_flavors: usize,
10 current: Option<Vec<usize>>,
11 total_configs: usize,
12 current_index: usize,
13}
14
15impl ConfigIterator {
16 pub fn new(num_variables: usize, num_flavors: usize) -> Self {
18 let total_configs = num_flavors.pow(num_variables as u32);
19 let current = if num_variables == 0 || num_flavors == 0 {
20 None
21 } else {
22 Some(vec![0; num_variables])
23 };
24 Self {
25 num_variables,
26 num_flavors,
27 current,
28 total_configs,
29 current_index: 0,
30 }
31 }
32
33 pub fn total(&self) -> usize {
35 self.total_configs
36 }
37}
38
39impl Iterator for ConfigIterator {
40 type Item = Vec<usize>;
41
42 fn next(&mut self) -> Option<Self::Item> {
43 let current = self.current.take()?;
44 let result = current.clone();
45
46 let mut next = current;
48 let mut carry = true;
49 for i in (0..self.num_variables).rev() {
50 if carry {
51 next[i] += 1;
52 if next[i] >= self.num_flavors {
53 next[i] = 0;
54 } else {
55 carry = false;
56 }
57 }
58 }
59
60 self.current_index += 1;
61 if self.current_index < self.total_configs {
62 self.current = Some(next);
63 }
64
65 Some(result)
66 }
67
68 fn size_hint(&self) -> (usize, Option<usize>) {
69 let remaining = self.total_configs - self.current_index;
70 (remaining, Some(remaining))
71 }
72}
73
74impl ExactSizeIterator for ConfigIterator {}
75
76pub fn index_to_config(index: usize, num_variables: usize, num_flavors: usize) -> Vec<usize> {
80 let mut config = vec![0; num_variables];
81 let mut remaining = index;
82 for i in (0..num_variables).rev() {
83 config[i] = remaining % num_flavors;
84 remaining /= num_flavors;
85 }
86 config
87}
88
89pub fn config_to_index(config: &[usize], num_flavors: usize) -> usize {
93 let mut index = 0;
94 for &value in config {
95 index = index * num_flavors + value;
96 }
97 index
98}
99
100pub fn config_to_bits(config: &[usize]) -> Vec<bool> {
102 config.iter().map(|&v| v != 0).collect()
103}
104
105pub fn bits_to_config(bits: &[bool]) -> Vec<usize> {
107 bits.iter().map(|&b| if b { 1 } else { 0 }).collect()
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn test_config_iterator_binary() {
116 let iter = ConfigIterator::new(3, 2);
117 assert_eq!(iter.total(), 8);
118
119 let configs: Vec<_> = iter.collect();
120 assert_eq!(configs.len(), 8);
121 assert_eq!(configs[0], vec![0, 0, 0]);
122 assert_eq!(configs[1], vec![0, 0, 1]);
123 assert_eq!(configs[2], vec![0, 1, 0]);
124 assert_eq!(configs[3], vec![0, 1, 1]);
125 assert_eq!(configs[4], vec![1, 0, 0]);
126 assert_eq!(configs[5], vec![1, 0, 1]);
127 assert_eq!(configs[6], vec![1, 1, 0]);
128 assert_eq!(configs[7], vec![1, 1, 1]);
129 }
130
131 #[test]
132 fn test_config_iterator_ternary() {
133 let iter = ConfigIterator::new(2, 3);
134 assert_eq!(iter.total(), 9);
135
136 let configs: Vec<_> = iter.collect();
137 assert_eq!(configs.len(), 9);
138 assert_eq!(configs[0], vec![0, 0]);
139 assert_eq!(configs[1], vec![0, 1]);
140 assert_eq!(configs[2], vec![0, 2]);
141 assert_eq!(configs[3], vec![1, 0]);
142 assert_eq!(configs[8], vec![2, 2]);
143 }
144
145 #[test]
146 fn test_config_iterator_empty() {
147 let iter = ConfigIterator::new(0, 2);
148 assert_eq!(iter.total(), 1);
149 let configs: Vec<_> = iter.collect();
150 assert_eq!(configs.len(), 0); }
152
153 #[test]
154 fn test_config_iterator_single_variable() {
155 let iter = ConfigIterator::new(1, 4);
156 assert_eq!(iter.total(), 4);
157
158 let configs: Vec<_> = iter.collect();
159 assert_eq!(configs, vec![vec![0], vec![1], vec![2], vec![3]]);
160 }
161
162 #[test]
163 fn test_index_to_config() {
164 assert_eq!(index_to_config(0, 3, 2), vec![0, 0, 0]);
165 assert_eq!(index_to_config(1, 3, 2), vec![0, 0, 1]);
166 assert_eq!(index_to_config(7, 3, 2), vec![1, 1, 1]);
167 assert_eq!(index_to_config(5, 3, 2), vec![1, 0, 1]);
168 }
169
170 #[test]
171 fn test_config_to_index() {
172 assert_eq!(config_to_index(&[0, 0, 0], 2), 0);
173 assert_eq!(config_to_index(&[0, 0, 1], 2), 1);
174 assert_eq!(config_to_index(&[1, 1, 1], 2), 7);
175 assert_eq!(config_to_index(&[1, 0, 1], 2), 5);
176 }
177
178 #[test]
179 fn test_index_config_roundtrip() {
180 for i in 0..27 {
181 let config = index_to_config(i, 3, 3);
182 let back = config_to_index(&config, 3);
183 assert_eq!(i, back);
184 }
185 }
186
187 #[test]
188 fn test_config_to_bits() {
189 assert_eq!(
190 config_to_bits(&[0, 1, 0, 1]),
191 vec![false, true, false, true]
192 );
193 assert_eq!(config_to_bits(&[0, 0, 0]), vec![false, false, false]);
194 assert_eq!(config_to_bits(&[1, 1, 1]), vec![true, true, true]);
195 }
196
197 #[test]
198 fn test_bits_to_config() {
199 assert_eq!(
200 bits_to_config(&[false, true, false, true]),
201 vec![0, 1, 0, 1]
202 );
203 assert_eq!(bits_to_config(&[true, true, true]), vec![1, 1, 1]);
204 }
205
206 #[test]
207 fn test_exact_size_iterator() {
208 let mut iter = ConfigIterator::new(3, 2);
209 assert_eq!(iter.len(), 8);
210 iter.next();
211 assert_eq!(iter.len(), 7);
212 iter.next();
213 iter.next();
214 assert_eq!(iter.len(), 5);
215 }
216}