/**Function******************************************************************** Synopsis [Existentially Abstracts all the variables in cube from f.] Description [Abstracts all the variables in cube from f by summing over all possible values taken by the variables. Returns the abstracted ADD.] SideEffects [None] SeeAlso [Cudd_addUnivAbstract Cudd_bddExistAbstract Cudd_addOrAbstract] ******************************************************************************/ DdNode * Cudd_addExistAbstract( DdManager * manager, DdNode * f, DdNode * cube) { DdNode *res; two = cuddUniqueConst(manager,(CUDD_VALUE_TYPE) 2); if (two == NULL) return(NULL); cuddRef(two); if (addCheckPositiveCube(manager, cube) == 0) { (void) fprintf(manager->err,"Error: Can only abstract cubes"); return(NULL); } do { manager->reordered = 0; res = cuddAddExistAbstractRecur(manager, f, cube); } while (manager->reordered == 1); if (res == NULL) { Cudd_RecursiveDeref(manager,two); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(manager,two); cuddDeref(res); return(res); } /* end of Cudd_addExistAbstract */
/**Function******************************************************************** Synopsis [Converts an ADD to a BDD.] Description [Converts an ADD to a BDD by replacing all discriminants STRICTLY greater than value with 1, and all other discriminants with 0. Returns a pointer to the resulting BDD if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_addBddInterval Cudd_addBddPattern Cudd_BddToAdd Cudd_addBddThreshold] ******************************************************************************/ DdNode * Cudd_addBddStrictThreshold( DdManager * dd, DdNode * f, CUDD_VALUE_TYPE value) { DdNode *res; DdNode *val; /* NuSMV: begin add */ abort(); /* NOT USED BY NUSMV */ /* NuSMV: begin end */ val = cuddUniqueConst(dd,value); if (val == NULL) return(NULL); cuddRef(val); do { dd->reordered = 0; res = addBddDoStrictThreshold(dd, f, val); } while (dd->reordered == 1); if (res == NULL) { Cudd_RecursiveDeref(dd, val); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(dd, val); cuddDeref(res); return(res); } /* end of Cudd_addBddStrictThreshold */
/**Function******************************************************************** Synopsis [Computes a complement of a ZDD node.] Description [Computes the complement of a ZDD node. So far, since we couldn't find a direct way to get the complement of a ZDD cover, we first convert a ZDD cover to a BDD, then make the complement of the ZDD cover from the complement of the BDD node by using ISOP.] SideEffects [The result depends on current variable order.] SeeAlso [] ******************************************************************************/ DdNode * cuddZddComplement( DdManager * dd, DdNode *node) { DdNode *b, *isop, *zdd_I; /* Check cache */ zdd_I = cuddCacheLookup1Zdd(dd, cuddZddComplement, node); if (zdd_I) return(zdd_I); b = cuddMakeBddFromZddCover(dd, node); if (!b) return(NULL); cuddRef(b); isop = cuddZddIsop(dd, Cudd_Not(b), Cudd_Not(b), &zdd_I); if (!isop) { Cudd_RecursiveDeref(dd, b); return(NULL); } cuddRef(isop); cuddRef(zdd_I); Cudd_RecursiveDeref(dd, b); Cudd_RecursiveDeref(dd, isop); cuddCacheInsert1(dd, cuddZddComplement, node, zdd_I); cuddDeref(zdd_I); return(zdd_I); } /* end of cuddZddComplement */
/**Function******************************************************************** Synopsis [Computes the negative cofactor of a ZDD w.r.t. a variable.] Description [Computes the negative cofactor of a ZDD w.r.t. a variable. In terms of combinations, the result is the set of all combinations in which the variable is negated. Returns a pointer to the result if successful; NULL otherwise. cuddZddSubset0 performs the same function as Cudd_zddSubset0, but does not restart if reordering has taken place. Therefore it can be called from within a recursive procedure.] SideEffects [None] SeeAlso [cuddZddSubset1 Cudd_zddSubset0] ******************************************************************************/ DdNode * cuddZddSubset0( DdManager * dd, DdNode * P, int var) { DdNode *zvar, *r; DdNode *base, *empty; base = DD_TRUE(dd); empty = DD_FALSE(dd); zvar = cuddUniqueInterZdd(dd, var, base, empty); if (zvar == NULL) { return(NULL); } else { cuddRef(zvar); r = zdd_subset0_aux(dd, P, zvar); if (r == NULL) { Cudd_RecursiveDerefZdd(dd, zvar); return(NULL); } cuddRef(r); Cudd_RecursiveDerefZdd(dd, zvar); } cuddDeref(r); return(r); } /* end of cuddZddSubset0 */
/** @brief Performs the recursive step of addScalarInverse. @return a pointer to the resulting %ADD in case of success. Returns NULL if any discriminants smaller than epsilon is encountered. @sideeffect None */ DdNode * cuddAddScalarInverseRecur( DdManager * dd, DdNode * f, DdNode * epsilon) { DdNode *t, *e, *res; CUDD_VALUE_TYPE value; statLine(dd); if (cuddIsConstant(f)) { if (ddAbs(cuddV(f)) < cuddV(epsilon)) return(NULL); value = 1.0 / cuddV(f); res = cuddUniqueConst(dd,value); return(res); } res = cuddCacheLookup2(dd,Cudd_addScalarInverse,f,epsilon); if (res != NULL) return(res); checkWhetherToGiveUp(dd); t = cuddAddScalarInverseRecur(dd,cuddT(f),epsilon); if (t == NULL) return(NULL); cuddRef(t); e = cuddAddScalarInverseRecur(dd,cuddE(f),epsilon); if (e == NULL) { Cudd_RecursiveDeref(dd, t); return(NULL); } cuddRef(e); res = (t == e) ? t : cuddUniqueInter(dd,(int)f->index,t,e); if (res == NULL) { Cudd_RecursiveDeref(dd, t); Cudd_RecursiveDeref(dd, e); return(NULL); } cuddDeref(t); cuddDeref(e); cuddCacheInsert2(dd,Cudd_addScalarInverse,f,epsilon,res); return(res); } /* end of cuddAddScalarInverseRecur */
/**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 Extra_bddSpaceCanonVars().] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ DdNode * extraBddSpaceCanonVars( DdManager * dd, DdNode * bF ) { DdNode * bRes, * bFR; statLine( dd ); bFR = Cudd_Regular(bF); if ( cuddIsConstant(bFR) ) return bF; if ( (bRes = cuddCacheLookup1(dd, extraBddSpaceCanonVars, bF)) ) return bRes; else { DdNode * bF0, * bF1; DdNode * bRes, * bRes0; if ( bFR != bF ) // bF is complemented { bF0 = Cudd_Not( cuddE(bFR) ); bF1 = Cudd_Not( cuddT(bFR) ); } else { bF0 = cuddE(bFR); bF1 = cuddT(bFR); } if ( bF0 == b0 ) { bRes = extraBddSpaceCanonVars( dd, bF1 ); if ( bRes == NULL ) return NULL; } else if ( bF1 == b0 ) { bRes = extraBddSpaceCanonVars( dd, bF0 ); if ( bRes == NULL ) return NULL; } else { bRes0 = extraBddSpaceCanonVars( dd, bF0 ); if ( bRes0 == NULL ) return NULL; cuddRef( bRes0 ); bRes = cuddUniqueInter( dd, bFR->index, bRes0, b0 ); if ( bRes == NULL ) { Cudd_RecursiveDeref( dd,bRes0 ); return NULL; } cuddDeref( bRes0 ); } cuddCacheInsert1( dd, extraBddSpaceCanonVars, bF, bRes ); return bRes; } }
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_addCmpl.] Description [Performs the recursive step of Cudd_addCmpl. Returns a pointer to the resulting ADD if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_addCmpl] ******************************************************************************/ DdNode * cuddAddCmplRecur( DdManager * dd, DdNode * f) { DdNode *one,*zero; DdNode *r,*Fv,*Fnv,*t,*e; statLine(dd); one = DD_ONE(dd); zero = DD_ZERO(dd); if (cuddIsConstant(f)) { if (f == zero) { return(one); } else { return(zero); } } r = cuddCacheLookup1(dd,Cudd_addCmpl,f); if (r != NULL) { return(r); } Fv = cuddT(f); Fnv = cuddE(f); t = cuddAddCmplRecur(dd,Fv); if (t == NULL) return(NULL); cuddRef(t); e = cuddAddCmplRecur(dd,Fnv); if (e == NULL) { Cudd_RecursiveDeref(dd,t); return(NULL); } cuddRef(e); r = (t == e) ? t : cuddUniqueInter(dd,(int)f->index,t,e); if (r == NULL) { Cudd_RecursiveDeref(dd, t); Cudd_RecursiveDeref(dd, e); return(NULL); } cuddDeref(t); cuddDeref(e); cuddCacheInsert1(dd,Cudd_addCmpl,f,r); return(r); } /* end of cuddAddCmplRecur */
/**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 [Performs the recursive step of Extra_zddSelectOneSubset.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * extraZddSelectOneSubset( DdManager * dd, DdNode * zS ) // selects one subset from the ZDD zS // returns z0 if and only if zS is an empty set of cubes { DdNode * zRes; if ( zS == z0 ) return z0; if ( zS == z1 ) return z1; // check cache if ( (zRes = cuddCacheLookup1Zdd( dd, extraZddSelectOneSubset, zS )) ) return zRes; else { DdNode * zS0, * zS1, * zTemp; zS0 = cuddE(zS); zS1 = cuddT(zS); if ( zS0 != z0 ) { zRes = extraZddSelectOneSubset( dd, zS0 ); if ( zRes == NULL ) return NULL; } else // if ( zS0 == z0 ) { assert( zS1 != z0 ); zRes = extraZddSelectOneSubset( dd, zS1 ); if ( zRes == NULL ) return NULL; cuddRef( zRes ); zRes = cuddZddGetNode( dd, zS->index, zTemp = zRes, z0 ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zTemp ); return NULL; } cuddDeref( zTemp ); } // insert the result into cache cuddCacheInsert1( dd, extraZddSelectOneSubset, zS, zRes ); return zRes; } } /* end of extraZddSelectOneSubset */
/**Function******************************************************************** Synopsis [Generates a BDD for the function x > y.] Description [This function generates a BDD for the function x > y. Both x and y are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\] and y\[0\] y\[1\] ... y\[N-1\], with 0 the most significant bit. The BDD is built bottom-up. It has 3*N-1 internal nodes, if the variables are ordered as follows: x\[0\] y\[0\] x\[1\] y\[1\] ... x\[N-1\] y\[N-1\]. Argument z is not used by Cudd_Xgty: it is included to make it call-compatible to Cudd_Dxygtdxz and Cudd_Dxygtdyz.] SideEffects [None] SeeAlso [Cudd_PrioritySelect Cudd_Dxygtdxz Cudd_Dxygtdyz] ******************************************************************************/ DdNode * Cudd_Xgty( DdManager * dd /* DD manager */, int N /* number of x and y variables */, DdNode ** z /* array of z variables: unused */, DdNode ** x /* array of x variables */, DdNode ** y /* array of y variables */) { DdNode *u, *v, *w; int i; /* Build bottom part of BDD outside loop. */ u = Cudd_bddAnd(dd, x[N-1], Cudd_Not(y[N-1])); if (u == NULL) return(NULL); cuddRef(u); /* Loop to build the rest of the BDD. */ for (i = N-2; i >= 0; i--) { v = Cudd_bddAnd(dd, y[i], Cudd_Not(u)); if (v == NULL) { Cudd_RecursiveDeref(dd, u); return(NULL); } cuddRef(v); w = Cudd_bddAnd(dd, Cudd_Not(y[i]), u); if (w == NULL) { Cudd_RecursiveDeref(dd, u); Cudd_RecursiveDeref(dd, v); return(NULL); } cuddRef(w); Cudd_RecursiveDeref(dd, u); u = Cudd_bddIte(dd, x[i], Cudd_Not(v), w); if (u == NULL) { Cudd_RecursiveDeref(dd, v); Cudd_RecursiveDeref(dd, w); return(NULL); } cuddRef(u); Cudd_RecursiveDeref(dd, v); Cudd_RecursiveDeref(dd, w); } cuddDeref(u); return(u); } /* end of Cudd_Xgty */
/**Function******************************************************************** Synopsis [Performs a recursive step of Extra_zddGetSingletons.] Description [Returns the set of ZDD singletons, containing those positive polarity ZDD variables that correspond to the BDD variables in bVars.] SideEffects [] SeeAlso [] ******************************************************************************/ DdNode * extraZddGetSingletons( DdManager * dd, /* the DD manager */ DdNode * bVars) /* the set of variables */ { DdNode * zRes; if ( bVars == b1 ) // if ( bVars == b0 ) // bug fixed by Jin Zhang, Jan 23, 2004 return z1; if ( (zRes = cuddCacheLookup1Zdd(dd, extraZddGetSingletons, bVars)) ) return zRes; else { DdNode * zTemp, * zPlus; // solve subproblem zRes = extraZddGetSingletons( dd, cuddT(bVars) ); if ( zRes == NULL ) return NULL; cuddRef( zRes ); zPlus = cuddZddGetNode( dd, 2*bVars->index, z1, z0 ); if ( zPlus == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes ); return NULL; } cuddRef( zPlus ); // add these to the result zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); return NULL; } cuddRef( zRes ); Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); cuddDeref( zRes ); cuddCacheInsert1( dd, extraZddGetSingletons, bVars, zRes ); return zRes; } } /* end of extraZddGetSingletons */
/**Function******************************************************************** Synopsis [Converts an ADD to a BDD.] Description [Converts an ADD to a BDD by replacing all discriminants greater than or equal to lower and less than or equal to upper with 1, and all other discriminants with 0. Returns a pointer to the resulting BDD if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_addBddThreshold Cudd_addBddStrictThreshold Cudd_addBddPattern Cudd_BddToAdd] ******************************************************************************/ DdNode * Cudd_addBddInterval( DdManager * dd, DdNode * f, CUDD_VALUE_TYPE lower, CUDD_VALUE_TYPE upper) { DdNode *res; DdNode *l; DdNode *u; /* NuSMV: begin add */ abort(); /* NOT USED BY NUSMV */ /* NuSMV: begin end */ /* Create constant nodes for the interval bounds, so that we can use ** the global cache. */ l = cuddUniqueConst(dd,lower); if (l == NULL) return(NULL); cuddRef(l); u = cuddUniqueConst(dd,upper); if (u == NULL) { Cudd_RecursiveDeref(dd,l); return(NULL); } cuddRef(u); do { dd->reordered = 0; res = addBddDoInterval(dd, f, l, u); } while (dd->reordered == 1); if (res == NULL) { Cudd_RecursiveDeref(dd, l); Cudd_RecursiveDeref(dd, u); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(dd, l); Cudd_RecursiveDeref(dd, u); cuddDeref(res); return(res); } /* end of Cudd_addBddInterval */
/**Function******************************************************************** Synopsis [Computes the Hamming distance ADD.] Description [Computes the Hamming distance ADD. Returns an ADD that gives the Hamming distance between its two arguments if successful; NULL otherwise. The two vectors xVars and yVars identify the variables that form the two arguments.] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * Cudd_addHamming( DdManager * dd, DdNode ** xVars, DdNode ** yVars, int nVars) { DdNode *result,*tempBdd; DdNode *tempAdd,*temp; int i; result = DD_ZERO(dd); cuddRef(result); for (i = 0; i < nVars; i++) { tempBdd = Cudd_bddIte(dd,xVars[i],Cudd_Not(yVars[i]),yVars[i]); if (tempBdd == NULL) { Cudd_RecursiveDeref(dd,result); return(NULL); } cuddRef(tempBdd); tempAdd = Cudd_BddToAdd(dd,tempBdd); if (tempAdd == NULL) { Cudd_RecursiveDeref(dd,tempBdd); Cudd_RecursiveDeref(dd,result); return(NULL); } cuddRef(tempAdd); Cudd_RecursiveDeref(dd,tempBdd); temp = Cudd_addApply(dd,Cudd_addPlus,tempAdd,result); if (temp == NULL) { Cudd_RecursiveDeref(dd,tempAdd); Cudd_RecursiveDeref(dd,result); return(NULL); } cuddRef(temp); Cudd_RecursiveDeref(dd,tempAdd); Cudd_RecursiveDeref(dd,result); result = temp; } cuddDeref(result); return(result); } /* end of Cudd_addHamming */
/**Function******************************************************************** Synopsis [Initializes the ZDD universe.] Description [Initializes the ZDD universe. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddZddFreeUniv] ******************************************************************************/ int cuddZddInitUniv( DdManager * zdd) { DdNode *p, *res; int i; #ifdef __osf__ #pragma pointer_size save #pragma pointer_size short #endif zdd->univ = ALLOC(DdNode *, zdd->sizeZ); #ifdef __osf__ #pragma pointer_size restore #endif if (zdd->univ == NULL) { zdd->errorCode = CUDD_MEMORY_OUT; return(0); } res = DD_ONE(zdd); cuddRef(res); for (i = zdd->sizeZ - 1; i >= 0; i--) { unsigned int index = zdd->invpermZ[i]; p = res; res = cuddUniqueInterZdd(zdd, index, p, p); if (res == NULL) { Cudd_RecursiveDerefZdd(zdd,p); FREE(zdd->univ); return(0); } cuddRef(res); cuddDeref(p); zdd->univ[i] = res; } #ifdef DD_VERBOSE cuddZddP(zdd, zdd->univ[0]); #endif return(1); } /* end of cuddZddInitUniv */
/**Function******************************************************************** Synopsis [Convert a BDD from a manager to another one.] Description [Convert a BDD from a manager to another one. Returns a pointer to the BDD in the destination manager if successful; NULL otherwise.] SideEffects [None] SeeAlso [Extra_TransferPermute] ******************************************************************************/ DdNode * extraTransferPermuteTime( DdManager * ddS, DdManager * ddD, DdNode * f, int * Permute, int TimeOut ) { DdNode *res; st_table *table = NULL; st_generator *gen = NULL; DdNode *key, *value; table = st_init_table( st_ptrcmp, st_ptrhash ); if ( table == NULL ) goto failure; res = extraTransferPermuteRecurTime( ddS, ddD, f, table, Permute, TimeOut ); if ( res != NULL ) cuddRef( res ); /* Dereference all elements in the table and dispose of the table. ** This must be done also if res is NULL to avoid leaks in case of ** reordering. */ gen = st_init_gen( table ); if ( gen == NULL ) goto failure; while ( st_gen( gen, ( const char ** ) &key, ( char ** ) &value ) ) { Cudd_RecursiveDeref( ddD, value ); } st_free_gen( gen ); gen = NULL; st_free_table( table ); table = NULL; if ( res != NULL ) cuddDeref( res ); return ( res ); failure: if ( table != NULL ) st_free_table( table ); if ( gen != NULL ) st_free_gen( gen ); return ( NULL ); } /* end of extraTransferPermuteTime */
/**Function******************************************************************** Synopsis [Convert a BDD from a manager to another one.] Description [Convert a BDD from a manager to another one. Returns a pointer to the BDD in the destination manager if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_bddTransfer] ******************************************************************************/ DdNode * cuddBddTransfer( DdManager * ddS, DdManager * ddD, DdNode * f) { DdNode *res; st_table *table = NULL; st_generator *gen = NULL; DdNode *key, *value; /* NuSMV: begin add */ abort(); /* NOT USED BY NUSMV */ /* NuSMV: begin end */ table = st_init_table(st_ptrcmp,st_ptrhash); if (table == NULL) goto failure; res = cuddBddTransferRecur(ddS, ddD, f, table); if (res != NULL) cuddRef(res); /* Dereference all elements in the table and dispose of the table. ** This must be done also if res is NULL to avoid leaks in case of ** reordering. */ gen = st_init_gen(table); if (gen == NULL) goto failure; while (st_gen(gen, &key, &value)) { Cudd_RecursiveDeref(ddD, value); } st_free_gen(gen); gen = NULL; st_free_table(table); table = NULL; if (res != NULL) cuddDeref(res); return(res); failure: if (table != NULL) st_free_table(table); if (gen != NULL) st_free_gen(gen); return(NULL); } /* end of cuddBddTransfer */
/**Function******************************************************************** Synopsis [Computes the compatible projection of R w.r.t. cube Y.] Description [Computes the compatible projection of relation R with respect to cube Y. Returns a pointer to the c-projection if successful; NULL otherwise. For a comparison between Cudd_CProjection and Cudd_PrioritySelect, see the documentation of the latter.] SideEffects [None] SeeAlso [Cudd_PrioritySelect] ******************************************************************************/ DdNode * Cudd_CProjection( DdManager * dd, DdNode * R, DdNode * Y) { DdNode *res; DdNode *support; if (cuddCheckCube(dd,Y) == 0) { (void) fprintf(dd->err, "Error: The third argument of Cudd_CProjection should be a cube\n"); dd->errorCode = CUDD_INVALID_ARG; return(NULL); } /* Compute the support of Y, which is used by the abstraction step ** in cuddCProjectionRecur. */ support = Cudd_Support(dd,Y); if (support == NULL) return(NULL); cuddRef(support); do { dd->reordered = 0; res = cuddCProjectionRecur(dd,R,Y,support); } while (dd->reordered == 1); if (res == NULL) { Cudd_RecursiveDeref(dd,support); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(dd,support); cuddDeref(res); return(res); } /* end of Cudd_CProjection */
/**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 [Substitutes a variable with its complement in a ZDD.] Description [Substitutes a variable with its complement in a ZDD. returns a pointer to the result if successful; NULL otherwise. cuddZddChange performs the same function as Cudd_zddChange, but does not restart if reordering has taken place. Therefore it can be called from within a recursive procedure.] SideEffects [None] SeeAlso [Cudd_zddChange] ******************************************************************************/ DdNode * cuddZddChange( DdManager * dd, DdNode * P, int var) { DdNode *zvar, *res; zvar = cuddUniqueInterZdd(dd, var, DD_ONE(dd), DD_ZERO(dd)); if (zvar == NULL) return(NULL); cuddRef(zvar); res = cuddZddChangeAux(dd, P, zvar); if (res == NULL) { Cudd_RecursiveDerefZdd(dd,zvar); return(NULL); } cuddRef(res); Cudd_RecursiveDerefZdd(dd,zvar); cuddDeref(res); return(res); } /* end of cuddZddChange */
/**Function******************************************************************** Synopsis [Performs the triangulation step for the shortest path computation.] Description [Implements the semiring multiplication algorithm used in the triangulation step for the shortest path computation. f is assumed to depend on variables x (rows) and z (columns). g is assumed to depend on variables z (rows) and y (columns). The product of f and g then depends on x (rows) and y (columns). Only the z variables have to be explicitly identified; they are the "abstraction" variables. Returns a pointer to the result if successful; NULL otherwise. ] SideEffects [None] SeeAlso [Cudd_addMatrixMultiply Cudd_bddAndAbstract] ******************************************************************************/ DdNode * Cudd_addTriangle( DdManager * dd, DdNode * f, DdNode * g, DdNode ** z, int nz) { int i, nvars, *vars; DdNode *res, *cube; nvars = dd->size; vars = ALLOC(int, nvars); if (vars == NULL) { dd->errorCode = CUDD_MEMORY_OUT; return(NULL); } for (i = 0; i < nvars; i++) vars[i] = -1; for (i = 0; i < nz; i++) vars[z[i]->index] = i; cube = Cudd_addComputeCube(dd, z, NULL, nz); if (cube == NULL) { FREE(vars); return(NULL); } cuddRef(cube); do { dd->reordered = 0; res = addTriangleRecur(dd, f, g, vars, cube); } while (dd->reordered == 1); if (res != NULL) cuddRef(res); Cudd_RecursiveDeref(dd,cube); if (res != NULL) cuddDeref(res); FREE(vars); return(res); } /* end of Cudd_addTriangle */
/**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 */
/** @brief Implements the recursive step of Cudd_addWalsh. @return a pointer to the matrixi if successful; NULL otherwise. @sideeffect None @see Cudd_addWalsh */ static DdNode * addWalshInt( DdManager * dd, DdNode ** x, DdNode ** y, int n) { DdNode *one, *minusone; DdNode *t = NULL, *u, *t1, *u1, *v, *w; int i; one = DD_ONE(dd); if (n == 0) return(one); /* Build bottom part of ADD outside loop */ minusone = cuddUniqueConst(dd,(CUDD_VALUE_TYPE) -1); if (minusone == NULL) return(NULL); cuddRef(minusone); v = Cudd_addIte(dd, y[n-1], minusone, one); if (v == NULL) { Cudd_RecursiveDeref(dd, minusone); return(NULL); } cuddRef(v); u = Cudd_addIte(dd, x[n-1], v, one); if (u == NULL) { Cudd_RecursiveDeref(dd, minusone); Cudd_RecursiveDeref(dd, v); return(NULL); } cuddRef(u); Cudd_RecursiveDeref(dd, v); if (n>1) { w = Cudd_addIte(dd, y[n-1], one, minusone); if (w == NULL) { Cudd_RecursiveDeref(dd, minusone); Cudd_RecursiveDeref(dd, u); return(NULL); } cuddRef(w); t = Cudd_addIte(dd, x[n-1], w, minusone); if (t == NULL) { Cudd_RecursiveDeref(dd, minusone); Cudd_RecursiveDeref(dd, u); Cudd_RecursiveDeref(dd, w); return(NULL); } cuddRef(t); Cudd_RecursiveDeref(dd, w); } cuddDeref(minusone); /* minusone is in the result; it won't die */ /* Loop to build the rest of the ADD */ for (i=n-2; i>=0; i--) { t1 = t; u1 = u; v = Cudd_addIte(dd, y[i], t1, u1); if (v == NULL) { Cudd_RecursiveDeref(dd, u1); Cudd_RecursiveDeref(dd, t1); return(NULL); } cuddRef(v); u = Cudd_addIte(dd, x[i], v, u1); if (u == NULL) { Cudd_RecursiveDeref(dd, u1); Cudd_RecursiveDeref(dd, t1); Cudd_RecursiveDeref(dd, v); return(NULL); } cuddRef(u); Cudd_RecursiveDeref(dd, v); if (i>0) { w = Cudd_addIte(dd, y[i], u1, t1); if (w == NULL) { Cudd_RecursiveDeref(dd, u1); Cudd_RecursiveDeref(dd, t1); Cudd_RecursiveDeref(dd, u); return(NULL); } cuddRef(w); t = Cudd_addIte(dd, x[i], w, t1); if (u == NULL) { Cudd_RecursiveDeref(dd, u1); Cudd_RecursiveDeref(dd, t1); Cudd_RecursiveDeref(dd, u); Cudd_RecursiveDeref(dd, w); return(NULL); } cuddRef(t); Cudd_RecursiveDeref(dd, w); } Cudd_RecursiveDeref(dd, u1); Cudd_RecursiveDeref(dd, t1); } cuddDeref(u); return(u); } /* end of addWalshInt */
/** @brief Builds an %ADD for the residue modulo m of an n-bit number. @details The modulus must be at least 2, and the number of bits at least 1. Parameter options specifies whether the MSB should be on top or the LSB; and whther the number whose residue is computed is in two's complement notation or not. The macro CUDD_RESIDUE_DEFAULT specifies LSB on top and unsigned number. The macro CUDD_RESIDUE_MSB specifies MSB on top, and the macro CUDD_RESIDUE_TC specifies two's complement residue. To request MSB on top and two's complement residue simultaneously, one can OR the two macros: CUDD_RESIDUE_MSB | CUDD_RESIDUE_TC. @return a pointer to the resulting %ADD if successful; NULL otherwise. @sideeffect None */ DdNode * Cudd_addResidue( DdManager * dd /**< manager */, int n /**< number of bits */, int m /**< modulus */, int options /**< options */, int top /**< index of top variable */) { int msbLsb; /* MSB on top (1) or LSB on top (0) */ int tc; /* two's complement (1) or unsigned (0) */ int i, j, k, t, residue, thisOne, previous, index; DdNode **array[2], *var, *tmp, *res; /* Sanity check. */ if (n < 1 && m < 2) return(NULL); msbLsb = options & CUDD_RESIDUE_MSB; tc = options & CUDD_RESIDUE_TC; /* Allocate and initialize working arrays. */ array[0] = ALLOC(DdNode *,m); if (array[0] == NULL) { dd->errorCode = CUDD_MEMORY_OUT; return(NULL); } array[1] = ALLOC(DdNode *,m); if (array[1] == NULL) { FREE(array[0]); dd->errorCode = CUDD_MEMORY_OUT; return(NULL); } for (i = 0; i < m; i++) { array[0][i] = array[1][i] = NULL; } /* Initialize residues. */ for (i = 0; i < m; i++) { tmp = cuddUniqueConst(dd,(CUDD_VALUE_TYPE) i); if (tmp == NULL) { for (j = 0; j < i; j++) { Cudd_RecursiveDeref(dd,array[1][j]); } FREE(array[0]); FREE(array[1]); return(NULL); } cuddRef(tmp); array[1][i] = tmp; } /* Main iteration. */ residue = 1; /* residue of 2**0 */ for (k = 0; k < n; k++) { /* Choose current and previous arrays. */ thisOne = k & 1; previous = thisOne ^ 1; /* Build an ADD projection function. */ if (msbLsb) { index = top+n-k-1; } else { index = top+k; } var = cuddUniqueInter(dd,index,DD_ONE(dd),DD_ZERO(dd)); if (var == NULL) { for (j = 0; j < m; j++) { Cudd_RecursiveDeref(dd,array[previous][j]); } FREE(array[0]); FREE(array[1]); return(NULL); } cuddRef(var); for (i = 0; i < m; i ++) { t = (i + residue) % m; tmp = Cudd_addIte(dd,var,array[previous][t],array[previous][i]); if (tmp == NULL) { for (j = 0; j < i; j++) { Cudd_RecursiveDeref(dd,array[thisOne][j]); } for (j = 0; j < m; j++) { Cudd_RecursiveDeref(dd,array[previous][j]); } FREE(array[0]); FREE(array[1]); return(NULL); } cuddRef(tmp); array[thisOne][i] = tmp; } /* One layer completed. Free the other array for the next iteration. */ for (i = 0; i < m; i++) { Cudd_RecursiveDeref(dd,array[previous][i]); } Cudd_RecursiveDeref(dd,var); /* Update residue of 2**k. */ residue = (2 * residue) % m; /* Adjust residue for MSB, if this is a two's complement number. */ if (tc && (k == n - 1)) { residue = (m - residue) % m; } } /* We are only interested in the 0-residue node of the top layer. */ for (i = 1; i < m; i++) { Cudd_RecursiveDeref(dd,array[(n - 1) & 1][i]); } res = array[(n - 1) & 1][0]; FREE(array[0]); FREE(array[1]); cuddDeref(res); return(res); } /* end of Cudd_addResidue */
/**Function******************************************************************** Synopsis [Performs a recursive step of Extra_zddGetSymmetricVars.] Description [Returns the set of ZDD singletons, containing those positive ZDD variables that correspond to BDD variables x, for which it is true that bF(x=0) == bG(x=1).] SideEffects [] SeeAlso [] ******************************************************************************/ DdNode * extraZddGetSymmetricVars( DdManager * dd, /* the DD manager */ DdNode * bF, /* the first function - originally, the positive cofactor */ DdNode * bG, /* the second function - originally, the negative cofactor */ DdNode * bVars) /* the set of variables, on which F and G depend */ { DdNode * zRes; DdNode * bFR = Cudd_Regular(bF); DdNode * bGR = Cudd_Regular(bG); if ( cuddIsConstant(bFR) && cuddIsConstant(bGR) ) { if ( bF == bG ) return extraZddGetSingletons( dd, bVars ); else return z0; } assert( bVars != b1 ); if ( (zRes = cuddCacheLookupZdd(dd, DD_GET_SYMM_VARS_TAG, bF, bG, bVars)) ) return zRes; else { DdNode * zRes0, * zRes1; DdNode * zPlus, * zTemp; DdNode * bF0, * bF1; DdNode * bG0, * bG1; DdNode * bVarsNew; int LevelF = cuddI(dd,bFR->index); int LevelG = cuddI(dd,bGR->index); int LevelFG; if ( LevelF < LevelG ) LevelFG = LevelF; else LevelFG = LevelG; // at least one of the arguments is not a constant assert( LevelFG < dd->size ); // every variable in bF and bG should be also in bVars, therefore LevelFG cannot be above LevelV // if LevelFG is below LevelV, scroll through the vars in bVars to the same level as LevelFG for ( bVarsNew = bVars; LevelFG > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) ); assert( LevelFG == dd->perm[bVarsNew->index] ); // cofactor the functions if ( LevelF == LevelFG ) { if ( bFR != bF ) // bF is complemented { bF0 = Cudd_Not( cuddE(bFR) ); bF1 = Cudd_Not( cuddT(bFR) ); } else { bF0 = cuddE(bFR); bF1 = cuddT(bFR); } } else bF0 = bF1 = bF; if ( LevelG == LevelFG ) { if ( bGR != bG ) // bG is complemented { bG0 = Cudd_Not( cuddE(bGR) ); bG1 = Cudd_Not( cuddT(bGR) ); } else { bG0 = cuddE(bGR); bG1 = cuddT(bGR); } } else bG0 = bG1 = bG; // solve subproblems zRes0 = extraZddGetSymmetricVars( dd, bF0, bG0, cuddT(bVarsNew) ); if ( zRes0 == NULL ) return NULL; cuddRef( zRes0 ); // if there is not symmetries in the negative cofactor // there is no need to test the positive cofactor if ( zRes0 == z0 ) zRes = zRes0; // zRes takes reference else { zRes1 = extraZddGetSymmetricVars( dd, bF1, bG1, cuddT(bVarsNew) ); if ( zRes1 == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes0 ); return NULL; } cuddRef( zRes1 ); // only those variables should belong to the resulting set // for which the property is true for both cofactors zRes = cuddZddIntersect( dd, zRes0, zRes1 ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes0 ); Cudd_RecursiveDerefZdd( dd, zRes1 ); return NULL; } cuddRef( zRes ); Cudd_RecursiveDerefZdd( dd, zRes0 ); Cudd_RecursiveDerefZdd( dd, zRes1 ); } // add one more singleton if the property is true for this variable if ( bF0 == bG1 ) { zPlus = cuddZddGetNode( dd, 2*bVarsNew->index, z1, z0 ); if ( zPlus == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes ); return NULL; } cuddRef( zPlus ); // add these variable pairs to the result zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); return NULL; } cuddRef( zRes ); Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); } if ( bF == bG && bVars != bVarsNew ) { // if the functions are equal, so are their cofactors // add those variables from V that are above F and G DdNode * bVarsExtra; assert( LevelFG > dd->perm[bVars->index] ); // create the BDD of the extra variables bVarsExtra = cuddBddExistAbstractRecur( dd, bVars, bVarsNew ); if ( bVarsExtra == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes ); return NULL; } cuddRef( bVarsExtra ); zPlus = extraZddGetSingletons( dd, bVarsExtra ); if ( zPlus == NULL ) { Cudd_RecursiveDeref( dd, bVarsExtra ); Cudd_RecursiveDerefZdd( dd, zRes ); return NULL; } cuddRef( zPlus ); Cudd_RecursiveDeref( dd, bVarsExtra ); // add these to the result zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); return NULL; } cuddRef( zRes ); Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); } cuddDeref( zRes ); cuddCacheInsert( dd, DD_GET_SYMM_VARS_TAG, bF, bG, bVars, zRes ); return zRes; } } /* end of extraZddGetSymmetricVars */
/**Function******************************************************************** Synopsis [Performs a recursive step of Extra_SymmPairsCompute.] Description [Returns the set of symmetric variable pairs represented as a set of two-literal ZDD cubes. Both variables always appear in the positive polarity in the cubes. This function works without building new BDD nodes. Some relatively small number of ZDD nodes may be built to ensure proper bookkeeping of the symmetry information.] SideEffects [] SeeAlso [] ******************************************************************************/ DdNode * extraZddSymmPairsCompute( DdManager * dd, /* the manager */ DdNode * bFunc, /* the function whose symmetries are computed */ DdNode * bVars ) /* the set of variables on which this function depends */ { DdNode * zRes; DdNode * bFR = Cudd_Regular(bFunc); if ( cuddIsConstant(bFR) ) { int nVars, i; // determine how many vars are in the bVars nVars = Extra_bddSuppSize( dd, bVars ); if ( nVars < 2 ) return z0; else { DdNode * bVarsK; // create the BDD bVarsK corresponding to K = 2; bVarsK = bVars; for ( i = 0; i < nVars-2; i++ ) bVarsK = cuddT( bVarsK ); return extraZddTuplesFromBdd( dd, bVarsK, bVars ); } } assert( bVars != b1 ); if ( (zRes = cuddCacheLookup2Zdd(dd, extraZddSymmPairsCompute, bFunc, bVars)) ) return zRes; else { DdNode * zRes0, * zRes1; DdNode * zTemp, * zPlus, * zSymmVars; DdNode * bF0, * bF1; DdNode * bVarsNew; int nVarsExtra; int LevelF; // every variable in bF should be also in bVars, therefore LevelF cannot be above LevelV // if LevelF is below LevelV, scroll through the vars in bVars to the same level as F // count how many extra vars are there in bVars nVarsExtra = 0; LevelF = dd->perm[bFR->index]; for ( bVarsNew = bVars; LevelF > dd->perm[bVarsNew->index]; bVarsNew = cuddT(bVarsNew) ) nVarsExtra++; // the indexes (level) of variables should be synchronized now assert( bFR->index == bVarsNew->index ); // cofactor the function if ( bFR != bFunc ) // bFunc is complemented { bF0 = Cudd_Not( cuddE(bFR) ); bF1 = Cudd_Not( cuddT(bFR) ); } else { bF0 = cuddE(bFR); bF1 = cuddT(bFR); } // solve subproblems zRes0 = extraZddSymmPairsCompute( dd, bF0, cuddT(bVarsNew) ); if ( zRes0 == NULL ) return NULL; cuddRef( zRes0 ); // if there is no symmetries in the negative cofactor // there is no need to test the positive cofactor if ( zRes0 == z0 ) zRes = zRes0; // zRes takes reference else { zRes1 = extraZddSymmPairsCompute( dd, bF1, cuddT(bVarsNew) ); if ( zRes1 == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes0 ); return NULL; } cuddRef( zRes1 ); // only those variables are pair-wise symmetric // that are pair-wise symmetric in both cofactors // therefore, intersect the solutions zRes = cuddZddIntersect( dd, zRes0, zRes1 ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes0 ); Cudd_RecursiveDerefZdd( dd, zRes1 ); return NULL; } cuddRef( zRes ); Cudd_RecursiveDerefZdd( dd, zRes0 ); Cudd_RecursiveDerefZdd( dd, zRes1 ); } // consider the current top-most variable and find all the vars // that are pairwise symmetric with it // these variables are returned as a set of ZDD singletons zSymmVars = extraZddGetSymmetricVars( dd, bF1, bF0, cuddT(bVarsNew) ); if ( zSymmVars == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes ); return NULL; } cuddRef( zSymmVars ); // attach the topmost variable to the set, to get the variable pairs // use the positive polarity ZDD variable for the purpose // there is no need to do so, if zSymmVars is empty if ( zSymmVars == z0 ) Cudd_RecursiveDerefZdd( dd, zSymmVars ); else { zPlus = cuddZddGetNode( dd, 2*bFR->index, zSymmVars, z0 ); if ( zPlus == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes ); Cudd_RecursiveDerefZdd( dd, zSymmVars ); return NULL; } cuddRef( zPlus ); cuddDeref( zSymmVars ); // add these variable pairs to the result zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); return NULL; } cuddRef( zRes ); Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); } // only zRes is referenced at this point // if we skipped some variables, these variables cannot be symmetric with // any variables that are currently in the support of bF, but they can be // symmetric with the variables that are in bVars but not in the support of bF if ( nVarsExtra ) { // it is possible to improve this step: // (1) there is no need to enter here, if nVarsExtra < 2 // create the set of topmost nVarsExtra in bVars DdNode * bVarsExtra; int nVars; // remove from bVars all the variable that are in the support of bFunc bVarsExtra = extraBddReduceVarSet( dd, bVars, bFunc ); if ( bVarsExtra == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes ); return NULL; } cuddRef( bVarsExtra ); // determine how many vars are in the bVarsExtra nVars = Extra_bddSuppSize( dd, bVarsExtra ); if ( nVars < 2 ) { Cudd_RecursiveDeref( dd, bVarsExtra ); } else { int i; DdNode * bVarsK; // create the BDD bVarsK corresponding to K = 2; bVarsK = bVarsExtra; for ( i = 0; i < nVars-2; i++ ) bVarsK = cuddT( bVarsK ); // create the 2 variable tuples zPlus = extraZddTuplesFromBdd( dd, bVarsK, bVarsExtra ); if ( zPlus == NULL ) { Cudd_RecursiveDeref( dd, bVarsExtra ); Cudd_RecursiveDerefZdd( dd, zRes ); return NULL; } cuddRef( zPlus ); Cudd_RecursiveDeref( dd, bVarsExtra ); // add these to the result zRes = cuddZddUnion( dd, zTemp = zRes, zPlus ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); return NULL; } cuddRef( zRes ); Cudd_RecursiveDerefZdd( dd, zTemp ); Cudd_RecursiveDerefZdd( dd, zPlus ); } } cuddDeref( zRes ); /* insert the result into cache */ cuddCacheInsert2(dd, extraZddSymmPairsCompute, bFunc, bVars, zRes); return zRes; } } /* end of extraZddSymmPairsCompute */
/**Function******************************************************************** Synopsis [Performs the reordering-sensitive step of Extra_zddTupleFromBdd().] Description [Generates in a bottom-up fashion ZDD for all combinations composed of k variables out of variables belonging to Support.] SideEffects [] SeeAlso [] ******************************************************************************/ DdNode* extraZddTuplesFromBdd( DdManager * dd, /* the DD manager */ DdNode * bVarsK, /* the number of variables in tuples */ DdNode * bVarsN) /* the set of all variables */ { DdNode *zRes, *zRes0, *zRes1; statLine(dd); /* terminal cases */ /* if ( k < 0 || k > n ) * return dd->zero; * if ( n == 0 ) * return dd->one; */ if ( cuddI( dd, bVarsK->index ) < cuddI( dd, bVarsN->index ) ) return z0; if ( bVarsN == b1 ) return z1; /* check cache */ zRes = cuddCacheLookup2Zdd(dd, extraZddTuplesFromBdd, bVarsK, bVarsN); if (zRes) return(zRes); /* ZDD in which this variable is 0 */ /* zRes0 = extraZddTuplesFromBdd( dd, k, n-1 ); */ zRes0 = extraZddTuplesFromBdd( dd, bVarsK, cuddT(bVarsN) ); if ( zRes0 == NULL ) return NULL; cuddRef( zRes0 ); /* ZDD in which this variable is 1 */ /* zRes1 = extraZddTuplesFromBdd( dd, k-1, n-1 ); */ if ( bVarsK == b1 ) { zRes1 = z0; cuddRef( zRes1 ); } else { zRes1 = extraZddTuplesFromBdd( dd, cuddT(bVarsK), cuddT(bVarsN) ); if ( zRes1 == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes0 ); return NULL; } cuddRef( zRes1 ); } /* compose Res0 and Res1 with the given ZDD variable */ zRes = cuddZddGetNode( dd, 2*bVarsN->index, zRes1, zRes0 ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd( dd, zRes0 ); Cudd_RecursiveDerefZdd( dd, zRes1 ); return NULL; } cuddDeref( zRes0 ); cuddDeref( zRes1 ); /* insert the result into cache */ cuddCacheInsert2(dd, extraZddTuplesFromBdd, bVarsK, bVarsN, zRes); return zRes; } /* end of extraZddTuplesFromBdd */
/**Function******************************************************************** Synopsis [Performs a recursive step of Extra_bddReduceVarSet.] Description [Returns the set of all variables in the given set that are not in the support of the given function.] SideEffects [] SeeAlso [] ******************************************************************************/ DdNode * extraBddReduceVarSet( DdManager * dd, /* the DD manager */ DdNode * bVars, /* the set of variables to be reduced */ DdNode * bF) /* the function whose support is used for reduction */ { DdNode * bRes; DdNode * bFR = Cudd_Regular(bF); if ( cuddIsConstant(bFR) || bVars == b1 ) return bVars; if ( (bRes = cuddCacheLookup2(dd, extraBddReduceVarSet, bVars, bF)) ) return bRes; else { DdNode * bF0, * bF1; DdNode * bVarsThis, * bVarsLower, * bTemp; int LevelF; // if LevelF is below LevelV, scroll through the vars in bVars LevelF = dd->perm[bFR->index]; for ( bVarsThis = bVars; LevelF > cuddI(dd,bVarsThis->index); bVarsThis = cuddT(bVarsThis) ); // scroll also through the current var, because it should be not be added if ( LevelF == cuddI(dd,bVarsThis->index) ) bVarsLower = cuddT(bVarsThis); else bVarsLower = bVarsThis; // cofactor the function if ( bFR != bF ) // bFunc is complemented { bF0 = Cudd_Not( cuddE(bFR) ); bF1 = Cudd_Not( cuddT(bFR) ); } else { bF0 = cuddE(bFR); bF1 = cuddT(bFR); } // solve subproblems bRes = extraBddReduceVarSet( dd, bVarsLower, bF0 ); if ( bRes == NULL ) return NULL; cuddRef( bRes ); bRes = extraBddReduceVarSet( dd, bTemp = bRes, bF1 ); if ( bRes == NULL ) { Cudd_RecursiveDeref( dd, bTemp ); return NULL; } cuddRef( bRes ); Cudd_RecursiveDeref( dd, bTemp ); // the current var should not be added // add the skipped vars if ( bVarsThis != bVars ) { DdNode * bVarsExtra; // extract the skipped variables bVarsExtra = cuddBddExistAbstractRecur( dd, bVars, bVarsThis ); if ( bVarsExtra == NULL ) { Cudd_RecursiveDeref( dd, bRes ); return NULL; } cuddRef( bVarsExtra ); // add these variables bRes = cuddBddAndRecur( dd, bTemp = bRes, bVarsExtra ); if ( bRes == NULL ) { Cudd_RecursiveDeref( dd, bTemp ); Cudd_RecursiveDeref( dd, bVarsExtra ); return NULL; } cuddRef( bRes ); Cudd_RecursiveDeref( dd, bTemp ); Cudd_RecursiveDeref( dd, bVarsExtra ); } cuddDeref( bRes ); cuddCacheInsert2( dd, extraBddReduceVarSet, bVars, bF, bRes ); return bRes; } } /* end of extraBddReduceVarSet */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_CProjection.] Description [Performs the recursive step of Cudd_CProjection. Returns the projection if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_CProjection] ******************************************************************************/ DdNode * cuddCProjectionRecur( DdManager * dd, DdNode * R, DdNode * Y, DdNode * Ysupp) { DdNode *res, *res1, *res2, *resA; DdNode *r, *y, *RT, *RE, *YT, *YE, *Yrest, *Ra, *Ran, *Gamma, *Alpha; unsigned int topR, topY, top, index; DdNode *one = DD_ONE(dd); statLine(dd); if (Y == one) return(R); #ifdef DD_DEBUG assert(!Cudd_IsConstant(Y)); #endif if (R == Cudd_Not(one)) return(R); res = cuddCacheLookup2(dd, Cudd_CProjection, R, Y); if (res != NULL) return(res); r = Cudd_Regular(R); topR = cuddI(dd,r->index); y = Cudd_Regular(Y); topY = cuddI(dd,y->index); top = ddMin(topR, topY); /* Compute the cofactors of R */ if (topR == top) { index = r->index; RT = cuddT(r); RE = cuddE(r); if (r != R) { RT = Cudd_Not(RT); RE = Cudd_Not(RE); } } else { RT = RE = R; } if (topY > top) { /* Y does not depend on the current top variable. ** We just need to compute the results on the two cofactors of R ** and make them the children of a node labeled r->index. */ res1 = cuddCProjectionRecur(dd,RT,Y,Ysupp); if (res1 == NULL) return(NULL); cuddRef(res1); res2 = cuddCProjectionRecur(dd,RE,Y,Ysupp); if (res2 == NULL) { Cudd_RecursiveDeref(dd,res1); return(NULL); } cuddRef(res2); res = cuddBddIteRecur(dd, dd->vars[index], res1, res2); if (res == NULL) { Cudd_RecursiveDeref(dd,res1); Cudd_RecursiveDeref(dd,res2); return(NULL); } /* If we have reached this point, res1 and res2 are now ** incorporated in res. cuddDeref is therefore sufficient. */ cuddDeref(res1); cuddDeref(res2); } else { /* Compute the cofactors of Y */ index = y->index; YT = cuddT(y); YE = cuddE(y); if (y != Y) { YT = Cudd_Not(YT); YE = Cudd_Not(YE); } if (YT == Cudd_Not(one)) { Alpha = Cudd_Not(dd->vars[index]); Yrest = YE; Ra = RE; Ran = RT; } else { Alpha = dd->vars[index]; Yrest = YT; Ra = RT; Ran = RE; } Gamma = cuddBddExistAbstractRecur(dd,Ra,cuddT(Ysupp)); if (Gamma == NULL) return(NULL); if (Gamma == one) { res1 = cuddCProjectionRecur(dd,Ra,Yrest,cuddT(Ysupp)); if (res1 == NULL) return(NULL); cuddRef(res1); res = cuddBddAndRecur(dd, Alpha, res1); if (res == NULL) { Cudd_RecursiveDeref(dd,res1); return(NULL); } cuddDeref(res1); } else if (Gamma == Cudd_Not(one)) { res1 = cuddCProjectionRecur(dd,Ran,Yrest,cuddT(Ysupp)); if (res1 == NULL) return(NULL); cuddRef(res1); res = cuddBddAndRecur(dd, Cudd_Not(Alpha), res1); if (res == NULL) { Cudd_RecursiveDeref(dd,res1); return(NULL); } cuddDeref(res1); } else { cuddRef(Gamma); resA = cuddCProjectionRecur(dd,Ran,Yrest,cuddT(Ysupp)); if (resA == NULL) { Cudd_RecursiveDeref(dd,Gamma); return(NULL); } cuddRef(resA); res2 = cuddBddAndRecur(dd, Cudd_Not(Gamma), resA); if (res2 == NULL) { Cudd_RecursiveDeref(dd,Gamma); Cudd_RecursiveDeref(dd,resA); return(NULL); } cuddRef(res2); Cudd_RecursiveDeref(dd,Gamma); Cudd_RecursiveDeref(dd,resA); res1 = cuddCProjectionRecur(dd,Ra,Yrest,cuddT(Ysupp)); if (res1 == NULL) { Cudd_RecursiveDeref(dd,res2); return(NULL); } cuddRef(res1); res = cuddBddIteRecur(dd, Alpha, res1, res2); if (res == NULL) { Cudd_RecursiveDeref(dd,res1); Cudd_RecursiveDeref(dd,res2); return(NULL); } cuddDeref(res1); cuddDeref(res2); } } cuddCacheInsert2(dd,Cudd_CProjection,R,Y,res); return(res); } /* end of cuddCProjectionRecur */
/**Function******************************************************************** Synopsis [Generates a BDD for the function d(x,y) > d(y,z).] Description [This function generates a BDD for the function d(x,y) > d(y,z); x, y, and z are N-bit numbers, x\[0\] x\[1\] ... x\[N-1\], y\[0\] y\[1\] ... y\[N-1\], and z\[0\] z\[1\] ... z\[N-1\], with 0 the most significant bit. The distance d(x,y) is defined as: \sum_{i=0}^{N-1}(|x_i - y_i| \cdot 2^{N-i-1}). The BDD is built bottom-up. It has 7*N-3 internal nodes, if the variables are ordered as follows: x\[0\] y\[0\] z\[0\] x\[1\] y\[1\] z\[1\] ... x\[N-1\] y\[N-1\] z\[N-1\]. ] SideEffects [None] SeeAlso [Cudd_PrioritySelect Cudd_Dxygtdxz Cudd_Xgty Cudd_bddAdjPermuteX] ******************************************************************************/ DdNode * Cudd_Dxygtdyz( DdManager * dd /* DD manager */, int N /* number of x, y, and z variables */, DdNode ** x /* array of x variables */, DdNode ** y /* array of y variables */, DdNode ** z /* array of z variables */) { DdNode *one, *zero; DdNode *z1, *z2, *z3, *z4, *y1_, *y2, *x1; int i; one = DD_ONE(dd); zero = Cudd_Not(one); /* Build bottom part of BDD outside loop. */ y1_ = Cudd_bddIte(dd, y[N-1], one, z[N-1]); if (y1_ == NULL) return(NULL); cuddRef(y1_); y2 = Cudd_bddIte(dd, y[N-1], z[N-1], zero); if (y2 == NULL) { Cudd_RecursiveDeref(dd, y1_); return(NULL); } cuddRef(y2); x1 = Cudd_bddIte(dd, x[N-1], y1_, Cudd_Not(y2)); if (x1 == NULL) { Cudd_RecursiveDeref(dd, y1_); Cudd_RecursiveDeref(dd, y2); return(NULL); } cuddRef(x1); Cudd_RecursiveDeref(dd, y1_); Cudd_RecursiveDeref(dd, y2); /* Loop to build the rest of the BDD. */ for (i = N-2; i >= 0; i--) { z1 = Cudd_bddIte(dd, z[i], x1, zero); if (z1 == NULL) { Cudd_RecursiveDeref(dd, x1); return(NULL); } cuddRef(z1); z2 = Cudd_bddIte(dd, z[i], x1, one); if (z2 == NULL) { Cudd_RecursiveDeref(dd, x1); Cudd_RecursiveDeref(dd, z1); return(NULL); } cuddRef(z2); z3 = Cudd_bddIte(dd, z[i], one, x1); if (z3 == NULL) { Cudd_RecursiveDeref(dd, x1); Cudd_RecursiveDeref(dd, z1); Cudd_RecursiveDeref(dd, z2); return(NULL); } cuddRef(z3); z4 = Cudd_bddIte(dd, z[i], one, Cudd_Not(x1)); if (z4 == NULL) { Cudd_RecursiveDeref(dd, x1); Cudd_RecursiveDeref(dd, z1); Cudd_RecursiveDeref(dd, z2); Cudd_RecursiveDeref(dd, z3); return(NULL); } cuddRef(z4); Cudd_RecursiveDeref(dd, x1); y1_ = Cudd_bddIte(dd, y[i], z2, z1); if (y1_ == NULL) { Cudd_RecursiveDeref(dd, z1); Cudd_RecursiveDeref(dd, z2); Cudd_RecursiveDeref(dd, z3); Cudd_RecursiveDeref(dd, z4); return(NULL); } cuddRef(y1_); y2 = Cudd_bddIte(dd, y[i], z4, Cudd_Not(z3)); if (y2 == NULL) { Cudd_RecursiveDeref(dd, z1); Cudd_RecursiveDeref(dd, z2); Cudd_RecursiveDeref(dd, z3); Cudd_RecursiveDeref(dd, z4); Cudd_RecursiveDeref(dd, y1_); return(NULL); } cuddRef(y2); Cudd_RecursiveDeref(dd, z1); Cudd_RecursiveDeref(dd, z2); Cudd_RecursiveDeref(dd, z3); Cudd_RecursiveDeref(dd, z4); x1 = Cudd_bddIte(dd, x[i], y1_, Cudd_Not(y2)); if (x1 == NULL) { Cudd_RecursiveDeref(dd, y1_); Cudd_RecursiveDeref(dd, y2); return(NULL); } cuddRef(x1); Cudd_RecursiveDeref(dd, y1_); Cudd_RecursiveDeref(dd, y2); } cuddDeref(x1); return(Cudd_Not(x1)); } /* end of Cudd_Dxygtdyz */