1
use std::collections::HashMap;
2
use std::error::Error;
3
use std::fs::File;
4
use std::io::Read;
5

            
6
use crate::Ldd;
7
use crate::Storage;
8
use crate::Value;
9
use crate::compute_meta;
10

            
11
pub struct Transition {
12
    pub relation: Ldd,
13
    pub meta: Ldd,
14
}
15

            
16
/// Returns the (initial state, transitions) read from the file in Sylvan's format.
17
2
pub fn load_model(storage: &mut Storage, filename: &str) -> Result<(Ldd, Vec<Transition>), Box<dyn Error>> {
18
2
    let mut file = File::open(filename)?;
19
2
    let mut reader = SylvanReader::new();
20

            
21
2
    let _vector_length = read_u32(&mut file)?;
22
    //println!("Length of vector {}", vector_length);
23

            
24
2
    let _unused = read_u32(&mut file)?; // This is called 'k' in Sylvan's ldd2bdd.c, but unused.
25
2
    let initial_state = reader.read_ldd(storage, &mut file)?;
26

            
27
2
    let num_transitions: usize = read_u32(&mut file)? as usize;
28
2
    let mut transitions: Vec<Transition> = Vec::new();
29

            
30
    // Read all the transition groups.
31
2
    for _ in 0..num_transitions {
32
77
        let (read_proj, write_proj) = read_projection(&mut file)?;
33
77
        transitions.push(Transition {
34
77
            relation: storage.empty_set().clone(),
35
77
            meta: compute_meta(storage, &read_proj, &write_proj),
36
77
        });
37
    }
38

            
39
77
    for transition in transitions.iter_mut().take(num_transitions) {
40
77
        transition.relation = reader.read_ldd(storage, &mut file)?;
41
    }
42

            
43
    // Ignore the rest for now.
44
2
    Ok((initial_state, transitions))
45
2
}
46

            
47
struct SylvanReader {
48
    indexed_set: HashMap<u64, Ldd>, // Assigns LDDs to every index.
49
    last_index: u64,                // The index of the last LDD read from file.
50
}
51

            
52
impl SylvanReader {
53
2
    fn new() -> Self {
54
2
        Self {
55
2
            indexed_set: HashMap::new(),
56
2
            last_index: 2,
57
2
        }
58
2
    }
59

            
60
    /// Returns an LDD read from the given file in the Sylvan format.
61
79
    fn read_ldd(&mut self, storage: &mut Storage, file: &mut File) -> Result<Ldd, Box<dyn Error>> {
62
79
        let count = read_u64(file)?;
63
        //println!("node count = {}", count);
64

            
65
79
        for _ in 0..count {
66
            // Read a single MDD node. It has the following structure: u64 | u64
67
            // RmRR RRRR RRRR VVVV | VVVV DcDD DDDD DDDD (little endian)
68
            // Every character is 4 bits, V = value, D = down, R = right, m = marked, c = copy.
69
564
            let a = read_u64(file)?;
70
564
            let b = read_u64(file)?;
71
            //println!("{:064b} | {:064b}", a, b);
72

            
73
564
            let right = (a & 0x0000ffffffffffff) >> 1;
74
564
            let down = b >> 17;
75

            
76
564
            let mut bytes: [u8; 4] = Default::default();
77
564
            bytes[0..2].copy_from_slice(&a.to_le_bytes()[6..8]);
78
564
            bytes[2..4].copy_from_slice(&b.to_le_bytes()[0..2]);
79
564
            let value = u32::from_le_bytes(bytes);
80

            
81
564
            let copy = right & 0x10000;
82
564
            if copy != 0 {
83
                panic!("We do not yet deal with copy nodes.");
84
564
            }
85

            
86
564
            let down = self.node_from_index(storage, down);
87
564
            let right = self.node_from_index(storage, right);
88

            
89
564
            let ldd = storage.insert(value as Value, &down, &right);
90
564
            self.indexed_set.insert(self.last_index, ldd);
91

            
92
564
            self.last_index += 1;
93
        }
94

            
95
79
        let result = read_u64(file)?;
96
79
        Ok(self.node_from_index(storage, result))
97
79
    }
98

            
99
    /// Returns the LDD belonging to the given index.
100
1207
    fn node_from_index(&self, storage: &mut Storage, index: u64) -> Ldd {
101
1207
        if index == 0 {
102
445
            storage.empty_set().clone()
103
762
        } else if index == 1 {
104
2
            storage.empty_vector().clone()
105
        } else {
106
760
            self.indexed_set.get(&index).unwrap().clone()
107
        }
108
1207
    }
109
}
110

            
111
/// Returns a single u32 read from the file.
112
575
fn read_u32(file: &mut File) -> Result<u32, Box<dyn Error>> {
113
575
    let mut buffer: [u8; 4] = Default::default();
114
575
    file.read_exact(&mut buffer)?;
115

            
116
575
    Ok(u32::from_le_bytes(buffer))
117
575
}
118

            
119
/// Returns a single u64 read from the file.
120
1286
fn read_u64(file: &mut File) -> Result<u64, Box<dyn Error>> {
121
1286
    let mut buffer: [u8; 8] = Default::default();
122
1286
    file.read_exact(&mut buffer)?;
123

            
124
1286
    Ok(u64::from_le_bytes(buffer))
125
1286
}
126

            
127
/// Reads the read and write projections from the file.
128
77
fn read_projection(file: &mut File) -> Result<(Vec<Value>, Vec<Value>), Box<dyn Error>> {
129
77
    let num_read = read_u32(file)?;
130
77
    let num_write = read_u32(file)?;
131

            
132
    // Read num_read integers for the read parameters.
133
77
    let mut read_proj: Vec<Value> = Vec::new();
134
77
    for _ in 0..num_read {
135
217
        let value = read_u32(file)?;
136
217
        read_proj.push(value as Value);
137
    }
138

            
139
    // Read num_write integers for the write parameters.
140
77
    let mut write_proj: Vec<Value> = Vec::new();
141
77
    for _ in 0..num_write {
142
198
        let value = read_u32(file)?;
143
198
        write_proj.push(value as Value);
144
    }
145

            
146
77
    Ok((read_proj, write_proj))
147
77
}
148

            
149
#[cfg(test)]
150
mod test {
151
    use super::*;
152

            
153
    #[test]
154
1
    fn test_load_anderson_4() {
155
1
        let mut storage = Storage::new();
156
1
        let (_, _) = load_model(&mut storage, "../../examples/ldd/anderson.4.ldd").expect("Loading should work correctly");
157
1
    }
158

            
159
    #[test]
160
1
    fn test_load_collision_4() {
161
1
        let mut storage = Storage::new();
162
1
        let (_, _) = load_model(&mut storage, "../../examples/ldd/collision.4.ldd").expect("Loading should work correctly");
163
1
    }
164
}