1
use oxidd::BooleanFunction;
2
use oxidd::ManagerRef;
3
use oxidd::bdd::BDDFunction;
4
use oxidd::bdd::BDDManagerRef;
5
use oxidd::util::OptBool;
6
use oxidd::util::OutOfMemory;
7
use rand::Rng;
8
use rand::RngExt;
9

            
10
/// Generate `num_vectors` random bitvectors of length `num_vars`.
11
8292
pub fn random_bitvectors<R: Rng>(rng: &mut R, num_vars: usize, num_vectors: usize) -> Vec<Vec<OptBool>> {
12
8292
    let mut vectors = Vec::new();
13
    // random_range panics on an empty range, so a request for zero vectors yields nothing.
14
8292
    let count = if num_vectors == 0 {
15
        0
16
    } else {
17
8292
        rng.random_range(0..num_vectors)
18
    };
19
8292
    for _ in 0..count {
20
38575
        let mut vec = Vec::new();
21
38575
        for _ in 0..num_vars {
22
119754
            vec.push(if rng.random_bool(0.5) {
23
60103
                OptBool::True
24
            } else {
25
59651
                OptBool::False
26
            });
27
        }
28
38575
        vectors.push(vec);
29
    }
30
8292
    vectors
31
8292
}
32

            
33
/// Constructs a BDD representing the given cube (bitvector) over the given variables.
34
111417
pub fn bdd_from_cube(
35
111417
    manager_ref: &BDDManagerRef,
36
111417
    variables: &[BDDFunction],
37
111417
    cube: &[OptBool],
38
111417
) -> Result<BDDFunction, OutOfMemory> {
39
111417
    assert_eq!(
40
111417
        variables.len(),
41
111417
        cube.len(),
42
        "variables and cube must have the same length"
43
    );
44
111417
    let mut bdd = manager_ref.with_manager_shared(|manager| BDDFunction::t(manager));
45
338280
    for (i, bit) in cube.iter().enumerate() {
46
338280
        let var = variables[i].clone();
47
338280
        let literal = match *bit {
48
169833
            OptBool::True => var,
49
168447
            OptBool::False => var.not()?,
50
            OptBool::None => continue,
51
        };
52
338280
        bdd = bdd.and(&literal)?;
53
    }
54
111417
    Ok(bdd)
55
111417
}
56

            
57
/// Create a BDD from the given iterator over bitvector.
58
8292
pub fn bdd_from_iter<'a, I>(
59
8292
    manager_ref: &BDDManagerRef,
60
8292
    variables: &[BDDFunction],
61
8292
    vectors: I,
62
8292
) -> Result<BDDFunction, OutOfMemory>
63
8292
where
64
8292
    I: Iterator<Item = &'a Vec<OptBool>>,
65
{
66
8292
    let mut bdd = manager_ref.with_manager_shared(|manager| BDDFunction::f(manager));
67
38575
    for bits in vectors {
68
38575
        bdd = bdd.or(&bdd_from_cube(manager_ref, variables, bits)?)?;
69
    }
70

            
71
8292
    Ok(bdd)
72
8292
}
73

            
74
/// Create a random BDD over the given variables with the given number of cubes.
75
8092
pub fn random_bdd<R: Rng>(
76
8092
    manager_ref: &BDDManagerRef,
77
8092
    rng: &mut R,
78
8092
    variables: &[BDDFunction],
79
8092
    num_of_cubes: usize,
80
8092
) -> Result<BDDFunction, OutOfMemory> {
81
8092
    let bitvectors = random_bitvectors(rng, variables.len(), num_of_cubes);
82
8092
    bdd_from_iter(manager_ref, variables, bitvectors.iter())
83
8092
}