oxidd_parser/lib.rs
1//! Collection of parsers for various logical problem formats
2//!
3//! Every format is parsed into a [`Circuit`], i.e., a propositional formula
4//! with structure sharing, to enable (mostly) uniform handling of different
5//! formats in an application.
6//!
7//! ## Example
8//!
9//! ```no_run
10//! # use oxidd_parser::*;
11//! let parse_options = ParseOptionsBuilder::default().build().unwrap();
12//! let Some(problem) = load_file("foo.dimacs", &parse_options) else {
13//! return; // an error message has been printed to stderr
14//! };
15//! println!("circuit: {:?}", problem.circuit);
16//! println!("additional details: {:?}", problem.details);
17//! ```
18//!
19//! ## Feature flags
20#![doc = document_features::document_features!()]
21#![forbid(unsafe_code)]
22#![warn(missing_docs)]
23#![allow(clippy::type_complexity)]
24
25use std::collections::hash_map::Entry;
26use std::fmt::{self, Write};
27
28use bitvec::{slice::BitSlice, vec::BitVec};
29use bumpalo::boxed::Box as BumpBox;
30use bumpalo::collections::Vec as BumpVec;
31use derive_builder::Builder;
32use rustc_hash::FxHashMap;
33
34pub mod aiger;
35pub mod dimacs;
36pub mod nnf;
37mod tv_bitvec;
38mod util;
39mod vec2d;
40
41use tv_bitvec::TVBitVec;
42pub use vec2d::{Vec2d, Vec2dIter};
43
44#[cfg(feature = "load-file")]
45mod load_file;
46#[cfg(feature = "load-file")]
47pub use load_file::*;
48
49/// Variable type
50///
51/// The two most significant bits are never set.
52pub type Var = usize;
53
54/// A possibly negated variable
55///
56/// There are three kinds of variables: constants ([`Literal::FALSE`] and
57/// [`Literal::TRUE`]), circuit inputs, and gates.
58///
59/// Concerning ordering, the following properties hold: Given two [`Literal`]s
60/// `a, b`, `a <= b` is equivalent to the lexicographic comparison
61/// `(a.positive(), a.is_negative()) <= (b.positive(), b.is_negative())`.
62/// Furthermore, `Literal::FALSE <= a` holds (and thus `Literal::TRUE <= a` if
63/// `a != Literal::FALSE`).
64#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
65pub struct Literal(usize);
66
67impl Literal {
68 // We rely on POLARITY_BIT being the least significant bit for the ordering
69 const POLARITY_BIT: u32 = 0;
70 const GATE_BIT: u32 = 1;
71 const VAR_LSB: u32 = 2;
72
73 /// Maximum input number representable as literal
74 pub const MAX_INPUT: usize = (usize::MAX >> Self::VAR_LSB) - 2;
75 /// Maximum gate number representable as literal
76 pub const MAX_GATE: usize = usize::MAX >> Self::VAR_LSB;
77
78 /// Literal representing the constant `⊥`
79 ///
80 /// This is literal is considered to be positive (i.e., not negated):
81 ///
82 /// ```
83 /// # use oxidd_parser::Literal;
84 /// assert!(Literal::FALSE.is_positive());
85 /// assert!(Literal::FALSE < Literal::TRUE);
86 /// ```
87 pub const FALSE: Self = Self(0);
88 /// Literal representing the constant `⊤`
89 ///
90 /// This is literal is considered to be negated:
91 ///
92 /// ```
93 /// # use oxidd_parser::Literal;
94 /// assert!(Literal::TRUE.is_negative());
95 /// assert!(Literal::TRUE < Literal::from_input(false, 0));
96 /// assert!(Literal::TRUE < Literal::from_gate(false, 0));
97 /// ```
98 pub const TRUE: Self = Self(1 << Self::POLARITY_BIT);
99
100 /// Undefined literal
101 ///
102 /// This is considered to be a positive (i.e., not negated) input, but its
103 /// variable number is larger than `Self::MAX_INPUT`. Attempting to create
104 /// this literal using [`Self::from_input()`] will trigger a debug
105 /// assertion.
106 ///
107 /// ```
108 /// # use oxidd_parser::Literal;
109 /// assert!(Literal::UNDEF.is_positive());
110 /// assert!(Literal::UNDEF.is_input());
111 /// assert_eq!(Literal::UNDEF.get_input(), Some(Literal::MAX_INPUT + 1));
112 /// ```
113 pub const UNDEF: Self = Self((Self::MAX_INPUT + 2) << Self::VAR_LSB);
114
115 /// Create a new literal from an input variable
116 #[track_caller]
117 #[inline]
118 pub const fn from_input(negative: bool, input: Var) -> Self {
119 debug_assert!(input <= Self::MAX_INPUT, "input too large");
120 Self(((input + 1) << Self::VAR_LSB) | ((negative as usize) << Self::POLARITY_BIT))
121 }
122
123 /// Create a new literal from an input variable (value range `1..`) or false
124 /// (`0`)
125 #[track_caller]
126 #[inline]
127 const fn from_input_or_false(negative: bool, input: Var) -> Self {
128 debug_assert!(input <= Self::MAX_INPUT + 1, "input too large");
129 Self((input << Self::VAR_LSB) | ((negative as usize) << Self::POLARITY_BIT))
130 }
131
132 /// Create a new literal from a gate number
133 #[track_caller]
134 #[inline]
135 pub const fn from_gate(negative: bool, gate: Var) -> Self {
136 debug_assert!(gate <= Self::MAX_GATE, "gate number too large");
137 Self(
138 (gate << Self::VAR_LSB)
139 | (1 << Self::GATE_BIT)
140 | ((negative as usize) << Self::POLARITY_BIT),
141 )
142 }
143
144 /// Is the literal positive?
145 ///
146 /// Same as [`!self.is_negative()`][Self::is_negative]
147 ///
148 /// ```
149 /// # use oxidd_parser::Literal;
150 /// assert!(Literal::from_input(false, 42).is_positive());
151 /// assert!(!Literal::from_input(true, 1337).is_positive());
152 /// ```
153 #[inline(always)]
154 pub const fn is_positive(self) -> bool {
155 self.0 & (1 << Self::POLARITY_BIT) == 0
156 }
157 /// Is the literal negative?
158 ///
159 /// Same as [`!self.is_positive()`][Self::is_positive]
160 ///
161 /// ```
162 /// # use oxidd_parser::Literal;
163 /// assert!(Literal::from_gate(true, 42).is_negative());
164 /// assert!(!Literal::from_gate(false, 1337).is_negative());
165 /// ```
166 #[inline(always)]
167 pub const fn is_negative(self) -> bool {
168 !self.is_positive()
169 }
170
171 /// Get the positive variant of this literal
172 ///
173 /// ```
174 /// # use oxidd_parser::Literal;
175 /// assert!(Literal::from_input(true, 42).positive().is_positive());
176 /// ```
177 #[inline(always)]
178 pub const fn positive(self) -> Self {
179 Self(self.0 & !(1 << Self::POLARITY_BIT))
180 }
181
182 /// Get the negative variant of this literal
183 ///
184 /// ```
185 /// # use oxidd_parser::Literal;
186 /// assert_eq!(Literal::from_input(true, 42), Literal::from_input(false, 42).negative());
187 /// assert!(Literal::from_input(false, 42).negative().is_negative());
188 /// ```
189 #[inline(always)]
190 pub const fn negative(self) -> Self {
191 Self(self.0 | (1 << Self::POLARITY_BIT))
192 }
193
194 /// Does this literal refer to an input?
195 ///
196 /// ```
197 /// # use oxidd_parser::Literal;
198 /// assert!(Literal::from_input(false, 42).is_input());
199 /// assert!(!Literal::FALSE.is_input());
200 /// assert!(!Literal::TRUE.is_input());
201 /// assert!(!Literal::from_gate(false, 1337).is_input());
202 /// ```
203 #[inline(always)]
204 pub const fn is_input(self) -> bool {
205 self.get_input().is_some()
206 }
207
208 /// Check if this literal refers to a gate
209 ///
210 /// ```
211 /// # use oxidd_parser::Literal;
212 /// assert!(Literal::from_gate(false, 42).is_gate());
213 /// assert!(!Literal::FALSE.is_gate());
214 /// assert!(!Literal::TRUE.is_gate());
215 /// assert!(!Literal::from_input(false, 1337).is_gate());
216 /// ```
217 #[inline(always)]
218 pub const fn is_gate(self) -> bool {
219 self.0 & (1 << Self::GATE_BIT) != 0
220 }
221
222 /// Get the input number (if this literal refers to an input)
223 ///
224 /// ```
225 /// # use oxidd_parser::Literal;
226 /// assert_eq!(Literal::from_input(false, 42).get_input(), Some(42));
227 /// assert_eq!(Literal::FALSE.get_input(), None);
228 /// assert_eq!(Literal::TRUE.get_input(), None);
229 /// assert_eq!(Literal::from_gate(false, 42).get_input(), None);
230 /// ```
231 #[inline]
232 pub const fn get_input(self) -> Option<Var> {
233 if self.is_gate() {
234 return None;
235 }
236 (self.0 >> Self::VAR_LSB).checked_sub(1)
237 }
238
239 /// Get the gate number (if this literal refers to an input)
240 ///
241 /// ```
242 /// # use oxidd_parser::Literal;
243 /// assert_eq!(Literal::from_gate(false, 42).get_gate_no(), Some(42));
244 /// assert_eq!(Literal::FALSE.get_gate_no(), None);
245 /// assert_eq!(Literal::TRUE.get_gate_no(), None);
246 /// assert_eq!(Literal::from_input(false, 42).get_gate_no(), None);
247 /// ```
248 ///
249 /// See also: [`Circuit::gate()`]
250 #[inline]
251 pub const fn get_gate_no(self) -> Option<Var> {
252 if self.is_gate() {
253 return Some(self.0 >> Self::VAR_LSB);
254 }
255 None
256 }
257
258 /// Map this literal based on `gate_map`
259 ///
260 /// If this literal refers to a gate, the method performs a lookup for the
261 /// gate number in `gate_map`. If the gate number is in bounds, the return
262 /// value is the mapped literal with its sign adjusted, otherwise the return
263 /// value is [`Literal::UNDEF`]. Non-gate literals are returned as they are.
264 #[inline]
265 pub fn apply_gate_map(self, gate_map: &[Literal]) -> Self {
266 if let Some(gate) = self.get_gate_no() {
267 if let Some(mapped) = gate_map.get(gate) {
268 *mapped ^ self.is_negative()
269 } else {
270 Self::UNDEF
271 }
272 } else {
273 self
274 }
275 }
276}
277
278impl fmt::Display for Literal {
279 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
280 let i = self.0 >> Literal::VAR_LSB;
281 let (kind, i) = if self.0 & (1 << Self::GATE_BIT) != 0 {
282 ('g', i)
283 } else {
284 if i == 0 {
285 return f.write_char(if self.is_positive() { '⊤' } else { '⊥' });
286 }
287 if i == Literal::MAX_INPUT + 2 {
288 return f.write_str(if self.is_positive() { "+U" } else { "-U" });
289 }
290 ('i', i - 1)
291 };
292
293 let sign = if self.is_positive() { '+' } else { '-' };
294 write!(f, "{sign}{kind}{i}")
295 }
296}
297impl fmt::Debug for Literal {
298 #[inline(always)]
299 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
300 <Self as fmt::Display>::fmt(self, f)
301 }
302}
303
304impl std::ops::Not for Literal {
305 type Output = Self;
306
307 fn not(self) -> Self {
308 Self(self.0 ^ (1 << Self::POLARITY_BIT))
309 }
310}
311
312impl std::ops::BitXor<bool> for Literal {
313 type Output = Self;
314
315 #[inline(always)]
316 fn bitxor(self, rhs: bool) -> Self::Output {
317 Self(self.0 ^ ((rhs as usize) << Self::POLARITY_BIT))
318 }
319}
320
321/// Rooted tree with values of type `T` at the leaves
322#[allow(missing_docs)]
323#[derive(Clone, PartialEq, Eq, Debug)]
324pub enum Tree<T> {
325 Inner(Box<[Tree<T>]>),
326 Leaf(T),
327}
328
329impl<T: Clone> Tree<T> {
330 fn flatten_into(&self, into: &mut Vec<T>) {
331 match self {
332 Tree::Inner(sub) => sub.iter().for_each(|t| t.flatten_into(into)),
333 Tree::Leaf(v) => into.push(v.clone()),
334 }
335 }
336}
337
338/// Problem that may be returned by the problem parsers
339#[derive(Clone, PartialEq, Eq, Debug)]
340pub struct Problem {
341 /// Combinational circuit as the core of the problem
342 pub circuit: Circuit,
343
344 /// Additional details on the problem
345 pub details: ProblemDetails,
346}
347
348impl Problem {
349 /// Simplify the circuit (see [`Circuit::simplify()`]), and map the gate
350 /// literals in the additional problem details accordingly
351 ///
352 /// If the reachable circuit fragment contains a cycle, this method returns
353 /// `Err(l)`, where `l` represents a gate that is part of the cycle.
354 ///
355 /// On success, `simplify()` returns the simplified problem along with a
356 /// `Vec<Literal>` which maps the gates of `self` to literals valid in the
357 /// simplified circuit. The simplified circuit only contains gates reachable
358 /// from the problem details (except for the
359 /// [AIGER literal map][AIGERDetails::map_aiger_literal]).
360 pub fn simplify(&self) -> Result<(Self, Vec<Literal>), Literal> {
361 let (circuit, map) = match &self.details {
362 ProblemDetails::Root(l) => self.circuit.simplify([*l]),
363 ProblemDetails::AIGER(aig) => {
364 let aig = &**aig;
365 self.circuit.simplify(
366 aig.latches
367 .iter()
368 .chain(aig.outputs.iter())
369 .chain(aig.bad.iter())
370 .chain(aig.invariants.iter())
371 .chain(aig.justice.all_elements().iter())
372 .chain(aig.fairness.iter())
373 .copied(),
374 )
375 }
376 }?;
377 let new_problem = Self {
378 circuit,
379 details: self.details.apply_gate_map(&map),
380 };
381 Ok((new_problem, map))
382 }
383}
384
385/// Details of a [`Problem`] in addition to the circuit structure
386#[derive(Clone, PartialEq, Eq, Debug)]
387pub enum ProblemDetails {
388 /// Simple circuit with a single root
389 Root(Literal),
390 /// Details from the AIGER format
391 AIGER(Box<AIGERDetails>),
392}
393
394impl ProblemDetails {
395 /// Map the literals in `self` based on `gate_map`
396 ///
397 /// See [`Literal::apply_gate_map()`] for more details.
398 pub fn apply_gate_map(&self, map: &[Literal]) -> Self {
399 match self {
400 ProblemDetails::Root(l) => ProblemDetails::Root(l.apply_gate_map(map)),
401 ProblemDetails::AIGER(aig) => ProblemDetails::AIGER(Box::new(aig.apply_gate_map(map))),
402 }
403 }
404
405 /// In-place version of [`Self::apply_gate_map()`]
406 pub fn apply_gate_map_in_place(&mut self, map: &[Literal]) {
407 match self {
408 ProblemDetails::Root(l) => *l = l.apply_gate_map(map),
409 ProblemDetails::AIGER(aig) => aig.apply_gate_map_in_place(map),
410 }
411 }
412}
413
414/// Variable set, potentially along with a variable order and variable names
415///
416/// The variable numbers are in range `0..self.len()`.
417#[derive(Clone, PartialEq, Eq, Debug)]
418pub struct VarSet {
419 /// Number of variables
420 len: usize,
421
422 /// Permutation of the variables. `order[0]` is supposed to be the number of
423 /// the top-most variable.
424 order: Vec<Var>,
425 /// If present, `order` is just the flattened tree
426 order_tree: Option<Tree<Var>>,
427
428 /// Mapping from variable numbers to optional names. Has minimal length,
429 /// i.e., `names.last() != Some(&None)`.
430 names: Vec<Option<String>>,
431}
432
433impl VarSet {
434 /// Create a variable set without a variable order and names
435 #[inline(always)]
436 pub const fn new(n: usize) -> Self {
437 Self {
438 len: n,
439 order: Vec::new(),
440 order_tree: None,
441 names: Vec::new(),
442 }
443 }
444
445 /// Create a variable set with the given names
446 ///
447 /// The number of variables is given by `names.len()`.
448 pub fn with_names(mut names: Vec<Option<String>>) -> Self {
449 let len = names.len();
450 while let Some(None) = names.last() {
451 names.pop();
452 }
453 Self {
454 len,
455 order: Vec::new(),
456 order_tree: None,
457 names,
458 }
459 }
460
461 /// Number of variables
462 #[inline(always)]
463 pub fn len(&self) -> usize {
464 self.len
465 }
466
467 /// Returns true iff the number of variables is 0
468 #[inline(always)]
469 pub fn is_empty(&self) -> bool {
470 self.len == 0
471 }
472
473 /// Get the linear variable order, if present
474 ///
475 /// If [`self.order_tree()`][Self::order_tree] is not `None`, then it is the
476 /// flattened tree.
477 #[inline]
478 pub fn order(&self) -> Option<&[Var]> {
479 if self.len != self.order.len() {
480 None
481 } else {
482 Some(&self.order)
483 }
484 }
485
486 /// Get the tree of variable groups, if present
487 ///
488 /// This may be useful for, e.g., group sifting.
489 #[inline]
490 pub fn order_tree(&self) -> Option<&Tree<Var>> {
491 self.order_tree.as_ref()
492 }
493
494 /// Get the name for variable `var`
495 #[inline]
496 pub fn name(&self, var: Var) -> Option<&str> {
497 self.names.get(var)?.as_deref()
498 }
499 /// Set the name for variable `var`. Returns the previous name.
500 #[track_caller]
501 pub fn set_name(&mut self, var: Var, name: impl Into<String>) -> Option<String> {
502 if var >= self.names.len() {
503 if var >= self.len {
504 return None;
505 }
506 self.names.resize(var + 1, None);
507 }
508 self.names[var].replace(name.into())
509 }
510
511 #[allow(unused)]
512 fn check_valid(&self) {
513 assert!(self.order.is_empty() || self.order.len() == self.len);
514 assert!(!self.order.is_empty() || self.order_tree.is_none());
515 assert_ne!(self.names.last(), Some(&None));
516 }
517}
518
519type GateVec2d = vec2d::with_metadata::Vec2d<Literal, { Circuit::GATE_METADATA_BITS }>;
520
521/// Combinational circuit with negation as well as n-ary AND, OR, and XOR gates
522#[derive(Clone, PartialEq, Eq)]
523pub struct Circuit {
524 inputs: VarSet,
525 gates: GateVec2d,
526}
527
528/// Logical gate including the literals representing its inputs
529///
530/// This enum type includes the phony gate variants `False` (representing the
531/// constant false) and `Input` (for a circuit input). This is mainly to make
532/// using [`Circuit::gate()`] more ergonomic.
533#[allow(missing_docs)]
534#[derive(Clone, Copy, PartialEq, Eq)]
535pub struct Gate<'a> {
536 pub kind: GateKind,
537 pub inputs: &'a [Literal],
538}
539
540impl fmt::Debug for Gate<'_> {
541 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542 let mut builder = f.debug_tuple(match self.kind {
543 GateKind::And => "and",
544 GateKind::Or => "or",
545 GateKind::Xor => "xor",
546 });
547 for literal in self.inputs {
548 builder.field(literal);
549 }
550 builder.finish()
551 }
552}
553
554#[allow(unused)] // used in tests
555impl<'a> Gate<'a> {
556 const fn and(inputs: &'a [Literal]) -> Self {
557 Self {
558 kind: GateKind::And,
559 inputs,
560 }
561 }
562 const fn or(inputs: &'a [Literal]) -> Self {
563 Self {
564 kind: GateKind::Or,
565 inputs,
566 }
567 }
568 const fn xor(inputs: &'a [Literal]) -> Self {
569 Self {
570 kind: GateKind::Xor,
571 inputs,
572 }
573 }
574}
575
576/// Kind of a logical gate in a [`Circuit`]
577#[allow(missing_docs)]
578#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
579pub enum GateKind {
580 And,
581 Or,
582 Xor,
583}
584
585impl GateKind {
586 /// Get the literal representing a gate of this kind without any inputs
587 const fn empty_gate(self) -> Literal {
588 match self {
589 GateKind::And => Literal::TRUE,
590 GateKind::Or | GateKind::Xor => Literal::FALSE,
591 }
592 }
593}
594
595impl From<usize> for GateKind {
596 fn from(value: usize) -> Self {
597 match value {
598 _ if value == GateKind::And as usize => GateKind::And,
599 _ if value == GateKind::Or as usize => GateKind::Or,
600 _ => GateKind::Xor,
601 }
602 }
603}
604
605impl Circuit {
606 const GATE_METADATA_BITS: u32 = 2;
607
608 /// Create an empty circuit with the given circuit inputs
609 #[inline(always)]
610 pub fn new(inputs: VarSet) -> Self {
611 Self {
612 inputs,
613 gates: Default::default(),
614 }
615 }
616
617 /// Get the circuit inputs
618 #[inline(always)]
619 pub fn inputs(&self) -> &VarSet {
620 &self.inputs
621 }
622 /// Get a mutable reference to the circuit inputs
623 #[inline(always)]
624 pub fn inputs_mut(&mut self) -> &mut VarSet {
625 &mut self.inputs
626 }
627
628 /// Reserve space for at least `additional` more gates. Note that this will
629 /// not reserve space for gate inputs. To that end, use
630 /// [`Self::reserve_gate_inputs()`].
631 ///
632 /// This is essentially a wrapper around [`Vec::reserve()`], so the
633 /// documentation there provides more details.
634 #[inline(always)]
635 pub fn reserve_gates(&mut self, additional: usize) {
636 self.gates.reserve_vectors(additional);
637 }
638
639 /// Reserve space for at least `additional` more gate inputs (the space is
640 /// shared between all gates). Note that this will not reserve space for
641 /// the gate metadata. To that end, use [`Self::reserve_gates()`].
642 ///
643 /// This is essentially a wrapper around [`Vec::reserve()`], so the
644 /// documentation there provides more details.
645 #[inline(always)]
646 pub fn reserve_gate_inputs(&mut self, additional: usize) {
647 self.gates.reserve_elements(additional);
648 }
649
650 /// Get the number of gates in this circuit
651 #[inline(always)]
652 pub fn num_gates(&self) -> usize {
653 self.gates.len()
654 }
655
656 /// Get the [`Gate`] for `literal`
657 ///
658 /// Returns [`None`] iff `literal` refers to a constant, a circuit input, or
659 /// a gate that is not present in this circuit.
660 ///
661 /// See also: [`Self::gate_for_no()`]
662 #[inline]
663 pub fn gate(&self, literal: Literal) -> Option<Gate> {
664 self.gate_for_no(literal.get_gate_no()?)
665 }
666
667 /// Get the [`Gate`] for `gate_no`
668 ///
669 /// Returns [`None`] iff `literal` refers to a gate that is not present in
670 /// this circuit.
671 ///
672 /// See also: [`Self::gate()`]
673 pub fn gate_for_no(&self, gate_no: Var) -> Option<Gate> {
674 if let Some((kind, inputs)) = self.gates.get(gate_no) {
675 Some(Gate {
676 kind: kind.into(),
677 inputs,
678 })
679 } else {
680 None
681 }
682 }
683
684 /// Get a mutable reference to the gate inputs
685 ///
686 /// Returns [`None`] iff `literal` refers to a constant, a circuit input, or
687 /// a gate that is not present in this circuit.
688 #[inline]
689 pub fn gate_inputs_mut(&mut self, literal: Literal) -> Option<&mut [Literal]> {
690 self.gates.get_mut(literal.get_gate_no()?)
691 }
692
693 /// Get a mutable reference to the gate inputs
694 ///
695 /// Returns [`None`] iff `literal` refers to a constant, a circuit input, or
696 /// a gate that is not present in this circuit.
697 #[inline(always)]
698 pub fn gate_inputs_mut_for_no(&mut self, gate_no: Var) -> Option<&mut [Literal]> {
699 self.gates.get_mut(gate_no)
700 }
701
702 /// Set the kind of the gate referenced by `literal`
703 ///
704 /// Panics if `literal` does not refer to a gate in this circuit.
705 #[track_caller]
706 #[inline]
707 pub fn set_gate_kind(&mut self, literal: Literal, kind: GateKind) {
708 self.gates.set_metadata(
709 literal
710 .get_gate_no()
711 .expect("`literal` must refer to a gate"),
712 kind as usize,
713 );
714 }
715
716 /// Set the kind of the gate referenced by `gate_no`
717 ///
718 /// Panics if `literal` does not refer to a gate in this circuit.
719 #[track_caller]
720 #[inline(always)]
721 pub fn set_gate_kind_for_no(&mut self, gate_no: Var, kind: GateKind) {
722 self.gates.set_metadata(gate_no, kind as usize);
723 }
724
725 /// Set the kind of the gate referenced by `literal`
726 ///
727 /// Panics if the circuit is empty.
728 #[track_caller]
729 #[inline]
730 pub fn set_last_gate_kind(&mut self, kind: GateKind) {
731 let n = self.gates.len();
732 if n == 0 {
733 panic!("there are no gates in the circuit");
734 }
735 self.gates.set_metadata(n - 1, kind as usize);
736 }
737
738 /// Get the first gate
739 ///
740 /// Returns [`None`] iff `literal` refers to a constant, a circuit input, or
741 /// a gate that is not present in this circuit.
742 pub fn first_gate(&self) -> Option<Gate> {
743 let (kind, inputs) = self.gates.first()?;
744 Some(Gate {
745 kind: kind.into(),
746 inputs,
747 })
748 }
749
750 /// Get the last gate
751 ///
752 /// Returns [`None`] iff `literal` refers to a constant, a circuit input, or
753 /// a gate that is not present in this circuit.
754 pub fn last_gate(&self) -> Option<Gate> {
755 let (kind, inputs) = self.gates.last()?;
756 Some(Gate {
757 kind: kind.into(),
758 inputs,
759 })
760 }
761
762 /// Create a new empty gate at the end of the sequence
763 pub fn push_gate(&mut self, kind: GateKind) -> Literal {
764 let l = Literal::from_gate(false, self.gates.len());
765 self.gates.push_vec(kind as _);
766 l
767 }
768
769 /// Remove the last gate (if there is one)
770 ///
771 /// Returns true iff the number of gates was positive before removal.
772 #[inline(always)]
773 pub fn pop_gate(&mut self) -> bool {
774 self.gates.pop_vec()
775 }
776
777 /// Add an input to the last gate
778 ///
779 /// There must be already one gate in the circuit, otherwise this method
780 /// triggers a debug assertion or does not do anything, respectively.
781 #[inline(always)]
782 #[track_caller]
783 pub fn push_gate_input(&mut self, literal: Literal) {
784 self.gates.push_element(literal);
785 }
786
787 /// Add inputs to the last gate
788 ///
789 /// There must be already one gate in the circuit, otherwise this method
790 /// triggers a debug assertion or does not do anything, respectively.
791 #[inline(always)]
792 #[track_caller]
793 pub fn push_gate_inputs(&mut self, literals: impl IntoIterator<Item = Literal>) {
794 self.gates.push_elements(literals);
795 }
796
797 /// Iterate over all gates in the circuit
798 ///
799 /// The iteration order is from first to last in the gate sequence.
800 #[inline(always)]
801 pub fn iter_gates(&self) -> CircuitGateIter {
802 CircuitGateIter(self.gates.iter())
803 }
804
805 /// Retain the gates for which `predicate` returns `true`
806 ///
807 /// Note that removing one gate changes the gate numbers of all subsequent
808 /// gates, but this method does not automatically update the gate inputs.
809 #[inline]
810 pub fn retain_gates(&mut self, mut predicate: impl FnMut(&mut [Literal]) -> bool) {
811 self.gates.retain(move |_, inputs| predicate(inputs))
812 }
813
814 /// Remove all gate definitions from the circuit
815 #[inline(always)]
816 pub fn clear_gates(&mut self) {
817 self.gates.clear();
818 }
819
820 /// Check if this circuit is acyclic
821 ///
822 /// Returns [`None`] if acyclic, or [`Some(literal)`][Some] if `literal`
823 /// depends on itself.
824 pub fn find_cycle(&self) -> Option<Literal> {
825 let mut visited = BitVec::repeat(false, self.gates.len() * 2);
826
827 fn inner(gates: &GateVec2d, visited: &mut BitSlice, index: usize) -> bool {
828 if visited[index * 2 + 1] {
829 return false; // finished
830 }
831 if visited[index * 2] {
832 return true; // discovered -> cycle
833 }
834 visited.set(index * 2, true); // discovered
835
836 for &l in gates.get(index).unwrap().1 {
837 if l.is_gate() && inner(gates, visited, l.0 >> Literal::VAR_LSB) {
838 return true;
839 }
840 }
841
842 visited.set(index * 2 + 1, true); // finished
843 false
844 }
845
846 for index in 0..self.gates.len() {
847 if inner(&self.gates, visited.as_mut_bitslice(), index) {
848 return Some(Literal::from_gate(false, index));
849 }
850 }
851 None
852 }
853
854 /// Simplify the circuit such that
855 ///
856 /// 1. no gate has constant inputs
857 /// 2. no inputs of XOR gates are negated (only the output)
858 /// 3. for every gate, all its inputs are distinct (disregarding polarities)
859 /// 4. all gates have at least two inputs
860 /// 5. there are no two structurally equivalent gates (same kind and inputs,
861 /// disregarding the input order)
862 ///
863 /// Additionally, the new circuit will only contain gates reachable from
864 /// `roots`. The order of gate inputs in the resulting circuit follows the
865 /// order of the first discovered equivalent gate (with duplicates etc.
866 /// removed).
867 ///
868 /// If the reachable circuit fragment contains a cycle, this method returns
869 /// `Err(l)`, where `l` represents a gate that is part of the cycle.
870 /// Likewise, if the reachable fragment depends on unknown inputs
871 /// (`input_number >= self.inputs().len()`, including [`Literal::UNDEF`]),
872 /// the return value is `Err(l)`, where `l` is the unknown literal.
873 ///
874 /// On success, the gates in the returned circuit are topologically sorted.
875 /// The additional `Vec<Literal>` maps the gates of `self` to literals valid
876 /// in the simplified circuit.
877 ///
878 /// Hint: [`Problem::simplify`] uses this method to simplify the circuit and
879 /// also maps the
880 pub fn simplify(
881 &self,
882 roots: impl IntoIterator<Item = Literal>,
883 ) -> Result<(Self, Vec<Literal>), Literal> {
884 const DISCOVERED: Literal = Literal::UNDEF.negative();
885
886 let bump = bumpalo::Bump::new();
887 let mut gate_map = Vec::new();
888 gate_map.resize(self.gates.len(), Literal::UNDEF);
889 let mut input_set = BitVec::repeat(false, 2 * (self.gates.len() + self.inputs.len()));
890 let mut new_gates: GateVec2d =
891 GateVec2d::with_capacity(self.gates.len(), self.gates.all_elements().len());
892 let mut unique_map = FxHashMap::default();
893 unique_map.reserve(self.gates.len());
894
895 fn inner<'a>(
896 bump: &'a bumpalo::Bump,
897 gates: &GateVec2d,
898 index: usize,
899 input_set: &mut BitSlice,
900 unique_map: &mut FxHashMap<(GateKind, BumpBox<'a, [Literal]>), Literal>,
901 new_gates: &mut GateVec2d,
902 gate_map: &mut [Literal],
903 ) -> Result<(), Literal> {
904 if gate_map[index] == DISCOVERED {
905 // discovered -> cycle
906 return Err(Literal::from_gate(false, index));
907 }
908 if gate_map[index] != Literal::UNDEF {
909 return Ok(()); // finished
910 }
911 gate_map[index] = DISCOVERED;
912
913 let (meta, inputs) = gates.get(index).unwrap();
914 let kind = GateKind::from(meta);
915
916 for &l in inputs {
917 if let Some(gate) = l.get_gate_no() {
918 inner(
919 bump, gates, gate, input_set, unique_map, new_gates, gate_map,
920 )?;
921 }
922 }
923
924 // apply `gate_map` to the inputs and establish conditions 1+2
925 let mut neg_out = false;
926 let mut mapped = BumpVec::with_capacity_in(inputs.len(), bump);
927 let known_inputs = input_set.len() - gates.len();
928 match kind {
929 GateKind::And | GateKind::Or => {
930 let (identity, dominator) = match kind {
931 GateKind::And => (Literal::TRUE, Literal::FALSE),
932 GateKind::Or => (Literal::FALSE, Literal::TRUE),
933 _ => unreachable!(),
934 };
935 for &l in inputs {
936 let l = l.get_gate_no().map_or(l, |i| gate_map[i] ^ l.is_negative());
937 if l.is_input() && l.get_input().unwrap() > known_inputs {
938 return Err(l);
939 }
940 if l == dominator {
941 gate_map[index] = dominator;
942 return Ok(());
943 }
944 if l != identity {
945 mapped.push(l);
946 }
947 }
948 }
949 GateKind::Xor => {
950 for &l in inputs {
951 neg_out ^= l.is_negative(); // negate for every flip
952 let l = if let Some(i) = l.get_gate_no() {
953 let l = gate_map[i];
954 neg_out ^= l.is_negative();
955 l.positive()
956 } else {
957 let l = l.positive();
958 debug_assert!(l != Literal::TRUE);
959 if l == Literal::FALSE {
960 continue; // x ⊕ ⊥ ≡ x
961 }
962 l
963 };
964 if l.is_input() && l.get_input().unwrap() > known_inputs {
965 return Err(l);
966 }
967 mapped.push(l);
968 }
969 }
970 };
971 let mut inputs = mapped;
972
973 // first part of condition 4
974 if inputs.is_empty() {
975 gate_map[index] = match kind {
976 GateKind::And => Literal::TRUE,
977 GateKind::Or => Literal::FALSE,
978 GateKind::Xor => Literal::TRUE ^ neg_out,
979 };
980 return Ok(());
981 }
982
983 // condition 3 with fast-path for exactly two different inputs
984 if inputs.len() >= 3
985 || (inputs.len() == 2 && inputs[0].negative() == inputs[1].negative())
986 {
987 let no_gate_add = 2 * gates.len() - 2; // -2 for constants
988 let map = move |l: Literal| {
989 const { assert!(Literal::POLARITY_BIT == 0) };
990 let i = ((l.0 >> Literal::VAR_LSB) << 1) | (l.0 & (1 << Literal::POLARITY_BIT));
991 if l.is_gate() {
992 i
993 } else {
994 i + no_gate_add
995 }
996 };
997
998 match kind {
999 GateKind::And | GateKind::Or => {
1000 for (i, &l) in inputs.iter().enumerate() {
1001 if input_set[map(!l)] {
1002 // found complement literal -> clear `input_set` and return ⊥/⊤
1003 for &l in &inputs[..i] {
1004 input_set.set(map(l), false);
1005 }
1006 gate_map[index] = match kind {
1007 GateKind::And => Literal::FALSE, // x ∧ ¬x ≡ ⊥
1008 GateKind::Or => Literal::TRUE, // x ∨ ¬x ≡ ⊤
1009 _ => unreachable!(),
1010 };
1011 return Ok(());
1012 }
1013 input_set.set(map(l), true);
1014 }
1015 }
1016 GateKind::Xor => {
1017 for &l in &inputs {
1018 let i = map(l);
1019 input_set.set(i, !input_set[i]);
1020 }
1021 }
1022 }
1023
1024 inputs.retain(|&l| {
1025 let i = map(l);
1026 if input_set[i] {
1027 input_set.set(i, false);
1028 true
1029 } else {
1030 false
1031 }
1032 });
1033 }
1034 // second part of condition 4
1035 if let [l] = &inputs[..] {
1036 gate_map[index] = *l ^ neg_out;
1037 return Ok(());
1038 }
1039
1040 // save the children in the current order and sort
1041 let new_gate_no = new_gates.len();
1042 new_gates.push_vec(kind as usize);
1043 new_gates.push_elements(inputs.iter().copied());
1044 inputs.sort_unstable();
1045
1046 let l = match unique_map.entry((kind, inputs.into_boxed_slice())) {
1047 Entry::Occupied(e) => {
1048 new_gates.pop_vec();
1049 *e.get()
1050 }
1051 Entry::Vacant(e) => *e.insert(Literal::from_gate(false, new_gate_no)),
1052 };
1053 gate_map[index] = l ^ neg_out;
1054
1055 Ok(())
1056 }
1057
1058 for root in roots {
1059 if let Some(i) = root.get_gate_no() {
1060 inner(
1061 &bump,
1062 &self.gates,
1063 i,
1064 &mut input_set,
1065 &mut unique_map,
1066 &mut new_gates,
1067 &mut gate_map,
1068 )?;
1069 }
1070 }
1071
1072 let new_circuit = Self {
1073 inputs: self.inputs.clone(),
1074 gates: new_gates,
1075 };
1076 Ok((new_circuit, gate_map))
1077 }
1078}
1079
1080/// Iterator returned by [`Circuit::iter_gates()`]
1081#[derive(Clone)]
1082pub struct CircuitGateIter<'a>(
1083 vec2d::with_metadata::Vec2dIter<'a, Literal, { Circuit::GATE_METADATA_BITS }>,
1084);
1085
1086impl<'a> Iterator for CircuitGateIter<'a> {
1087 type Item = Gate<'a>;
1088
1089 #[inline]
1090 fn next(&mut self) -> Option<Self::Item> {
1091 let (kind, inputs) = self.0.next()?;
1092 Some(Gate {
1093 kind: kind.into(),
1094 inputs,
1095 })
1096 }
1097
1098 #[inline(always)]
1099 fn size_hint(&self) -> (usize, Option<usize>) {
1100 self.0.size_hint()
1101 }
1102}
1103
1104impl ExactSizeIterator for CircuitGateIter<'_> {
1105 #[inline(always)]
1106 fn len(&self) -> usize {
1107 self.0.len()
1108 }
1109}
1110
1111impl fmt::Debug for CircuitGateIter<'_> {
1112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1113 f.debug_list().entries(self.clone()).finish()
1114 }
1115}
1116
1117impl fmt::Debug for Circuit {
1118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1119 f.debug_struct("Circuit")
1120 .field("inputs", &self.inputs)
1121 .field("gates", &self.iter_gates())
1122 .finish()
1123 }
1124}
1125
1126/// Problem details such as latches, outputs, and bad states for an and-inverter
1127/// graph
1128///
1129/// Latches are not natively supported by [`Circuit`s][Circuit], but each latch
1130/// output is modeled as a an additional circuit input, and each latch input is
1131/// modeled as a Boolean function, concretely a [`Literal`]. In the current
1132/// implementation, the input numbers for latches are in range
1133/// `(self.inputs() + 1)..(self.inputs() + self.latches().len())`.
1134#[derive(Clone, PartialEq, Eq, Debug)]
1135pub struct AIGERDetails {
1136 /// Number of input variables
1137 inputs: usize,
1138 /// Latch inputs
1139 latches: Vec<Literal>,
1140 /// Latch initial values
1141 latch_init_values: TVBitVec,
1142 /// Outputs
1143 outputs: Vec<Literal>,
1144 /// Bad state literals
1145 bad: Vec<Literal>,
1146 /// Invariant constraints
1147 invariants: Vec<Literal>,
1148 /// Justice properties
1149 justice: Vec2d<Literal>,
1150 /// Fairness constraints
1151 fairness: Vec<Literal>,
1152
1153 /// Mapping from AIGER variable numbers (literals divided by 2) to literals
1154 /// in the circuit
1155 map: Vec<Literal>,
1156
1157 /// Output names
1158 ///
1159 /// Either empty or has the same length as `outputs`
1160 output_names: Vec<Option<String>>,
1161 /// Bad state literal names
1162 ///
1163 /// Either empty or has the same length as `bad`
1164 bad_names: Vec<Option<String>>,
1165 /// Invariant state names
1166 ///
1167 /// Either empty or has the same length as `invariants`
1168 invariant_names: Vec<Option<String>>,
1169 /// Justice property names
1170 ///
1171 /// Either empty or has the same length as `justice`
1172 justice_names: Vec<Option<String>>,
1173 /// Fairness constraint names
1174 ///
1175 /// Either empty or has the same length as `fairness`
1176 fairness_names: Vec<Option<String>>,
1177}
1178
1179impl AIGERDetails {
1180 /// Get the latch number of `literal`, if it refers to a latch
1181 ///
1182 /// If the return value is `Some(index)`, `index` is valid for the slice
1183 /// returned by [`Self::latches()`].
1184 #[inline]
1185 pub fn get_latch_no(&self, literal: Literal) -> Option<usize> {
1186 if literal.is_gate() {
1187 return None;
1188 }
1189 let first_latch = 1 + self.inputs;
1190 let result = (literal.0 >> Literal::VAR_LSB).checked_sub(first_latch)?;
1191 if result >= self.latches.len() {
1192 return None;
1193 }
1194 Some(result)
1195 }
1196
1197 /// Get the number of input variables
1198 #[inline(always)]
1199 pub fn inputs(&self) -> usize {
1200 self.inputs
1201 }
1202
1203 /// Get the input literals of each latch
1204 #[inline(always)]
1205 pub fn latches(&self) -> &[Literal] {
1206 &self.latches
1207 }
1208 /// Get the initial value of latch `i`
1209 #[inline(always)]
1210 pub fn latch_init_value(&self, i: usize) -> Option<bool> {
1211 self.latch_init_values[i]
1212 }
1213
1214 /// Get the output definitions
1215 #[inline(always)]
1216 pub fn outputs(&self) -> &[Literal] {
1217 &self.outputs
1218 }
1219
1220 /// Map the given AIGER literal to a [`Literal`] for use with the
1221 /// [`Circuit`]
1222 ///
1223 /// Note that the literals in [`AIGERDetails`] are already mapped
1224 /// accordingly. This method is useful if you want to refer to specific
1225 /// gates or literals using the values from the AIGER source.
1226 #[inline(always)]
1227 pub fn map_aiger_literal(&self, literal: usize) -> Option<Literal> {
1228 let l = *self.map.get(literal >> 1)?;
1229 Some(if literal & 1 != 0 { !l } else { l })
1230 }
1231
1232 /// Get the name for output `i`
1233 #[inline(always)]
1234 pub fn output_name(&self, i: usize) -> Option<&str> {
1235 self.output_names.get(i)?.as_deref()
1236 }
1237 /// Get the name for bad state literal `i`
1238 #[inline(always)]
1239 pub fn bad_name(&self, i: usize) -> Option<&str> {
1240 self.bad_names.get(i)?.as_deref()
1241 }
1242 /// Get the name for invariant constraint `i`
1243 #[inline(always)]
1244 pub fn invariant_name(&self, i: usize) -> Option<&str> {
1245 self.invariant_names.get(i)?.as_deref()
1246 }
1247 /// Get the name for justice constraint `i`
1248 #[inline(always)]
1249 pub fn justice_name(&self, i: usize) -> Option<&str> {
1250 self.justice_names.get(i)?.as_deref()
1251 }
1252
1253 /// Map the literals in `self` based on `gate_map`
1254 ///
1255 /// See [`Literal::apply_gate_map()`] for more details.
1256 pub fn apply_gate_map(&self, gate_map: &[Literal]) -> Self {
1257 let map_slice = move |slice: &[Literal]| {
1258 slice
1259 .iter()
1260 .map(move |l| l.apply_gate_map(gate_map))
1261 .collect::<Vec<_>>()
1262 };
1263
1264 let mut justice =
1265 Vec2d::with_capacity(self.justice.len(), self.justice.all_elements().len());
1266 for j in self.justice.iter() {
1267 justice.push_vec();
1268 justice.push_elements(j.iter().map(move |l| l.apply_gate_map(gate_map)));
1269 }
1270
1271 Self {
1272 inputs: self.inputs,
1273 latches: map_slice(&self.latches),
1274 latch_init_values: self.latch_init_values.clone(),
1275 outputs: map_slice(&self.outputs),
1276 bad: map_slice(&self.bad),
1277 invariants: map_slice(&self.invariants),
1278 justice,
1279 fairness: map_slice(&self.fairness),
1280 map: map_slice(&self.map),
1281 output_names: self.output_names.clone(),
1282 bad_names: self.bad_names.clone(),
1283 invariant_names: self.invariant_names.clone(),
1284 justice_names: self.justice_names.clone(),
1285 fairness_names: self.fairness_names.clone(),
1286 }
1287 }
1288
1289 /// In-place version of [`Self::apply_gate_map()`]
1290 pub fn apply_gate_map_in_place(&mut self, map: &[Literal]) {
1291 let map_slice = move |slice: &mut [Literal]| {
1292 for l in slice.iter_mut() {
1293 *l = l.apply_gate_map(map);
1294 }
1295 };
1296
1297 map_slice(&mut self.latches);
1298 map_slice(&mut self.outputs);
1299 map_slice(&mut self.bad);
1300 map_slice(&mut self.invariants);
1301 map_slice(self.justice.all_elements_mut());
1302 map_slice(&mut self.fairness);
1303 map_slice(&mut self.map);
1304 }
1305}
1306
1307/// Options for the parsers
1308#[non_exhaustive]
1309#[derive(Clone, Builder, Default, Debug)]
1310pub struct ParseOptions {
1311 /// Whether to parse a variable orders
1312 ///
1313 /// The [DIMACS satisfiability formats][dimacs], for instance, do not
1314 /// natively support specifying a variable order, however it is not uncommon
1315 /// to use the comment lines for this purpose. But while some files may
1316 /// contain a variable order in the comment lines, others may use them for
1317 /// arbitrary comments. Hence, it may be desired to turn on parsing orders
1318 /// for some files and turn it off for other files.
1319 #[builder(default = "false")]
1320 pub var_order: bool,
1321
1322 /// Whether to parse a clause tree (for [DIMACS CNF][dimacs])
1323 ///
1324 /// If the CNF contains, e.g., five clauses, and one of the comment lines
1325 /// contains `co [[0, 1], [2, 3, 4]]`, then the parsed circuit will have
1326 /// three AND gates (one with clauses 0 and 1 as input, one with clauses
1327 /// 2, 3, and 4, as well as one with those two conjuncts).
1328 #[builder(default = "false")]
1329 pub clause_tree: bool,
1330
1331 /// Whether to check that the circuit is acyclic
1332 ///
1333 /// The time complexity of this check is linear in the circuit's size, and
1334 /// therefore rather inexpensive. Therefore, it is enabled by default.
1335 #[builder(default = "true")]
1336 pub check_acyclic: bool,
1337}
1338
1339#[cfg(test)]
1340mod tests {
1341 use super::*;
1342 use crate::util::test::*;
1343
1344 #[test]
1345 fn simplify() {
1346 let mut circuit = Circuit::new(VarSet::new(3));
1347 circuit.push_gate(GateKind::Xor);
1348 circuit.push_gate_inputs([!v(0), v(1), v(2)]);
1349 circuit.push_gate(GateKind::And);
1350 circuit.push_gate_input(g(0));
1351
1352 let (simplified, map) = circuit.simplify([Literal::from_gate(false, 1)]).unwrap();
1353 assert_eq!(simplified.num_gates(), 1);
1354 assert_eq!(
1355 simplified.gate_for_no(0),
1356 Some(Gate::xor(&[v(0), v(1), v(2)]))
1357 );
1358 assert_eq!(&map, &[!g(0), !g(0)]);
1359 }
1360}