1
use oxidd::Edge;
2
use oxidd::HasLevel;
3
use oxidd::InnerNode;
4
use oxidd::Manager;
5
use oxidd::ManagerRef;
6
use oxidd::bdd::BDDManagerRef;
7
use oxidd::util::Borrowed;
8
use oxidd::util::OutOfMemory;
9
use oxidd_core::function::EdgeOfFunc;
10
use oxidd::bdd::BDDFunction;
11
use oxidd::BooleanFunction;
12
use oxidd::Function;
13
use oxidd::util::OptBool;
14
use oxidd::VarNo;
15

            
16
use merc_ldd::DataRef;
17
use merc_ldd::height;
18
use merc_ldd::Ldd;
19
use merc_ldd::LddRef;
20
use merc_ldd::Storage;
21
use merc_ldd::union;
22
use merc_ldd::Value;
23
use oxidd_rules_bdd::simple::BDDTerminal;
24

            
25
/// Converts an LDD representing a set of vectors into a BDD representing the
26
/// same set by bitblasting the vector elements using the given variables as
27
/// bits.
28
///
29
/// # Details
30
///
31
/// The `bits_per_layer` should be a singleton LDD containing the result of
32
/// [compute_bits]. The conversion works recursively by processing the LDD node
33
/// by node, and introducing bit number of BDD variables (given by
34
/// `bit_variables`) for each layer in the LDD. These variables *must* already
35
/// exist in the given BDD manager.
36
520304
pub fn ldd_to_bdd<'id>(
37
520304
    storage: &mut Storage,
38
520304
    manager: &<BDDFunction as Function>::Manager<'id>,
39
520304
    ldd: &LddRef<'_>,
40
520304
    bits_per_layer: &LddRef<'_>,
41
520304
    bit_variables: &[VarNo],
42
520304
) -> Result<BDDFunction, OutOfMemory> {
43

            
44
    // Base cases
45
520304
    if **storage.empty_set() == *ldd {
46
226600
        return Ok(BDDFunction::f(manager));
47
293704
    }
48
293704
    if **storage.empty_vector() == *ldd {
49
34308
        return Ok(BDDFunction::t(manager));
50
259396
    }
51

            
52
    // TODO: Implement caching
53

            
54
259396
    let DataRef(value, down, right) = storage.get_ref(ldd);
55
259396
    let DataRef(bits_value, bits_down, _bits_right) = storage.get_ref(bits_per_layer);
56

            
57
    // Right branch does not consume variables at this layer
58
259396
    let right_bdd = ldd_to_bdd(storage, manager, &right, bits_per_layer, bit_variables)?;
59

            
60
    // Ensure we have enough variables for this layer
61
259396
    let needed = bits_value as usize;
62
259396
    if bit_variables.len() < needed {
63
        panic!("Insufficient variables: need {needed}, have {} for current layer", bit_variables.len());
64
259396
    }
65

            
66
    // Recurse on down with the remaining variables after consuming this layer
67
259396
    let mut down_bdd = ldd_to_bdd(storage, manager, &down, &bits_down, &bit_variables[needed..])?;
68

            
69
    // Encode current value using the variables for this layer (MSB to LSB)
70
    // Current layer variables: vars[0..bits_value]
71
777348
    for i in 0..bits_value {
72
777348
        let bit = bits_value - i - 1; // MSB first
73
777348
        let var_no = bit_variables[bit as usize];
74
777348
        if value & (1 << i) != 0 {
75
            // bit is 1
76
258564
            down_bdd = BDDFunction::var(manager, var_no)?.ite(&down_bdd, &BDDFunction::f(manager))?;
77
        } else {
78
            // bit is 0
79
518784
            down_bdd = BDDFunction::var(manager, var_no)?.ite(&BDDFunction::f(manager), &down_bdd)?;
80
        }
81
    }
82

            
83
259396
    down_bdd.or(&right_bdd)
84
520304
}
85

            
86
/// Converts a BDD representing a set of bitblasted vectors back into an LDD
87
/// representing the same set, i.e., the inverse of [ldd_to_bdd].
88
100
pub fn bdd_to_ldd(
89
100
    storage: &mut Storage,
90
100
    manager_ref: &BDDManagerRef,
91
100
    bdd: &BDDFunction,
92
100
    variables: &[VarNo],
93
100
    bits_per_layer: &[Value],
94
100
    current_bit: Value,
95
100
    current_value: Value,
96
100
) -> Result<Ldd, OutOfMemory> {
97
100
    manager_ref.with_manager_shared(|manager| {
98
100
        let edge = bdd.as_edge(manager);
99
100
        bdd_to_ldd_edge(storage, manager, edge.borrowed(), variables, bits_per_layer, current_bit, current_value)
100
100
    })
101
100
}
102

            
103
/// Recursive implementation of [bdd_to_ldd].
104
27008
pub fn bdd_to_ldd_edge<'id>(
105
27008
    storage: &mut Storage,
106
27008
    manager: &<BDDFunction as Function>::Manager<'id>,
107
27008
    bdd: Borrowed<EdgeOfFunc<'id, BDDFunction>>,
108
27008
    variables: &[VarNo],
109
27008
    bits_per_layer: &[Value],
110
27008
    current_bit: Value,
111
27008
    current_value: Value,
112
27008
) -> Result<Ldd, OutOfMemory> {
113
27008
    let bdd_node = match manager.get_node(&bdd) {
114
14246
        oxidd::Node::Inner(node) => node,
115
12762
        oxidd::Node::Terminal(terminal) => {
116
            // Base cases
117
12762
            match terminal {
118
                BDDTerminal::False => {
119
8066
                    return Ok(storage.empty_set().clone());
120
                }
121
                BDDTerminal::True => {
122
4696
                    if !variables.is_empty() {
123
                        // If there are still variables left, we must generate don't cares for the remaining layers
124
552
                        let num_bits = bits_per_layer.first().copied().expect("Missing bits per layer for current layer");
125

            
126
                        // There are don't care variables in this BDD that have been skipped, so generate both branches.
127
552
                        if num_bits == current_bit {
128
                            // We reached the last bit for this layer, variable still belongs to next layer.
129
                            let down = bdd_to_ldd_edge(storage, manager, bdd, variables, &bits_per_layer[1..], 0, 0)?;
130
                            let right = storage.empty_set().clone();
131
                            return Ok(storage.insert(current_value, &down, &right))
132
                        } else {  
133
552
                            debug_assert!(current_bit < num_bits, "Current bit exceeds number of bits for layer");        
134
552
                            let high = bdd_to_ldd_edge(storage, manager, bdd.borrowed(), &variables[1..], bits_per_layer, current_bit + 1, current_value | (1 << (num_bits - current_bit - 1)))?;
135
552
                            let low = bdd_to_ldd_edge(storage, manager, bdd, &variables[1..], bits_per_layer, current_bit + 1, current_value)?;
136
552
                            return Ok(union(storage, &high, &low));
137
                        }
138
4144
                    }
139

            
140
4144
                    return Ok(storage.insert_singleton(current_value));
141
                }
142
            }
143
        },
144
    };
145

            
146
    // TODO: Implement caching
147

            
148
    // Read the bits required per layer
149
14246
    let num_bits = bits_per_layer.first().copied().expect("Missing bits per layer for current layer");
150

            
151
14246
    let variable_level = variables.first().expect("Missing variable for current layer");
152
14246
    if *variable_level < bdd_node.level() { 
153
        // There are don't care variables in this BDD that have been skipped, so generate both branches without cofactors.
154
445
        if num_bits == current_bit {
155
            // We reached the last bit for this layer, variable still belongs to next layer.
156
70
            let down = bdd_to_ldd_edge(storage, manager, bdd, variables, &bits_per_layer[1..], 0, 0)?;
157
70
            let right = storage.empty_set().clone();
158
70
            return Ok(storage.insert(current_value, &down, &right))
159
        } else {    
160
375
            debug_assert!(current_bit < num_bits, "Current bit exceeds number of bits for layer");
161
375
            let high = bdd_to_ldd_edge(storage, manager, bdd.borrowed(), &variables[1..], bits_per_layer, current_bit + 1, current_value | (1 << (num_bits - current_bit - 1)))?;
162
375
            let low = bdd_to_ldd_edge(storage, manager, bdd, &variables[1..], bits_per_layer, current_bit + 1, current_value)?;
163
375
            return Ok(union(storage, &high, &low));
164
        }
165
13801
    }
166

            
167
13801
    debug_assert_eq!(*variable_level, bdd_node.level(), "Levels do not match");
168
13801
    if num_bits == current_bit {
169
        // We reached the last bit for this layer
170
2618
        let down = bdd_to_ldd_edge(storage, manager, bdd, variables, &bits_per_layer[1..], 0, 0)?;
171
2618
        let right = storage.empty_set().clone();
172
2618
        Ok(storage.insert(current_value, &down, &right))
173
    } else {
174
11183
        debug_assert!(current_bit < num_bits, "Current bit exceeds number of bits for layer");  
175
11183
        let (bdd_high, bdd_low) = collect_children(bdd_node);
176

            
177
        // Recurse for high and low cofactors
178
11183
        let high = bdd_to_ldd_edge(
179
11183
            storage,
180
11183
            manager,
181
11183
            bdd_high,
182
11183
            &variables[1..],
183
11183
            bits_per_layer,
184
11183
            current_bit + 1,
185
11183
            current_value | (1 << (num_bits - current_bit - 1)),
186
        )?;
187
11183
        let low = bdd_to_ldd_edge(storage, manager, bdd_low, &variables[1..], bits_per_layer, current_bit + 1, current_value)?;
188

            
189
11183
        Ok(union(storage, &high, &low))
190
    }
191
27008
}
192

            
193
/// Computes the highest value for every layer in the LDD
194
1411
pub fn compute_highest(storage: &mut Storage, ldd: &LddRef<'_>) -> Vec<u32> {
195
1411
    let mut result = vec![0; height(storage, ldd)];
196
1411
    compute_highest_rec(storage, &mut result, ldd, 0);
197
1411
    result
198
1411
}
199

            
200
/// Collect the two children of a binary node
201
#[inline]
202
#[must_use]
203
11183
fn collect_children<E: Edge, N: InnerNode<E>>(node: &N) -> (Borrowed<'_, E>, Borrowed<'_, E>) {
204
11183
    debug_assert_eq!(N::ARITY, 2);
205
11183
    let mut it = node.children();
206
11183
    let f_then = it.next().unwrap();
207
11183
    let f_else = it.next().unwrap();
208
11183
    debug_assert!(it.next().is_none());
209
11183
    (f_then, f_else)
210
11183
}
211

            
212
/// Iterator that yields values reconstructed from a bit cube, from a BDD obtained by
213
/// [ldd_to_bdd].
214
pub struct ValuesIter<'a> {
215
    bits: &'a [OptBool],
216
    num_of_bits: &'a [u32],
217
    offset: usize,
218
    index: usize,
219
}
220

            
221
impl<'a> ValuesIter<'a> {
222
    pub fn new(bits: &'a [OptBool], num_of_bits: &'a [u32]) -> Self {
223
        Self {
224
            bits,
225
            num_of_bits,
226
            offset: 0,
227
            index: 0,
228
        }
229
    }
230
}
231

            
232
impl<'a> Iterator for ValuesIter<'a> {
233
    type Item = u64;
234

            
235
    fn next(&mut self) -> Option<Self::Item> {
236
        if self.index >= self.num_of_bits.len() {
237
            return None;
238
        }
239

            
240
        let nb = self.num_of_bits[self.index] as usize;
241
        if self.offset + nb > self.bits.len() {
242
            // Malformed input; stop iterating.
243
            return None;
244
        }
245

            
246
        let value = to_value(&self.bits[self.offset..self.offset + nb]);
247
        self.offset += nb;
248
        self.index += 1;
249
        Some(value)
250
    }
251

            
252
    fn size_hint(&self) -> (usize, Option<usize>) {
253
        let remaining = self.num_of_bits.len().saturating_sub(self.index);
254
        (remaining, Some(remaining))
255
    }
256
}
257

            
258
impl<'a> ExactSizeIterator for ValuesIter<'a> {}
259

            
260
/// Reconstruct the value represented by the bits as encoded by
261
/// [crate::ldd_to_bdd]. So most significant bit first.
262
pub fn to_value(bits: &[OptBool]) -> u64 {
263
    let mut value = 0u64;
264
    for (i, bit) in bits.iter().rev().enumerate() {
265
        if *bit == OptBool::True {
266
            value |= 1 << i;
267
        }
268
    }
269

            
270
    value
271
}
272

            
273
/// Helper function for compute_highest
274
518329
fn compute_highest_rec(storage: &mut Storage, result: &mut [u32], set: &LddRef<'_>, depth: usize) {
275
518329
    if set == storage.empty_set() || set == storage.empty_vector() {
276
259870
        return;
277
258459
    }
278

            
279
258459
    let DataRef(value, down, right) = storage.get_ref(set);
280
258459
    compute_highest_rec(storage, result, &right, depth);
281
258459
    compute_highest_rec(storage, result, &down, depth + 1);
282

            
283
258459
    result[depth] = result[depth].max(value);
284
518329
}
285

            
286
/// Calculate minimum bits needed to represent the value
287
/// Use 1 bit if value is 0 to ensure at least 1 bit is written
288
3112
pub fn required_bits(value: u32) -> u32 {
289
3112
    (u32::BITS - value.leading_zeros()).max(1)
290
3112
}
291

            
292
/// Calculate minimum bits needed to represent the value
293
1383
pub fn required_bits_64(value: u64) -> u32 {
294
1383
    (u64::BITS - value.leading_zeros()).max(1)
295
1383
}
296

            
297
/// Computes the number of bits required to represent the highest value at each layer.
298
401
pub fn compute_bits(highest: &[u32]) -> Vec<u32> {
299
2611
    highest.iter().map(|&h| required_bits(h)).collect()
300
401
}
301

            
302
#[cfg(test)]
303
mod tests {
304
    use merc_ldd::LddDisplay;
305
    use merc_ldd::from_iter;
306
    use merc_ldd::random_vector_set;
307
    use merc_ldd::singleton;
308
    use merc_utilities::random_test;
309
    use oxidd::Manager;
310
    use oxidd::ManagerRef;
311

            
312
    use crate::FormatConfigSet;
313

            
314
    use super::*;
315

            
316
    #[test]
317
1
    fn test_random_compute_highest() {
318
100
        random_test(100, |rng| {
319
100
            let set = random_vector_set(rng, 4, 3, 5);
320
100
            let mut storage = Storage::new();
321
100
            let ldd = from_iter(&mut storage, set.iter());
322
100
            println!("LDD: {}", LddDisplay::new(&storage, &ldd));
323

            
324
100
            let highest = compute_highest(&mut storage, &ldd);
325
100
            println!("Highest: {:?}", highest);
326
300
            for (i, h) in highest.iter().enumerate() {
327
                // Determine the highest value for every vector
328
1194
                for value in set.iter() {
329
1194
                    assert!(
330
1194
                        *h >= value[i],
331
                        "The highest value for depth {} is {}, but vector has value {}",
332
                        i,
333
                        h,
334
                        value[i]
335
                    );
336
                }
337
            }
338

            
339
100
            let bits = compute_bits(&highest);
340
100
            println!("Bits: {:?}", bits);
341

            
342
300
            for (i, b) in bits.iter().enumerate() {
343
300
                let expected_bits = required_bits(highest[i]);
344
300
                assert_eq!(
345
                    *b, expected_bits,
346
                    "The number of bits for depth {} is {}, but expected {}",
347
                    i, b, expected_bits
348
                );
349
            }
350
100
        })
351
1
    }
352

            
353
    #[test]
354
    #[cfg_attr(miri, ignore)] // Oxidd does not work with miri
355
1
    fn test_random_ldd_to_bdd() {
356
100
        random_test(100, |rng| {
357
100
            let set = random_vector_set(rng, 50, 3, 5);
358

            
359
100
            let mut storage = Storage::new();
360
100
            let ldd = from_iter(&mut storage, set.iter());
361
100
            println!("LDD: {}", LddDisplay::new(&storage, &ldd));
362

            
363
100
            let highest = compute_highest(&mut storage, &ldd);
364
100
            let bits = compute_bits(&highest);
365
100
            let bits_dd = singleton(&mut storage, &bits);
366

            
367
100
            let manager_ref = oxidd::bdd::new_manager(2048, 1024, 1);
368

            
369
100
            let total_bits: u32 = bits.iter().sum();
370
100
            println!("Total bits: {}", total_bits);
371
100
            println!("Bits per layer: {:?}", bits);
372
100
            let vars = manager_ref.with_manager_exclusive(|manager| manager.add_vars(total_bits).collect::<Vec<_>>());
373
100
            let bdd =  manager_ref.with_manager_shared(|manager| ldd_to_bdd(&mut storage, manager, &ldd, &bits_dd, &vars).unwrap() );
374
100
            println!("resulting BDD: {}", FormatConfigSet(&bdd));
375
100
            let resulting_ldd = bdd_to_ldd(&mut storage, &manager_ref, &bdd, &vars, &bits, 0, 0).unwrap();
376

            
377
100
            println!("resulting LDD: {}", LddDisplay::new(&storage, &resulting_ldd));
378
100
            assert_eq!(ldd, resulting_ldd, "Converted LDD does not match original");
379
100
        });
380
1
    }
381
}