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