/**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 [Main program for ntr.] Description [Main program for ntr. Performs initialization. Reads command line options and network(s). Builds BDDs with reordering, and optionally does reachability analysis. Prints stats.] SideEffects [None] SeeAlso [] ******************************************************************************/ int main( int argc, char ** argv) { NtrOptions *option; /* options */ FILE *fp1; /* first network file pointer */ BnetNetwork *net1 = NULL; /* first network */ FILE *fp2; /* second network file pointer */ BnetNetwork *net2 = NULL; /* second network */ DdManager *dd; /* pointer to DD manager */ int exitval; /* return value of Cudd_CheckZeroRef */ int ok; /* overall return value from main() */ int result; /* stores the return value of functions */ BnetNode *node; /* auxiliary pointer to network node */ int i; /* loop index */ int j; /* loop index */ double *signatures; /* array of signatures */ int pr; /* verbosity level */ int reencoded; /* linear transformations attempted */ /* Initialize. */ option = mainInit(); ntrReadOptions(argc,argv,option); pr = option->verb; reencoded = option->reordering == CUDD_REORDER_LINEAR || option->reordering == CUDD_REORDER_LINEAR_CONVERGE || option->autoMethod == CUDD_REORDER_LINEAR || option->autoMethod == CUDD_REORDER_LINEAR_CONVERGE; /* Currently traversal requires global BDDs. Override whatever ** was specified for locGlob. */ if (option->traverse == TRUE || option->envelope == TRUE || option->scc == TRUE) { option->locGlob = BNET_GLOBAL_DD; } /* Read the first network... */ fp1 = open_file(option->file1, "r"); net1 = Bnet_ReadNetwork(fp1,pr); (void) fclose(fp1); if (net1 == NULL) { (void) fprintf(stderr,"Syntax error in %s.\n",option->file1); exit(2); } /* ... and optionally echo it to the standard output. */ if (pr > 2) { Bnet_PrintNetwork(net1); } /* Read the second network... */ if (option->verify == TRUE || option->second == TRUE || option->clip > 0.0 || option->dontcares) { fp2 = open_file(option->file2, "r"); net2 = Bnet_ReadNetwork(fp2,pr); (void) fclose(fp2); if (net2 == NULL) { (void) fprintf(stderr,"Syntax error in %s.\n",option->file2); exit(2); } /* ... and optionally echo it to the standard output. */ if (pr > 2) { Bnet_PrintNetwork(net2); } } /* Initialize manager. We start with 0 variables, because ** Ntr_buildDDs will create new variables rather than using ** whatever already exists. */ dd = startCudd(option,net1->ninputs); if (dd == NULL) { exit(2); } /* Build the BDDs for the nodes of the first network. */ result = Ntr_buildDDs(net1,dd,option,NULL); if (result == 0) { exit(2); } /* Build the BDDs for the nodes of the second network if requested. */ if (option->verify == TRUE || option->second == TRUE || option->clip > 0.0 || option->dontcares == TRUE) { char *nodesave = option->node; option->node = NULL; result = Ntr_buildDDs(net2,dd,option,net1); option->node = nodesave; if (result == 0) { exit(2); } } if (option->noBuild == TRUE) { Bnet_FreeNetwork(net1); if (option->verify == TRUE || option->second == TRUE || option->clip > 0.0) { Bnet_FreeNetwork(net2); } freeOption(option); exit(0); } if (option->locGlob != BNET_LOCAL_DD) { /* Print the order before the final reordering. */ (void) printf("Order before final reordering\n"); result = Bnet_PrintOrder(net1,dd); if (result == 0) exit(2); } /* Perform final reordering */ if (option->zddtest == FALSE) { result = reorder(net1,dd,option); if (result == 0) exit(2); /* Print final order. */ if ((option->reordering != CUDD_REORDER_NONE || option->gaOnOff) && option->locGlob != BNET_LOCAL_DD) { (void) printf("New order\n"); result = Bnet_PrintOrder(net1,dd); if (result == 0) exit(2); } /* Print the re-encoded inputs. */ if (pr >= 1 && reencoded == 1) { for (i = 0; i < net1->npis; i++) { if (!st_lookup(net1->hash,net1->inputs[i],&node)) { exit(2); } (void) fprintf(stdout,"%s:",node->name); Cudd_PrintDebug(dd,node->dd,Cudd_ReadSize(dd),pr); } for (i = 0; i < net1->nlatches; i++) { if (!st_lookup(net1->hash,net1->latches[i][1],&node)) { exit(2); } (void) fprintf(stdout,"%s:",node->name); Cudd_PrintDebug(dd,node->dd,Cudd_ReadSize(dd),pr); } if (pr >= 3) { result = Cudd_PrintLinear(dd); if (result == 0) exit(2); } } } /* Verify (combinational) equivalence. */ if (option->verify == TRUE) { result = Ntr_VerifyEquivalence(dd,net1,net2,option); if (result == 0) { (void) printf("Verification abnormally terminated\n"); exit(2); } else if (result == -1) { (void) printf("Combinational verification failed\n"); } else { (void) printf("Verification succeeded\n"); } } /* Traverse if requested and if the circuit is sequential. */ result = Ntr_Trav(dd,net1,option); if (result == 0) exit(2); /* Traverse with trasitive closure. */ result = Ntr_ClosureTrav(dd,net1,option); if (result == 0) exit(2); /* Compute outer envelope if requested and if the circuit is sequential. */ if (option->envelope == TRUE && net1->nlatches > 0) { NtrPartTR *T; T = Ntr_buildTR(dd,net1,option,option->image); result = Ntr_Envelope(dd,T,NULL,option); Ntr_freeTR(dd,T); } /* Compute SCCs if requested and if the circuit is sequential. */ result = Ntr_SCC(dd,net1,option); if (result == 0) exit(2); /* Test Constrain Decomposition. */ if (option->partition == TRUE && net1->nlatches > 0) { NtrPartTR *T; DdNode *product; DdNode **decomp; int sharingSize; T = Ntr_buildTR(dd,net1,option,NTR_IMAGE_MONO); decomp = Cudd_bddConstrainDecomp(dd,T->part[0]); if (decomp == NULL) exit(2); sharingSize = Cudd_SharingSize(decomp, Cudd_ReadSize(dd)); (void) fprintf(stdout, "Decomposition Size: %d components %d nodes\n", Cudd_ReadSize(dd), sharingSize); product = Cudd_ReadOne(dd); Cudd_Ref(product); for (i = 0; i < Cudd_ReadSize(dd); i++) { DdNode *intermediate = Cudd_bddAnd(dd, product, decomp[i]); if (intermediate == NULL) { exit(2); } Cudd_Ref(intermediate); Cudd_IterDerefBdd(dd, product); product = intermediate; } if (product != T->part[0]) exit(2); Cudd_IterDerefBdd(dd, product); for (i = 0; i < Cudd_ReadSize(dd); i++) { Cudd_IterDerefBdd(dd, decomp[i]); } FREE(decomp); Ntr_freeTR(dd,T); } /* Test char-to-vect conversion. */ result = Ntr_TestCharToVect(dd,net1,option); if (result == 0) exit(2); /* Test extraction of two-literal clauses. */ result = Ntr_TestTwoLiteralClauses(dd,net1,option); if (result == 0) exit(2); /* Test BDD minimization functions. */ result = Ntr_TestMinimization(dd,net1,net2,option); if (result == 0) exit(2); /* Test density-related functions. */ result = Ntr_TestDensity(dd,net1,option); if (result == 0) exit(2); /* Test decomposition functions. */ result = Ntr_TestDecomp(dd,net1,option); if (result == 0) exit(2); /* Test cofactor estimation functions. */ result = Ntr_TestCofactorEstimate(dd,net1,option); if (result == 0) exit(2); /* Test BDD clipping functions. */ result = Ntr_TestClipping(dd,net1,net2,option); if (result == 0) exit(2); /* Test BDD equivalence and containment under DC functions. */ result = Ntr_TestEquivAndContain(dd,net1,net2,option); if (result == 0) exit(2); /* Test BDD Cudd_bddClosestCube. */ result = Ntr_TestClosestCube(dd,net1,option); if (result == 0) exit(2); /* Test ZDDs if requested. */ if (option->stateOnly == FALSE && option->zddtest == TRUE) { result = Ntr_testZDD(dd,net1,option); if (result == 0) (void) fprintf(stdout,"ZDD test failed.\n"); result = Ntr_testISOP(dd,net1,option); if (result == 0) (void) fprintf(stdout,"ISOP test failed.\n"); } /* Compute maximum flow if requested and if the circuit is sequential. */ if (option->maxflow == TRUE && net1->nlatches > 0) { result = Ntr_maxflow(dd,net1,option); if (result == 0) (void) fprintf(stdout,"Maxflow computation failed.\n"); } /* Compute shortest paths if requested and if the circuit is sequential. */ if (option->shortPath != NTR_SHORT_NONE && net1->nlatches > 0) { result = Ntr_ShortestPaths(dd,net1,option); if (result == 0) (void) fprintf(stdout,"Shortest paths computation failed.\n"); } /* Compute output signatures if so requested. */ if (option->signatures) { (void) printf("Positive cofactor measures\n"); for (i = 0; i < net1->noutputs; i++) { if (!st_lookup(net1->hash,net1->outputs[i],&node)) { exit(2); } signatures = Cudd_CofMinterm(dd, node->dd); if (signatures) { (void) printf("%s:\n", node->name); for (j = 0; j < Cudd_ReadSize(dd); j++) { if((j%5 == 0)&&i) (void) printf("\n"); (void) printf("%5d: %-#8.4g ", j, signatures[j]); } (void) printf("\n"); FREE(signatures); } else { (void) printf("Signature computation failed.\n"); } } } /* Dump BDDs if so requested. */ if (option->bdddump && option->second == FALSE && option->density == FALSE && option->decomp == FALSE && option->cofest == FALSE && option->clip < 0.0 && option->scc == FALSE) { (void) printf("Dumping BDDs to %s\n", option->dumpfile); if (option->node != NULL) { if (!st_lookup(net1->hash,option->node,&node)) { exit(2); } result = Bnet_bddArrayDump(dd,net1,option->dumpfile,&(node->dd), &(node->name),1,option->dumpFmt); } else { result = Bnet_bddDump(dd, net1, option->dumpfile, option->dumpFmt, reencoded); } if (result != 1) { (void) printf("BDD dump failed.\n"); } } /* Print stats and clean up. */ if (pr >= 0) { result = Cudd_PrintInfo(dd,stdout); if (result != 1) { (void) printf("Cudd_PrintInfo failed.\n"); } } #if defined(DD_DEBUG) && !defined(DD_NO_DEATH_ROW) (void) fprintf(dd->err,"%d empty slots in death row\n", cuddTimesInDeathRow(dd,NULL)); #endif (void) printf("Final size: %ld\n", Cudd_ReadNodeCount(dd)); /* Dispose of node BDDs. */ node = net1->nodes; while (node != NULL) { if (node->dd != NULL && node->type != BNET_INPUT_NODE && node->type != BNET_PRESENT_STATE_NODE) { Cudd_IterDerefBdd(dd,node->dd); } node = node->next; } /* Dispose of network. */ Bnet_FreeNetwork(net1); /* Do the same cleanup for the second network if it was created. */ if (option->verify == TRUE || option->second == TRUE || option->clip > 0.0 || option->dontcares == TRUE) { node = net2->nodes; while (node != NULL) { if (node->dd != NULL && node->type != BNET_INPUT_NODE && node->type != BNET_PRESENT_STATE_NODE) { Cudd_IterDerefBdd(dd,node->dd); } node = node->next; } Bnet_FreeNetwork(net2); } /* Check reference counts: At this point we should have dereferenced ** everything we had, except in the case of re-encoding. */ exitval = Cudd_CheckZeroRef(dd); ok = exitval != 0; /* ok == 0 means O.K. */ if (exitval != 0) { (void) fflush(stdout); (void) fprintf(stderr, "%d non-zero DD reference counts after dereferencing\n", exitval); } #ifdef DD_DEBUG Cudd_CheckKeys(dd); #endif Cudd_Quit(dd); if (pr >= 0) (void) printf("total time = %s\n", util_print_time(util_cpu_time() - option->initialTime)); freeOption(option); if (pr >= 0) util_print_cpu_stats(stdout); #ifdef MNEMOSYNE mnem_writestats(); #endif exit(ok); /* NOTREACHED */ } /* end of main */
/**Function******************************************************************** Synopsis [Linearly combines two adjacent variables.] Description [Linearly combines two adjacent variables. It assumes that no dead nodes are present on entry to this procedure. The procedure then guarantees that no dead nodes will be present when it terminates. cuddZddLinearInPlace assumes that x < y. Returns the number of keys in the table if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddZddSwapInPlace cuddLinearInPlace] ******************************************************************************/ static int cuddZddLinearInPlace( DdManager * table, int x, int y) { DdNodePtr *xlist, *ylist; int xindex, yindex; int xslots, yslots; int xshift, yshift; int oldxkeys, oldykeys; int newxkeys, newykeys; int i; int posn; DdNode *f, *f1, *f0, *f11, *f10, *f01, *f00; DdNode *newf1, *newf0, *g, *next, *previous; DdNode *special; #ifdef DD_DEBUG assert(x < y); assert(cuddZddNextHigh(table,x) == y); assert(table->subtableZ[x].keys != 0); assert(table->subtableZ[y].keys != 0); assert(table->subtableZ[x].dead == 0); assert(table->subtableZ[y].dead == 0); #endif zddTotalNumberLinearTr++; /* Get parameters of x subtable. */ xindex = table->invpermZ[x]; xlist = table->subtableZ[x].nodelist; oldxkeys = table->subtableZ[x].keys; xslots = table->subtableZ[x].slots; xshift = table->subtableZ[x].shift; newxkeys = 0; /* Get parameters of y subtable. */ yindex = table->invpermZ[y]; ylist = table->subtableZ[y].nodelist; oldykeys = table->subtableZ[y].keys; yslots = table->subtableZ[y].slots; yshift = table->subtableZ[y].shift; newykeys = oldykeys; /* The nodes in the x layer are put in two chains. The chain ** pointed by g holds the normal nodes. When re-expressed they stay ** in the x list. The chain pointed by special holds the elements ** that will move to the y list. */ g = special = NULL; for (i = 0; i < xslots; i++) { f = xlist[i]; if (f == NULL) continue; xlist[i] = NULL; while (f != NULL) { next = f->next; f1 = cuddT(f); /* if (f1->index == yindex) */ cuddSatDec(f1->ref); f0 = cuddE(f); /* if (f0->index == yindex) */ cuddSatDec(f0->ref); if ((int) f1->index == yindex && cuddE(f1) == empty && (int) f0->index != yindex) { f->next = special; special = f; } else { f->next = g; g = f; } f = next; } /* while there are elements in the collision chain */ } /* for each slot of the x subtable */ /* Mark y nodes with pointers from above x. We mark them by ** changing their index to x. */ for (i = 0; i < yslots; i++) { f = ylist[i]; while (f != NULL) { if (f->ref != 0) { f->index = xindex; } f = f->next; } /* while there are elements in the collision chain */ } /* for each slot of the y subtable */ /* Move special nodes to the y list. */ f = special; while (f != NULL) { next = f->next; f1 = cuddT(f); f11 = cuddT(f1); cuddT(f) = f11; cuddSatInc(f11->ref); f0 = cuddE(f); cuddSatInc(f0->ref); f->index = yindex; /* Insert at the beginning of the list so that it will be ** found first if there is a duplicate. The duplicate will ** eventually be moved or garbage collected. No node ** re-expression will add a pointer to it. */ posn = ddHash(f11, f0, yshift); f->next = ylist[posn]; ylist[posn] = f; newykeys++; f = next; } /* Take care of the remaining x nodes that must be re-expressed. ** They form a linked list pointed by g. */ f = g; while (f != NULL) { #ifdef DD_COUNT table->swapSteps++; #endif next = f->next; /* Find f1, f0, f11, f10, f01, f00. */ f1 = cuddT(f); if ((int) f1->index == yindex || (int) f1->index == xindex) { f11 = cuddT(f1); f10 = cuddE(f1); } else { f11 = empty; f10 = f1; } f0 = cuddE(f); if ((int) f0->index == yindex || (int) f0->index == xindex) { f01 = cuddT(f0); f00 = cuddE(f0); } else { f01 = empty; f00 = f0; } /* Create the new T child. */ if (f01 == empty) { newf1 = f10; cuddSatInc(newf1->ref); } else { /* Check ylist for triple (yindex, f01, f10). */ posn = ddHash(f01, f10, yshift); /* For each element newf1 in collision list ylist[posn]. */ newf1 = ylist[posn]; /* Search the collision chain skipping the marked nodes. */ while (newf1 != NULL) { if (cuddT(newf1) == f01 && cuddE(newf1) == f10 && (int) newf1->index == yindex) { cuddSatInc(newf1->ref); break; /* match */ } newf1 = newf1->next; } /* while newf1 */ if (newf1 == NULL) { /* no match */ newf1 = cuddDynamicAllocNode(table); if (newf1 == NULL) goto zddSwapOutOfMem; newf1->index = yindex; newf1->ref = 1; cuddT(newf1) = f01; cuddE(newf1) = f10; /* Insert newf1 in the collision list ylist[pos]; ** increase the ref counts of f01 and f10 */ newykeys++; newf1->next = ylist[posn]; ylist[posn] = newf1; cuddSatInc(f01->ref); cuddSatInc(f10->ref); } } cuddT(f) = newf1; /* Do the same for f0. */ /* Create the new E child. */ if (f11 == empty) { newf0 = f00; cuddSatInc(newf0->ref); } else { /* Check ylist for triple (yindex, f11, f00). */ posn = ddHash(f11, f00, yshift); /* For each element newf0 in collision list ylist[posn]. */ newf0 = ylist[posn]; while (newf0 != NULL) { if (cuddT(newf0) == f11 && cuddE(newf0) == f00 && (int) newf0->index == yindex) { cuddSatInc(newf0->ref); break; /* match */ } newf0 = newf0->next; } /* while newf0 */ if (newf0 == NULL) { /* no match */ newf0 = cuddDynamicAllocNode(table); if (newf0 == NULL) goto zddSwapOutOfMem; newf0->index = yindex; newf0->ref = 1; cuddT(newf0) = f11; cuddE(newf0) = f00; /* Insert newf0 in the collision list ylist[posn]; ** increase the ref counts of f11 and f00. */ newykeys++; newf0->next = ylist[posn]; ylist[posn] = newf0; cuddSatInc(f11->ref); cuddSatInc(f00->ref); } } cuddE(f) = newf0; /* Re-insert the modified f in xlist. ** The modified f does not already exists in xlist. ** (Because of the uniqueness of the cofactors.) */ posn = ddHash(newf1, newf0, xshift); newxkeys++; f->next = xlist[posn]; xlist[posn] = f; f = next; } /* while f != NULL */ /* GC the y layer and move the marked nodes to the x list. */ /* For each node f in ylist. */ for (i = 0; i < yslots; i++) { previous = NULL; f = ylist[i]; while (f != NULL) { next = f->next; if (f->ref == 0) { cuddSatDec(cuddT(f)->ref); cuddSatDec(cuddE(f)->ref); cuddDeallocNode(table, f); newykeys--; if (previous == NULL) ylist[i] = next; else previous->next = next; } else if ((int) f->index == xindex) { /* move marked node */ if (previous == NULL) ylist[i] = next; else previous->next = next; f1 = cuddT(f); cuddSatDec(f1->ref); /* Check ylist for triple (yindex, f1, empty). */ posn = ddHash(f1, empty, yshift); /* For each element newf1 in collision list ylist[posn]. */ newf1 = ylist[posn]; while (newf1 != NULL) { if (cuddT(newf1) == f1 && cuddE(newf1) == empty && (int) newf1->index == yindex) { cuddSatInc(newf1->ref); break; /* match */ } newf1 = newf1->next; } /* while newf1 */ if (newf1 == NULL) { /* no match */ newf1 = cuddDynamicAllocNode(table); if (newf1 == NULL) goto zddSwapOutOfMem; newf1->index = yindex; newf1->ref = 1; cuddT(newf1) = f1; cuddE(newf1) = empty; /* Insert newf1 in the collision list ylist[posn]; ** increase the ref counts of f1 and empty. */ newykeys++; newf1->next = ylist[posn]; ylist[posn] = newf1; if (posn == i && previous == NULL) previous = newf1; cuddSatInc(f1->ref); cuddSatInc(empty->ref); } cuddT(f) = newf1; f0 = cuddE(f); /* Insert f in x list. */ posn = ddHash(newf1, f0, xshift); newxkeys++; newykeys--; f->next = xlist[posn]; xlist[posn] = f; } else { previous = f; } f = next; } /* while f */ } /* for i */ /* Set the appropriate fields in table. */ table->subtableZ[x].keys = newxkeys; table->subtableZ[y].keys = newykeys; table->keysZ += newxkeys + newykeys - oldxkeys - oldykeys; /* Update univ section; univ[x] remains the same. */ table->univ[y] = cuddT(table->univ[x]); #if 0 (void) fprintf(table->out,"x = %d y = %d\n", x, y); (void) Cudd_DebugCheck(table); (void) Cudd_CheckKeys(table); #endif return (table->keysZ); zddSwapOutOfMem: (void) fprintf(table->err, "Error: cuddZddSwapInPlace out of memory\n"); return (0); } /* end of cuddZddLinearInPlace */
/**Function******************************************************************** Synopsis [Applies reordering to the DDs.] Description [Explicitly applies reordering to the DDs. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [] *****************************************************************************/ static int reorder( BnetNetwork * net, DdManager * dd /* DD Manager */, NtrOptions * option) { #ifdef DD_DEBUG st_table *mintermTable; /* minterm counts for each output */ #endif int result; /* return value from functions */ (void) printf("Number of inputs = %d\n",net->ninputs); /* Perform the final reordering */ if (option->reordering != CUDD_REORDER_NONE) { #ifdef DD_DEBUG result = Cudd_DebugCheck(dd); if (result != 0) { (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n"); return(0); } result = Cudd_CheckKeys(dd); if (result != 0) { (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n"); return(0); } mintermTable = checkMinterms(net,dd,NULL); if (mintermTable == NULL) exit(2); #endif dd->siftMaxVar = 1000000; dd->siftMaxSwap = 1000000000; result = Cudd_ReduceHeap(dd,option->reordering,1); if (result == 0) return(0); #ifdef DD_DEBUG result = Cudd_DebugCheck(dd); if (result != 0) { (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n"); return(0); } result = Cudd_CheckKeys(dd); if (result != 0) { (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n"); return(0); } mintermTable = checkMinterms(net,dd,mintermTable); #endif /* Print symmetry stats if pertinent */ if (dd->tree == NULL && (option->reordering == CUDD_REORDER_SYMM_SIFT || option->reordering == CUDD_REORDER_SYMM_SIFT_CONV)) Cudd_SymmProfile(dd,0,dd->size - 1); } if (option->gaOnOff) { result = Cudd_ReduceHeap(dd,CUDD_REORDER_GENETIC,1); if (result == 0) { (void) printf("Something went wrong in cuddGa\n"); return(0); } } return(1); } /* end of reorder */