A step-by-step Ordered Binary Decision Diagram (OBDD) engine compiled to WebAssembly and deployed as an interactive visualization tool at:
https://tools.harryfoster.tech
This engine allows users to input propositional logic formulas as well as the desired ordering and observe their full transformation into an OBDD in real time, including parsing, simplification, recursion, and DAG construction.
Built with Rust and compiled to WebAssembly for execution directly in the browser.
This engine takes a propositional logic formula (e.g. ~a & b -> c) and:
- Lexes and parses it into an AST
- Simplifies the formula using boolean identities
- Constructs an Ordered Binary Decision Diagram (OBDD)
- Exposes each execution step for visualization
- Allows step-by-step forward/backward execution
| Operator | Meaning | Example |
|---|---|---|
~ / ! |
NOT | ~a |
& |
AND | a & b |
| |
OR | a | b |
-> |
IMPLIES | a -> b |
<-> |
IFF | a <-> b |
( ) |
Grouping | (a & b) |
Reserved identifiers:
T→ TrueF→ False
All binary operators are left-associative.
This ensures deterministic parsing of ambiguous expressions:
a -> b -> c ≡ (a -> b) -> c
The system is split into four modules:
- lexer → tokenization of input strings
- parser → Pratt parser producing AST
- formula → logical expression representation
- engine → OBDD construction + execution tracing
The engine is designed around state snapshots:
- Each step mutates a cloned execution state
- All states are stored in
state_history - UI can replay or rewind execution deterministically
- Execution is driven by a stack of frames
This engine directly implements a step-wise version of the classical OBDD construction algorithm.
procedure obdd(F)
input: propositional formula F
parameters: global DAG D
output: node n representing F
begin
F := simplify(F)
if F = ⊥ then return 0
if F = ⊤ then return 1
p := max_variable(F)
n1 := obdd(F[p := false])
n2 := obdd(F[p := true])
return integrate(n1, p, n2, D)
end
procedure integrate(n1, p, n2, D)
input: nodes n1, n2 in D, variable p
output: node n representing (if p then n2 else n1)
begin
if n1 = n2 then return n1
if D contains node (p, n1, n2) then
return existing node
create new node n = (p, n1, n2)
add n to D
return n
end
| Algorithm Concept | Rust Implementation |
|---|---|
| simplify(F) | simplify_step() |
| max_variable(F) | choose_variable() |
| F[p := value] | substitute_bool_ast_walk() |
| recursive obdd | recurse_var() |
| integrate() | call_integrate() |
| DAG D | unique_table + nodes |
Node {
id: usize,
var: Option<String>,
left: Option<usize>,
right: Option<usize>,
}Terminal nodes:
0→ False1→ True
const engine = new WasmOBDDEngine(formula, ordering);engine.step();Advances execution by one state transition.
engine.step_back();Rewinds execution.
const state = engine.get_state();Returns:
{
step_number: number,
nodes: Node[],
execution_stack: ExecutionFrame[],
message: string
}This is the primary interface for UI rendering.
validate_formula("(a & b) -> c");Returns true if syntactically valid.
The engine exposes internal computation steps for visualization:
- simplify
- check bottom/top
- choose variable
- recurse low/high
- integrate call/return
- check equality
- lookup node
- create node
- return
This enables a fully animated OBDD construction debugger.
const engine = new WasmOBDDEngine("~a & b -> c", ["a", "b", "c"]);
while (true) {
const state = engine.get_state();
render(state);
engine.step();
}wasm-pack build --target web