Skip to main content

flussab_aiger/
binary.rs

1use std::{
2    borrow::Cow,
3    io::{BufReader, Read},
4    marker::PhantomData,
5};
6
7use flussab::{text::LineReader, DeferredReader, DeferredWriter, Parsed::Fallthrough};
8
9use crate::{
10    aig::{OrderedAig, OrderedAndGate, OrderedLatch, Symbol, SymbolTarget},
11    token::{self, eof, unexpected},
12    Lit, ParseError,
13};
14
15#[derive(Default)]
16#[non_exhaustive]
17pub struct Config {}
18
19#[derive(Clone, Debug)]
20pub struct Header {
21    pub max_var_index: usize,
22    pub input_count: usize,
23    pub latch_count: usize,
24    pub output_count: usize,
25    pub and_gate_count: usize,
26    pub bad_state_property_count: usize,
27    pub invariant_constraint_count: usize,
28    pub justice_property_count: usize,
29    pub fairness_constraint_count: usize,
30}
31
32impl Header {
33    fn parse<L: Lit>(reader: &mut LineReader) -> Result<Self, ParseError> {
34        token::fixed(reader, b"aig")
35            .or_give_up(|| token::unexpected(reader, "binary AIGER header \"aig\""))?;
36
37        token::required_space(reader)?;
38        let max_var_index = token::header_field(
39            reader,
40            "maximum variable index",
41            (L::MAX_CODE - 1) / 2,
42            true,
43        )?;
44
45        let mut limit = max_var_index;
46
47        token::required_space(reader)?;
48        let input_count = token::header_field(reader, "input count", limit, false)?;
49
50        limit -= input_count;
51
52        token::required_space(reader)?;
53        let latch_count = token::header_field(reader, "latch count", limit, false)?;
54
55        limit -= latch_count;
56
57        token::required_space(reader)?;
58        let output_count = token::header_field(reader, "output count", usize::MAX, true)?;
59
60        token::required_space(reader)?;
61        let and_gate_count = token::header_field(reader, "and gate count", limit, false)?;
62
63        let mut bad_state_property_count = 0;
64        let mut invariant_constraint_count = 0;
65        let mut justice_property_count = 0;
66        let mut fairness_constraint_count = 0;
67
68        #[allow(clippy::never_loop)]
69        loop {
70            if !token::required_newline_or_space(reader)? {
71                break;
72            }
73
74            bad_state_property_count =
75                token::header_field(reader, "bad state property count", limit, false)?;
76
77            if !token::required_newline_or_space(reader)? {
78                break;
79            }
80            invariant_constraint_count =
81                token::header_field(reader, "invariant constraint count", limit, false)?;
82
83            if !token::required_newline_or_space(reader)? {
84                break;
85            }
86            justice_property_count =
87                token::header_field(reader, "justice property count", limit, false)?;
88
89            if !token::required_newline_or_space(reader)? {
90                break;
91            }
92            fairness_constraint_count =
93                token::header_field(reader, "fairness constraint count", limit, false)?;
94
95            token::required_newline(reader)?;
96            break;
97        }
98
99        Ok(Header {
100            max_var_index,
101            input_count,
102            latch_count,
103            output_count,
104            and_gate_count,
105            bad_state_property_count,
106            invariant_constraint_count,
107            justice_property_count,
108            fairness_constraint_count,
109        })
110    }
111}
112
113/// Parser for the ASCII version of the AIGER file format.
114pub struct Parser<'a, L> {
115    reader: LineReader<'a>,
116    header: Header,
117    max_lit: usize,
118    code: usize,
119    _lit_builder: std::marker::PhantomData<L>,
120}
121
122impl<'a, L> Parser<'a, L>
123where
124    L: Lit,
125{
126    /// Creates a parser reading from a [`BufReader`].
127    pub fn from_buf_reader(
128        buf_reader: BufReader<impl Read + 'a>,
129        config: Config,
130    ) -> Result<Self, ParseError> {
131        Self::new(
132            LineReader::new(DeferredReader::from_buf_reader(buf_reader)),
133            config,
134        )
135    }
136
137    /// Creates a parser reading from a [`Read`] instance.
138    ///
139    /// If the [`Read`] instance is a [`BufReader`], it is better to use
140    /// [`from_buf_reader`][Self::from_buf_reader] to avoid unnecessary double buffering of the
141    /// data.
142    pub fn from_read(read: impl Read + 'a, config: Config) -> Result<Self, ParseError> {
143        Self::new(LineReader::new(DeferredReader::from_read(read)), config)
144    }
145
146    /// Creates a parser reading from a boxed [`Read`] instance.
147    ///
148    /// If the [`Read`] instance is a [`BufReader`], it is better to use
149    /// [`from_buf_reader`][Self::from_buf_reader] to avoid unnecessary double buffering of the
150    /// data.
151    #[inline(never)]
152    pub fn from_boxed_dyn_read(
153        read: Box<dyn Read + 'a>,
154        config: Config,
155    ) -> Result<Self, ParseError> {
156        Self::new(
157            LineReader::new(DeferredReader::from_boxed_dyn_read(read)),
158            config,
159        )
160    }
161
162    /// Creates a parser reading from a [`LineReader`].
163    pub fn new(mut reader: LineReader<'a>, _config: Config) -> Result<Self, ParseError> {
164        let header = Header::parse::<L>(&mut reader)?;
165
166        Ok(Self {
167            reader,
168            max_lit: header.max_var_index * 2 + 1,
169            code: (header.input_count + 1) * 2,
170            header,
171            _lit_builder: std::marker::PhantomData,
172        })
173    }
174
175    pub fn latches(self) -> Result<ParseLatches<'a, L>, ParseError> {
176        Ok(ParseLatches {
177            latches_left: self.header.latch_count,
178            parser: self,
179        })
180    }
181
182    pub fn header(&self) -> &Header {
183        &self.header
184    }
185
186    pub fn parse(self) -> Result<OrderedAig<L>, ParseError> {
187        let mut aig = OrderedAig {
188            max_var_index: self.header.max_var_index,
189            input_count: self.header.input_count,
190            ..OrderedAig::default()
191        };
192
193        aig.latches.reserve(self.header.latch_count);
194        aig.outputs.reserve(self.header.output_count);
195        aig.bad_state_properties
196            .reserve(self.header.bad_state_property_count);
197        aig.invariant_constraints
198            .reserve(self.header.invariant_constraint_count);
199        aig.justice_properties = (0..self.header.justice_property_count)
200            .map(|_| vec![])
201            .collect();
202        aig.fairness_constraints
203            .reserve(self.header.fairness_constraint_count);
204        aig.and_gates.reserve(self.header.and_gate_count);
205
206        let justice_property_count = self.header.justice_property_count;
207
208        let mut aag_reader = self.latches()?;
209        while let Some(latch) = aag_reader.next_latch()? {
210            aig.latches.push(latch);
211        }
212
213        let mut aag_reader = aag_reader.outputs()?;
214        while let Some(output) = aag_reader.next_output()? {
215            aig.outputs.push(output);
216        }
217
218        let mut aag_reader = aag_reader.bad_state_properties()?;
219        while let Some(bad_state_property) = aag_reader.next_bad_state_property()? {
220            aig.bad_state_properties.push(bad_state_property);
221        }
222
223        let mut aag_reader = aag_reader.invariant_constraints()?;
224        while let Some(invariant_constraint) = aag_reader.next_invariant_constraint()? {
225            aig.invariant_constraints.push(invariant_constraint);
226        }
227
228        let mut justice_property_sizes = Vec::with_capacity(justice_property_count);
229
230        let mut aag_reader = aag_reader.justice_properties()?;
231        while let Some(justice_property_size) = aag_reader.next_justice_property_size()? {
232            justice_property_sizes.push(justice_property_size);
233        }
234
235        let mut justice_property = 0;
236
237        let mut aag_reader = aag_reader.justice_property_local_fairness_constraints()?;
238        while let Some(justice_property_local_fairness_constraint) =
239            aag_reader.next_justice_property_local_fairness_constraint()?
240        {
241            while aig.justice_properties[justice_property].len()
242                == justice_property_sizes[justice_property]
243            {
244                justice_property += 1;
245            }
246            aig.justice_properties[justice_property]
247                .push(justice_property_local_fairness_constraint);
248        }
249
250        let mut aag_reader = aag_reader.fairness_constraints()?;
251        while let Some(fairness_constraint) = aag_reader.next_fairness_constraint()? {
252            aig.fairness_constraints.push(fairness_constraint);
253        }
254
255        let mut aag_reader = aag_reader.and_gates()?;
256        while let Some(and_gate) = aag_reader.next_and_gate()? {
257            aig.and_gates.push(and_gate);
258        }
259
260        let mut aag_reader = aag_reader.symbols()?;
261        while let Some(symbol) = aag_reader.next_symbol()? {
262            aig.symbols.push(symbol.into_owned_name());
263        }
264
265        if let Some(comment) = aag_reader.comment()? {
266            aig.comment = Some(comment.to_owned());
267        }
268
269        Ok(aig)
270    }
271}
272
273pub struct ParseInputs<'a, L> {
274    parser: Parser<'a, L>,
275    inputs_left: usize,
276}
277
278impl<'a, L> std::ops::Deref for ParseInputs<'a, L> {
279    type Target = Parser<'a, L>;
280
281    fn deref(&self) -> &Self::Target {
282        &self.parser
283    }
284}
285
286impl<'a, L> ParseInputs<'a, L>
287where
288    L: Lit,
289{
290    pub fn next_input(&mut self) -> Result<Option<L>, ParseError> {
291        if self.inputs_left == 0 {
292            return Ok(None);
293        }
294        self.inputs_left -= 1;
295        let lit = L::from_code(token::lit(
296            &mut self.parser.reader,
297            "input literal",
298            self.parser.max_lit,
299            true,
300        )?);
301        token::required_newline(&mut self.parser.reader)?;
302        Ok(Some(lit))
303    }
304
305    pub fn latches(mut self) -> Result<ParseLatches<'a, L>, ParseError> {
306        while self.inputs_left != 0 {
307            self.next_input()?;
308        }
309
310        Ok(ParseLatches {
311            latches_left: self.parser.header.latch_count,
312            parser: self.parser,
313        })
314    }
315}
316pub struct ParseLatches<'a, L> {
317    parser: Parser<'a, L>,
318    latches_left: usize,
319}
320
321impl<'a, L> ParseLatches<'a, L>
322where
323    L: Lit,
324{
325    pub fn next_latch(&mut self) -> Result<Option<OrderedLatch<L>>, ParseError> {
326        if self.latches_left == 0 {
327            return Ok(None);
328        }
329        self.latches_left -= 1;
330
331        let next_state = L::from_code(token::lit(
332            &mut self.parser.reader,
333            "latch next state literal",
334            self.parser.max_lit,
335            false,
336        )?);
337
338        let mut initialization = Some(false);
339
340        if token::required_newline_or_space(&mut self.parser.reader)? {
341            let initialization_code = token::lit(
342                &mut self.parser.reader,
343                "latch initialization literal",
344                self.parser.max_lit,
345                false,
346            )?;
347
348            if initialization_code < 2 {
349                initialization = Some(initialization_code != 0);
350            } else if initialization_code == self.parser.code {
351                initialization = None;
352            } else {
353                return Err(token::invalid_initialization(
354                    &mut self.parser.reader,
355                    initialization_code,
356                    self.parser.code,
357                ));
358            }
359
360            token::required_newline(&mut self.parser.reader)?;
361        }
362        self.parser.code += 2;
363        Ok(Some(OrderedLatch {
364            next_state,
365            initialization,
366        }))
367    }
368
369    pub fn outputs(mut self) -> Result<ParseOutputs<'a, L>, ParseError> {
370        while self.latches_left != 0 {
371            self.next_latch()?;
372        }
373
374        Ok(ParseOutputs {
375            outputs_left: self.parser.header.output_count,
376            parser: self.parser,
377        })
378    }
379}
380
381pub struct ParseOutputs<'a, L> {
382    parser: Parser<'a, L>,
383    outputs_left: usize,
384}
385
386impl<'a, L> ParseOutputs<'a, L>
387where
388    L: Lit,
389{
390    pub fn next_output(&mut self) -> Result<Option<L>, ParseError> {
391        if self.outputs_left == 0 {
392            return Ok(None);
393        }
394        self.outputs_left -= 1;
395        let lit = L::from_code(token::lit(
396            &mut self.parser.reader,
397            "output literal",
398            self.parser.max_lit,
399            false,
400        )?);
401        token::required_newline(&mut self.parser.reader)?;
402        Ok(Some(lit))
403    }
404
405    pub fn bad_state_properties(mut self) -> Result<ParseBadStateProperties<'a, L>, ParseError> {
406        while self.outputs_left != 0 {
407            self.next_output()?;
408        }
409
410        Ok(ParseBadStateProperties {
411            bad_left: self.parser.header.bad_state_property_count,
412            parser: self.parser,
413        })
414    }
415}
416
417pub struct ParseBadStateProperties<'a, L> {
418    parser: Parser<'a, L>,
419    bad_left: usize,
420}
421
422impl<'a, L> ParseBadStateProperties<'a, L>
423where
424    L: Lit,
425{
426    pub fn next_bad_state_property(&mut self) -> Result<Option<L>, ParseError> {
427        if self.bad_left == 0 {
428            return Ok(None);
429        }
430        self.bad_left -= 1;
431        let lit = L::from_code(token::lit(
432            &mut self.parser.reader,
433            "bad state property literal",
434            self.parser.max_lit,
435            false,
436        )?);
437        token::required_newline(&mut self.parser.reader)?;
438        Ok(Some(lit))
439    }
440
441    pub fn invariant_constraints(mut self) -> Result<ParseInvariantConstraints<'a, L>, ParseError> {
442        while self.bad_left != 0 {
443            self.next_bad_state_property()?;
444        }
445
446        Ok(ParseInvariantConstraints {
447            constraints_left: self.parser.header.invariant_constraint_count,
448            parser: self.parser,
449        })
450    }
451}
452
453pub struct ParseInvariantConstraints<'a, L> {
454    parser: Parser<'a, L>,
455    constraints_left: usize,
456}
457
458impl<'a, L> ParseInvariantConstraints<'a, L>
459where
460    L: Lit,
461{
462    pub fn next_invariant_constraint(&mut self) -> Result<Option<L>, ParseError> {
463        if self.constraints_left == 0 {
464            return Ok(None);
465        }
466        self.constraints_left -= 1;
467        let lit = L::from_code(token::lit(
468            &mut self.parser.reader,
469            "invariant constraint literal",
470            self.parser.max_lit,
471            false,
472        )?);
473        token::required_newline(&mut self.parser.reader)?;
474        Ok(Some(lit))
475    }
476
477    pub fn justice_properties(mut self) -> Result<ParseJusticePropertySizes<'a, L>, ParseError> {
478        while self.constraints_left != 0 {
479            self.next_invariant_constraint()?;
480        }
481
482        Ok(ParseJusticePropertySizes {
483            justice_left: self.parser.header.justice_property_count,
484            parser: self.parser,
485            total_local_fairness_count: 0,
486        })
487    }
488}
489
490pub struct ParseJusticePropertySizes<'a, L: Lit> {
491    parser: Parser<'a, L>,
492    justice_left: usize,
493    total_local_fairness_count: usize,
494}
495
496impl<'a, L> ParseJusticePropertySizes<'a, L>
497where
498    L: Lit,
499{
500    pub fn next_justice_property_size(&mut self) -> Result<Option<usize>, ParseError> {
501        if self.justice_left == 0 {
502            return Ok(None);
503        }
504        self.justice_left -= 1;
505        let count = token::header_field(
506            &mut self.parser.reader,
507            "justice property local fairness constraint count",
508            usize::MAX - self.total_local_fairness_count,
509            true,
510        )?;
511        token::required_newline(&mut self.parser.reader)?;
512
513        self.total_local_fairness_count += count;
514
515        Ok(Some(count))
516    }
517
518    pub fn justice_property_local_fairness_constraints(
519        mut self,
520    ) -> Result<ParseJusticePropertyLocalFairnessConstraints<'a, L>, ParseError> {
521        while self.justice_left != 0 {
522            self.next_justice_property_size()?;
523        }
524
525        Ok(ParseJusticePropertyLocalFairnessConstraints {
526            local_fairness_left: self.total_local_fairness_count,
527            parser: self.parser,
528        })
529    }
530}
531
532pub struct ParseJusticePropertyLocalFairnessConstraints<'a, L: Lit> {
533    parser: Parser<'a, L>,
534    local_fairness_left: usize,
535}
536
537impl<'a, L> ParseJusticePropertyLocalFairnessConstraints<'a, L>
538where
539    L: Lit,
540{
541    pub fn next_justice_property_local_fairness_constraint(
542        &mut self,
543    ) -> Result<Option<L>, ParseError> {
544        if self.local_fairness_left == 0 {
545            return Ok(None);
546        }
547        self.local_fairness_left -= 1;
548        let lit = L::from_code(token::lit(
549            &mut self.parser.reader,
550            "justice property local fairness constraint literal",
551            self.parser.max_lit,
552            false,
553        )?);
554        token::required_newline(&mut self.parser.reader)?;
555
556        Ok(Some(lit))
557    }
558
559    pub fn fairness_constraints(mut self) -> Result<ParseFairnessConstraints<'a, L>, ParseError> {
560        while self.local_fairness_left != 0 {
561            self.next_justice_property_local_fairness_constraint()?;
562        }
563
564        Ok(ParseFairnessConstraints {
565            fairness_left: self.parser.header.fairness_constraint_count,
566            parser: self.parser,
567        })
568    }
569}
570
571pub struct ParseFairnessConstraints<'a, L> {
572    parser: Parser<'a, L>,
573    fairness_left: usize,
574}
575
576impl<'a, L> ParseFairnessConstraints<'a, L>
577where
578    L: Lit,
579{
580    pub fn next_fairness_constraint(&mut self) -> Result<Option<L>, ParseError> {
581        if self.fairness_left == 0 {
582            return Ok(None);
583        }
584        self.fairness_left -= 1;
585        let lit = L::from_code(token::lit(
586            &mut self.parser.reader,
587            "fairness constraint literal",
588            self.parser.max_lit,
589            false,
590        )?);
591        token::required_newline(&mut self.parser.reader)?;
592        Ok(Some(lit))
593    }
594
595    pub fn and_gates(mut self) -> Result<ParseAndGates<'a, L>, ParseError> {
596        while self.fairness_left != 0 {
597            self.next_fairness_constraint()?;
598        }
599
600        Ok(ParseAndGates {
601            ands_left: self.parser.header.and_gate_count,
602            parser: self.parser,
603        })
604    }
605}
606
607pub struct ParseAndGates<'a, L> {
608    parser: Parser<'a, L>,
609    ands_left: usize,
610}
611
612impl<'a, L> ParseAndGates<'a, L>
613where
614    L: Lit,
615{
616    pub fn next_and_gate(&mut self) -> Result<Option<OrderedAndGate<L>>, ParseError> {
617        if self.ands_left == 0 {
618            return Ok(None);
619        }
620
621        self.ands_left -= 1;
622
623        let output_code = self.parser.code;
624
625        let input_code_0: usize = token::delta_code(
626            &mut self.parser.reader,
627            output_code,
628            "first input",
629            "output code",
630        )?;
631
632        let input_code_1: usize = token::delta_code(
633            &mut self.parser.reader,
634            input_code_0,
635            "second input",
636            "first input code",
637        )?;
638
639        self.parser.code += 2;
640        Ok(Some(OrderedAndGate {
641            inputs: [L::from_code(input_code_0), L::from_code(input_code_1)],
642        }))
643    }
644
645    pub fn symbols(mut self) -> Result<ParseSymbols<'a, L>, ParseError> {
646        while self.ands_left != 0 {
647            self.next_and_gate()?;
648        }
649
650        Ok(ParseSymbols {
651            parser: self.parser,
652        })
653    }
654}
655
656pub struct ParseSymbols<'a, L> {
657    parser: Parser<'a, L>,
658}
659
660impl<'a, L> ParseSymbols<'a, L>
661where
662    L: Lit,
663{
664    pub fn next_symbol(&mut self) -> Result<Option<Symbol>, ParseError> {
665        let input = &mut self.parser.reader;
666        let target = if self.parser.header.input_count > 0 {
667            token::fixed(input, b"i")
668        } else {
669            Fallthrough
670        }
671        .and_then(|_| {
672            token::symbol_index(input, "input index", self.parser.header.input_count - 1)
673                .map(SymbolTarget::Input)
674        })
675        .or_parse(|| {
676            if self.parser.header.output_count > 0 {
677                token::fixed(input, b"o")
678            } else {
679                Fallthrough
680            }
681            .and_then(|_| {
682                token::symbol_index(input, "output index", self.parser.header.output_count - 1)
683                    .map(SymbolTarget::Output)
684            })
685        })
686        .or_parse(|| {
687            if self.parser.header.latch_count > 0 {
688                token::fixed(input, b"l")
689            } else {
690                Fallthrough
691            }
692            .and_then(|_| {
693                token::symbol_index(input, "latch index", self.parser.header.latch_count - 1)
694                    .map(SymbolTarget::Latch)
695            })
696        })
697        .or_parse(|| {
698            if self.parser.header.bad_state_property_count > 0 {
699                token::fixed(input, b"b")
700            } else {
701                Fallthrough
702            }
703            .and_then(|_| {
704                token::symbol_index(
705                    input,
706                    "bad state property index",
707                    self.parser.header.latch_count - 1,
708                )
709                .map(SymbolTarget::BadStateProperty)
710            })
711        })
712        .or_parse(|| {
713            if self.parser.header.invariant_constraint_count > 0 {
714                token::fixed_not_eol(input, b"c")
715            } else {
716                Fallthrough
717            }
718            .and_then(|_| {
719                token::symbol_index(
720                    input,
721                    "invariant constraint index or newline", // could be a comment
722                    self.parser.header.latch_count - 1,
723                )
724                .map(SymbolTarget::InvariantConstraint)
725            })
726        })
727        .or_parse(|| {
728            if self.parser.header.justice_property_count > 0 {
729                token::fixed(input, b"j")
730            } else {
731                Fallthrough
732            }
733            .and_then(|_| {
734                token::symbol_index(
735                    input,
736                    "justice property index",
737                    self.parser.header.latch_count - 1,
738                )
739                .map(SymbolTarget::JusticeProperty)
740            })
741        })
742        .or_parse(|| {
743            if self.parser.header.fairness_constraint_count > 0 {
744                token::fixed(input, b"f")
745            } else {
746                Fallthrough
747            }
748            .and_then(|_| {
749                token::symbol_index(
750                    input,
751                    "fairness constraint index",
752                    self.parser.header.latch_count - 1,
753                )
754                .map(SymbolTarget::FairnessConstraint)
755            })
756        })
757        .optional()?;
758
759        if let Some(target) = target {
760            token::required_space(input)?;
761            let name = token::remaining_line_content(input)?;
762
763            Ok(Some(Symbol {
764                target,
765                name: Cow::Borrowed(name),
766            }))
767        } else {
768            Ok(None)
769        }
770    }
771
772    pub fn comment(&mut self) -> Result<Option<&str>, ParseError> {
773        while self.next_symbol()?.is_some() {}
774        let input = &mut self.parser.reader;
775
776        if token::fixed(input, b"c").optional()?.is_some() {
777            token::required_newline(input)?;
778            let comment = token::remaining_file_content(input)?;
779
780            Ok(Some(comment))
781        } else {
782            eof(input).or_give_up(|| unexpected(input, "symbol, comment or end of file"))?;
783
784            Ok(None)
785        }
786    }
787}
788
789pub struct Writer<'a, L> {
790    pub writer: DeferredWriter<'a>,
791    pub code: usize,
792    codec: PhantomData<L>,
793}
794
795impl<'a, L> std::ops::Deref for Writer<'a, L> {
796    type Target = DeferredWriter<'a>;
797
798    fn deref(&self) -> &Self::Target {
799        &self.writer
800    }
801}
802
803impl<'a, L> std::ops::DerefMut for Writer<'a, L> {
804    fn deref_mut(&mut self) -> &mut Self::Target {
805        &mut self.writer
806    }
807}
808
809impl<'a, L> Writer<'a, L>
810where
811    L: Lit,
812{
813    pub fn new(writer: DeferredWriter<'a>) -> Self {
814        Self {
815            writer,
816            code: 0,
817            codec: PhantomData,
818        }
819    }
820
821    pub fn write_header(&mut self, header: &Header) {
822        let fields = [
823            header.max_var_index,
824            header.input_count,
825            header.latch_count,
826            header.output_count,
827            header.and_gate_count,
828            header.bad_state_property_count,
829            header.invariant_constraint_count,
830            header.justice_property_count,
831            header.fairness_constraint_count,
832        ];
833
834        self.code = (header.input_count + 1) * 2;
835
836        let mut fields = fields.as_slice();
837
838        while let Some((0, rest)) = fields.split_last() {
839            if rest.len() >= 5 {
840                fields = rest;
841            } else {
842                break;
843            }
844        }
845
846        self.writer.write_all_defer_err(b"aig");
847
848        for &field in fields {
849            self.writer.write_all_defer_err(b" ");
850            flussab::write::text::ascii_digits(&mut self.writer, field);
851        }
852        self.writer.write_all_defer_err(b"\n");
853    }
854
855    pub fn write_lit(&mut self, lit: L) {
856        flussab::write::text::ascii_digits(&mut self.writer, lit.code());
857        self.writer.write_all_defer_err(b"\n");
858    }
859
860    pub fn write_latch(&mut self, latch: OrderedLatch<L>) {
861        flussab::write::text::ascii_digits(&mut self.writer, latch.next_state.code());
862
863        match latch.initialization {
864            Some(true) => self.writer.write_all_defer_err(b" 1\n"),
865            Some(false) => self.writer.write_all_defer_err(b"\n"),
866            None => {
867                self.writer.write_all_defer_err(b" ");
868                flussab::write::text::ascii_digits(&mut self.writer, self.code);
869                self.writer.write_all_defer_err(b"\n");
870            }
871        }
872        self.code += 2;
873    }
874
875    pub fn write_count(&mut self, count: usize) {
876        flussab::write::text::ascii_digits(&mut self.writer, count);
877        self.writer.write_all_defer_err(b"\n");
878    }
879
880    pub fn write_and_gate(&mut self, mut and_gate: OrderedAndGate<L>) {
881        if and_gate.inputs[0].code() < and_gate.inputs[1].code() {
882            and_gate.inputs.swap(0, 1);
883        }
884        let code_0 = and_gate.inputs[0].code();
885        let code_1 = and_gate.inputs[1].code();
886        assert!(code_0 <= self.code);
887        let delta_0 = self.code - code_0;
888        let delta_1 = code_0 - code_1;
889
890        self.write_binary_uint(delta_0);
891        self.write_binary_uint(delta_1);
892        self.code += 2;
893    }
894
895    fn write_binary_uint(&mut self, mut code: usize) {
896        // TODO optimize
897        let mut bytes = [0u8; (usize::BITS as usize + 6) / 7];
898        let mut len = 0;
899        loop {
900            bytes[len] = (code as u8) | 0x80;
901            code >>= 7;
902
903            len += 1;
904            if code == 0 {
905                break;
906            }
907        }
908
909        bytes[len - 1] &= 0x7f;
910
911        self.writer.write_all_defer_err(&bytes[..len]);
912    }
913
914    pub fn write_symbol(&mut self, symbol: &Symbol) {
915        let (prefix, index) = match symbol.target {
916            SymbolTarget::Input(index) => (b"i", index),
917            SymbolTarget::Output(index) => (b"o", index),
918            SymbolTarget::Latch(index) => (b"l", index),
919            SymbolTarget::BadStateProperty(index) => (b"b", index),
920            SymbolTarget::InvariantConstraint(index) => (b"c", index),
921            SymbolTarget::JusticeProperty(index) => (b"j", index),
922            SymbolTarget::FairnessConstraint(index) => (b"f", index),
923        };
924
925        self.writer.write_all_defer_err(prefix);
926        flussab::write::text::ascii_digits(&mut self.writer, index);
927        self.writer.write_all_defer_err(b" ");
928        self.writer.write_all_defer_err(symbol.name.as_bytes());
929        self.writer.write_all_defer_err(b"\n");
930    }
931
932    pub fn write_comment(&mut self, comment: &str) {
933        self.writer.write_all_defer_err(b"c\n");
934        self.writer.write_all_defer_err(comment.as_bytes());
935        self.writer.write_all_defer_err(b"\n");
936    }
937
938    pub fn write_ordered_aig(&mut self, aig: &OrderedAig<L>) {
939        self.write_header(&Header {
940            max_var_index: aig.max_var_index,
941            input_count: aig.input_count,
942            latch_count: aig.latches.len(),
943            output_count: aig.outputs.len(),
944            and_gate_count: aig.and_gates.len(),
945            bad_state_property_count: aig.bad_state_properties.len(),
946            invariant_constraint_count: aig.invariant_constraints.len(),
947            justice_property_count: aig.justice_properties.len(),
948            fairness_constraint_count: aig.fairness_constraints.len(),
949        });
950
951        for &latch in &aig.latches {
952            self.write_latch(latch);
953        }
954
955        for &output in &aig.outputs {
956            self.write_lit(output);
957        }
958
959        for &bad_state_property in &aig.bad_state_properties {
960            self.write_lit(bad_state_property);
961        }
962
963        for &invariant_constraint in &aig.invariant_constraints {
964            self.write_lit(invariant_constraint);
965        }
966
967        for justice_property in &aig.justice_properties {
968            self.write_count(justice_property.len());
969        }
970
971        for justice_property in &aig.justice_properties {
972            for &justice_property_local_fairness_constraint in justice_property {
973                self.write_lit(justice_property_local_fairness_constraint);
974            }
975        }
976
977        for &fairness_constraint in &aig.fairness_constraints {
978            self.write_lit(fairness_constraint);
979        }
980
981        for &and_gate in &aig.and_gates {
982            self.write_and_gate(and_gate);
983        }
984
985        for symbol in &aig.symbols {
986            self.write_symbol(symbol);
987        }
988
989        if let Some(comment) = &aig.comment {
990            self.write_comment(comment);
991        }
992    }
993}