/**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 [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 steps of Cudd_bddBoleanDiff.] Description [Performs the recursive steps of Cudd_bddBoleanDiff. Returns the BDD obtained by XORing the cofactors of f with respect to var if successful; NULL otherwise. Exploits the fact that dF/dx = dF'/dx.] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * cuddBddBooleanDiffRecur( DdManager * manager, DdNode * f, DdNode * var) { DdNode *T, *E, *res, *res1, *res2; statLine(manager); if (cuddI(manager,f->index) > manager->perm[var->index]) { /* f does not depend on var. */ return(Cudd_Not(DD_ONE(manager))); } /* From now on, f is non-constant. */ /* If the two indices are the same, so are their levels. */ if (f->index == var->index) { res = cuddBddXorRecur(manager, cuddT(f), cuddE(f)); return(res); } /* From now on, cuddI(manager,f->index) < cuddI(manager,cube->index). */ /* Check the cache. */ res = cuddCacheLookup2(manager, cuddBddBooleanDiffRecur, f, var); if (res != NULL) { return(res); } /* Compute the cofactors of f. */ T = cuddT(f); E = cuddE(f); res1 = cuddBddBooleanDiffRecur(manager, T, var); if (res1 == NULL) return(NULL); cuddRef(res1); res2 = cuddBddBooleanDiffRecur(manager, Cudd_Regular(E), var); if (res2 == NULL) { Cudd_IterDerefBdd(manager, res1); return(NULL); } cuddRef(res2); /* ITE takes care of possible complementation of res1 and of the ** case in which res1 == res2. */ res = cuddBddIteRecur(manager, manager->vars[f->index], res1, res2); if (res == NULL) { Cudd_IterDerefBdd(manager, res1); Cudd_IterDerefBdd(manager, res2); return(NULL); } cuddDeref(res1); cuddDeref(res2); cuddCacheInsert2(manager, cuddBddBooleanDiffRecur, f, var, res); return(res); } /* end of cuddBddBooleanDiffRecur */
/**Function******************************************************************** Synopsis [Implements ITE(f,g,h).] Description [Implements ITE(f,g,h). Returns a pointer to the resulting BDD if successful; NULL if the intermediate result blows up.] SideEffects [None] SeeAlso [Cudd_addIte Cudd_bddIteConstant Cudd_bddIntersect] ******************************************************************************/ DdNode * Cudd_bddIte( DdManager * dd, DdNode * f, DdNode * g, DdNode * h) { DdNode *res; do { dd->reordered = 0; res = cuddBddIteRecur(dd,f,g,h); } while (dd->reordered == 1); return(res); } /* end of Cudd_bddIte */
/**Function******************************************************************** Synopsis [Implements ITE(f,g,h). Returns NULL if too many nodes are required.] Description [Implements ITE(f,g,h). Returns a pointer to the resulting BDD if successful; NULL if the intermediate result blows up or more new nodes than <code>limit</code> are required.] SideEffects [None] SeeAlso [Cudd_bddIte] ******************************************************************************/ DdNode * Cudd_bddIteLimit( DdManager * dd, DdNode * f, DdNode * g, DdNode * h, unsigned int limit) { DdNode *res; unsigned int saveLimit = dd->maxLive; dd->maxLive = (dd->keys - dd->dead) + (dd->keysZ - dd->deadZ) + limit; do { dd->reordered = 0; res = cuddBddIteRecur(dd,f,g,h); } while (dd->reordered == 1); dd->maxLive = saveLimit; return(res); } /* end of Cudd_bddIteLimit */
/**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 [Implements the recursive step of Cudd_SolveEqn.] Description [Implements the recursive step of Cudd_SolveEqn. Returns NULL if the intermediate solution blows up or reordering occurs. The parametric solutions are stored in the array G.] SideEffects [none] SeeAlso [Cudd_SolveEqn, Cudd_VerifySol] ******************************************************************************/ DdNode * cuddSolveEqnRecur( DdManager * bdd, DdNode * F /* the left-hand side of the equation */, DdNode * Y /* the cube of remaining y variables */, DdNode ** G /* the array of solutions */, int n /* number of unknowns */, int * yIndex /* array holding the y variable indices */, int i /* level of recursion */) { DdNode *Fn, *Fm1, *Fv, *Fvbar, *T, *w, *nextY, *one; DdNodePtr *variables; int j; statLine(bdd); variables = bdd->vars; one = DD_ONE(bdd); /* Base condition. */ if (Y == one) { return F; } /* Cofactor of Y. */ yIndex[i] = Y->index; nextY = Cudd_T(Y); /* Universal abstraction of F with respect to the top variable index. */ Fm1 = cuddBddExistAbstractRecur(bdd, Cudd_Not(F), variables[yIndex[i]]); if (Fm1) { Fm1 = Cudd_Not(Fm1); cuddRef(Fm1); } else { return(NULL); } Fn = cuddSolveEqnRecur(bdd, Fm1, nextY, G, n, yIndex, i+1); if (Fn) { cuddRef(Fn); } else { Cudd_RecursiveDeref(bdd, Fm1); return(NULL); } Fv = cuddCofactorRecur(bdd, F, variables[yIndex[i]]); if (Fv) { cuddRef(Fv); } else { Cudd_RecursiveDeref(bdd, Fm1); Cudd_RecursiveDeref(bdd, Fn); return(NULL); } Fvbar = cuddCofactorRecur(bdd, F, Cudd_Not(variables[yIndex[i]])); if (Fvbar) { cuddRef(Fvbar); } else { Cudd_RecursiveDeref(bdd, Fm1); Cudd_RecursiveDeref(bdd, Fn); Cudd_RecursiveDeref(bdd, Fv); return(NULL); } /* Build i-th component of the solution. */ w = cuddBddIteRecur(bdd, variables[yIndex[i]], Cudd_Not(Fv), Fvbar); if (w) { cuddRef(w); } else { Cudd_RecursiveDeref(bdd, Fm1); Cudd_RecursiveDeref(bdd, Fn); Cudd_RecursiveDeref(bdd, Fv); Cudd_RecursiveDeref(bdd, Fvbar); return(NULL); } T = cuddBddRestrictRecur(bdd, w, Cudd_Not(Fm1)); if(T) { cuddRef(T); } else { Cudd_RecursiveDeref(bdd, Fm1); Cudd_RecursiveDeref(bdd, Fn); Cudd_RecursiveDeref(bdd, Fv); Cudd_RecursiveDeref(bdd, Fvbar); Cudd_RecursiveDeref(bdd, w); return(NULL); } Cudd_RecursiveDeref(bdd,Fm1); Cudd_RecursiveDeref(bdd,w); Cudd_RecursiveDeref(bdd,Fv); Cudd_RecursiveDeref(bdd,Fvbar); /* Substitute components of solution already found into solution. */ for (j = n-1; j > i; j--) { w = cuddBddComposeRecur(bdd,T, G[j], variables[yIndex[j]]); if(w) { cuddRef(w); } else { Cudd_RecursiveDeref(bdd, Fn); Cudd_RecursiveDeref(bdd, T); return(NULL); } Cudd_RecursiveDeref(bdd,T); T = w; } G[i] = T; Cudd_Deref(Fn); return(Fn); } /* end of cuddSolveEqnRecur */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_zddPortToBdd.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ static DdNode * zddPortToBddStep( DdManager * dd /* manager */, DdNode * f /* ZDD to be converted */, int depth /* recursion depth */) { DdNode *one, *zero, *T, *E, *res, *var; unsigned int index; unsigned int level; statLine(dd); one = DD_ONE(dd); zero = DD_ZERO(dd); if (f == zero) return(Cudd_Not(one)); if (depth == dd->sizeZ) return(one); index = dd->invpermZ[depth]; level = cuddIZ(dd,f->index); var = cuddUniqueInter(dd,index,one,Cudd_Not(one)); if (var == NULL) return(NULL); cuddRef(var); if (level > (unsigned) depth) { E = zddPortToBddStep(dd,f,depth+1); if (E == NULL) { Cudd_RecursiveDeref(dd,var); return(NULL); } cuddRef(E); res = cuddBddIteRecur(dd,var,Cudd_Not(one),E); if (res == NULL) { Cudd_RecursiveDeref(dd,var); Cudd_RecursiveDeref(dd,E); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(dd,var); Cudd_RecursiveDeref(dd,E); cuddDeref(res); return(res); } res = cuddCacheLookup1(dd,Cudd_zddPortToBdd,f); if (res != NULL) { Cudd_RecursiveDeref(dd,var); return(res); } T = zddPortToBddStep(dd,cuddT(f),depth+1); if (T == NULL) { Cudd_RecursiveDeref(dd,var); return(NULL); } cuddRef(T); E = zddPortToBddStep(dd,cuddE(f),depth+1); if (E == NULL) { Cudd_RecursiveDeref(dd,var); Cudd_RecursiveDeref(dd,T); return(NULL); } cuddRef(E); res = cuddBddIteRecur(dd,var,T,E); if (res == NULL) { Cudd_RecursiveDeref(dd,var); Cudd_RecursiveDeref(dd,T); Cudd_RecursiveDeref(dd,E); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(dd,var); Cudd_RecursiveDeref(dd,T); Cudd_RecursiveDeref(dd,E); cuddDeref(res); cuddCacheInsert1(dd,Cudd_zddPortToBdd,f,res); return(res); } /* end of zddPortToBddStep */
/**Function******************************************************************** Synopsis [Implements the recursive step of Cudd_SplitSet.] Description [Implements the recursive step of Cudd_SplitSet. The procedure recursively traverses the BDD and checks to see if any node satisfies the minterm requirements as specified by 'n'. At any node X, n is compared to the number of minterms in the onset of X's children. If either of the child nodes have exactly n minterms, then that node is returned; else, if n is greater than the onset of one of the child nodes, that node is retained and the difference in the number of minterms is extracted from the other child. In case n minterms can be extracted from constant 1, the algorithm returns the result with at most log(n) nodes.] SideEffects [The array 'varSeen' is updated at every recursive call to set the variables traversed by the procedure.] SeeAlso [] ******************************************************************************/ DdNode* cuddSplitSetRecur( DdManager * manager, st_table * mtable, int * varSeen, DdNode * p, double n, double max, int index) { DdNode *one, *zero, *N, *Nv; DdNode *Nnv, *q, *r, *v; DdNode *result; double *dummy, numT, numE; int variable, positive; statLine(manager); one = DD_ONE(manager); zero = Cudd_Not(one); /* If p is constant, extract n minterms from constant 1. The procedure by ** construction guarantees that minterms will not be extracted from ** constant 0. */ if (Cudd_IsConstant(p)) { q = selectMintermsFromUniverse(manager,varSeen,n); return(q); } N = Cudd_Regular(p); /* Set variable as seen. */ variable = N->index; varSeen[manager->invperm[variable]] = -1; Nv = cuddT(N); Nnv = cuddE(N); if (Cudd_IsComplement(p)) { Nv = Cudd_Not(Nv); Nnv = Cudd_Not(Nnv); } /* If both the children of 'p' are constants, extract n minterms from a ** constant node. */ if (Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) { q = selectMintermsFromUniverse(manager,varSeen,n); if (q == NULL) { return(NULL); } cuddRef(q); r = cuddBddAndRecur(manager,p,q); if (r == NULL) { Cudd_RecursiveDeref(manager,q); return(NULL); } cuddRef(r); Cudd_RecursiveDeref(manager,q); cuddDeref(r); return(r); } /* Lookup the # of minterms in the onset of the node from the table. */ if (!Cudd_IsConstant(Nv)) { if (!st_lookup(mtable, Nv, &dummy)) return(NULL); numT = *dummy/(2*(1<<index)); } else if (Nv == one) { numT = max/(2*(1<<index)); } else { numT = 0; } if (!Cudd_IsConstant(Nnv)) { if (!st_lookup(mtable, Nnv, &dummy)) return(NULL); numE = *dummy/(2*(1<<index)); } else if (Nnv == one) { numE = max/(2*(1<<index)); } else { numE = 0; } v = cuddUniqueInter(manager,variable,one,zero); cuddRef(v); /* If perfect match. */ if (numT == n) { q = cuddBddAndRecur(manager,v,Nv); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); Cudd_RecursiveDeref(manager,v); cuddDeref(q); return(q); } if (numE == n) { q = cuddBddAndRecur(manager,Cudd_Not(v),Nnv); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); Cudd_RecursiveDeref(manager,v); cuddDeref(q); return(q); } /* If n is greater than numT, extract the difference from the ELSE child ** and retain the function represented by the THEN branch. */ if (numT < n) { q = cuddSplitSetRecur(manager,mtable,varSeen, Nnv,(n-numT),max,index+1); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); r = cuddBddIteRecur(manager,v,Nv,q); if (r == NULL) { Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(r); Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); cuddDeref(r); return(r); } /* If n is greater than numE, extract the difference from the THEN child ** and retain the function represented by the ELSE branch. */ if (numE < n) { q = cuddSplitSetRecur(manager,mtable,varSeen, Nv, (n-numE),max,index+1); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); r = cuddBddIteRecur(manager,v,q,Nnv); if (r == NULL) { Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(r); Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); cuddDeref(r); return(r); } /* None of the above cases; (n < numT and n < numE) and either of ** the Nv, Nnv or both are not constants. If possible extract the ** required minterms the constant branch. */ if (Cudd_IsConstant(Nv) && !Cudd_IsConstant(Nnv)) { q = selectMintermsFromUniverse(manager,varSeen,n); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); result = cuddBddAndRecur(manager,v,q); if (result == NULL) { Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(result); Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); cuddDeref(result); return(result); } else if (!Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) { q = selectMintermsFromUniverse(manager,varSeen,n); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); result = cuddBddAndRecur(manager,Cudd_Not(v),q); if (result == NULL) { Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(result); Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); cuddDeref(result); return(result); } /* Both Nv and Nnv are not constants. So choose the one which ** has fewer minterms in its onset. */ positive = 0; if (numT < numE) { q = cuddSplitSetRecur(manager,mtable,varSeen, Nv,n,max,index+1); positive = 1; } else { q = cuddSplitSetRecur(manager,mtable,varSeen, Nnv,n,max,index+1); } if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); if (positive) { result = cuddBddAndRecur(manager,v,q); } else { result = cuddBddAndRecur(manager,Cudd_Not(v),q); } if (result == NULL) { Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(result); Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); cuddDeref(result); return(result); } /* end of cuddSplitSetRecur */
/**Function******************************************************************** Synopsis [Performs the recursive steps of Cudd_bddExistAbstract.] Description [Performs the recursive steps of Cudd_bddExistAbstract. Returns the BDD obtained by abstracting the variables of cube from f if successful; NULL otherwise. It is also used by Cudd_bddUnivAbstract.] SideEffects [None] SeeAlso [Cudd_bddExistAbstract Cudd_bddUnivAbstract] ******************************************************************************/ DdNode * cuddBddExistAbstractRecur( DdManager * manager, DdNode * f, DdNode * cube) { DdNode *F, *T, *E, *res, *res1, *res2, *one; statLine(manager); one = DD_ONE(manager); F = Cudd_Regular(f); /* Cube is guaranteed to be a cube at this point. */ if (cube == one || F == one) { return(f); } /* From now on, f and cube are non-constant. */ /* Abstract a variable that does not appear in f. */ while (manager->perm[F->index] > manager->perm[cube->index]) { cube = cuddT(cube); if (cube == one) return(f); } /* Check the cache. */ if (F->ref != 1 && (res = cuddCacheLookup2(manager, Cudd_bddExistAbstract, f, cube)) != NULL) { return(res); } /* Compute the cofactors of f. */ T = cuddT(F); E = cuddE(F); if (f != F) { T = Cudd_Not(T); E = Cudd_Not(E); } /* If the two indices are the same, so are their levels. */ if (F->index == cube->index) { if (T == one || E == one || T == Cudd_Not(E)) { return(one); } res1 = cuddBddExistAbstractRecur(manager, T, cuddT(cube)); if (res1 == NULL) return(NULL); if (res1 == one) { if (F->ref != 1) cuddCacheInsert2(manager, Cudd_bddExistAbstract, f, cube, one); return(one); } cuddRef(res1); res2 = cuddBddExistAbstractRecur(manager, E, cuddT(cube)); if (res2 == NULL) { Cudd_IterDerefBdd(manager,res1); return(NULL); } cuddRef(res2); res = cuddBddAndRecur(manager, Cudd_Not(res1), Cudd_Not(res2)); if (res == NULL) { Cudd_IterDerefBdd(manager, res1); Cudd_IterDerefBdd(manager, res2); return(NULL); } res = Cudd_Not(res); cuddRef(res); Cudd_IterDerefBdd(manager, res1); Cudd_IterDerefBdd(manager, res2); if (F->ref != 1) cuddCacheInsert2(manager, Cudd_bddExistAbstract, f, cube, res); cuddDeref(res); return(res); } else { /* if (cuddI(manager,F->index) < cuddI(manager,cube->index)) */ res1 = cuddBddExistAbstractRecur(manager, T, cube); if (res1 == NULL) return(NULL); cuddRef(res1); res2 = cuddBddExistAbstractRecur(manager, E, cube); if (res2 == NULL) { Cudd_IterDerefBdd(manager, res1); return(NULL); } cuddRef(res2); /* ITE takes care of possible complementation of res1 and of the ** case in which res1 == res2. */ res = cuddBddIteRecur(manager, manager->vars[F->index], res1, res2); if (res == NULL) { Cudd_IterDerefBdd(manager, res1); Cudd_IterDerefBdd(manager, res2); return(NULL); } cuddDeref(res1); cuddDeref(res2); if (F->ref != 1) cuddCacheInsert2(manager, Cudd_bddExistAbstract, f, cube, res); return(res); } } /* end of cuddBddExistAbstractRecur */
/**Function******************************************************************** Synopsis [Implements the recursive step of Cudd_bddIte.] Description [Implements the recursive step of Cudd_bddIte. Returns a pointer to the resulting BDD. NULL if the intermediate result blows up or if reordering occurs.] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * cuddBddIteRecur( DdManager * dd, DdNode * f, DdNode * g, DdNode * h) { DdNode *one, *zero, *res; DdNode *r, *Fv, *Fnv, *Gv, *Gnv, *H, *Hv, *Hnv, *t, *e; unsigned int topf, topg, toph, v; int index = -1; int comple; statLine(dd); /* Terminal cases. */ /* One variable cases. */ if (f == (one = DD_ONE(dd))) /* ITE(1,G,H) = G */ return(g); if (f == (zero = Cudd_Not(one))) /* ITE(0,G,H) = H */ return(h); /* From now on, f is known not to be a constant. */ if (g == one || f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */ if (h == zero) { /* ITE(F,1,0) = F */ return(f); } else { res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(h)); return(Cudd_NotCond(res,res != NULL)); } } else if (g == zero || f == Cudd_Not(g)) { /* ITE(F,!F,H) = ITE(F,0,H) = !F * H */ if (h == one) { /* ITE(F,0,1) = !F */ return(Cudd_Not(f)); } else { res = cuddBddAndRecur(dd,Cudd_Not(f),h); return(res); } } if (h == zero || f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */ res = cuddBddAndRecur(dd,f,g); return(res); } else if (h == one || f == Cudd_Not(h)) { /* ITE(F,G,!F) = ITE(F,G,1) = !F + G */ res = cuddBddAndRecur(dd,f,Cudd_Not(g)); return(Cudd_NotCond(res,res != NULL)); } /* Check remaining one variable case. */ if (g == h) { /* ITE(F,G,G) = G */ return(g); } else if (g == Cudd_Not(h)) { /* ITE(F,G,!G) = F <-> G */ res = cuddBddXorRecur(dd,f,h); return(res); } /* From here, there are no constants. */ comple = bddVarToCanonicalSimple(dd, &f, &g, &h, &topf, &topg, &toph); /* f & g are now regular pointers */ v = ddMin(topg, toph); /* A shortcut: ITE(F,G,H) = (v,G,H) if F = (v,1,0), v < top(G,H). */ if (topf < v && cuddT(f) == one && cuddE(f) == zero) { r = cuddUniqueInter(dd, (int) f->index, g, h); return(Cudd_NotCond(r,comple && r != NULL)); } /* Check cache. */ r = cuddCacheLookup(dd, DD_BDD_ITE_TAG, f, g, h); if (r != NULL) { return(Cudd_NotCond(r,comple)); } /* Compute cofactors. */ if (topf <= v) { v = ddMin(topf, v); /* v = top_var(F,G,H) */ index = f->index; Fv = cuddT(f); Fnv = cuddE(f); } else { Fv = Fnv = f; } if (topg == v) { index = g->index; Gv = cuddT(g); Gnv = cuddE(g); } else { Gv = Gnv = g; } if (toph == v) { H = Cudd_Regular(h); index = H->index; Hv = cuddT(H); Hnv = cuddE(H); if (Cudd_IsComplement(h)) { Hv = Cudd_Not(Hv); Hnv = Cudd_Not(Hnv); } } else { Hv = Hnv = h; } /* Recursive step. */ t = cuddBddIteRecur(dd,Fv,Gv,Hv); if (t == NULL) return(NULL); cuddRef(t); e = cuddBddIteRecur(dd,Fnv,Gnv,Hnv); if (e == NULL) { Cudd_IterDerefBdd(dd,t); return(NULL); } cuddRef(e); r = (t == e) ? t : cuddUniqueInter(dd,index,t,e); if (r == NULL) { Cudd_IterDerefBdd(dd,t); Cudd_IterDerefBdd(dd,e); return(NULL); } cuddDeref(t); cuddDeref(e); cuddCacheInsert(dd, DD_BDD_ITE_TAG, f, g, h, r); return(Cudd_NotCond(r,comple)); } /* end of cuddBddIteRecur */
/**Function******************************************************************** Synopsis [Performs the recursive step of Extra_TransferPermute.] Description [Performs the recursive step of Extra_TransferPermute. Returns a pointer to the result if successful; NULL otherwise.] SideEffects [None] SeeAlso [extraTransferPermuteTime] ******************************************************************************/ static DdNode * extraTransferPermuteRecurTime( DdManager * ddS, DdManager * ddD, DdNode * f, st_table * table, int * Permute, int TimeOut ) { DdNode *ft, *fe, *t, *e, *var, *res; DdNode *one, *zero; int index; int comple = 0; statLine( ddD ); one = DD_ONE( ddD ); comple = Cudd_IsComplement( f ); /* Trivial cases. */ if ( Cudd_IsConstant( f ) ) return ( Cudd_NotCond( one, comple ) ); /* Make canonical to increase the utilization of the cache. */ f = Cudd_NotCond( f, comple ); /* Now f is a regular pointer to a non-constant node. */ /* Check the cache. */ if ( st_lookup( table, ( char * ) f, ( char ** ) &res ) ) return ( Cudd_NotCond( res, comple ) ); if ( TimeOut && TimeOut < clock() ) return NULL; /* Recursive step. */ if ( Permute ) index = Permute[f->index]; else index = f->index; ft = cuddT( f ); fe = cuddE( f ); t = extraTransferPermuteRecurTime( ddS, ddD, ft, table, Permute, TimeOut ); if ( t == NULL ) { return ( NULL ); } cuddRef( t ); e = extraTransferPermuteRecurTime( ddS, ddD, fe, table, Permute, TimeOut ); if ( e == NULL ) { Cudd_RecursiveDeref( ddD, t ); return ( NULL ); } cuddRef( e ); zero = Cudd_Not(ddD->one); var = cuddUniqueInter( ddD, index, one, zero ); if ( var == NULL ) { Cudd_RecursiveDeref( ddD, t ); Cudd_RecursiveDeref( ddD, e ); return ( NULL ); } res = cuddBddIteRecur( ddD, var, t, e ); if ( res == NULL ) { Cudd_RecursiveDeref( ddD, t ); Cudd_RecursiveDeref( ddD, e ); return ( NULL ); } cuddRef( res ); Cudd_RecursiveDeref( ddD, t ); Cudd_RecursiveDeref( ddD, e ); if ( st_add_direct( table, ( char * ) f, ( char * ) res ) == ST_OUT_OF_MEM ) { Cudd_RecursiveDeref( ddD, res ); return ( NULL ); } return ( Cudd_NotCond( res, comple ) ); } /* end of extraTransferPermuteRecurTime */
/**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_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 [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 */