/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_zddWeakDivF.] Description [] SideEffects [None] SeeAlso [Cudd_zddWeakDivF] ******************************************************************************/ DdNode * cuddZddWeakDivF( DdManager * dd, DdNode * f, DdNode * g) { int v, top_f, top_g, vf, vg; DdNode *one = DD_ONE(dd); DdNode *zero = DD_ZERO(dd); DdNode *f0, *f1, *fd, *g0, *g1, *gd; DdNode *q, *tmp; DdNode *r; DdNode *term1, *term0, *termd; int flag; int pv, nv; statLine(dd); if (g == one) return(f); if (f == zero || f == one) return(zero); if (f == g) return(one); /* Check cache. */ r = cuddCacheLookup2Zdd(dd, cuddZddWeakDivF, f, g); if (r) return(r); top_f = dd->permZ[f->index]; top_g = dd->permZ[g->index]; vf = top_f >> 1; vg = top_g >> 1; v = ddMin(top_f, top_g); if (v == top_f && vf < vg) { v = f->index; flag = cuddZddGetCofactors3(dd, f, v, &f1, &f0, &fd); if (flag == 1) return(NULL); Cudd_Ref(f1); Cudd_Ref(f0); Cudd_Ref(fd); pv = cuddZddGetPosVarIndex(dd, v); nv = cuddZddGetNegVarIndex(dd, v); term1 = cuddZddWeakDivF(dd, f1, g); if (term1 == NULL) { Cudd_RecursiveDerefZdd(dd, f1); Cudd_RecursiveDerefZdd(dd, f0); Cudd_RecursiveDerefZdd(dd, fd); return(NULL); } Cudd_Ref(term1); Cudd_RecursiveDerefZdd(dd, f1); term0 = cuddZddWeakDivF(dd, f0, g); if (term0 == NULL) { Cudd_RecursiveDerefZdd(dd, f0); Cudd_RecursiveDerefZdd(dd, fd); Cudd_RecursiveDerefZdd(dd, term1); return(NULL); } Cudd_Ref(term0); Cudd_RecursiveDerefZdd(dd, f0); termd = cuddZddWeakDivF(dd, fd, g); if (termd == NULL) { Cudd_RecursiveDerefZdd(dd, fd); Cudd_RecursiveDerefZdd(dd, term1); Cudd_RecursiveDerefZdd(dd, term0); return(NULL); } Cudd_Ref(termd); Cudd_RecursiveDerefZdd(dd, fd); tmp = cuddZddGetNode(dd, nv, term0, termd); /* nv = zi */ if (tmp == NULL) { Cudd_RecursiveDerefZdd(dd, term1); Cudd_RecursiveDerefZdd(dd, term0); Cudd_RecursiveDerefZdd(dd, termd); return(NULL); } Cudd_Ref(tmp); Cudd_RecursiveDerefZdd(dd, term0); Cudd_RecursiveDerefZdd(dd, termd); q = cuddZddGetNode(dd, pv, term1, tmp); /* pv = yi */ if (q == NULL) { Cudd_RecursiveDerefZdd(dd, term1); Cudd_RecursiveDerefZdd(dd, tmp); return(NULL); } Cudd_Ref(q); Cudd_RecursiveDerefZdd(dd, term1); Cudd_RecursiveDerefZdd(dd, tmp); cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, q); Cudd_Deref(q); return(q); } if (v == top_f) v = f->index; else v = g->index; flag = cuddZddGetCofactors3(dd, f, v, &f1, &f0, &fd); if (flag == 1) return(NULL); Cudd_Ref(f1); Cudd_Ref(f0); Cudd_Ref(fd); flag = cuddZddGetCofactors3(dd, g, v, &g1, &g0, &gd); if (flag == 1) { Cudd_RecursiveDerefZdd(dd, f1); Cudd_RecursiveDerefZdd(dd, f0); Cudd_RecursiveDerefZdd(dd, fd); return(NULL); } Cudd_Ref(g1); Cudd_Ref(g0); Cudd_Ref(gd); q = g; if (g0 != zero) { q = cuddZddWeakDivF(dd, f0, g0); if (q == NULL) { Cudd_RecursiveDerefZdd(dd, f1); Cudd_RecursiveDerefZdd(dd, f0); Cudd_RecursiveDerefZdd(dd, fd); Cudd_RecursiveDerefZdd(dd, g1); Cudd_RecursiveDerefZdd(dd, g0); Cudd_RecursiveDerefZdd(dd, gd); return(NULL); } Cudd_Ref(q); } else Cudd_Ref(q); Cudd_RecursiveDerefZdd(dd, f0); Cudd_RecursiveDerefZdd(dd, g0); if (q == zero) { Cudd_RecursiveDerefZdd(dd, f1); Cudd_RecursiveDerefZdd(dd, g1); Cudd_RecursiveDerefZdd(dd, fd); Cudd_RecursiveDerefZdd(dd, gd); cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, zero); Cudd_Deref(q); return(zero); } if (g1 != zero) { Cudd_RecursiveDerefZdd(dd, q); tmp = cuddZddWeakDivF(dd, f1, g1); if (tmp == NULL) { Cudd_RecursiveDerefZdd(dd, f1); Cudd_RecursiveDerefZdd(dd, g1); Cudd_RecursiveDerefZdd(dd, fd); Cudd_RecursiveDerefZdd(dd, gd); return(NULL); } Cudd_Ref(tmp); Cudd_RecursiveDerefZdd(dd, f1); Cudd_RecursiveDerefZdd(dd, g1); if (q == g) q = tmp; else { q = cuddZddIntersect(dd, q, tmp); if (q == NULL) { Cudd_RecursiveDerefZdd(dd, fd); Cudd_RecursiveDerefZdd(dd, gd); return(NULL); } Cudd_Ref(q); Cudd_RecursiveDerefZdd(dd, tmp); } } else { Cudd_RecursiveDerefZdd(dd, f1); Cudd_RecursiveDerefZdd(dd, g1); } if (q == zero) { Cudd_RecursiveDerefZdd(dd, fd); Cudd_RecursiveDerefZdd(dd, gd); cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, zero); Cudd_Deref(q); return(zero); } if (gd != zero) { Cudd_RecursiveDerefZdd(dd, q); tmp = cuddZddWeakDivF(dd, fd, gd); if (tmp == NULL) { Cudd_RecursiveDerefZdd(dd, fd); Cudd_RecursiveDerefZdd(dd, gd); return(NULL); } Cudd_Ref(tmp); Cudd_RecursiveDerefZdd(dd, fd); Cudd_RecursiveDerefZdd(dd, gd); if (q == g) q = tmp; else { q = cuddZddIntersect(dd, q, tmp); if (q == NULL) { Cudd_RecursiveDerefZdd(dd, tmp); return(NULL); } Cudd_Ref(q); Cudd_RecursiveDerefZdd(dd, tmp); } } else { Cudd_RecursiveDerefZdd(dd, fd); Cudd_RecursiveDerefZdd(dd, gd); } cuddCacheInsert2(dd, cuddZddWeakDivF, f, g, q); Cudd_Deref(q); return(q); } /* end of cuddZddWeakDivF */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_zddIte.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * cuddZddIte( DdManager * dd, DdNode * f, DdNode * g, DdNode * h) { DdNode *tautology, *empty; DdNode *r,*Gv,*Gvn,*Hv,*Hvn,*t,*e; unsigned int topf,topg,toph,v,top; int index; statLine(dd); /* Trivial cases. */ /* One variable cases. */ if (f == (empty = DD_ZERO(dd))) { /* ITE(0,G,H) = H */ return(h); } topf = cuddIZ(dd,f->index); topg = cuddIZ(dd,g->index); toph = cuddIZ(dd,h->index); v = ddMin(topg,toph); top = ddMin(topf,v); tautology = (top == CUDD_MAXINDEX) ? DD_ONE(dd) : dd->univ[top]; if (f == tautology) { /* ITE(1,G,H) = G */ return(g); } /* From now on, f is known to not be a constant. */ zddVarToConst(f,&g,&h,tautology,empty); /* Check remaining one variable cases. */ if (g == h) { /* ITE(F,G,G) = G */ return(g); } if (g == tautology) { /* ITE(F,1,0) = F */ if (h == empty) return(f); } /* Check cache. */ r = cuddCacheLookupZdd(dd,DD_ZDD_ITE_TAG,f,g,h); if (r != NULL) { return(r); } /* Recompute these because they may have changed in zddVarToConst. */ topg = cuddIZ(dd,g->index); toph = cuddIZ(dd,h->index); v = ddMin(topg,toph); if (topf < v) { r = cuddZddIte(dd,cuddE(f),g,h); if (r == NULL) return(NULL); } else if (topf > v) { if (topg > v) { Gvn = g; index = h->index; } else { Gvn = cuddE(g); index = g->index; } if (toph > v) { Hv = empty; Hvn = h; } else { Hv = cuddT(h); Hvn = cuddE(h); } e = cuddZddIte(dd,f,Gvn,Hvn); if (e == NULL) return(NULL); cuddRef(e); r = cuddZddGetNode(dd,index,Hv,e); if (r == NULL) { Cudd_RecursiveDerefZdd(dd,e); return(NULL); } cuddDeref(e); } else { index = f->index; if (topg > v) { Gv = empty; Gvn = g; } else { Gv = cuddT(g); Gvn = cuddE(g); } if (toph > v) { Hv = empty; Hvn = h; } else { Hv = cuddT(h); Hvn = cuddE(h); } e = cuddZddIte(dd,cuddE(f),Gvn,Hvn); if (e == NULL) return(NULL); cuddRef(e); t = cuddZddIte(dd,cuddT(f),Gv,Hv); if (t == NULL) { Cudd_RecursiveDerefZdd(dd,e); return(NULL); } cuddRef(t); r = cuddZddGetNode(dd,index,t,e); if (r == NULL) { Cudd_RecursiveDerefZdd(dd,e); Cudd_RecursiveDerefZdd(dd,t); return(NULL); } cuddDeref(t); cuddDeref(e); } cuddCacheInsert(dd,DD_ZDD_ITE_TAG,f,g,h,r); return(r); } /* end of cuddZddIte */
/**Function******************************************************************** Synopsis [Implementation of the linear sifting algorithm for ZDDs.] Description [Implementation of the linear sifting algorithm for ZDDs. Assumes that no dead nodes are present. <ol> <li> Order all the variables according to the number of entries in each unique table. <li> Sift the variable up and down and applies the XOR transformation, remembering each time the total size of the DD heap. <li> Select the best permutation. <li> Repeat 3 and 4 for all variables. </ol> Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ int cuddZddLinearSifting( DdManager * table, int lower, int upper) { int i; int *var; int size; int x; int result; #ifdef DD_STATS int previousSize; #endif size = table->sizeZ; empty = table->zero; /* Find order in which to sift variables. */ var = NULL; zdd_entry = ALLOC(int, size); if (zdd_entry == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto cuddZddSiftingOutOfMem; } var = ALLOC(int, size); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto cuddZddSiftingOutOfMem; } for (i = 0; i < size; i++) { x = table->permZ[i]; zdd_entry[i] = table->subtableZ[x].keys; var[i] = i; } qsort((void *)var, size, sizeof(int), (DD_QSFP)cuddZddUniqueCompare); /* Now sift. */ for (i = 0; i < ddMin(table->siftMaxVar, size); i++) { if (table->zddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDynZ = 0; /* prevent further reordering */ break; } x = table->permZ[var[i]]; if (x < lower || x > upper) continue; #ifdef DD_STATS previousSize = table->keysZ; #endif result = cuddZddLinearAux(table, x, lower, upper); if (!result) goto cuddZddSiftingOutOfMem; #ifdef DD_STATS if (table->keysZ < (unsigned) previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > (unsigned) previousSize) { (void) fprintf(table->out,"+"); /* should never happen */ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ , var[i]); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } FREE(var); FREE(zdd_entry); return(1); cuddZddSiftingOutOfMem: if (zdd_entry != NULL) FREE(zdd_entry); if (var != NULL) FREE(var); return(0); } /* end of cuddZddLinearSifting */
/** @brief Implementation of Rudell's sifting algorithm. @details Assumes that no dead nodes are present. <ol> <li> Order all the variables according to the number of entries in each unique table. <li> Sift the variable up and down, remembering each time the total size of the %DD heap. <li> Select the best permutation. <li> Repeat 3 and 4 for all variables. </ol> @return 1 if successful; 0 otherwise. @sideeffect None */ int cuddZddSifting( DdManager * table, int lower, int upper) { int i; IndexKey *var; int size; int x; int result; #ifdef DD_STATS int previousSize; #endif size = table->sizeZ; /* Find order in which to sift variables. */ var = ALLOC(IndexKey, size); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto cuddZddSiftingOutOfMem; } for (i = 0; i < size; i++) { x = table->permZ[i]; var[i].index = i; var[i].keys = table->subtableZ[x].keys; } util_qsort(var, size, sizeof(IndexKey), cuddZddUniqueCompare); /* Now sift. */ for (i = 0; i < ddMin(table->siftMaxVar, size); i++) { if (table->zddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDynZ = 0; /* prevent further reordering */ break; } if (table->terminationCallback != NULL && table->terminationCallback(table->tcbArg)) { table->autoDynZ = 0; /* prevent further reordering */ break; } x = table->permZ[var[i].index]; if (x < lower || x > upper) continue; #ifdef DD_STATS previousSize = table->keysZ; #endif result = cuddZddSiftingAux(table, x, lower, upper); if (!result) goto cuddZddSiftingOutOfMem; #ifdef DD_STATS if (table->keysZ < (unsigned) previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > (unsigned) previousSize) { (void) fprintf(table->out,"+"); /* should never happen */ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ , var[i].index); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } FREE(var); return(1); cuddZddSiftingOutOfMem: if (var != NULL) FREE(var); return(0); } /* end of cuddZddSifting */
/**Function******************************************************************** Synopsis [Symmetric sifting algorithm.] Description [Symmetric sifting algorithm. Assumes that no dead nodes are present. <ol> <li> Order all the variables according to the number of entries in each unique subtable. <li> Sift the variable up and down, remembering each time the total size of the DD heap and grouping variables that are symmetric. <li> Select the best permutation. <li> Repeat 3 and 4 for all variables. </ol> Returns 1 plus the number of symmetric variables if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddSymmSiftingConv] ******************************************************************************/ int cuddSymmSifting( DdManager * table, int lower, int upper) { int i; int *var; int size; int x; int result; int symvars; int symgroups; #ifdef DD_STATS int previousSize; #endif size = table->size; /* Find order in which to sift variables. */ var = NULL; entry = ALLOC(int,size); if (entry == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto ddSymmSiftingOutOfMem; } var = ALLOC(int,size); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto ddSymmSiftingOutOfMem; } for (i = 0; i < size; i++) { x = table->perm[i]; entry[i] = table->subtables[x].keys; var[i] = i; } qsort((void *)var,size,sizeof(int),(DD_QSFP)ddSymmUniqueCompare); /* Initialize the symmetry of each subtable to itself. */ for (i = lower; i <= upper; i++) { table->subtables[i].next = i; } for (i = 0; i < ddMin(table->siftMaxVar,size); i++) { if (ddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDyn = 0; /* prevent further reordering */ break; } x = table->perm[var[i]]; #ifdef DD_STATS previousSize = table->keys - table->isolated; #endif if (x < lower || x > upper) continue; if (table->subtables[x].next == (unsigned) x) { result = ddSymmSiftingAux(table,x,lower,upper); if (!result) goto ddSymmSiftingOutOfMem; #ifdef DD_STATS if (table->keys < (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"-"); } else if (table->keys > (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"+"); /* should never happen */ } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } } FREE(var); FREE(entry); ddSymmSummary(table, lower, upper, &symvars, &symgroups); #ifdef DD_STATS (void) fprintf(table->out, "\n#:S_SIFTING %8d: symmetric variables\n", symvars); (void) fprintf(table->out, "#:G_SIFTING %8d: symmetric groups", symgroups); #endif return(1+symvars); ddSymmSiftingOutOfMem: if (entry != NULL) FREE(entry); if (var != NULL) FREE(var); return(0); } /* end of cuddSymmSifting */
/**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 */
/**Function******************************************************************** Synopsis [Sifts from treenode->low to treenode->high.] Description [Sifts from treenode->low to treenode->high. If croupcheck == CUDD_GROUP_CHECK7, it checks for group creation at the end of the initial sifting. If a group is created, it is then sifted again. After sifting one variable, the group that contains it is dissolved. Returns 1 in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int zddGroupSifting( DdManager * table, int lower, int upper) { int *var; int i,j,x,xInit; int nvars; int classes; int result; int *sifted; #ifdef DD_STATS unsigned previousSize; #endif int xindex; nvars = table->sizeZ; /* Order variables to sift. */ entry = NULL; sifted = NULL; var = ALLOC(int,nvars); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto zddGroupSiftingOutOfMem; } entry = ALLOC(int,nvars); if (entry == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto zddGroupSiftingOutOfMem; } sifted = ALLOC(int,nvars); if (sifted == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto zddGroupSiftingOutOfMem; } /* Here we consider only one representative for each group. */ for (i = 0, classes = 0; i < nvars; i++) { sifted[i] = 0; x = table->permZ[i]; if ((unsigned) x >= table->subtableZ[x].next) { entry[i] = table->subtableZ[x].keys; var[classes] = i; classes++; } } qsort((void *)var,classes,sizeof(int),(int (*)(const void *, const void *))zddUniqueCompareGroup); /* Now sift. */ for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) { if (zddTotalNumberSwapping >= table->siftMaxSwap) break; xindex = var[i]; if (sifted[xindex] == 1) /* variable already sifted as part of group */ continue; x = table->permZ[xindex]; /* find current level of this variable */ if (x < lower || x > upper) continue; #ifdef DD_STATS previousSize = table->keysZ; #endif #ifdef DD_DEBUG /* x is bottom of group */ assert((unsigned) x >= table->subtableZ[x].next); #endif result = zddGroupSiftingAux(table,x,lower,upper); if (!result) goto zddGroupSiftingOutOfMem; #ifdef DD_STATS if (table->keysZ < previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > previousSize) { (void) fprintf(table->out,"+"); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif /* Mark variables in the group just sifted. */ x = table->permZ[xindex]; if ((unsigned) x != table->subtableZ[x].next) { xInit = x; do { j = table->invpermZ[x]; sifted[j] = 1; x = table->subtableZ[x].next; } while (x != xInit); } #ifdef DD_DEBUG if (pr > 0) (void) fprintf(table->out,"zddGroupSifting:"); #endif } /* for */ FREE(sifted); FREE(var); FREE(entry); return(1); zddGroupSiftingOutOfMem: if (entry != NULL) FREE(entry); if (var != NULL) FREE(var); if (sifted != NULL) FREE(sifted); return(0); } /* end of zddGroupSifting */
/**Function******************************************************************** Synopsis [Symmetric sifting algorithm for ZDDs.] Description [Symmetric sifting algorithm. Assumes that no dead nodes are present. <ol> <li> Order all the variables according to the number of entries in each unique subtable. <li> Sift the variable up and down, remembering each time the total size of the ZDD heap and grouping variables that are symmetric. <li> Select the best permutation. <li> Repeat 3 and 4 for all variables. </ol> Returns 1 plus the number of symmetric variables if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddZddSymmSiftingConv] ******************************************************************************/ int cuddZddSymmSifting( DdManager * table, int lower, int upper) { int i; int *var; int nvars; int x; int result; int symvars; int symgroups; int iteration; #ifdef DD_STATS int previousSize; #endif nvars = table->sizeZ; /* Find order in which to sift variables. */ var = NULL; zdd_entry = ALLOC(int, nvars); if (zdd_entry == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto cuddZddSymmSiftingOutOfMem; } var = ALLOC(int, nvars); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto cuddZddSymmSiftingOutOfMem; } for (i = 0; i < nvars; i++) { x = table->permZ[i]; zdd_entry[i] = table->subtableZ[x].keys; var[i] = i; } qsort((void *)var, nvars, sizeof(int), (DD_QSFP)cuddZddUniqueCompare); /* Initialize the symmetry of each subtable to itself. */ for (i = lower; i <= upper; i++) table->subtableZ[i].next = i; iteration = ddMin(table->siftMaxVar, nvars); for (i = 0; i < iteration; i++) { if (zddTotalNumberSwapping >= table->siftMaxSwap) break; x = table->permZ[var[i]]; #ifdef DD_STATS previousSize = table->keysZ; #endif if (x < lower || x > upper) continue; if (table->subtableZ[x].next == (unsigned) x) { result = cuddZddSymmSiftingAux(table, x, lower, upper); if (!result) goto cuddZddSymmSiftingOutOfMem; #ifdef DD_STATS if (table->keysZ < (unsigned) previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > (unsigned) previousSize) { (void) fprintf(table->out,"+"); #ifdef DD_VERBOSE (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]); #endif } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } } FREE(var); FREE(zdd_entry); cuddZddSymmSummary(table, lower, upper, &symvars, &symgroups); #ifdef DD_STATS (void) fprintf(table->out,"\n#:S_SIFTING %8d: symmetric variables\n",symvars); (void) fprintf(table->out,"#:G_SIFTING %8d: symmetric groups\n",symgroups); #endif return(1+symvars); cuddZddSymmSiftingOutOfMem: if (zdd_entry != NULL) FREE(zdd_entry); if (var != NULL) FREE(var); return(0); } /* end of cuddZddSymmSifting */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_addNonSimCompose.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ static DdNode * cuddAddNonSimComposeRecur( DdManager * dd, DdNode * f, DdNode ** vector, DdNode * key, DdNode * cube, int lastsub) { DdNode *f1, *f0, *key1, *key0, *cube1, *var; DdNode *T,*E; DdNode *r; unsigned int top, topf, topk, topc; unsigned int index; int i; DdNode **vect1; DdNode **vect0; statLine(dd); /* If we are past the deepest substitution, return f. */ if (cube == DD_ONE(dd) || cuddIsConstant(f)) { return(f); } /* If problem already solved, look up answer and return. */ r = cuddCacheLookup(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube); if (r != NULL) { return(r); } /* Find top variable. we just need to look at f, key, and cube, ** because all the varibles in the gi are in key. */ topf = cuddI(dd,f->index); topk = cuddI(dd,key->index); top = ddMin(topf,topk); topc = cuddI(dd,cube->index); top = ddMin(top,topc); index = dd->invperm[top]; /* Compute the cofactors. */ if (topf == top) { f1 = cuddT(f); f0 = cuddE(f); } else { f1 = f0 = f; } if (topc == top) { cube1 = cuddT(cube); /* We want to eliminate vector[index] from key. Otherwise ** cache performance is severely affected. Hence we ** existentially quantify the variable with index "index" from key. */ var = Cudd_addIthVar(dd, (int) index); if (var == NULL) { return(NULL); } cuddRef(var); key1 = cuddAddExistAbstractRecur(dd, key, var); if (key1 == NULL) { Cudd_RecursiveDeref(dd,var); return(NULL); } cuddRef(key1); Cudd_RecursiveDeref(dd,var); key0 = key1; } else { cube1 = cube; if (topk == top) { key1 = cuddT(key); key0 = cuddE(key); } else { key1 = key0 = key; } cuddRef(key1); } /* Allocate two new vectors for the cofactors of vector. */ vect1 = ALLOC(DdNode *,lastsub); if (vect1 == NULL) { dd->errorCode = CUDD_MEMORY_OUT; Cudd_RecursiveDeref(dd,key1); return(NULL); } vect0 = ALLOC(DdNode *,lastsub); if (vect0 == NULL) { dd->errorCode = CUDD_MEMORY_OUT; Cudd_RecursiveDeref(dd,key1); FREE(vect1); return(NULL); } /* Cofactor the gi. Eliminate vect1[index] and vect0[index], because ** we do not need them. */ for (i = 0; i < lastsub; i++) { DdNode *gi = vector[i]; if (gi == NULL) { vect1[i] = vect0[i] = NULL; } else if (gi->index == index) { vect1[i] = cuddT(gi); vect0[i] = cuddE(gi); } else { vect1[i] = vect0[i] = gi; } } vect1[index] = vect0[index] = NULL; /* Recur on children. */ T = cuddAddNonSimComposeRecur(dd,f1,vect1,key1,cube1,lastsub); FREE(vect1); if (T == NULL) { Cudd_RecursiveDeref(dd,key1); FREE(vect0); return(NULL); } cuddRef(T); E = cuddAddNonSimComposeRecur(dd,f0,vect0,key0,cube1,lastsub); FREE(vect0); if (E == NULL) { Cudd_RecursiveDeref(dd,key1); Cudd_RecursiveDeref(dd,T); return(NULL); } cuddRef(E); Cudd_RecursiveDeref(dd,key1); /* Retrieve the 0-1 ADD for the current top variable from vector, ** and call cuddAddIteRecur with the T and E we just created. */ r = cuddAddIteRecur(dd,vector[index],T,E); if (r == NULL) { Cudd_RecursiveDeref(dd,T); Cudd_RecursiveDeref(dd,E); return(NULL); } cuddRef(r); Cudd_RecursiveDeref(dd,T); Cudd_RecursiveDeref(dd,E); cuddDeref(r); /* Store answer to trim recursion. */ cuddCacheInsert(dd,DD_ADD_NON_SIM_COMPOSE_TAG,f,key,cube,r); return(r); } /* end of cuddAddNonSimComposeRecur */
/**Function******************************************************************** Synopsis [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 [Implements the recursive step of Cudd_addIte(f,g,h).] Description [Implements the recursive step of Cudd_addIte(f,g,h). Returns a pointer to the resulting ADD if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_addIte] ******************************************************************************/ DdNode * cuddAddIteRecur( DdManager * dd, DdNode * f, DdNode * g, DdNode * h) { DdNode *one,*zero; DdNode *r,*Fv,*Fnv,*Gv,*Gnv,*Hv,*Hnv,*t,*e; unsigned int topf,topg,toph,v; int index; statLine(dd); /* Trivial cases. */ /* One variable cases. */ if (f == (one = DD_ONE(dd))) { /* ITE(1,G,H) = G */ return(g); } if (f == (zero = DD_ZERO(dd))) { /* ITE(0,G,H) = H */ return(h); } /* From now on, f is known to not be a constant. */ addVarToConst(f,&g,&h,one,zero); /* Check remaining one variable cases. */ if (g == h) { /* ITE(F,G,G) = G */ return(g); } if (g == one) { /* ITE(F,1,0) = F */ if (h == zero) return(f); } topf = cuddI(dd,f->index); topg = cuddI(dd,g->index); toph = cuddI(dd,h->index); v = ddMin(topg,toph); /* A shortcut: ITE(F,G,H) = (x,G,H) if F=(x,1,0), x < top(G,H). */ if (topf < v && cuddT(f) == one && cuddE(f) == zero) { r = cuddUniqueInter(dd,(int)f->index,g,h); return(r); } if (topf < v && cuddT(f) == zero && cuddE(f) == one) { r = cuddUniqueInter(dd,(int)f->index,h,g); return(r); } /* Check cache. */ r = cuddCacheLookup(dd,DD_ADD_ITE_TAG,f,g,h); if (r != NULL) { return(r); } /* Compute cofactors. */ if (topf <= v) { v = ddMin(topf,v); /* v = top_var(F,G,H) */ index = f->index; Fv = cuddT(f); Fnv = cuddE(f); } else { Fv = Fnv = f; } if (topg == v) { index = g->index; Gv = cuddT(g); Gnv = cuddE(g); } else { Gv = Gnv = g; } if (toph == v) { index = h->index; Hv = cuddT(h); Hnv = cuddE(h); } else { Hv = Hnv = h; } /* Recursive step. */ t = cuddAddIteRecur(dd,Fv,Gv,Hv); if (t == NULL) return(NULL); cuddRef(t); e = cuddAddIteRecur(dd,Fnv,Gnv,Hnv); if (e == NULL) { Cudd_RecursiveDeref(dd,t); return(NULL); } cuddRef(e); r = (t == e) ? t : cuddUniqueInter(dd,index,t,e); if (r == NULL) { Cudd_RecursiveDeref(dd,t); Cudd_RecursiveDeref(dd,e); return(NULL); } cuddDeref(t); cuddDeref(e); cuddCacheInsert(dd,DD_ADD_ITE_TAG,f,g,h,r); return(r); } /* end of cuddAddIteRecur */
/**Function******************************************************************** Synopsis [Implements ITEconstant for ADDs.] Description [Implements ITEconstant for ADDs. f must be a 0-1 ADD. Returns a pointer to the resulting ADD (which may or may not be constant) or DD_NON_CONSTANT. No new nodes are created. This function can be used, for instance, to check that g has a constant value (specified by h) whenever f is 1. If the constant value is unknown, then one should use Cudd_addEvalConst.] SideEffects [None] SeeAlso [Cudd_addIte Cudd_addEvalConst Cudd_bddIteConstant] ******************************************************************************/ DdNode * Cudd_addIteConstant( DdManager * dd, DdNode * f, DdNode * g, DdNode * h) { DdNode *one,*zero; DdNode *Fv,*Fnv,*Gv,*Gnv,*Hv,*Hnv,*r,*t,*e; unsigned int topf,topg,toph,v; statLine(dd); /* Trivial cases. */ if (f == (one = DD_ONE(dd))) { /* ITE(1,G,H) = G */ return(g); } if (f == (zero = DD_ZERO(dd))) { /* ITE(0,G,H) = H */ return(h); } /* From now on, f is known not to be a constant. */ addVarToConst(f,&g,&h,one,zero); /* Check remaining one variable cases. */ if (g == h) { /* ITE(F,G,G) = G */ return(g); } if (cuddIsConstant(g) && cuddIsConstant(h)) { return(DD_NON_CONSTANT); } topf = cuddI(dd,f->index); topg = cuddI(dd,g->index); toph = cuddI(dd,h->index); v = ddMin(topg,toph); /* ITE(F,G,H) = (x,G,H) (non constant) if F = (x,1,0), x < top(G,H). */ if (topf < v && cuddIsConstant(cuddT(f)) && cuddIsConstant(cuddE(f))) { return(DD_NON_CONSTANT); } /* Check cache. */ r = cuddConstantLookup(dd,DD_ADD_ITE_CONSTANT_TAG,f,g,h); if (r != NULL) { return(r); } /* Compute cofactors. */ if (topf <= v) { v = ddMin(topf,v); /* v = top_var(F,G,H) */ Fv = cuddT(f); Fnv = cuddE(f); } else { Fv = Fnv = f; } if (topg == v) { Gv = cuddT(g); Gnv = cuddE(g); } else { Gv = Gnv = g; } if (toph == v) { Hv = cuddT(h); Hnv = cuddE(h); } else { Hv = Hnv = h; } /* Recursive step. */ t = Cudd_addIteConstant(dd,Fv,Gv,Hv); if (t == DD_NON_CONSTANT || !cuddIsConstant(t)) { cuddCacheInsert(dd, DD_ADD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT); return(DD_NON_CONSTANT); } e = Cudd_addIteConstant(dd,Fnv,Gnv,Hnv); if (e == DD_NON_CONSTANT || !cuddIsConstant(e) || t != e) { cuddCacheInsert(dd, DD_ADD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT); return(DD_NON_CONSTANT); } cuddCacheInsert(dd, DD_ADD_ITE_CONSTANT_TAG, f, g, h, t); return(t); } /* end of Cudd_addIteConstant */
/** @brief Sifts from treenode->low to treenode->high. @details If croupcheck == CUDD_GROUP_CHECK7, it checks for group creation at the end of the initial sifting. If a group is created, it is then sifted again. After sifting one variable, the group that contains it is dissolved. @return 1 in case of success; 0 otherwise. @sideeffect None */ static int zddGroupSifting( DdManager * table, int lower, int upper) { IndexKey *var; int i,j,x,xInit; int nvars; int classes; int result; int *sifted; #ifdef DD_STATS unsigned previousSize; #endif int xindex; nvars = table->sizeZ; /* Order variables to sift. */ sifted = NULL; var = ALLOC(IndexKey,nvars); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto zddGroupSiftingOutOfMem; } sifted = ALLOC(int,nvars); if (sifted == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto zddGroupSiftingOutOfMem; } /* Here we consider only one representative for each group. */ for (i = 0, classes = 0; i < nvars; i++) { sifted[i] = 0; x = table->permZ[i]; if ((unsigned) x >= table->subtableZ[x].next) { var[classes].index = i; var[classes].keys = table->subtableZ[x].keys; classes++; } } util_qsort(var,classes,sizeof(IndexKey),zddUniqueCompareGroup); /* Now sift. */ for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) { if (table->zddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDynZ = 0; /* prevent further reordering */ break; } if (table->terminationCallback != NULL && table->terminationCallback(table->tcbArg)) { table->autoDynZ = 0; /* prevent further reordering */ break; } xindex = var[i].index; if (sifted[xindex] == 1) /* variable already sifted as part of group */ continue; x = table->permZ[xindex]; /* find current level of this variable */ if (x < lower || x > upper) continue; #ifdef DD_STATS previousSize = table->keysZ; #endif #ifdef DD_DEBUG /* x is bottom of group */ assert((unsigned) x >= table->subtableZ[x].next); #endif result = zddGroupSiftingAux(table,x,lower,upper); if (!result) goto zddGroupSiftingOutOfMem; #ifdef DD_STATS if (table->keysZ < previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > previousSize) { (void) fprintf(table->out,"+"); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif /* Mark variables in the group just sifted. */ x = table->permZ[xindex]; if ((unsigned) x != table->subtableZ[x].next) { xInit = x; do { j = table->invpermZ[x]; sifted[j] = 1; x = table->subtableZ[x].next; } while (x != xInit); } #ifdef DD_DEBUG if (table->enableExtraDebug > 0) (void) fprintf(table->out,"zddGroupSifting:"); #endif } /* for */ FREE(sifted); FREE(var); return(1); zddGroupSiftingOutOfMem: if (var != NULL) FREE(var); if (sifted != NULL) FREE(sifted); return(0); } /* end of zddGroupSifting */
/**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 (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 [Shrinks almost empty ZDD subtables at the end of reordering to guarantee that they have a reasonable load factor.] Description [Shrinks almost empty subtables at the end of reordering to guarantee that they have a reasonable load factor. However, if there many nodes are being reclaimed, then no resizing occurs. Returns 1 in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int zddReorderPostprocess( DdManager * table) { int i, j, posn; DdNodePtr *nodelist, *oldnodelist; DdNode *node, *next; unsigned int slots, oldslots; extern DD_OOMFP MMoutOfMemory; DD_OOMFP saveHandler; #ifdef DD_VERBOSE (void) fflush(table->out); #endif /* If we have very many reclaimed nodes, we do not want to shrink ** the subtables, because this will lead to more garbage ** collections. More garbage collections mean shorter mean life for ** nodes with zero reference count; hence lower probability of finding ** a result in the cache. */ if (table->reclaimed > table->allocated * 0.5) return(1); /* Resize subtables. */ for (i = 0; i < table->sizeZ; i++) { int shift; oldslots = table->subtableZ[i].slots; if (oldslots < table->subtableZ[i].keys * DD_MAX_SUBTABLE_SPARSITY || oldslots <= table->initSlots) continue; oldnodelist = table->subtableZ[i].nodelist; slots = oldslots >> 1; saveHandler = MMoutOfMemory; MMoutOfMemory = Cudd_OutOfMem; nodelist = ALLOC(DdNodePtr, slots); MMoutOfMemory = saveHandler; if (nodelist == NULL) { return(1); } table->subtableZ[i].nodelist = nodelist; table->subtableZ[i].slots = slots; table->subtableZ[i].shift++; table->subtableZ[i].maxKeys = slots * DD_MAX_SUBTABLE_DENSITY; #ifdef DD_VERBOSE (void) fprintf(table->err, "shrunk layer %d (%d keys) from %d to %d slots\n", i, table->subtableZ[i].keys, oldslots, slots); #endif for (j = 0; (unsigned) j < slots; j++) { nodelist[j] = NULL; } shift = table->subtableZ[i].shift; for (j = 0; (unsigned) j < oldslots; j++) { node = oldnodelist[j]; while (node != NULL) { next = node->next; posn = ddHash(cuddT(node), cuddE(node), shift); node->next = nodelist[posn]; nodelist[posn] = node; node = next; } } FREE(oldnodelist); table->memused += (slots - oldslots) * sizeof(DdNode *); table->slots += slots - oldslots; table->minDead = (unsigned) (table->gcFrac * (double) table->slots); table->cacheSlack = (int) ddMin(table->maxCacheHard, DD_MAX_CACHE_TO_SLOTS_RATIO*table->slots) - 2 * (int) table->cacheSlots; } /* We don't look at the constant subtable, because it is not ** affected by reordering. */ return(1); } /* end of zddReorderPostprocess */
/**Function******************************************************************** Synopsis [Approximates the AND of two BDDs and simultaneously abstracts the variables in cube.] Description [Approximates 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_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; unsigned int topf, topg, topcube, top, 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); } } /* 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 [Performs the recursive step of Cudd_addMatrixMultiply.] Description [Performs the recursive step of Cudd_addMatrixMultiply. Returns a pointer to the result if successful; NULL otherwise.] SideEffects [None] ******************************************************************************/ static DdNode * addMMRecur( DdManager * dd, DdNode * A, DdNode * B, int topP, int * vars) { DdNode *zero, *At, /* positive cofactor of first operand */ *Ae, /* negative cofactor of first operand */ *Bt, /* positive cofactor of second operand */ *Be, /* negative cofactor of second operand */ *t, /* positive cofactor of result */ *e, /* negative cofactor of result */ *scaled, /* scaled result */ *add_scale, /* ADD representing the scaling factor */ *res; int i; /* loop index */ double scale; /* scaling factor */ int index; /* index of the top variable */ CUDD_VALUE_TYPE value; unsigned int topA, topB, topV; DD_CTFP cacheOp; statLine(dd); zero = DD_ZERO(dd); if (A == zero || B == zero) { return(zero); } if (cuddIsConstant(A) && cuddIsConstant(B)) { /* Compute the scaling factor. It is 2^k, where k is the ** number of summation variables below the current variable. ** Indeed, these constants represent blocks of 2^k identical ** constant values in both A and B. */ value = cuddV(A) * cuddV(B); for (i = 0; i < dd->size; i++) { if (vars[i]) { if (dd->perm[i] > topP) { value *= (CUDD_VALUE_TYPE) 2; } } } res = cuddUniqueConst(dd, value); return(res); } /* Standardize to increase cache efficiency. Clearly, A*B != B*A ** in matrix multiplication. However, which matrix is which is ** determined by the variables appearing in the ADDs and not by ** which one is passed as first argument. */ if (A > B) { DdNode *tmp = A; A = B; B = tmp; } topA = cuddI(dd,A->index); topB = cuddI(dd,B->index); topV = ddMin(topA,topB); cacheOp = (DD_CTFP) addMMRecur; res = cuddCacheLookup2(dd,cacheOp,A,B); if (res != NULL) { /* If the result is 0, there is no need to normalize. ** Otherwise we count the number of z variables between ** the current depth and the top of the ADDs. These are ** the missing variables that determine the size of the ** constant blocks. */ if (res == zero) return(res); scale = 1.0; for (i = 0; i < dd->size; i++) { if (vars[i]) { if (dd->perm[i] > topP && (unsigned) dd->perm[i] < topV) { scale *= 2; } } } if (scale > 1.0) { cuddRef(res); add_scale = cuddUniqueConst(dd,(CUDD_VALUE_TYPE)scale); if (add_scale == NULL) { Cudd_RecursiveDeref(dd, res); return(NULL); } cuddRef(add_scale); scaled = cuddAddApplyRecur(dd,Cudd_addTimes,res,add_scale); if (scaled == NULL) { Cudd_RecursiveDeref(dd, add_scale); Cudd_RecursiveDeref(dd, res); return(NULL); } cuddRef(scaled); Cudd_RecursiveDeref(dd, add_scale); Cudd_RecursiveDeref(dd, res); res = scaled; cuddDeref(res); } return(res); } /* compute the cofactors */ if (topV == topA) { At = cuddT(A); Ae = cuddE(A); } else { At = Ae = A; } if (topV == topB) { Bt = cuddT(B); Be = cuddE(B); } else { Bt = Be = B; } t = addMMRecur(dd, At, Bt, (int)topV, vars); if (t == NULL) return(NULL); cuddRef(t); e = addMMRecur(dd, Ae, Be, (int)topV, vars); if (e == NULL) { Cudd_RecursiveDeref(dd, t); return(NULL); } cuddRef(e); index = dd->invperm[topV]; if (vars[index] == 0) { /* We have split on either the rows of A or the columns ** of B. We just need to connect the two subresults, ** which correspond to two submatrices of the result. */ res = (t == e) ? t : cuddUniqueInter(dd,index,t,e); if (res == NULL) { Cudd_RecursiveDeref(dd, t); Cudd_RecursiveDeref(dd, e); return(NULL); } cuddRef(res); cuddDeref(t); cuddDeref(e); } else { /* we have simultaneously split on the columns of A and ** the rows of B. The two subresults must be added. */ res = cuddAddApplyRecur(dd,Cudd_addPlus,t,e); if (res == NULL) { Cudd_RecursiveDeref(dd, t); Cudd_RecursiveDeref(dd, e); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(dd, t); Cudd_RecursiveDeref(dd, e); } cuddCacheInsert2(dd,cacheOp,A,B,res); /* We have computed (and stored in the computed table) a minimal ** result; that is, a result that assumes no summation variables ** between the current depth of the recursion and its top ** variable. We now take into account the z variables by properly ** scaling the result. */ if (res != zero) { scale = 1.0; for (i = 0; i < dd->size; i++) { if (vars[i]) { if (dd->perm[i] > topP && (unsigned) dd->perm[i] < topV) { scale *= 2; } } } if (scale > 1.0) { add_scale = cuddUniqueConst(dd,(CUDD_VALUE_TYPE)scale); if (add_scale == NULL) { Cudd_RecursiveDeref(dd, res); return(NULL); } cuddRef(add_scale); scaled = cuddAddApplyRecur(dd,Cudd_addTimes,res,add_scale); if (scaled == NULL) { Cudd_RecursiveDeref(dd, res); Cudd_RecursiveDeref(dd, add_scale); return(NULL); } cuddRef(scaled); Cudd_RecursiveDeref(dd, add_scale); Cudd_RecursiveDeref(dd, res); res = scaled; } } cuddDeref(res); return(res); } /* end of addMMRecur */
/**Function******************************************************************** Synopsis [Symmetric sifting to convergence algorithm for ZDDs.] Description [Symmetric sifting to convergence algorithm for ZDDs. Assumes that no dead nodes are present. <ol> <li> Order all the variables according to the number of entries in each unique subtable. <li> Sift the variable up and down, remembering each time the total size of the ZDD heap and grouping variables that are symmetric. <li> Select the best permutation. <li> Repeat 3 and 4 for all variables. <li> Repeat 1-4 until no further improvement. </ol> Returns 1 plus the number of symmetric variables if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddZddSymmSifting] ******************************************************************************/ int cuddZddSymmSiftingConv( DdManager * table, int lower, int upper) { int i; int *var; int nvars; int initialSize; int x; int result; int symvars; int symgroups; int classes; int iteration; #ifdef DD_STATS int previousSize; #endif initialSize = table->keysZ; nvars = table->sizeZ; /* Find order in which to sift variables. */ var = NULL; zdd_entry = ALLOC(int, nvars); if (zdd_entry == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto cuddZddSymmSiftingConvOutOfMem; } var = ALLOC(int, nvars); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto cuddZddSymmSiftingConvOutOfMem; } for (i = 0; i < nvars; i++) { x = table->permZ[i]; zdd_entry[i] = table->subtableZ[x].keys; var[i] = i; } qsort((void *)var, nvars, sizeof(int), (DD_QSFP)cuddZddUniqueCompare); /* Initialize the symmetry of each subtable to itself ** for first pass of converging symmetric sifting. */ for (i = lower; i <= upper; i++) table->subtableZ[i].next = i; iteration = ddMin(table->siftMaxVar, table->sizeZ); for (i = 0; i < iteration; i++) { if (zddTotalNumberSwapping >= table->siftMaxSwap) break; x = table->permZ[var[i]]; if (x < lower || x > upper) continue; /* Only sift if not in symmetry group already. */ if (table->subtableZ[x].next == (unsigned) x) { #ifdef DD_STATS previousSize = table->keysZ; #endif result = cuddZddSymmSiftingAux(table, x, lower, upper); if (!result) goto cuddZddSymmSiftingConvOutOfMem; #ifdef DD_STATS if (table->keysZ < (unsigned) previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > (unsigned) previousSize) { (void) fprintf(table->out,"+"); #ifdef DD_VERBOSE (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]); #endif } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } } /* Sifting now until convergence. */ while ((unsigned) initialSize > table->keysZ) { initialSize = table->keysZ; #ifdef DD_STATS (void) fprintf(table->out,"\n"); #endif /* Here we consider only one representative for each symmetry class. */ for (x = lower, classes = 0; x <= upper; x++, classes++) { while ((unsigned) x < table->subtableZ[x].next) x = table->subtableZ[x].next; /* Here x is the largest index in a group. ** Groups consists of adjacent variables. ** Hence, the next increment of x will move it to a new group. */ i = table->invpermZ[x]; zdd_entry[i] = table->subtableZ[x].keys; var[classes] = i; } qsort((void *)var,classes,sizeof(int),(DD_QSFP)cuddZddUniqueCompare); /* Now sift. */ iteration = ddMin(table->siftMaxVar, nvars); for (i = 0; i < iteration; i++) { if (zddTotalNumberSwapping >= table->siftMaxSwap) break; x = table->permZ[var[i]]; if ((unsigned) x >= table->subtableZ[x].next) { #ifdef DD_STATS previousSize = table->keysZ; #endif result = cuddZddSymmSiftingConvAux(table, x, lower, upper); if (!result) goto cuddZddSymmSiftingConvOutOfMem; #ifdef DD_STATS if (table->keysZ < (unsigned) previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > (unsigned) previousSize) { (void) fprintf(table->out,"+"); #ifdef DD_VERBOSE (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ, var[i]); #endif } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } } /* for */ } cuddZddSymmSummary(table, lower, upper, &symvars, &symgroups); #ifdef DD_STATS (void) fprintf(table->out,"\n#:S_SIFTING %8d: symmetric variables\n", symvars); (void) fprintf(table->out,"#:G_SIFTING %8d: symmetric groups\n", symgroups); #endif FREE(var); FREE(zdd_entry); return(1+symvars); cuddZddSymmSiftingConvOutOfMem: if (zdd_entry != NULL) FREE(zdd_entry); if (var != NULL) FREE(var); return(0); } /* end of cuddZddSymmSiftingConv */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_addTriangle.] Description [Performs the recursive step of Cudd_addTriangle. Returns a pointer to the result if successful; NULL otherwise.] SideEffects [None] ******************************************************************************/ static DdNode * addTriangleRecur( DdManager * dd, DdNode * f, DdNode * g, int * vars, DdNode *cube) { DdNode *fv, *fvn, *gv, *gvn, *t, *e, *res; CUDD_VALUE_TYPE value; int top, topf, topg, index; statLine(dd); if (f == DD_PLUS_INFINITY(dd) || g == DD_PLUS_INFINITY(dd)) { return(DD_PLUS_INFINITY(dd)); } if (cuddIsConstant(f) && cuddIsConstant(g)) { value = cuddV(f) + cuddV(g); res = cuddUniqueConst(dd, value); return(res); } if (f < g) { DdNode *tmp = f; f = g; g = tmp; } if (f->ref != 1 || g->ref != 1) { res = cuddCacheLookup(dd, DD_ADD_TRIANGLE_TAG, f, g, cube); if (res != NULL) { return(res); } } topf = cuddI(dd,f->index); topg = cuddI(dd,g->index); top = ddMin(topf,topg); if (top == topf) {fv = cuddT(f); fvn = cuddE(f);} else {fv = fvn = f;} if (top == topg) {gv = cuddT(g); gvn = cuddE(g);} else {gv = gvn = g;} t = addTriangleRecur(dd, fv, gv, vars, cube); if (t == NULL) return(NULL); cuddRef(t); e = addTriangleRecur(dd, fvn, gvn, vars, cube); if (e == NULL) { Cudd_RecursiveDeref(dd, t); return(NULL); } cuddRef(e); index = dd->invperm[top]; if (vars[index] < 0) { res = (t == e) ? t : cuddUniqueInter(dd,index,t,e); if (res == NULL) { Cudd_RecursiveDeref(dd, t); Cudd_RecursiveDeref(dd, e); return(NULL); } cuddDeref(t); cuddDeref(e); } else { res = cuddAddApplyRecur(dd,Cudd_addMinimum,t,e); if (res == NULL) { Cudd_RecursiveDeref(dd, t); Cudd_RecursiveDeref(dd, e); return(NULL); } cuddRef(res); Cudd_RecursiveDeref(dd, t); Cudd_RecursiveDeref(dd, e); cuddDeref(res); } if (f->ref != 1 || g->ref != 1) { cuddCacheInsert(dd, DD_ADD_TRIANGLE_TAG, f, g, cube, res); } return(res); } /* end of addTriangleRecur */
/**Function******************************************************************** Synopsis [Symmetric sifting to convergence algorithm.] Description [Symmetric sifting to convergence algorithm. Assumes that no dead nodes are present. <ol> <li> Order all the variables according to the number of entries in each unique subtable. <li> Sift the variable up and down, remembering each time the total size of the DD heap and grouping variables that are symmetric. <li> Select the best permutation. <li> Repeat 3 and 4 for all variables. <li> Repeat 1-4 until no further improvement. </ol> Returns 1 plus the number of symmetric variables if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddSymmSifting] ******************************************************************************/ int cuddSymmSiftingConv( DdManager * table, int lower, int upper) { int i; int *var; int size; int x; int result; int symvars; int symgroups; int classes; int initialSize; #ifdef DD_STATS int previousSize; #endif initialSize = table->keys - table->isolated; size = table->size; /* Find order in which to sift variables. */ var = NULL; entry = ALLOC(int,size); if (entry == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto ddSymmSiftingConvOutOfMem; } var = ALLOC(int,size); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto ddSymmSiftingConvOutOfMem; } for (i = 0; i < size; i++) { x = table->perm[i]; entry[i] = table->subtables[x].keys; var[i] = i; } qsort((void *)var,size,sizeof(int),(DD_QSFP)ddSymmUniqueCompare); /* Initialize the symmetry of each subtable to itself ** for first pass of converging symmetric sifting. */ for (i = lower; i <= upper; i++) { table->subtables[i].next = i; } for (i = 0; i < ddMin(table->siftMaxVar, table->size); i++) { if (ddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDyn = 0; /* prevent further reordering */ break; } x = table->perm[var[i]]; if (x < lower || x > upper) continue; /* Only sift if not in symmetry group already. */ if (table->subtables[x].next == (unsigned) x) { #ifdef DD_STATS previousSize = table->keys - table->isolated; #endif result = ddSymmSiftingAux(table,x,lower,upper); if (!result) goto ddSymmSiftingConvOutOfMem; #ifdef DD_STATS if (table->keys < (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"-"); } else if (table->keys > (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"+"); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } } /* Sifting now until convergence. */ while ((unsigned) initialSize > table->keys - table->isolated) { initialSize = table->keys - table->isolated; #ifdef DD_STATS (void) fprintf(table->out,"\n"); #endif /* Here we consider only one representative for each symmetry class. */ for (x = lower, classes = 0; x <= upper; x++, classes++) { while ((unsigned) x < table->subtables[x].next) { x = table->subtables[x].next; } /* Here x is the largest index in a group. ** Groups consist of adjacent variables. ** Hence, the next increment of x will move it to a new group. */ i = table->invperm[x]; entry[i] = table->subtables[x].keys; var[classes] = i; } qsort((void *)var,classes,sizeof(int),(DD_QSFP)ddSymmUniqueCompare); /* Now sift. */ for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) { if (ddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDyn = 0; /* prevent further reordering */ break; } x = table->perm[var[i]]; if ((unsigned) x >= table->subtables[x].next) { #ifdef DD_STATS previousSize = table->keys - table->isolated; #endif result = ddSymmSiftingConvAux(table,x,lower,upper); if (!result ) goto ddSymmSiftingConvOutOfMem; #ifdef DD_STATS if (table->keys < (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"-"); } else if (table->keys > (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"+"); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } } /* for */ } ddSymmSummary(table, lower, upper, &symvars, &symgroups); #ifdef DD_STATS (void) fprintf(table->out, "\n#:S_SIFTING %8d: symmetric variables\n", symvars); (void) fprintf(table->out, "#:G_SIFTING %8d: symmetric groups", symgroups); #endif FREE(var); FREE(entry); return(1+symvars); ddSymmSiftingConvOutOfMem: if (entry != NULL) FREE(entry); if (var != NULL) FREE(var); return(0); } /* end of cuddSymmSiftingConv */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_addOuterSum.] Description [Performs the recursive step of Cudd_addOuterSum. Returns a pointer to the result if successful; NULL otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static DdNode * cuddAddOuterSumRecur( DdManager *dd, DdNode *M, DdNode *r, DdNode *c) { DdNode *P, *R, *Mt, *Me, *rt, *re, *ct, *ce, *Rt, *Re; int topM, topc, topr; int v, index; statLine(dd); /* Check special cases. */ if (r == DD_PLUS_INFINITY(dd) || c == DD_PLUS_INFINITY(dd)) return(M); if (cuddIsConstant(c) && cuddIsConstant(r)) { R = cuddUniqueConst(dd,Cudd_V(c)+Cudd_V(r)); cuddRef(R); if (cuddIsConstant(M)) { if (cuddV(R) <= cuddV(M)) { cuddDeref(R); return(R); } else { Cudd_RecursiveDeref(dd,R); return(M); } } else { P = Cudd_addApply(dd,Cudd_addMinimum,R,M); cuddRef(P); Cudd_RecursiveDeref(dd,R); cuddDeref(P); return(P); } } /* Check the cache. */ R = cuddCacheLookup(dd,DD_ADD_OUT_SUM_TAG,M,r,c); if (R != NULL) return(R); topM = cuddI(dd,M->index); topr = cuddI(dd,r->index); topc = cuddI(dd,c->index); v = ddMin(topM,ddMin(topr,topc)); /* Compute cofactors. */ if (topM == v) { Mt = cuddT(M); Me = cuddE(M); } else { Mt = Me = M; } if (topr == v) { rt = cuddT(r); re = cuddE(r); } else { rt = re = r; } if (topc == v) { ct = cuddT(c); ce = cuddE(c); } else { ct = ce = c; } /* Recursively solve. */ Rt = cuddAddOuterSumRecur(dd,Mt,rt,ct); if (Rt == NULL) return(NULL); cuddRef(Rt); Re = cuddAddOuterSumRecur(dd,Me,re,ce); if (Re == NULL) { Cudd_RecursiveDeref(dd, Rt); return(NULL); } cuddRef(Re); index = dd->invperm[v]; R = (Rt == Re) ? Rt : cuddUniqueInter(dd,index,Rt,Re); if (R == NULL) { Cudd_RecursiveDeref(dd, Rt); Cudd_RecursiveDeref(dd, Re); return(NULL); } cuddDeref(Rt); cuddDeref(Re); /* Store the result in the cache. */ cuddCacheInsert(dd,DD_ADD_OUT_SUM_TAG,M,r,c,R); return(R); } /* end of cuddAddOuterSumRecur */
/**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 [Implements the recursive step of Cudd_bddIte.] Description [Implements the recursive step of Cudd_bddIte. Returns a pointer to the resulting BDD. NULL if the intermediate result blows up or if reordering occurs.] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * cuddBddIteRecur( DdManager * dd, DdNode * f, DdNode * g, DdNode * h) { DdNode *_true, *_false, *res; DdNode *r, *Fv, *Fnv, *Gv, *Gnv, *H, *Hv, *Hnv, *t, *e; unsigned int topf, topg, toph, v; int index = 0; int comple; statLine(dd); /* Terminal cases. */ /* _True variable cases. */ if (f == (_true = DD_TRUE(dd))) /* ITE(TRUE,G,H) = G */ return(g); if (f == (_false = Cudd_Not(_true))) /* ITE(FALSE,G,H) = H */ return(h); /* From now on, f is known not to be a constant. */ if (g == _true || f == g) { /* ITE(F,F,H) = ITE(F,TRUE,H) = F + H */ if (h == _false) { /* ITE(F,TRUE,FALSE) = F */ return(f); } else { res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(h)); return(Cudd_NotCond(res,res != NULL)); } } else if (g == _false || f == Cudd_Not(g)) { /* ITE(F,!F,H) = ITE(F,FALSE,H) = !F * H */ if (h == _true) { /* ITE(F,FALSE,TRUE) = !F */ return(Cudd_Not(f)); } else { res = cuddBddAndRecur(dd,Cudd_Not(f),h); return(res); } } if (h == _false || f == h) { /* ITE(F,G,F) = ITE(F,G,FALSE) = F * G */ res = cuddBddAndRecur(dd,f,g); return(res); } else if (h == _true || f == Cudd_Not(h)) { /* ITE(F,G,!F) = ITE(F,G,TRUE) = !F + G */ res = cuddBddAndRecur(dd,f,Cudd_Not(g)); return(Cudd_NotCond(res,res != NULL)); } /* Check remaining _true variable case. */ if (g == h) { /* ITE(F,G,G) = G */ return(g); } else if (g == Cudd_Not(h)) { /* ITE(F,G,!G) = F <-> G */ res = cuddBddXorRecur(dd,f,h); return(res); } /* From here, there are no constants. */ comple = bddVarToCanonicalSimple(dd, &f, &g, &h, &topf, &topg, &toph); /* f & g are now regular pointers */ v = ddMin(topg, toph); /* A shortcut: ITE(F,G,H) = (v,G,H) if F = (v,TRUE,FALSE), v < top(G,H). */ if (topf < v && cuddT(f) == _true && cuddE(f) == _false) { r = cuddUniqueInter(dd, (int) f->index, g, h); return(Cudd_NotCond(r,comple && r != NULL)); } /* Check cache. */ r = cuddCacheLookup(dd, DD_BDD_ITE_TAG, f, g, h); if (r != NULL) { return(Cudd_NotCond(r,comple)); } /* Compute cofactors. */ if (topf <= v) { v = ddMin(topf, v); /* v = top_var(F,G,H) */ index = f->index; Fv = cuddT(f); Fnv = cuddE(f); } else { Fv = Fnv = f; } if (topg == v) { index = g->index; Gv = cuddT(g); Gnv = cuddE(g); } else { Gv = Gnv = g; } if (toph == v) { H = Cudd_Regular(h); index = H->index; Hv = cuddT(H); Hnv = cuddE(H); if (Cudd_IsComplement(h)) { Hv = Cudd_Not(Hv); Hnv = Cudd_Not(Hnv); } } else { Hv = Hnv = h; } /* Recursive step. */ t = cuddBddIteRecur(dd,Fv,Gv,Hv); if (t == NULL) return(NULL); cuddRef(t); e = cuddBddIteRecur(dd,Fnv,Gnv,Hnv); if (e == NULL) { Cudd_IterDerefBdd(dd,t); return(NULL); } cuddRef(e); r = (t == e) ? t : cuddUniqueInter(dd,index,t,e); if (r == NULL) { Cudd_IterDerefBdd(dd,t); Cudd_IterDerefBdd(dd,e); return(NULL); } cuddDeref(t); cuddDeref(e); cuddCacheInsert(dd, DD_BDD_ITE_TAG, f, g, h, r); return(Cudd_NotCond(r,comple)); } /* end of cuddBddIteRecur */
/**Function******************************************************************** Synopsis [Implements ITEconstant(f,g,h).] Description [Implements ITEconstant(f,g,h). Returns a pointer to the resulting BDD (which may or may not be constant) or DD_NON_CONSTANT. No new nodes are created.] SideEffects [None] SeeAlso [Cudd_bddIte Cudd_bddIntersect Cudd_bddLeq Cudd_addIteConstant] ******************************************************************************/ DdNode * Cudd_bddIteConstant( DdManager * dd, DdNode * f, DdNode * g, DdNode * h) { DdNode *r, *Fv, *Fnv, *Gv, *Gnv, *H, *Hv, *Hnv, *t, *e; DdNode *one = DD_ONE(dd); DdNode *zero = Cudd_Not(one); int comple; unsigned int topf, topg, toph, v; statLine(dd); /* Trivial cases. */ if (f == one) /* ITE(1,G,H) => G */ return(g); if (f == zero) /* ITE(0,G,H) => H */ return(h); /* f now not a constant. */ bddVarToConst(f, &g, &h, one); /* possibly convert g or h */ /* to constants */ if (g == h) /* ITE(F,G,G) => G */ return(g); if (Cudd_IsConstant(g) && Cudd_IsConstant(h)) return(DD_NON_CONSTANT); /* ITE(F,1,0) or ITE(F,0,1) */ /* => DD_NON_CONSTANT */ if (g == Cudd_Not(h)) return(DD_NON_CONSTANT); /* ITE(F,G,G') => DD_NON_CONSTANT */ /* if F != G and F != G' */ comple = bddVarToCanonical(dd, &f, &g, &h, &topf, &topg, &toph); /* Cache lookup. */ r = cuddConstantLookup(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h); if (r != NULL) { return(Cudd_NotCond(r,comple && r != DD_NON_CONSTANT)); } v = ddMin(topg, toph); /* ITE(F,G,H) = (v,G,H) (non constant) if F = (v,1,0), v < top(G,H). */ if (topf < v && cuddT(f) == one && cuddE(f) == zero) { return(DD_NON_CONSTANT); } /* Compute cofactors. */ if (topf <= v) { v = ddMin(topf, v); /* v = top_var(F,G,H) */ Fv = cuddT(f); Fnv = cuddE(f); } else { Fv = Fnv = f; } if (topg == v) { Gv = cuddT(g); Gnv = cuddE(g); } else { Gv = Gnv = g; } if (toph == v) { H = Cudd_Regular(h); Hv = cuddT(H); Hnv = cuddE(H); if (Cudd_IsComplement(h)) { Hv = Cudd_Not(Hv); Hnv = Cudd_Not(Hnv); } } else { Hv = Hnv = h; } /* Recursion. */ t = Cudd_bddIteConstant(dd, Fv, Gv, Hv); if (t == DD_NON_CONSTANT || !Cudd_IsConstant(t)) { cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT); return(DD_NON_CONSTANT); } e = Cudd_bddIteConstant(dd, Fnv, Gnv, Hnv); if (e == DD_NON_CONSTANT || !Cudd_IsConstant(e) || t != e) { cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, DD_NON_CONSTANT); return(DD_NON_CONSTANT); } cuddCacheInsert(dd, DD_BDD_ITE_CONSTANT_TAG, f, g, h, t); return(Cudd_NotCond(t,comple)); } /* end of Cudd_bddIteConstant */
/**Function******************************************************************** Synopsis [Implements the recursive step of Cudd_addIteGeneral(f,g,h).] Description [Implements the recursive step of Cudd_addIteGeneral(f,g,h), meaning that g and h are not supposed to be 0-1 ADDs but may have more terminals. Applying arithmetic addition in the terminal case. Returns a pointer to the resulting ADD if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_addIte] ******************************************************************************/ DdNode * extraAddIteRecurGeneral( DdManager * dd, DdNode * bX, DdNode * aF, DdNode * aG ) { DdNode * aRes; statLine( dd ); assert( !Cudd_IsConstant(bX) ); assert( cuddE(bX) == b0 && cuddT(bX) == b1 ); /* the elementary variable */ /* check cache */ if ( aRes = cuddCacheLookup(dd, DD_ADD_ITE_GENERAL_TAG, bX, aF, aG) ) return aRes; else { DdNode * aF0, * aF1, * aG0, * aG1; int LevelF, LevelG, LevelX, LevelTop; LevelF = cuddI(dd,aF->index); LevelG = cuddI(dd,aG->index); LevelX = dd->perm[bX->index]; LevelTop = ddMin(LevelF, LevelG); LevelTop = ddMin(LevelX, LevelTop); if ( LevelF == LevelTop ) { aF0 = cuddE(aF); aF1 = cuddT(aF); } else aF0 = aF1 = aF; if ( LevelG == LevelTop ) { aG0 = cuddE(aG); aG1 = cuddT(aG); } else aG0 = aG1 = aG; if ( LevelX == LevelTop ) { assert( LevelX < LevelF ); assert( LevelX < LevelG ); /* consider the case when Res0 and Res1 are the same node */ aRes = (aF == aG) ? aF : cuddUniqueInter( dd, bX->index, aF, aG ); if (aRes == NULL) return NULL; } else { DdNode * aRes0, * aRes1; /* partial results to be composed by ITE */ aRes0 = extraAddIteRecurGeneral( dd, bX, aF0, aG0 ); if ( aRes0 == NULL ) return NULL; cuddRef( aRes0 ); aRes1 = extraAddIteRecurGeneral( dd, bX, aF1, aG1 ); if ( aRes1 == NULL ) { Cudd_RecursiveDeref(dd, aRes0); return NULL; } cuddRef( aRes1 ); /* only aRes0 and aRes1 are referenced at this point */ /* consider the case when Res0 and Res1 are the same node */ aRes = (aRes1 == aRes0) ? aRes1 : cuddUniqueInter( dd, dd->invperm[LevelTop], aRes1, aRes0 ); if (aRes == NULL) { Cudd_RecursiveDeref(dd, aRes1); Cudd_RecursiveDeref(dd, aRes0); return NULL; } cuddDeref(aRes1); cuddDeref(aRes0); } cuddCacheInsert( dd, DD_ADD_ITE_GENERAL_TAG, bX, aF, aG, aRes ); return aRes; } } /* end of extraAddIteRecurGeneral */