/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_addCompose.] Description [Performs the recursive step of Cudd_addCompose. Returns the composed BDD if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_addCompose] ******************************************************************************/ DdNode * cuddAddComposeRecur( DdManager * dd, DdNode * f, DdNode * g, DdNode * proj) { DdNode *f1, *f0, *g1, *g0, *r, *t, *e; unsigned int v, topf, topg, topindex; statLine(dd); v = dd->perm[proj->index]; topf = cuddI(dd,f->index); /* Terminal case. Subsumes the test for constant f. */ if (topf > v) return(f); /* Check cache. */ r = cuddCacheLookup(dd,DD_ADD_COMPOSE_RECUR_TAG,f,g,proj); if (r != NULL) { return(r); } if (topf == v) { /* Compose. */ f1 = cuddT(f); f0 = cuddE(f); r = cuddAddIteRecur(dd, g, f1, f0); if (r == NULL) return(NULL); } else { /* Compute cofactors of f and g. Remember the index of the top ** variable. */ topg = cuddI(dd,g->index); if (topf > topg) { topindex = g->index; f1 = f0 = f; } else { topindex = f->index; f1 = cuddT(f); f0 = cuddE(f); } if (topg > topf) { g1 = g0 = g; } else { g1 = cuddT(g); g0 = cuddE(g); } /* Recursive step. */ t = cuddAddComposeRecur(dd, f1, g1, proj); if (t == NULL) return(NULL); cuddRef(t); e = cuddAddComposeRecur(dd, f0, g0, proj); if (e == NULL) { Cudd_RecursiveDeref(dd, t); return(NULL); } cuddRef(e); if (t == e) { r = t; } else { r = cuddUniqueInter(dd, (int) topindex, t, e); if (r == NULL) { Cudd_RecursiveDeref(dd, t); Cudd_RecursiveDeref(dd, e); return(NULL); } } cuddDeref(t); cuddDeref(e); } cuddCacheInsert(dd,DD_ADD_COMPOSE_RECUR_TAG,f,g,proj,r); return(r); } /* end of cuddAddComposeRecur */
/**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 [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 [Decreases the reference count of BDD node n.] Description [Enqueues node n for later dereferencing. If the queue is full decreases the reference count of the oldest node N to make room for n. If N dies, recursively decreases the reference counts of its children. It is used to dispose of a BDD that is currently not needed, but may be useful again in the near future. The dereferencing proper is done as in Cudd_IterDerefBdd.] SideEffects [None] SeeAlso [Cudd_RecursiveDeref Cudd_IterDerefBdd] ******************************************************************************/ void Cudd_DelayedDerefBdd( DdManager * table, DdNode * n) { DdNode *N; int ord; DdNodePtr *stack; int SP; unsigned int live = table->keys - table->dead; if (live > table->peakLiveNodes) { table->peakLiveNodes = live; } n = Cudd_Regular(n); #ifdef DD_DEBUG assert(n->ref != 0); #endif #ifdef DD_NO_DEATH_ROW N = n; #else if (cuddIsConstant(n) || n->ref > 1) { #ifdef DD_DEBUG assert(n->ref != 1 && (!cuddIsConstant(n) || n == DD_ONE(table))); #endif cuddSatDec(n->ref); return; } N = table->deathRow[table->nextDead]; if (N != NULL) { #endif #ifdef DD_DEBUG assert(!Cudd_IsComplement(N)); #endif stack = table->stack; SP = 1; do { #ifdef DD_DEBUG assert(N->ref != 0); #endif if (N->ref == 1) { N->ref = 0; table->dead++; #ifdef DD_STATS table->nodesDropped++; #endif ord = table->perm[N->index]; stack[SP++] = Cudd_Regular(cuddE(N)); table->subtables[ord].dead++; N = cuddT(N); } else { cuddSatDec(N->ref); N = stack[--SP]; } } while (SP != 0); #ifndef DD_NO_DEATH_ROW } table->deathRow[table->nextDead] = n; /* Udate insertion point. */ table->nextDead++; table->nextDead &= table->deadMask; #if 0 if (table->nextDead == table->deathRowDepth) { if (table->deathRowDepth < table->looseUpTo / 2) { extern void (*MMoutOfMemory)(long); void (*saveHandler)(long) = MMoutOfMemory; DdNodePtr *newRow; MMoutOfMemory = Cudd_OutOfMem; newRow = REALLOC(DdNodePtr,table->deathRow,2*table->deathRowDepth); MMoutOfMemory = saveHandler; if (newRow == NULL) { table->nextDead = 0; } else { int i; table->memused += table->deathRowDepth; i = table->deathRowDepth; table->deathRowDepth <<= 1; for (; i < table->deathRowDepth; i++) { newRow[i] = NULL; } table->deadMask = table->deathRowDepth - 1; table->deathRow = newRow; } } else { table->nextDead = 0; } } #endif #endif } /* end of Cudd_DelayedDerefBdd */
/**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 [Performs the recursive step of Extra_TransferPermute.] Description [Performs the recursive step of Extra_TransferPermute. Returns a pointer to the result if successful; NULL otherwise.] SideEffects [None] SeeAlso [extraTransferPermuteTime] ******************************************************************************/ static DdNode * extraTransferPermuteRecurTime( DdManager * ddS, DdManager * ddD, DdNode * f, st_table * table, int * Permute, int TimeOut ) { DdNode *ft, *fe, *t, *e, *var, *res; DdNode *one, *zero; int index; int comple = 0; statLine( ddD ); one = DD_ONE( ddD ); comple = Cudd_IsComplement( f ); /* Trivial cases. */ if ( Cudd_IsConstant( f ) ) return ( Cudd_NotCond( one, comple ) ); /* Make canonical to increase the utilization of the cache. */ f = Cudd_NotCond( f, comple ); /* Now f is a regular pointer to a non-constant node. */ /* Check the cache. */ if ( st_lookup( table, ( char * ) f, ( char ** ) &res ) ) return ( Cudd_NotCond( res, comple ) ); if ( TimeOut && TimeOut < clock() ) return NULL; /* Recursive step. */ if ( Permute ) index = Permute[f->index]; else index = f->index; ft = cuddT( f ); fe = cuddE( f ); t = extraTransferPermuteRecurTime( ddS, ddD, ft, table, Permute, TimeOut ); if ( t == NULL ) { return ( NULL ); } cuddRef( t ); e = extraTransferPermuteRecurTime( ddS, ddD, fe, table, Permute, TimeOut ); if ( e == NULL ) { Cudd_RecursiveDeref( ddD, t ); return ( NULL ); } cuddRef( e ); zero = Cudd_Not(ddD->one); var = cuddUniqueInter( ddD, index, one, zero ); if ( var == NULL ) { Cudd_RecursiveDeref( ddD, t ); Cudd_RecursiveDeref( ddD, e ); return ( NULL ); } res = cuddBddIteRecur( ddD, var, t, e ); if ( res == NULL ) { Cudd_RecursiveDeref( ddD, t ); Cudd_RecursiveDeref( ddD, e ); return ( NULL ); } cuddRef( res ); Cudd_RecursiveDeref( ddD, t ); Cudd_RecursiveDeref( ddD, e ); if ( st_add_direct( table, ( char * ) f, ( char * ) res ) == ST_OUT_OF_MEM ) { Cudd_RecursiveDeref( ddD, res ); return ( NULL ); } return ( Cudd_NotCond( res, comple ) ); } /* end of extraTransferPermuteRecurTime */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cuddaux_addConstrain.] Description [Performs the recursive step of Cuddaux_addConstrain. Returns a pointer to the result if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cuddaux_addConstrain] ******************************************************************************/ DdNode * cuddauxAddConstrainRecur( DdManager * dd, DdNode * f, DdNode * c) { DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *res; DdNode *one, *zero; unsigned int topf, topc; int index; one = DD_ONE(dd); zero = Cudd_Not(one); /* Trivial cases. */ if (c == one) return(f); if (c == zero){ fprintf(stderr,"CuddauxAddConstrainRecur: warning: false careset\n"); return(DD_BACKGROUND(dd)); } if (Cudd_IsConstant(f)) return(f); /* Now f and c are non-constant. */ /* Check the cache. */ res = cuddCacheLookup2(dd, Cuddaux_addConstrain, f, c); if (res != NULL) { return(res); } /* Recursive step. */ topf = dd->perm[f->index]; topc = dd->perm[Cudd_Regular(c)->index]; if (topf <= topc) { index = f->index; Fv = cuddT(f); Fnv = cuddE(f); } else { index = Cudd_Regular(c)->index; Fv = Fnv = f; } if (topc <= topf) { Cv = Cudd_T(c); Cnv = Cudd_E(c); if (Cudd_IsComplement(c)) { Cv = Cudd_Not(Cv); Cnv = Cudd_Not(Cnv); } } else { Cv = Cnv = c; } if (!Cudd_IsConstant(Cv)) { t = cuddauxAddConstrainRecur(dd, Fv, Cv); if (t == NULL) return(NULL); } else if (Cv == one) { t = Fv; } else { /* Cv == zero: return Fnv @ Cnv */ if (Cnv == one) { res = Fnv; } else { res = cuddauxAddConstrainRecur(dd, Fnv, Cnv); if (res == NULL) return(NULL); } return(res); } cuddRef(t); if (!Cudd_IsConstant(Cnv)) { e = cuddauxAddConstrainRecur(dd, Fnv, Cnv); if (e == NULL) { Cudd_RecursiveDeref(dd, t); return(NULL); } } else if (Cnv == one) { e = Fnv; } else { /* Cnv == zero: return Fv @ Cv previously computed */ cuddDeref(t); return(t); } cuddRef(e); res = (t == e) ? t : cuddUniqueInter(dd, index, t, e); if (res == NULL) { Cudd_RecursiveDeref(dd, e); Cudd_RecursiveDeref(dd, t); return(NULL); } cuddDeref(t); cuddDeref(e); cuddCacheInsert2(dd, Cuddaux_addConstrain, f, c, res); return(res); } /* end of cuddauxAddConstrainRecur */
/**Function************************************************************* Synopsis [Performs the recursive step of Extra_bddSpaceFromFunctionPos().] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ DdNode * extraBddSpaceFromFunctionNeg( DdManager * dd, DdNode * bF ) { DdNode * bRes, * bFR; statLine( dd ); bFR = Cudd_Regular(bF); if ( cuddIsConstant(bFR) ) return b0; if ( (bRes = cuddCacheLookup1(dd, extraBddSpaceFromFunctionNeg, bF)) ) return bRes; else { DdNode * bF0, * bF1; DdNode * bPos0, * bPos1; DdNode * bNeg0, * bNeg1; DdNode * bRes0, * bRes1; if ( bFR != bF ) // bF is complemented { bF0 = Cudd_Not( cuddE(bFR) ); bF1 = Cudd_Not( cuddT(bFR) ); } else { bF0 = cuddE(bFR); bF1 = cuddT(bFR); } bPos0 = extraBddSpaceFromFunctionNeg( dd, bF0 ); if ( bPos0 == NULL ) return NULL; cuddRef( bPos0 ); bPos1 = extraBddSpaceFromFunctionNeg( dd, bF1 ); if ( bPos1 == NULL ) { Cudd_RecursiveDeref( dd, bPos0 ); return NULL; } cuddRef( bPos1 ); bRes0 = cuddBddAndRecur( dd, bPos0, bPos1 ); if ( bRes0 == NULL ) { Cudd_RecursiveDeref( dd, bPos0 ); Cudd_RecursiveDeref( dd, bPos1 ); return NULL; } cuddRef( bRes0 ); Cudd_RecursiveDeref( dd, bPos0 ); Cudd_RecursiveDeref( dd, bPos1 ); bNeg0 = extraBddSpaceFromFunctionPos( dd, bF0 ); if ( bNeg0 == NULL ) { Cudd_RecursiveDeref( dd, bRes0 ); return NULL; } cuddRef( bNeg0 ); bNeg1 = extraBddSpaceFromFunctionPos( dd, bF1 ); if ( bNeg1 == NULL ) { Cudd_RecursiveDeref( dd, bRes0 ); Cudd_RecursiveDeref( dd, bNeg0 ); return NULL; } cuddRef( bNeg1 ); bRes1 = cuddBddAndRecur( dd, bNeg0, bNeg1 ); if ( bRes1 == NULL ) { Cudd_RecursiveDeref( dd, bRes0 ); Cudd_RecursiveDeref( dd, bNeg0 ); Cudd_RecursiveDeref( dd, bNeg1 ); return NULL; } cuddRef( bRes1 ); Cudd_RecursiveDeref( dd, bNeg0 ); Cudd_RecursiveDeref( dd, bNeg1 ); // consider the case when Res0 and Res1 are the same node if ( bRes0 == bRes1 ) bRes = bRes1; // consider the case when Res1 is complemented else if ( Cudd_IsComplement(bRes1) ) { bRes = cuddUniqueInter( dd, bFR->index, Cudd_Not(bRes1), Cudd_Not(bRes0) ); if ( bRes == NULL ) { Cudd_RecursiveDeref(dd,bRes0); Cudd_RecursiveDeref(dd,bRes1); return NULL; } bRes = Cudd_Not(bRes); } else { bRes = cuddUniqueInter( dd, bFR->index, bRes1, bRes0 ); if ( bRes == NULL ) { Cudd_RecursiveDeref(dd,bRes0); Cudd_RecursiveDeref(dd,bRes1); return NULL; } } cuddDeref( bRes0 ); cuddDeref( bRes1 ); cuddCacheInsert1( dd, extraBddSpaceFromFunctionNeg, bF, bRes ); return bRes; } }
/**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 [] ******************************************************************************/ 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 ratio. */ 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 step of Extra_bddSpaceFromFunctionPos().] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ DdNode * extraBddSpaceFromMatrixNeg( DdManager * dd, DdNode * zA ) { DdNode * bRes; statLine( dd ); if ( zA == z0 ) return b1; if ( zA == z1 ) return b0; if ( (bRes = cuddCacheLookup1(dd, extraBddSpaceFromMatrixNeg, zA)) ) return bRes; else { DdNode * bP0, * bP1; DdNode * bN0, * bN1; DdNode * bRes0, * bRes1; bP0 = extraBddSpaceFromMatrixNeg( dd, cuddE(zA) ); if ( bP0 == NULL ) return NULL; cuddRef( bP0 ); bP1 = extraBddSpaceFromMatrixNeg( dd, cuddT(zA) ); if ( bP1 == NULL ) { Cudd_RecursiveDeref( dd, bP0 ); return NULL; } cuddRef( bP1 ); bRes0 = cuddBddAndRecur( dd, bP0, bP1 ); if ( bRes0 == NULL ) { Cudd_RecursiveDeref( dd, bP0 ); Cudd_RecursiveDeref( dd, bP1 ); return NULL; } cuddRef( bRes0 ); Cudd_RecursiveDeref( dd, bP0 ); Cudd_RecursiveDeref( dd, bP1 ); bN0 = extraBddSpaceFromMatrixNeg( dd, cuddE(zA) ); if ( bN0 == NULL ) { Cudd_RecursiveDeref( dd, bRes0 ); return NULL; } cuddRef( bN0 ); bN1 = extraBddSpaceFromMatrixPos( dd, cuddT(zA) ); if ( bN1 == NULL ) { Cudd_RecursiveDeref( dd, bRes0 ); Cudd_RecursiveDeref( dd, bN0 ); return NULL; } cuddRef( bN1 ); bRes1 = cuddBddAndRecur( dd, bN0, bN1 ); if ( bRes1 == NULL ) { Cudd_RecursiveDeref( dd, bRes0 ); Cudd_RecursiveDeref( dd, bN0 ); Cudd_RecursiveDeref( dd, bN1 ); return NULL; } cuddRef( bRes1 ); Cudd_RecursiveDeref( dd, bN0 ); Cudd_RecursiveDeref( dd, bN1 ); // consider the case when Res0 and Res1 are the same node if ( bRes0 == bRes1 ) bRes = bRes1; // consider the case when Res1 is complemented else if ( Cudd_IsComplement(bRes1) ) { bRes = cuddUniqueInter( dd, zA->index/2, Cudd_Not(bRes1), Cudd_Not(bRes0) ); if ( bRes == NULL ) { Cudd_RecursiveDeref(dd,bRes0); Cudd_RecursiveDeref(dd,bRes1); return NULL; } bRes = Cudd_Not(bRes); } else { bRes = cuddUniqueInter( dd, zA->index/2, bRes1, bRes0 ); if ( bRes == NULL ) { Cudd_RecursiveDeref(dd,bRes0); Cudd_RecursiveDeref(dd,bRes1); return NULL; } } cuddDeref( bRes0 ); cuddDeref( bRes1 ); cuddCacheInsert1( dd, extraBddSpaceFromMatrixNeg, zA, bRes ); return bRes; } }
/**Function******************************************************************** Synopsis [Performs the recursive steps of Extra_bddSpaceFromFunction.] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ DdNode * extraBddSpaceFromFunction( DdManager * dd, DdNode * bF, DdNode * bG ) { DdNode * bRes; DdNode * bFR, * bGR; bFR = Cudd_Regular( bF ); bGR = Cudd_Regular( bG ); if ( cuddIsConstant(bFR) ) { if ( bF == bG ) return b1; else return b0; } if ( cuddIsConstant(bGR) ) return b0; // both bFunc and bCore are not constants // the operation is commutative - normalize the problem if ( (unsigned)(ABC_PTRUINT_T)bF > (unsigned)(ABC_PTRUINT_T)bG ) return extraBddSpaceFromFunction(dd, bG, bF); if ( (bRes = cuddCacheLookup2(dd, extraBddSpaceFromFunction, bF, bG)) ) return bRes; else { DdNode * bF0, * bF1; DdNode * bG0, * bG1; DdNode * bTemp1, * bTemp2; DdNode * bRes0, * bRes1; int LevelF, LevelG; int index; LevelF = dd->perm[bFR->index]; LevelG = dd->perm[bGR->index]; if ( LevelF <= LevelG ) { index = dd->invperm[LevelF]; if ( bFR != bF ) { bF0 = Cudd_Not( cuddE(bFR) ); bF1 = Cudd_Not( cuddT(bFR) ); } else { bF0 = cuddE(bFR); bF1 = cuddT(bFR); } } else { index = dd->invperm[LevelG]; bF0 = bF1 = bF; } if ( LevelG <= LevelF ) { if ( bGR != bG ) { bG0 = Cudd_Not( cuddE(bGR) ); bG1 = Cudd_Not( cuddT(bGR) ); } else { bG0 = cuddE(bGR); bG1 = cuddT(bGR); } } else bG0 = bG1 = bG; bTemp1 = extraBddSpaceFromFunction( dd, bF0, bG0 ); if ( bTemp1 == NULL ) return NULL; cuddRef( bTemp1 ); bTemp2 = extraBddSpaceFromFunction( dd, bF1, bG1 ); if ( bTemp2 == NULL ) { Cudd_RecursiveDeref( dd, bTemp1 ); return NULL; } cuddRef( bTemp2 ); bRes0 = cuddBddAndRecur( dd, bTemp1, bTemp2 ); if ( bRes0 == NULL ) { Cudd_RecursiveDeref( dd, bTemp1 ); Cudd_RecursiveDeref( dd, bTemp2 ); return NULL; } cuddRef( bRes0 ); Cudd_RecursiveDeref( dd, bTemp1 ); Cudd_RecursiveDeref( dd, bTemp2 ); bTemp1 = extraBddSpaceFromFunction( dd, bF0, bG1 ); if ( bTemp1 == NULL ) { Cudd_RecursiveDeref( dd, bRes0 ); return NULL; } cuddRef( bTemp1 ); bTemp2 = extraBddSpaceFromFunction( dd, bF1, bG0 ); if ( bTemp2 == NULL ) { Cudd_RecursiveDeref( dd, bRes0 ); Cudd_RecursiveDeref( dd, bTemp1 ); return NULL; } cuddRef( bTemp2 ); bRes1 = cuddBddAndRecur( dd, bTemp1, bTemp2 ); if ( bRes1 == NULL ) { Cudd_RecursiveDeref( dd, bRes0 ); Cudd_RecursiveDeref( dd, bTemp1 ); Cudd_RecursiveDeref( dd, bTemp2 ); return NULL; } cuddRef( bRes1 ); Cudd_RecursiveDeref( dd, bTemp1 ); Cudd_RecursiveDeref( dd, bTemp2 ); // consider the case when Res0 and Res1 are the same node if ( bRes0 == bRes1 ) bRes = bRes1; // consider the case when Res1 is complemented else if ( Cudd_IsComplement(bRes1) ) { bRes = cuddUniqueInter(dd, index, Cudd_Not(bRes1), Cudd_Not(bRes0)); if ( bRes == NULL ) { Cudd_RecursiveDeref(dd,bRes0); Cudd_RecursiveDeref(dd,bRes1); return NULL; } bRes = Cudd_Not(bRes); } else { bRes = cuddUniqueInter( dd, index, bRes1, bRes0 ); if ( bRes == NULL ) { Cudd_RecursiveDeref(dd,bRes0); Cudd_RecursiveDeref(dd,bRes1); return NULL; } } cuddDeref( bRes0 ); cuddDeref( bRes1 ); // insert the result into cache cuddCacheInsert2(dd, extraBddSpaceFromFunction, bF, bG, bRes); return bRes; } } /* end of extraBddSpaceFromFunction */
/**Function************************************************************* Synopsis [Performs the recursive step of Extra_bddSpaceEquationsNev().] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ DdNode * extraBddSpaceEquationsNeg( DdManager * dd, DdNode * bF ) { DdNode * zRes; statLine( dd ); if ( bF == b0 ) return z1; if ( bF == b1 ) return z0; if ( (zRes = cuddCacheLookup1Zdd(dd, extraBddSpaceEquationsNeg, bF)) ) return zRes; else { DdNode * bFR, * bF0, * bF1; DdNode * zPos0, * zPos1, * zNeg1; DdNode * zRes, * zRes0, * zRes1; bFR = Cudd_Regular(bF); if ( bFR != bF ) // bF is complemented { bF0 = Cudd_Not( cuddE(bFR) ); bF1 = Cudd_Not( cuddT(bFR) ); } else { bF0 = cuddE(bFR); bF1 = cuddT(bFR); } if ( bF0 == b0 ) { zRes = extraBddSpaceEquationsNeg( dd, bF1 ); if ( zRes == NULL ) return NULL; } else if ( bF1 == b0 ) { zRes0 = extraBddSpaceEquationsNeg( dd, bF0 ); if ( zRes0 == NULL ) return NULL; cuddRef( zRes0 ); // add the current element to the set zRes = cuddZddGetNode( dd, 2*bFR->index, z1, zRes0 ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd(dd, zRes0); return NULL; } cuddDeref( zRes0 ); } else { zPos0 = extraBddSpaceEquationsNeg( dd, bF0 ); if ( zPos0 == NULL ) return NULL; cuddRef( zPos0 ); zPos1 = extraBddSpaceEquationsNeg( dd, bF1 ); if ( zPos1 == NULL ) { Cudd_RecursiveDerefZdd(dd, zPos0); return NULL; } cuddRef( zPos1 ); zNeg1 = extraBddSpaceEquationsPos( dd, bF1 ); if ( zNeg1 == NULL ) { Cudd_RecursiveDerefZdd(dd, zPos0); Cudd_RecursiveDerefZdd(dd, zPos1); return NULL; } cuddRef( zNeg1 ); zRes0 = cuddZddIntersect( dd, zPos0, zPos1 ); if ( zRes0 == NULL ) { Cudd_RecursiveDerefZdd(dd, zNeg1); Cudd_RecursiveDerefZdd(dd, zPos0); Cudd_RecursiveDerefZdd(dd, zPos1); return NULL; } cuddRef( zRes0 ); zRes1 = cuddZddIntersect( dd, zPos0, zNeg1 ); if ( zRes1 == NULL ) { Cudd_RecursiveDerefZdd(dd, zRes0); Cudd_RecursiveDerefZdd(dd, zNeg1); Cudd_RecursiveDerefZdd(dd, zPos0); Cudd_RecursiveDerefZdd(dd, zPos1); return NULL; } cuddRef( zRes1 ); Cudd_RecursiveDerefZdd(dd, zNeg1); Cudd_RecursiveDerefZdd(dd, zPos0); Cudd_RecursiveDerefZdd(dd, zPos1); // only zRes0 and zRes1 are refed at this point zRes = cuddZddGetNode( dd, 2*bFR->index, zRes1, zRes0 ); if ( zRes == NULL ) { Cudd_RecursiveDerefZdd(dd, zRes0); Cudd_RecursiveDerefZdd(dd, zRes1); return NULL; } cuddDeref( zRes0 ); cuddDeref( zRes1 ); } cuddCacheInsert1( dd, extraBddSpaceEquationsNeg, bF, zRes ); return zRes; } }
/**Function******************************************************************** Synopsis [Performs the recursive step of cuddZddP.] Description [Performs the recursive step of cuddZddP. Returns 1 in case of success; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int zp2( DdManager * zdd, DdNode * f, st_table * t) { DdNode *n; int T, E; DdNode *base = DD_ONE(zdd); if (f == NULL) return(0); if (Cudd_IsConstant(f)) { (void)fprintf(zdd->out, "ID = %d\n", (f == base)); return(1); } if (st_is_member(t, (char *)f) == 1) return(1); if (st_insert(t, (char *) f, NULL) == ST_OUT_OF_MEM) return(0); #if SIZEOF_VOID_P == 8 (void) fprintf(zdd->out, "ID = 0x%lx\tindex = %d\tr = %d\t", (unsigned long)f / (unsigned long) sizeof(DdNode), f->index, f->ref); #else (void) fprintf(zdd->out, "ID = 0x%x\tindex = %d\tr = %d\t", (unsigned)f / (unsigned) sizeof(DdNode), f->index, f->ref); #endif n = cuddT(f); if (Cudd_IsConstant(n)) { (void) fprintf(zdd->out, "T = %d\t\t", (n == base)); T = 1; } else { #if SIZEOF_VOID_P == 8 (void) fprintf(zdd->out, "T = 0x%lx\t", (unsigned long) n / (unsigned long) sizeof(DdNode)); #else (void) fprintf(zdd->out, "T = 0x%x\t", (unsigned) n / (unsigned) sizeof(DdNode)); #endif T = 0; } n = cuddE(f); if (Cudd_IsConstant(n)) { (void) fprintf(zdd->out, "E = %d\n", (n == base)); E = 1; } else { #if SIZEOF_VOID_P == 8 (void) fprintf(zdd->out, "E = 0x%lx\n", (unsigned long) n / (unsigned long) sizeof(DdNode)); #else (void) fprintf(zdd->out, "E = 0x%x\n", (unsigned) n / (unsigned) sizeof(DdNode)); #endif E = 0; } if (E == 0) if (zp2(zdd, cuddE(f), t) == 0) return(0); if (T == 0) if (zp2(zdd, cuddT(f), t) == 0) return(0); return(1); } /* end of zp2 */
/**Function******************************************************************** Synopsis [Writes a dot file representing the argument ZDDs.] Description [Writes a file representing the argument ZDDs in a format suitable for the graph drawing program dot. It returns 1 in case of success; 0 otherwise (e.g., out-of-memory, file system full). Cudd_zddDumpDot does not close the file: This is the caller responsibility. Cudd_zddDumpDot uses a minimal unique subset of the hexadecimal address of a node as name for it. If the argument inames is non-null, it is assumed to hold the pointers to the names of the inputs. Similarly for onames. Cudd_zddDumpDot uses the following convention to draw arcs: <ul> <li> solid line: THEN arcs; <li> dashed line: ELSE arcs. </ul> The dot options are chosen so that the drawing fits on a letter-size sheet. ] SideEffects [None] SeeAlso [Cudd_DumpDot Cudd_zddPrintDebug] ******************************************************************************/ int Cudd_zddDumpDot( DdManager * dd /* manager */, int n /* number of output nodes to be dumped */, DdNode ** f /* array of output nodes to be dumped */, char ** inames /* array of input names (or NULL) */, char ** onames /* array of output names (or NULL) */, FILE * fp /* pointer to the dump file */) { DdNode *support = NULL; DdNode *scan; int *sorted = NULL; int nvars = dd->sizeZ; st_table *visited = NULL; st_generator *gen; int retval; int i, j; int slots; DdNodePtr *nodelist; long refAddr, diff, mask; /* Build a bit array with the support of f. */ sorted = ALLOC(int,nvars); if (sorted == NULL) { dd->errorCode = CUDD_MEMORY_OUT; goto failure; } for (i = 0; i < nvars; i++) sorted[i] = 0; /* Take the union of the supports of each output function. */ for (i = 0; i < n; i++) { support = Cudd_Support(dd,f[i]); if (support == NULL) goto failure; cuddRef(support); scan = support; while (!cuddIsConstant(scan)) { sorted[scan->index] = 1; scan = cuddT(scan); } Cudd_RecursiveDeref(dd,support); } support = NULL; /* so that we do not try to free it in case of failure */ /* Initialize symbol table for visited nodes. */ visited = st_init_table(st_ptrcmp, st_ptrhash); if (visited == NULL) goto failure; /* Collect all the nodes of this DD in the symbol table. */ for (i = 0; i < n; i++) { retval = cuddCollectNodes(f[i],visited); if (retval == 0) goto failure; } /* Find how many most significant hex digits are identical ** in the addresses of all the nodes. Build a mask based ** on this knowledge, so that digits that carry no information ** will not be printed. This is done in two steps. ** 1. We scan the symbol table to find the bits that differ ** in at least 2 addresses. ** 2. We choose one of the possible masks. There are 8 possible ** masks for 32-bit integer, and 16 possible masks for 64-bit ** integers. */ /* Find the bits that are different. */ refAddr = (long) f[0]; diff = 0; gen = st_init_gen(visited); while (st_gen(gen, (char **) &scan, NULL)) { diff |= refAddr ^ (long) scan; } st_free_gen(gen); /* Choose the mask. */ for (i = 0; (unsigned) i < 8 * sizeof(long); i += 4) { mask = (1 << i) - 1; if (diff <= mask) break; } /* Write the header and the global attributes. */ retval = fprintf(fp,"digraph \"ZDD\" {\n"); if (retval == EOF) return(0); retval = fprintf(fp, "size = \"7.5,10\"\ncenter = true;\nedge [dir = none];\n"); if (retval == EOF) return(0); /* Write the input name subgraph by scanning the support array. */ retval = fprintf(fp,"{ node [shape = plaintext];\n"); if (retval == EOF) goto failure; retval = fprintf(fp," edge [style = invis];\n"); if (retval == EOF) goto failure; /* We use a name ("CONST NODES") with an embedded blank, because ** it is unlikely to appear as an input name. */ retval = fprintf(fp," \"CONST NODES\" [style = invis];\n"); if (retval == EOF) goto failure; for (i = 0; i < nvars; i++) { if (sorted[dd->invpermZ[i]]) { if (inames == NULL) { retval = fprintf(fp,"\" %d \" -> ", dd->invpermZ[i]); } else { retval = fprintf(fp,"\" %s \" -> ", inames[dd->invpermZ[i]]); } if (retval == EOF) goto failure; } } retval = fprintf(fp,"\"CONST NODES\"; \n}\n"); if (retval == EOF) goto failure; /* Write the output node subgraph. */ retval = fprintf(fp,"{ rank = same; node [shape = box]; edge [style = invis];\n"); if (retval == EOF) goto failure; for (i = 0; i < n; i++) { if (onames == NULL) { retval = fprintf(fp,"\"F%d\"", i); } else { retval = fprintf(fp,"\" %s \"", onames[i]); } if (retval == EOF) goto failure; if (i == n - 1) { retval = fprintf(fp,"; }\n"); } else { retval = fprintf(fp," -> "); } if (retval == EOF) goto failure; } /* Write rank info: All nodes with the same index have the same rank. */ for (i = 0; i < nvars; i++) { if (sorted[dd->invpermZ[i]]) { retval = fprintf(fp,"{ rank = same; "); if (retval == EOF) goto failure; if (inames == NULL) { retval = fprintf(fp,"\" %d \";\n", dd->invpermZ[i]); } else { retval = fprintf(fp,"\" %s \";\n", inames[dd->invpermZ[i]]); } if (retval == EOF) goto failure; nodelist = dd->subtableZ[i].nodelist; slots = dd->subtableZ[i].slots; for (j = 0; j < slots; j++) { scan = nodelist[j]; while (scan != NULL) { if (st_is_member(visited,(char *) scan)) { retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode)); if (retval == EOF) goto failure; } scan = scan->next; } } retval = fprintf(fp,"}\n"); if (retval == EOF) goto failure; } } /* All constants have the same rank. */ retval = fprintf(fp, "{ rank = same; \"CONST NODES\";\n{ node [shape = box]; "); if (retval == EOF) goto failure; nodelist = dd->constants.nodelist; slots = dd->constants.slots; for (j = 0; j < slots; j++) { scan = nodelist[j]; while (scan != NULL) { if (st_is_member(visited,(char *) scan)) { retval = fprintf(fp,"\"%lx\";\n", (mask & (long) scan) / sizeof(DdNode)); if (retval == EOF) goto failure; } scan = scan->next; } } retval = fprintf(fp,"}\n}\n"); if (retval == EOF) goto failure; /* Write edge info. */ /* Edges from the output nodes. */ for (i = 0; i < n; i++) { if (onames == NULL) { retval = fprintf(fp,"\"F%d\"", i); } else { retval = fprintf(fp,"\" %s \"", onames[i]); } if (retval == EOF) goto failure; retval = fprintf(fp," -> \"%lx\" [style = solid];\n", (mask & (long) f[i]) / sizeof(DdNode)); if (retval == EOF) goto failure; } /* Edges from internal nodes. */ for (i = 0; i < nvars; i++) { if (sorted[dd->invpermZ[i]]) { nodelist = dd->subtableZ[i].nodelist; slots = dd->subtableZ[i].slots; for (j = 0; j < slots; j++) { scan = nodelist[j]; while (scan != NULL) { if (st_is_member(visited,(char *) scan)) { retval = fprintf(fp, "\"%lx\" -> \"%lx\";\n", (mask & (long) scan) / sizeof(DdNode), (mask & (long) cuddT(scan)) / sizeof(DdNode)); if (retval == EOF) goto failure; retval = fprintf(fp, "\"%lx\" -> \"%lx\" [style = dashed];\n", (mask & (long) scan) / sizeof(DdNode), (mask & (long) cuddE(scan)) / sizeof(DdNode)); if (retval == EOF) goto failure; } scan = scan->next; } } } } /* Write constant labels. */ nodelist = dd->constants.nodelist; slots = dd->constants.slots; for (j = 0; j < slots; j++) { scan = nodelist[j]; while (scan != NULL) { if (st_is_member(visited,(char *) scan)) { retval = fprintf(fp,"\"%lx\" [label = \"%g\"];\n", (mask & (long) scan) / sizeof(DdNode), cuddV(scan)); if (retval == EOF) goto failure; } scan = scan->next; } } /* Write trailer and return. */ retval = fprintf(fp,"}\n"); if (retval == EOF) goto failure; st_free_table(visited); FREE(sorted); return(1); failure: if (sorted != NULL) FREE(sorted); if (support != NULL) Cudd_RecursiveDeref(dd,support); if (visited != NULL) st_free_table(visited); return(0); } /* end of Cudd_zddDumpBlif */
/**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 * cuddBddAndRecurTime( DdManager * manager, DdNode * f, DdNode * g, int * pRecCalls, int TimeOut) { 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 (f > 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 ( TimeOut && ((*pRecCalls)++ % CHECK_FACTOR) == 0 && TimeOut < clock() ) if ( TimeOut && TimeOut < clock() ) 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 = cuddBddAndRecurTime(manager, fv, gv, pRecCalls, TimeOut); if (t == NULL) return(NULL); cuddRef(t); e = cuddBddAndRecurTime(manager, fnv, gnv, pRecCalls, TimeOut); 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_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 (f > 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 */
/**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 * cuddBddAndAbstractRecurTime( DdManager * manager, DdNode * f, DdNode * g, DdNode * cube, int * pRecCalls, int TimeOut) { 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(cuddBddAndRecurTime(manager, f, g, pRecCalls, TimeOut)); } 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(cuddBddAndRecurTime(manager, f, g, pRecCalls, TimeOut)); } 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 ( TimeOut && ((*pRecCalls)++ % CHECK_FACTOR) == 0 && TimeOut < clock() ) if ( TimeOut && TimeOut < clock() ) return NULL; if (topf == top) { index = F->index; ft = cuddT(F); fe = cuddE(F); if (Cudd_IsComplement(f)) { ft = Cudd_Not(ft); fe = Cudd_Not(fe); } } else { index = G->index; ft = fe = f; } if (topg == top) { gt = cuddT(G); ge = cuddE(G); if (Cudd_IsComplement(g)) { gt = Cudd_Not(gt); ge = Cudd_Not(ge); } } else { gt = ge = g; } if (topcube == top) { /* quantify */ DdNode *Cube = cuddT(cube); t = cuddBddAndAbstractRecurTime(manager, ft, gt, Cube, pRecCalls, TimeOut); 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 = cuddBddAndAbstractRecurTime(manager, fe, ge, Cube, pRecCalls, TimeOut); } if (e == NULL) { Cudd_IterDerefBdd(manager, t); return(NULL); } if (t == e) { r = t; cuddDeref(t); } else { cuddRef(e); r = cuddBddAndRecurTime(manager, Cudd_Not(t), Cudd_Not(e), pRecCalls, TimeOut); 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 = cuddBddAndAbstractRecurTime(manager, ft, gt, cube, pRecCalls, TimeOut); if (t == NULL) return(NULL); cuddRef(t); e = cuddBddAndAbstractRecurTime(manager, fe, ge, cube, pRecCalls, TimeOut); 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 [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 [Performs the recursive step of Cuddaux_addRestrict.] Description [Performs the recursive step of Cuddaux_addRestrict. Returns the restricted ADD if successful; otherwise NULL.] SideEffects [None] SeeAlso [Cudd_addRestrict] ******************************************************************************/ DdNode * cuddauxAddRestrictRecur( DdManager * dd, DdNode * f, DdNode * c) { DdNode *Fv, *Fnv, *Cv, *Cnv, *t, *e, *res, *one, *zero; unsigned int topf, topc; int index; one = DD_ONE(dd); zero = Cudd_Not(one); /* Trivial cases */ if (c == one) return(f); if (c == zero){ fprintf(stderr,"CuddauxAddRestrictRecur: warning: false careset\n"); return(DD_BACKGROUND(dd)); } if (Cudd_IsConstant(f)) return(f); /* Now f and c are non-constant. */ /* Check the cache. */ res = cuddCacheLookup2(dd, Cuddaux_addRestrict, f, c); if (res != NULL) { return(res); } topf = dd->perm[f->index]; topc = dd->perm[Cudd_Regular(c)->index]; if (topc < topf) { /* abstract top variable from c */ DdNode *d, *s1, *s2; /* Take the OR by applying DeMorgan. */ /* Find complements of cofactors of c. */ if (Cudd_IsComplement(c)) { s1 = cuddT(Cudd_Regular(c)); s2 = cuddE(Cudd_Regular(c)); } else { s1 = Cudd_Not(cuddT(c)); s2 = Cudd_Not(cuddE(c)); } /* Take the AND and negate */ d = cuddBddAndRecur(dd, s1, s2); if (d == NULL) return(NULL); d = Cudd_Not(d); cuddRef(d); res = cuddauxAddRestrictRecur(dd, f, d); if (res == NULL) { Cudd_IterDerefBdd(dd, d); return(NULL); } cuddRef(res); Cudd_IterDerefBdd(dd, d); cuddDeref(res); cuddCacheInsert2(dd, Cuddaux_addRestrict, f, c, res); return(res); } /* Recursive step. Here topf <= topc. */ index = f->index; Fv = cuddT(f); Fnv = cuddE(f); if (topc == topf) { Cv = Cudd_T(c); Cnv = Cudd_E(c); if (Cudd_IsComplement(c)) { Cv = Cudd_Not(Cv); Cnv = Cudd_Not(Cnv); } } else { Cv = Cnv = c; } if (!Cudd_IsConstant(Cv)) { t = cuddauxAddRestrictRecur(dd, Fv, Cv); if (t == NULL) return(NULL); } else if (Cv == one) { t = Fv; } else { /* Cv == zero: return(Fnv @ Cnv) */ if (Cnv == one) { res = Fnv; } else { res = cuddauxAddRestrictRecur(dd, Fnv, Cnv); if (res == NULL) return(NULL); } return(res); } cuddRef(t); if (!Cudd_IsConstant(Cnv)) { e = cuddauxAddRestrictRecur(dd, Fnv, Cnv); if (e == NULL) { Cudd_RecursiveDeref(dd, t); return(NULL); } } else if (Cnv == one) { e = Fnv; } else { /* Cnv == zero: return (Fv @ Cv) previously computed */ cuddDeref(t); return(t); } cuddRef(e); res = (t == e) ? t : cuddUniqueInter(dd, index, t, e); if (res == NULL) { Cudd_RecursiveDeref(dd, e); Cudd_RecursiveDeref(dd, t); return(NULL); } cuddDeref(t); cuddDeref(e); cuddCacheInsert2(dd, Cuddaux_addRestrict, f, c, res); return(res); } /* end of cuddauxAddRestrictRecur */
/**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) && g < 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 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 [Implements the recursive step of Cudd_bddIte.] Description [Implements the recursive step of Cudd_bddIte. Returns a pointer to the resulting BDD. NULL if the intermediate result blows up or if reordering occurs.] SideEffects [None] SeeAlso [] ******************************************************************************/ DdNode * cuddBddIteRecur( DdManager * dd, DdNode * f, DdNode * g, DdNode * h) { DdNode *one, *zero, *res; DdNode *r, *Fv, *Fnv, *Gv, *Gnv, *H, *Hv, *Hnv, *t, *e; unsigned int topf, topg, toph, v; int index; int comple; statLine(dd); /* Terminal cases. */ /* One variable cases. */ if (f == (one = DD_ONE(dd))) /* ITE(1,G,H) = G */ return(g); if (f == (zero = Cudd_Not(one))) /* ITE(0,G,H) = H */ return(h); /* From now on, f is known not to be a constant. */ if (g == one || f == g) { /* ITE(F,F,H) = ITE(F,1,H) = F + H */ if (h == zero) { /* ITE(F,1,0) = F */ return(f); } else { res = cuddBddAndRecur(dd,Cudd_Not(f),Cudd_Not(h)); return(Cudd_NotCond(res,res != NULL)); } } else if (g == zero || f == Cudd_Not(g)) { /* ITE(F,!F,H) = ITE(F,0,H) = !F * H */ if (h == one) { /* ITE(F,0,1) = !F */ return(Cudd_Not(f)); } else { res = cuddBddAndRecur(dd,Cudd_Not(f),h); return(res); } } if (h == zero || f == h) { /* ITE(F,G,F) = ITE(F,G,0) = F * G */ res = cuddBddAndRecur(dd,f,g); return(res); } else if (h == one || f == Cudd_Not(h)) { /* ITE(F,G,!F) = ITE(F,G,1) = !F + G */ res = cuddBddAndRecur(dd,f,Cudd_Not(g)); return(Cudd_NotCond(res,res != NULL)); } /* Check remaining one variable case. */ if (g == h) { /* ITE(F,G,G) = G */ return(g); } else if (g == Cudd_Not(h)) { /* ITE(F,G,!G) = F <-> G */ res = cuddBddXorRecur(dd,f,h); return(res); } /* From here, there are no constants. */ comple = bddVarToCanonicalSimple(dd, &f, &g, &h, &topf, &topg, &toph); /* f & g are now regular pointers */ v = ddMin(topg, toph); /* A shortcut: ITE(F,G,H) = (v,G,H) if F = (v,1,0), v < top(G,H). */ if (topf < v && cuddT(f) == one && cuddE(f) == zero) { r = cuddUniqueInter(dd, (int) f->index, g, h); return(Cudd_NotCond(r,comple && r != NULL)); } /* Check cache. */ r = cuddCacheLookup(dd, DD_BDD_ITE_TAG, f, g, h); if (r != NULL) { return(Cudd_NotCond(r,comple)); } /* Compute cofactors. */ if (topf <= v) { v = ddMin(topf, v); /* v = top_var(F,G,H) */ index = f->index; Fv = cuddT(f); Fnv = cuddE(f); } else { Fv = Fnv = f; } if (topg == v) { index = g->index; Gv = cuddT(g); Gnv = cuddE(g); } else { Gv = Gnv = g; } if (toph == v) { H = Cudd_Regular(h); index = H->index; Hv = cuddT(H); Hnv = cuddE(H); if (Cudd_IsComplement(h)) { Hv = Cudd_Not(Hv); Hnv = Cudd_Not(Hnv); } } else { Hv = Hnv = h; } /* Recursive step. */ t = cuddBddIteRecur(dd,Fv,Gv,Hv); if (t == NULL) return(NULL); cuddRef(t); e = cuddBddIteRecur(dd,Fnv,Gnv,Hnv); if (e == NULL) { Cudd_IterDerefBdd(dd,t); return(NULL); } cuddRef(e); r = (t == e) ? t : cuddUniqueInter(dd,index,t,e); if (r == NULL) { Cudd_IterDerefBdd(dd,t); Cudd_IterDerefBdd(dd,e); return(NULL); } cuddDeref(t); cuddDeref(e); cuddCacheInsert(dd, DD_BDD_ITE_TAG, f, g, h, r); return(Cudd_NotCond(r,comple)); } /* end of cuddBddIteRecur */
/**Function******************************************************************** Synopsis [Checks for symmetry of x and y.] Description [Checks for symmetry of x and y. Ignores projection functions, unless they are isolated. Returns 1 in case of symmetry; 0 otherwise.] SideEffects [None] ******************************************************************************/ int cuddSymmCheck( DdManager * table, int x, int y) { DdNode *f,*f0,*f1,*f01,*f00,*f11,*f10; int comple; /* f0 is complemented */ int xsymmy; /* x and y may be positively symmetric */ int xsymmyp; /* x and y may be negatively symmetric */ int arccount; /* number of arcs from layer x to layer y */ int TotalRefCount; /* total reference count of layer y minus 1 */ int yindex; int i; DdNodePtr *list; int slots; DdNode *sentinel = &(table->sentinel); #ifdef DD_DEBUG int xindex; #endif /* Checks that x and y are not the projection functions. ** For x it is sufficient to check whether there is only one ** node; indeed, if there is one node, it is the projection function ** and it cannot point to y. Hence, if y isn't just the projection ** function, it has one arc coming from a layer different from x. */ if (table->subtables[x].keys == 1) { return(0); } yindex = table->invperm[y]; if (table->subtables[y].keys == 1) { if (table->vars[yindex]->ref == 1) return(0); } xsymmy = xsymmyp = 1; arccount = 0; slots = table->subtables[x].slots; list = table->subtables[x].nodelist; for (i = 0; i < slots; i++) { f = list[i]; while (f != sentinel) { /* Find f1, f0, f11, f10, f01, f00. */ f1 = cuddT(f); f0 = Cudd_Regular(cuddE(f)); comple = Cudd_IsComplement(cuddE(f)); if ((int) f1->index == yindex) { arccount++; f11 = cuddT(f1); f10 = cuddE(f1); } else { if ((int) f0->index != yindex) { /* If f is an isolated projection function it is ** allowed to bypass layer y. */ if (f1 != DD_ONE(table) || f0 != DD_ONE(table) || f->ref != 1) return(0); /* f bypasses layer y */ } f11 = f10 = f1; } if ((int) f0->index == yindex) { arccount++; f01 = cuddT(f0); f00 = cuddE(f0); } else { f01 = f00 = f0; } if (comple) { f01 = Cudd_Not(f01); f00 = Cudd_Not(f00); } if (f1 != DD_ONE(table) || f0 != DD_ONE(table) || f->ref != 1) { xsymmy &= f01 == f10; xsymmyp &= f11 == f00; if ((xsymmy == 0) && (xsymmyp == 0)) return(0); } f = f->next; } /* while */ } /* for */ /* Calculate the total reference counts of y */ TotalRefCount = -1; /* -1 for projection function */ slots = table->subtables[y].slots; list = table->subtables[y].nodelist; for (i = 0; i < slots; i++) { f = list[i]; while (f != sentinel) { TotalRefCount += f->ref; f = f->next; } } #if defined(DD_DEBUG) && defined(DD_VERBOSE) if (arccount == TotalRefCount) { xindex = table->invperm[x]; (void) fprintf(table->out, "Found symmetry! x =%d\ty = %d\tPos(%d,%d)\n", xindex,yindex,x,y); } #endif return(arccount == TotalRefCount); } /* end of cuddSymmCheck */
/**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 (f > 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 [Swaps two adjacent variables.] Description [Swaps two adjacent variables. It assumes that no dead nodes are present on entry to this procedure. The procedure then guarantees that no dead nodes will be present when it terminates. cuddZddSwapInPlace assumes that x < y. Returns the number of keys in the table if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ int cuddZddSwapInPlace( DdManager * table, int x, int y) { DdNodePtr *xlist, *ylist; int xindex, yindex; int xslots, yslots; int xshift, yshift; int oldxkeys, oldykeys; int newxkeys, newykeys; int i; int posn; DdNode *f, *f1, *f0, *f11, *f10, *f01, *f00; DdNode *newf1, *newf0, *next; DdNodePtr g, *lastP, *previousP; #ifdef DD_DEBUG assert(x < y); assert(cuddZddNextHigh(table,x) == y); assert(table->subtableZ[x].keys != 0); assert(table->subtableZ[y].keys != 0); assert(table->subtableZ[x].dead == 0); assert(table->subtableZ[y].dead == 0); #endif zddTotalNumberSwapping++; /* Get parameters of x subtable. */ xindex = table->invpermZ[x]; xlist = table->subtableZ[x].nodelist; oldxkeys = table->subtableZ[x].keys; xslots = table->subtableZ[x].slots; xshift = table->subtableZ[x].shift; newxkeys = 0; yindex = table->invpermZ[y]; ylist = table->subtableZ[y].nodelist; oldykeys = table->subtableZ[y].keys; yslots = table->subtableZ[y].slots; yshift = table->subtableZ[y].shift; newykeys = oldykeys; /* The nodes in the x layer that don't depend on y directly ** will stay there; the others are put in a chain. ** The chain is handled as a FIFO; g points to the beginning and ** last points to the end. */ g = NULL; lastP = &g; for (i = 0; i < xslots; i++) { previousP = &(xlist[i]); f = *previousP; while (f != NULL) { next = f->next; f1 = cuddT(f); f0 = cuddE(f); if ((f1->index != (DdHalfWord) yindex) && (f0->index != (DdHalfWord) yindex)) { /* stays */ newxkeys++; *previousP = f; previousP = &(f->next); } else { f->index = yindex; *lastP = f; lastP = &(f->next); } f = next; } /* while there are elements in the collision chain */ *previousP = NULL; } /* for each slot of the x subtable */ *lastP = NULL; #ifdef DD_COUNT table->swapSteps += oldxkeys - newxkeys; #endif /* Take care of the x nodes that must be re-expressed. ** They form a linked list pointed by g. Their index has been ** changed to yindex already. */ f = g; while (f != NULL) { next = f->next; /* Find f1, f0, f11, f10, f01, f00. */ f1 = cuddT(f); if ((int) f1->index == yindex) { f11 = cuddT(f1); f10 = cuddE(f1); } else { f11 = empty; f10 = f1; } f0 = cuddE(f); if ((int) f0->index == yindex) { f01 = cuddT(f0); f00 = cuddE(f0); } else { f01 = empty; f00 = f0; } /* Decrease ref count of f1. */ cuddSatDec(f1->ref); /* Create the new T child. */ if (f11 == empty) { if (f01 != empty) { newf1 = f01; cuddSatInc(newf1->ref); } /* else case was already handled when finding nodes ** with both children below level y */ } else { /* Check xlist for triple (xindex, f11, f01). */ posn = ddHash(f11, f01, xshift); /* For each element newf1 in collision list xlist[posn]. */ newf1 = xlist[posn]; while (newf1 != NULL) { if (cuddT(newf1) == f11 && cuddE(newf1) == f01) { cuddSatInc(newf1->ref); break; /* match */ } newf1 = newf1->next; } /* while newf1 */ if (newf1 == NULL) { /* no match */ newf1 = cuddDynamicAllocNode(table); if (newf1 == NULL) goto zddSwapOutOfMem; newf1->index = xindex; newf1->ref = 1; cuddT(newf1) = f11; cuddE(newf1) = f01; /* Insert newf1 in the collision list xlist[pos]; ** increase the ref counts of f11 and f01 */ newxkeys++; newf1->next = xlist[posn]; xlist[posn] = newf1; cuddSatInc(f11->ref); cuddSatInc(f01->ref); } } cuddT(f) = newf1; /* Do the same for f0. */ /* Decrease ref count of f0. */ cuddSatDec(f0->ref); /* Create the new E child. */ if (f10 == empty) { newf0 = f00; cuddSatInc(newf0->ref); } else { /* Check xlist for triple (xindex, f10, f00). */ posn = ddHash(f10, f00, xshift); /* For each element newf0 in collision list xlist[posn]. */ newf0 = xlist[posn]; while (newf0 != NULL) { if (cuddT(newf0) == f10 && cuddE(newf0) == f00) { cuddSatInc(newf0->ref); break; /* match */ } newf0 = newf0->next; } /* while newf0 */ if (newf0 == NULL) { /* no match */ newf0 = cuddDynamicAllocNode(table); if (newf0 == NULL) goto zddSwapOutOfMem; newf0->index = xindex; newf0->ref = 1; cuddT(newf0) = f10; cuddE(newf0) = f00; /* Insert newf0 in the collision list xlist[posn]; ** increase the ref counts of f10 and f00. */ newxkeys++; newf0->next = xlist[posn]; xlist[posn] = newf0; cuddSatInc(f10->ref); cuddSatInc(f00->ref); } } cuddE(f) = newf0; /* Insert the modified f in ylist. ** The modified f does not already exists in ylist. ** (Because of the uniqueness of the cofactors.) */ posn = ddHash(newf1, newf0, yshift); newykeys++; f->next = ylist[posn]; ylist[posn] = f; f = next; } /* while f != NULL */ /* GC the y layer. */ /* For each node f in ylist. */ for (i = 0; i < yslots; i++) { previousP = &(ylist[i]); f = *previousP; while (f != NULL) { next = f->next; if (f->ref == 0) { cuddSatDec(cuddT(f)->ref); cuddSatDec(cuddE(f)->ref); cuddDeallocNode(table, f); newykeys--; } else { *previousP = f; previousP = &(f->next); } f = next; } /* while f */ *previousP = NULL; } /* for i */ /* Set the appropriate fields in table. */ table->subtableZ[x].nodelist = ylist; table->subtableZ[x].slots = yslots; table->subtableZ[x].shift = yshift; table->subtableZ[x].keys = newykeys; table->subtableZ[x].maxKeys = yslots * DD_MAX_SUBTABLE_DENSITY; table->subtableZ[y].nodelist = xlist; table->subtableZ[y].slots = xslots; table->subtableZ[y].shift = xshift; table->subtableZ[y].keys = newxkeys; table->subtableZ[y].maxKeys = xslots * DD_MAX_SUBTABLE_DENSITY; table->permZ[xindex] = y; table->permZ[yindex] = x; table->invpermZ[x] = yindex; table->invpermZ[y] = xindex; table->keysZ += newxkeys + newykeys - oldxkeys - oldykeys; /* Update univ section; univ[x] remains the same. */ table->univ[y] = cuddT(table->univ[x]); return (table->keysZ); zddSwapOutOfMem: (void) fprintf(table->err, "Error: cuddZddSwapInPlace out of memory\n"); return (0); } /* end of cuddZddSwapInPlace */
/**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 [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 [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_SplitSet.] Description [Implements the recursive step of Cudd_SplitSet. The procedure recursively traverses the BDD and checks to see if any node satisfies the minterm requirements as specified by 'n'. At any node X, n is compared to the number of minterms in the onset of X's children. If either of the child nodes have exactly n minterms, then that node is returned; else, if n is greater than the onset of one of the child nodes, that node is retained and the difference in the number of minterms is extracted from the other child. In case n minterms can be extracted from constant 1, the algorithm returns the result with at most log(n) nodes.] SideEffects [The array 'varSeen' is updated at every recursive call to set the variables traversed by the procedure.] SeeAlso [] ******************************************************************************/ DdNode* cuddSplitSetRecur( DdManager * manager, st_table * mtable, int * varSeen, DdNode * p, double n, double max, int index) { DdNode *one, *zero, *N, *Nv; DdNode *Nnv, *q, *r, *v; DdNode *result; double *dummy, numT, numE; int variable, positive; statLine(manager); one = DD_ONE(manager); zero = Cudd_Not(one); /* If p is constant, extract n minterms from constant 1. The procedure by ** construction guarantees that minterms will not be extracted from ** constant 0. */ if (Cudd_IsConstant(p)) { q = selectMintermsFromUniverse(manager,varSeen,n); return(q); } N = Cudd_Regular(p); /* Set variable as seen. */ variable = N->index; varSeen[manager->invperm[variable]] = -1; Nv = cuddT(N); Nnv = cuddE(N); if (Cudd_IsComplement(p)) { Nv = Cudd_Not(Nv); Nnv = Cudd_Not(Nnv); } /* If both the children of 'p' are constants, extract n minterms from a ** constant node. */ if (Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) { q = selectMintermsFromUniverse(manager,varSeen,n); if (q == NULL) { return(NULL); } cuddRef(q); r = cuddBddAndRecur(manager,p,q); if (r == NULL) { Cudd_RecursiveDeref(manager,q); return(NULL); } cuddRef(r); Cudd_RecursiveDeref(manager,q); cuddDeref(r); return(r); } /* Lookup the # of minterms in the onset of the node from the table. */ if (!Cudd_IsConstant(Nv)) { if (!st_lookup(mtable, Nv, &dummy)) return(NULL); numT = *dummy/(2*(1<<index)); } else if (Nv == one) { numT = max/(2*(1<<index)); } else { numT = 0; } if (!Cudd_IsConstant(Nnv)) { if (!st_lookup(mtable, Nnv, &dummy)) return(NULL); numE = *dummy/(2*(1<<index)); } else if (Nnv == one) { numE = max/(2*(1<<index)); } else { numE = 0; } v = cuddUniqueInter(manager,variable,one,zero); cuddRef(v); /* If perfect match. */ if (numT == n) { q = cuddBddAndRecur(manager,v,Nv); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); Cudd_RecursiveDeref(manager,v); cuddDeref(q); return(q); } if (numE == n) { q = cuddBddAndRecur(manager,Cudd_Not(v),Nnv); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); Cudd_RecursiveDeref(manager,v); cuddDeref(q); return(q); } /* If n is greater than numT, extract the difference from the ELSE child ** and retain the function represented by the THEN branch. */ if (numT < n) { q = cuddSplitSetRecur(manager,mtable,varSeen, Nnv,(n-numT),max,index+1); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); r = cuddBddIteRecur(manager,v,Nv,q); if (r == NULL) { Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(r); Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); cuddDeref(r); return(r); } /* If n is greater than numE, extract the difference from the THEN child ** and retain the function represented by the ELSE branch. */ if (numE < n) { q = cuddSplitSetRecur(manager,mtable,varSeen, Nv, (n-numE),max,index+1); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); r = cuddBddIteRecur(manager,v,q,Nnv); if (r == NULL) { Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(r); Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); cuddDeref(r); return(r); } /* None of the above cases; (n < numT and n < numE) and either of ** the Nv, Nnv or both are not constants. If possible extract the ** required minterms the constant branch. */ if (Cudd_IsConstant(Nv) && !Cudd_IsConstant(Nnv)) { q = selectMintermsFromUniverse(manager,varSeen,n); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); result = cuddBddAndRecur(manager,v,q); if (result == NULL) { Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(result); Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); cuddDeref(result); return(result); } else if (!Cudd_IsConstant(Nv) && Cudd_IsConstant(Nnv)) { q = selectMintermsFromUniverse(manager,varSeen,n); if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); result = cuddBddAndRecur(manager,Cudd_Not(v),q); if (result == NULL) { Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(result); Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); cuddDeref(result); return(result); } /* Both Nv and Nnv are not constants. So choose the one which ** has fewer minterms in its onset. */ positive = 0; if (numT < numE) { q = cuddSplitSetRecur(manager,mtable,varSeen, Nv,n,max,index+1); positive = 1; } else { q = cuddSplitSetRecur(manager,mtable,varSeen, Nnv,n,max,index+1); } if (q == NULL) { Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(q); if (positive) { result = cuddBddAndRecur(manager,v,q); } else { result = cuddBddAndRecur(manager,Cudd_Not(v),q); } if (result == NULL) { Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); return(NULL); } cuddRef(result); Cudd_RecursiveDeref(manager,q); Cudd_RecursiveDeref(manager,v); cuddDeref(result); return(result); } /* end of cuddSplitSetRecur */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_bddCompose.] Description [Performs the recursive step of Cudd_bddCompose. Exploits the fact that the composition of f' with g produces the complement of the composition of f with g to better utilize the cache. Returns the composed BDD if successful; NULL otherwise.] SideEffects [None] SeeAlso [Cudd_bddCompose] ******************************************************************************/ DdNode * cuddBddComposeRecur( DdManager * dd, DdNode * f, DdNode * g, DdNode * proj) { DdNode *F, *G, *f1, *f0, *g1, *g0, *r, *t, *e; unsigned int v, topf, topg, topindex; int comple; statLine(dd); v = dd->perm[proj->index]; F = Cudd_Regular(f); topf = cuddI(dd,F->index); /* Terminal case. Subsumes the test for constant f. */ if (topf > v) return(f); /* We solve the problem for a regular pointer, and then complement ** the result if the pointer was originally complemented. */ comple = Cudd_IsComplement(f); /* Check cache. */ r = cuddCacheLookup(dd,DD_BDD_COMPOSE_RECUR_TAG,F,g,proj); if (r != NULL) { return(Cudd_NotCond(r,comple)); } if (topf == v) { /* Compose. */ f1 = cuddT(F); f0 = cuddE(F); r = cuddBddIteRecur(dd, g, f1, f0); if (r == NULL) return(NULL); } else { /* Compute cofactors of f and g. Remember the index of the top ** variable. */ G = Cudd_Regular(g); topg = cuddI(dd,G->index); if (topf > topg) { topindex = G->index; f1 = f0 = F; } else { topindex = F->index; f1 = cuddT(F); f0 = cuddE(F); } if (topg > topf) { g1 = g0 = g; } else { g1 = cuddT(G); g0 = cuddE(G); if (g != G) { g1 = Cudd_Not(g1); g0 = Cudd_Not(g0); } } /* Recursive step. */ t = cuddBddComposeRecur(dd, f1, g1, proj); if (t == NULL) return(NULL); cuddRef(t); e = cuddBddComposeRecur(dd, f0, g0, proj); if (e == NULL) { Cudd_IterDerefBdd(dd, t); return(NULL); } cuddRef(e); r = cuddBddIteRecur(dd, dd->vars[topindex], t, e); if (r == NULL) { Cudd_IterDerefBdd(dd, t); Cudd_IterDerefBdd(dd, e); return(NULL); } cuddRef(r); Cudd_IterDerefBdd(dd, t); /* t & e not necessarily part of r */ Cudd_IterDerefBdd(dd, e); cuddDeref(r); } cuddCacheInsert(dd,DD_BDD_COMPOSE_RECUR_TAG,F,g,proj,r); return(Cudd_NotCond(r,comple)); } /* end of cuddBddComposeRecur */