/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_zddSubset1.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ static DdNode * zdd_subset1_aux( DdManager * zdd, DdNode * P, DdNode * zvar) { int top_var, level; DdNode *res, *t, *e; DdNode *empty; statLine(zdd); empty = DD_ZERO(zdd); /* Check cache. */ res = cuddCacheLookup2Zdd(zdd, zdd_subset1_aux, P, zvar); if (res != NULL) return(res); if (cuddIsConstant(P)) { res = empty; cuddCacheInsert2(zdd, zdd_subset1_aux, P, zvar, res); return(res); } top_var = zdd->permZ[P->index]; level = zdd->permZ[zvar->index]; if (top_var > level) { res = empty; } else if (top_var == level) { res = cuddT(P); } else { t = zdd_subset1_aux(zdd, cuddT(P), zvar); if (t == NULL) return(NULL); cuddRef(t); e = zdd_subset1_aux(zdd, cuddE(P), zvar); if (e == NULL) { Cudd_RecursiveDerefZdd(zdd, t); return(NULL); } cuddRef(e); res = cuddZddGetNode(zdd, P->index, t, e); if (res == NULL) { Cudd_RecursiveDerefZdd(zdd, t); Cudd_RecursiveDerefZdd(zdd, e); return(NULL); } cuddDeref(t); cuddDeref(e); } cuddCacheInsert2(zdd, zdd_subset1_aux, P, zvar, res); return(res); } /* end of zdd_subset1_aux */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cuddaux_IsVarIn.] Description [Performs the recursive step of Cuddaux_IsVarIn. var is supposed to be a BDD projection function. Returns the logical one or zero.] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode* cuddauxIsVarInRecur(DdManager* manager, DdNode* f, DdNode* Var) { DdNode *zero,*one, *F, *res; int topV,topF; one = DD_ONE(manager); zero = Cudd_Not(one); F = Cudd_Regular(f); if (cuddIsConstant(F)) return zero; if (Var==F) return(one); topV = Var->index; topF = F->index; if (topF == topV) return(one); if (cuddI(manager,topV) < cuddI(manager,topF)) return(zero); res = cuddCacheLookup2(manager,cuddauxIsVarInRecur, F, Var); if (res != NULL) return(res); res = cuddauxIsVarInRecur(manager,cuddT(F),Var); if (res==zero){ res = cuddauxIsVarInRecur(manager,cuddE(F),Var); } cuddCacheInsert2(manager,cuddauxIsVarInRecur,F,Var,res); return(res); }
/**Function******************************************************************** Synopsis [Performs the recursive step for Cudd_addBddStrictThreshold.] Description [Performs the recursive step for Cudd_addBddStrictThreshold. Returns a pointer to the BDD if successful; NULL otherwise.] SideEffects [None] SeeAlso [addBddDoThreshold] ******************************************************************************/ static DdNode * addBddDoStrictThreshold( DdManager * dd, DdNode * f, DdNode * val) { DdNode *res, *T, *E; DdNode *fv, *fvn; int v; statLine(dd); /* Check terminal case. */ if (cuddIsConstant(f)) { return(Cudd_NotCond(DD_TRUE(dd),cuddV(f) <= cuddV(val))); } /* Check cache. */ res = cuddCacheLookup2(dd,addBddDoStrictThreshold,f,val); if (res != NULL) return(res); /* Recursive step. */ v = f->index; fv = cuddT(f); fvn = cuddE(f); T = addBddDoStrictThreshold(dd,fv,val); if (T == NULL) return(NULL); cuddRef(T); E = addBddDoStrictThreshold(dd,fvn,val); if (E == NULL) { Cudd_RecursiveDeref(dd, T); return(NULL); } cuddRef(E); if (Cudd_IsComplement(T)) { res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E)); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } res = Cudd_Not(res); } else { res = (T == E) ? T : cuddUniqueInter(dd,v,T,E); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } } cuddDeref(T); cuddDeref(E); /* Store result. */ cuddCacheInsert2(dd,addBddDoStrictThreshold,f,val,res); return(res); } /* end of addBddDoStrictThreshold */
DdNode* cuddauxAddGuardOfNodeRecur(DdManager* manager, DdNode* f, DdNode* h) { DdNode *one, *res, *T, *E; int topf, toph; /* Handle terminal cases */ one = DD_ONE(manager); if (f==h){ return(one); } topf = cuddI(manager,f->index); toph = cuddI(manager,h->index); if (topf >= toph){ return Cudd_Not(one); } /* Look in the cache */ res = cuddCacheLookup2(manager,Cuddaux_addGuardOfNode,f,h); if (res != NULL) return(res); T = cuddauxAddGuardOfNodeRecur(manager,cuddT(f),h); if (T == NULL) return(NULL); cuddRef(T); E = cuddauxAddGuardOfNodeRecur(manager,cuddE(f),h); if (E == NULL){ Cudd_IterDerefBdd(manager, T); return(NULL); } cuddRef(E); if (T == E){ res = T; } else { if (Cudd_IsComplement(T)){ res = cuddUniqueInter(manager,f->index,Cudd_Not(T),Cudd_Not(E)); if (res == NULL) { Cudd_IterDerefBdd(manager, T); Cudd_IterDerefBdd(manager, E); return(NULL); } res = Cudd_Not(res); } else { res = cuddUniqueInter(manager,f->index,T,E); if (res == NULL) { Cudd_IterDerefBdd(manager, T); Cudd_IterDerefBdd(manager, E); return(NULL); } } } cuddDeref(T); cuddDeref(E); cuddCacheInsert2(manager,Cuddaux_addGuardOfNode,f,h,res); return(res); }
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_zddChange.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * cuddZddChangeAux( DdManager * zdd, DdNode * P, DdNode * zvar) { int top_var, level; DdNode *res, *t, *e; DdNode *base = DD_ONE(zdd); DdNode *empty = DD_ZERO(zdd); statLine(zdd); if (P == empty) return(empty); if (P == base) return(zvar); /* Check cache. */ res = cuddCacheLookup2Zdd(zdd, cuddZddChangeAux, P, zvar); if (res != NULL) return(res); top_var = zdd->permZ[P->index]; level = zdd->permZ[zvar->index]; if (top_var > level) { res = cuddZddGetNode(zdd, zvar->index, P, DD_ZERO(zdd)); if (res == NULL) return(NULL); } else if (top_var == level) { res = cuddZddGetNode(zdd, zvar->index, cuddE(P), cuddT(P)); if (res == NULL) return(NULL); } else { t = cuddZddChangeAux(zdd, cuddT(P), zvar); if (t == NULL) return(NULL); cuddRef(t); e = cuddZddChangeAux(zdd, cuddE(P), zvar); if (e == NULL) { Cudd_RecursiveDerefZdd(zdd, t); return(NULL); } cuddRef(e); res = cuddZddGetNode(zdd, P->index, t, e); if (res == NULL) { Cudd_RecursiveDerefZdd(zdd, t); Cudd_RecursiveDerefZdd(zdd, e); return(NULL); } cuddDeref(t); cuddDeref(e); } cuddCacheInsert2(zdd, cuddZddChangeAux, P, zvar, res); return(res); } /* end of cuddZddChangeAux */
/**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 [Performs the recursive step for Cudd_addIthBit.] Description [Performs the recursive step for Cudd_addIthBit. Returns a pointer to the BDD if successful; NULL otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static DdNode * addDoIthBit( DdManager * dd, DdNode * f, DdNode * index) { DdNode *res, *T, *E; DdNode *fv, *fvn; int mask, value; int v; statLine(dd); /* Check terminal case. */ if (cuddIsConstant(f)) { mask = 1 << ((int) cuddV(index)); value = (int) cuddV(f); return((value & mask) == 0 ? DD_ZERO(dd) : DD_ONE(dd)); } /* Check cache. */ res = cuddCacheLookup2(dd,addDoIthBit,f,index); if (res != NULL) return(res); /* Recursive step. */ v = f->index; fv = cuddT(f); fvn = cuddE(f); T = addDoIthBit(dd,fv,index); if (T == NULL) return(NULL); cuddRef(T); E = addDoIthBit(dd,fvn,index); if (E == NULL) { Cudd_RecursiveDeref(dd, T); return(NULL); } cuddRef(E); res = (T == E) ? T : cuddUniqueInter(dd,v,T,E); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } cuddDeref(T); cuddDeref(E); /* Store result. */ cuddCacheInsert2(dd,addDoIthBit,f,index,res); return(res); } /* end of addDoIthBit */
/**Function******************************************************************** Synopsis [Checks whether a variable is dependent on others in a function.] Description [Checks whether a variable is dependent on others in a function. Returns 1 if the variable is dependent; 0 otherwise. No new nodes are created.] SideEffects [None] SeeAlso [] ******************************************************************************/ int Cudd_bddVarIsDependent( DdManager *dd, /* manager */ DdNode *f, /* function */ DdNode *var /* variable */) { DdNode *F, *res, *zero, *ft, *fe; unsigned topf, level; DD_CTFP cacheOp; int retval; /* NuSMV: begin add */ abort(); /* NOT USED BY NUSMV */ /* NuSMV: begin end */ zero = Cudd_Not(DD_TRUE(dd)); if (Cudd_IsConstant(f)) return(f == zero); /* From now on f is not constant. */ F = Cudd_Regular(f); topf = (unsigned) dd->perm[F->index]; level = (unsigned) dd->perm[var->index]; /* Check terminal case. If topf > index of var, f does not depend on var. ** Therefore, var is not dependent in f. */ if (topf > level) { return(0); } cacheOp = (DD_CTFP) Cudd_bddVarIsDependent; res = cuddCacheLookup2(dd,cacheOp,f,var); if (res != NULL) { return(res != zero); } /* Compute cofactors. */ ft = Cudd_NotCond(cuddT(F), f != F); fe = Cudd_NotCond(cuddE(F), f != F); if (topf == level) { retval = Cudd_bddLeq(dd,ft,Cudd_Not(fe)); } else { retval = Cudd_bddVarIsDependent(dd,ft,var) && Cudd_bddVarIsDependent(dd,fe,var); } cuddCacheInsert2(dd,cacheOp,f,var,Cudd_NotCond(zero,retval)); return(retval); } /* Cudd_bddVarIsDependent */
/**Function******************************************************************** Synopsis [Determines whether f is less than or equal to g.] Description [Returns 1 if f is less than or equal to g; 0 otherwise. No new nodes are created. This procedure works for arbitrary ADDs. For 0-1 ADDs Cudd_addEvalConst is more efficient.] SideEffects [None] SeeAlso [Cudd_addIteConstant Cudd_addEvalConst Cudd_bddLeq] ******************************************************************************/ int Cudd_addLeq( DdManager * dd, DdNode * f, DdNode * g) { DdNode *tmp, *fv, *fvn, *gv, *gvn; unsigned int topf, topg, res; /* Terminal cases. */ if (f == g) return(1); statLine(dd); if (cuddIsConstant(f)) { if (cuddIsConstant(g)) return(cuddV(f) <= cuddV(g)); if (f == DD_MINUS_INFINITY(dd)) return(1); if (f == DD_PLUS_INFINITY(dd)) return(0); /* since f != g */ } if (g == DD_PLUS_INFINITY(dd)) return(1); if (g == DD_MINUS_INFINITY(dd)) return(0); /* since f != g */ /* Check cache. */ tmp = cuddCacheLookup2(dd,(DD_CTFP)Cudd_addLeq,f,g); if (tmp != NULL) { return(tmp == DD_ONE(dd)); } /* Compute cofactors. One of f and g is not constant. */ topf = cuddI(dd,f->index); topg = cuddI(dd,g->index); if (topf <= topg) { fv = cuddT(f); fvn = cuddE(f); } else { fv = fvn = f; } if (topg <= topf) { gv = cuddT(g); gvn = cuddE(g); } else { gv = gvn = g; } res = Cudd_addLeq(dd,fvn,gvn) && Cudd_addLeq(dd,fv,gv); /* Store result in cache and return. */ cuddCacheInsert2(dd,(DD_CTFP) Cudd_addLeq,f,g, Cudd_NotCond(DD_ONE(dd),res==0)); return(res); } /* end of Cudd_addLeq */
/**Function******************************************************************** Synopsis [Performs the inclusion test for ZDDs (P implies Q).] Description [Inclusion test for ZDDs (P implies Q). No new nodes are generated by this procedure. Returns empty if true; a valid pointer different from empty or DD_NON_CONSTANT otherwise.] SideEffects [None] SeeAlso [Cudd_zddDiff] ******************************************************************************/ DdNode * Cudd_zddDiffConst( DdManager * zdd, DdNode * P, DdNode * Q) { int p_top, q_top; DdNode *empty = DD_ZERO(zdd), *t, *res; DdManager *table = zdd; statLine(zdd); if (P == empty) return(empty); if (Q == empty) return(P); if (P == Q) return(empty); /* Check cache. The cache is shared by cuddZddDiff(). */ res = cuddCacheLookup2Zdd(table, cuddZddDiff, P, Q); if (res != NULL) return(res); if (cuddIsConstant(P)) p_top = P->index; else p_top = zdd->permZ[P->index]; if (cuddIsConstant(Q)) q_top = Q->index; else q_top = zdd->permZ[Q->index]; if (p_top < q_top) { res = DD_NON_CONSTANT; } else if (p_top > q_top) { res = Cudd_zddDiffConst(zdd, P, cuddE(Q)); } else { t = Cudd_zddDiffConst(zdd, cuddT(P), cuddT(Q)); if (t != empty) res = DD_NON_CONSTANT; else res = Cudd_zddDiffConst(zdd, cuddE(P), cuddE(Q)); } cuddCacheInsert2(table, cuddZddDiff, P, Q, res); return(res); } /* end of Cudd_zddDiffConst */
/** @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 [Performs the recursive step of Cudd_bddIsop.] Description [] SideEffects [None] SeeAlso [Cudd_bddIsop] ******************************************************************************/ DdNode * cuddBddIsop( DdManager * dd, DdNode * L, DdNode * U) { DdNode *one = DD_ONE(dd); DdNode *zero = Cudd_Not(one); int v, top_l, top_u; DdNode *Lsub0, *Usub0, *Lsub1, *Usub1, *Ld, *Ud; DdNode *Lsuper0, *Usuper0, *Lsuper1, *Usuper1; DdNode *Isub0, *Isub1, *Id; DdNode *x; DdNode *term0, *term1, *sum; DdNode *Lv, *Uv, *Lnv, *Unv; DdNode *r; int index; statLine(dd); if (L == zero) return(zero); if (U == one) return(one); /* Check cache */ r = cuddCacheLookup2(dd, cuddBddIsop, L, U); if (r) return(r); top_l = dd->perm[Cudd_Regular(L)->index]; top_u = dd->perm[Cudd_Regular(U)->index]; v = ddMin(top_l, top_u); /* Compute cofactors */ if (top_l == v) { index = Cudd_Regular(L)->index; Lv = Cudd_T(L); Lnv = Cudd_E(L); if (Cudd_IsComplement(L)) { Lv = Cudd_Not(Lv); Lnv = Cudd_Not(Lnv); } } else { index = Cudd_Regular(U)->index; Lv = Lnv = L; } if (top_u == v) { Uv = Cudd_T(U); Unv = Cudd_E(U); if (Cudd_IsComplement(U)) { Uv = Cudd_Not(Uv); Unv = Cudd_Not(Unv); } } else { Uv = Unv = U; } Lsub0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Uv)); if (Lsub0 == NULL) return(NULL); Cudd_Ref(Lsub0); Usub0 = Unv; Lsub1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Unv)); if (Lsub1 == NULL) { Cudd_RecursiveDeref(dd, Lsub0); return(NULL); } Cudd_Ref(Lsub1); Usub1 = Uv; Isub0 = cuddBddIsop(dd, Lsub0, Usub0); if (Isub0 == NULL) { Cudd_RecursiveDeref(dd, Lsub0); Cudd_RecursiveDeref(dd, Lsub1); return(NULL); } Cudd_Ref(Isub0); Isub1 = cuddBddIsop(dd, Lsub1, Usub1); if (Isub1 == NULL) { Cudd_RecursiveDeref(dd, Lsub0); Cudd_RecursiveDeref(dd, Lsub1); Cudd_RecursiveDeref(dd, Isub0); return(NULL); } Cudd_Ref(Isub1); Cudd_RecursiveDeref(dd, Lsub0); Cudd_RecursiveDeref(dd, Lsub1); Lsuper0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Isub0)); if (Lsuper0 == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDeref(dd, Isub1); return(NULL); } Cudd_Ref(Lsuper0); Lsuper1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Isub1)); if (Lsuper1 == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDeref(dd, Lsuper0); return(NULL); } Cudd_Ref(Lsuper1); Usuper0 = Unv; Usuper1 = Uv; /* Ld = Lsuper0 + Lsuper1 */ Ld = cuddBddAndRecur(dd, Cudd_Not(Lsuper0), Cudd_Not(Lsuper1)); Ld = Cudd_NotCond(Ld, Ld != NULL); if (Ld == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDeref(dd, Lsuper0); Cudd_RecursiveDeref(dd, Lsuper1); return(NULL); } Cudd_Ref(Ld); Ud = cuddBddAndRecur(dd, Usuper0, Usuper1); if (Ud == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDeref(dd, Lsuper0); Cudd_RecursiveDeref(dd, Lsuper1); Cudd_RecursiveDeref(dd, Ld); return(NULL); } Cudd_Ref(Ud); Cudd_RecursiveDeref(dd, Lsuper0); Cudd_RecursiveDeref(dd, Lsuper1); Id = cuddBddIsop(dd, Ld, Ud); if (Id == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDeref(dd, Ld); Cudd_RecursiveDeref(dd, Ud); return(NULL); } Cudd_Ref(Id); Cudd_RecursiveDeref(dd, Ld); Cudd_RecursiveDeref(dd, Ud); x = cuddUniqueInter(dd, index, one, zero); if (x == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDeref(dd, Id); return(NULL); } Cudd_Ref(x); term0 = cuddBddAndRecur(dd, Cudd_Not(x), Isub0); if (term0 == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDeref(dd, Id); Cudd_RecursiveDeref(dd, x); return(NULL); } Cudd_Ref(term0); Cudd_RecursiveDeref(dd, Isub0); term1 = cuddBddAndRecur(dd, x, Isub1); if (term1 == NULL) { Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDeref(dd, Id); Cudd_RecursiveDeref(dd, x); Cudd_RecursiveDeref(dd, term0); return(NULL); } Cudd_Ref(term1); Cudd_RecursiveDeref(dd, x); Cudd_RecursiveDeref(dd, Isub1); /* sum = term0 + term1 */ sum = cuddBddAndRecur(dd, Cudd_Not(term0), Cudd_Not(term1)); sum = Cudd_NotCond(sum, sum != NULL); if (sum == NULL) { Cudd_RecursiveDeref(dd, Id); Cudd_RecursiveDeref(dd, term0); Cudd_RecursiveDeref(dd, term1); return(NULL); } Cudd_Ref(sum); Cudd_RecursiveDeref(dd, term0); Cudd_RecursiveDeref(dd, term1); /* r = sum + Id */ r = cuddBddAndRecur(dd, Cudd_Not(sum), Cudd_Not(Id)); r = Cudd_NotCond(r, r != NULL); if (r == NULL) { Cudd_RecursiveDeref(dd, Id); Cudd_RecursiveDeref(dd, sum); return(NULL); } Cudd_Ref(r); Cudd_RecursiveDeref(dd, sum); Cudd_RecursiveDeref(dd, Id); cuddCacheInsert2(dd, cuddBddIsop, L, U, r); Cudd_Deref(r); return(r); } /* end of cuddBddIsop */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_zddIsop.] Description [] SideEffects [None] SeeAlso [Cudd_zddIsop] ******************************************************************************/ DdNode * cuddZddIsop( DdManager * dd, DdNode * L, DdNode * U, DdNode ** zdd_I) { DdNode *one = DD_ONE(dd); DdNode *zero = Cudd_Not(one); DdNode *zdd_one = DD_ONE(dd); DdNode *zdd_zero = DD_ZERO(dd); int v, top_l, top_u; DdNode *Lsub0, *Usub0, *Lsub1, *Usub1, *Ld, *Ud; DdNode *Lsuper0, *Usuper0, *Lsuper1, *Usuper1; DdNode *Isub0, *Isub1, *Id; DdNode *zdd_Isub0, *zdd_Isub1, *zdd_Id; DdNode *x; DdNode *term0, *term1, *sum; DdNode *Lv, *Uv, *Lnv, *Unv; DdNode *r, *y, *z; int index; DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *); statLine(dd); if (L == zero) { *zdd_I = zdd_zero; return(zero); } if (U == one) { *zdd_I = zdd_one; return(one); } if (U == zero || L == one) { printf("*** ERROR : illegal condition for ISOP (U < L).\n"); exit(1); } /* Check the cache. We store two results for each recursive call. ** One is the BDD, and the other is the ZDD. Both are needed. ** Hence we need a double hit in the cache to terminate the ** recursion. Clearly, collisions may evict only one of the two ** results. */ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *)) cuddZddIsop; r = cuddCacheLookup2(dd, cuddBddIsop, L, U); if (r) { *zdd_I = cuddCacheLookup2Zdd(dd, cacheOp, L, U); if (*zdd_I) return(r); else { /* The BDD result may have been dead. In that case ** cuddCacheLookup2 would have called cuddReclaim, ** whose effects we now have to undo. */ cuddRef(r); Cudd_RecursiveDeref(dd, r); } } top_l = dd->perm[Cudd_Regular(L)->index]; top_u = dd->perm[Cudd_Regular(U)->index]; v = ddMin(top_l, top_u); /* Compute cofactors. */ if (top_l == v) { index = Cudd_Regular(L)->index; Lv = Cudd_T(L); Lnv = Cudd_E(L); if (Cudd_IsComplement(L)) { Lv = Cudd_Not(Lv); Lnv = Cudd_Not(Lnv); } } else { index = Cudd_Regular(U)->index; Lv = Lnv = L; } if (top_u == v) { Uv = Cudd_T(U); Unv = Cudd_E(U); if (Cudd_IsComplement(U)) { Uv = Cudd_Not(Uv); Unv = Cudd_Not(Unv); } } else { Uv = Unv = U; } Lsub0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Uv)); if (Lsub0 == NULL) return(NULL); Cudd_Ref(Lsub0); Usub0 = Unv; Lsub1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Unv)); if (Lsub1 == NULL) { Cudd_RecursiveDeref(dd, Lsub0); return(NULL); } Cudd_Ref(Lsub1); Usub1 = Uv; Isub0 = cuddZddIsop(dd, Lsub0, Usub0, &zdd_Isub0); if (Isub0 == NULL) { Cudd_RecursiveDeref(dd, Lsub0); Cudd_RecursiveDeref(dd, Lsub1); return(NULL); } /* if ((!cuddIsConstant(Cudd_Regular(Isub0))) && (Cudd_Regular(Isub0)->index != zdd_Isub0->index / 2 || dd->permZ[index * 2] > dd->permZ[zdd_Isub0->index])) { printf("*** ERROR : illegal permutation in ZDD. ***\n"); } */ Cudd_Ref(Isub0); Cudd_Ref(zdd_Isub0); Isub1 = cuddZddIsop(dd, Lsub1, Usub1, &zdd_Isub1); if (Isub1 == NULL) { Cudd_RecursiveDeref(dd, Lsub0); Cudd_RecursiveDeref(dd, Lsub1); Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub0); return(NULL); } /* if ((!cuddIsConstant(Cudd_Regular(Isub1))) && (Cudd_Regular(Isub1)->index != zdd_Isub1->index / 2 || dd->permZ[index * 2] > dd->permZ[zdd_Isub1->index])) { printf("*** ERROR : illegal permutation in ZDD. ***\n"); } */ Cudd_Ref(Isub1); Cudd_Ref(zdd_Isub1); Cudd_RecursiveDeref(dd, Lsub0); Cudd_RecursiveDeref(dd, Lsub1); Lsuper0 = cuddBddAndRecur(dd, Lnv, Cudd_Not(Isub0)); if (Lsuper0 == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); return(NULL); } Cudd_Ref(Lsuper0); Lsuper1 = cuddBddAndRecur(dd, Lv, Cudd_Not(Isub1)); if (Lsuper1 == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDeref(dd, Lsuper0); return(NULL); } Cudd_Ref(Lsuper1); Usuper0 = Unv; Usuper1 = Uv; /* Ld = Lsuper0 + Lsuper1 */ Ld = cuddBddAndRecur(dd, Cudd_Not(Lsuper0), Cudd_Not(Lsuper1)); if (Ld == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDeref(dd, Lsuper0); Cudd_RecursiveDeref(dd, Lsuper1); return(NULL); } Ld = Cudd_Not(Ld); Cudd_Ref(Ld); /* Ud = Usuper0 * Usuper1 */ Ud = cuddBddAndRecur(dd, Usuper0, Usuper1); if (Ud == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDeref(dd, Lsuper0); Cudd_RecursiveDeref(dd, Lsuper1); Cudd_RecursiveDeref(dd, Ld); return(NULL); } Cudd_Ref(Ud); Cudd_RecursiveDeref(dd, Lsuper0); Cudd_RecursiveDeref(dd, Lsuper1); Id = cuddZddIsop(dd, Ld, Ud, &zdd_Id); if (Id == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDeref(dd, Ld); Cudd_RecursiveDeref(dd, Ud); return(NULL); } /* if ((!cuddIsConstant(Cudd_Regular(Id))) && (Cudd_Regular(Id)->index != zdd_Id->index / 2 || dd->permZ[index * 2] > dd->permZ[zdd_Id->index])) { printf("*** ERROR : illegal permutation in ZDD. ***\n"); } */ Cudd_Ref(Id); Cudd_Ref(zdd_Id); Cudd_RecursiveDeref(dd, Ld); Cudd_RecursiveDeref(dd, Ud); x = cuddUniqueInter(dd, index, one, zero); if (x == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDeref(dd, Id); Cudd_RecursiveDerefZdd(dd, zdd_Id); return(NULL); } Cudd_Ref(x); /* term0 = x * Isub0 */ term0 = cuddBddAndRecur(dd, Cudd_Not(x), Isub0); if (term0 == NULL) { Cudd_RecursiveDeref(dd, Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDeref(dd, Id); Cudd_RecursiveDerefZdd(dd, zdd_Id); Cudd_RecursiveDeref(dd, x); return(NULL); } Cudd_Ref(term0); Cudd_RecursiveDeref(dd, Isub0); /* term1 = x * Isub1 */ term1 = cuddBddAndRecur(dd, x, Isub1); if (term1 == NULL) { Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDeref(dd, Isub1); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDeref(dd, Id); Cudd_RecursiveDerefZdd(dd, zdd_Id); Cudd_RecursiveDeref(dd, x); Cudd_RecursiveDeref(dd, term0); return(NULL); } Cudd_Ref(term1); Cudd_RecursiveDeref(dd, x); Cudd_RecursiveDeref(dd, Isub1); /* sum = term0 + term1 */ sum = cuddBddAndRecur(dd, Cudd_Not(term0), Cudd_Not(term1)); if (sum == NULL) { Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDeref(dd, Id); Cudd_RecursiveDerefZdd(dd, zdd_Id); Cudd_RecursiveDeref(dd, term0); Cudd_RecursiveDeref(dd, term1); return(NULL); } sum = Cudd_Not(sum); Cudd_Ref(sum); Cudd_RecursiveDeref(dd, term0); Cudd_RecursiveDeref(dd, term1); /* r = sum + Id */ r = cuddBddAndRecur(dd, Cudd_Not(sum), Cudd_Not(Id)); r = Cudd_NotCond(r, r != NULL); if (r == NULL) { Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDeref(dd, Id); Cudd_RecursiveDerefZdd(dd, zdd_Id); Cudd_RecursiveDeref(dd, sum); return(NULL); } Cudd_Ref(r); Cudd_RecursiveDeref(dd, sum); Cudd_RecursiveDeref(dd, Id); if (zdd_Isub0 != zdd_zero) { z = cuddZddGetNodeIVO(dd, index * 2 + 1, zdd_Isub0, zdd_Id); if (z == NULL) { Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDerefZdd(dd, zdd_Id); Cudd_RecursiveDeref(dd, r); return(NULL); } } else { z = zdd_Id; } Cudd_Ref(z); if (zdd_Isub1 != zdd_zero) { y = cuddZddGetNodeIVO(dd, index * 2, zdd_Isub1, z); if (y == NULL) { Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDerefZdd(dd, zdd_Id); Cudd_RecursiveDeref(dd, r); Cudd_RecursiveDerefZdd(dd, z); return(NULL); } } else y = z; Cudd_Ref(y); Cudd_RecursiveDerefZdd(dd, zdd_Isub0); Cudd_RecursiveDerefZdd(dd, zdd_Isub1); Cudd_RecursiveDerefZdd(dd, zdd_Id); Cudd_RecursiveDerefZdd(dd, z); cuddCacheInsert2(dd, cuddBddIsop, L, U, r); cuddCacheInsert2(dd, cacheOp, L, U, y); Cudd_Deref(r); Cudd_Deref(y); *zdd_I = y; /* if (Cudd_Regular(r)->index != y->index / 2) { printf("*** ERROR : mismatch in indices between BDD and ZDD. ***\n"); } */ return(r); } /* end of cuddZddIsop */
/** @brief Implements the recursive step of Cudd_bddClippingAnd. @details Takes the conjunction of two BDDs. @return a pointer to the result is successful; NULL otherwise. @sideeffect None @see cuddBddClippingAnd */ static DdNode * cuddBddClippingAndRecur( DdManager * manager, DdNode * f, DdNode * g, int distance, int direction) { DdNode *F, *ft, *fe, *G, *gt, *ge; DdNode *one, *zero, *r, *t, *e; int topf, topg; unsigned int index; DD_CTFP cacheOp; 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 == g || g == one) return(f); if (f == one) return(g); if (distance == 0) { /* One last attempt at returning the right result. We sort of ** cheat by calling Cudd_bddLeq. */ if (Cudd_bddLeq(manager,f,g)) return(f); if (Cudd_bddLeq(manager,g,f)) return(g); if (direction == 1) { if (Cudd_bddLeq(manager,f,Cudd_Not(g)) || Cudd_bddLeq(manager,g,Cudd_Not(f))) return(zero); } return(Cudd_NotCond(one,(direction == 0))); } /* At this point f and g are not constant. */ distance--; /* Check cache. Try to increase cache efficiency by sorting the ** pointers. */ if (f > g) { DdNode *tmp = f; f = g; g = tmp; } F = Cudd_Regular(f); G = Cudd_Regular(g); cacheOp = (DD_CTFP) (direction ? Cudd_bddClippingAnd : cuddBddClippingAnd); if (F->ref != 1 || G->ref != 1) { r = cuddCacheLookup2(manager, cacheOp, f, g); 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]; /* Compute cofactors. */ if (topf <= topg) { 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 <= topf) { gt = cuddT(G); ge = cuddE(G); if (Cudd_IsComplement(g)) { gt = Cudd_Not(gt); ge = Cudd_Not(ge); } } else { gt = ge = g; } t = cuddBddClippingAndRecur(manager, ft, gt, distance, direction); if (t == NULL) return(NULL); cuddRef(t); e = cuddBddClippingAndRecur(manager, fe, ge, distance, direction); if (e == NULL) { Cudd_RecursiveDeref(manager, t); return(NULL); } cuddRef(e); if (t == e) { r = t; } 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) cuddCacheInsert2(manager, cacheOp, f, g, r); return(r); } /* end of cuddBddClippingAndRecur */
/**Function******************************************************************** Synopsis [Determines whether f is less than or equal to g.] Description [Returns 1 if f is less than or equal to g; 0 otherwise. No new nodes are created.] SideEffects [None] SeeAlso [Cudd_bddIteConstant Cudd_addEvalConst] ******************************************************************************/ int Cudd_bddLeq( DdManager * dd, DdNode * f, DdNode * g) { DdNode *one, *zero, *tmp, *F, *fv, *fvn, *gv, *gvn; unsigned int topf, topg, res; statLine(dd); /* Terminal cases and normalization. */ if (f == g) return(1); if (Cudd_IsComplement(g)) { /* Special case: if f is regular and g is complemented, ** f(1,...,1) = 1 > 0 = g(1,...,1). */ if (!Cudd_IsComplement(f)) return(0); /* Both are complemented: Swap and complement because ** f <= g <=> g' <= f' and we want the second argument to be regular. */ tmp = g; g = Cudd_Not(f); f = Cudd_Not(tmp); } else if (Cudd_IsComplement(f) && cuddF2L(g) < cuddF2L(f)) { tmp = g; g = Cudd_Not(f); f = Cudd_Not(tmp); } /* Now g is regular and, if f is not regular, f < g. */ one = DD_ONE(dd); if (g == one) return(1); /* no need to test against zero */ if (f == one) return(0); /* since at this point g != one */ if (Cudd_Not(f) == g) return(0); /* because neither is constant */ zero = Cudd_Not(one); if (f == zero) return(1); /* Here neither f nor g is constant. */ /* Check cache. */ tmp = cuddCacheLookup2(dd,(DD_CTFP)Cudd_bddLeq,f,g); if (tmp != NULL) { return(tmp == one); } /* Compute cofactors. */ F = Cudd_Regular(f); topf = dd->perm[F->index]; topg = dd->perm[g->index]; if (topf <= topg) { fv = cuddT(F); fvn = cuddE(F); if (f != F) { fv = Cudd_Not(fv); fvn = Cudd_Not(fvn); } } else { fv = fvn = f; } if (topg <= topf) { gv = cuddT(g); gvn = cuddE(g); } else { gv = gvn = g; } /* Recursive calls. Since we want to maximize the probability of ** the special case f(1,...,1) > g(1,...,1), we consider the negative ** cofactors first. Indeed, the complementation parity of the positive ** cofactors is the same as the one of the parent functions. */ res = Cudd_bddLeq(dd,fvn,gvn) && Cudd_bddLeq(dd,fv,gv); /* Store result in cache and return. */ cuddCacheInsert2(dd,(DD_CTFP)Cudd_bddLeq,f,g,(res ? one : zero)); return(res); } /* end of Cudd_bddLeq */
/**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 recursive step of Extra_bddCheckVarsSymmetric().] Description [Returns b0 if the variables are not symmetric. Returns b1 if the variables can be symmetric. The variables are represented in the form of a two-variable cube. In case the cube contains one variable (below Var1 level), the cube's pointer is complemented if the variable Var1 occurred on the current path; otherwise, the cube's pointer is regular. Uses additional complemented bit (Hash_Not) to mark the result if in the BDD rooted that this node there is a branch passing though the node labeled with Var2.] SideEffects [] SeeAlso [] ******************************************************************************/ DdNode * extraBddCheckVarsSymmetric( DdManager * dd, /* the DD manager */ DdNode * bF, DdNode * bVars) { DdNode * bRes; if ( bF == b0 ) return b1; assert( bVars != b1 ); if ( (bRes = cuddCacheLookup2(dd, extraBddCheckVarsSymmetric, bF, bVars)) ) return bRes; else { DdNode * bRes0, * bRes1; DdNode * bF0, * bF1; DdNode * bFR = Cudd_Regular(bF); int LevelF = cuddI(dd,bFR->index); DdNode * bVarsR = Cudd_Regular(bVars); int fVar1Pres; int iLev1; int iLev2; if ( bVarsR != bVars ) // cube's pointer is complemented { assert( cuddT(bVarsR) == b1 ); fVar1Pres = 1; // the first var is present on the path iLev1 = -1; // we are already below the first var level iLev2 = dd->perm[bVarsR->index]; // the level of the second var } else // cube's pointer is NOT complemented { fVar1Pres = 0; // the first var is absent on the path if ( cuddT(bVars) == b1 ) { iLev1 = -1; // we are already below the first var level iLev2 = dd->perm[bVars->index]; // the level of the second var } else { assert( cuddT(cuddT(bVars)) == b1 ); iLev1 = dd->perm[bVars->index]; // the level of the first var iLev2 = dd->perm[cuddT(bVars)->index]; // the level of the second var } } // cofactor the function // the cofactors are needed only if we are above the second level if ( LevelF < iLev2 ) { if ( bFR != bF ) // bFunc is complemented { bF0 = Cudd_Not( cuddE(bFR) ); bF1 = Cudd_Not( cuddT(bFR) ); } else { bF0 = cuddE(bFR); bF1 = cuddT(bFR); } } else bF0 = bF1 = NULL; // consider five cases: // (1) F is above iLev1 // (2) F is on the level iLev1 // (3) F is between iLev1 and iLev2 // (4) F is on the level iLev2 // (5) F is below iLev2 // (1) F is above iLev1 if ( LevelF < iLev1 ) { // the returned result cannot have the hash attribute // because we still did not reach the level of Var1; // the attribute never travels above the level of Var1 bRes0 = extraBddCheckVarsSymmetric( dd, bF0, bVars ); // assert( !Hash_IsComplement( bRes0 ) ); assert( bRes0 != z0 ); if ( bRes0 == b0 ) bRes = b0; else bRes = extraBddCheckVarsSymmetric( dd, bF1, bVars ); // assert( !Hash_IsComplement( bRes ) ); assert( bRes != z0 ); } // (2) F is on the level iLev1 else if ( LevelF == iLev1 ) { bRes0 = extraBddCheckVarsSymmetric( dd, bF0, Cudd_Not( cuddT(bVars) ) ); if ( bRes0 == b0 ) bRes = b0; else { bRes1 = extraBddCheckVarsSymmetric( dd, bF1, Cudd_Not( cuddT(bVars) ) ); if ( bRes1 == b0 ) bRes = b0; else { // if ( Hash_IsComplement( bRes0 ) || Hash_IsComplement( bRes1 ) ) if ( bRes0 == z0 || bRes1 == z0 ) bRes = b1; else bRes = b0; } } } // (3) F is between iLev1 and iLev2 else if ( LevelF < iLev2 ) { bRes0 = extraBddCheckVarsSymmetric( dd, bF0, bVars ); if ( bRes0 == b0 ) bRes = b0; else { bRes1 = extraBddCheckVarsSymmetric( dd, bF1, bVars ); if ( bRes1 == b0 ) bRes = b0; else { // if ( Hash_IsComplement( bRes0 ) || Hash_IsComplement( bRes1 ) ) // bRes = Hash_Not( b1 ); if ( bRes0 == z0 || bRes1 == z0 ) bRes = z0; else bRes = b1; } } } // (4) F is on the level iLev2 else if ( LevelF == iLev2 ) { // this is the only place where the hash attribute (Hash_Not) can be added // to the result; it can be added only if the path came through the node // lebeled with Var1; therefore, the hash attribute cannot be returned // to the caller function if ( fVar1Pres ) // bRes = Hash_Not( b1 ); bRes = z0; else bRes = b0; } // (5) F is below iLev2 else // if ( LevelF > iLev2 ) { // it is possible that the path goes through the node labeled by Var1 // and still everything is okay; we do not label with Hash_Not here // because the path does not go through node labeled by Var2 bRes = b1; } cuddCacheInsert2(dd, extraBddCheckVarsSymmetric, bF, bVars, bRes); return bRes; } } /* end of extraBddCheckVarsSymmetric */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_addOrAbstract.] Description [Performs the recursive step of Cudd_addOrAbstract. Returns the ADD obtained by abstracting the variables of cube from f, if successful; NULL otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * cuddAddOrAbstractRecur( DdManager * manager, DdNode * f, DdNode * cube) { DdNode *T, *E, *res, *res1, *res2, *one; statLine(manager); one = DD_ONE(manager); /* Cube is guaranteed to be a cube at this point. */ if (cuddIsConstant(f) || cube == one) { return(f); } /* Abstract a variable that does not appear in f. */ if (cuddI(manager,f->index) > cuddI(manager,cube->index)) { res = cuddAddOrAbstractRecur(manager, f, cuddT(cube)); return(res); } if ((res = cuddCacheLookup2(manager, Cudd_addOrAbstract, f, cube)) != NULL) { return(res); } T = cuddT(f); E = cuddE(f); /* If the two indices are the same, so are their levels. */ if (f->index == cube->index) { res1 = cuddAddOrAbstractRecur(manager, T, cuddT(cube)); if (res1 == NULL) return(NULL); cuddRef(res1); if (res1 != one) { res2 = cuddAddOrAbstractRecur(manager, E, cuddT(cube)); if (res2 == NULL) { Cudd_RecursiveDeref(manager,res1); return(NULL); } cuddRef(res2); res = cuddAddApplyRecur(manager, Cudd_addOr, res1, res2); if (res == NULL) { Cudd_RecursiveDeref(manager,res1); Cudd_RecursiveDeref(manager,res2); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(manager,res1); Cudd_RecursiveDeref(manager,res2); } else { res = res1; } cuddCacheInsert2(manager, Cudd_addOrAbstract, f, cube, res); cuddDeref(res); return(res); } else { /* if (cuddI(manager,f->index) < cuddI(manager,cube->index)) */ res1 = cuddAddOrAbstractRecur(manager, T, cube); if (res1 == NULL) return(NULL); cuddRef(res1); res2 = cuddAddOrAbstractRecur(manager, E, cube); if (res2 == NULL) { Cudd_RecursiveDeref(manager,res1); return(NULL); } cuddRef(res2); res = (res1 == res2) ? res1 : cuddUniqueInter(manager, (int) f->index, res1, res2); if (res == NULL) { Cudd_RecursiveDeref(manager,res1); Cudd_RecursiveDeref(manager,res2); return(NULL); } cuddDeref(res1); cuddDeref(res2); cuddCacheInsert2(manager, Cudd_addOrAbstract, f, cube, res); return(res); } } /* end of cuddAddOrAbstractRecur */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_Cofactor.] Description [Performs the recursive step of Cudd_Cofactor. Returns a pointer to the cofactor if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_Cofactor] ******************************************************************************/ DdNode * cuddCofactorRecur( DdManager * dd, DdNode * f, DdNode * g) { DdNode *one,*zero,*F,*G,*g1,*g0,*f1,*f0,*t,*e,*r; unsigned int topf,topg; int comple; F = Cudd_Regular(f); if (cuddIsConstant(F)) return(f); one = DD_ONE(dd); /* The invariant g != 0 is true on entry to this procedure and is ** recursively maintained by it. Therefore it suffices to test g ** against one to make sure it is not constant. */ if (g == one) return(f); /* From now on, f and g are known not to be constants. */ comple = f != F; r = cuddCacheLookup2(dd,Cudd_Cofactor,F,g); if (r != NULL) { return(Cudd_NotCond(r,comple)); } topf = dd->perm[F->index]; G = Cudd_Regular(g); topg = dd->perm[G->index]; /* We take the cofactors of F because we are going to rely on ** the fact that the cofactors of the complement are the complements ** of the cofactors to better utilize the cache. Variable comple ** remembers whether we have to complement the result or not. */ if (topf <= topg) { f1 = cuddT(F); f0 = cuddE(F); } else { f1 = f0 = F; } if (topg <= topf) { g1 = cuddT(G); g0 = cuddE(G); if (g != G) { g1 = Cudd_Not(g1); g0 = Cudd_Not(g0); } } else { g1 = g0 = g; } zero = Cudd_Not(one); if (topf >= topg) { if (g0 == zero || g0 == DD_ZERO(dd)) { r = cuddCofactorRecur(dd, f1, g1); } else if (g1 == zero || g1 == DD_ZERO(dd)) { r = cuddCofactorRecur(dd, f0, g0); } else { (void) fprintf(stdout,"Cudd_Cofactor: Invalid restriction 2\n"); return(NULL); } if (r == NULL) return(NULL); } else /* if (topf < topg) */ { t = cuddCofactorRecur(dd, f1, g); if (t == NULL) return(NULL); cuddRef(t); e = cuddCofactorRecur(dd, f0, g); if (e == NULL) { Cudd_RecursiveDeref(dd, t); return(NULL); } cuddRef(e); if (t == e) { r = t; } else if (Cudd_IsComplement(t)) { r = cuddUniqueInter(dd,(int)F->index,Cudd_Not(t),Cudd_Not(e)); if (r != NULL) r = Cudd_Not(r); } else { r = cuddUniqueInter(dd,(int)F->index,t,e); } if (r == NULL) { Cudd_RecursiveDeref(dd ,e); Cudd_RecursiveDeref(dd ,t); return(NULL); } cuddDeref(t); cuddDeref(e); } cuddCacheInsert2(dd,Cudd_Cofactor,F,g,r); return(Cudd_NotCond(r,comple)); } /* end of cuddCofactorRecur */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_addApply.] Description [Performs the recursive step of Cudd_addApply. Returns a pointer to the result if successful; NULL otherwise.] SideEffects [None] SeeAlso [cuddAddMonadicApplyRecur] ******************************************************************************/ DdNode * cuddAddApplyRecur( DdManager * dd, DdNode * (*op)(DdManager *, DdNode **, DdNode **), DdNode * f, DdNode * g) { DdNode *res, *fv, *fvn, *gv, *gvn, *T, *E; unsigned int ford, gord; unsigned int index; DdNode *(*cacheOp)(DdManager *, DdNode *, DdNode *); /* Check terminal cases. Op may swap f and g to increase the * cache hit rate. */ statLine(dd); res = (*op)(dd,&f,&g); if (res != NULL) return(res); /* Check cache. */ cacheOp = (DdNode *(*)(DdManager *, DdNode *, DdNode *)) op; res = cuddCacheLookup2(dd,cacheOp,f,g); if (res != NULL) return(res); /* Recursive step. */ ford = cuddI(dd,f->index); gord = cuddI(dd,g->index); if (ford <= gord) { index = f->index; fv = cuddT(f); fvn = cuddE(f); } else { index = g->index; fv = fvn = f; } if (gord <= ford) { gv = cuddT(g); gvn = cuddE(g); } else { gv = gvn = g; } T = cuddAddApplyRecur(dd,op,fv,gv); if (T == NULL) return(NULL); cuddRef(T); E = cuddAddApplyRecur(dd,op,fvn,gvn); if (E == NULL) { Cudd_RecursiveDeref(dd,T); return(NULL); } cuddRef(E); res = (T == E) ? T : cuddUniqueInter(dd,(int)index,T,E); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } cuddDeref(T); cuddDeref(E); /* Store result. */ cuddCacheInsert2(dd,cacheOp,f,g,res); return(res); } /* end of cuddAddApplyRecur */
/**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_bddAnd.] Description [Implements the recursive step of Cudd_bddAnd by taking the conjunction of two BDDs. Returns a pointer to the result is successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_bddAnd] ******************************************************************************/ DdNode * cuddBddAndRecur( DdManager * manager, DdNode * f, DdNode * g) { DdNode *F, *fv, *fnv, *G, *gv, *gnv; DdNode *one, *r, *t, *e; unsigned int topf, topg, index; statLine(manager); one = DD_ONE(manager); /* Terminal cases. */ F = Cudd_Regular(f); G = Cudd_Regular(g); if (F == G) { if (f == g) return(f); else return(Cudd_Not(one)); } if (F == one) { if (f == one) return(g); else return(f); } if (G == one) { if (g == one) return(f); else return(g); } /* At this point f and g are not constant. */ if (cuddF2L(f) > cuddF2L(g)) { /* Try to increase cache efficiency. */ DdNode *tmp = f; f = g; g = tmp; F = Cudd_Regular(f); G = Cudd_Regular(g); } /* Check cache. */ if (F->ref != 1 || G->ref != 1) { r = cuddCacheLookup2(manager, Cudd_bddAnd, f, g); if (r != NULL) return(r); } if ( manager->TimeStop && Abc_Clock() > manager->TimeStop ) return NULL; /* 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]; /* Compute cofactors. */ if (topf <= topg) { 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 <= topf) { gv = cuddT(G); gnv = cuddE(G); if (Cudd_IsComplement(g)) { gv = Cudd_Not(gv); gnv = Cudd_Not(gnv); } } else { gv = gnv = g; } t = cuddBddAndRecur(manager, fv, gv); if (t == NULL) return(NULL); cuddRef(t); e = cuddBddAndRecur(manager, fnv, gnv); if (e == NULL) { Cudd_IterDerefBdd(manager, t); return(NULL); } cuddRef(e); if (t == e) { r = t; } 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); if (F->ref != 1 || G->ref != 1) cuddCacheInsert2(manager, Cudd_bddAnd, f, g, r); return(r); } /* end of cuddBddAndRecur */
/**Function******************************************************************** Synopsis [Implements the recursive step of Cudd_bddIntersect.] Description [] SideEffects [None] SeeAlso [Cudd_bddIntersect] ******************************************************************************/ DdNode * cuddBddIntersectRecur( DdManager * dd, DdNode * f, DdNode * g) { DdNode *res; DdNode *F, *G, *t, *e; DdNode *fv, *fnv, *gv, *gnv; DdNode *one, *zero; unsigned int index, topf, topg; statLine(dd); one = DD_ONE(dd); zero = Cudd_Not(one); /* Terminal cases. */ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero); if (f == g || g == one) return(f); if (f == one) return(g); /* At this point f and g are not constant. */ if (cuddF2L(f) > cuddF2L(g)) { DdNode *tmp = f; f = g; g = tmp; } res = cuddCacheLookup2(dd,Cudd_bddIntersect,f,g); if (res != NULL) return(res); /* Find splitting variable. Here we can skip the use of cuddI, ** because the operands are known to be non-constant. */ F = Cudd_Regular(f); topf = dd->perm[F->index]; G = Cudd_Regular(g); topg = dd->perm[G->index]; /* Compute cofactors. */ if (topf <= topg) { 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 <= topf) { gv = cuddT(G); gnv = cuddE(G); if (Cudd_IsComplement(g)) { gv = Cudd_Not(gv); gnv = Cudd_Not(gnv); } } else { gv = gnv = g; } /* Compute partial results. */ t = cuddBddIntersectRecur(dd,fv,gv); if (t == NULL) return(NULL); cuddRef(t); if (t != zero) { e = zero; } else { e = cuddBddIntersectRecur(dd,fnv,gnv); if (e == NULL) { Cudd_IterDerefBdd(dd, t); return(NULL); } } cuddRef(e); if (t == e) { /* both equal zero */ res = t; } else if (Cudd_IsComplement(t)) { res = cuddUniqueInter(dd,(int)index,Cudd_Not(t),Cudd_Not(e)); if (res == NULL) { Cudd_IterDerefBdd(dd, t); Cudd_IterDerefBdd(dd, e); return(NULL); } res = Cudd_Not(res); } else { res = cuddUniqueInter(dd,(int)index,t,e); if (res == NULL) { Cudd_IterDerefBdd(dd, t); Cudd_IterDerefBdd(dd, e); return(NULL); } } cuddDeref(e); cuddDeref(t); cuddCacheInsert2(dd,Cudd_bddIntersect,f,g,res); return(res); } /* end of cuddBddIntersectRecur */
/**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 [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_zddDiff.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * cuddZddDiff( DdManager * zdd, DdNode * P, DdNode * Q) { int p_top, q_top; DdNode *empty = DD_ZERO(zdd), *t, *e, *res; DdManager *table = zdd; statLine(zdd); if (P == empty) return(empty); if (Q == empty) return(P); if (P == Q) return(empty); /* Check cache. The cache is shared by Cudd_zddDiffConst(). */ res = cuddCacheLookup2Zdd(table, cuddZddDiff, P, Q); if (res != NULL && res != DD_NON_CONSTANT) return(res); if (cuddIsConstant(P)) p_top = P->index; else p_top = zdd->permZ[P->index]; if (cuddIsConstant(Q)) q_top = Q->index; else q_top = zdd->permZ[Q->index]; if (p_top < q_top) { e = cuddZddDiff(zdd, cuddE(P), Q); if (e == NULL) return(NULL); cuddRef(e); res = cuddZddGetNode(zdd, P->index, cuddT(P), e); if (res == NULL) { Cudd_RecursiveDerefZdd(table, e); return(NULL); } cuddDeref(e); } else if (p_top > q_top) { res = cuddZddDiff(zdd, P, cuddE(Q)); if (res == NULL) return(NULL); } else { t = cuddZddDiff(zdd, cuddT(P), cuddT(Q)); if (t == NULL) return(NULL); cuddRef(t); e = cuddZddDiff(zdd, cuddE(P), cuddE(Q)); if (e == NULL) { Cudd_RecursiveDerefZdd(table, t); return(NULL); } cuddRef(e); res = cuddZddGetNode(zdd, P->index, t, e); if (res == NULL) { Cudd_RecursiveDerefZdd(table, t); Cudd_RecursiveDerefZdd(table, e); return(NULL); } cuddDeref(t); cuddDeref(e); } cuddCacheInsert2(table, cuddZddDiff, P, Q, res); return(res); } /* end of cuddZddDiff */
/**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 the recursive step of Cudd_bddLiteralSetIntersection.] Description [Performs the recursive step of Cudd_bddLiteralSetIntersection. Scans the cubes for common variables, and checks whether they agree in phase. Returns a pointer to the resulting cube if successful; NULL otherwise.] SideEffects [None] ******************************************************************************/ DdNode * cuddBddLiteralSetIntersectionRecur( DdManager * dd, DdNode * f, DdNode * g) { DdNode *res, *tmp; DdNode *F, *G; DdNode *fc, *gc; DdNode *one; DdNode *zero; unsigned int topf, topg, comple; int phasef, phaseg; statLine(dd); if (f == g) return(f); F = Cudd_Regular(f); G = Cudd_Regular(g); one = DD_ONE(dd); /* Here f != g. If F == G, then f and g are complementary. ** Since they are two cubes, this case only occurs when f == v, ** g == v', and v is a variable or its complement. */ if (F == G) return(one); zero = Cudd_Not(one); topf = cuddI(dd,F->index); topg = cuddI(dd,G->index); /* Look for a variable common to both cubes. If there are none, this ** loop will stop when the constant node is reached in both cubes. */ while (topf != topg) { if (topf < topg) { /* move down on f */ comple = f != F; f = cuddT(F); if (comple) f = Cudd_Not(f); if (f == zero) { f = cuddE(F); if (comple) f = Cudd_Not(f); } F = Cudd_Regular(f); topf = cuddI(dd,F->index); } else if (topg < topf) { comple = g != G; g = cuddT(G); if (comple) g = Cudd_Not(g); if (g == zero) { g = cuddE(G); if (comple) g = Cudd_Not(g); } G = Cudd_Regular(g); topg = cuddI(dd,G->index); } } /* At this point, f == one <=> g == 1. It suffices to test one of them. */ if (f == one) return(one); res = cuddCacheLookup2(dd,Cudd_bddLiteralSetIntersection,f,g); if (res != NULL) { return(res); } /* Here f and g are both non constant and have the same top variable. */ comple = f != F; fc = cuddT(F); phasef = 1; if (comple) fc = Cudd_Not(fc); if (fc == zero) { fc = cuddE(F); phasef = 0; if (comple) fc = Cudd_Not(fc); } comple = g != G; gc = cuddT(G); phaseg = 1; if (comple) gc = Cudd_Not(gc); if (gc == zero) { gc = cuddE(G); phaseg = 0; if (comple) gc = Cudd_Not(gc); } tmp = cuddBddLiteralSetIntersectionRecur(dd,fc,gc); if (tmp == NULL) { return(NULL); } if (phasef != phaseg) { res = tmp; } else { cuddRef(tmp); if (phasef == 0) { res = cuddBddAndRecur(dd,Cudd_Not(dd->vars[F->index]),tmp); } else { res = cuddBddAndRecur(dd,dd->vars[F->index],tmp); } if (res == NULL) { Cudd_RecursiveDeref(dd,tmp); return(NULL); } cuddDeref(tmp); /* Just cuddDeref, because it is included in result */ } cuddCacheInsert2(dd,Cudd_bddLiteralSetIntersection,f,g,res); return(res); } /* end of cuddBddLiteralSetIntersectionRecur */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_addUnivAbstract.] Description [Performs the recursive step of Cudd_addUnivAbstract. Returns the ADD obtained by abstracting the variables of cube from f, if successful; NULL otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * cuddAddUnivAbstractRecur( DdManager * manager, DdNode * f, DdNode * cube) { DdNode *T, *E, *res, *res1, *res2, *one, *zero; statLine(manager); one = DD_ONE(manager); zero = DD_ZERO(manager); /* Cube is guaranteed to be a cube at this point. ** zero and one are the only constatnts c such that c*c=c. */ if (f == zero || f == one || cube == one) { return(f); } /* Abstract a variable that does not appear in f. */ if (cuddI(manager,f->index) > cuddI(manager,cube->index)) { res1 = cuddAddUnivAbstractRecur(manager, f, cuddT(cube)); if (res1 == NULL) return(NULL); cuddRef(res1); /* Use the "internal" procedure to be alerted in case of ** dynamic reordering. If dynamic reordering occurs, we ** have to abort the entire abstraction. */ res = cuddAddApplyRecur(manager, Cudd_addTimes, res1, res1); if (res == NULL) { Cudd_RecursiveDeref(manager,res1); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(manager,res1); cuddDeref(res); return(res); } if ((res = cuddCacheLookup2(manager, Cudd_addUnivAbstract, f, cube)) != NULL) { return(res); } T = cuddT(f); E = cuddE(f); /* If the two indices are the same, so are their levels. */ if (f->index == cube->index) { res1 = cuddAddUnivAbstractRecur(manager, T, cuddT(cube)); if (res1 == NULL) return(NULL); cuddRef(res1); res2 = cuddAddUnivAbstractRecur(manager, E, cuddT(cube)); if (res2 == NULL) { Cudd_RecursiveDeref(manager,res1); return(NULL); } cuddRef(res2); res = cuddAddApplyRecur(manager, Cudd_addTimes, res1, res2); if (res == NULL) { Cudd_RecursiveDeref(manager,res1); Cudd_RecursiveDeref(manager,res2); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(manager,res1); Cudd_RecursiveDeref(manager,res2); cuddCacheInsert2(manager, Cudd_addUnivAbstract, f, cube, res); cuddDeref(res); return(res); } else { /* if (cuddI(manager,f->index) < cuddI(manager,cube->index)) */ res1 = cuddAddUnivAbstractRecur(manager, T, cube); if (res1 == NULL) return(NULL); cuddRef(res1); res2 = cuddAddUnivAbstractRecur(manager, E, cube); if (res2 == NULL) { Cudd_RecursiveDeref(manager,res1); return(NULL); } cuddRef(res2); res = (res1 == res2) ? res1 : cuddUniqueInter(manager, (int) f->index, res1, res2); if (res == NULL) { Cudd_RecursiveDeref(manager,res1); Cudd_RecursiveDeref(manager,res2); return(NULL); } cuddDeref(res1); cuddDeref(res2); cuddCacheInsert2(manager, Cudd_addUnivAbstract, f, cube, res); return(res); } } /* end of cuddAddUnivAbstractRecur */
/**Function******************************************************************** Synopsis [Implements the recursive step of Cudd_bddXor.] Description [Implements the recursive step of Cudd_bddXor by taking the exclusive OR of two BDDs. Returns a pointer to the result is successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_bddXor] ******************************************************************************/ DdNode * cuddBddXorRecur( DdManager * manager, DdNode * f, DdNode * g) { DdNode *fv, *fnv, *G, *gv, *gnv; DdNode *one, *zero, *r, *t, *e; unsigned int topf, topg, 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 (cuddF2L(f) > cuddF2L(g)) { /* Try to increase cache efficiency and simplify tests. */ DdNode *tmp = f; f = g; g = tmp; } if (g == zero) return(f); if (g == one) return(Cudd_Not(f)); if (Cudd_IsComplement(f)) { f = Cudd_Not(f); g = Cudd_Not(g); } /* Now the first argument is regular. */ if (f == one) return(Cudd_Not(g)); /* At this point f and g are not constant. */ /* Check cache. */ r = cuddCacheLookup2(manager, Cudd_bddXor, f, g); if (r != NULL) return(r); /* Here we can skip the use of cuddI, because the operands are known ** to be non-constant. */ topf = manager->perm[f->index]; G = Cudd_Regular(g); topg = manager->perm[G->index]; /* Compute cofactors. */ if (topf <= topg) { index = f->index; fv = cuddT(f); fnv = cuddE(f); } else { index = G->index; fv = fnv = f; } if (topg <= topf) { gv = cuddT(G); gnv = cuddE(G); if (Cudd_IsComplement(g)) { gv = Cudd_Not(gv); gnv = Cudd_Not(gnv); } } else { gv = gnv = g; } t = cuddBddXorRecur(manager, fv, gv); if (t == NULL) return(NULL); cuddRef(t); e = cuddBddXorRecur(manager, fnv, gnv); if (e == NULL) { Cudd_IterDerefBdd(manager, t); return(NULL); } cuddRef(e); if (t == e) { r = t; } 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); cuddCacheInsert2(manager, Cudd_bddXor, f, g, r); return(r); } /* end of cuddBddXorRecur */