diff options
Diffstat (limited to 'src/bdd/cudd/cuddCompose.c')
-rw-r--r-- | src/bdd/cudd/cuddCompose.c | 1722 |
1 files changed, 1722 insertions, 0 deletions
diff --git a/src/bdd/cudd/cuddCompose.c b/src/bdd/cudd/cuddCompose.c new file mode 100644 index 00000000..8c858051 --- /dev/null +++ b/src/bdd/cudd/cuddCompose.c @@ -0,0 +1,1722 @@ +/**CFile*********************************************************************** + + FileName [cuddCompose.c] + + PackageName [cudd] + + Synopsis [Functional composition and variable permutation of DDs.] + + Description [External procedures included in this module: + <ul> + <li> Cudd_bddCompose() + <li> Cudd_addCompose() + <li> Cudd_addPermute() + <li> Cudd_addSwapVariables() + <li> Cudd_bddPermute() + <li> Cudd_bddVarMap() + <li> Cudd_SetVarMap() + <li> Cudd_bddSwapVariables() + <li> Cudd_bddAdjPermuteX() + <li> Cudd_addVectorCompose() + <li> Cudd_addGeneralVectorCompose() + <li> Cudd_addNonSimCompose() + <li> Cudd_bddVectorCompose() + </ul> + Internal procedures included in this module: + <ul> + <li> cuddBddComposeRecur() + <li> cuddAddComposeRecur() + </ul> + Static procedures included in this module: + <ul> + <li> cuddAddPermuteRecur() + <li> cuddBddPermuteRecur() + <li> cuddBddVarMapRecur() + <li> cuddAddVectorComposeRecur() + <li> cuddAddGeneralVectorComposeRecur() + <li> cuddAddNonSimComposeRecur() + <li> cuddBddVectorComposeRecur() + <li> ddIsIthAddVar() + <li> ddIsIthAddVarPair() + </ul> + The permutation functions use a local cache because the results to + be remembered depend on the permutation being applied. Since the + permutation is just an array, it cannot be stored in the global + cache. There are different procedured for BDDs and ADDs. This is + because bddPermuteRecur uses cuddBddIteRecur. If this were changed, + the procedures could be merged.] + + Author [Fabio Somenzi and Kavita Ravi] + + 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_hack.h" +#include "cuddInt.h" + + +/*---------------------------------------------------------------------------*/ +/* Constant declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Stucture declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Type declarations */ +/*---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/* Variable declarations */ +/*---------------------------------------------------------------------------*/ + +#ifndef lint +static char rcsid[] DD_UNUSED = "$Id: cuddCompose.c,v 1.1.1.1 2003/02/24 22:23:51 wjiang Exp $"; +#endif + +#ifdef DD_DEBUG +static int addPermuteRecurHits; +static int bddPermuteRecurHits; +static int bddVectorComposeHits; +static int addVectorComposeHits; + +static int addGeneralVectorComposeHits; +#endif + +/*---------------------------------------------------------------------------*/ +/* Macro declarations */ +/*---------------------------------------------------------------------------*/ + + +/**AutomaticStart*************************************************************/ + +/*---------------------------------------------------------------------------*/ +/* Static function prototypes */ +/*---------------------------------------------------------------------------*/ + +static DdNode * cuddAddPermuteRecur ARGS((DdManager *manager, DdHashTable *table, DdNode *node, int *permut)); +static DdNode * cuddBddPermuteRecur ARGS((DdManager *manager, DdHashTable *table, DdNode *node, int *permut)); +static DdNode * cuddBddVarMapRecur ARGS((DdManager *manager, DdNode *f)); +static DdNode * cuddAddVectorComposeRecur ARGS((DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vector, int deepest)); +static DdNode * cuddAddNonSimComposeRecur ARGS((DdManager *dd, DdNode *f, DdNode **vector, DdNode *key, DdNode *cube, int lastsub)); +static DdNode * cuddBddVectorComposeRecur ARGS((DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vector, int deepest)); +DD_INLINE static int ddIsIthAddVar ARGS((DdManager *dd, DdNode *f, unsigned int i)); + +static DdNode * cuddAddGeneralVectorComposeRecur ARGS((DdManager *dd, DdHashTable *table, DdNode *f, DdNode **vectorOn, DdNode **vectorOff, int deepest)); +DD_INLINE static int ddIsIthAddVarPair ARGS((DdManager *dd, DdNode *f, DdNode *g, unsigned int i)); + +/**AutomaticEnd***************************************************************/ + + +/*---------------------------------------------------------------------------*/ +/* Definition of exported functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Substitutes g for x_v in the BDD for f.] + + Description [Substitutes g for x_v in the BDD for f. v is the index of the + variable to be substituted. Cudd_bddCompose passes the corresponding + projection function to the recursive procedure, so that the cache may + be used. Returns the composed BDD if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_addCompose] + +******************************************************************************/ +DdNode * +Cudd_bddCompose( + DdManager * dd, + DdNode * f, + DdNode * g, + int v) +{ + DdNode *proj, *res; + + /* Sanity check. */ + if (v < 0 || v > dd->size) return(NULL); + + proj = dd->vars[v]; + do { + dd->reordered = 0; + res = cuddBddComposeRecur(dd,f,g,proj); + } while (dd->reordered == 1); + return(res); + +} /* end of Cudd_bddCompose */ + + +/**Function******************************************************************** + + Synopsis [Substitutes g for x_v in the ADD for f.] + + Description [Substitutes g for x_v in the ADD for f. v is the index of the + variable to be substituted. g must be a 0-1 ADD. Cudd_bddCompose passes + the corresponding projection function to the recursive procedure, so + that the cache may be used. Returns the composed ADD if successful; + NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddCompose] + +******************************************************************************/ +DdNode * +Cudd_addCompose( + DdManager * dd, + DdNode * f, + DdNode * g, + int v) +{ + DdNode *proj, *res; + + /* Sanity check. */ + if (v < 0 || v > dd->size) return(NULL); + + proj = dd->vars[v]; + do { + dd->reordered = 0; + res = cuddAddComposeRecur(dd,f,g,proj); + } while (dd->reordered == 1); + return(res); + +} /* end of Cudd_addCompose */ + + +/**Function******************************************************************** + + Synopsis [Permutes the variables of an ADD.] + + Description [Given a permutation in array permut, creates a new ADD + with permuted variables. There should be an entry in array permut + for each variable in the manager. The i-th entry of permut holds the + index of the variable that is to substitute the i-th + variable. Returns a pointer to the resulting ADD if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddPermute Cudd_addSwapVariables] + +******************************************************************************/ +DdNode * +Cudd_addPermute( + DdManager * manager, + DdNode * node, + int * permut) +{ + DdHashTable *table; + DdNode *res; + + do { + manager->reordered = 0; + table = cuddHashTableInit(manager,1,2); + if (table == NULL) return(NULL); + /* Recursively solve the problem. */ + res = cuddAddPermuteRecur(manager,table,node,permut); + if (res != NULL) cuddRef(res); + /* Dispose of local cache. */ + cuddHashTableQuit(table); + } while (manager->reordered == 1); + + if (res != NULL) cuddDeref(res); + return(res); + +} /* end of Cudd_addPermute */ + + +/**Function******************************************************************** + + Synopsis [Swaps two sets of variables of the same size (x and y) in + the ADD f.] + + Description [Swaps two sets of variables of the same size (x and y) in + the ADD f. The size is given by n. The two sets of variables are + assumed to be disjoint. Returns a pointer to the resulting ADD if + successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_addPermute Cudd_bddSwapVariables] + +******************************************************************************/ +DdNode * +Cudd_addSwapVariables( + DdManager * dd, + DdNode * f, + DdNode ** x, + DdNode ** y, + int n) +{ + DdNode *swapped; + int i, j, k; + int *permut; + + permut = ALLOC(int,dd->size); + if (permut == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(NULL); + } + for (i = 0; i < dd->size; i++) permut[i] = i; + for (i = 0; i < n; i++) { + j = x[i]->index; + k = y[i]->index; + permut[j] = k; + permut[k] = j; + } + + swapped = Cudd_addPermute(dd,f,permut); + FREE(permut); + + return(swapped); + +} /* end of Cudd_addSwapVariables */ + + +/**Function******************************************************************** + + Synopsis [Permutes the variables of a BDD.] + + Description [Given a permutation in array permut, creates a new BDD + with permuted variables. There should be an entry in array permut + for each variable in the manager. The i-th entry of permut holds the + index of the variable that is to substitute the i-th variable. + Returns a pointer to the resulting BDD if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_addPermute Cudd_bddSwapVariables] + +******************************************************************************/ +DdNode * +Cudd_bddPermute( + DdManager * manager, + DdNode * node, + int * permut) +{ + DdHashTable *table; + DdNode *res; + + do { + manager->reordered = 0; + table = cuddHashTableInit(manager,1,2); + if (table == NULL) return(NULL); + res = cuddBddPermuteRecur(manager,table,node,permut); + if (res != NULL) cuddRef(res); + /* Dispose of local cache. */ + cuddHashTableQuit(table); + + } while (manager->reordered == 1); + + if (res != NULL) cuddDeref(res); + return(res); + +} /* end of Cudd_bddPermute */ + + +/**Function******************************************************************** + + Synopsis [Remaps the variables of a BDD using the default variable map.] + + Description [Remaps the variables of a BDD using the default + variable map. A typical use of this function is to swap two sets of + variables. The variable map must be registered with Cudd_SetVarMap. + Returns a pointer to the resulting BDD if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddPermute Cudd_bddSwapVariables Cudd_SetVarMap] + +******************************************************************************/ +DdNode * +Cudd_bddVarMap( + DdManager * manager /* DD manager */, + DdNode * f /* function in which to remap variables */) +{ + DdNode *res; + + if (manager->map == NULL) return(NULL); + do { + manager->reordered = 0; + res = cuddBddVarMapRecur(manager, f); + } while (manager->reordered == 1); + + return(res); + +} /* end of Cudd_bddVarMap */ + + +/**Function******************************************************************** + + Synopsis [Registers a variable mapping with the manager.] + + Description [Registers with the manager a variable mapping described + by two sets of variables. This variable mapping is then used by + functions like Cudd_bddVarMap. This function is convenient for + those applications that perform the same mapping several times. + However, if several different permutations are used, it may be more + efficient not to rely on the registered mapping, because changing + mapping causes the cache to be cleared. (The initial setting, + however, does not clear the cache.) The two sets of variables (x and + y) must have the same size (x and y). The size is given by n. The + two sets of variables are normally disjoint, but this restriction is + not imposeded by the function. When new variables are created, the + map is automatically extended (each new variable maps to + itself). The typical use, however, is to wait until all variables + are created, and then create the map. Returns 1 if the mapping is + successfully registered with the manager; 0 otherwise.] + + SideEffects [Modifies the manager. May clear the cache.] + + SeeAlso [Cudd_bddVarMap Cudd_bddPermute Cudd_bddSwapVariables] + +******************************************************************************/ +int +Cudd_SetVarMap ( + DdManager *manager /* DD manager */, + DdNode **x /* first array of variables */, + DdNode **y /* second array of variables */, + int n /* length of both arrays */) +{ + int i; + + if (manager->map != NULL) { + cuddCacheFlush(manager); + } else { + manager->map = ALLOC(int,manager->maxSize); + if (manager->map == NULL) { + manager->errorCode = CUDD_MEMORY_OUT; + return(0); + } + manager->memused += sizeof(int) * manager->maxSize; + } + /* Initialize the map to the identity. */ + for (i = 0; i < manager->size; i++) { + manager->map[i] = i; + } + /* Create the map. */ + for (i = 0; i < n; i++) { + manager->map[x[i]->index] = y[i]->index; + manager->map[y[i]->index] = x[i]->index; + } + return(1); + +} /* end of Cudd_SetVarMap */ + + +/**Function******************************************************************** + + Synopsis [Swaps two sets of variables of the same size (x and y) in + the BDD f.] + + Description [Swaps two sets of variables of the same size (x and y) + in the BDD f. The size is given by n. The two sets of variables are + assumed to be disjoint. Returns a pointer to the resulting BDD if + successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddPermute Cudd_addSwapVariables] + +******************************************************************************/ +DdNode * +Cudd_bddSwapVariables( + DdManager * dd, + DdNode * f, + DdNode ** x, + DdNode ** y, + int n) +{ + DdNode *swapped; + int i, j, k; + int *permut; + + permut = ALLOC(int,dd->size); + if (permut == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(NULL); + } + for (i = 0; i < dd->size; i++) permut[i] = i; + for (i = 0; i < n; i++) { + j = x[i]->index; + k = y[i]->index; + permut[j] = k; + permut[k] = j; + } + + swapped = Cudd_bddPermute(dd,f,permut); + FREE(permut); + + return(swapped); + +} /* end of Cudd_bddSwapVariables */ + + +/**Function******************************************************************** + + Synopsis [Rearranges a set of variables in the BDD B.] + + Description [Rearranges a set of variables in the BDD B. The size of + the set is given by n. This procedure is intended for the + `randomization' of the priority functions. Returns a pointer to the + BDD if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddPermute Cudd_bddSwapVariables + Cudd_Dxygtdxz Cudd_Dxygtdyz Cudd_PrioritySelect] + +******************************************************************************/ +DdNode * +Cudd_bddAdjPermuteX( + DdManager * dd, + DdNode * B, + DdNode ** x, + int n) +{ + DdNode *swapped; + int i, j, k; + int *permut; + + permut = ALLOC(int,dd->size); + if (permut == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + return(NULL); + } + for (i = 0; i < dd->size; i++) permut[i] = i; + for (i = 0; i < n-2; i += 3) { + j = x[i]->index; + k = x[i+1]->index; + permut[j] = k; + permut[k] = j; + } + + swapped = Cudd_bddPermute(dd,B,permut); + FREE(permut); + + return(swapped); + +} /* end of Cudd_bddAdjPermuteX */ + + +/**Function******************************************************************** + + Synopsis [Composes an ADD with a vector of 0-1 ADDs.] + + Description [Given a vector of 0-1 ADDs, creates a new ADD by + substituting the 0-1 ADDs for the variables of the ADD f. There + should be an entry in vector for each variable in the manager. + If no substitution is sought for a given variable, the corresponding + projection function should be specified in the vector. + This function implements simultaneous composition. + Returns a pointer to the resulting ADD if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_addNonSimCompose Cudd_addPermute Cudd_addCompose + Cudd_bddVectorCompose] + +******************************************************************************/ +DdNode * +Cudd_addVectorCompose( + DdManager * dd, + DdNode * f, + DdNode ** vector) +{ + DdHashTable *table; + DdNode *res; + int deepest; + int i; + + do { + dd->reordered = 0; + /* Initialize local cache. */ + table = cuddHashTableInit(dd,1,2); + if (table == NULL) return(NULL); + + /* Find deepest real substitution. */ + for (deepest = dd->size - 1; deepest >= 0; deepest--) { + i = dd->invperm[deepest]; + if (!ddIsIthAddVar(dd,vector[i],i)) { + break; + } + } + + /* Recursively solve the problem. */ + res = cuddAddVectorComposeRecur(dd,table,f,vector,deepest); + if (res != NULL) cuddRef(res); + + /* Dispose of local cache. */ + cuddHashTableQuit(table); + } while (dd->reordered == 1); + + if (res != NULL) cuddDeref(res); + return(res); + +} /* end of Cudd_addVectorCompose */ + + +/**Function******************************************************************** + + Synopsis [Composes an ADD with a vector of ADDs.] + + Description [Given a vector of ADDs, creates a new ADD by substituting the + ADDs for the variables of the ADD f. vectorOn contains ADDs to be substituted + for the x_v and vectorOff the ADDs to be substituted for x_v'. There should + be an entry in vector for each variable in the manager. If no substitution + is sought for a given variable, the corresponding projection function should + be specified in the vector. This function implements simultaneous + composition. Returns a pointer to the resulting ADD if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_addVectorCompose Cudd_addNonSimCompose Cudd_addPermute + Cudd_addCompose Cudd_bddVectorCompose] + +******************************************************************************/ +DdNode * +Cudd_addGeneralVectorCompose( + DdManager * dd, + DdNode * f, + DdNode ** vectorOn, + DdNode ** vectorOff) +{ + DdHashTable *table; + DdNode *res; + int deepest; + int i; + + do { + dd->reordered = 0; + /* Initialize local cache. */ + table = cuddHashTableInit(dd,1,2); + if (table == NULL) return(NULL); + + /* Find deepest real substitution. */ + for (deepest = dd->size - 1; deepest >= 0; deepest--) { + i = dd->invperm[deepest]; + if (!ddIsIthAddVarPair(dd,vectorOn[i],vectorOff[i],i)) { + break; + } + } + + /* Recursively solve the problem. */ + res = cuddAddGeneralVectorComposeRecur(dd,table,f,vectorOn, + vectorOff,deepest); + if (res != NULL) cuddRef(res); + + /* Dispose of local cache. */ + cuddHashTableQuit(table); + } while (dd->reordered == 1); + + if (res != NULL) cuddDeref(res); + return(res); + +} /* end of Cudd_addGeneralVectorCompose */ + + +/**Function******************************************************************** + + Synopsis [Composes an ADD with a vector of 0-1 ADDs.] + + Description [Given a vector of 0-1 ADDs, creates a new ADD by + substituting the 0-1 ADDs for the variables of the ADD f. There + should be an entry in vector for each variable in the manager. + This function implements non-simultaneous composition. If any of the + functions being composed depends on any of the variables being + substituted, then the result depends on the order of composition, + which in turn depends on the variable order: The variables farther from + the roots in the order are substituted first. + Returns a pointer to the resulting ADD if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_addVectorCompose Cudd_addPermute Cudd_addCompose] + +******************************************************************************/ +DdNode * +Cudd_addNonSimCompose( + DdManager * dd, + DdNode * f, + DdNode ** vector) +{ + DdNode *cube, *key, *var, *tmp, *piece; + DdNode *res; + int i, lastsub; + + /* The cache entry for this function is composed of three parts: + ** f itself, the replacement relation, and the cube of the + ** variables being substituted. + ** The replacement relation is the product of the terms (yi EXNOR gi). + ** This apporach allows us to use the global cache for this function, + ** with great savings in memory with respect to using arrays for the + ** cache entries. + ** First we build replacement relation and cube of substituted + ** variables from the vector specifying the desired composition. + */ + key = DD_ONE(dd); + cuddRef(key); + cube = DD_ONE(dd); + cuddRef(cube); + for (i = (int) dd->size - 1; i >= 0; i--) { + if (ddIsIthAddVar(dd,vector[i],(unsigned int)i)) { + continue; + } + var = Cudd_addIthVar(dd,i); + if (var == NULL) { + Cudd_RecursiveDeref(dd,key); + Cudd_RecursiveDeref(dd,cube); + return(NULL); + } + cuddRef(var); + /* Update cube. */ + tmp = Cudd_addApply(dd,Cudd_addTimes,var,cube); + if (tmp == NULL) { + Cudd_RecursiveDeref(dd,key); + Cudd_RecursiveDeref(dd,cube); + Cudd_RecursiveDeref(dd,var); + return(NULL); + } + cuddRef(tmp); + Cudd_RecursiveDeref(dd,cube); + cube = tmp; + /* Update replacement relation. */ + piece = Cudd_addApply(dd,Cudd_addXnor,var,vector[i]); + if (piece == NULL) { + Cudd_RecursiveDeref(dd,key); + Cudd_RecursiveDeref(dd,var); + return(NULL); + } + cuddRef(piece); + Cudd_RecursiveDeref(dd,var); + tmp = Cudd_addApply(dd,Cudd_addTimes,key,piece); + if (tmp == NULL) { + Cudd_RecursiveDeref(dd,key); + Cudd_RecursiveDeref(dd,piece); + return(NULL); + } + cuddRef(tmp); + Cudd_RecursiveDeref(dd,key); + Cudd_RecursiveDeref(dd,piece); + key = tmp; + } + + /* Now try composition, until no reordering occurs. */ + do { + /* Find real substitution with largest index. */ + for (lastsub = dd->size - 1; lastsub >= 0; lastsub--) { + if (!ddIsIthAddVar(dd,vector[lastsub],(unsigned int)lastsub)) { + break; + } + } + + /* Recursively solve the problem. */ + dd->reordered = 0; + res = cuddAddNonSimComposeRecur(dd,f,vector,key,cube,lastsub+1); + if (res != NULL) cuddRef(res); + + } while (dd->reordered == 1); + + Cudd_RecursiveDeref(dd,key); + Cudd_RecursiveDeref(dd,cube); + if (res != NULL) cuddDeref(res); + return(res); + +} /* end of Cudd_addNonSimCompose */ + + +/**Function******************************************************************** + + Synopsis [Composes a BDD with a vector of BDDs.] + + Description [Given a vector of BDDs, creates a new BDD by + substituting the BDDs for the variables of the BDD f. There + should be an entry in vector for each variable in the manager. + If no substitution is sought for a given variable, the corresponding + projection function should be specified in the vector. + This function implements simultaneous composition. + Returns a pointer to the resulting BDD if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddPermute Cudd_bddCompose Cudd_addVectorCompose] + +******************************************************************************/ +DdNode * +Cudd_bddVectorCompose( + DdManager * dd, + DdNode * f, + DdNode ** vector) +{ + DdHashTable *table; + DdNode *res; + int deepest; + int i; + + do { + dd->reordered = 0; + /* Initialize local cache. */ + table = cuddHashTableInit(dd,1,2); + if (table == NULL) return(NULL); + + /* Find deepest real substitution. */ + for (deepest = dd->size - 1; deepest >= 0; deepest--) { + i = dd->invperm[deepest]; + if (vector[i] != dd->vars[i]) { + break; + } + } + + /* Recursively solve the problem. */ + res = cuddBddVectorComposeRecur(dd,table,f,vector, deepest); + if (res != NULL) cuddRef(res); + + /* Dispose of local cache. */ + cuddHashTableQuit(table); + } while (dd->reordered == 1); + + if (res != NULL) cuddDeref(res); + return(res); + +} /* end of Cudd_bddVectorCompose */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of internal functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_bddCompose.] + + Description [Performs the recursive step of Cudd_bddCompose. + Exploits the fact that the composition of f' with g + produces the complement of the composition of f with g to better + utilize the cache. Returns the composed BDD if successful; NULL + otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddCompose] + +******************************************************************************/ +DdNode * +cuddBddComposeRecur( + DdManager * dd, + DdNode * f, + DdNode * g, + DdNode * proj) +{ + DdNode *F, *G, *f1, *f0, *g1, *g0, *r, *t, *e; + unsigned int v, topf, topg, topindex; + int comple; + + statLine(dd); + v = dd->perm[proj->index]; + F = Cudd_Regular(f); + topf = cuddI(dd,F->index); + + /* Terminal case. Subsumes the test for constant f. */ + if (topf > v) return(f); + + /* We solve the problem for a regular pointer, and then complement + ** the result if the pointer was originally complemented. + */ + comple = Cudd_IsComplement(f); + + /* Check cache. */ + r = cuddCacheLookup(dd,DD_BDD_COMPOSE_RECUR_TAG,F,g,proj); + if (r != NULL) { + return(Cudd_NotCond(r,comple)); + } + + if (topf == v) { + /* Compose. */ + f1 = cuddT(F); + f0 = cuddE(F); + r = cuddBddIteRecur(dd, g, f1, f0); + if (r == NULL) return(NULL); + } else { + /* Compute cofactors of f and g. Remember the index of the top + ** variable. + */ + G = Cudd_Regular(g); + topg = cuddI(dd,G->index); + if (topf > topg) { + topindex = G->index; + f1 = f0 = F; + } else { + topindex = F->index; + f1 = cuddT(F); + f0 = cuddE(F); + } + if (topg > topf) { + g1 = g0 = g; + } else { + g1 = cuddT(G); + g0 = cuddE(G); + if (g != G) { + g1 = Cudd_Not(g1); + g0 = Cudd_Not(g0); + } + } + /* Recursive step. */ + t = cuddBddComposeRecur(dd, f1, g1, proj); + if (t == NULL) return(NULL); + cuddRef(t); + e = cuddBddComposeRecur(dd, f0, g0, proj); + if (e == NULL) { + Cudd_IterDerefBdd(dd, t); + return(NULL); + } + cuddRef(e); + + r = cuddBddIteRecur(dd, dd->vars[topindex], t, e); + if (r == NULL) { + Cudd_IterDerefBdd(dd, t); + Cudd_IterDerefBdd(dd, e); + return(NULL); + } + cuddRef(r); + Cudd_IterDerefBdd(dd, t); /* t & e not necessarily part of r */ + Cudd_IterDerefBdd(dd, e); + cuddDeref(r); + } + + cuddCacheInsert(dd,DD_BDD_COMPOSE_RECUR_TAG,F,g,proj,r); + + return(Cudd_NotCond(r,comple)); + +} /* end of cuddBddComposeRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_addCompose.] + + Description [Performs the recursive step of Cudd_addCompose. + Returns the composed BDD if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_addCompose] + +******************************************************************************/ +DdNode * +cuddAddComposeRecur( + DdManager * dd, + DdNode * f, + DdNode * g, + DdNode * proj) +{ + DdNode *f1, *f0, *g1, *g0, *r, *t, *e; + unsigned int v, topf, topg, topindex; + + statLine(dd); + v = dd->perm[proj->index]; + topf = cuddI(dd,f->index); + + /* Terminal case. Subsumes the test for constant f. */ + if (topf > v) return(f); + + /* Check cache. */ + r = cuddCacheLookup(dd,DD_ADD_COMPOSE_RECUR_TAG,f,g,proj); + if (r != NULL) { + return(r); + } + + if (topf == v) { + /* Compose. */ + f1 = cuddT(f); + f0 = cuddE(f); + r = cuddAddIteRecur(dd, g, f1, f0); + if (r == NULL) return(NULL); + } else { + /* Compute cofactors of f and g. Remember the index of the top + ** variable. + */ + topg = cuddI(dd,g->index); + if (topf > topg) { + topindex = g->index; + f1 = f0 = f; + } else { + topindex = f->index; + f1 = cuddT(f); + f0 = cuddE(f); + } + if (topg > topf) { + g1 = g0 = g; + } else { + g1 = cuddT(g); + g0 = cuddE(g); + } + /* Recursive step. */ + t = cuddAddComposeRecur(dd, f1, g1, proj); + if (t == NULL) return(NULL); + cuddRef(t); + e = cuddAddComposeRecur(dd, f0, g0, proj); + if (e == NULL) { + Cudd_RecursiveDeref(dd, t); + return(NULL); + } + cuddRef(e); + + if (t == e) { + r = t; + } else { + r = cuddUniqueInter(dd, (int) topindex, t, e); + if (r == NULL) { + Cudd_RecursiveDeref(dd, t); + Cudd_RecursiveDeref(dd, e); + return(NULL); + } + } + cuddDeref(t); + cuddDeref(e); + } + + cuddCacheInsert(dd,DD_ADD_COMPOSE_RECUR_TAG,f,g,proj,r); + + return(r); + +} /* end of cuddAddComposeRecur */ + + +/*---------------------------------------------------------------------------*/ +/* Definition of static functions */ +/*---------------------------------------------------------------------------*/ + + +/**Function******************************************************************** + + Synopsis [Implements the recursive step of Cudd_addPermute.] + + Description [ Recursively puts the ADD in the order given in the + array permut. Checks for trivial cases to terminate recursion, then + splits on the children of this node. Once the solutions for the + children are obtained, it puts into the current position the node + from the rest of the ADD that should be here. Then returns this ADD. + The key here is that the node being visited is NOT put in its proper + place by this instance, but rather is switched when its proper + position is reached in the recursion tree.<p> + The DdNode * that is returned is the same ADD as passed in as node, + but in the new order.] + + SideEffects [None] + + SeeAlso [Cudd_addPermute cuddBddPermuteRecur] + +******************************************************************************/ +static DdNode * +cuddAddPermuteRecur( + DdManager * manager /* DD manager */, + DdHashTable * table /* computed table */, + DdNode * node /* ADD to be reordered */, + int * permut /* permutation array */) +{ + DdNode *T,*E; + DdNode *res,*var; + int index; + + statLine(manager); + /* Check for terminal case of constant node. */ + if (cuddIsConstant(node)) { + return(node); + } + + /* If problem already solved, look up answer and return. */ + if (node->ref != 1 && (res = cuddHashTableLookup1(table,node)) != NULL) { +#ifdef DD_DEBUG + addPermuteRecurHits++; +#endif + return(res); + } + + /* Split and recur on children of this node. */ + T = cuddAddPermuteRecur(manager,table,cuddT(node),permut); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddAddPermuteRecur(manager,table,cuddE(node),permut); + if (E == NULL) { + Cudd_RecursiveDeref(manager, T); + return(NULL); + } + cuddRef(E); + + /* Move variable that should be in this position to this position + ** by creating a single var ADD for that variable, and calling + ** cuddAddIteRecur with the T and E we just created. + */ + index = permut[node->index]; + var = cuddUniqueInter(manager,index,DD_ONE(manager),DD_ZERO(manager)); + if (var == NULL) return(NULL); + cuddRef(var); + res = cuddAddIteRecur(manager,var,T,E); + if (res == NULL) { + Cudd_RecursiveDeref(manager,var); + Cudd_RecursiveDeref(manager, T); + Cudd_RecursiveDeref(manager, E); + return(NULL); + } + cuddRef(res); + Cudd_RecursiveDeref(manager,var); + Cudd_RecursiveDeref(manager, T); + Cudd_RecursiveDeref(manager, E); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again. + */ + if (node->ref != 1) { + ptrint fanout = (ptrint) node->ref; + cuddSatDec(fanout); + if (!cuddHashTableInsert1(table,node,res,fanout)) { + Cudd_RecursiveDeref(manager, res); + return(NULL); + } + } + cuddDeref(res); + return(res); + +} /* end of cuddAddPermuteRecur */ + + +/**Function******************************************************************** + + Synopsis [Implements the recursive step of Cudd_bddPermute.] + + Description [ Recursively puts the BDD in the order given in the array permut. + Checks for trivial cases to terminate recursion, then splits on the + children of this node. Once the solutions for the children are + obtained, it puts into the current position the node from the rest of + the BDD that should be here. Then returns this BDD. + The key here is that the node being visited is NOT put in its proper + place by this instance, but rather is switched when its proper position + is reached in the recursion tree.<p> + The DdNode * that is returned is the same BDD as passed in as node, + but in the new order.] + + SideEffects [None] + + SeeAlso [Cudd_bddPermute cuddAddPermuteRecur] + +******************************************************************************/ +static DdNode * +cuddBddPermuteRecur( + DdManager * manager /* DD manager */, + DdHashTable * table /* computed table */, + DdNode * node /* BDD to be reordered */, + int * permut /* permutation array */) +{ + DdNode *N,*T,*E; + DdNode *res; + int index; + + statLine(manager); + N = Cudd_Regular(node); + + /* Check for terminal case of constant node. */ + if (cuddIsConstant(N)) { + return(node); + } + + /* If problem already solved, look up answer and return. */ + if (N->ref != 1 && (res = cuddHashTableLookup1(table,N)) != NULL) { +#ifdef DD_DEBUG + bddPermuteRecurHits++; +#endif + return(Cudd_NotCond(res,N != node)); + } + + /* Split and recur on children of this node. */ + T = cuddBddPermuteRecur(manager,table,cuddT(N),permut); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddBddPermuteRecur(manager,table,cuddE(N),permut); + if (E == NULL) { + Cudd_IterDerefBdd(manager, T); + return(NULL); + } + cuddRef(E); + + /* Move variable that should be in this position to this position + ** by retrieving the single var BDD for that variable, and calling + ** cuddBddIteRecur with the T and E we just created. + */ + index = permut[N->index]; + res = cuddBddIteRecur(manager,manager->vars[index],T,E); + if (res == NULL) { + Cudd_IterDerefBdd(manager, T); + Cudd_IterDerefBdd(manager, E); + return(NULL); + } + cuddRef(res); + Cudd_IterDerefBdd(manager, T); + Cudd_IterDerefBdd(manager, E); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again. + */ + if (N->ref != 1) { + ptrint fanout = (ptrint) N->ref; + cuddSatDec(fanout); + if (!cuddHashTableInsert1(table,N,res,fanout)) { + Cudd_IterDerefBdd(manager, res); + return(NULL); + } + } + cuddDeref(res); + return(Cudd_NotCond(res,N != node)); + +} /* end of cuddBddPermuteRecur */ + + +/**Function******************************************************************** + + Synopsis [Implements the recursive step of Cudd_bddVarMap.] + + Description [Implements the recursive step of Cudd_bddVarMap. + Returns a pointer to the result if successful; NULL otherwise.] + + SideEffects [None] + + SeeAlso [Cudd_bddVarMap] + +******************************************************************************/ +static DdNode * +cuddBddVarMapRecur( + DdManager *manager /* DD manager */, + DdNode *f /* BDD to be remapped */) +{ + DdNode *F, *T, *E; + DdNode *res; + int index; + + statLine(manager); + F = Cudd_Regular(f); + + /* Check for terminal case of constant node. */ + if (cuddIsConstant(F)) { + return(f); + } + + /* If problem already solved, look up answer and return. */ + if (F->ref != 1 && + (res = cuddCacheLookup1(manager,Cudd_bddVarMap,F)) != NULL) { + return(Cudd_NotCond(res,F != f)); + } + + /* Split and recur on children of this node. */ + T = cuddBddVarMapRecur(manager,cuddT(F)); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddBddVarMapRecur(manager,cuddE(F)); + if (E == NULL) { + Cudd_IterDerefBdd(manager, T); + return(NULL); + } + cuddRef(E); + + /* Move variable that should be in this position to this position + ** by retrieving the single var BDD for that variable, and calling + ** cuddBddIteRecur with the T and E we just created. + */ + index = manager->map[F->index]; + res = cuddBddIteRecur(manager,manager->vars[index],T,E); + if (res == NULL) { + Cudd_IterDerefBdd(manager, T); + Cudd_IterDerefBdd(manager, E); + return(NULL); + } + cuddRef(res); + Cudd_IterDerefBdd(manager, T); + Cudd_IterDerefBdd(manager, E); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again. + */ + if (F->ref != 1) { + cuddCacheInsert1(manager,Cudd_bddVarMap,F,res); + } + cuddDeref(res); + return(Cudd_NotCond(res,F != f)); + +} /* end of cuddBddVarMapRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_addVectorCompose.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +static DdNode * +cuddAddVectorComposeRecur( + DdManager * dd /* DD manager */, + DdHashTable * table /* computed table */, + DdNode * f /* ADD in which to compose */, + DdNode ** vector /* functions to substitute */, + int deepest /* depth of deepest substitution */) +{ + DdNode *T,*E; + DdNode *res; + + statLine(dd); + /* If we are past the deepest substitution, return f. */ + if (cuddI(dd,f->index) > deepest) { + return(f); + } + + if ((res = cuddHashTableLookup1(table,f)) != NULL) { +#ifdef DD_DEBUG + addVectorComposeHits++; +#endif + return(res); + } + + /* Split and recur on children of this node. */ + T = cuddAddVectorComposeRecur(dd,table,cuddT(f),vector,deepest); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddAddVectorComposeRecur(dd,table,cuddE(f),vector,deepest); + if (E == NULL) { + Cudd_RecursiveDeref(dd, T); + return(NULL); + } + cuddRef(E); + + /* Retrieve the 0-1 ADD for the current top variable and call + ** cuddAddIteRecur with the T and E we just created. + */ + res = cuddAddIteRecur(dd,vector[f->index],T,E); + if (res == NULL) { + Cudd_RecursiveDeref(dd, T); + Cudd_RecursiveDeref(dd, E); + return(NULL); + } + cuddRef(res); + Cudd_RecursiveDeref(dd, T); + Cudd_RecursiveDeref(dd, E); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again + */ + if (f->ref != 1) { + ptrint fanout = (ptrint) f->ref; + cuddSatDec(fanout); + if (!cuddHashTableInsert1(table,f,res,fanout)) { + Cudd_RecursiveDeref(dd, res); + return(NULL); + } + } + cuddDeref(res); + return(res); + +} /* end of cuddAddVectorComposeRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_addGeneralVectorCompose.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +static DdNode * +cuddAddGeneralVectorComposeRecur( + DdManager * dd /* DD manager */, + DdHashTable * table /* computed table */, + DdNode * f /* ADD in which to compose */, + DdNode ** vectorOn /* functions to substitute for x_i */, + DdNode ** vectorOff /* functions to substitute for x_i' */, + int deepest /* depth of deepest substitution */) +{ + DdNode *T,*E,*t,*e; + DdNode *res; + + /* If we are past the deepest substitution, return f. */ + if (cuddI(dd,f->index) > deepest) { + return(f); + } + + if ((res = cuddHashTableLookup1(table,f)) != NULL) { +#ifdef DD_DEBUG + addGeneralVectorComposeHits++; +#endif + return(res); + } + + /* Split and recur on children of this node. */ + T = cuddAddGeneralVectorComposeRecur(dd,table,cuddT(f), + vectorOn,vectorOff,deepest); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddAddGeneralVectorComposeRecur(dd,table,cuddE(f), + vectorOn,vectorOff,deepest); + if (E == NULL) { + Cudd_RecursiveDeref(dd, T); + return(NULL); + } + cuddRef(E); + + /* Retrieve the compose ADDs for the current top variable and call + ** cuddAddApplyRecur with the T and E we just created. + */ + t = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOn[f->index],T); + if (t == NULL) { + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + return(NULL); + } + cuddRef(t); + e = cuddAddApplyRecur(dd,Cudd_addTimes,vectorOff[f->index],E); + if (e == NULL) { + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + Cudd_RecursiveDeref(dd,t); + return(NULL); + } + cuddRef(e); + res = cuddAddApplyRecur(dd,Cudd_addPlus,t,e); + if (res == NULL) { + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + Cudd_RecursiveDeref(dd,t); + Cudd_RecursiveDeref(dd,e); + return(NULL); + } + cuddRef(res); + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + Cudd_RecursiveDeref(dd,t); + Cudd_RecursiveDeref(dd,e); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again + */ + if (f->ref != 1) { + ptrint fanout = (ptrint) f->ref; + cuddSatDec(fanout); + if (!cuddHashTableInsert1(table,f,res,fanout)) { + Cudd_RecursiveDeref(dd, res); + return(NULL); + } + } + cuddDeref(res); + return(res); + +} /* end of cuddAddGeneralVectorComposeRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_addNonSimCompose.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +static DdNode * +cuddAddNonSimComposeRecur( + DdManager * dd, + DdNode * f, + DdNode ** vector, + DdNode * key, + DdNode * cube, + int lastsub) +{ + DdNode *f1, *f0, *key1, *key0, *cube1, *var; + DdNode *T,*E; + DdNode *r; + unsigned int top, topf, topk, topc; + unsigned int index; + int i; + DdNode **vect1; + DdNode **vect0; + + statLine(dd); + /* If we are past the deepest substitution, return f. */ + if (cube == DD_ONE(dd) || cuddIsConstant(f)) { + return(f); + } + + /* If problem already solved, look up answer and return. */ + r = cuddCacheLookup(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube); + if (r != NULL) { + return(r); + } + + /* Find top variable. we just need to look at f, key, and cube, + ** because all the varibles in the gi are in key. + */ + topf = cuddI(dd,f->index); + topk = cuddI(dd,key->index); + top = ddMin(topf,topk); + topc = cuddI(dd,cube->index); + top = ddMin(top,topc); + index = dd->invperm[top]; + + /* Compute the cofactors. */ + if (topf == top) { + f1 = cuddT(f); + f0 = cuddE(f); + } else { + f1 = f0 = f; + } + if (topc == top) { + cube1 = cuddT(cube); + /* We want to eliminate vector[index] from key. Otherwise + ** cache performance is severely affected. Hence we + ** existentially quantify the variable with index "index" from key. + */ + var = Cudd_addIthVar(dd, (int) index); + if (var == NULL) { + return(NULL); + } + cuddRef(var); + key1 = cuddAddExistAbstractRecur(dd, key, var); + if (key1 == NULL) { + Cudd_RecursiveDeref(dd,var); + return(NULL); + } + cuddRef(key1); + Cudd_RecursiveDeref(dd,var); + key0 = key1; + } else { + cube1 = cube; + if (topk == top) { + key1 = cuddT(key); + key0 = cuddE(key); + } else { + key1 = key0 = key; + } + cuddRef(key1); + } + + /* Allocate two new vectors for the cofactors of vector. */ + vect1 = ALLOC(DdNode *,lastsub); + if (vect1 == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + Cudd_RecursiveDeref(dd,key1); + return(NULL); + } + vect0 = ALLOC(DdNode *,lastsub); + if (vect0 == NULL) { + dd->errorCode = CUDD_MEMORY_OUT; + Cudd_RecursiveDeref(dd,key1); + FREE(vect1); + return(NULL); + } + + /* Cofactor the gi. Eliminate vect1[index] and vect0[index], because + ** we do not need them. + */ + for (i = 0; i < lastsub; i++) { + DdNode *gi = vector[i]; + if (gi == NULL) { + vect1[i] = vect0[i] = NULL; + } else if (gi->index == index) { + vect1[i] = cuddT(gi); + vect0[i] = cuddE(gi); + } else { + vect1[i] = vect0[i] = gi; + } + } + vect1[index] = vect0[index] = NULL; + + /* Recur on children. */ + T = cuddAddNonSimComposeRecur(dd,f1,vect1,key1,cube1,lastsub); + FREE(vect1); + if (T == NULL) { + Cudd_RecursiveDeref(dd,key1); + FREE(vect0); + return(NULL); + } + cuddRef(T); + E = cuddAddNonSimComposeRecur(dd,f0,vect0,key0,cube1,lastsub); + FREE(vect0); + if (E == NULL) { + Cudd_RecursiveDeref(dd,key1); + Cudd_RecursiveDeref(dd,T); + return(NULL); + } + cuddRef(E); + Cudd_RecursiveDeref(dd,key1); + + /* Retrieve the 0-1 ADD for the current top variable from vector, + ** and call cuddAddIteRecur with the T and E we just created. + */ + r = cuddAddIteRecur(dd,vector[index],T,E); + if (r == NULL) { + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + return(NULL); + } + cuddRef(r); + Cudd_RecursiveDeref(dd,T); + Cudd_RecursiveDeref(dd,E); + cuddDeref(r); + + /* Store answer to trim recursion. */ + cuddCacheInsert(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube,r); + + return(r); + +} /* end of cuddAddNonSimComposeRecur */ + + +/**Function******************************************************************** + + Synopsis [Performs the recursive step of Cudd_bddVectorCompose.] + + Description [] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +static DdNode * +cuddBddVectorComposeRecur( + DdManager * dd /* DD manager */, + DdHashTable * table /* computed table */, + DdNode * f /* BDD in which to compose */, + DdNode ** vector /* functions to be composed */, + int deepest /* depth of the deepest substitution */) +{ + DdNode *F,*T,*E; + DdNode *res; + + statLine(dd); + F = Cudd_Regular(f); + + /* If we are past the deepest substitution, return f. */ + if (cuddI(dd,F->index) > deepest) { + return(f); + } + + /* If problem already solved, look up answer and return. */ + if ((res = cuddHashTableLookup1(table,F)) != NULL) { +#ifdef DD_DEBUG + bddVectorComposeHits++; +#endif + return(Cudd_NotCond(res,F != f)); + } + + /* Split and recur on children of this node. */ + T = cuddBddVectorComposeRecur(dd,table,cuddT(F),vector, deepest); + if (T == NULL) return(NULL); + cuddRef(T); + E = cuddBddVectorComposeRecur(dd,table,cuddE(F),vector, deepest); + if (E == NULL) { + Cudd_IterDerefBdd(dd, T); + return(NULL); + } + cuddRef(E); + + /* Call cuddBddIteRecur with the BDD that replaces the current top + ** variable and the T and E we just created. + */ + res = cuddBddIteRecur(dd,vector[F->index],T,E); + if (res == NULL) { + Cudd_IterDerefBdd(dd, T); + Cudd_IterDerefBdd(dd, E); + return(NULL); + } + cuddRef(res); + Cudd_IterDerefBdd(dd, T); + Cudd_IterDerefBdd(dd, E); + + /* Do not keep the result if the reference count is only 1, since + ** it will not be visited again. + */ + if (F->ref != 1) { + ptrint fanout = (ptrint) F->ref; + cuddSatDec(fanout); + if (!cuddHashTableInsert1(table,F,res,fanout)) { + Cudd_IterDerefBdd(dd, res); + return(NULL); + } + } + cuddDeref(res); + return(Cudd_NotCond(res,F != f)); + +} /* end of cuddBddVectorComposeRecur */ + + +/**Function******************************************************************** + + Synopsis [Comparison of a function to the i-th ADD variable.] + + Description [Comparison of a function to the i-th ADD variable. Returns 1 if + the function is the i-th ADD variable; 0 otherwise.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DD_INLINE +static int +ddIsIthAddVar( + DdManager * dd, + DdNode * f, + unsigned int i) +{ + return(f->index == i && cuddT(f) == DD_ONE(dd) && cuddE(f) == DD_ZERO(dd)); + +} /* end of ddIsIthAddVar */ + + +/**Function******************************************************************** + + Synopsis [Comparison of a pair of functions to the i-th ADD variable.] + + Description [Comparison of a pair of functions to the i-th ADD + variable. Returns 1 if the functions are the i-th ADD variable and its + complement; 0 otherwise.] + + SideEffects [None] + + SeeAlso [] + +******************************************************************************/ +DD_INLINE +static int +ddIsIthAddVarPair( + DdManager * dd, + DdNode * f, + DdNode * g, + unsigned int i) +{ + return(f->index == i && g->index == i && + cuddT(f) == DD_ONE(dd) && cuddE(f) == DD_ZERO(dd) && + cuddT(g) == DD_ZERO(dd) && cuddE(g) == DD_ONE(dd)); + +} /* end of ddIsIthAddVarPair */ |