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