The CUDD package, BDD and ADD Tutorial

Learn it by examples

By David Kebo Houngninou

On this page, you will find some simple and practical examples of how to use CUDD.
Note: All Credits go to the author of the package, Fabio Somenzi at the Dept. of Electrical and Computer Engineering, University of Colorado at Boulder

Table of contents

  • What is CUDD?
  • Where to download CUDD?
  • How to install CUDD?
  • Tutorial 1: Write your first program with CUDD
  • How to debug your program
  • Visualize the BDD
  • Tutorial 2: BDD of Boolean functions
  • BDD for the Exclusive-OR Boolean function
  • BDD for the AND Boolean function
  • BDD for the OR Boolean function
  • BDD for the XNOR Boolean function
  • BDD for the NAND Boolean function
  • BDD for the NOR Boolean function
  • BDD for the NOT Boolean function
  • BDD for the function f = x0’x1’x2’x3′
  • Tutorial 3: Variable reordering
  • Tutorial 4: Additional functions
  • Algebraic Decision Diagram (ADD) for a fanout
  • Algebraic Decision Diagram (ADD) for a crossover

What is CUDD?

CUDD stands for Colorado University Decision Diagram. It is a package for the manipulation of Binary Decision Diagrams (BDDs), Algebraic Decision Diagrams (ADDs), and Zero-suppressed Binary Decision Diagrams (ZDDs).

Where to download CUDD?

cudd-3.0.0
cudd-2.5.1
cudd-2.5.0
cudd-2.4.2

These directories contain the decision diagram package and a few support libraries

How to install CUDD?

To build an application that uses the CUDD package, you should add:

#include "util.h"
#include "cudd.h"

to your source files, and should link libcudd.a , libmtr.a , libst.a , and libutil.a to your executable. (All these libraries are part of the distribution.) Some platforms require specific compiler and linker flags. Refer to the Makefile in the top-level directory of the distribution.

An example of a Makefile is the following: Makefile

Tutorial 1: Write your first program with CUDD

The basic use of CUDD is easy:

  • Initialize a DdManager using Cudd_Init
  • Create the DD
  • Shut down the DdManager using Cudd_Quit(DdManager* ddmanager)

Sample code for the main program

The program below creates a single BDD variable

int main (int argc, char *argv[])
{
    DdManager *gbm; /* Global BDD manager. */
    char filename[30];
    gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
    DdNode *bdd = Cudd_bddNewVar(gbm); /*Create a new BDD variable*/
    Cudd_Ref(bdd); /*Increases the reference count of a node*/
    Cudd_Quit(gbm);
    return 0;
}

How to debug your program

One handy debugging tool in the CUDD package is a function called Cudd_PrintDebug()
Cudd_PrintDebug() takes as parameters the following (in the listed order):

DdManager* ddmanager; //The manager
DdNode* ddnode; //The Decision diagram
int n;
int pr; //The level of debugging 

pr can be set from 0 to any number, depending on the amount of information you want to display.
This function prints out useful statistics including the number of nodes, the number of leaves, and the number of minterms.

Sample function for printing a DD summary

/**
 * Print a dd summary
 * pr = 0 : prints nothing
 * pr = 1 : prints counts of nodes and minterms
 * pr = 2 : prints counts + disjoint sum of product
 * pr = 3 : prints counts + list of nodes
 * pr > 3 : prints counts + disjoint sum of product + list of nodes
 * @param the dd node
 */
void print_dd (DdNode	*dd, int n, int pr, char *name)
{
    printf("%s\n", name);
    printf("DdManager nodes: %ld | ", Cudd_ReadNodeCount(gbm)); /*Reports the number of live nodes in BDDs and ADDs*/
    printf("DdManager vars: %d | ", Cudd_ReadSize(gbm) ); /*Returns the number of BDD variables in existance*/
    printf("DdNode nodes: %d | ", Cudd_DagSize(dd)); /*Reports the number of nodes in the BDD*/
	printf("DdNode vars: %d | ", Cudd_SupportSize(gbm, dd) ); /*Returns the number of variables in the BDD*/
    printf("DdManager reorderings: %d | ", Cudd_ReadReorderings(gbm) ); /*Returns the number of times reordering has occurred*/
    printf("DdManager memory: %ld |\n\n", Cudd_ReadMemoryInUse(gbm) ); /*Returns the memory in use by the manager measured in bytes*/
    Cudd_PrintDebug(gbm, dd, n, pr);	// Prints to the standard output a DD and its statistics: number of nodes, number of leaves, number of minterms.
}

Another handy function is Cudd_PrintInfo()
Cudd_PrintInfo() prints out statistics and settings for a CUDD manager:
You can get a lot of useful information from Cudd_PrintInfo(). The lines below show the statistics dumped to a file:

**** CUDD modifiable parameters ****
Hard limit for cache size: 699050
Cache hit threshold for resizing: 30%
Garbage collection enabled: yes
Limit for fast unique table growth: 419430
Maximum number of variables sifted per reordering: 1000
Maximum number of variable swaps per reordering: 2000000
Maximum growth while sifting a variable: 1.2
Dynamic reordering of BDDs enabled: no
Default BDD reordering method: 4
Dynamic reordering of ZDDs enabled: no
Default ZDD reordering method: 4
Realignment of ZDDs to BDDs enabled: no
Realignment of BDDs to ZDDs enabled: no
Dead nodes counted in triggering reordering: no
Group checking criterion: 7
Recombination threshold: 0
Symmetry violation threshold: 0
Arc violation threshold: 0
GA population size: 0
Number of crossovers for GA: 0
Next reordering threshold: 4004
**** CUDD non-modifiable parameters ****
Memory in use: 8949888
Peak number of nodes: 1022
Peak number of live nodes: 19
Number of BDD variables: 4
Number of ZDD variables: 0
Number of cache entries: 262144
Number of cache look-ups: 12
Number of cache hits: 0
Number of cache insertions: 14
Number of cache collisions: 0
Number of cache deletions: 0
Cache used slots = 0.01% (expected 0.01%)
Soft limit for cache size: 5120
Number of buckets in unique table: 1280
Used buckets in unique table: 1.80% (expected 1.78%)
Number of BDD and ADD nodes: 23
Number of ZDD nodes: 0
Number of dead BDD and ADD nodes: 8
Number of dead ZDD nodes: 0
Total number of nodes allocated: 23
Total number of nodes reclaimed: 0
Garbage collections so far: 0
Time for garbage collection: 0.00 sec
Reorderings so far: 0
Time for reordering: 0.00 sec

Visualize the BDD

So, you successfully created a BDD, now what?

After you create a BDD or an ADD of type DdNode, you can plot it as a .dot file using the Cudd_DumpDot() function. You should provide an output file pointer, the DD manager, the number of nodes, and the node array pointer. The following functions show how to print a DD to a file.

Here is a simple way to visualize the BDD as an actual graph.

Sample function for printing a dd summary

/**
 * Writes a dot file representing the argument DDs
 * @param the node object
 */
void write_dd (DdNode *dd, char* filename)
{
    FILE *outfile; // output file pointer for .dot file
    outfile = fopen(filename,"w");
    DdNode **ddnodearray = (DdNode**)malloc(sizeof(DdNode*)); // initialize the function array
    ddnodearray[0] = dd;
    Cudd_DumpDot(gbm, 1, ddnodearray, NULL, NULL, outfile); // dump the function to .dot file
    free(ddnodearray);
    fclose (outfile); // close the file */
}

Once you generate the .dot file, you can open it using the GraphViz tool.
Graphviz is open-source graph visualization software. It works very well for representing structural information as diagrams of abstract graphs and networks. GraphViz is available for download here: https://www.graphviz.org/download/.
Just locate the .dot file and open it with Graphviz.

Sample program for printing a creating and printing a dd (Complete)

The entire program looks like this

/*
* FILENAME: transfer.c
* Overview: BDD tutorial
* AUTHOR: David Kebo Houngninou
*/

#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>
#include "cudd.h"

/**
 * Print a dd summary
 * pr = 0 : prints nothing
 * pr = 1 : prints counts of nodes and minterms
 * pr = 2 : prints counts + disjoint sum of product
 * pr = 3 : prints counts + list of nodes
 * pr > 3 : prints counts + disjoint sum of product + list of nodes
 * @param the dd node
 */
void print_dd (DdManager *gbm, DdNode *dd, int n, int pr )
{
    printf("DdManager nodes: %ld | ", Cudd_ReadNodeCount(gbm)); /*Reports the number of live nodes in BDDs and ADDs*/
    printf("DdManager vars: %d | ", Cudd_ReadSize(gbm) ); /*Returns the number of BDD variables in existence*/
    printf("DdManager reorderings: %d | ", Cudd_ReadReorderings(gbm) ); /*Returns the number of times reordering has occurred*/
    printf("DdManager memory: %ld \n", Cudd_ReadMemoryInUse(gbm) ); /*Returns the memory in use by the manager measured in bytes*/
    Cudd_PrintDebug(gbm, dd, n, pr);  // Prints to the standard output a DD and its statistics: number of nodes, number of leaves, number of minterms.
}


/**
 * Writes a dot file representing the argument DDs
 * @param the node object
 */
void write_dd (DdManager *gbm, DdNode *dd, char* filename)
{
    FILE *outfile; // output file pointer for .dot file
    outfile = fopen(filename,"w");
    DdNode **ddnodearray = (DdNode**)malloc(sizeof(DdNode*)); // initialize the function array
    ddnodearray[0] = dd;
    Cudd_DumpDot(gbm, 1, ddnodearray, NULL, NULL, outfile); // dump the function to .dot file
    free(ddnodearray);
    fclose (outfile); // close the file */
}

// This program creates a single BDD variable
int main (int argc, char *argv[])
{
    DdManager *gbm; /* Global BDD manager. */
    char filename[30];
    gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
    DdNode *bdd = Cudd_bddNewVar(gbm); /*Create a new BDD variable*/
    Cudd_Ref(bdd); /*Increases the reference count of a node*/
    bdd = Cudd_BddToAdd(gbm, bdd); /*Convert BDD to ADD for display purpose*/
    print_dd (gbm, bdd, 2,4); /*Print the dd to standard output*/
    sprintf(filename, "./bdd/graph.dot"); /*Write .dot filename to a string*/
    write_dd(gbm, bdd, filename);  /*Write the resulting cascade dd to a file*/
    Cudd_Quit(gbm);
    return 0;
}

Graph representation of the BDD

Using Graphviz, you can visualize the BDD as a graph. The graph should look like this.

Download Tutorial 1

You can download the full code for this example here:

tutorial1.tar.gz


Tutorial 2: BDD of Boolean functions

Common manipulations of BDDs can be accomplished by calling operators on variables.
The CUDD package includes Boolean functions that can be used for BDD operations such as Cudd_Not, Cudd_bddAnd, Cudd_bddOr, Cudd_Xor, etc.

BDD for the Exclusive-OR Boolean function

The truth table for an Exclusive-OR

x1 x2 f
0 0 0
0 1 1
1 0 1
1 1 0

Logic gate for an Exclusive-OR

BDD for an Exclusive-OR

For the Exclusive-OR Boolean function, we use Cudd_bddXor
The following fragment of code illustrates how to build the BDD for the function f = x1 ⊕ x2

Sample program for the XOR Boolean function

The main function looks like this

int main (int argc, char *argv[])
{
    char filename[30];
    DdManager *gbm; /* Global BDD manager. */
    gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
    DdNode *bdd, *x1, *x2;
    x1 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x1*/
    x2 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x2*/
    bdd = Cudd_bddXor(gbm, x1, x2); /*Perform XOR Boolean operation*/
    Cudd_Ref(bdd);          /*Update the reference count for the node just created.*/
    bdd = Cudd_BddToAdd(gbm, bdd); /*Convert BDD to ADD for display purpose*/
    print_dd (gbm, bdd, 2,4);   /*Print the dd to standard output*/
    sprintf(filename, "./bdd/graph.dot"); /*Write .dot filename to a string*/
    write_dd(gbm, bdd, filename);  /*Write the resulting cascade dd to a file*/
    Cudd_Quit(gbm);
    return 0; 
}

BDD for the AND Boolean function

The truth table for an AND

x1 x2 f
0 0 0
0 1 0
1 0 0
1 1 1

Logic gate for a logic AND

BDD for a logic AND

For the AND Boolean function, we use Cudd_bddAnd
The following fragment of code illustrates how to build the BDD for the function f = x1 ∧ x1

Sample program for the AND Boolean function

The main function looks like this

int main (int argc, char *argv[])
{
    char filename[30];
    DdManager *gbm; /* Global BDD manager. */
    gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
    DdNode *bdd, *x1, *x2;
    x1 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x1*/
    x2 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x2*/
    bdd = Cudd_bddAnd(gbm, x1, x2); /*Perform AND Boolean operation*/
    Cudd_Ref(bdd);          /*Update the reference count for the node just created.*/
    bdd = Cudd_BddToAdd(gbm, bdd); /*Convert BDD to ADD for display purpose*/
    print_dd (gbm, bdd, 2,4);   /*Print the dd to standard output*/
    sprintf(filename, "./bdd/graph.dot"); /*Write .dot filename to a string*/
    write_dd(gbm, bdd, filename);  /*Write the resulting cascade dd to a file*/
    Cudd_Quit(gbm);
    return 0; 
}

BDD for the OR Boolean function

The truth table for a logic OR

x1 x2 f
0 0 0
0 1 1
1 0 1
1 1 1

Logic gate for a logic OR

BDD for a logic OR

For the OR Boolean function, we use Cudd_bddOr
The following fragment of code illustrates how to build the BDD for the function f = x1 ∨ x2

Sample program for the OR Boolean function

The main function looks like this

int main (int argc, char *argv[])
{
    char filename[30];
    DdManager *gbm; /* Global BDD manager. */
    gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
    DdNode *bdd, *x1, *x2;
    x1 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x1*/
    x2 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x2*/
    bdd = Cudd_bddOr(gbm, x1, x2); /*Perform OR Boolean operation*/
    Cudd_Ref(bdd);          /*Update the reference count for the node just created.*/
    bdd = Cudd_BddToAdd(gbm, bdd); /*Convert BDD to ADD for display purpose*/
    print_dd (gbm, bdd, 2,4);   /*Print the dd to standard output*/
    sprintf(filename, "./bdd/graph.dot"); /*Write .dot filename to a string*/
    write_dd(gbm, bdd, filename);  /*Write the resulting cascade dd to a file*/
    Cudd_Quit(gbm);
    return 0; 
}

BDD for the XNOR Boolean function

The truth table for an XNOR

x1 x2 f
0 0 1
0 1 0
1 0 0
1 1 1

Logic gate for an XNOR

BDD for an XNOR

For the XNOR Boolean function, we use Cudd_bddXnor
The following fragment of code illustrates how to build the BDD for the function f = ¬ (x1 ⊕ x2)

Sample program for the XNOR Boolean function

The main function looks like this

int main (int argc, char *argv[])
{
    char filename[30];
    DdManager *gbm; /* Global BDD manager. */
    gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
    DdNode *bdd, *x1, *x2;
    x1 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x1*/
    x2 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x2*/
    bdd = Cudd_bddXnor(gbm, x1, x2); /*Perform XNOR Boolean operation*/
    Cudd_Ref(bdd);          /*Update the reference count for the node just created.*/
    bdd = Cudd_BddToAdd(gbm, bdd); /*Convert BDD to ADD for display purpose*/
    print_dd (gbm, bdd, 2,4);   /*Print the dd to standard output*/
    sprintf(filename, "./bdd/graph.dot"); /*Write .dot filename to a string*/
    write_dd(gbm, bdd, filename);  /*Write the resulting cascade dd to a file*/
    Cudd_Quit(gbm);
    return 0; 
}

BDD for the NAND Boolean function

The truth table for an NAND

x1 x2 f
0 0 1
0 1 1
1 0 1
1 1 0

Logic gate for an NAND

BDD for an NAND

For the NAND Boolean function, we use Cudd_bddNand
The following fragment of code illustrates how to build the BDD for the function f = ¬ (x1 ∧ x2)

Sample program for the OR Boolean function

The main function looks like this

int main (int argc, char *argv[])
{
    char filename[30];
    DdManager *gbm; /* Global BDD manager. */
    gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
    DdNode *bdd, *x1, *x2;
    x1 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x1*/
    x2 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x2*/
    bdd = Cudd_bddNand(gbm, x1, x2); /*Perform NAND Boolean operation*/
    Cudd_Ref(bdd);          /*Update the reference count for the node just created.*/
    bdd = Cudd_BddToAdd(gbm, bdd); /*Convert BDD to ADD for display purpose*/
    print_dd (gbm, bdd, 2,4);   /*Print the dd to standard output*/
    sprintf(filename, "./bdd/graph.dot"); /*Write .dot filename to a string*/
    write_dd(gbm, bdd, filename);  /*Write the resulting cascade dd to a file*/
    Cudd_Quit(gbm);
    return 0; 
}

BDD for the NOR Boolean function

The truth table for an NOR

x1 x2 f
0 0 1
0 1 0
1 0 0
1 1 0

Logic gate for an NOR

BDD for an NOR

For the NOR Boolean function, we use Cudd_bddNor
The following fragment of code illustrates how to build the BDD for the function f = ¬ (x1 ∨ x2)

Sample program for the NOR Boolean function

The main function looks like this

int main (int argc, char *argv[])
{
    char filename[30];
    DdManager *gbm; /* Global BDD manager. */
    gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
    DdNode *bdd, *x1, *x2;
    x1 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x1*/
    x2 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x2*/
    bdd = Cudd_bddNor(gbm, x1, x2); /*Perform NOR Boolean operation*/
    Cudd_Ref(bdd);          /*Update the reference count for the node just created.*/
    bdd = Cudd_BddToAdd(gbm, bdd); /*Convert BDD to ADD for display purpose*/
    print_dd (gbm, bdd, 2,4);   /*Print the dd to standard output*/
    sprintf(filename, "./bdd/graph.dot"); /*Write .dot filename to a string*/
    write_dd(gbm, bdd, filename);  /*Write the resulting cascade dd to a file*/
    Cudd_Quit(gbm);
    return 0; 
}

BDD for the NOT Boolean function

The truth table for a NOT

x1 f
0 1
1 0

Logic gate for a NOT

BDD for a NOT

For the NOT Boolean function, we use Cudd_Not
The following fragment of code illustrates how to build the BDD for the function f = ¬x1

Sample program for the NOT Boolean function

The main function looks like this

int main (int argc, char *argv[])
{
    char filename[30];
    DdManager *gbm; /* Global BDD manager. */
    gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
    DdNode *bdd, *x1;
    x1 = Cudd_bddNewVar(gbm); /*Create a new BDD variable x1*/
    bdd = Cudd_Not(x1); /*Perform NOT Boolean operation*/
    Cudd_Ref(bdd);          /*Update the reference count for the node just created.*/
    bdd = Cudd_BddToAdd(gbm, bdd); /*Convert BDD to ADD for display purpose*/
    print_dd (gbm, bdd, 2,4);   /*Print the dd to standard output*/
    sprintf(filename, "./bdd/graph.dot"); /*Write .dot filename to a string*/
    write_dd(gbm, bdd, filename);  /*Write the resulting cascade dd to a file*/
    Cudd_Quit(gbm);
    return 0;
}

BDD for the function f = x0’x1’x2’x3′

The truth table for this function is the following:

The truth table for f = x0’x1’x2’x3′

x0 x1 x2 x3 f
0 0 0 0 1
0 0 0 1 0
0 0 1 0 0
0 0 1 1 0
0 1 0 0 0
0 1 0 1 0
0 1 1 0 0
0 1 1 1 0
1 0 0 0 0
1 0 0 1 0
1 0 1 0 0
1 0 1 1 0
1 1 0 0 0
1 1 0 1 0
1 1 1 0 0
1 1 1 1 0

Logic circuit for f = x0’x1’x2’x3′

BDD for f = x0’x1’x2’x3′

Sample program to create a BDD for the function f = x0’x1’x2’x3′

The entire program looks like this

/*
* FILENAME: tutorial.c
* Overview: BDD tutorial
* AUTHOR: David Kebo Houngninou
*/

#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>
#include "cudd.h"

/**
 * Print a dd summary
 * pr = 0 : prints nothing
 * pr = 1 : prints counts of nodes and minterms
 * pr = 2 : prints counts + disjoint sum of product
 * pr = 3 : prints counts + list of nodes
 * pr > 3 : prints counts + disjoint sum of product + list of nodes
 * @param the dd node
 */
void print_dd (DdManager *gbm, DdNode *dd, int n, int pr )
{
    printf("DdManager nodes: %ld | ", Cudd_ReadNodeCount(gbm)); /*Reports the number of live nodes in BDDs and ADDs*/
    printf("DdManager vars: %d | ", Cudd_ReadSize(gbm) ); /*Returns the number of BDD variables in existence*/
    printf("DdManager reorderings: %d | ", Cudd_ReadReorderings(gbm) ); /*Returns the number of times reordering has occurred*/
    printf("DdManager memory: %ld \n", Cudd_ReadMemoryInUse(gbm) ); /*Returns the memory in use by the manager measured in bytes*/
    Cudd_PrintDebug(gbm, dd, n, pr);  // Prints to the standard output a DD and its statistics: number of nodes, number of leaves, number of minterms.
}


/**
 * Writes a dot file representing the argument DDs
 * @param the node object
 */
void write_dd (DdManager *gbm, DdNode *dd, char* filename)
{
    FILE *outfile; // output file pointer for .dot file
    outfile = fopen(filename,"w");
    DdNode **ddnodearray = (DdNode**)malloc(sizeof(DdNode*)); // initialize the function array
    ddnodearray[0] = dd;
    Cudd_DumpDot(gbm, 1, ddnodearray, NULL, NULL, outfile); // dump the function to .dot file
    free(ddnodearray);
    fclose (outfile); // close the file */
}

int main (int argc, char *argv[])
{
    char filename[30];
    DdManager *gbm; /* Global BDD manager. */
    gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0); /* Initialize a new BDD manager. */
    DdNode *bdd, *var, *tmp_neg, *tmp;
    int i;
    bdd = Cudd_ReadOne(gbm); /*Returns the logic one constant of the manager*/
    Cudd_Ref(bdd); /*Increases the reference count of a node*/
    
    for (i = 3; i >= 0; i--) {
      var = Cudd_bddIthVar(gbm,i); /*Create a new BDD variable*/
      tmp_neg = Cudd_Not(var); /*Perform NOT Boolean operation*/
      tmp = Cudd_bddAnd(gbm, tmp_neg, bdd); /*Perform AND Boolean operation*/
      Cudd_Ref(tmp);
      Cudd_RecursiveDeref(gbm,bdd);
      bdd = tmp;
    }
    
    bdd = Cudd_BddToAdd(gbm, bdd); /*Convert BDD to ADD for display purpose*/
    print_dd (gbm, bdd, 2,4); /*Print the dd to standard output*/
    sprintf(filename, "./bdd/graph.dot"); /*Write .dot filename to a string*/
    write_dd(gbm, bdd, filename);  /*Write the resulting cascade dd to a file*/
    Cudd_Quit(gbm);
    return 0; 
}

Download Tutorial 2

You can download the full code for this example here:

tutorial2.tar.gz


Tutorial 3: Variable reordering

The purpose of variable reordering is to reduce the size (number of nodes) of the BDD by optimizing the order of the variables. Finding an optimal order for a BDD is an NP-complete problem; therefore, several heuristic methods were developed for variable ordering. The CUDD package provides a rich set of dynamic reordering algorithms that you can apply to your BDD.

After initializing the BDD manager, we can make a call to a variable reordering method (Choose only one of the options below)

// Initialize a new BDD manager
gbm = Cudd_Init(0,0,CUDD_UNIQUE_SLOTS,CUDD_CACHE_SLOTS,0);

//Option 1: Dynamic reordering by sifting
Cudd_AutodynEnable(gbm, CUDD_REORDER_SYMM_SIFT);
Cudd_ReduceHeap(gbm, CUDD_REORDER_SYMM_SIFT, 3000);

//Option 2: Dynamic reordering by window permutation
Cudd_AutodynEnable(gbm, CUDD_REORDER_WINDOW2);
Cudd_ReduceHeap(gbm, CUDD_REORDER_WINDOW2, 3000);

//Option 3: Dynamic reordering by simulated annealing
Cudd_AutodynEnable(gbm, CUDD_REORDER_ANNEALING);
Cudd_ReduceHeap(gbm, CUDD_REORDER_ANNEALING, 3000);

//Option 4: Dynamic reordering by genetic algorithm
Cudd_AutodynEnable(gbm, CUDD_REORDER_GENETIC);
Cudd_ReduceHeap(gbm, CUDD_REORDER_GENETIC, 3000);

//Option 5: Dynamic reordering by swapping
Cudd_AutodynEnable(gbm, CUDD_REORDER_RANDOM);
Cudd_ReduceHeap(gbm, CUDD_REORDER_RANDOM, 3000);

//Option 6: No reordering
Cudd_AutodynDisable (gbm);

Tutorial 4: Additional functions

Algebraic Decision Diagram (ADD) for a fanout

The fanout of a logic gate output is the number of gate inputs it can feed. A fanout can also be modeled as a Boolean function

An Algebraic Decision Diagram (ADD) is a BDD with a set of constant values different than the set {0,1}.
Instead of using a BDD, we use an ADD to represent a fanout because the leaf nodes have values different than 0 and 1.

The truth table for a fanout

x f1 f2
0 0 0
1 1 1

Representation of a fanout

ADD for a fanout

/**Function********************************************************************

  Synopsis    [Create a ADD from different sizes of fanouts]

  Description [The Else branch is always a zero (0)
 	Depending on the number of fanouts the Then branch varies between: (3 or 7 or 15 or 31 etc.)]

  @param the number of fanout branches
******************************************************************************/
DdNode * Cudd_fanout (int fanouts)
{
    DdNode *var = Cudd_addNewVar(gbm); /*Root node of the fanout*/
    Cudd_Ref(var);
    int coef = pow(2, fanouts)-1; /*Calculate the max value depending on the number of fanouts*/
    DdNode *retval = Cudd_addIte(gbm, var,  Cudd_addConst (gbm, (CUDD_VALUE_TYPE)coef), Cudd_addConst(gbm, (CUDD_VALUE_TYPE)0)); /*Else branch=0, Then branch=(3 or 7 or 15 or 31 etc.)*/
    Cudd_RecursiveDeref(gbm,var);
    return retval;
}

Algebraic Decision Diagram (ADD) for a crossover

A crossover represents two wires crossing each other. A crossover can also be modeled as a Boolean function

An Algebraic Decision Diagram (ADD) is a BDD with a set of constant values different than the set {0,1}.
Instead of using a BDD, we use an ADD to represent a crossover because the leaf nodes have values different than 0 and 1.

The truth table for a crossover

x1 x2 f1 f2
0 0 0 0
0 1 1 0
1 0 0 1
1 1 1 1

Representation of a crossover

ADD for a crossover

/**Function********************************************************************

  Synopsis    [Creates a ADD for a crossover]

  Description [A crossover is the intersection (crossing) of two wires
  The terminal nodes of a crossover ADD are 0, 2, 1 and 3]

  @param none
******************************************************************************/
DdNode * Cudd_crossover ()
{
    DdNode *var1 = Cudd_addNewVar(gbm); /*First variable in the crossover DD*/
    Cudd_Ref(var1);
    DdNode *var2 = Cudd_addNewVar(gbm); /*Second variable in the crossover DD*/
    Cudd_Ref(var2);
    DdNode *node1 = Cudd_addIte(gbm,var2, Cudd_addConst (gbm, (CUDD_VALUE_TYPE)2), Cudd_addConst(gbm, (CUDD_VALUE_TYPE)0)); /*Else branch=0, Then branch=2*/
    Cudd_Ref(node1);
    DdNode *node2 = Cudd_addIte(gbm,var2, Cudd_addConst (gbm, (CUDD_VALUE_TYPE)3), Cudd_addConst(gbm, (CUDD_VALUE_TYPE)1)); /*Else branch=1, Then branch=3*/
    Cudd_Ref(node2);

    DdNode *retval = Cudd_addIte(gbm,var1, node2 ,node1);
    Cudd_RecursiveDeref(gbm,var1);
    Cudd_RecursiveDeref(gbm,var2);
    Cudd_RecursiveDeref(gbm,node1);
    Cudd_RecursiveDeref(gbm,node2);
    return retval;
}
Scroll to Top