/**Function************************************************************* Synopsis [Prints one row of the latch dependency matrix.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ void Extra_bddImagePrintLatchDependencyOne( DdManager * dd, DdNode * bFunc, // the function DdNode * bVarsCs, DdNode * bVarsNs, // the current/next state vars int iPart ) { DdNode * bSupport; int v; bSupport = Cudd_Support( dd, bFunc ); Cudd_Ref( bSupport ); printf( " %3d : ", iPart ); for ( v = 0; v < dd->size; v++ ) { if ( Cudd_bddLeq( dd, bSupport, dd->vars[v] ) ) { if ( Cudd_bddLeq( dd, bVarsCs, dd->vars[v] ) ) printf( "c" ); else if ( Cudd_bddLeq( dd, bVarsNs, dd->vars[v] ) ) printf( "n" ); else printf( "i" ); } else printf( "." ); } printf( "\n" ); Cudd_RecursiveDeref( dd, bSupport ); }
Vec_IntForEachEntry( vNodes, Entry, i ) { if ( Entry != 0 && Entry != 1 ) continue; pObj = Aig_ManObj( p, i ); bFunc = Llb_ManComputeIndCase_rec( p, pObj, dd, vBdds ); if ( Entry == 0 ) { // Extra_bddPrint( dd, Cudd_Not(pObj->pData) ); printf( "\n" ); // Extra_bddPrint( dd, Cudd_Not(bFunc) ); printf( "\n" ); if ( !Cudd_bddLeq( dd, Cudd_Not(pObj->pData), Cudd_Not(bFunc) ) ) Vec_IntWriteEntry( vNodes, i, -1 ); } else if ( Entry == 1 ) { // Extra_bddPrint( dd, pObj->pData ); printf( "\n" ); // Extra_bddPrint( dd, bFunc ); printf( "\n" ); if ( !Cudd_bddLeq( dd, (DdNode *)pObj->pData, bFunc ) ) Vec_IntWriteEntry( vNodes, i, -1 ); } }
/**Function******************************************************************** Synopsis [Checks whether a variable is dependent on others in a function.] Description [Checks whether a variable is dependent on others in a function. Returns 1 if the variable is dependent; 0 otherwise. No new nodes are created.] SideEffects [None] SeeAlso [] ******************************************************************************/ int Cudd_bddVarIsDependent( DdManager *dd, /* manager */ DdNode *f, /* function */ DdNode *var /* variable */) { DdNode *F, *res, *zero, *ft, *fe; unsigned topf, level; DD_CTFP cacheOp; int retval; /* NuSMV: begin add */ abort(); /* NOT USED BY NUSMV */ /* NuSMV: begin end */ zero = Cudd_Not(DD_TRUE(dd)); if (Cudd_IsConstant(f)) return(f == zero); /* From now on f is not constant. */ F = Cudd_Regular(f); topf = (unsigned) dd->perm[F->index]; level = (unsigned) dd->perm[var->index]; /* Check terminal case. If topf > index of var, f does not depend on var. ** Therefore, var is not dependent in f. */ if (topf > level) { return(0); } cacheOp = (DD_CTFP) Cudd_bddVarIsDependent; res = cuddCacheLookup2(dd,cacheOp,f,var); if (res != NULL) { return(res != zero); } /* Compute cofactors. */ ft = Cudd_NotCond(cuddT(F), f != F); fe = Cudd_NotCond(cuddE(F), f != F); if (topf == level) { retval = Cudd_bddLeq(dd,ft,Cudd_Not(fe)); } else { retval = Cudd_bddVarIsDependent(dd,ft,var) && Cudd_bddVarIsDependent(dd,fe,var); } cuddCacheInsert2(dd,cacheOp,f,var,Cudd_NotCond(zero,retval)); return(retval); } /* Cudd_bddVarIsDependent */
/**Function******************************************************************** Synopsis [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 */
/** @brief Implements the recursive step of Cudd_bddClippingAnd. @details Takes the conjunction of two BDDs. @return a pointer to the result is successful; NULL otherwise. @sideeffect None @see cuddBddClippingAnd */ static DdNode * cuddBddClippingAndRecur( DdManager * manager, DdNode * f, DdNode * g, int distance, int direction) { DdNode *F, *ft, *fe, *G, *gt, *ge; DdNode *one, *zero, *r, *t, *e; int topf, topg; unsigned int index; DD_CTFP cacheOp; statLine(manager); one = DD_ONE(manager); zero = Cudd_Not(one); /* Terminal cases. */ if (f == zero || g == zero || f == Cudd_Not(g)) return(zero); if (f == g || g == one) return(f); if (f == one) return(g); if (distance == 0) { /* One last attempt at returning the right result. We sort of ** cheat by calling Cudd_bddLeq. */ if (Cudd_bddLeq(manager,f,g)) return(f); if (Cudd_bddLeq(manager,g,f)) return(g); if (direction == 1) { if (Cudd_bddLeq(manager,f,Cudd_Not(g)) || Cudd_bddLeq(manager,g,Cudd_Not(f))) return(zero); } return(Cudd_NotCond(one,(direction == 0))); } /* At this point f and g are not constant. */ distance--; /* Check cache. Try to increase cache efficiency by sorting the ** pointers. */ if (f > g) { DdNode *tmp = f; f = g; g = tmp; } F = Cudd_Regular(f); G = Cudd_Regular(g); cacheOp = (DD_CTFP) (direction ? Cudd_bddClippingAnd : cuddBddClippingAnd); if (F->ref != 1 || G->ref != 1) { r = cuddCacheLookup2(manager, cacheOp, f, g); if (r != NULL) return(r); } checkWhetherToGiveUp(manager); /* Here we can skip the use of cuddI, because the operands are known ** to be non-constant. */ topf = manager->perm[F->index]; topg = manager->perm[G->index]; /* Compute cofactors. */ if (topf <= topg) { index = F->index; ft = cuddT(F); fe = cuddE(F); if (Cudd_IsComplement(f)) { ft = Cudd_Not(ft); fe = Cudd_Not(fe); } } else { index = G->index; ft = fe = f; } if (topg <= topf) { gt = cuddT(G); ge = cuddE(G); if (Cudd_IsComplement(g)) { gt = Cudd_Not(gt); ge = Cudd_Not(ge); } } else { gt = ge = g; } t = cuddBddClippingAndRecur(manager, ft, gt, distance, direction); if (t == NULL) return(NULL); cuddRef(t); e = cuddBddClippingAndRecur(manager, fe, ge, distance, direction); if (e == NULL) { Cudd_RecursiveDeref(manager, t); return(NULL); } cuddRef(e); if (t == e) { r = t; } else { if (Cudd_IsComplement(t)) { r = cuddUniqueInter(manager,(int)index,Cudd_Not(t),Cudd_Not(e)); if (r == NULL) { Cudd_RecursiveDeref(manager, t); Cudd_RecursiveDeref(manager, e); return(NULL); } r = Cudd_Not(r); } else { r = cuddUniqueInter(manager,(int)index,t,e); if (r == NULL) { Cudd_RecursiveDeref(manager, t); Cudd_RecursiveDeref(manager, e); return(NULL); } } } cuddDeref(e); cuddDeref(t); if (F->ref != 1 || G->ref != 1) cuddCacheInsert2(manager, cacheOp, f, g, r); return(r); } /* end of cuddBddClippingAndRecur */
/**Function******************************************************************** Synopsis [Determines whether f is less than or equal to g.] Description [Returns 1 if f is less than or equal to g; 0 otherwise. No new nodes are created.] SideEffects [None] SeeAlso [Cudd_bddIteConstant Cudd_addEvalConst] ******************************************************************************/ int Cudd_bddLeq( DdManager * dd, DdNode * f, DdNode * g) { DdNode *one, *zero, *tmp, *F, *fv, *fvn, *gv, *gvn; unsigned int topf, topg, res; statLine(dd); /* Terminal cases and normalization. */ if (f == g) return(1); if (Cudd_IsComplement(g)) { /* Special case: if f is regular and g is complemented, ** f(1,...,1) = 1 > 0 = g(1,...,1). */ if (!Cudd_IsComplement(f)) return(0); /* Both are complemented: Swap and complement because ** f <= g <=> g' <= f' and we want the second argument to be regular. */ tmp = g; g = Cudd_Not(f); f = Cudd_Not(tmp); } else if (Cudd_IsComplement(f) && cuddF2L(g) < cuddF2L(f)) { tmp = g; g = Cudd_Not(f); f = Cudd_Not(tmp); } /* Now g is regular and, if f is not regular, f < g. */ one = DD_ONE(dd); if (g == one) return(1); /* no need to test against zero */ if (f == one) return(0); /* since at this point g != one */ if (Cudd_Not(f) == g) return(0); /* because neither is constant */ zero = Cudd_Not(one); if (f == zero) return(1); /* Here neither f nor g is constant. */ /* Check cache. */ tmp = cuddCacheLookup2(dd,(DD_CTFP)Cudd_bddLeq,f,g); if (tmp != NULL) { return(tmp == one); } /* Compute cofactors. */ F = Cudd_Regular(f); topf = dd->perm[F->index]; topg = dd->perm[g->index]; if (topf <= topg) { fv = cuddT(F); fvn = cuddE(F); if (f != F) { fv = Cudd_Not(fv); fvn = Cudd_Not(fvn); } } else { fv = fvn = f; } if (topg <= topf) { gv = cuddT(g); gvn = cuddE(g); } else { gv = gvn = g; } /* Recursive calls. Since we want to maximize the probability of ** the special case f(1,...,1) > g(1,...,1), we consider the negative ** cofactors first. Indeed, the complementation parity of the positive ** cofactors is the same as the one of the parent functions. */ res = Cudd_bddLeq(dd,fvn,gvn) && Cudd_bddLeq(dd,fv,gv); /* Store result in cache and return. */ cuddCacheInsert2(dd,(DD_CTFP)Cudd_bddLeq,f,g,(res ? one : zero)); return(res); } /* end of Cudd_bddLeq */
/** * @brief Basic test of timeout handler. * * @details Sets a short timeout and then tries to build a function * with a large BDD. Strives to avoid leaking nodes. * * @return 0 if successful; -1 otherwise. */ static int testTimeout(int verbosity) { DdManager *dd; /* Declare these "volatile" to prevent clobbering by longjmp. */ DdNode * volatile f; DdNode * volatile clause = NULL; DdNode * var1, * var2; int i, ret, count; int const N = 20; /* half the number of variables in f */ unsigned long timeout = 100UL; /* in milliseconds */ jmp_buf timeoutEnv; dd = Cudd_Init(0, 0, CUDD_UNIQUE_SLOTS, CUDD_CACHE_SLOTS, 0); if (!dd) { if (verbosity) { printf("initialization failed\n"); } return -1; } /* Set up timeout handling. */ if (setjmp(timeoutEnv) > 0) { if (verbosity) { printf("caught timeout\n"); } /* The nodes of clause may be leaked if the timeout was * detected while conjoining the clause to f. We set * clause to NULL when it's not in use to be able to * detect this case. */ if (clause) Cudd_RecursiveDeref(dd, clause); goto finally; } (void) Cudd_RegisterTimeoutHandler(dd, timeoutHandler, (void *) &timeoutEnv); (void) Cudd_SetTimeLimit(dd, timeout); /* Try to build function. This is expected to run out of time. */ f = Cudd_ReadOne(dd); Cudd_Ref(f); for (i = 0; i < N; i++) { DdNode * tmp; var1 = Cudd_bddIthVar(dd, i); if (!var1) { if (verbosity) { printf("computation failed\n"); return -1; } } var2 = Cudd_bddIthVar(dd, i+N); if (!var2) { if (verbosity) { printf("computation failed\n"); return -1; } } clause = Cudd_bddOr(dd, var1, var2); if (!clause) { if (verbosity) { printf("computation failed\n"); } return -1; } Cudd_Ref(clause); tmp = Cudd_bddAnd(dd, f, clause); if (!tmp) { if (verbosity) { printf("computation failed\n"); } return -1; } Cudd_Ref(tmp); Cudd_RecursiveDeref(dd, clause); clause = NULL; Cudd_RecursiveDeref(dd, f); f = tmp; } if (verbosity > 1) { Cudd_bddPrintCover(dd, f, f); } finally: if (verbosity) { printf("so far"); Cudd_PrintSummary(dd, f, 2*N, 0); } count = 0; for (i = 0; i < N-1; i += 2) { var1 = Cudd_bddIthVar(dd, i); if (!var1) { printf("computation failed\n"); return -1; } var2 = Cudd_bddIthVar(dd, i+1); if (!var2) { printf("computation failed\n"); return -1; } clause = Cudd_bddOr(dd, var1, var2); if (!clause) { printf("computation failed\n"); return -1; } Cudd_Ref(clause); if (Cudd_bddLeq(dd, f, clause)) { count++; } Cudd_RecursiveDeref(dd, clause); } if (verbosity) { printf("f implies %d clauses\n", count); } Cudd_RecursiveDeref(dd, f); ret = Cudd_CheckZeroRef(dd); if (verbosity) { Cudd_PrintInfo(dd, stdout); if (ret != 0) { printf("%d non-zero references\n", ret); } } Cudd_Quit(dd); return 0; }
DdNode *compute_winning_set_BDD( DdManager *manager, DdNode *etrans, DdNode *strans, DdNode **egoals, DdNode **sgoals, unsigned char verbose ) { DdNode *X = NULL, *X_prev = NULL; DdNode *Y = NULL, *Y_exmod = NULL, *Y_prev = NULL; DdNode **Z = NULL, **Z_prev = NULL; bool Z_changed; /* Use to detect occurrence of fixpoint for all Z_i */ /* Fixpoint iteration counters */ int num_it_Z, num_it_Y, num_it_X; DdNode *tmp, *tmp2; int i, j; /* Generic counters */ DdNode **vars, **pvars; int num_env, num_sys; int *cube; /* length will be twice total number of variables (to account for both variables and their primes). */ num_env = tree_size( spc.evar_list ); num_sys = tree_size( spc.svar_list ); /* Allocate cube array, used later for quantifying over variables. */ cube = (int *)malloc( sizeof(int)*2*(num_env+num_sys) ); if (cube == NULL) { perror( __FILE__ ", malloc" ); exit(-1); } /* Define a map in the manager to easily swap variables with their primed selves. */ vars = malloc( (num_env+num_sys)*sizeof(DdNode *) ); pvars = malloc( (num_env+num_sys)*sizeof(DdNode *) ); for (i = 0; i < num_env+num_sys; i++) { *(vars+i) = Cudd_bddIthVar( manager, i ); *(pvars+i) = Cudd_bddIthVar( manager, i+num_env+num_sys ); } if (!Cudd_SetVarMap( manager, vars, pvars, num_env+num_sys )) { fprintf( stderr, "Error: failed to define variable map in CUDD manager.\n" ); free( cube ); return NULL; } free( vars ); free( pvars ); if (spc.num_sgoals > 0) { Z = malloc( spc.num_sgoals*sizeof(DdNode *) ); Z_prev = malloc( spc.num_sgoals*sizeof(DdNode *) ); for (i = 0; i < spc.num_sgoals; i++) { *(Z+i) = NULL; *(Z_prev+i) = NULL; } } /* Initialize */ for (i = 0; i < spc.num_sgoals; i++) { *(Z+i) = Cudd_ReadOne( manager ); Cudd_Ref( *(Z+i) ); } num_it_Z = 0; do { num_it_Z++; if (verbose > 1) { logprint( "Z iteration %d", num_it_Z ); logprint( "Cudd_ReadMemoryInUse (bytes): %d", Cudd_ReadMemoryInUse( manager ) ); } for (i = 0; i < spc.num_sgoals; i++) { if (*(Z_prev+i) != NULL) Cudd_RecursiveDeref( manager, *(Z_prev+i) ); *(Z_prev+i) = *(Z+i); } for (i = 0; i < spc.num_sgoals; i++) { if (i == spc.num_sgoals-1) { *(Z+i) = compute_existsmodal( manager, *Z_prev, etrans, strans, num_env, num_sys, cube ); } else { *(Z+i) = compute_existsmodal( manager, *(Z_prev+i+1), etrans, strans, num_env, num_sys, cube ); } if (*(Z+i) == NULL) { /* fatal error */ return NULL; } /* (Re)initialize Y */ if (Y != NULL) Cudd_RecursiveDeref( manager, Y ); Y = Cudd_Not( Cudd_ReadOne( manager ) ); Cudd_Ref( Y ); num_it_Y = 0; do { num_it_Y++; if (verbose > 1) { logprint( "\tY iteration %d", num_it_Y ); logprint( "\tCudd_ReadMemoryInUse (bytes): %d", Cudd_ReadMemoryInUse( manager ) ); } if (Y_prev != NULL) Cudd_RecursiveDeref( manager, Y_prev ); Y_prev = Y; if (Y_exmod != NULL) Cudd_RecursiveDeref( manager, Y_exmod ); Y_exmod = compute_existsmodal( manager, Y_prev, etrans, strans, num_env, num_sys, cube ); if (Y_exmod == NULL) { /* fatal error */ return NULL; } Y = Cudd_Not( Cudd_ReadOne( manager ) ); Cudd_Ref( Y ); for (j = 0; j < spc.num_egoals; j++) { /* (Re)initialize X */ if (X != NULL) Cudd_RecursiveDeref( manager, X ); X = Cudd_ReadOne( manager ); Cudd_Ref( X ); /* Greatest fixpoint for X, for this env goal */ num_it_X = 0; do { num_it_X++; if (verbose > 1) { logprint( "\t\tX iteration %d", num_it_X ); logprint( "\t\tCudd_ReadMemoryInUse (bytes): %d", Cudd_ReadMemoryInUse( manager ) ); } if (X_prev != NULL) Cudd_RecursiveDeref( manager, X_prev ); X_prev = X; X = compute_existsmodal( manager, X_prev, etrans, strans, num_env, num_sys, cube ); if (X == NULL) { /* fatal error */ return NULL; } tmp = Cudd_bddAnd( manager, *(sgoals+i), *(Z+i) ); Cudd_Ref( tmp ); tmp2 = Cudd_bddOr( manager, tmp, Y_exmod ); Cudd_Ref( tmp2 ); Cudd_RecursiveDeref( manager, tmp ); tmp = Cudd_bddAnd( manager, X, Cudd_Not( *(egoals+j) ) ); Cudd_Ref( tmp ); Cudd_RecursiveDeref( manager, X ); X = Cudd_bddOr( manager, tmp2, tmp ); Cudd_Ref( X ); Cudd_RecursiveDeref( manager, tmp ); Cudd_RecursiveDeref( manager, tmp2 ); tmp = X; X = Cudd_bddAnd( manager, X, X_prev ); Cudd_Ref( X ); Cudd_RecursiveDeref( manager, tmp ); } while (!Cudd_bddLeq( manager, X, X_prev ) || !Cudd_bddLeq( manager, X_prev, X )); tmp = Y; Y = Cudd_bddOr( manager, Y, X ); Cudd_Ref( Y ); Cudd_RecursiveDeref( manager, tmp ); Cudd_RecursiveDeref( manager, X ); X = NULL; Cudd_RecursiveDeref( manager, X_prev ); X_prev = NULL; } tmp2 = Y; Y = Cudd_bddOr( manager, Y, Y_prev ); Cudd_Ref( Y ); Cudd_RecursiveDeref( manager, tmp2 ); } while (!Cudd_bddLeq( manager, Y, Y_prev ) || !Cudd_bddLeq( manager, Y_prev, Y )); Cudd_RecursiveDeref( manager, *(Z+i) ); *(Z+i) = Cudd_bddAnd( manager, Y, *(Z_prev+i) ); Cudd_Ref( *(Z+i) ); Cudd_RecursiveDeref( manager, Y ); Y = NULL; Cudd_RecursiveDeref( manager, Y_prev ); Y_prev = NULL; Cudd_RecursiveDeref( manager, Y_exmod ); Y_exmod = NULL; } Z_changed = False; for (i = 0; i < spc.num_sgoals; i++) { if (!Cudd_bddLeq( manager, *(Z+i), *(Z_prev+i) ) || !Cudd_bddLeq( manager, *(Z_prev+i), *(Z+i) )) { Z_changed = True; break; } } } while (Z_changed); /* Pre-exit clean-up */ tmp = *Z; Cudd_RecursiveDeref( manager, *Z_prev ); for (i = 1; i < spc.num_sgoals; i++) { Cudd_RecursiveDeref( manager, *(Z+i) ); Cudd_RecursiveDeref( manager, *(Z_prev+i) ); } free( Z ); free( Z_prev ); free( cube ); return tmp; }
/**Function******************************************************************** Synopsis [Performs the recursive step of Dsd_CheckRootFunctionIdentity().] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ int Dsd_CheckRootFunctionIdentity_rec( DdManager * dd, DdNode * bF1, DdNode * bF2, DdNode * bC1, DdNode * bC2 ) { unsigned HKey; // if either bC1 or bC2 is zero, the test is true // if ( bC1 == b0 || bC2 == b0 ) return 1; assert( bC1 != b0 ); assert( bC2 != b0 ); // if both bC1 and bC2 are one - perform comparison if ( bC1 == b1 && bC2 == b1 ) return (int)( bF1 == bF2 ); if ( bF1 == b0 ) return Cudd_bddLeq( dd, bC2, Cudd_Not(bF2) ); if ( bF1 == b1 ) return Cudd_bddLeq( dd, bC2, bF2 ); if ( bF2 == b0 ) return Cudd_bddLeq( dd, bC1, Cudd_Not(bF1) ); if ( bF2 == b1 ) return Cudd_bddLeq( dd, bC1, bF1 ); // otherwise, keep expanding // check cache // HKey = _Hash( ((unsigned)bF1), ((unsigned)bF2), ((unsigned)bC1), ((unsigned)bC2) ); HKey = hashKey4( bF1, bF2, bC1, bC2, pCache->nTableSize ); if ( pCache->pTable[HKey].bX[0] == bF1 && pCache->pTable[HKey].bX[1] == bF2 && pCache->pTable[HKey].bX[2] == bC1 && pCache->pTable[HKey].bX[3] == bC2 ) { pCache->nSuccess++; return (int)(ABC_PTRUINT_T)pCache->pTable[HKey].bX[4]; // the last bit records the result (yes/no) } else { // determine the top variables int RetValue; DdNode * bA[4] = { bF1, bF2, bC1, bC2 }; // arguments DdNode * bAR[4] = { Cudd_Regular(bF1), Cudd_Regular(bF2), Cudd_Regular(bC1), Cudd_Regular(bC2) }; // regular arguments int CurLevel[4] = { cuddI(dd,bAR[0]->index), cuddI(dd,bAR[1]->index), cuddI(dd,bAR[2]->index), cuddI(dd,bAR[3]->index) }; int TopLevel = CUDD_CONST_INDEX; int i; DdNode * bE[4], * bT[4]; DdNode * bF1next, * bF2next, * bC1next, * bC2next; pCache->nFailure++; // determine the top level for ( i = 0; i < 4; i++ ) if ( TopLevel > CurLevel[i] ) TopLevel = CurLevel[i]; // compute the cofactors for ( i = 0; i < 4; i++ ) if ( TopLevel == CurLevel[i] ) { if ( bA[i] != bAR[i] ) // complemented { bE[i] = Cudd_Not(cuddE(bAR[i])); bT[i] = Cudd_Not(cuddT(bAR[i])); } else { bE[i] = cuddE(bAR[i]); bT[i] = cuddT(bAR[i]); } } else bE[i] = bT[i] = bA[i]; // solve subproblems // three cases are possible // (1) the top var belongs to both C1 and C2 // in this case, any cofactor of F1 and F2 will do, // as long as the corresponding cofactor of C1 and C2 is not equal to 0 if ( TopLevel == CurLevel[2] && TopLevel == CurLevel[3] ) { if ( bE[2] != b0 ) // C1 { bF1next = bE[0]; bC1next = bE[2]; } else { bF1next = bT[0]; bC1next = bT[2]; } if ( bE[3] != b0 ) // C2 { bF2next = bE[1]; bC2next = bE[3]; } else { bF2next = bT[1]; bC2next = bT[3]; } RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bF2next, bC1next, bC2next ); } // (2) the top var belongs to either C1 or C2 // in this case normal splitting of cofactors else if ( TopLevel == CurLevel[2] && TopLevel != CurLevel[3] ) { if ( bE[2] != b0 ) // C1 { bF1next = bE[0]; bC1next = bE[2]; } else { bF1next = bT[0]; bC1next = bT[2]; } // split around this variable RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bE[1], bC1next, bE[3] ); if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bF1next, bT[1], bC1next, bT[3] ); } else if ( TopLevel != CurLevel[2] && TopLevel == CurLevel[3] ) { if ( bE[3] != b0 ) // C2 { bF2next = bE[1]; bC2next = bE[3]; } else { bF2next = bT[1]; bC2next = bT[3]; } // split around this variable RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bE[0], bF2next, bE[2], bC2next ); if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bT[0], bF2next, bT[2], bC2next ); } // (3) the top var does not belong to C1 and C2 // in this case normal splitting of cofactors else // if ( TopLevel != CurLevel[2] && TopLevel != CurLevel[3] ) { // split around this variable RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bE[0], bE[1], bE[2], bE[3] ); if ( RetValue == 1 ) // test another branch; otherwise, there is no need to test RetValue = Dsd_CheckRootFunctionIdentity_rec( dd, bT[0], bT[1], bT[2], bT[3] ); } // set cache for ( i = 0; i < 4; i++ ) pCache->pTable[HKey].bX[i] = bA[i]; pCache->pTable[HKey].bX[4] = (DdNode*)(ABC_PTRUINT_T)RetValue; return RetValue; } }
/**Function************************************************************* Synopsis [Builds the tree.] Description [] SideEffects [] SeeAlso [] ***********************************************************************/ int Extra_BuildTreeNode( DdManager * dd, int nNodes, Extra_ImageNode_t ** pNodes, int nVars, Extra_ImageVar_t ** pVars ) { Extra_ImageNode_t * pNode1, * pNode2; Extra_ImageVar_t * pVar; Extra_ImageNode_t * pNode; DdNode * bCube, * bTemp, * bSuppTemp, * bParts; int iNode1, iNode2; int iVarBest, nSupp, v; // find the best variable iVarBest = Extra_FindBestVariable( dd, nNodes, pNodes, nVars, pVars ); if ( iVarBest == -1 ) return 0; pVar = pVars[iVarBest]; // this var cannot appear in one partition only nSupp = Extra_bddSuppSize( dd, pVar->bParts ); assert( nSupp == pVar->nParts ); assert( nSupp != 1 ); // if it appears in only two partitions, quantify it if ( pVar->nParts == 2 ) { // get the nodes iNode1 = pVar->bParts->index; iNode2 = cuddT(pVar->bParts)->index; pNode1 = pNodes[iNode1]; pNode2 = pNodes[iNode2]; // get the quantification cube bCube = dd->vars[pVar->iNum]; Cudd_Ref( bCube ); // add the variables that appear only in these partitions for ( v = 0; v < nVars; v++ ) if ( pVars[v] && v != iVarBest && pVars[v]->bParts == pVars[iVarBest]->bParts ) { // add this var bCube = Cudd_bddAnd( dd, bTemp = bCube, dd->vars[pVars[v]->iNum] ); Cudd_Ref( bCube ); Cudd_RecursiveDeref( dd, bTemp ); // clean this var Cudd_RecursiveDeref( dd, pVars[v]->bParts ); ABC_FREE( pVars[v] ); } // clean the best var Cudd_RecursiveDeref( dd, pVars[iVarBest]->bParts ); ABC_FREE( pVars[iVarBest] ); // combines two nodes pNode = Extra_CombineTwoNodes( dd, bCube, pNode1, pNode2 ); Cudd_RecursiveDeref( dd, bCube ); } else // if ( pVar->nParts > 2 ) { // find two smallest BDDs that have this var Extra_FindBestPartitions( dd, pVar->bParts, nNodes, pNodes, &iNode1, &iNode2 ); pNode1 = pNodes[iNode1]; pNode2 = pNodes[iNode2]; // it is not possible that a var appears only in these two // otherwise, it would have a different cost bParts = Cudd_bddAnd( dd, dd->vars[iNode1], dd->vars[iNode2] ); Cudd_Ref( bParts ); for ( v = 0; v < nVars; v++ ) if ( pVars[v] && pVars[v]->bParts == bParts ) assert( 0 ); Cudd_RecursiveDeref( dd, bParts ); // combines two nodes pNode = Extra_CombineTwoNodes( dd, b1, pNode1, pNode2 ); } // clean the old nodes pNodes[iNode1] = pNode; pNodes[iNode2] = NULL; // update the variables that appear in pNode[iNode2] for ( bSuppTemp = pNode2->pPart->bSupp; bSuppTemp != b1; bSuppTemp = cuddT(bSuppTemp) ) { pVar = pVars[bSuppTemp->index]; if ( pVar == NULL ) // this variable is not be quantified continue; // quantify this var assert( Cudd_bddLeq( dd, pVar->bParts, dd->vars[iNode2] ) ); pVar->bParts = Cudd_bddExistAbstract( dd, bTemp = pVar->bParts, dd->vars[iNode2] ); Cudd_Ref( pVar->bParts ); Cudd_RecursiveDeref( dd, bTemp ); // add the new var pVar->bParts = Cudd_bddAnd( dd, bTemp = pVar->bParts, dd->vars[iNode1] ); Cudd_Ref( pVar->bParts ); Cudd_RecursiveDeref( dd, bTemp ); // update the score pVar->nParts = Extra_bddSuppSize( dd, pVar->bParts ); } return 1; }