problemreductions/
config.rs

1//! Configuration utilities for problem solving.
2
3/// Iterator over all possible configurations for a given number of variables and flavors.
4///
5/// Generates configurations in lexicographic order, from [0, 0, ..., 0] to
6/// [num_flavors-1, num_flavors-1, ..., num_flavors-1].
7pub 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    /// Create a new configuration iterator.
17    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    /// Returns the total number of configurations.
34    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        // Advance to next configuration
47        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
76/// Convert a configuration index to a configuration vector.
77///
78/// The index is treated as a number in base `num_flavors`.
79pub 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
89/// Convert a configuration vector to an index.
90///
91/// The configuration is treated as digits in base `num_flavors`.
92pub 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
100/// Convert a binary configuration to a bitvec-style representation.
101pub fn config_to_bits(config: &[usize]) -> Vec<bool> {
102    config.iter().map(|&v| v != 0).collect()
103}
104
105/// Convert a bitvec-style representation to a binary configuration.
106pub 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); // Empty because num_variables is 0
151    }
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}