TDD — Tree Decision Diagrams

A canonical generalization of OBDDs

Florent Capelli, YooJung Choi, Stefan Mengel, Martín Muñoz, Guy Van den Broeck

CRIL, Université d’Artois

Dagstuhl Seminar 26221

May, 2026

TDDs

Overview of TDDs

Tree Decision Diagrams is a new datastructure for representing Boolean functions:

OBDD<TDD<SDDOBDD < TDD < SDD

TDDs improves the tractability of OBDDs without sacrificing much.

Definition by example

g cluster_x1 x₁ cluster_x2 x₂ cluster_x3 x₃ cluster_x4 x₄ cluster_t1 t₁ cluster_t2 t₂ cluster_t3 t₃ x1 x₁ nx1 ¬x₁ x2 x₂ nx2 ¬x₂ x3 x₃ nx3 ¬x₃ x4 x₄ nx4 ¬x₄ Nt1_0 Nt1_0:v1->x1 Nt1_0:v0->nx1 Nt1_0:v1->x2 Nt1_0:v0->nx2 Ct1->Cx1 Ct1->Cx2 Nt1_1 Nt1_1:v0->x1 Nt1_1:v1->nx1 Nt1_1:v1->x2 Nt1_1:v0->nx2 Nt2_0 Nt2_0:v1->x3 Nt2_0:v0->nx3 Nt2_0:v1->x4 Nt2_0:v0->nx4 Ct2->Cx3 Ct2->Cx4 Nt2_1 Nt2_1:v0->x3 Nt2_1:v1->nx3 Nt2_1:v1->x4 Nt2_1:v0->nx4 root root:v0->Nt1_0 root:v1->Nt1_1 root:v2->Nt1_1 root:v1->Nt2_0 root:v0->Nt2_1 root:v2->Nt2_1 Ct3->Ct1 Ct3->Ct2

Fix a vtree shape (variables at the leaves).

Input nodes: labeled by literals (constants allowed under strict conditions, see later).

A node: list of pairs of nodes from the children bags. Here, it computes (x1x2)(¬x1¬x2)(x_1 \wedge x_2) \vee (\neg x_1 \wedge \neg x_2) that is x1x21x_1 \oplus x_2 \oplus 1.

Another node computing (x1¬x2)(¬x1x2)(x_1 \wedge \neg x_2) \vee (\neg x_1 \wedge x_2) that is x1x2x_1 \oplus x_2

Nodes in each bag! One output node in the root. Here it computes (x1x2x3x4)((x1x2)(x3x4))(x_1 \oplus x_2 \oplus x_3 \oplus x_4) \vee ((x_1 \oplus x_2) \wedge (x_3 \oplus x_4))

Model ¬x1,¬x2,x3,¬x4\neg x_1, \neg x_2, x_3, \neg x_4 of (x1x2x3x4)((x1x2)(x3x4))(x_1 \oplus x_2 \oplus x_3 \oplus x_4) \vee ((x_1 \oplus x_2) \wedge (x_3 \oplus x_4))

¬x1,¬x2,¬x3,¬x4\neg x_1, \neg x_2, \neg x_3, \neg x_4 is not a model of (x1x2x3x4)((x1x2)(x3x4))(x_1 \oplus x_2 \oplus x_3 \oplus x_4) \vee ((x_1 \oplus x_2) \wedge (x_3 \oplus x_4))

Non deterministic TDD (nTDD): only a rigid normal form of smooth structured DNNF.

Determinism (TDD)

g cluster_x1 x₁ cluster_x2 x₂ cluster_x3 x₃ cluster_x4 x₄ cluster_t1 t₁ cluster_t2 t₂ cluster_t3 t₃ x1 x₁ nx1 ¬x₁ x2 x₂ nx2 ¬x₂ x3 x₃ nx3 ¬x₃ x4 x₄ nx4 ¬x₄ Nt1_0 Nt1_0:v1->x1 Nt1_0:v0->nx1 Nt1_0:v1->x2 Nt1_0:v0->nx2 Ct1->Cx1 Ct1->Cx2 Nt1_1 Nt1_1:v0->x1 Nt1_1:v1->nx1 Nt1_1:v1->x2 Nt1_1:v0->nx2 Nt2_0 Nt2_0:v1->x3 Nt2_0:v0->nx3 Nt2_0:v1->x4 Nt2_0:v0->nx4 Ct2->Cx3 Ct2->Cx4 Nt2_1 Nt2_1:v0->x3 Nt2_1:v1->nx3 Nt2_1:v1->x4 Nt2_1:v0->nx4 root root:v0->Nt1_0 root:v1->Nt1_1 root:v2->Nt1_1 root:v1->Nt2_0 root:v0->Nt2_1 root:v2->Nt2_1 Ct3->Ct1 Ct3->Ct2

Determinism: Each pair of sibling nodes can be the input of at most one node.

Same node can be used twice, as long as it is used with another sibling.

For each assignment of variables and every bag tt, at most one node in bag tt is satisfied.

Negation

g cluster_x1 cluster_x2 cluster_x3 cluster_x4 cluster_t1 t₁ cluster_t2 t₂ cluster_t0 t₀ x1 x₁ nx1 ¬x₁ x2 x₂ nx2 ¬x₂ x3 x₃ nx3 ¬x₃ x4 x₄ nx4 ¬x₄ x1eqx2 x1eqx2:v1->x1 x1eqx2:v0->nx1 x1eqx2:v1->x2 x1eqx2:v0->nx2 x1ltx2 x1ltx2:v0->nx1 x1ltx2:v0->x2 x2ltx1 x2ltx1:v0->x1 x2ltx1:v0->nx2 x3eqx4 x3eqx4:v1->x3 x3eqx4:v0->nx3 x3eqx4:v1->x4 x3eqx4:v0->nx4 x3ltx4 x3ltx4:v0->nx3 x3ltx4:v0->x4 x4ltx3 x4ltx3:v0->x3 x4ltx3:v0->nx4 out out:v0->x1eqx2 out:v1->x1ltx2 out:v0->x3eqx4 out:v1->x3ltx4 nout nout:v0->x1eqx2 nout:v2->x1eqx2 nout:v1->x1ltx2 nout:v3->x1ltx2 nout:v4->x2ltx1 nout:v5->x2ltx1 nout:v6->x2ltx1 nout:v1->x3eqx4 nout:v4->x3eqx4 nout:v0->x3ltx4 nout:v5->x3ltx4 nout:v2->x4ltx3 nout:v3->x4ltx3 nout:v6->x4ltx3

For each vtree node tt, add a tt-node containing all missing pairs; bottom up!

Bottom up: also add missing pairs with red nodes below!

Red nodes accept the rejected assignments at each level.

Root red node computes the negation (new output).

Complexity: O(#varsw2)O(\#vars \cdot w^2) where ww is the width, ie, maximum number of nodes in a bag.

Canonicity and Minimization

Twins contraction

g cluster_x1 cluster_x2 cluster_x3 cluster_x4 cluster_t1 t₁ cluster_t2 t₂ cluster_t3 t₃ x1 x₁ nx1 ¬x₁ x2 x₂ nx2 ¬x₂ x3 x₃ nx3 ¬x₃ x4 x₄ nx4 ¬x₄ nx1nx2 nx1nx2:v0->nx1 nx1nx2:v0->nx2 x1x2 x1x2:v0->x1 x1x2:v0->x2 x1nx2 x1nx2:v0->x1 x1nx2:v0->nx2 x3x4 x3x4:v0->x3 x3x4:v0->x4 nx3nx4 nx3nx4:v0->nx3 nx3nx4:v0->nx4 x3neqx4 x3neqx4:v1->x3 x3neqx4:v0->nx3 x3neqx4:v0->x4 x3neqx4:v1->nx4 a a:v1->nx1nx2 a:v0->x1x2 a:v2->x1nx2 a:v0->x3neqx4 a:v1->x3neqx4 a:v2->x3neqx4 b b:v2->nx1nx2 b:v1->x1x2 b:v0->x1nx2 b:v00->x1nx2 b:v0->x3x4 b:v00->nx3nx4 b:v1->nx3nx4 b:v2->nx3nx4
g cluster_x1 cluster_x2 cluster_x3 cluster_x4 cluster_t1 t₁ cluster_t2 t₂ cluster_t3 t₃ x1 x₁ nx1 ¬x₁ x2 x₂ nx2 ¬x₂ x3 x₃ nx3 ¬x₃ x4 x₄ nx4 ¬x₄ x1eqx2 x1eqx2:v1->x1 x1eqx2:v0->nx1 x1eqx2:v1->x2 x1eqx2:v0->nx2 x1nx2 x1nx2:v0->x1 x1nx2:v0->nx2 x3x4 x3x4:v0->x3 x3x4:v0->x4 nx3nx4 nx3nx4:v0->nx3 nx3nx4:v0->nx4 x3neqx4 x3neqx4:v1->x3 x3neqx4:v0->nx3 x3neqx4:v0->x4 x3neqx4:v1->nx4 a a:v0->x1eqx2 a:v2->x1nx2 a:v0->x3neqx4 a:v2->x3neqx4 b b:v1->x1eqx2 b:v0->x1nx2 b:v00->x1nx2 b:v0->x3x4 b:v00->nx3nx4 b:v1->nx3nx4

Two nodes N1,N2N_1,N_2 are twins if they have the same siblings for every parent node.

Same sibling for this parent.

But not for this one: these two nodes are not twins.

Same sibling for this parent.

And for this one. They are twins!

We can merge them. This does not change the function computed.

Minimization

Theorem.

Iteratively merging twins until no twins remains converges to a canonical and minimal TDD computing the same function.

In particular: TDDs can be minimized in polynomial time.

Next slides: why is the result canonical and minimal?

Subfunctions

Let f:2X{0,1}f : 2^X \rightarrow \{0,1\} and YXY \subseteq X. Subfunctions of ff on YY:

subfunctions(f,Y)={f[τ]τ2X\Y,f[τ]}.subfunctions(f,Y) = \{ f[\tau] \mid \tau \in 2^{X \setminus Y}, f[\tau] \neq \bot\}.

Subfunctions and canonicity

Lower bound:

For two models τ1,τ2\tau_1, \tau_2 of node NN, f[τ1]=f[τ2]f[\tau_1] = f[\tau_2].

τ1\tau_1 and τ2\tau_2 define the same subfunction!

At least #subfunctions(f,Xt)\#subfunctions(f,X_t) nodes in bag tt for each tt

Upper bound:

If one bag tt has size >#subfunctions(f,Xt)> \#subfunctions(f,X_t), the TDD must contain one pair of twins.

Iteratively contracting twins converges to a canonical minimal TDD!

g cluster_t t r r dots1 ... r->c r->d t N n1 dots ... t->a t->b n2 Xt τ₁,τ₂ Xₜ

Bottom-up compilation

def cnf2tdd(F: cnf, T: vtree):
    D = TDD(1, T)
    for c in F:
        Dc = TDD(c, T)
        D.apply(Dc)
        D.minimize()
    return D

For a CNF F=C1CmF = C_1 \wedge \dots \wedge C_m with nn variables:

  • Let Wi=W_i = width of Fi=C1CiF_i = C_1 \wedge \dots \wedge C_i.
  • Runs in time O(nm(maxWi))O(nm \cdot (\max W_i))
  • O(2knm)O(2^k \cdot nm) for CNF of incidence tw kk!
  • Complexity follows by just analysing the number of subfunctions!

Conclusion

The slides you missed

Learning TDD

Angluin-style learning algorithm.

Build the canonical TDD of size SS of a Boolean function with O(S)O(S) equivalence queries to the oracle.

Compiling constraints

Bottom up algorithm with constraints represented by TDDs over the same vtree.

FPT compilation with bounded incidence treewidth:

  • Parity constraints
  • Cardinality constraints etc.

Existential and Universal Projection

Given a TDD CC of width ww and YXY \subseteq X.

We can construct a TDD computing Y.C\exists Y. C and Y.C\forall Y. C of width at most 2w2^w!

Applications to QBF solving!

Future work

And in practice? TiDiDi compiler! Stay tuned with Guy!