/**Function******************************************************************** Synopsis [Existentially abstracts all the variables in cube from f.] Description [Existentially abstracts all the variables in cube from f. Returns the abstracted BDD if successful; NULL if the intermediate result blows up or more new nodes than <code>limit</code> are required.] SideEffects [None] SeeAlso [Cudd_bddExistAbstract] ******************************************************************************/ DdNode * Cudd_bddExistAbstractLimit( DdManager * manager, DdNode * f, DdNode * cube, unsigned int limit) { DdNode *res; unsigned int saveLimit = manager->maxLive; if (bddCheckPositiveCube(manager, cube) == 0) { (void) fprintf(manager->err, "Error: Can only abstract positive cubes\n"); manager->errorCode = CUDD_INVALID_ARG; return(NULL); } manager->maxLive = (manager->keys - manager->dead) + (manager->keysZ - manager->deadZ) + limit; do { manager->reordered = 0; res = cuddBddExistAbstractRecur(manager, f, cube); } while (manager->reordered == 1); manager->maxLive = saveLimit; return(res); } /* end of Cudd_bddExistAbstractLimit */
/** @brief Existentially abstracts all the variables in cube from f. @return the abstracted %BDD if successful; NULL otherwise. @sideeffect None @see Cudd_bddUnivAbstract Cudd_addExistAbstract */ DdNode * Cudd_bddExistAbstract( DdManager * manager, DdNode * f, DdNode * cube) { DdNode *res; if (bddCheckPositiveCube(manager, cube) == 0) { (void) fprintf(manager->err, "Error: Can only abstract positive cubes\n"); manager->errorCode = CUDD_INVALID_ARG; return(NULL); } do { manager->reordered = 0; res = cuddBddExistAbstractRecur(manager, f, cube); } while (manager->reordered == 1); if (manager->errorCode == CUDD_TIMEOUT_EXPIRED && manager->timeoutHandler) { manager->timeoutHandler(manager, manager->tohArg); } return(res); } /* end of Cudd_bddExistAbstract */
/**Function******************************************************************** Synopsis [Universally abstracts all the variables in cube from f.] Description [Universally abstracts all the variables in cube from f. Returns the abstracted BDD if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_bddExistAbstract Cudd_addUnivAbstract] ******************************************************************************/ DdNode * Cudd_bddUnivAbstract( DdManager * manager, DdNode * f, DdNode * cube) { DdNode *res; if (bddCheckPositiveCube(manager, cube) == 0) { (void) fprintf(manager->err, "Error: Can only abstract positive cubes\n"); manager->errorCode = CUDD_INVALID_ARG; return(NULL); } do { manager->reordered = 0; res = cuddBddExistAbstractRecur(manager, Cudd_Not(f), cube); } while (manager->reordered == 1); if (res != NULL) res = Cudd_Not(res); return(res); } /* end of Cudd_bddUnivAbstract */
/**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_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 */
/** @brief Approximates the AND of two BDDs and simultaneously abstracts the variables in cube. @details The variables are existentially abstracted. @return a pointer to the result is successful; NULL otherwise. @sideeffect None @see Cudd_bddClippingAndAbstract */ static DdNode * cuddBddClipAndAbsRecur( DdManager * manager, DdNode * f, DdNode * g, DdNode * cube, int distance, int direction) { DdNode *F, *ft, *fe, *G, *gt, *ge; DdNode *one, *zero, *r, *t, *e, *Cube; int topf, topg, topcube, top; unsigned int index; ptruint cacheTag; statLine(manager); one = DD_ONE(manager); zero = Cudd_Not(one); /* Terminal cases. */ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero); if (f == one && g == one) return(one); if (cube == one) { return(cuddBddClippingAndRecur(manager, f, g, distance, direction)); } if (f == one || f == g) { return (cuddBddExistAbstractRecur(manager, g, cube)); } if (g == one) { return (cuddBddExistAbstractRecur(manager, f, cube)); } if (distance == 0) return(Cudd_NotCond(one,(direction == 0))); /* At this point f, g, and cube are not constant. */ distance--; /* Check cache. */ if (f > g) { /* Try to increase cache efficiency. */ DdNode *tmp = f; f = g; g = tmp; } F = Cudd_Regular(f); G = Cudd_Regular(g); cacheTag = direction ? DD_BDD_CLIPPING_AND_ABSTRACT_UP_TAG : DD_BDD_CLIPPING_AND_ABSTRACT_DOWN_TAG; if (F->ref != 1 || G->ref != 1) { r = cuddCacheLookup(manager, cacheTag, f, g, cube); if (r != NULL) { return(r); } } checkWhetherToGiveUp(manager); /* Here we can skip the use of cuddI, because the operands are known ** to be non-constant. */ topf = manager->perm[F->index]; topg = manager->perm[G->index]; top = ddMin(topf, topg); topcube = manager->perm[cube->index]; if (topcube < top) { return(cuddBddClipAndAbsRecur(manager, f, g, cuddT(cube), distance, direction)); } /* Now, topcube >= top. */ if (topf == top) { index = F->index; ft = cuddT(F); fe = cuddE(F); if (Cudd_IsComplement(f)) { ft = Cudd_Not(ft); fe = Cudd_Not(fe); } } else { index = G->index; ft = fe = f; } if (topg == top) { gt = cuddT(G); ge = cuddE(G); if (Cudd_IsComplement(g)) { gt = Cudd_Not(gt); ge = Cudd_Not(ge); } } else { gt = ge = g; } if (topcube == top) { Cube = cuddT(cube); } else { Cube = cube; } t = cuddBddClipAndAbsRecur(manager, ft, gt, Cube, distance, direction); if (t == NULL) return(NULL); /* Special case: 1 OR anything = 1. Hence, no need to compute ** the else branch if t is 1. */ if (t == one && topcube == top) { if (F->ref != 1 || G->ref != 1) cuddCacheInsert(manager, cacheTag, f, g, cube, one); return(one); } cuddRef(t); e = cuddBddClipAndAbsRecur(manager, fe, ge, Cube, distance, direction); if (e == NULL) { Cudd_RecursiveDeref(manager, t); return(NULL); } cuddRef(e); if (topcube == top) { /* abstract */ r = cuddBddClippingAndRecur(manager, Cudd_Not(t), Cudd_Not(e), distance, (direction == 0)); if (r == NULL) { Cudd_RecursiveDeref(manager, t); Cudd_RecursiveDeref(manager, e); return(NULL); } r = Cudd_Not(r); cuddRef(r); Cudd_RecursiveDeref(manager, t); Cudd_RecursiveDeref(manager, e); cuddDeref(r); } else if (t == e) { r = t; cuddDeref(t); cuddDeref(e); } else { if (Cudd_IsComplement(t)) { r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e)); if (r == NULL) { Cudd_RecursiveDeref(manager, t); Cudd_RecursiveDeref(manager, e); return(NULL); } r = Cudd_Not(r); } else { r = cuddUniqueInter(manager,(int)index,t,e); if (r == NULL) { Cudd_RecursiveDeref(manager, t); Cudd_RecursiveDeref(manager, e); return(NULL); } } cuddDeref(e); cuddDeref(t); } if (F->ref != 1 || G->ref != 1) cuddCacheInsert(manager, cacheTag, f, g, cube, r); return (r); } /* end of cuddBddClipAndAbsRecur */
/**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 [Takes the AND of two BDDs and simultaneously abstracts the variables in cube.] Description [Takes the AND of two BDDs and simultaneously abstracts the variables in cube. The variables are existentially abstracted. Returns a pointer to the result is successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_bddAndAbstract] ******************************************************************************/ DdNode * cuddBddAndAbstractRecur( DdManager * manager, DdNode * f, DdNode * g, DdNode * cube) { DdNode *F, *ft, *fe, *G, *gt, *ge; DdNode *one, *zero, *r, *t, *e; unsigned int topf, topg, topcube, top, index; statLine(manager); one = DD_ONE(manager); zero = Cudd_Not(one); /* Terminal cases. */ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero); if (f == one && g == one) return(one); if (cube == one) { return(cuddBddAndRecur(manager, f, g)); } if (f == one || f == g) { return(cuddBddExistAbstractRecur(manager, g, cube)); } if (g == one) { return(cuddBddExistAbstractRecur(manager, f, cube)); } /* At this point f, g, and cube are not constant. */ if (f > g) { /* Try to increase cache efficiency. */ DdNode *tmp = f; f = g; g = tmp; } /* Here we can skip the use of cuddI, because the operands are known ** to be non-constant. */ F = Cudd_Regular(f); G = Cudd_Regular(g); topf = manager->perm[F->index]; topg = manager->perm[G->index]; top = ddMin(topf, topg); topcube = manager->perm[cube->index]; while (topcube < top) { cube = cuddT(cube); if (cube == one) { return(cuddBddAndRecur(manager, f, g)); } topcube = manager->perm[cube->index]; } /* Now, topcube >= top. */ /* Check cache. */ if (F->ref != 1 || G->ref != 1) { r = cuddCacheLookup(manager, DD_BDD_AND_ABSTRACT_TAG, f, g, cube); if (r != NULL) { return(r); } } if ( manager->TimeStop && manager->TimeStop < clock() ) return NULL; if (topf == top) { index = F->index; ft = cuddT(F); fe = cuddE(F); if (Cudd_IsComplement(f)) { ft = Cudd_Not(ft); fe = Cudd_Not(fe); } } else { index = G->index; ft = fe = f; } if (topg == top) { gt = cuddT(G); ge = cuddE(G); if (Cudd_IsComplement(g)) { gt = Cudd_Not(gt); ge = Cudd_Not(ge); } } else { gt = ge = g; } if (topcube == top) { /* quantify */ DdNode *Cube = cuddT(cube); t = cuddBddAndAbstractRecur(manager, ft, gt, Cube); if (t == NULL) return(NULL); /* Special case: 1 OR anything = 1. Hence, no need to compute ** the else branch if t is 1. Likewise t + t * anything == t. ** Notice that t == fe implies that fe does not depend on the ** variables in Cube. Likewise for t == ge. */ if (t == one || t == fe || t == ge) { if (F->ref != 1 || G->ref != 1) cuddCacheInsert(manager, DD_BDD_AND_ABSTRACT_TAG, f, g, cube, t); return(t); } cuddRef(t); /* Special case: t + !t * anything == t + anything. */ if (t == Cudd_Not(fe)) { e = cuddBddExistAbstractRecur(manager, ge, Cube); } else if (t == Cudd_Not(ge)) { e = cuddBddExistAbstractRecur(manager, fe, Cube); } else { e = cuddBddAndAbstractRecur(manager, fe, ge, Cube); } if (e == NULL) { Cudd_IterDerefBdd(manager, t); return(NULL); } if (t == e) { r = t; cuddDeref(t); } else { cuddRef(e); r = cuddBddAndRecur(manager, Cudd_Not(t), Cudd_Not(e)); if (r == NULL) { Cudd_IterDerefBdd(manager, t); Cudd_IterDerefBdd(manager, e); return(NULL); } r = Cudd_Not(r); cuddRef(r); Cudd_DelayedDerefBdd(manager, t); Cudd_DelayedDerefBdd(manager, e); cuddDeref(r); } } else { t = cuddBddAndAbstractRecur(manager, ft, gt, cube); if (t == NULL) return(NULL); cuddRef(t); e = cuddBddAndAbstractRecur(manager, fe, ge, cube); if (e == NULL) { Cudd_IterDerefBdd(manager, t); return(NULL); } if (t == e) { r = t; cuddDeref(t); } else { cuddRef(e); if (Cudd_IsComplement(t)) { r = cuddUniqueInter(manager, (int) index, Cudd_Not(t), Cudd_Not(e)); if (r == NULL) { Cudd_IterDerefBdd(manager, t); Cudd_IterDerefBdd(manager, e); return(NULL); } r = Cudd_Not(r); } else { r = cuddUniqueInter(manager,(int)index,t,e); if (r == NULL) { Cudd_IterDerefBdd(manager, t); Cudd_IterDerefBdd(manager, e); return(NULL); } } cuddDeref(e); cuddDeref(t); } } if (F->ref != 1 || G->ref != 1) cuddCacheInsert(manager, DD_BDD_AND_ABSTRACT_TAG, f, g, cube, r); return (r); } /* end of cuddBddAndAbstractRecur */
/**Function******************************************************************** Synopsis [Takes the exclusive OR of two BDDs and simultaneously abstracts the variables in cube.] Description [Takes the exclusive OR of two BDDs and simultaneously abstracts the variables in cube. The variables are existentially abstracted. Returns a pointer to the result is successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_bddAndAbstract] ******************************************************************************/ DdNode * cuddBddXorExistAbstractRecur( DdManager * manager, DdNode * f, DdNode * g, DdNode * cube) { DdNode *F, *fv, *fnv, *G, *gv, *gnv; DdNode *one, *zero, *r, *t, *e, *Cube; unsigned int topf, topg, topcube, top, index; statLine(manager); one = DD_ONE(manager); zero = Cudd_Not(one); /* Terminal cases. */ if (f == g) { return(zero); } if (f == Cudd_Not(g)) { return(one); } if (cube == one) { return(cuddBddXorRecur(manager, f, g)); } if (f == one) { return(cuddBddExistAbstractRecur(manager, Cudd_Not(g), cube)); } if (g == one) { return(cuddBddExistAbstractRecur(manager, Cudd_Not(f), cube)); } if (f == zero) { return(cuddBddExistAbstractRecur(manager, g, cube)); } if (g == zero) { return(cuddBddExistAbstractRecur(manager, f, cube)); } /* At this point f, g, and cube are not constant. */ if (f > g) { /* Try to increase cache efficiency. */ DdNode *tmp = f; f = g; g = tmp; } /* Check cache. */ r = cuddCacheLookup(manager, DD_BDD_XOR_EXIST_ABSTRACT_TAG, f, g, cube); if (r != NULL) { return(r); } /* Here we can skip the use of cuddI, because the operands are known ** to be non-constant. */ F = Cudd_Regular(f); topf = manager->perm[F->index]; G = Cudd_Regular(g); topg = manager->perm[G->index]; top = ddMin(topf, topg); topcube = manager->perm[cube->index]; if (topcube < top) { return(cuddBddXorExistAbstractRecur(manager, f, g, cuddT(cube))); } /* Now, topcube >= top. */ if (topf == top) { index = F->index; fv = cuddT(F); fnv = cuddE(F); if (Cudd_IsComplement(f)) { fv = Cudd_Not(fv); fnv = Cudd_Not(fnv); } } else { index = G->index; fv = fnv = f; } if (topg == top) { gv = cuddT(G); gnv = cuddE(G); if (Cudd_IsComplement(g)) { gv = Cudd_Not(gv); gnv = Cudd_Not(gnv); } } else { gv = gnv = g; } if (topcube == top) { Cube = cuddT(cube); } else { Cube = cube; } t = cuddBddXorExistAbstractRecur(manager, fv, gv, Cube); if (t == NULL) return(NULL); /* Special case: 1 OR anything = 1. Hence, no need to compute ** the else branch if t is 1. */ if (t == one && topcube == top) { cuddCacheInsert(manager, DD_BDD_XOR_EXIST_ABSTRACT_TAG, f, g, cube, one); return(one); } cuddRef(t); e = cuddBddXorExistAbstractRecur(manager, fnv, gnv, Cube); if (e == NULL) { Cudd_IterDerefBdd(manager, t); return(NULL); } cuddRef(e); if (topcube == top) { /* abstract */ r = cuddBddAndRecur(manager, Cudd_Not(t), Cudd_Not(e)); if (r == NULL) { Cudd_IterDerefBdd(manager, t); Cudd_IterDerefBdd(manager, e); return(NULL); } r = Cudd_Not(r); cuddRef(r); Cudd_IterDerefBdd(manager, t); Cudd_IterDerefBdd(manager, e); cuddDeref(r); } else if (t == e) { r = t; cuddDeref(t); cuddDeref(e); } else { if (Cudd_IsComplement(t)) { r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e)); if (r == NULL) { Cudd_IterDerefBdd(manager, t); Cudd_IterDerefBdd(manager, e); return(NULL); } r = Cudd_Not(r); } else { r = cuddUniqueInter(manager,(int)index,t,e); if (r == NULL) { Cudd_IterDerefBdd(manager, t); Cudd_IterDerefBdd(manager, e); return(NULL); } } cuddDeref(e); cuddDeref(t); } cuddCacheInsert(manager, DD_BDD_XOR_EXIST_ABSTRACT_TAG, f, g, cube, r); return (r); } /* end of cuddBddXorExistAbstractRecur */
/**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 */