/**Function******************************************************************** Synopsis [Integer and floating point multiplication.] Description [Integer and floating point multiplication. Returns NULL if not a terminal case; f * g otherwise. This function can be used also to take the AND of two 0-1 ADDs.] SideEffects [None] SeeAlso [Cudd_addApply] ******************************************************************************/ DdNode * Cudd_addTimes( DdManager * dd, DdNode ** f, DdNode ** g) { DdNode *res; DdNode *F, *G; CUDD_VALUE_TYPE value; F = *f; G = *g; if (F == DD_ZERO(dd) || G == DD_ZERO(dd)) return(DD_ZERO(dd)); if (F == DD_ONE(dd)) return(G); if (G == DD_ONE(dd)) return(F); if (cuddIsConstant(F) && cuddIsConstant(G)) { value = cuddV(F)*cuddV(G); res = cuddUniqueConst(dd,value); return(res); } if (F > G) { /* swap f and g */ *f = G; *g = F; } return(NULL); } /* end of Cudd_addTimes */
/**Function******************************************************************** Synopsis [Finds the maximum discriminant of f.] Description [Returns a pointer to a constant ADD.] SideEffects [None] ******************************************************************************/ DdNode * Cudd_addFindMax( DdManager * dd, DdNode * f) { DdNode *t, *e, *res; statLine(dd); if (cuddIsConstant(f)) { return(f); } res = cuddCacheLookup1(dd,Cudd_addFindMax,f); if (res != NULL) { return(res); } t = Cudd_addFindMax(dd,cuddT(f)); if (t == DD_PLUS_INFINITY(dd)) return(t); e = Cudd_addFindMax(dd,cuddE(f)); res = (cuddV(t) >= cuddV(e)) ? t : e; cuddCacheInsert1(dd,Cudd_addFindMax,f,res); return(res); } /* end of Cudd_addFindMax */
/**Function******************************************************************** Synopsis [Returns plusinfinity if f=g; returns min(f,g) if f!=g.] Description [Returns NULL if not a terminal case; f op g otherwise, where f op g is plusinfinity if f=g; min(f,g) if f!=g.] SideEffects [None] SeeAlso [Cudd_addApply] ******************************************************************************/ DdNode * Cudd_addDiff( DdManager * dd, DdNode ** f, DdNode ** g) { DdNode *F, *G; F = *f; G = *g; if (F == G) return(DD_PLUS_INFINITY(dd)); if (F == DD_PLUS_INFINITY(dd)) return(G); if (G == DD_PLUS_INFINITY(dd)) return(F); if (cuddIsConstant(F) && cuddIsConstant(G)) { if (cuddV(F) != cuddV(G)) { if (cuddV(F) < cuddV(G)) { return(F); } else { return(G); } } else { return(DD_PLUS_INFINITY(dd)); } } return(NULL); } /* end of Cudd_addDiff */
/**Function******************************************************************** Synopsis [Integer and floating point max.] Description [Integer and floating point max for Cudd_addApply. Returns NULL if not a terminal case; max(f,g) otherwise.] SideEffects [None] SeeAlso [Cudd_addApply] ******************************************************************************/ DdNode * Cudd_addMaximum( DdManager * dd, DdNode ** f, DdNode ** g) { DdNode *F, *G; F = *f; G = *g; if (F == G) return(F); if (F == DD_MINUS_INFINITY(dd)) return(G); if (G == DD_MINUS_INFINITY(dd)) return(F); #if 0 /* These special cases probably do not pay off. */ if (F == DD_PLUS_INFINITY(dd)) return(F); if (G == DD_PLUS_INFINITY(dd)) return(G); #endif if (cuddIsConstant(F) && cuddIsConstant(G)) { if (cuddV(F) >= cuddV(G)) { return(F); } else { return(G); } } if (F > G) { /* swap f and g */ *f = G; *g = F; } return(NULL); } /* end of Cudd_addMaximum */
/**Function******************************************************************** Synopsis [Performs the recursive step for Cudd_addBddInterval.] Description [Performs the recursive step for Cudd_addBddInterval. Returns a pointer to the BDD if successful; NULL otherwise.] SideEffects [None] SeeAlso [addBddDoThreshold addBddDoStrictThreshold] ******************************************************************************/ static DdNode * addBddDoInterval( DdManager * dd, DdNode * f, DdNode * l, DdNode * u) { DdNode *res, *T, *E; DdNode *fv, *fvn; int v; statLine(dd); /* Check terminal case. */ if (cuddIsConstant(f)) { return(Cudd_NotCond(DD_TRUE(dd),cuddV(f) < cuddV(l) || cuddV(f) > cuddV(u))); } /* Check cache. */ res = cuddCacheLookup(dd,DD_ADD_BDD_DO_INTERVAL_TAG,f,l,u); if (res != NULL) return(res); /* Recursive step. */ v = f->index; fv = cuddT(f); fvn = cuddE(f); T = addBddDoInterval(dd,fv,l,u); if (T == NULL) return(NULL); cuddRef(T); E = addBddDoInterval(dd,fvn,l,u); if (E == NULL) { Cudd_RecursiveDeref(dd, T); return(NULL); } cuddRef(E); if (Cudd_IsComplement(T)) { res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E)); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } res = Cudd_Not(res); } else { res = (T == E) ? T : cuddUniqueInter(dd,v,T,E); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } } cuddDeref(T); cuddDeref(E); /* Store result. */ cuddCacheInsert(dd,DD_ADD_BDD_DO_INTERVAL_TAG,f,l,u,res); return(res); } /* end of addBddDoInterval */
/**Function******************************************************************** Synopsis [Performs the recursive step for Cudd_addBddStrictThreshold.] Description [Performs the recursive step for Cudd_addBddStrictThreshold. Returns a pointer to the BDD if successful; NULL otherwise.] SideEffects [None] SeeAlso [addBddDoThreshold] ******************************************************************************/ static DdNode * addBddDoStrictThreshold( DdManager * dd, DdNode * f, DdNode * val) { DdNode *res, *T, *E; DdNode *fv, *fvn; int v; statLine(dd); /* Check terminal case. */ if (cuddIsConstant(f)) { return(Cudd_NotCond(DD_TRUE(dd),cuddV(f) <= cuddV(val))); } /* Check cache. */ res = cuddCacheLookup2(dd,addBddDoStrictThreshold,f,val); if (res != NULL) return(res); /* Recursive step. */ v = f->index; fv = cuddT(f); fvn = cuddE(f); T = addBddDoStrictThreshold(dd,fv,val); if (T == NULL) return(NULL); cuddRef(T); E = addBddDoStrictThreshold(dd,fvn,val); if (E == NULL) { Cudd_RecursiveDeref(dd, T); return(NULL); } cuddRef(E); if (Cudd_IsComplement(T)) { res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E)); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } res = Cudd_Not(res); } else { res = (T == E) ? T : cuddUniqueInter(dd,v,T,E); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } } cuddDeref(T); cuddDeref(E); /* Store result. */ cuddCacheInsert2(dd,addBddDoStrictThreshold,f,val,res); return(res); } /* end of addBddDoStrictThreshold */
/**Function******************************************************************** Synopsis [Performs the recursive step for Cudd_addIthBit.] Description [Performs the recursive step for Cudd_addIthBit. Returns a pointer to the BDD if successful; NULL otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static DdNode * addDoIthBit( DdManager * dd, DdNode * f, DdNode * index) { DdNode *res, *T, *E; DdNode *fv, *fvn; int mask, value; int v; statLine(dd); /* Check terminal case. */ if (cuddIsConstant(f)) { mask = 1 << ((int) cuddV(index)); value = (int) cuddV(f); return((value & mask) == 0 ? DD_ZERO(dd) : DD_ONE(dd)); } /* Check cache. */ res = cuddCacheLookup2(dd,addDoIthBit,f,index); if (res != NULL) return(res); /* Recursive step. */ v = f->index; fv = cuddT(f); fvn = cuddE(f); T = addDoIthBit(dd,fv,index); if (T == NULL) return(NULL); cuddRef(T); E = addDoIthBit(dd,fvn,index); if (E == NULL) { Cudd_RecursiveDeref(dd, T); return(NULL); } cuddRef(E); res = (T == E) ? T : cuddUniqueInter(dd,v,T,E); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } cuddDeref(T); cuddDeref(E); /* Store result. */ cuddCacheInsert2(dd,addDoIthBit,f,index,res); return(res); } /* end of addDoIthBit */
/**Function******************************************************************** Synopsis [Determines whether f is less than or equal to g.] Description [Returns 1 if f is less than or equal to g; 0 otherwise. No new nodes are created. This procedure works for arbitrary ADDs. For 0-1 ADDs Cudd_addEvalConst is more efficient.] SideEffects [None] SeeAlso [Cudd_addIteConstant Cudd_addEvalConst Cudd_bddLeq] ******************************************************************************/ int Cudd_addLeq( DdManager * dd, DdNode * f, DdNode * g) { DdNode *tmp, *fv, *fvn, *gv, *gvn; unsigned int topf, topg, res; /* Terminal cases. */ if (f == g) return(1); statLine(dd); if (cuddIsConstant(f)) { if (cuddIsConstant(g)) return(cuddV(f) <= cuddV(g)); if (f == DD_MINUS_INFINITY(dd)) return(1); if (f == DD_PLUS_INFINITY(dd)) return(0); /* since f != g */ } if (g == DD_PLUS_INFINITY(dd)) return(1); if (g == DD_MINUS_INFINITY(dd)) return(0); /* since f != g */ /* Check cache. */ tmp = cuddCacheLookup2(dd,(DD_CTFP)Cudd_addLeq,f,g); if (tmp != NULL) { return(tmp == DD_ONE(dd)); } /* Compute cofactors. One of f and g is not constant. */ topf = cuddI(dd,f->index); topg = cuddI(dd,g->index); if (topf <= topg) { fv = cuddT(f); fvn = cuddE(f); } else { fv = fvn = f; } if (topg <= topf) { gv = cuddT(g); gvn = cuddE(g); } else { gv = gvn = g; } res = Cudd_addLeq(dd,fvn,gvn) && Cudd_addLeq(dd,fv,gv); /* Store result in cache and return. */ cuddCacheInsert2(dd,(DD_CTFP) Cudd_addLeq,f,g, Cudd_NotCond(DD_ONE(dd),res==0)); return(res); } /* end of Cudd_addLeq */
/** @brief Performs the recursive step of addScalarInverse. @return a pointer to the resulting %ADD in case of success. Returns NULL if any discriminants smaller than epsilon is encountered. @sideeffect None */ DdNode * cuddAddScalarInverseRecur( DdManager * dd, DdNode * f, DdNode * epsilon) { DdNode *t, *e, *res; CUDD_VALUE_TYPE value; statLine(dd); if (cuddIsConstant(f)) { if (ddAbs(cuddV(f)) < cuddV(epsilon)) return(NULL); value = 1.0 / cuddV(f); res = cuddUniqueConst(dd,value); return(res); } res = cuddCacheLookup2(dd,Cudd_addScalarInverse,f,epsilon); if (res != NULL) return(res); checkWhetherToGiveUp(dd); t = cuddAddScalarInverseRecur(dd,cuddT(f),epsilon); if (t == NULL) return(NULL); cuddRef(t); e = cuddAddScalarInverseRecur(dd,cuddE(f),epsilon); if (e == NULL) { Cudd_RecursiveDeref(dd, t); return(NULL); } cuddRef(e); res = (t == e) ? t : cuddUniqueInter(dd,(int)f->index,t,e); if (res == NULL) { Cudd_RecursiveDeref(dd, t); Cudd_RecursiveDeref(dd, e); return(NULL); } cuddDeref(t); cuddDeref(e); cuddCacheInsert2(dd,Cudd_addScalarInverse,f,epsilon,res); return(res); } /* end of cuddAddScalarInverseRecur */
/**Function******************************************************************** Synopsis [f if f>=g; 0 if f<g.] Description [Threshold operator for Apply (f if f >=g; 0 if f<g). Returns NULL if not a terminal case; f op g otherwise.] SideEffects [None] SeeAlso [Cudd_addApply] ******************************************************************************/ DdNode * Cudd_addThreshold( DdManager * dd, DdNode ** f, DdNode ** g) { DdNode *F, *G; F = *f; G = *g; if (cuddIsConstant(F) && cuddIsConstant(G)) { if (cuddV(F) >= cuddV(G)) { return(F); } else { return(DD_ZERO(dd)); } } return(NULL); } /* end of Cudd_addThreshold */
/**Function******************************************************************** Synopsis [Returns 1 if f > g and 0 otherwise.] Description [Returns 1 if f > g (both should be terminal cases) and 0 otherwise. Used in conjunction with Cudd_addApply. Returns NULL if not a terminal case.] SideEffects [None] SeeAlso [Cudd_addApply] ******************************************************************************/ DdNode * Cudd_addOneZeroMaximum( DdManager * dd, DdNode ** f, DdNode ** g) { if (*g == DD_PLUS_INFINITY(dd)) return DD_ZERO(dd); if (cuddIsConstant(*f) && cuddIsConstant(*g)) { if (cuddV(*f) > cuddV(*g)) { return(DD_ONE(dd)); } else { return(DD_ZERO(dd)); } } return(NULL); } /* end of Cudd_addOneZeroMaximum */
/**Function******************************************************************** Synopsis [Integer and floating point subtraction.] Description [Integer and floating point subtraction. Returns NULL if not a terminal case; f - g otherwise.] SideEffects [None] SeeAlso [Cudd_addApply] ******************************************************************************/ DdNode * Cudd_addMinus( DdManager * dd, DdNode ** f, DdNode ** g) { DdNode *res; DdNode *F, *G; CUDD_VALUE_TYPE value; F = *f; G = *g; if (F == DD_ZERO(dd)) return(cuddAddNegateRecur(dd,G)); if (G == DD_ZERO(dd)) return(F); if (cuddIsConstant(F) && cuddIsConstant(G)) { value = cuddV(F)-cuddV(G); res = cuddUniqueConst(dd,value); return(res); } return(NULL); } /* end of Cudd_addMinus */
/**Function******************************************************************** Synopsis [Integer and floating point division.] Description [Integer and floating point division. Returns NULL if not a terminal case; f / g otherwise.] SideEffects [None] SeeAlso [Cudd_addApply] ******************************************************************************/ DdNode * Cudd_addDivide( DdManager * dd, DdNode ** f, DdNode ** g) { DdNode *res; DdNode *F, *G; CUDD_VALUE_TYPE value; F = *f; G = *g; if (F == DD_ZERO(dd)) return(DD_ZERO(dd)); if (G == DD_ONE(dd)) return(F); if (cuddIsConstant(F) && cuddIsConstant(G)) { value = cuddV(F)/cuddV(G); res = cuddUniqueConst(dd,value); return(res); } return(NULL); } /* end of Cudd_addDivide */
/**Function******************************************************************** Synopsis [Natural logarithm of an ADD.] Description [Natural logarithm of an ADDs. Returns NULL if not a terminal case; log(f) otherwise. The discriminants of f must be positive double's.] SideEffects [None] SeeAlso [Cudd_addMonadicApply] ******************************************************************************/ DdNode * Cudd_addLog( DdManager * dd, DdNode * f) { if (cuddIsConstant(f)) { CUDD_VALUE_TYPE value = log(cuddV(f)); DdNode *res = cuddUniqueConst(dd,value); return(res); } return(NULL); } /* end of Cudd_addLog */
/** @brief Implements the recursive step of Cudd_addRoundOff. @return a pointer to the result. @sideeffect None */ DdNode * cuddAddRoundOffRecur( DdManager * dd, DdNode * f, double trunc) { DdNode *res, *fv, *fvn, *T, *E; double n; DD_CTFP1 cacheOp; statLine(dd); if (cuddIsConstant(f)) { n = ceil(cuddV(f)*trunc)/trunc; res = cuddUniqueConst(dd,n); return(res); } cacheOp = (DD_CTFP1) Cudd_addRoundOff; res = cuddCacheLookup1(dd,cacheOp,f); if (res != NULL) { return(res); } checkWhetherToGiveUp(dd); /* Recursive Step */ fv = cuddT(f); fvn = cuddE(f); T = cuddAddRoundOffRecur(dd,fv,trunc); if (T == NULL) { return(NULL); } cuddRef(T); E = cuddAddRoundOffRecur(dd,fvn,trunc); if (E == NULL) { Cudd_RecursiveDeref(dd,T); return(NULL); } cuddRef(E); res = (T == E) ? T : cuddUniqueInter(dd,(int)f->index,T,E); if (res == NULL) { Cudd_RecursiveDeref(dd,T); Cudd_RecursiveDeref(dd,E); return(NULL); } cuddDeref(T); cuddDeref(E); /* Store result. */ cuddCacheInsert1(dd,cacheOp,f,res); return(res); } /* end of cuddAddRoundOffRecur */
/**Function******************************************************************** Synopsis [Integer and floating point division.] Description [Integer and floating point division. Returns NULL if not a terminal case; f / g otherwise.] SideEffects [None] SeeAlso [Cudd_addApply] ******************************************************************************/ DdNode * Cudd_addDivide( DdManager * dd, DdNode ** f, DdNode ** g) { DdNode *res; DdNode *F, *G; CUDD_VALUE_TYPE value; F = *f; G = *g; /* We would like to use F == G -> F/G == 1, but F and G may ** contain zeroes. */ if (F == DD_ZERO(dd)) return(DD_ZERO(dd)); if (G == DD_ONE(dd)) return(F); if (cuddIsConstant(F) && cuddIsConstant(G)) { value = cuddV(F)/cuddV(G); res = cuddUniqueConst(dd,value); return(res); } return(NULL); } /* end of Cudd_addDivide */
/** @brief Implements the recursive step of Cudd_addNegate. @return a pointer to the result. @sideeffect None */ DdNode * cuddAddNegateRecur( DdManager * dd, DdNode * f) { DdNode *res, *fv, *fvn, *T, *E; statLine(dd); /* Check terminal cases. */ if (cuddIsConstant(f)) { res = cuddUniqueConst(dd,-cuddV(f)); return(res); } /* Check cache */ res = cuddCacheLookup1(dd,Cudd_addNegate,f); if (res != NULL) return(res); checkWhetherToGiveUp(dd); /* Recursive Step */ fv = cuddT(f); fvn = cuddE(f); T = cuddAddNegateRecur(dd,fv); if (T == NULL) return(NULL); cuddRef(T); E = cuddAddNegateRecur(dd,fvn); if (E == NULL) { Cudd_RecursiveDeref(dd,T); return(NULL); } cuddRef(E); res = (T == E) ? T : cuddUniqueInter(dd,(int)f->index,T,E); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } cuddDeref(T); cuddDeref(E); /* Store result. */ cuddCacheInsert1(dd,Cudd_addNegate,f,res); return(res); } /* end of cuddAddNegateRecur */
static void I_BDD_minterms_aux (DdManager * dd, DdNode * node, char *list, List * minterm_list) { DdNode *N, *Nv, *Nnv; int i, index; char *new_list; N = Cudd_Regular (node); if (cuddIsConstant (N)) { /* Terminal case: Print one cube based on the current recursion ** path, unless we have reached the background value (ADDs) or ** the logical zero (BDDs). */ if (node != dd->background && node != Cudd_Not (dd->one)) { if (!(new_list = (char *) malloc (sizeof (char) * dd->size))) I_punt ("I_BDD_minterms_aux: cannot allocate array"); for (i = 0; i < dd->size; i++) new_list[i] = list[i]; if (cuddV (node) != 1) I_punt ("I_BDD_minterms_aux: bad BDD"); *minterm_list = List_insert_last (*minterm_list, new_list); } } else { Nv = cuddT (N); Nnv = cuddE (N); if (Cudd_IsComplement (node)) { Nv = Cudd_Not (Nv); Nnv = Cudd_Not (Nnv); } index = N->index; list[index] = 0; I_BDD_minterms_aux (dd, Nnv, list, minterm_list); list[index] = 1; I_BDD_minterms_aux (dd, Nv, list, minterm_list); list[index] = 2; } return; }
/**Function******************************************************************** Synopsis [Performs the recursive step for Cudd_addBddIthBit.] Description [Performs the recursive step for Cudd_addBddIthBit. Returns a pointer to the BDD if successful; NULL otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static DdNode * addBddDoIthBit( DdManager * dd, DdNode * f, DdNode * index) { DdNode *res, *T, *E; DdNode *fv, *fvn; /* NuSMV: add begin */ ptrint mask, value; /* WAS: long mask, value; */ /* NuSMV: add end */ int v; statLine(dd); /* Check terminal case. */ if (cuddIsConstant(f)) { /* NuSMV: add begin */ mask = 1 << ((ptrint) cuddV(index)); value = (ptrint) cuddV(f); /* WAS: mask = 1 << ((long) cuddV(index)); value = (long) cuddV(f); */ /* NuSMV: add end */ return(Cudd_NotCond(DD_TRUE(dd),(value & mask) == 0)); } /* Check cache. */ res = cuddCacheLookup2(dd,addBddDoIthBit,f,index); if (res != NULL) return(res); /* Recursive step. */ v = f->index; fv = cuddT(f); fvn = cuddE(f); T = addBddDoIthBit(dd,fv,index); if (T == NULL) return(NULL); cuddRef(T); E = addBddDoIthBit(dd,fvn,index); if (E == NULL) { Cudd_RecursiveDeref(dd, T); return(NULL); } cuddRef(E); if (Cudd_IsComplement(T)) { res = (T == E) ? Cudd_Not(T) : cuddUniqueInter(dd,v,Cudd_Not(T),Cudd_Not(E)); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } res = Cudd_Not(res); } else { res = (T == E) ? T : cuddUniqueInter(dd,v,T,E); if (res == NULL) { Cudd_RecursiveDeref(dd, T); Cudd_RecursiveDeref(dd, E); return(NULL); } } cuddDeref(T); cuddDeref(E); /* Store result. */ cuddCacheInsert2(dd,addBddDoIthBit,f,index,res); return(res); } /* end of addBddDoIthBit */
/**Function******************************************************************** Synopsis [Performs the reordering-sensitive step of Extra_bddHaar().] Description [Generates in a bottom-up fashion an ADD for all spectral coefficients of the functions represented by a BDD.] SideEffects [] SeeAlso [] ******************************************************************************/ DdNode* extraBddHaar( DdManager * dd, /* the manager */ DdNode * bFunc, /* the function whose spectrum is being computed */ DdNode * bVars) /* the variables on which the function depends */ { DdNode * aRes; statLine(dd); /* terminal cases */ if ( bVars == b1 ) { assert( Cudd_IsConstant(bFunc) ); if ( bFunc == b0 ) return a0; else return a1; } /* check cache */ // if ( bFunc->ref != 1 ) if ( aRes = cuddCacheLookup2(dd, extraBddHaar, bFunc, bVars) ) return aRes; else { DdNode * bFunc0, * bFunc1; /* cofactors of the function */ DdNode * aHaar0, * aHaar1; /* partial solutions of the problem */ DdNode * aNode0, * aNode1; /* the special terminal nodes */ DdNode * aRes0, * aRes1; /* partial results to be composed by ITE */ DdNode * bFuncR = Cudd_Regular(bFunc); /* the regular pointer to the function */ DdNode * aTemp; double dValue0, dValue1; /* bFunc cannot depend on a variable that is not in bVars */ assert( cuddI(dd,bFuncR->index) >= cuddI(dd,bVars->index) ); /* cofactor the BDD */ if ( bFuncR->index == bVars->index ) { if ( bFuncR != bFunc ) /* bFunc is complemented */ { bFunc0 = Cudd_Not( cuddE(bFuncR) ); bFunc1 = Cudd_Not( cuddT(bFuncR) ); } else { bFunc0 = cuddE(bFuncR); bFunc1 = cuddT(bFuncR); } } else /* bVars is higher in the variable order */ bFunc0 = bFunc1 = bFunc; /* solve subproblems */ aHaar0 = extraBddHaar( dd, bFunc0, cuddT(bVars) ); if ( aHaar0 == NULL ) return NULL; cuddRef( aHaar0 ); aHaar1 = extraBddHaar( dd, bFunc1, cuddT(bVars) ); if ( aHaar1 == NULL ) { Cudd_RecursiveDeref( dd, aHaar0 ); return NULL; } cuddRef( aHaar1 ); /* retrieve the terminal values in aHaar0 and aHaar1 */ for ( aTemp = aHaar0; aTemp->index != CUDD_CONST_INDEX; aTemp = cuddE(aTemp) ); dValue0 = cuddV( aTemp ); for ( aTemp = aHaar1; aTemp->index != CUDD_CONST_INDEX; aTemp = cuddE(aTemp) ); dValue1 = cuddV( aTemp ); /* get the new terminal nodes */ aNode0 = cuddUniqueConst( dd, dValue0 + dValue1 ); if ( aNode0 == NULL ) { Cudd_RecursiveDeref( dd, aHaar0 ); Cudd_RecursiveDeref( dd, aHaar1 ); return NULL; } cuddRef( aNode0 ); aNode1 = cuddUniqueConst( dd, dValue0 - dValue1 ); if ( aNode1 == NULL ) { Cudd_RecursiveDeref( dd, aHaar0 ); Cudd_RecursiveDeref( dd, aHaar1 ); Cudd_RecursiveDeref( dd, aNode0 ); return NULL; } cuddRef( aNode1 ); /* replace the terminal nodes in the cofactor ADDs */ aRes0 = extraAddUpdateZeroCubeValue( dd, aHaar0, cuddT(bVars), aNode0 ); if ( aRes0 == NULL ) { Cudd_RecursiveDeref( dd, aHaar0 ); Cudd_RecursiveDeref( dd, aHaar1 ); Cudd_RecursiveDeref( dd, aNode0 ); Cudd_RecursiveDeref( dd, aNode1 ); return NULL; } cuddRef( aRes0 ); aRes1 = extraAddUpdateZeroCubeValue( dd, aHaar1, cuddT(bVars), aNode1 ); if ( aRes1 == NULL ) { Cudd_RecursiveDeref( dd, aHaar0 ); Cudd_RecursiveDeref( dd, aHaar1 ); Cudd_RecursiveDeref( dd, aNode0 ); Cudd_RecursiveDeref( dd, aNode1 ); Cudd_RecursiveDeref( dd, aRes0 ); return NULL; } cuddRef( aRes1 ); Cudd_RecursiveDeref(dd, aHaar0); Cudd_RecursiveDeref(dd, aHaar1); Cudd_RecursiveDeref(dd, aNode0); Cudd_RecursiveDeref(dd, aNode1); /* 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, bVars->index, aRes1, aRes0 ); if (aRes == NULL) { Cudd_RecursiveDeref(dd, aRes1); Cudd_RecursiveDeref(dd, aRes0); return NULL; } cuddDeref(aRes1); cuddDeref(aRes0); /* insert the result into cache */ // if ( bFunc->ref != 1 ) cuddCacheInsert2(dd, extraBddHaar, bFunc, bVars, aRes); return aRes; } } /* end of extraBddHaar */
/**Function******************************************************************** Synopsis [Main function for testcudd.] Description [] SideEffects [None] SeeAlso [] ******************************************************************************/ int main(int argc, char **argv) { FILE *fp; /* pointer to input file */ char *file = (char *) ""; /* input file name */ FILE *dfp = NULL; /* pointer to dump file */ char *dfile; /* file for DD dump */ DdNode *dfunc[2]; /* addresses of the functions to be dumped */ DdManager *dd; /* pointer to DD manager */ DdNode *_true; /* fast access to constant function */ DdNode *M; DdNode **x; /* pointers to variables */ DdNode **y; /* pointers to variables */ DdNode **xn; /* complements of row variables */ DdNode **yn_; /* complements of column variables */ DdNode **xvars; DdNode **yvars; DdNode *C; /* result of converting from ADD to BDD */ DdNode *ess; /* cube of essential variables */ DdNode *shortP; /* BDD cube of shortest path */ DdNode *largest; /* BDD of largest cube */ DdNode *shortA; /* ADD cube of shortest path */ DdNode *constN; /* value returned by evaluation of ADD */ DdNode *ycube; /* cube of the negated y vars for c-proj */ DdNode *CP; /* C-Projection of C */ DdNode *CPr; /* C-Selection of C */ int length; /* length of the shortest path */ int nx; /* number of variables */ int ny; int maxnx; int maxny; int m; int n; int N; int cmu; /* use CMU multiplication */ int pr; /* verbose printout level */ int harwell; int multiple; /* read multiple matrices */ int ok; int c; /* variable to read in options */ int approach; /* reordering approach */ int autodyn; /* automatic reordering */ int groupcheck; /* option for group sifting */ int profile; /* print heap profile if != 0 */ int keepperm; /* keep track of permutation */ int clearcache; /* clear the cache after each matrix */ int blifOrDot; /* dump format: 0 -> dot, 1 -> blif, ... */ int retval; /* return value */ int i; /* loop index */ long startTime; /* initial time */ long lapTime; int size; unsigned int cacheSize, maxMemory; unsigned int nvars,nslots; startTime = util_cpu_time(); approach = CUDD_REORDER_NONE; autodyn = 0; pr = 0; harwell = 0; multiple = 0; profile = 0; keepperm = 0; cmu = 0; N = 4; nvars = 4; cacheSize = 127; maxMemory = 0; nslots = CUDD_UNIQUE_SLOTS; clearcache = 0; groupcheck = CUDD_GROUP_CHECK7; dfile = NULL; blifOrDot = 0; /* dot format */ /* Parse command line. */ while ((c = util_getopt(argc, argv, (char *) "CDHMPS:a:bcd:g:hkmn:p:v:x:X:")) != EOF) { switch(c) { case 'C': cmu = 1; break; case 'D': autodyn = 1; break; case 'H': harwell = 1; break; case 'M': #ifdef MNEMOSYNE (void) mnem_setrecording(0); #endif break; case 'P': profile = 1; break; case 'S': nslots = atoi(util_optarg); break; case 'X': maxMemory = atoi(util_optarg); break; case 'a': approach = atoi(util_optarg); break; case 'b': blifOrDot = 1; /* blif format */ break; case 'c': clearcache = 1; break; case 'd': dfile = util_optarg; break; case 'g': groupcheck = atoi(util_optarg); break; case 'k': keepperm = 1; break; case 'm': multiple = 1; break; case 'n': N = atoi(util_optarg); break; case 'p': pr = atoi(util_optarg); break; case 'v': nvars = atoi(util_optarg); break; case 'x': cacheSize = atoi(util_optarg); break; case 'h': default: usage(argv[0]); break; } } if (argc - util_optind == 0) { file = (char *) "-"; } else if (argc - util_optind == 1) { file = argv[util_optind]; } else { usage(argv[0]); } if ((approach<0) || (approach>17)) { (void) fprintf(stderr,"Invalid approach: %d \n",approach); usage(argv[0]); } if (pr >= 0) { (void) printf("# %s\n", TESTCUDD_VERSION); /* Echo command line and arguments. */ (void) printf("#"); for (i = 0; i < argc; i++) { (void) printf(" %s", argv[i]); } (void) printf("\n"); (void) fflush(stdout); } /* Initialize manager and provide easy reference to terminals. */ dd = Cudd_Init(nvars,0,nslots,cacheSize,maxMemory); _true = DD_TRUE(dd); dd->groupcheck = (Cudd_AggregationType) groupcheck; if (autodyn) Cudd_AutodynEnable(dd,CUDD_REORDER_SAME); /* Open input file. */ fp = open_file(file, "r"); /* Open dump file if requested */ if (dfile != NULL) { dfp = open_file(dfile, "w"); } x = y = xn = yn_ = NULL; do { /* We want to start anew for every matrix. */ maxnx = maxny = 0; nx = maxnx; ny = maxny; if (pr>0) lapTime = util_cpu_time(); if (harwell) { if (pr >= 0) (void) printf(":name: "); ok = Cudd_addHarwell(fp, dd, &M, &x, &y, &xn, &yn_, &nx, &ny, &m, &n, 0, 2, 1, 2, pr); } else { ok = Cudd_addRead(fp, dd, &M, &x, &y, &xn, &yn_, &nx, &ny, &m, &n, 0, 2, 1, 2); if (pr >= 0) (void) printf(":name: %s: %d rows %d columns\n", file, m, n); } if (!ok) { (void) fprintf(stderr, "Error reading matrix\n"); exit(1); } if (nx > maxnx) maxnx = nx; if (ny > maxny) maxny = ny; /* Build cube of negated y's. */ ycube = DD_TRUE(dd); Cudd_Ref(ycube); for (i = maxny - 1; i >= 0; i--) { DdNode *tmpp; tmpp = Cudd_bddAnd(dd,Cudd_Not(dd->vars[y[i]->index]),ycube); if (tmpp == NULL) exit(2); Cudd_Ref(tmpp); Cudd_RecursiveDeref(dd,ycube); ycube = tmpp; } /* Initialize vectors of BDD variables used by priority func. */ xvars = ALLOC(DdNode *, nx); if (xvars == NULL) exit(2); for (i = 0; i < nx; i++) { xvars[i] = dd->vars[x[i]->index]; } yvars = ALLOC(DdNode *, ny); if (yvars == NULL) exit(2); for (i = 0; i < ny; i++) { yvars[i] = dd->vars[y[i]->index]; } /* Clean up */ for (i=0; i < maxnx; i++) { Cudd_RecursiveDeref(dd, x[i]); Cudd_RecursiveDeref(dd, xn[i]); } FREE(x); FREE(xn); for (i=0; i < maxny; i++) { Cudd_RecursiveDeref(dd, y[i]); Cudd_RecursiveDeref(dd, yn_[i]); } FREE(y); FREE(yn_); if (pr>0) {(void) printf(":1: M"); Cudd_PrintDebug(dd,M,nx+ny,pr);} if (pr>0) (void) printf(":2: time to read the matrix = %s\n", util_print_time(util_cpu_time() - lapTime)); C = Cudd_addBddPattern(dd, M); if (C == 0) exit(2); Cudd_Ref(C); if (pr>0) {(void) printf(":3: C"); Cudd_PrintDebug(dd,C,nx+ny,pr);} /* Test iterators. */ retval = testIterators(dd,M,C,pr); if (retval == 0) exit(2); cuddCacheProfile(dd,stdout); /* Test XOR */ retval = testXor(dd,C,pr,nx+ny); if (retval == 0) exit(2); /* Test Hamming distance functions. */ retval = testHamming(dd,C,pr); if (retval == 0) exit(2); /* Test selection functions. */ CP = Cudd_CProjection(dd,C,ycube); if (CP == NULL) exit(2); Cudd_Ref(CP); if (pr>0) {(void) printf("ycube"); Cudd_PrintDebug(dd,ycube,nx+ny,pr);} if (pr>0) {(void) printf("CP"); Cudd_PrintDebug(dd,CP,nx+ny,pr);} if (nx == ny) { CPr = Cudd_PrioritySelect(dd,C,xvars,yvars,(DdNode **)NULL, (DdNode *)NULL,ny,Cudd_Xgty); if (CPr == NULL) exit(2); Cudd_Ref(CPr); if (pr>0) {(void) printf(":4: CPr"); Cudd_PrintDebug(dd,CPr,nx+ny,pr);} if (CP != CPr) { (void) printf("CP != CPr!\n"); } Cudd_RecursiveDeref(dd, CPr); } FREE(xvars); FREE(yvars); Cudd_RecursiveDeref(dd, CP); Cudd_RecursiveDeref(dd, ycube); /* Test functions for essential variables. */ ess = Cudd_FindEssential(dd,C); if (ess == NULL) exit(2); Cudd_Ref(ess); if (pr>0) {(void) printf(":4: ess"); Cudd_PrintDebug(dd,ess,nx+ny,pr);} Cudd_RecursiveDeref(dd, ess); /* Test functions for shortest paths. */ shortP = Cudd_ShortestPath(dd, M, NULL, NULL, &length); if (shortP == NULL) exit(2); Cudd_Ref(shortP); if (pr>0) { (void) printf(":5: shortP"); Cudd_PrintDebug(dd,shortP,nx+ny,pr); } /* Test functions for largest cubes. */ largest = Cudd_LargestCube(dd, Cudd_Not(C), &length); if (largest == NULL) exit(2); Cudd_Ref(largest); if (pr>0) { (void) printf(":5b: largest"); Cudd_PrintDebug(dd,largest,nx+ny,pr); } Cudd_RecursiveDeref(dd, largest); /* Test Cudd_addEvalConst and Cudd_addIteConstant. */ shortA = Cudd_BddToAdd(dd,shortP); if (shortA == NULL) exit(2); Cudd_Ref(shortA); Cudd_RecursiveDeref(dd, shortP); constN = Cudd_addEvalConst(dd,shortA,M); if (constN == DD_NON_CONSTANT) exit(2); if (Cudd_addIteConstant(dd,shortA,M,constN) != constN) exit(2); if (pr>0) {(void) printf("The value of M along the chosen shortest path is %g\n", cuddV(constN));} Cudd_RecursiveDeref(dd, shortA); shortP = Cudd_ShortestPath(dd, C, NULL, NULL, &length); if (shortP == NULL) exit(2); Cudd_Ref(shortP); if (pr>0) { (void) printf(":6: shortP"); Cudd_PrintDebug(dd,shortP,nx+ny,pr); } /* Test Cudd_bddIteConstant and Cudd_bddLeq. */ if (!Cudd_bddLeq(dd,shortP,C)) exit(2); if (Cudd_bddIteConstant(dd,Cudd_Not(shortP),_true,C) != _true) exit(2); Cudd_RecursiveDeref(dd, shortP); if (profile) { retval = cuddHeapProfile(dd); } size = dd->size; if (pr>0) { (void) printf("Average distance: %g\n", Cudd_AverageDistance(dd)); } /* Reorder if so requested. */ if (approach != CUDD_REORDER_NONE) { #ifndef DD_STATS retval = Cudd_EnableReorderingReporting(dd); if (retval == 0) { (void) fprintf(stderr,"Error reported by Cudd_EnableReorderingReporting\n"); exit(3); } #endif #ifdef DD_DEBUG retval = Cudd_DebugCheck(dd); if (retval != 0) { (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n"); exit(3); } retval = Cudd_CheckKeys(dd); if (retval != 0) { (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n"); exit(3); } #endif retval = Cudd_ReduceHeap(dd,(Cudd_ReorderingType)approach,5); if (retval == 0) { (void) fprintf(stderr,"Error reported by Cudd_ReduceHeap\n"); exit(3); } #ifndef DD_STATS retval = Cudd_DisableReorderingReporting(dd); if (retval == 0) { (void) fprintf(stderr,"Error reported by Cudd_DisableReorderingReporting\n"); exit(3); } #endif #ifdef DD_DEBUG retval = Cudd_DebugCheck(dd); if (retval != 0) { (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n"); exit(3); } retval = Cudd_CheckKeys(dd); if (retval != 0) { (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n"); exit(3); } #endif if (approach == CUDD_REORDER_SYMM_SIFT || approach == CUDD_REORDER_SYMM_SIFT_CONV) { Cudd_SymmProfile(dd,0,dd->size-1); } if (pr>0) { (void) printf("Average distance: %g\n", Cudd_AverageDistance(dd)); } if (keepperm) { /* Print variable permutation. */ (void) printf("Variable Permutation:"); for (i=0; i<size; i++) { if (i%20 == 0) (void) printf("\n"); (void) printf("%d ", dd->invperm[i]); } (void) printf("\n"); (void) printf("Inverse Permutation:"); for (i=0; i<size; i++) { if (i%20 == 0) (void) printf("\n"); (void) printf("%d ", dd->perm[i]); } (void) printf("\n"); } if (pr>0) {(void) printf("M"); Cudd_PrintDebug(dd,M,nx+ny,pr);} if (profile) { retval = cuddHeapProfile(dd); } } /* Dump DDs of C and M if so requested. */ if (dfile != NULL) { dfunc[0] = C; dfunc[1] = M; if (blifOrDot == 1) { /* Only dump C because blif cannot handle ADDs */ retval = Cudd_DumpBlif(dd,1,dfunc,NULL,(char **)onames, NULL,dfp); } else { retval = Cudd_DumpDot(dd,2,dfunc,NULL,(char **)onames,dfp); } if (retval != 1) { (void) fprintf(stderr,"abnormal termination\n"); exit(2); } } Cudd_RecursiveDeref(dd, C); Cudd_RecursiveDeref(dd, M); if (clearcache) { if (pr>0) {(void) printf("Clearing the cache... ");} for (i = dd->cacheSlots - 1; i>=0; i--) { dd->cache[i].data = NIL(DdNode); } if (pr>0) {(void) printf("done\n");} } if (pr>0) { (void) printf("Number of variables = %6d\t",dd->size); (void) printf("Number of slots = %6d\n",dd->slots); (void) printf("Number of keys = %6d\t",dd->keys); (void) printf("Number of min dead = %6d\n",dd->minDead); } } while (multiple && !feof(fp)); fclose(fp); if (dfile != NULL) { fclose(dfp); } /* Second phase: experiment with Walsh matrices. */ if (!testWalsh(dd,N,cmu,approach,pr)) { exit(2); } /* Check variable destruction. */ assert(cuddDestroySubtables(dd,3)); assert(Cudd_DebugCheck(dd) == 0); assert(Cudd_CheckKeys(dd) == 0); retval = Cudd_CheckZeroRef(dd); ok = retval != 0; /* ok == 0 means O.K. */ if (retval != 0) { (void) fprintf(stderr, "%d non-zero DD reference counts after dereferencing\n", retval); } if (pr >= 0) { (void) Cudd_PrintInfo(dd,stdout); } Cudd_Quit(dd); #ifdef MNEMOSYNE mnem_writestats(); #endif if (pr>0) (void) printf("total time = %s\n", util_print_time(util_cpu_time() - startTime)); if (pr >= 0) util_print_cpu_stats(stdout); exit(ok); /* NOTREACHED */ } /* end of main */
/**Function******************************************************************** Synopsis [Performs the recursive step of Cudd_MinHammingDist.] Description [Performs the recursive step of Cudd_MinHammingDist. It is based on the following identity. Let H(f) be the minimum Hamming distance of the minterms of f from the reference minterm. Then: <xmp> H(f) = min(H(f0)+h0,H(f1)+h1) </xmp> where f0 and f1 are the two cofactors of f with respect to its top variable; h0 is 1 if the minterm assigns 1 to the top variable of f; h1 is 1 if the minterm assigns 0 to the top variable of f. The upper bound on the distance is used to bound the depth of the recursion. Returns the minimum distance unless it exceeds the upper bound or computation fails.] SideEffects [None] SeeAlso [Cudd_MinHammingDist] ******************************************************************************/ static int cuddMinHammingDistRecur( DdNode * f, int *minterm, DdHashTable * table, int upperBound) { DdNode *F, *Ft, *Fe; double h, hT, hE; DdNode *zero, *res; DdManager *dd = table->manager; statLine(dd); if (upperBound == 0) return(0); F = Cudd_Regular(f); if (cuddIsConstant(F)) { zero = Cudd_Not(DD_ONE(dd)); if (f == dd->background || f == zero) { return(upperBound); } else { return(0); } } if ((res = cuddHashTableLookup1(table,f)) != NULL) { //Rob Apr 6 2001: might need to change this, not sure what it does..... h = (*cuddV(res)).get_val(); if (res->ref == 0) { dd->dead++; dd->constants.dead++; } return((int) h); } Ft = cuddT(F); Fe = cuddE(F); if (Cudd_IsComplement(f)) { Ft = Cudd_Not(Ft); Fe = Cudd_Not(Fe); } if (minterm[F->index] == 0) { DdNode *temp = Ft; Ft = Fe; Fe = temp; } hT = cuddMinHammingDistRecur(Ft,minterm,table,upperBound); if (hT == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM); if (hT == 0) { hE = upperBound; } else { hE = cuddMinHammingDistRecur(Fe,minterm,table,upperBound - 1); if (hE == CUDD_OUT_OF_MEM) return(CUDD_OUT_OF_MEM); } h = ddMin(hT, hE + 1); if (F->ref != 1) { ptrint fanout = (ptrint) F->ref; cuddSatDec(fanout); Terminal hTerminal; hTerminal.set((double) h); res = cuddUniqueConst(dd,&hTerminal); //res = cuddUniqueConst(dd, (CUDD_VALUE_TYPE) h); if (!cuddHashTableInsert1(table,f,res,fanout)) { cuddRef(res); Cudd_RecursiveDeref(dd, res); return(CUDD_OUT_OF_MEM); } } return((int) h); } /* end of cuddMinHammingDistRecur */
/**Function************************************************************* Synopsis [Transfers the DD into the internal reordering data structure.] Description [It is important that the hash table is lossless.] SideEffects [] SeeAlso [] ***********************************************************************/ reo_unit * reoTransferNodesToUnits_rec( reo_man * p, DdNode * F ) { DdManager * dd = p->dd; reo_unit * pUnit; int HKey, fComp; fComp = Cudd_IsComplement(F); F = Cudd_Regular(F); // check the hash-table if ( F->ref != 1 ) { // search cache - use linear probing for ( HKey = hashKey2(p->Signature,F,p->nTableSize); p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize ) if ( p->HTable[HKey].Arg1 == (reo_unit *)F ) { pUnit = p->HTable[HKey].Arg2; assert( pUnit ); // increment the edge counter pUnit->n++; return Unit_NotCond( pUnit, fComp ); } } // the entry in not found in the cache // create a new entry pUnit = reoUnitsGetNextUnit( p ); pUnit->n = 1; if ( cuddIsConstant(F) ) { pUnit->lev = REO_CONST_LEVEL; pUnit->pE = (reo_unit*)((int)(cuddV(F))); pUnit->pT = NULL; // check if the diagram that is being reordering has complement edges if ( F != dd->one ) p->fThisIsAdd = 1; // insert the unit into the corresponding plane reoUnitsAddUnitToPlane( &(p->pPlanes[p->nSupp]), pUnit ); // increments the unit counter } else { pUnit->lev = p->pMapToPlanes[F->index]; pUnit->pE = reoTransferNodesToUnits_rec( p, cuddE(F) ); pUnit->pT = reoTransferNodesToUnits_rec( p, cuddT(F) ); // insert the unit into the corresponding plane reoUnitsAddUnitToPlane( &(p->pPlanes[pUnit->lev]), pUnit ); // increments the unit counter } // add to the hash table if ( F->ref != 1 ) { // the next free entry is already found - it is pointed to by HKey // while we traversed the diagram, the hash entry to which HKey points, // might have been used. Make sure that its signature is different. for ( ; p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize ); p->HTable[HKey].Sign = p->Signature; p->HTable[HKey].Arg1 = (reo_unit *)F; p->HTable[HKey].Arg2 = pUnit; } // increment the counter of nodes p->nNodesCur++; return Unit_NotCond( pUnit, fComp ); }
/**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 [Performs the recursive step of Cudd_bddTransfer.] Description [Performs the recursive step of Cudd_bddTransfer. Returns a pointer to the result if successful; NULL otherwise.] SideEffects [None] SeeAlso [cuddauxAddTransfer] ******************************************************************************/ static DdNode * cuddauxAddTransferRecur( DdManager * ddS, DdManager * ddD, DdNode * f, st_table * table) { DdNode *ft, *fe, *t, *e, *var, *res; DdNode *one, *zero; int index; /* Trivial cases. */ if (cuddIsConstant(f)){ double v = cuddV(f); return (cuddUniqueConst(ddD,v)); } /* Check the cache. */ if(st_lookup(table, f, &res)) return(res); /* Recursive step. */ index = f->index; ft = cuddT(f); fe = cuddE(f); t = cuddauxAddTransferRecur(ddS, ddD, ft, table); if (t == NULL) { return(NULL); } cuddRef(t); e = cuddauxAddTransferRecur(ddS, ddD, fe, table); if (e == NULL) { Cudd_RecursiveDeref(ddD, t); return(NULL); } cuddRef(e); one = DD_ONE(ddD); zero = Cudd_Not(one); var = cuddUniqueInter(ddD,index,one,zero); if (var == NULL) { Cudd_RecursiveDeref(ddD, t); Cudd_RecursiveDeref(ddD, e); return(NULL); } res = cuddauxAddIteRecur(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(res); } /* end of cuddauxAddTransferRecur */
/**Function******************************************************************** Synopsis [Performs the reordering-sensitive step of Extra_bddHaarInverse().] Description [Generates in a bottom-up fashion an ADD for the inverse Haar.] SideEffects [The third cached argument (bSteps) is the BDD of the elementary variable whose index equal to the number of lazy steps made thus far plus one. On the top-most level it is 0, next it is 1, etc.] SeeAlso [] ******************************************************************************/ DdNode * extraBddHaarInverse( DdManager * dd, /* the manager */ DdNode * aFunc, /* the function whose spectrum is being computed */ DdNode * aSteps, /* the index of this variable indicates the number of previous lazy recursive calls */ DdNode * bVars, /* the variables, on which the function depends */ DdNode * bVarsAll, /* the set of all variables, which will never change through the calls */ int nVarsAll, /* the number of vars in the set */ int * InverseMap ) /* the variable map mapping the var index into its inverse var index */ { DdNode * aRes; DdNode * bCacheCube; statLine(dd); /* terminal cases */ if ( bVars == b1 ) { // return a terminal node with a value equal to cuddV(aFunc) * 2^(nSteps-1) if ( cuddV(aSteps) == 0.0 ) return cuddUniqueConst( dd, cuddV(aFunc) ); else return cuddUniqueConst( dd, cuddV(aFunc) * Extra_Power2( (int)(cuddV(aSteps)-1) ) ); } /* check cache */ /* the last two arguments are derivitives, therefore there are useless for caching */ /* the other two arguments (bVars and bVarsAll) can be combined into one argument */ bCacheCube = extraCachingCube( dd, bVarsAll, bVars ); Cudd_Ref( bCacheCube ); if ( aRes = cuddCacheLookup(dd, DD_ADD_HAAR_INVERSE_TAG, aFunc, aSteps, bCacheCube) ) { Cudd_RecursiveDeref( dd, bCacheCube ); return aRes; } else { DdNode * aFunc0, * aFunc1; /* cofactors of the function */ DdNode * aInvH0, * aInvH1; /* partial solutions of the problem */ DdNode * aRes0, * aRes1; /* partial results to be composed by ITE */ DdNode * aStepNext; /* aFunc cannot depend on a variable that is not in bVars */ assert( cuddI(dd,aFunc->index) >= cuddI(dd,bVars->index) ); /* cofactor the ADD */ if ( aFunc->index == bVars->index ) { aFunc0 = cuddE(aFunc); aFunc1 = cuddT(aFunc); } else /* bVars is higher in the variable order */ aFunc0 = aFunc1 = aFunc; if ( cuddV(aSteps) > 0.0 ) /* meaning that it is a lazy call */ { /* solve subproblems */ aStepNext = cuddUniqueConst( dd, cuddV(aSteps)+1 ); if ( aStepNext == NULL ) return NULL; cuddRef( aStepNext ); aInvH0 = extraBddHaarInverse( dd, aFunc0, aStepNext, cuddT(bVars), bVarsAll, nVarsAll, InverseMap ); if ( aInvH0 == NULL ) { Cudd_RecursiveDeref( dd, aStepNext ); return NULL; } cuddRef( aInvH0 ); aInvH1 = extraBddHaarInverse( dd, aFunc1, aStepNext, cuddT(bVars), bVarsAll, nVarsAll, InverseMap ); if ( aInvH1 == NULL ) { Cudd_RecursiveDeref( dd, aStepNext ); Cudd_RecursiveDeref( dd, aInvH0 ); return NULL; } cuddRef( aInvH1 ); Cudd_RecursiveDeref( dd, aStepNext ); aRes0 = aInvH0; aRes1 = aInvH1; } else // if ( cuddV(aSteps) == 0.0 ) { /* solve subproblems */ aInvH0 = extraBddHaarInverse( dd, aFunc0, aSteps, cuddT(bVars), bVarsAll, nVarsAll, InverseMap ); if ( aInvH0 == NULL ) return NULL; cuddRef( aInvH0 ); aStepNext = cuddUniqueConst( dd, 1.0 ); if ( aStepNext == NULL ) { Cudd_RecursiveDeref( dd, aInvH0 ); return NULL; } cuddRef( aStepNext ); aInvH1 = extraBddHaarInverse( dd, aFunc1, aStepNext, cuddT(bVars), bVarsAll, nVarsAll, InverseMap ); if ( aInvH1 == NULL ) { Cudd_RecursiveDeref( dd, aStepNext ); Cudd_RecursiveDeref( dd, aInvH0 ); return NULL; } cuddRef( aInvH1 ); Cudd_RecursiveDeref( dd, aStepNext ); /* compute aRes0 = aWalsh0 + aWalsh1 */ aRes0 = cuddAddApplyRecur( dd, Cudd_addPlus, aInvH0, aInvH1 ); if ( aRes0 == NULL ) { Cudd_RecursiveDeref( dd, aInvH0 ); Cudd_RecursiveDeref( dd, aInvH1 ); return NULL; } cuddRef( aRes0 ); /* compute aRes1 = aWalsh0 - aWalsh1 */ aRes1 = cuddAddApplyRecur( dd, Cudd_addMinus, aInvH0, aInvH1 ); if ( aRes1 == NULL ) { Cudd_RecursiveDeref( dd, aInvH0 ); Cudd_RecursiveDeref( dd, aInvH1 ); Cudd_RecursiveDeref( dd, aRes0 ); return NULL; } cuddRef( aRes1 ); Cudd_RecursiveDeref(dd, aInvH0); Cudd_RecursiveDeref(dd, aInvH1); } /* only aRes0 and aRes1 are referenced at this point */ /* consider the case when Res0 and Res1 are the same node */ aRes = extraAddIteRecurGeneral( dd, dd->vars[ InverseMap[bVars->index] ], aRes1, aRes0 ); if (aRes == NULL) { Cudd_RecursiveDeref(dd, aRes1); Cudd_RecursiveDeref(dd, aRes0); return NULL; } cuddRef( aRes ); Cudd_RecursiveDeref(dd, aRes1); Cudd_RecursiveDeref(dd, aRes0); cuddDeref( aRes ); /* insert the result into cache */ cuddCacheInsert(dd, DD_ADD_HAAR_INVERSE_TAG, aFunc, aSteps, bCacheCube, aRes); Cudd_RecursiveDeref( dd, bCacheCube ); return aRes; } } /* end of extraBddHaarInverse */
/**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_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 [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 */