summaryrefslogtreecommitdiffstats
path: root/src/bdd/cudd/cuddSplit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bdd/cudd/cuddSplit.c')
-rw-r--r--src/bdd/cudd/cuddSplit.c657
1 files changed, 657 insertions, 0 deletions
diff --git a/src/bdd/cudd/cuddSplit.c b/src/bdd/cudd/cuddSplit.c
new file mode 100644
index 00000000..af7d6372
--- /dev/null
+++ b/src/bdd/cudd/cuddSplit.c
@@ -0,0 +1,657 @@
+/**CFile***********************************************************************
+
+ FileName [cuddSplit.c]
+
+ PackageName [cudd]
+
+ Synopsis [Returns a subset of minterms from a boolean function.]
+
+ Description [External functions included in this modoule:
+ <ul>
+ <li> Cudd_SplitSet()
+ </ul>
+ Internal functions included in this module:
+ <ul>
+ <li> cuddSplitSetRecur()
+ </u>
+ Static functions included in this module:
+ <ul>
+ <li> selectMintermsFromUniverse()
+ <li> mintermsFromUniverse()
+ <li> bddAnnotateMintermCount()
+ </ul> ]
+
+ SeeAlso []
+
+ Author [Balakrishna Kumthekar]
+
+ Copyright [This file was created at the University of Colorado at
+ Boulder. The University of Colorado at Boulder makes no warranty
+ about the suitability of this software for any purpose. It is
+ presented on an AS IS basis.]
+
+******************************************************************************/
+
+#include "util.h"
+#include "cuddInt.h"
+
+/*---------------------------------------------------------------------------*/
+/* Constant declarations */
+/*---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*/
+/* Type declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Structure declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Variable declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*/
+/* Macro declarations */
+/*---------------------------------------------------------------------------*/
+
+
+/**AutomaticStart*************************************************************/
+
+/*---------------------------------------------------------------------------*/
+/* Static function prototypes */
+/*---------------------------------------------------------------------------*/
+
+static DdNode * selectMintermsFromUniverse ARGS((DdManager *manager, int *varSeen, double n));
+static DdNode * mintermsFromUniverse ARGS((DdManager *manager, DdNode **vars, int numVars, double n, int index));
+static double bddAnnotateMintermCount ARGS((DdManager *manager, DdNode *node, double max, st_table *table));
+
+/**AutomaticEnd***************************************************************/
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of exported functions */
+/*---------------------------------------------------------------------------*/
+
+
+/**Function********************************************************************
+
+ Synopsis [Returns m minterms from a BDD.]
+
+ Description [Returns <code>m</code> minterms from a BDD whose
+ support has <code>n</code> variables at most. The procedure tries
+ to create as few extra nodes as possible. The function represented
+ by <code>S</code> depends on at most <code>n</code> of the variables
+ in <code>xVars</code>. Returns a BDD with <code>m</code> minterms
+ of the on-set of S if successful; NULL otherwise.]
+
+ SideEffects [None]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode *
+Cudd_SplitSet(
+ DdManager * manager,
+ DdNode * S,
+ DdNode ** xVars,
+ int n,
+ double m)
+{
+ DdNode *result;
+ DdNode *zero, *one;
+ double max, num;
+ st_table *mtable;
+ int *varSeen;
+ int i,index, size;
+
+ size = manager->size;
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Trivial cases. */
+ if (m == 0.0) {
+ return(zero);
+ }
+ if (S == zero) {
+ return(NULL);
+ }
+
+ max = pow(2.0,(double)n);
+ if (m > max)
+ return(NULL);
+
+ do {
+ manager->reordered = 0;
+ /* varSeen is used to mark the variables that are encountered
+ ** while traversing the BDD S.
+ */
+ varSeen = ALLOC(int, size);
+ if (varSeen == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ for (i = 0; i < size; i++) {
+ varSeen[i] = -1;
+ }
+ for (i = 0; i < n; i++) {
+ index = (xVars[i])->index;
+ varSeen[manager->invperm[index]] = 0;
+ }
+
+ if (S == one) {
+ if (m == max)
+ return(S);
+ result = selectMintermsFromUniverse(manager,varSeen,m);
+ if (result)
+ cuddRef(result);
+ FREE(varSeen);
+ } else {
+ mtable = st_init_table(st_ptrcmp,st_ptrhash);
+ if (mtable == NULL) {
+ (void) fprintf(manager->out,
+ "Cudd_SplitSet: out-of-memory.\n");
+ FREE(varSeen);
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+ /* The nodes of BDD S are annotated by the number of minterms
+ ** in their onset. The node and the number of minterms in its
+ ** onset are stored in mtable.
+ */
+ num = bddAnnotateMintermCount(manager,S,max,mtable);
+ if (m == num) {
+ st_foreach(mtable,cuddStCountfree,NIL(char));
+ st_free_table(mtable);
+ FREE(varSeen);
+ return(S);
+ }
+
+ result = cuddSplitSetRecur(manager,mtable,varSeen,S,m,max,0);
+ if (result)
+ cuddRef(result);
+ st_foreach(mtable,cuddStCountfree,NULL);
+ st_free_table(mtable);
+ FREE(varSeen);
+ }
+ } while (manager->reordered == 1);
+
+ cuddDeref(result);
+ return(result);
+
+} /* end of Cudd_SplitSet */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of internal functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [Implements the recursive step of Cudd_SplitSet.]
+
+ Description [Implements the recursive step of Cudd_SplitSet. The
+ procedure recursively traverses the BDD and checks to see if any
+ node satisfies the minterm requirements as specified by 'n'. At any
+ node X, n is compared to the number of minterms in the onset of X's
+ children. If either of the child nodes have exactly n minterms, then
+ that node is returned; else, if n is greater than the onset of one
+ of the child nodes, that node is retained and the difference in the
+ number of minterms is extracted from the other child. In case n
+ minterms can be extracted from constant 1, the algorithm returns the
+ result with at most log(n) nodes.]
+
+ SideEffects [The array 'varSeen' is updated at every recursive call
+ to set the variables traversed by the procedure.]
+
+ SeeAlso []
+
+******************************************************************************/
+DdNode*
+cuddSplitSetRecur(
+ DdManager * manager,
+ st_table * mtable,
+ int * varSeen,
+ DdNode * p,
+ double n,
+ double max,
+ int index)
+{
+ DdNode *one, *zero, *N, *Nv;
+ DdNode *Nnv, *q, *r, *v;
+ DdNode *result;
+ double *dummy, numT, numE;
+ int variable, positive;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* If p is constant, extract n minterms from constant 1. The procedure by
+ ** construction guarantees that minterms will not be extracted from
+ ** constant 0.
+ */
+ if (Cudd_IsConstant(p)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ return(q);
+ }
+
+ N = Cudd_Regular(p);
+
+ /* Set variable as seen. */
+ variable = N->index;
+ varSeen[manager->invperm[variable]] = -1;
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ if (Cudd_IsComplement(p)) {
+ Nv = Cudd_Not(Nv);
+ Nnv = Cudd_Not(Nnv);
+ }
+
+ /* If both the children of 'p' are constants, extract n minterms from a
+ ** constant node.
+ */
+ if (Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ if (q == NULL) {
+ return(NULL);
+ }
+ cuddRef(q);
+ r = cuddBddAndRecur(manager,p,q);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(manager,q);
+ cuddDeref(r);
+ return(r);
+ }
+
+ /* Lookup the # of minterms in the onset of the node from the table. */
+ if (!Cudd_IsConstant(Nv)) {
+ st_lookup(mtable,(char *)Nv, (char **)&dummy);
+ numT = *dummy/(2*(1<<index));
+ } else if (Nv == one) {
+ numT = max/(2*(1<<index));
+ } else {
+ numT = 0;
+ }
+
+ if (!Cudd_IsConstant(Nnv)) {
+ st_lookup(mtable,(char *)Nnv, (char **)&dummy);
+ numE = *dummy/(2*(1<<index));
+ } else if (Nnv == one) {
+ numE = max/(2*(1<<index));
+ } else {
+ numE = 0;
+ }
+
+ v = cuddUniqueInter(manager,variable,one,zero);
+ cuddRef(v);
+
+ /* If perfect match. */
+ if (numT == n) {
+ q = cuddBddAndRecur(manager,v,Nv);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(q);
+ return(q);
+ }
+ if (numE == n) {
+ q = cuddBddAndRecur(manager,Cudd_Not(v),Nnv);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(q);
+ return(q);
+ }
+ /* If n is greater than numT, extract the difference from the ELSE child
+ ** and retain the function represented by the THEN branch.
+ */
+ if (numT < n) {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nnv,(n-numT),max,index+1);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ r = cuddBddIteRecur(manager,v,Nv,q);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(r);
+ return(r);
+ }
+ /* If n is greater than numE, extract the difference from the THEN child
+ ** and retain the function represented by the ELSE branch.
+ */
+ if (numE < n) {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nv, (n-numE),max,index+1);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ r = cuddBddIteRecur(manager,v,q,Nnv);
+ if (r == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(r);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(r);
+ return(r);
+ }
+
+ /* None of the above cases; (n < numT and n < numE) and either of
+ ** the Nv, Nnv or both are not constants. If possible extract the
+ ** required minterms the constant branch.
+ */
+ if (Cudd_IsConstant(Nv) && !Cudd_IsConstant(Nnv)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ result = cuddBddAndRecur(manager,v,q);
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(result);
+ return(result);
+ } else if (!Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) {
+ q = selectMintermsFromUniverse(manager,varSeen,n);
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+ result = cuddBddAndRecur(manager,Cudd_Not(v),q);
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(result);
+ return(result);
+ }
+
+ /* Both Nv and Nnv are not constants. So choose the one which
+ ** has fewer minterms in its onset.
+ */
+ positive = 0;
+ if (numT < numE) {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nv,n,max,index+1);
+ positive = 1;
+ } else {
+ q = cuddSplitSetRecur(manager,mtable,varSeen,
+ Nnv,n,max,index+1);
+ }
+
+ if (q == NULL) {
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(q);
+
+ if (positive) {
+ result = cuddBddAndRecur(manager,v,q);
+ } else {
+ result = cuddBddAndRecur(manager,Cudd_Not(v),q);
+ }
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ Cudd_RecursiveDeref(manager,v);
+ cuddDeref(result);
+
+ return(result);
+
+} /* end of cuddSplitSetRecur */
+
+
+/*---------------------------------------------------------------------------*/
+/* Definition of static functions */
+/*---------------------------------------------------------------------------*/
+
+/**Function********************************************************************
+
+ Synopsis [This function prepares an array of variables which have not been
+ encountered so far when traversing the procedure cuddSplitSetRecur.]
+
+ Description [This function prepares an array of variables which have not been
+ encountered so far when traversing the procedure cuddSplitSetRecur. This
+ array is then used to extract the required number of minterms from a constant
+ 1. The algorithm guarantees that the size of BDD will be utmost \log(n).]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+selectMintermsFromUniverse(
+ DdManager * manager,
+ int * varSeen,
+ double n)
+{
+ int numVars;
+ int i, size, j;
+ DdNode *one, *zero, *result;
+ DdNode **vars;
+
+ numVars = 0;
+ size = manager->size;
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ /* Count the number of variables not encountered so far in procedure
+ ** cuddSplitSetRecur.
+ */
+ for (i = size-1; i >= 0; i--) {
+ if(varSeen[i] == 0)
+ numVars++;
+ }
+ vars = ALLOC(DdNode *, numVars);
+ if (!vars) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return(NULL);
+ }
+
+ j = 0;
+ for (i = size-1; i >= 0; i--) {
+ if(varSeen[i] == 0) {
+ vars[j] = cuddUniqueInter(manager,manager->perm[i],one,zero);
+ cuddRef(vars[j]);
+ j++;
+ }
+ }
+
+ /* Compute a function which has n minterms and depends on at most
+ ** numVars variables.
+ */
+ result = mintermsFromUniverse(manager,vars,numVars,n, 0);
+ if (result)
+ cuddRef(result);
+
+ for (i = 0; i < numVars; i++)
+ Cudd_RecursiveDeref(manager,vars[i]);
+ FREE(vars);
+
+ return(result);
+
+} /* end of selectMintermsFromUniverse */
+
+
+/**Function********************************************************************
+
+ Synopsis [Recursive procedure to extract n mintems from constant 1.]
+
+ Description [Recursive procedure to extract n mintems from constant 1.]
+
+ SideEffects [None]
+
+******************************************************************************/
+static DdNode *
+mintermsFromUniverse(
+ DdManager * manager,
+ DdNode ** vars,
+ int numVars,
+ double n,
+ int index)
+{
+ DdNode *one, *zero;
+ DdNode *q, *result;
+ double max, max2;
+
+ statLine(manager);
+ one = DD_ONE(manager);
+ zero = Cudd_Not(one);
+
+ max = pow(2.0, (double)numVars);
+ max2 = max / 2.0;
+
+ if (n == max)
+ return(one);
+ if (n == 0.0)
+ return(zero);
+ /* if n == 2^(numVars-1), return a single variable */
+ if (n == max2)
+ return vars[index];
+ else if (n > max2) {
+ /* When n > 2^(numVars-1), a single variable vars[index]
+ ** contains 2^(numVars-1) minterms. The rest are extracted
+ ** from a constant with 1 less variable.
+ */
+ q = mintermsFromUniverse(manager,vars,numVars-1,(n-max2),index+1);
+ if (q == NULL)
+ return(NULL);
+ cuddRef(q);
+ result = cuddBddIteRecur(manager,vars[index],one,q);
+ } else {
+ /* When n < 2^(numVars-1), a literal of variable vars[index]
+ ** is selected. The required n minterms are extracted from a
+ ** constant with 1 less variable.
+ */
+ q = mintermsFromUniverse(manager,vars,numVars-1,n,index+1);
+ if (q == NULL)
+ return(NULL);
+ cuddRef(q);
+ result = cuddBddAndRecur(manager,vars[index],q);
+ }
+
+ if (result == NULL) {
+ Cudd_RecursiveDeref(manager,q);
+ return(NULL);
+ }
+ cuddRef(result);
+ Cudd_RecursiveDeref(manager,q);
+ cuddDeref(result);
+ return(result);
+
+} /* end of mintermsFromUniverse */
+
+
+/**Function********************************************************************
+
+ Synopsis [Annotates every node in the BDD node with its minterm count.]
+
+ Description [Annotates every node in the BDD node with its minterm count.
+ In this function, every node and the minterm count represented by it are
+ stored in a hash table.]
+
+ SideEffects [Fills up 'table' with the pair <node,minterm_count>.]
+
+******************************************************************************/
+static double
+bddAnnotateMintermCount(
+ DdManager * manager,
+ DdNode * node,
+ double max,
+ st_table * table)
+{
+
+ DdNode *N,*Nv,*Nnv;
+ register double min_v,min_nv;
+ register double min_N;
+ double *pmin;
+ double *dummy;
+
+ statLine(manager);
+ N = Cudd_Regular(node);
+ if (cuddIsConstant(N)) {
+ if (node == DD_ONE(manager)) {
+ return(max);
+ } else {
+ return(0.0);
+ }
+ }
+
+ if (st_lookup(table,(char *)node,(char **)&dummy)) {
+ return(*dummy);
+ }
+
+ Nv = cuddT(N);
+ Nnv = cuddE(N);
+ if (N != node) {
+ Nv = Cudd_Not(Nv);
+ Nnv = Cudd_Not(Nnv);
+ }
+
+ /* Recur on the two branches. */
+ min_v = bddAnnotateMintermCount(manager,Nv,max,table) / 2.0;
+ if (min_v == (double)CUDD_OUT_OF_MEM)
+ return ((double)CUDD_OUT_OF_MEM);
+ min_nv = bddAnnotateMintermCount(manager,Nnv,max,table) / 2.0;
+ if (min_nv == (double)CUDD_OUT_OF_MEM)
+ return ((double)CUDD_OUT_OF_MEM);
+ min_N = min_v + min_nv;
+
+ pmin = ALLOC(double,1);
+ if (pmin == NULL) {
+ manager->errorCode = CUDD_MEMORY_OUT;
+ return((double)CUDD_OUT_OF_MEM);
+ }
+ *pmin = min_N;
+
+ if (st_insert(table,(char *)node, (char *)pmin) == ST_OUT_OF_MEM) {
+ FREE(pmin);
+ return((double)CUDD_OUT_OF_MEM);
+ }
+
+ return(min_N);
+
+} /* end of bddAnnotateMintermCount */