1use std::collections::HashMap;
21
22#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
25pub struct AigLit(u32);
26
27impl AigLit {
28 pub const FALSE: AigLit = AigLit(0);
29 pub const TRUE: AigLit = AigLit(1);
30
31 pub fn new(node: u32, complemented: bool) -> AigLit {
32 AigLit(node << 1 | complemented as u32)
33 }
34
35 pub fn from_code(code: u32) -> AigLit {
37 AigLit(code)
38 }
39
40 pub fn node(self) -> u32 {
41 self.0 >> 1
42 }
43
44 pub fn is_complemented(self) -> bool {
45 self.0 & 1 == 1
46 }
47
48 pub fn code(self) -> u32 {
49 self.0
50 }
51
52 pub fn with_phase(self, flip: bool) -> AigLit {
54 AigLit(self.0 ^ flip as u32)
55 }
56}
57
58impl std::ops::Not for AigLit {
59 type Output = AigLit;
60 fn not(self) -> AigLit {
61 AigLit(self.0 ^ 1)
62 }
63}
64
65#[derive(Clone, Copy, PartialEq, Eq, Debug)]
67pub enum Node {
68 False,
69 Input(usize),
71 Latch(usize),
73 And(AigLit, AigLit),
75}
76
77#[derive(Clone, Copy, PartialEq, Eq, Debug)]
79pub enum Init {
80 Zero,
81 One,
82 Free,
84}
85
86#[derive(Clone, Debug, PartialEq, Eq)]
87pub struct Latch {
88 pub node: u32,
89 pub next: AigLit,
90 pub init: Init,
91 pub name: Option<String>,
92}
93
94#[derive(Clone, Debug, PartialEq, Eq)]
96pub struct Port {
97 pub lit: AigLit,
98 pub name: Option<String>,
99}
100
101#[derive(Clone, Copy, PartialEq, Eq, Debug)]
103pub enum Leaf {
104 Input(usize),
105 Latch(usize),
106}
107
108#[derive(Clone, Debug, PartialEq, Eq)]
110pub enum AigerError {
111 Header(String),
112 Literal { line: usize, literal: u64 },
114 Undefined { line: usize, var: u64 },
116 Redefined { line: usize, var: u64 },
118 Cycle { var: u64 },
120 Malformed { line: usize },
122 Unsupported(String),
123 Truncated,
124}
125
126impl std::fmt::Display for AigerError {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 match self {
129 AigerError::Header(why) => write!(f, "AIGER header: {why}"),
130 AigerError::Literal { line, literal } => write!(f, "line {line}: literal {literal} is out of place"),
131 AigerError::Undefined { line, var } => write!(f, "line {line}: variable {var} is never defined"),
132 AigerError::Redefined { line, var } => write!(f, "line {line}: variable {var} is defined twice"),
133 AigerError::Cycle { var } => write!(f, "gate {var} depends on itself"),
134 AigerError::Malformed { line } => write!(f, "line {line} is malformed"),
135 AigerError::Unsupported(what) => write!(f, "unsupported: {what}"),
136 AigerError::Truncated => write!(f, "the file ends early"),
137 }
138 }
139}
140
141impl std::error::Error for AigerError {}
142
143#[derive(Clone, Debug)]
146pub struct Aig {
147 nodes: Vec<Node>,
148 inputs: Vec<Port>,
149 latches: Vec<Latch>,
150 outputs: Vec<Port>,
151 bad: Vec<Port>,
152 constraints: Vec<Port>,
153 comments: Vec<String>,
154 strash: HashMap<(AigLit, AigLit), u32>,
155}
156
157impl Default for Aig {
158 fn default() -> Aig {
159 Aig::new()
160 }
161}
162
163impl Aig {
164 pub fn new() -> Aig {
166 Aig {
167 nodes: vec![Node::False],
168 inputs: Vec::new(),
169 latches: Vec::new(),
170 outputs: Vec::new(),
171 bad: Vec::new(),
172 constraints: Vec::new(),
173 comments: Vec::new(),
174 strash: HashMap::new(),
175 }
176 }
177
178 fn push(&mut self, node: Node) -> u32 {
179 let n = self.nodes.len() as u32;
180 self.nodes.push(node);
181 n
182 }
183
184 pub fn add_input(&mut self, name: Option<String>) -> AigLit {
185 let n = self.push(Node::Input(self.inputs.len()));
186 let lit = AigLit::new(n, false);
187 self.inputs.push(Port { lit, name });
188 lit
189 }
190
191 pub fn add_latch(&mut self, name: Option<String>, init: Init) -> usize {
193 let k = self.latches.len();
194 let node = self.push(Node::Latch(k));
195 self.latches.push(Latch { node, next: AigLit::FALSE, init, name });
196 k
197 }
198
199 pub fn latch_lit(&self, latch: usize) -> AigLit {
201 AigLit::new(self.latches[latch].node, false)
202 }
203
204 pub fn set_next(&mut self, latch: usize, next: AigLit) {
205 self.latches[latch].next = next;
206 }
207
208 pub fn and(&mut self, a: AigLit, b: AigLit) -> AigLit {
210 let (hi, lo) = if a >= b { (a, b) } else { (b, a) };
211 if lo == AigLit::FALSE || hi == !lo {
212 return AigLit::FALSE;
213 }
214 if lo == AigLit::TRUE || hi == lo {
215 return hi;
216 }
217 if let Some(&n) = self.strash.get(&(hi, lo)) {
218 return AigLit::new(n, false);
219 }
220 let n = self.push(Node::And(hi, lo));
221 self.strash.insert((hi, lo), n);
222 AigLit::new(n, false)
223 }
224
225 pub fn or(&mut self, a: AigLit, b: AigLit) -> AigLit {
226 !self.and(!a, !b)
227 }
228
229 pub fn xor(&mut self, a: AigLit, b: AigLit) -> AigLit {
230 let l = self.and(a, !b);
231 let r = self.and(!a, b);
232 self.or(l, r)
233 }
234
235 pub fn xnor(&mut self, a: AigLit, b: AigLit) -> AigLit {
236 !self.xor(a, b)
237 }
238
239 pub fn mux(&mut self, s: AigLit, t: AigLit, e: AigLit) -> AigLit {
241 let l = self.and(s, t);
242 let r = self.and(!s, e);
243 self.or(l, r)
244 }
245
246 pub fn add_output(&mut self, lit: AigLit, name: Option<String>) {
247 self.outputs.push(Port { lit, name });
248 }
249
250 pub fn add_bad(&mut self, lit: AigLit, name: Option<String>) {
251 self.bad.push(Port { lit, name });
252 }
253
254 pub fn add_constraint(&mut self, lit: AigLit, name: Option<String>) {
255 self.constraints.push(Port { lit, name });
256 }
257
258 pub fn node(&self, n: u32) -> Node {
259 self.nodes[n as usize]
260 }
261
262 pub fn num_nodes(&self) -> usize {
263 self.nodes.len()
264 }
265
266 pub fn num_ands(&self) -> usize {
267 self.nodes.iter().filter(|n| matches!(n, Node::And(..))).count()
268 }
269
270 pub fn inputs(&self) -> &[Port] {
271 &self.inputs
272 }
273
274 pub fn latches(&self) -> &[Latch] {
275 &self.latches
276 }
277
278 pub fn outputs(&self) -> &[Port] {
279 &self.outputs
280 }
281
282 pub fn bad(&self) -> &[Port] {
283 &self.bad
284 }
285
286 pub fn constraints(&self) -> &[Port] {
287 &self.constraints
288 }
289
290 pub fn comments(&self) -> &[String] {
291 &self.comments
292 }
293
294 pub fn input_index(&self, name: &str) -> Option<usize> {
295 self.inputs.iter().position(|p| p.name.as_deref() == Some(name))
296 }
297
298 pub fn output_index(&self, name: &str) -> Option<usize> {
299 self.outputs.iter().position(|p| p.name.as_deref() == Some(name))
300 }
301
302 pub fn eval(&self, inputs: &[bool], latches: &[bool]) -> Vec<bool> {
304 let mut v = vec![false; self.nodes.len()];
305 for (n, node) in self.nodes.iter().enumerate() {
306 v[n] = match *node {
307 Node::False => false,
308 Node::Input(i) => inputs[i],
309 Node::Latch(k) => latches[k],
310 Node::And(a, b) => Aig::value(&v, a) && Aig::value(&v, b),
311 };
312 }
313 v
314 }
315
316 pub fn value(values: &[bool], lit: AigLit) -> bool {
318 values[lit.node() as usize] ^ lit.is_complemented()
319 }
320
321 pub fn simulate(&self, words: usize, inputs: &[u64], latches: &[u64]) -> Vec<u64> {
325 let mut v = vec![0u64; self.nodes.len() * words];
326 for (n, node) in self.nodes.iter().enumerate() {
327 match *node {
328 Node::False => {}
329 Node::Input(i) => v[n * words..(n + 1) * words].copy_from_slice(&inputs[i * words..(i + 1) * words]),
330 Node::Latch(k) => {
331 v[n * words..(n + 1) * words].copy_from_slice(&latches[k * words..(k + 1) * words])
332 }
333 Node::And(a, b) => {
334 for w in 0..words {
335 v[n * words + w] = Aig::word(&v, words, a, w) & Aig::word(&v, words, b, w);
336 }
337 }
338 }
339 }
340 v
341 }
342
343 pub fn word(sim: &[u64], words: usize, lit: AigLit, w: usize) -> u64 {
345 let x = sim[lit.node() as usize * words + w];
346 if lit.is_complemented() {
347 !x
348 } else {
349 x
350 }
351 }
352
353 pub fn cone(&self, roots: &[AigLit]) -> Vec<u32> {
355 let mut seen = vec![false; self.nodes.len()];
356 let mut stack: Vec<u32> = roots.iter().map(|l| l.node()).collect();
357 let mut out = Vec::new();
358 while let Some(n) = stack.pop() {
359 if std::mem::replace(&mut seen[n as usize], true) {
360 continue;
361 }
362 out.push(n);
363 if let Node::And(a, b) = self.nodes[n as usize] {
364 stack.push(a.node());
365 stack.push(b.node());
366 }
367 }
368 out.sort_unstable();
369 out
370 }
371
372 pub fn compact(&self) -> (Aig, Vec<Option<AigLit>>) {
376 self.compact_keeping(&[])
377 }
378
379 pub fn compact_keeping(&self, keep: &[AigLit]) -> (Aig, Vec<Option<AigLit>>) {
381 let mut live = vec![false; self.nodes.len()];
382 let mut stack: Vec<u32> = self
383 .outputs
384 .iter()
385 .chain(&self.bad)
386 .chain(&self.constraints)
387 .map(|p| p.lit.node())
388 .chain(self.latches.iter().map(|l| l.next.node()))
389 .chain(keep.iter().map(|l| l.node()))
390 .collect();
391 while let Some(n) = stack.pop() {
392 if std::mem::replace(&mut live[n as usize], true) {
393 continue;
394 }
395 if let Node::And(a, b) = self.nodes[n as usize] {
396 stack.push(a.node());
397 stack.push(b.node());
398 }
399 }
400 let mut out = Aig::new();
401 let inputs: Vec<AigLit> = self.inputs.iter().map(|p| out.add_input(p.name.clone())).collect();
402 let latches: Vec<usize> = self.latches.iter().map(|l| out.add_latch(l.name.clone(), l.init)).collect();
403 let mut map: Vec<Option<AigLit>> = vec![None; self.nodes.len()];
404 map[0] = Some(AigLit::FALSE);
405 for (n, node) in self.nodes.iter().enumerate() {
406 map[n] = match *node {
407 Node::False => Some(AigLit::FALSE),
408 Node::Input(i) => Some(inputs[i]),
409 Node::Latch(k) => Some(out.latch_lit(latches[k])),
410 Node::And(a, b) if live[n] => {
411 let at = |l: AigLit, map: &[Option<AigLit>]| map[l.node() as usize].expect("a live node's fan-ins are live").with_phase(l.is_complemented());
412 let (x, y) = (at(a, &map), at(b, &map));
413 Some(out.and(x, y))
414 }
415 Node::And(..) => None,
416 };
417 }
418 let at = |l: AigLit| map[l.node() as usize].expect("read, so live").with_phase(l.is_complemented());
419 for (k, l) in self.latches.iter().enumerate() {
420 out.set_next(latches[k], at(l.next));
421 }
422 for p in &self.outputs {
423 out.add_output(at(p.lit), p.name.clone());
424 }
425 for p in &self.bad {
426 out.add_bad(at(p.lit), p.name.clone());
427 }
428 for p in &self.constraints {
429 out.add_constraint(at(p.lit), p.name.clone());
430 }
431 out.comments = self.comments.clone();
432 (out, map)
433 }
434
435 pub fn sequential_cone(&self, outputs: &[usize]) -> Aig {
439 let mut live = vec![false; self.nodes.len()];
440 let mut kept = vec![false; self.latches.len()];
441 let mut stack: Vec<u32> = outputs.iter().map(|&o| self.outputs[o].lit.node()).collect();
442 while let Some(n) = stack.pop() {
443 if std::mem::replace(&mut live[n as usize], true) {
444 continue;
445 }
446 match self.nodes[n as usize] {
447 Node::And(a, b) => {
448 stack.push(a.node());
449 stack.push(b.node());
450 }
451 Node::Latch(k) => {
452 kept[k] = true;
453 stack.push(self.latches[k].next.node());
454 }
455 Node::False | Node::Input(_) => {}
456 }
457 }
458 let mut out = Aig::new();
459 let inputs: Vec<AigLit> = self.inputs.iter().map(|p| out.add_input(p.name.clone())).collect();
460 let latches: Vec<Option<usize>> =
461 self.latches.iter().zip(&kept).map(|(l, &k)| k.then(|| out.add_latch(l.name.clone(), l.init))).collect();
462 let mut map: Vec<Option<AigLit>> = vec![None; self.nodes.len()];
463 for (n, node) in self.nodes.iter().enumerate() {
464 map[n] = match *node {
465 Node::False => Some(AigLit::FALSE),
466 Node::Input(i) => Some(inputs[i]),
467 Node::Latch(k) => latches[k].map(|j| out.latch_lit(j)),
468 Node::And(a, b) if live[n] => {
469 let at = |l: AigLit, map: &[Option<AigLit>]| map[l.node() as usize].expect("a live node's fan-ins are live").with_phase(l.is_complemented());
470 let (x, y) = (at(a, &map), at(b, &map));
471 Some(out.and(x, y))
472 }
473 Node::And(..) => None,
474 };
475 }
476 let at = |l: AigLit| map[l.node() as usize].expect("in the cone, so live").with_phase(l.is_complemented());
477 for (k, l) in self.latches.iter().enumerate() {
478 if let Some(j) = latches[k] {
479 out.set_next(j, at(l.next));
480 }
481 }
482 for &o in outputs {
483 out.add_output(at(self.outputs[o].lit), self.outputs[o].name.clone());
484 }
485 out
486 }
487
488 pub fn import(&mut self, other: &Aig, leaves: &mut dyn FnMut(Leaf) -> AigLit) -> Vec<AigLit> {
491 let mut map: Vec<AigLit> = Vec::with_capacity(other.nodes.len());
492 for node in &other.nodes {
493 let lit = match *node {
494 Node::False => AigLit::FALSE,
495 Node::Input(i) => leaves(Leaf::Input(i)),
496 Node::Latch(k) => leaves(Leaf::Latch(k)),
497 Node::And(a, b) => {
498 let ma = map[a.node() as usize].with_phase(a.is_complemented());
499 let mb = map[b.node() as usize].with_phase(b.is_complemented());
500 self.and(ma, mb)
501 }
502 };
503 map.push(lit);
504 }
505 map
506 }
507
508 fn numbering(&self) -> Vec<u32> {
510 let mut var = vec![0u32; self.nodes.len()];
511 for (i, p) in self.inputs.iter().enumerate() {
512 var[p.lit.node() as usize] = i as u32 + 1;
513 }
514 let base = self.inputs.len() as u32;
515 for (k, l) in self.latches.iter().enumerate() {
516 var[l.node as usize] = base + k as u32 + 1;
517 }
518 let mut next = base + self.latches.len() as u32 + 1;
519 for (n, node) in self.nodes.iter().enumerate() {
520 if let Node::And(..) = node {
521 var[n] = next;
522 next += 1;
523 }
524 }
525 var
526 }
527
528 fn header(&self, magic: &str) -> String {
529 let (i, l, a) = (self.inputs.len(), self.latches.len(), self.num_ands());
530 let mut h = format!("{magic} {} {i} {l} {} {a}", i + l + a, self.outputs.len());
531 if !self.bad.is_empty() || !self.constraints.is_empty() {
532 h.push_str(&format!(" {} {}", self.bad.len(), self.constraints.len()));
533 }
534 h.push('\n');
535 h
536 }
537
538 fn symbols_and_comments(&self, out: &mut String) {
539 let tables: [(char, Vec<&Option<String>>); 5] = [
540 ('i', self.inputs.iter().map(|p| &p.name).collect()),
541 ('l', self.latches.iter().map(|l| &l.name).collect()),
542 ('o', self.outputs.iter().map(|p| &p.name).collect()),
543 ('b', self.bad.iter().map(|p| &p.name).collect()),
544 ('c', self.constraints.iter().map(|p| &p.name).collect()),
545 ];
546 for (kind, names) in tables {
547 for (k, name) in names.into_iter().enumerate() {
548 if let Some(name) = name {
549 out.push_str(&format!("{kind}{k} {name}\n"));
550 }
551 }
552 }
553 if !self.comments.is_empty() {
554 out.push_str("c\n");
555 for c in &self.comments {
556 out.push_str(c);
557 out.push('\n');
558 }
559 }
560 }
561
562 fn latch_line(&self, var: &[u32], l: &Latch) -> String {
563 let code = |lit: AigLit| var[lit.node() as usize] * 2 + lit.is_complemented() as u32;
564 match l.init {
565 Init::Zero => format!("{}", code(l.next)),
566 Init::One => format!("{} 1", code(l.next)),
567 Init::Free => format!("{} {}", code(l.next), var[l.node as usize] * 2),
568 }
569 }
570
571 pub fn to_ascii(&self) -> String {
573 let var = self.numbering();
574 let code = |lit: AigLit| var[lit.node() as usize] * 2 + lit.is_complemented() as u32;
575 let mut out = self.header("aag");
576 for p in &self.inputs {
577 out.push_str(&format!("{}\n", code(p.lit)));
578 }
579 for l in &self.latches {
580 out.push_str(&format!("{} {}\n", var[l.node as usize] * 2, self.latch_line(&var, l)));
581 }
582 for p in self.outputs.iter().chain(&self.bad).chain(&self.constraints) {
583 out.push_str(&format!("{}\n", code(p.lit)));
584 }
585 for (n, node) in self.nodes.iter().enumerate() {
586 if let Node::And(a, b) = *node {
587 let (x, y) = (code(a), code(b));
588 out.push_str(&format!("{} {} {}\n", var[n] * 2, x.max(y), x.min(y)));
589 }
590 }
591 self.symbols_and_comments(&mut out);
592 out
593 }
594
595 pub fn to_binary(&self) -> Vec<u8> {
597 let var = self.numbering();
598 let code = |lit: AigLit| var[lit.node() as usize] * 2 + lit.is_complemented() as u32;
599 let mut text = self.header("aig");
600 for l in &self.latches {
601 text.push_str(&self.latch_line(&var, l));
602 text.push('\n');
603 }
604 for p in self.outputs.iter().chain(&self.bad).chain(&self.constraints) {
605 text.push_str(&format!("{}\n", code(p.lit)));
606 }
607 let mut out = text.into_bytes();
608 for (n, node) in self.nodes.iter().enumerate() {
609 if let Node::And(a, b) = *node {
610 let (x, y) = (code(a), code(b));
611 let (r0, r1) = (x.max(y), x.min(y));
612 let lhs = var[n] * 2;
613 push_varint(&mut out, lhs - r0);
614 push_varint(&mut out, r0 - r1);
615 }
616 }
617 let mut tail = String::new();
618 self.symbols_and_comments(&mut tail);
619 out.extend_from_slice(tail.as_bytes());
620 out
621 }
622
623 pub fn parse(bytes: &[u8]) -> Result<Aig, AigerError> {
625 Parser { bytes, pos: 0, line: 0 }.parse()
626 }
627}
628
629fn push_varint(out: &mut Vec<u8>, mut x: u32) {
630 while x >= 0x80 {
631 out.push((x & 0x7f) as u8 | 0x80);
632 x >>= 7;
633 }
634 out.push(x as u8);
635}
636
637#[derive(Clone, Copy)]
639enum Def {
640 None,
641 Input,
642 Latch,
643 And { r0: u64, r1: u64, line: usize },
644}
645
646struct Parser<'a> {
647 bytes: &'a [u8],
648 pos: usize,
649 line: usize,
650}
651
652impl Parser<'_> {
653 fn next_line(&mut self) -> Option<String> {
655 if self.pos >= self.bytes.len() {
656 return None;
657 }
658 let end = self.bytes[self.pos..].iter().position(|&b| b == b'\n').map_or(self.bytes.len(), |k| self.pos + k);
659 let text = String::from_utf8_lossy(&self.bytes[self.pos..end]).into_owned();
660 self.pos = end + 1;
661 self.line += 1;
662 Some(text)
663 }
664
665 fn numbers(&mut self, want: std::ops::RangeInclusive<usize>) -> Result<(Vec<u64>, usize), AigerError> {
666 let text = self.next_line().ok_or(AigerError::Truncated)?;
667 let nums: Result<Vec<u64>, _> = text.split_whitespace().map(str::parse::<u64>).collect();
668 match nums {
669 Ok(n) if want.contains(&n.len()) => Ok((n, self.line)),
670 _ => Err(AigerError::Malformed { line: self.line }),
671 }
672 }
673
674 fn varint(&mut self) -> Result<u64, AigerError> {
675 let mut x: u64 = 0;
676 let mut shift = 0;
677 loop {
678 let &b = self.bytes.get(self.pos).ok_or(AigerError::Truncated)?;
679 self.pos += 1;
680 if shift > 56 {
681 return Err(AigerError::Malformed { line: self.line });
682 }
683 x |= ((b & 0x7f) as u64) << shift;
684 if b & 0x80 == 0 {
685 return Ok(x);
686 }
687 shift += 7;
688 }
689 }
690
691 fn parse(mut self) -> Result<Aig, AigerError> {
692 let header = self.next_line().ok_or(AigerError::Truncated)?;
693 let toks: Vec<&str> = header.split_whitespace().collect();
694 let binary = match toks.first() {
695 Some(&"aag") => false,
696 Some(&"aig") => true,
697 _ => return Err(AigerError::Header(format!("expected `aag` or `aig`, read `{header}`"))),
698 };
699 let nums: Vec<u64> = toks[1..]
700 .iter()
701 .map(|t| t.parse::<u64>())
702 .collect::<Result<_, _>>()
703 .map_err(|_| AigerError::Header(format!("non-numeric field in `{header}`")))?;
704 if !(5..=9).contains(&nums.len()) {
705 return Err(AigerError::Header(format!("expected M I L O A [B C J F], read `{header}`")));
706 }
707 let field = |k: usize| nums.get(k).copied().unwrap_or(0);
708 let (m, ni, nl, no, na) = (field(0), field(1), field(2), field(3), field(4));
709 let (nb, nc, nj, nf) = (field(5), field(6), field(7), field(8));
710 if nj > 0 || nf > 0 {
711 return Err(AigerError::Unsupported("justice and fairness properties".into()));
712 }
713 if binary && m != ni + nl + na {
714 return Err(AigerError::Header(format!("a binary file has M = I + L + A, read `{header}`")));
715 }
716 let max_lit = 2 * m + 1;
717 let mut def = vec![Def::None; m as usize + 1];
718 let define = |var: u64, d: Def, line: usize, def: &mut Vec<Def>| -> Result<(), AigerError> {
719 if var == 0 || var > m {
720 return Err(AigerError::Literal { line, literal: var * 2 });
721 }
722 if !matches!(def[var as usize], Def::None) {
723 return Err(AigerError::Redefined { line, var });
724 }
725 def[var as usize] = d;
726 Ok(())
727 };
728 let mut input_vars = Vec::with_capacity(ni as usize);
729 for k in 0..ni {
730 let var = if binary {
731 k + 1
732 } else {
733 let (n, line) = self.numbers(1..=1)?;
734 if n[0] % 2 == 1 || n[0] == 0 || n[0] > 2 * m {
735 return Err(AigerError::Literal { line, literal: n[0] });
736 }
737 define(n[0] / 2, Def::Input, line, &mut def)?;
738 n[0] / 2
739 };
740 if binary {
741 define(var, Def::Input, 0, &mut def)?;
742 }
743 input_vars.push(var);
744 }
745 let mut latch_defs: Vec<(u64, u64, Init, usize)> = Vec::with_capacity(nl as usize);
747 for k in 0..nl {
748 let (n, line) = if binary { self.numbers(1..=2)? } else { self.numbers(2..=3)? };
749 let (lit, rest) = if binary { (2 * (ni + k + 1), &n[..]) } else { (n[0], &n[1..]) };
750 if lit % 2 == 1 || lit == 0 || lit > 2 * m {
751 return Err(AigerError::Literal { line, literal: lit });
752 }
753 let next = rest[0];
754 if next > max_lit {
755 return Err(AigerError::Literal { line, literal: next });
756 }
757 let init = match rest.get(1).copied() {
758 None | Some(0) => Init::Zero,
759 Some(1) => Init::One,
760 Some(x) if x == lit => Init::Free,
761 Some(x) => return Err(AigerError::Literal { line, literal: x }),
762 };
763 define(lit / 2, Def::Latch, line, &mut def)?;
764 latch_defs.push((lit / 2, next, init, line));
765 }
766 let read_ports = |count: u64, this: &mut Self| -> Result<Vec<(u64, usize)>, AigerError> {
767 let mut out = Vec::with_capacity(count as usize);
768 for _ in 0..count {
769 let (n, line) = this.numbers(1..=1)?;
770 if n[0] > max_lit {
771 return Err(AigerError::Literal { line, literal: n[0] });
772 }
773 out.push((n[0], line));
774 }
775 Ok(out)
776 };
777 let outputs = read_ports(no, &mut self)?;
778 let bad = read_ports(nb, &mut self)?;
779 let constraints = read_ports(nc, &mut self)?;
780 let mut and_vars = Vec::with_capacity(na as usize);
781 for k in 0..na {
782 if binary {
783 let lhs = 2 * (ni + nl + k + 1);
784 let d0 = self.varint()?;
785 let d1 = self.varint()?;
786 if d0 == 0 || d0 > lhs || d1 > lhs - d0 {
787 return Err(AigerError::Malformed { line: self.line });
788 }
789 let r0 = lhs - d0;
790 let r1 = r0 - d1;
791 define(lhs / 2, Def::And { r0, r1, line: self.line }, self.line, &mut def)?;
792 and_vars.push(lhs / 2);
793 } else {
794 let (n, line) = self.numbers(3..=3)?;
795 let (lhs, r0, r1) = (n[0], n[1], n[2]);
796 if lhs % 2 == 1 || lhs == 0 || lhs > 2 * m {
797 return Err(AigerError::Literal { line, literal: lhs });
798 }
799 for r in [r0, r1] {
800 if r > max_lit {
801 return Err(AigerError::Literal { line, literal: r });
802 }
803 }
804 define(lhs / 2, Def::And { r0, r1, line }, line, &mut def)?;
805 and_vars.push(lhs / 2);
806 }
807 }
808 let mut aig = Aig::new();
809 let mut map: Vec<Option<AigLit>> = vec![None; m as usize + 1];
810 map[0] = Some(AigLit::FALSE);
811 for &v in &input_vars {
812 map[v as usize] = Some(aig.add_input(None));
813 }
814 for &(v, _, init, _) in &latch_defs {
815 let k = aig.add_latch(None, init);
816 map[v as usize] = Some(aig.latch_lit(k));
817 }
818 let resolve = |map: &[Option<AigLit>], code: u64, line: usize| -> Result<AigLit, AigerError> {
819 map[(code / 2) as usize]
820 .map(|l| l.with_phase(code % 2 == 1))
821 .ok_or(AigerError::Undefined { line, var: code / 2 })
822 };
823 let mut on_path = vec![false; m as usize + 1];
824 for &root in &and_vars {
825 let mut stack: Vec<(u64, bool)> = vec![(root, false)];
826 while let Some((v, expanded)) = stack.pop() {
827 if map[v as usize].is_some() {
828 continue;
829 }
830 let Def::And { r0, r1, line } = def[v as usize] else {
831 return Err(AigerError::Undefined { line: 0, var: v });
832 };
833 if expanded {
834 let a = resolve(&map, r0, line)?;
835 let b = resolve(&map, r1, line)?;
836 map[v as usize] = Some(aig.and(a, b));
837 on_path[v as usize] = false;
838 continue;
839 }
840 if on_path[v as usize] {
841 return Err(AigerError::Cycle { var: v });
842 }
843 on_path[v as usize] = true;
844 stack.push((v, true));
845 for r in [r1, r0] {
846 let c = r / 2;
847 if map[c as usize].is_some() {
848 continue;
849 }
850 match def[c as usize] {
851 Def::And { .. } => {
852 if on_path[c as usize] {
853 return Err(AigerError::Cycle { var: c });
854 }
855 stack.push((c, false));
856 }
857 _ => return Err(AigerError::Undefined { line, var: c }),
858 }
859 }
860 }
861 }
862 for (k, &(_, next, _, line)) in latch_defs.iter().enumerate() {
863 let lit = resolve(&map, next, line)?;
864 aig.set_next(k, lit);
865 }
866 for (code, line) in outputs {
867 let lit = resolve(&map, code, line)?;
868 aig.add_output(lit, None);
869 }
870 for (code, line) in bad {
871 let lit = resolve(&map, code, line)?;
872 aig.add_bad(lit, None);
873 }
874 for (code, line) in constraints {
875 let lit = resolve(&map, code, line)?;
876 aig.add_constraint(lit, None);
877 }
878 while let Some(text) = self.next_line() {
879 if text == "c" {
880 while let Some(c) = self.next_line() {
881 aig.comments.push(c);
882 }
883 break;
884 }
885 if text.is_empty() {
886 continue;
887 }
888 let malformed = AigerError::Malformed { line: self.line };
889 let mut chars = text.chars();
890 let kind = chars.next().ok_or(malformed.clone())?;
891 let rest = chars.as_str();
892 let (pos, name) = rest.split_once(' ').ok_or(malformed.clone())?;
893 let pos: usize = pos.parse().map_err(|_| malformed.clone())?;
894 let slot = match kind {
895 'i' => aig.inputs.get_mut(pos).map(|p| &mut p.name),
896 'l' => aig.latches.get_mut(pos).map(|l| &mut l.name),
897 'o' => aig.outputs.get_mut(pos).map(|p| &mut p.name),
898 'b' => aig.bad.get_mut(pos).map(|p| &mut p.name),
899 'c' => aig.constraints.get_mut(pos).map(|p| &mut p.name),
900 _ => None,
901 };
902 *slot.ok_or(malformed)? = Some(name.to_string());
903 }
904 Ok(aig)
905 }
906}
907
908#[cfg(test)]
909#[path = "../../logicaffeine_tests/unit/logicaffeine_proof/aig/tests.rs"]
910mod tests;