biodivine_lib_bdd/
lib.rs

1//! # Biodivine/LibBDD
2//!
3//! This crate provides a basic implementation of [binary decision diagrams](https://en.wikipedia.org/wiki/Binary_decision_diagram) (BDDs) — a symbolic data
4//! structure for representing Boolean functions or other equivalent objects (such as bit-vector
5//! sets).
6//!
7//! Compared to other popular implementations, every BDD owns its memory. It is thus trivial to
8//! serialise, but also to share between threads. This makes it useful for applications that
9//! process high number of BDDs concurrently, but is also generally more idiomatic in Rust.
10//!
11//! At the moment, we support many standard operations on BDDs:
12//!
13//!  - Any binary logical operation (`and`, `or`, `iff`, ...), and of course negation.
14//!  - Evaluation of Boolean expressions parsed from a string.
15//!  - A `bdd!` macro for a more idiomatic specification of operation chains.
16//!  - Simplified methods for CNF/DNF formula construction.
17//!  - Binary and text serialization/deserialization.
18//!  - Valuation/path iterators and other `Bdd` introspection methods (`random_valuation`, `most_fixed_clause`, ...).
19//!  - Export of `Bdd` back into a Boolean expression.
20//!  - "Relational" operations: projection (existential quantification), selection (restriction) and unique subset picking (see tutorials for more info).
21//!  - A "variable flip" operation fused with custom logical binary operators.
22//!  - Export to `.dot` graphs.
23//!
24//! More detailed description of all features can be found in our [tutorial module](https://docs.rs/biodivine-lib-bdd/latest/biodivine_lib_bdd/tutorial/index.html), and of course in the [API documentation](https://docs.rs/biodivine-lib-bdd/latest/).
25//!
26//! ```rust
27//! use biodivine_lib_bdd::*;
28//!
29//! let mut builder = BddVariableSetBuilder::new();
30//! let [a, b, c] = builder.make(&["a", "b", "c"]);
31//! let variables: BddVariableSet = builder.build();
32//!
33//! // String expressions:
34//! let x = variables.eval_expression_string("(a <=> !b) | c ^ a");
35//! // Macro:
36//! let y = bdd!(variables, (a <=> (!b)) | (c ^ a));
37//! // Logical operators:
38//! let z = variables.mk_literal(a, true)
39//!     .iff(&variables.mk_literal(b, false))
40//!     .or(&variables.mk_literal(c, true).xor(&variables.mk_literal(a, true)));
41//!
42//! assert!(!x.is_false());
43//! assert_eq!(6.0, x.cardinality());
44//! assert_eq!(x, y);
45//! assert_eq!(y, z);
46//! assert_eq!(z, x);
47//!
48//! for valuation in x.sat_valuations() {
49//!     assert!(x.eval_in(&valuation));
50//! }
51//! ```
52//!
53
54use std::collections::{HashMap, HashSet};
55
56pub mod boolean_expression;
57pub mod op_function;
58pub mod random_sampling;
59pub mod tutorial;
60
61/// **(internal)** Implementations for the `Bdd` struct.
62mod _impl_bdd;
63
64/// **(internal)** Several complex test scenarios for the `Bdd` struct.
65#[cfg(test)]
66mod _test_bdd;
67
68/// **(internal)** Implementation of the `BddNode`.
69mod _impl_bdd_node;
70
71/// **(internal)** Implementation of the `BddPointer`.
72mod _impl_bdd_pointer;
73
74/// **(internal)** Implementation of the `BddValuation`.
75mod _impl_bdd_valuation;
76
77/// **(internal)** Implementation of the `BddPartialValuation`.
78mod _impl_bdd_partial_valuation;
79
80/// **(internal)** Implementation of the `BddValuationsIterator`.
81mod _impl_bdd_satisfying_valuations;
82
83/// **(internal)** Implementation of the `BddVariable`.
84mod _impl_bdd_variable;
85
86/// **(internal)** Implementation of the `BddVariableSet`.
87mod _impl_bdd_variable_set;
88
89/// **(internal)** Implementation of the `BddVariableSetBuilder`.
90mod _impl_bdd_variable_set_builder;
91
92/// **(internal)** Implementation of the `ValuationOfClauseIterator`.
93mod _impl_iterator_valuations_of_clause;
94
95/// **(internal)** Implementation of the `BddPathIterator`.
96mod _impl_bdd_path_iterator;
97
98/// **(internal)** A macro module for simplifying BDD operations.
99mod _macro_bdd;
100
101/// Several basic utility methods for testing `Bdd`s.
102#[cfg(test)]
103mod _test_util;
104
105/// **(internal)** Characters that cannot appear in the variable name
106/// (based on possible tokens in a boolean expression).
107const NOT_IN_VAR_NAME: [char; 11] = ['!', '&', '|', '^', '=', '<', '>', '(', ')', '?', ':'];
108
109/// An array-based encoding of the binary decision diagram implementing basic logical operations.
110///
111/// To create `Bdd`s for atomic formulas, use a `BddVariableSet`.
112#[derive(Clone, Debug, Eq, Hash, PartialEq)]
113#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
114pub struct Bdd(Vec<BddNode>);
115
116/// Identifies one of the variables that can appear as a decision condition in the `Bdd`.
117#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
118#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
119pub struct BddVariable(u16);
120
121/// Exactly describes one assignment of boolean values to variables of a `Bdd`.
122///
123/// It can be used as a witness of `Bdd` non-emptiness, since one can evaluate every `Bdd`
124/// in some corresponding valuation and get a `true/false` result.
125#[derive(Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
126#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
127pub struct BddValuation(Vec<bool>);
128
129/// Describes assignment of some arbitrary number of `Bdd` variables.
130///
131/// A partial valuation can be used to quickly construct simple conjunctive/disjunctive clauses.
132/// It also exactly describes one path in a `Bdd` and hence can be used as an intermediate
133/// value when traversing the valuations of a `Bdd`.
134#[derive(Clone, Debug)]
135#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
136pub struct BddPartialValuation(Vec<Option<bool>>);
137
138/// Exhaustively iterates over all valuations with a certain number of variables.
139///
140/// Be aware of the exponential time complexity of such operation!
141///
142/// *Deprecated in favour of `ValuationsOfClauseIterator` which provides the same
143/// functionality when given an empty clause.*
144#[deprecated]
145pub struct BddValuationIterator(ValuationsOfClauseIterator);
146
147/// An iterator over all satisfying valuations of a specific BDD.
148///
149/// Be aware of the potential exponential number of iterations!
150pub struct BddSatisfyingValuations<'a> {
151    bdd: &'a Bdd,
152    paths: BddPathIterator<'a>,
153    valuations: ValuationsOfClauseIterator,
154}
155
156/// Same as [BddSatisfyingValuations], but owns the underlying [Bdd] and thus does not
157/// require a lifetime.
158pub struct OwnedBddSatisfyingValuations {
159    num_vars: u16,
160    paths: OwnedBddPathIterator,
161    valuations: ValuationsOfClauseIterator,
162}
163
164/// An iterator which goes through all paths in the `Bdd`, representing them as clauses using
165/// `BddPartialValuation`.
166pub struct BddPathIterator<'a> {
167    bdd: &'a Bdd,
168    // Stack keeps the last discovered path. If last path was consumed, the stack is empty.
169    stack: Vec<BddPointer>,
170}
171
172/// Same as [BddPathIterator], but owns the underlying [Bdd] and thus does not require a lifetime.
173pub struct OwnedBddPathIterator {
174    bdd: Bdd,
175    stack: Vec<BddPointer>,
176}
177
178/// An iterator which goes through all valuations that satisfy a specific *conjunctive* clause.
179///
180/// Mind that the number of valuations satisfying a clause can be exponential!
181///
182/// Note that the clause can be empty, in which case this is equivalent to `BddValuationIterator`.
183#[derive(Clone)]
184pub struct ValuationsOfClauseIterator {
185    next_valuation: Option<BddValuation>,
186    clause: BddPartialValuation,
187}
188
189/// Maintains the set of variables that can appear in a `Bdd`.
190/// Used to create new `Bdd`s for basic formulas.
191#[derive(Clone, Debug)]
192#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
193pub struct BddVariableSet {
194    num_vars: u16,
195    var_names: Vec<String>,
196    var_index_mapping: HashMap<String, u16>,
197}
198
199/// Used to safely initialize `BddVariableSet`.
200///
201/// Note that some characters are not allowed in variable names (to allow safe serialisation,
202/// formula parsers and export as `.dot`, etc.).
203/// These characters are `!`, `&`, `|`, `^`, `=`, `<`, `>`, `(` and `)`.
204#[derive(Clone)]
205pub struct BddVariableSetBuilder {
206    var_names: Vec<String>,
207    var_names_set: HashSet<String>,
208}
209
210/// A type-safe index into the `Bdd` node array representation.
211///
212/// BDD pointers are an internal type-safe wrapper around indices into BDD arrays.
213/// Outside this crate, no one should know or care about their existence. Since
214/// we can't reasonably expect a BDD to be larger than `2^32` right now, the pointer is
215/// represented as `u32` instead of `usize`, because `usize` can be 64-bits and pointers
216/// represent most of the memory consumed by our BDDs.
217#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
218#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
219pub struct BddPointer(u32);
220
221/// **(internal)** Representation of individual vertices of the `Bdd` directed acyclic graph.
222///
223/// A `BddNode` can be a terminal, in which case it is either `0` or `1`, or a decision node,
224/// in which case it contains a variable `v_i` which it conditions upon and two pointers
225/// (`low` and `high`) to other nodes in the same `Bdd`:
226///
227/// ```mermaid
228/// graph LR
229///     id1(`v_i`)
230///     id2(`v_j`)
231///     id3(`v_k`)
232///     id1 -->|low| id2
233///     id1 -->|high| id3
234/// ```
235///
236/// Internally, we represent terminal nodes using the same structure, giving them cyclic
237/// pointers. Instead of variable id, we use the number of variables in the original
238/// `BddVariableSet`. This is consistent with the fact that we first condition on smallest
239/// variable ids. It can be also used for consistency checks inside the library.
240#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
241#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
242pub struct BddNode {
243    pub var: BddVariable,
244    pub low_link: BddPointer,
245    pub high_link: BddPointer,
246}
247
248/// A trait which allows quick conversion of a type into a `Bdd`, assuming an appropriate
249/// `BddVariablesSet` is provided.
250pub trait IntoBdd {
251    fn into_bdd(self, variables: &BddVariableSet) -> Bdd;
252}