boolean_circuit/file_formats/
aiger.rs

1use std::{
2    cmp::{max, min},
3    collections::{HashMap, HashSet},
4    io::{BufRead, BufReader, Read, Write},
5};
6
7use itertools::Itertools;
8
9use crate::{Node, Operation};
10
11/// Translates the output node (and the circuit it references) to (text) AIGER
12/// format and writes it to the given writer.
13pub fn to_aiger(f: impl Write, output: &Node) -> Result<(), String> {
14    AigerWriter::new(output, false).process(f)
15}
16
17/// Translates the output node (and the circuit it references) to binary AIGER
18/// format and writes it to the given writer.
19pub fn to_aiger_binary(f: impl Write, output: &Node) -> Result<(), String> {
20    AigerWriter::new(output, true).process(f)
21}
22
23/// Reads an AIGER file (in binary or text format) and returns the output node.
24///
25/// Does not support latches or more than one output node.
26pub fn from_aiger(f: impl Read) -> Result<Node, String> {
27    let mut input = BufReader::new(f);
28    let AigerHeader {
29        is_binary,
30        input_count,
31        and_count,
32    } = parse_header(&mut input)?;
33    let input_literals = parse_input_literals(input_count, is_binary, &mut input)?;
34    let output_literal = parse_output_literal(&mut input)?;
35    let and_gates = parse_and_gates(input_count, and_count, is_binary, &mut input)?;
36    let gates = build_named_inputs(input_literals, &mut input)?;
37
38    CircuitBuilder { gates, and_gates }.build_node(output_literal)
39}
40
41/// Returns true if the output of the AIG translation of the node is inverted.
42fn has_inverted_output(n: &Node) -> bool {
43    match n.operation() {
44        Operation::Variable(_) => false,
45        Operation::Constant(v) => *v,
46        Operation::Conjunction(_, _) => false,
47        Operation::Disjunction(_, _) => true,
48        Operation::Xor(_, _) => true,
49        Operation::Negation(_) => true,
50    }
51}
52
53/// Returns the number of AND gates required to translate this gate.
54fn and_gates_needed(n: &Node) -> usize {
55    match n.operation() {
56        Operation::Variable(_) | Operation::Constant(_) | Operation::Negation(_) => 0,
57        Operation::Conjunction(..) | Operation::Disjunction(..) => 1,
58        Operation::Xor(..) => 3,
59    }
60}
61
62fn invert(literal: u32) -> u32 {
63    literal ^ 1
64}
65
66fn aiger_encode_number(f: &mut impl Write, mut n: u32) -> Result<(), std::io::Error> {
67    while n >= 0x80 {
68        f.write_all(&[(n & 0x7f | 0x80) as u8])?;
69        n >>= 7;
70    }
71    f.write_all(&[n as u8])
72}
73
74struct AigerWriter<'a> {
75    binary_format: bool,
76    output: &'a Node,
77    node_id_to_literal: HashMap<usize, u32>,
78    input_name_to_literal: HashMap<&'a str, u32>,
79    var_count: usize,
80}
81
82impl<'a> AigerWriter<'a> {
83    pub fn new(output: &'a Node, binary_format: bool) -> Self {
84        // Create a node-to-literal mapping that already incorporates if the
85        // output is inverted or not.
86        // Start with inputs since this is a requirement for binary encoding.
87        let var_name_to_literal: HashMap<_, _> = output
88            .iter()
89            .filter_map(|n| {
90                if let Operation::Variable(name) = n.operation() {
91                    Some(name.as_str())
92                } else {
93                    None
94                }
95            })
96            .unique()
97            .enumerate()
98            .map(|(i, name)| {
99                let literal = 2 * (i + 1) as u32;
100                (name, literal)
101            })
102            .collect();
103        // We skip constants and not-gates, since they do not need variables.
104        // Post-order traversal is important since the predecessor nodes have to
105        // have smaller IDs.
106        let (node_id_to_literal, var_count) = output
107            .post_visit_iter()
108            .filter(|n| {
109                !matches!(
110                    n.operation(),
111                    Operation::Constant(_) | Operation::Negation(_) | Operation::Variable(_)
112                )
113            })
114            .fold(
115                (HashMap::new(), var_name_to_literal.len()),
116                |(mut map, var_count), node| {
117                    let gates_needed = and_gates_needed(node);
118                    assert!(gates_needed > 0);
119                    let var_id = var_count + gates_needed;
120                    let literal = 2 * var_id as u32 + if has_inverted_output(node) { 1 } else { 0 };
121                    map.insert(node.id(), literal);
122                    (map, var_id)
123                },
124            );
125        Self {
126            binary_format,
127            output,
128            node_id_to_literal,
129            input_name_to_literal: var_name_to_literal,
130            var_count,
131        }
132    }
133
134    pub fn process(mut self, mut f: impl Write) -> Result<(), String> {
135        let and_gates = self.compute_and_gates();
136        self.write_out(&mut f, and_gates).map_err(|e| e.to_string())
137    }
138
139    fn compute_and_gates(&mut self) -> Vec<(u32, u32, u32)> {
140        let mut and_gates = vec![];
141        for n in self.output.post_visit_iter() {
142            let gate_var = self.literal(n);
143            match n.operation() {
144                Operation::Variable(_) | Operation::Constant(_) | Operation::Negation(_) => {}
145                Operation::Conjunction(left, right) => {
146                    let left = self.literal_ref(left);
147                    let right = self.literal_ref(right);
148                    and_gates.push((gate_var, left, right));
149                }
150                Operation::Disjunction(left, right) => {
151                    let left = self.literal_ref(left);
152                    let right = self.literal_ref(right);
153                    and_gates.push((gate_var, invert(left), invert(right)));
154                }
155                Operation::Xor(left, right) => {
156                    let left = self.literal_ref(left);
157                    let right = self.literal_ref(right);
158                    let a = gate_var - 4;
159                    and_gates.push((a, left, invert(right)));
160                    let b = gate_var - 2;
161                    and_gates.push((b, invert(left), right));
162                    and_gates.push((gate_var, invert(a), invert(b)));
163                }
164            }
165        }
166        and_gates
167    }
168
169    fn write_out(
170        self,
171        f: &mut impl Write,
172        and_gates: Vec<(u32, u32, u32)>,
173    ) -> Result<(), std::io::Error> {
174        // Header
175        writeln!(
176            f,
177            "a{}g {} {} 0 1 {}",
178            if self.binary_format { "i" } else { "a" },
179            self.var_count,
180            self.input_name_to_literal.len(),
181            and_gates.len()
182        )?;
183        if !self.binary_format {
184            // Inputs
185            for var in self.input_name_to_literal.values().sorted() {
186                writeln!(f, "{var}")?;
187            }
188        }
189        // Output
190        writeln!(f, "{}", self.literal_ref(self.output))?;
191        // And gates
192        for (out, left, right) in and_gates {
193            self.write_gate(f, (out, left, right))?;
194        }
195        // Symbol table
196        for (i, (name, _)) in self
197            .input_name_to_literal
198            .iter()
199            .sorted_by_key(|(_, v)| *v)
200            .enumerate()
201        {
202            writeln!(f, "i{i} {name}")?;
203        }
204
205        Ok(())
206    }
207
208    fn write_gate(&self, f: &mut impl Write, gate: (u32, u32, u32)) -> Result<(), std::io::Error> {
209        let (gate_var, left, right) = gate;
210        let (left, right) = (max(left, right), min(left, right));
211        if self.binary_format {
212            aiger_encode_number(f, gate_var - left)?;
213            aiger_encode_number(f, left - right)
214        } else {
215            writeln!(f, "{gate_var} {left} {right}")
216        }
217    }
218
219    /// Returns the literal when referencing the node, i.e. including the inversion.
220    fn literal_ref(&self, node: &Node) -> u32 {
221        match node.operation() {
222            Operation::Constant(v) => *v as u32,
223            Operation::Variable(name) => self.input_name_to_literal[name.as_str()],
224            Operation::Negation(inner) => invert(self.literal_ref(inner)),
225            _ => self.node_id_to_literal[&node.id()],
226        }
227    }
228
229    /// Returns the literal when identifying the node in the definition,
230    /// i.e. excluding the inversion.
231    fn literal(&self, node: &Node) -> u32 {
232        self.literal_ref(node) & !1
233    }
234}
235
236struct AigerHeader {
237    is_binary: bool,
238    input_count: usize,
239    and_count: usize,
240}
241
242fn parse_header(input: &mut impl BufRead) -> Result<AigerHeader, String> {
243    let header = read_line(input)?;
244    let (is_binary, header) = if let Some(header) = header.strip_prefix("aag ") {
245        (false, header)
246    } else if let Some(header) = header.strip_prefix("aig ") {
247        (true, header)
248    } else {
249        return Err("Invalid header".to_string());
250    };
251    let header_numbers = header
252        .split(' ')
253        .map(|n| {
254            n.parse::<usize>()
255                .map_err(|e| format!("Error reading number in header: {e}"))
256        })
257        .collect::<Result<Vec<_>, _>>()?;
258    let [_variable_count, input_count, latch_count, output_count, and_count] = header_numbers
259        .try_into()
260        .map_err(|_| "Invalid number of items in the header".to_string())?;
261
262    if latch_count != 0 {
263        return Err("Latches are not supported".to_string());
264    }
265    if output_count != 1 {
266        return Err("Only one output is supported".to_string());
267    }
268    Ok(AigerHeader {
269        is_binary,
270        input_count,
271        and_count,
272    })
273}
274
275fn parse_input_literals(
276    input_count: usize,
277    is_binary: bool,
278    f: &mut impl BufRead,
279) -> Result<Vec<u64>, String> {
280    Ok(if is_binary {
281        (0..input_count).map(|i| 2 * (i as u64 + 1)).collect()
282    } else {
283        let literals = (0..input_count)
284            .map(|_| {
285                let line = read_line(f)?;
286                line.parse::<u64>().map_err(|e| e.to_string())
287            })
288            .collect::<Result<Vec<_>, _>>()?;
289        assert_eq!(literals.len(), input_count);
290        literals
291    })
292}
293
294fn parse_output_literal(f: &mut impl BufRead) -> Result<u64, String> {
295    read_line(f)?.parse::<u64>().map_err(|e| e.to_string())
296}
297
298/// Parses the gates into a hash map of output -> (left, right).
299fn parse_and_gates(
300    input_count: usize,
301    and_count: usize,
302    is_binary: bool,
303    f: &mut impl BufRead,
304) -> Result<HashMap<u64, (u64, u64)>, String> {
305    if is_binary {
306        (0..and_count)
307            .map(|i| {
308                let output_literal = 2 * (input_count + 1 + i) as u64;
309                let delta0 = aiger_decode_number(f)? as u64;
310                let delta1 = aiger_decode_number(f)? as u64;
311                let left = output_literal - delta0;
312                let right = left - delta1;
313                Ok((output_literal, (left, right)))
314            })
315            .collect()
316    } else {
317        // Lines of the form: (out, left, right)
318        (0..and_count)
319            .map(|_| {
320                let line = read_line(f)?;
321                let items = line
322                    .split(' ')
323                    .map(|n| {
324                        n.parse::<u64>()
325                            .map_err(|e| format!("Error parsing gate number: {e}"))
326                    })
327                    .collect::<Result<Vec<_>, _>>()?;
328                match items.as_slice() {
329                    [output, left, right] => {
330                        if output % 2 != 0 {
331                            Err(format!("Expected even literal for output: {output}"))
332                        } else {
333                            Ok((*output, (*left, *right)))
334                        }
335                    }
336                    _ => Err(format!(
337                        "Invalid number of gate items, expected 3 got {}",
338                        items.len()
339                    )),
340                }
341            })
342            .try_fold(HashMap::new(), |mut acc, res| {
343                let (output, (left, right)) = res?;
344                if acc.insert(output, (left, right)).is_none() {
345                    Ok(acc)
346                } else {
347                    Err(format!("Duplicate output gate ID: {output}"))
348                }
349            })
350    }
351}
352
353fn aiger_decode_number(f: &mut impl Read) -> Result<u32, String> {
354    let mut result: u32 = 0;
355    let mut buf = [0; 1];
356    for shift_amount in (0..).step_by(7) {
357        f.read_exact(&mut buf).map_err(|e| e.to_string())?;
358        let b = buf[0];
359        result |= ((b & 0x7f) as u32) << shift_amount;
360        if b & 0x80 == 0 {
361            break;
362        }
363    }
364    Ok(result)
365}
366
367fn build_named_inputs(
368    input_literals: Vec<u64>,
369    f: &mut impl BufRead,
370) -> Result<HashMap<u64, Node>, String> {
371    let mut used_input_names: HashSet<String> = Default::default();
372    let mut named_inputs = HashMap::default();
373    loop {
374        let Ok(line) = read_line(f) else {
375            break;
376        };
377        let Some(suffix) = line.strip_prefix("i") else {
378            break;
379        };
380        let parts = suffix.split(' ').collect_vec();
381        if parts.len() != 2 {
382            return Err(format!(
383                "Expected exactly two parts for input name, but got {suffix}"
384            ));
385        }
386        let index = parts[0]
387            .parse::<usize>()
388            .map_err(|e| format!("Expected input literal: {e}"))?;
389        if index >= input_literals.len() {
390            return Err(format!("Out of range for input literal name: {index}"));
391        }
392        let name = parts[1];
393        if !used_input_names.insert(name.to_string()) {
394            return Err(format!("Duplicate input name: {name}"));
395        }
396        named_inputs.insert(input_literals[index], Node::from(parts[1]));
397    }
398    let mut last_input_id = 0;
399    let anonymous_inputs = input_literals
400        .iter()
401        .filter(|lit| !named_inputs.contains_key(lit))
402        .map(|&lit| {
403            while used_input_names.contains(&format!("v_{last_input_id}")) {
404                last_input_id += 1;
405            }
406            (lit, Node::from(format!("v_{last_input_id}")))
407        })
408        .collect_vec();
409    named_inputs.extend(anonymous_inputs);
410    assert_eq!(named_inputs.len(), input_literals.len());
411    Ok(named_inputs)
412}
413
414struct CircuitBuilder {
415    gates: HashMap<u64, Node>,
416    and_gates: HashMap<u64, (u64, u64)>,
417}
418
419impl CircuitBuilder {
420    fn build_node(&mut self, literal: u64) -> Result<Node, String> {
421        if literal & 1 == 1 {
422            return Ok(!(self.build_node(literal & !1)?));
423        }
424        Ok(if let Some(n) = self.gates.get(&literal) {
425            n.clone()
426        } else {
427            let (left, right) = self
428                .and_gates
429                .get(&literal)
430                .cloned()
431                .ok_or_else(|| format!("Gate not found: {literal}"))?;
432            self.build_node(left)? & self.build_node(right)?
433        })
434    }
435}
436
437fn read_line(input: &mut impl BufRead) -> Result<String, String> {
438    let mut line = String::new();
439    match input.read_line(&mut line) {
440        Ok(0) => Err("Unexpected end of input".to_string()),
441        Ok(_n) => {
442            if line.ends_with('\n') {
443                line.pop();
444                if line.ends_with('\r') {
445                    line.pop();
446                }
447            }
448            Ok(line)
449        }
450        Err(e) => Err(e.to_string()),
451    }
452}
453
454#[cfg(test)]
455mod test {
456    use super::*;
457
458    fn test_aiger_out(node: Node, expected: &str) {
459        let mut buf = vec![];
460        to_aiger(&mut buf, &node).unwrap();
461        assert_eq!(String::from_utf8(buf).unwrap(), expected);
462    }
463
464    mod output {
465        use super::*;
466        use pretty_assertions::assert_eq;
467
468        #[test]
469        fn constant_true() {
470            let output = Node::from(true);
471            test_aiger_out(output, "aag 0 0 0 1 0\n1\n");
472        }
473
474        #[test]
475        fn constant_false() {
476            let output = Node::from(false);
477            test_aiger_out(output, "aag 0 0 0 1 0\n0\n");
478        }
479
480        #[test]
481        fn inverter() {
482            let output = !Node::from("x");
483            test_aiger_out(output, "aag 1 1 0 1 0\n2\n3\ni0 x\n");
484        }
485
486        #[test]
487        fn and_gate() {
488            let output = Node::from("x") & Node::from("y");
489            test_aiger_out(output, "aag 3 2 0 1 1\n2\n4\n6\n6 4 2\ni0 x\ni1 y\n");
490        }
491
492        #[test]
493        fn or_gate() {
494            let output = Node::from("x") | Node::from("y");
495            test_aiger_out(output, "aag 3 2 0 1 1\n2\n4\n7\n6 5 3\ni0 x\ni1 y\n");
496        }
497
498        #[test]
499        fn xor_gate() {
500            let output = Node::from("x") ^ Node::from("y");
501            test_aiger_out(
502                output,
503                "aag 5 2 0 1 3\n2\n4\n11\n6 5 2\n8 4 3\n10 9 7\ni0 x\ni1 y\n",
504            );
505        }
506
507        #[test]
508        fn var_repetition() {
509            // Tests repetition of the same variable name but in different nodes.
510            let output = Node::from("x") & Node::from("x");
511            test_aiger_out(output, "aag 2 1 0 1 1\n2\n4\n4 2 2\ni0 x\n");
512        }
513
514        #[test]
515        fn multi_stage() {
516            let a = Node::from("x") & Node::from("y");
517            let output = &a | &!&a;
518            test_aiger_out(output, "aag 4 2 0 1 2\n2\n4\n9\n6 4 2\n8 7 6\ni0 x\ni1 y\n");
519        }
520
521        #[test]
522        fn encode_number() {
523            let mut buf = vec![];
524            aiger_encode_number(&mut buf, 0x7f).unwrap();
525            assert_eq!(buf, vec![0x7f]);
526            buf.clear();
527            aiger_encode_number(&mut buf, 0x80).unwrap();
528            assert_eq!(buf, vec![0x80, 0x01]);
529            buf.clear();
530            aiger_encode_number(&mut buf, 0x81).unwrap();
531            assert_eq!(buf, vec![0x81, 0x01]);
532            buf.clear();
533            aiger_encode_number(&mut buf, 16387).unwrap();
534            assert_eq!(buf, vec![0x83, 0x80, 0x01]);
535            buf.clear();
536        }
537
538        #[test]
539        fn multi_stage_binary() {
540            let a = Node::from("x") & Node::from("y");
541            let output = &a | &!&a;
542            let mut buf = vec![];
543            to_aiger_binary(&mut buf, &output).unwrap();
544            let expected = b"aig 4 2 0 1 2\n9\n\x02\x02\x01\x01i0 x\ni1 y\n";
545            assert_eq!(buf, expected);
546        }
547    }
548
549    mod input {
550
551        use crate::evaluate;
552
553        use super::*;
554
555        fn test_function_x_y(data: &[u8], fun: &impl Fn(bool, bool) -> bool) {
556            let out = from_aiger(data).unwrap();
557            for x_val in [false, true] {
558                for y_val in [false, true] {
559                    let assignments = [("x", x_val), ("y", y_val)]
560                        .into_iter()
561                        .map(|(n, v)| (n.to_string(), v))
562                        .collect();
563                    let result = evaluate(&out, &assignments);
564                    assert_eq!(result, fun(x_val, y_val));
565                }
566            }
567        }
568
569        #[test]
570        fn xor_ascii() {
571            let data = b"aag 5 2 0 1 3\n2\n4\n11\n6 5 2\n8 4 3\n10 9 7\ni0 x\ni1 y\n";
572            test_function_x_y(data, &|x, y| x ^ y);
573        }
574
575        #[test]
576        fn multi_stage_binary() {
577            let data = b"aig 4 2 0 1 2\n9\n\x02\x02\x01\x01i0 x\ni1 y\n";
578            test_function_x_y(data, &|_, _| true);
579        }
580
581        #[test]
582        fn decode_number() {
583            let buf = vec![0x7f];
584            assert_eq!(aiger_decode_number(&mut &*buf).unwrap(), 0x7f);
585            let buf = vec![0x80, 0x01];
586            assert_eq!(aiger_decode_number(&mut &*buf).unwrap(), 0x80);
587            let buf = vec![0x81, 0x01];
588            assert_eq!(aiger_decode_number(&mut &*buf).unwrap(), 0x81);
589            let buf = vec![0x83, 0x80, 0x01];
590            assert_eq!(aiger_decode_number(&mut &*buf).unwrap(), 16387);
591        }
592    }
593}