1
//! Iterator over cubes in a BDD.
2

            
3
use std::marker::PhantomData;
4

            
5
use merc_utilities::MercError;
6
use oxidd::BooleanFunction;
7
use oxidd::bdd::BDDFunction;
8
use oxidd::util::OptBool;
9

            
10
/// Iterator over all cubes (satisfying assignments) in a BDD.
11
///
12
/// The returned cubes contain don't care values (OptBool::None) for variables
13
/// that can be either true or false without affecting the satisfaction of the
14
/// BDD.
15
pub struct CubeIter<'a> {
16
    /// The BDD to iterate over.
17
    bdd: BDDFunction,
18

            
19
    _marker: PhantomData<&'a ()>,
20
}
21

            
22
impl<'a> CubeIter<'a> {
23
    /// Creates a new cube iterator for the given BDD.
24
100
    pub fn new(bdd: &'a BDDFunction) -> Self {
25
100
        Self {
26
100
            bdd: bdd.clone(),
27
100
            _marker: PhantomData,
28
100
        }
29
100
    }
30
}
31

            
32
impl Iterator for CubeIter<'_> {
33
    type Item = Vec<OptBool>;
34

            
35
683
    fn next(&mut self) -> Option<Self::Item> {
36
683
        let cube = self.bdd.pick_cube_dd(|_, _, _| true).unwrap();
37

            
38
683
        self.bdd = self.bdd.and(&cube.not().unwrap()).ok().unwrap();
39

            
40
683
        cube.pick_cube(|_, _, _| true)
41
683
    }
42
}
43

            
44
/// The same as [CubeIter], but iterates over all satisfying assignments without
45
/// considering don't care values. For the universe BDD, the [CubeIter] yields only
46
/// one cube with all don't cares, while this iterator yields all possible cubes.
47
pub struct CubeIterAll<'a> {
48
    bdd: &'a BDDFunction,
49
    // The variables used in the BDD.
50
    variables: &'a Vec<BDDFunction>,
51
    // The last cube generated.
52
    cube: Vec<OptBool>,
53
    // Whether to stop the iteration.
54
    done: bool,
55
}
56

            
57
impl<'a> CubeIterAll<'a> {
58
    /// Creates a new cube iterator that iterates over the single cube
59
200
    pub fn new(variables: &'a Vec<BDDFunction>, bdd: &'a BDDFunction) -> CubeIterAll<'a> {
60
200
        let cube = Vec::from_iter((0..variables.len()).map(|_| OptBool::False));
61
200
        Self {
62
200
            bdd,
63
200
            cube,
64
200
            variables,
65
200
            done: false,
66
200
        }
67
200
    }
68
}
69

            
70
impl Iterator for CubeIterAll<'_> {
71
    type Item = Result<(Vec<OptBool>, BDDFunction), MercError>;
72

            
73
1809
    fn next(&mut self) -> Option<Self::Item> {
74
1809
        if self.done {
75
123
            return None;
76
1686
        }
77

            
78
        loop {
79
4000
            let mut tmp = self.bdd.clone();
80
14920
            for (index, value) in self.cube.iter().enumerate() {
81
14920
                if *value == OptBool::True {
82
7460
                    tmp = match tmp.and(&self.variables[index]) {
83
7460
                        Ok(val) => val,
84
                        Err(e) => return Some(Err(e.into())),
85
                    };
86
                } else {
87
7460
                    let not_var = match self.variables[index].not() {
88
7460
                        Ok(val) => val,
89
                        Err(e) => return Some(Err(e.into())),
90
                    };
91
7460
                    tmp = match tmp.and(&not_var) {
92
7460
                        Ok(val) => val,
93
                        Err(e) => return Some(Err(e.into())),
94
                    };
95
                }
96

            
97
14920
                if !tmp.satisfiable() {
98
                    // This cube is not satisfying, try the next one, or quit if overflow
99
2391
                    if !increment(&mut self.cube) {
100
77
                        return None;
101
2314
                    }
102
2314
                    break;
103
12529
                }
104
            }
105

            
106
3923
            if tmp.satisfiable() {
107
1609
                let result = self.cube.clone();
108
                // The next iteration overflows, we are done
109
1609
                self.done = !increment(&mut self.cube);
110
1609
                return Some(Ok((result, tmp)));
111
2314
            }
112
        }
113
1809
    }
114
}
115

            
116
/// Perform the binary increment, returns false if overflow occurs.
117
4000
fn increment(cube: &mut [OptBool]) -> bool {
118
7600
    for value in cube.iter_mut() {
119
        // Set each variable to true until we find one that is false
120
7600
        if *value == OptBool::False {
121
3800
            *value = OptBool::True;
122
3800
            return true;
123
3800
        }
124

            
125
3800
        *value = OptBool::False;
126
    }
127

            
128
    // All variables were true, overflow
129
200
    false
130
4000
}
131

            
132
#[cfg(test)]
133
mod tests {
134
    use std::collections::HashSet;
135

            
136
    use itertools::Itertools;
137

            
138
    use merc_utilities::MercError;
139
    use merc_utilities::random_test;
140
    use oxidd::bdd::BDDFunction;
141
    use oxidd::util::OptBool;
142

            
143
    use crate::CubeIter;
144
    use crate::CubeIterAll;
145
    use crate::FormatConfig;
146
    use crate::create_variables;
147
    use crate::from_iter;
148
    use crate::random_bitvectors;
149

            
150
    #[test]
151
    #[cfg_attr(miri, ignore)] // Oxidd does not work with miri
152
1
    fn test_random_cube_iter_all() {
153
100
        random_test(100, |rng| {
154
100
            let manager_ref = oxidd::bdd::new_manager(2048, 1024, 1);
155
100
            let set = random_bitvectors(rng, 5, 20);
156
1036
            println!("Set: {:?}", set.iter().format_with(", ", |v, f| f(&FormatConfig(v))));
157

            
158
100
            let variables = create_variables(&manager_ref, 5).unwrap();
159

            
160
100
            let bdd = from_iter(&manager_ref, &variables, set.iter()).unwrap();
161

            
162
            // Check that the cube iterator yields all the expected cubes
163
100
            let result: Result<Vec<(Vec<OptBool>, BDDFunction)>, MercError> =
164
100
                CubeIterAll::new(&variables, &bdd).collect();
165
100
            let cubes: Vec<(Vec<OptBool>, BDDFunction)> = result.unwrap();
166
100
            let mut seen = HashSet::new();
167
856
            for (bits, _) in &cubes {
168
856
                println!("Cube: {}", FormatConfig(&bits));
169
856
                assert!(set.contains(&bits), "Cube {} not in expected set", FormatConfig(&bits));
170
856
                assert!(
171
856
                    seen.insert(bits.clone()),
172
                    "Duplicate cube found: {}",
173
                    FormatConfig(&bits)
174
                );
175
            }
176

            
177
1036
            for cube in &set {
178
6186
                let found = cubes.iter().find(|(bits, _)| bits == cube);
179
1036
                assert!(found.is_some(), "Expected cube {} not found", FormatConfig(cube));
180
            }
181
100
        })
182
1
    }
183

            
184
    #[test]
185
    #[cfg_attr(miri, ignore)] // Oxidd does not work with miri
186
1
    fn test_random_cube_iter() {
187
100
        random_test(100, |rng| {
188
100
            let manager_ref = oxidd::bdd::new_manager(2048, 1024, 1);
189
100
            let set = random_bitvectors(rng, 5, 20);
190
915
            println!("Set: {:?}", set.iter().format_with(", ", |v, f| f(&FormatConfig(v))));
191

            
192
100
            let variables = create_variables(&manager_ref, 5).unwrap();
193

            
194
100
            let bdd = from_iter(&manager_ref, &variables, set.iter()).unwrap();
195

            
196
            // Check that it does not yield duplicates.
197
100
            let mut seen = HashSet::new();
198
583
            for cube in CubeIter::new(&bdd) {
199
583
                println!("Cube: {}", FormatConfig(&cube));
200
583
                assert!(
201
583
                    seen.insert(cube.clone()),
202
                    "Duplicate cube found: {}",
203
                    FormatConfig(&cube)
204
                );
205
            }
206
100
        })
207
1
    }
208
}