Skip to main content

BDDs and Variable Orders

Learn how to use Binary Decision Diagrams and define a variable ordering.

Concept: Knowledge Representations​

Broadly, there are many different ways to represent and compile knowledge bases. RSDD supports different "backends" that enable you to choose the one best suited for your problem.

Binary Decision Diagrams and Variable Ordering​

We'll start with a traditional form: Binary Decision Diagrams (BDDs). In particular, we will use Reduced Order Binary Decision Diagrams (ROBDDs), which come with a fixed order and canonicity property.

Getting a Cnf Object​

First, we'll convert the string input we've received into a strongly-typed internal CNF representation.

src/main.rs
extern crate rsdd;

use std::{env, fs};

use rsdd::repr::cnf::Cnf;

fn main() {
let args: Vec<String> = env::args().collect();

if args.is_empty() {
panic!("No file provided");
}

let path = &args[1];

let cnf_input = match fs::read_to_string(path) {
Ok(s) => s,
Err(err) => panic!("Error reading file: {}", err),
};

let cnf = Cnf::from_file(cnf_input);
}

Creating a BddManager​

In RSDD, the behaviour for most knowledge representation is split into two pieces:

  • a Ptr type, which holds a bonafide Rust pointer to data itself and provides immutable data properties
  • a manager, which operates on pointers (mutably or immutably)

Let's create a new function that creates a BddManager (for operating on BddPtrs):

src/main.rs
use rsdd::{
builder::{bdd_builder::BddManager, cache::lru_app::BddApplyTable},
repr::{cnf::Cnf, robdd::BddPtr},
};

fn compile_as_bdd(cnf: &Cnf) {
let man = BddManager::<BddApplyTable<BddPtr>>::new_default_order_lru(cnf.num_vars());
let bdd = man.from_cnf(cnf);
println!("{:?}", bdd)
}

note

This part of the API is unstable, and is likely to change very soon.

To break down what's happening here,

  • the base data structure we are operating on is a BddPtr. These work like pointers: each BddPtr points to a real, in-memory BDD.
  • we are creating a BddManager. Currently, BddManager is generic over its "ApplyTable", which caches apply operations. We are using the "default" LRU cache.
  • the ::new_default_order_lru() constructor automatically picks a variable ordering for us, which is linear from left to right. You can also specify a specific variable ordering when using ::new().
  • the BddManager::from_cnf() function generates a BddPtr from a CNF

Let's now call this function!

src/main.rs
fn main() {
// ...

let cnf = Cnf::from_file(cnf_input);
compile_as_bdd(&cnf);
}
$ cargo run example.cnf
... something very long

Neat!

Varying Variable Orders​

This section is coming soon! It will have a nice interactive demo :)