/**Function******************************************************************** Synopsis [Reorders ZDD variables according to a given permutation.] Description [Reorders ZDD variables according to a given permutation. The i-th permutation array contains the index of the variable that should be brought to the i-th level. zddShuffle assumes that no dead nodes are present. The reordering is achieved by a series of upward sifts. Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ static int zddShuffle( DdManager * table, int * permutation) { int index; int level; int position; int numvars; int result; #ifdef DD_STATS long localTime; int initialSize; int finalSize; int previousSize; #endif zddTotalNumberSwapping = 0; #ifdef DD_STATS localTime = util_cpu_time(); initialSize = table->keysZ; (void) fprintf(table->out,"#:I_SHUFFLE %8d: initial size\n", initialSize); #endif numvars = table->sizeZ; for (level = 0; level < numvars; level++) { index = permutation[level]; position = table->permZ[index]; #ifdef DD_STATS previousSize = table->keysZ; #endif result = zddSiftUp(table,position,level); if (!result) return(0); #ifdef DD_STATS if (table->keysZ < (unsigned) previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > (unsigned) previousSize) { (void) fprintf(table->out,"+"); /* should never happen */ } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } #ifdef DD_STATS (void) fprintf(table->out,"\n"); finalSize = table->keysZ; (void) fprintf(table->out,"#:F_SHUFFLE %8d: final size\n",finalSize); (void) fprintf(table->out,"#:T_SHUFFLE %8g: total time (sec)\n", ((double)(util_cpu_time() - localTime)/1000.0)); (void) fprintf(table->out,"#:N_SHUFFLE %8d: total swaps\n", zddTotalNumberSwapping); #endif return(1); } /* end of zddShuffle */
/**Function******************************************************************** Synopsis [Tries to solve formulas in groups belonging to the solver except the groups in the list.] Description [The permanent group must not be in the list. Returns a flag whether the solving was successful. If it was successful only then SatSolver_get_model may be invoked to obtain the model ] SideEffects [] SeeAlso [SatSolverResult,SatSolver_get_permanent_group, SatIncSolver_create_group, SatSolver_get_model] ******************************************************************************/ SatSolverResult SatIncSolver_solve_without_groups(const SatIncSolver_ptr self, const Olist_ptr groups) { SatSolverResult result; SAT_INC_SOLVER_CHECK_INSTANCE(self); if ((Slist_ptr)NULL != SAT_SOLVER(self)->model) { Slist_destroy(SAT_SOLVER(self)->model); /* destroy the model of previous solving */ } SAT_SOLVER(self)->model = (Slist_ptr)NULL; if (opt_verbose_level_gt(OptsHandler_get_instance(), 0)) { fprintf(nusmv_stderr, "Invoking solver '%s'...\n", SatSolver_get_name(SAT_SOLVER(self))); } SAT_SOLVER(self)->solvingTime = util_cpu_time(); result = self->solve_without_groups(self, groups); SAT_SOLVER(self)->solvingTime = util_cpu_time() - SAT_SOLVER(self)->solvingTime; if (opt_verbose_level_gt(OptsHandler_get_instance(), 0)) { fprintf(nusmv_stderr, "Solver '%s' returned after %f secs \n", SatSolver_get_name(SAT_SOLVER(self)), SatSolver_get_last_solving_time(SAT_SOLVER(self))/1000.0); } return result; }
static pset_family do_minimize(pset_family F, pset_family D, pset_family R, int exact_cover, int weighted) { pset_family newF, E, Rt, Rp; pset p, last; int heur, level, *weights; sm_matrix *table; sm_row *cover; sm_element *pe; int debug_save = debug; if (debug & 0x0400) { debug |= (0x0020 | 0x0800); } if (debug & 0x0800) { setlinebuf((&_iob[1])); } level = (debug & 0x0800) ? 4 : 0; heur = ! exact_cover; {long t=util_cpu_time();F = primes_consensus(cube2list(F, D));if(trace)print_trace( F, "PRIMES ",util_cpu_time()-t);}; {long t=util_cpu_time();irred_split_cover(F, D, &E, &Rt, &Rp);if(trace)print_trace( E, "ESSENTIALS ",util_cpu_time()-t);}; {long t=util_cpu_time();table = irred_derive_table(D, E, Rp);if(trace)print_trace( Rp, "PI-TABLE ",util_cpu_time()-t);}; if (weighted) { weights = ((int *) malloc(sizeof(int) * ( F->count))); for( p=Rp->data, last= p+Rp->count*Rp->wsize; p< last; p+=Rp->wsize) { weights[(p[0] >> 16)] = cube.size - set_ord(p); } } else {
pset_family last_gasp(pset_family F, pset_family D, pset_family R, cost_t *cost) { pset_family G, G1; {long t=util_cpu_time();G = reduce_gasp(F, D);totals(t, 9, G,&( *cost));}; {long t=util_cpu_time();G1 = expand_gasp(G, D, R, F);totals(t, 7, G1,&( *cost));}; sf_free(G); {long t=util_cpu_time();F = irred_gasp(F, D, G1);totals(t, 8, F,&( *cost));}; return F; }
pset_family super_gasp(pset_family F, pset_family D, pset_family R, cost_t *cost) { pset_family G, G1; {long t=util_cpu_time();G = reduce_gasp(F, D);totals(t, 9, G,&( *cost));}; {long t=util_cpu_time();G1 = all_primes(G, R);totals(t, 7, G1,&( *cost));}; sf_free(G); {long t=util_cpu_time();G = sf_dupl(sf_append(F, G1));if(trace)print_trace( G, "NEWPRIMES",util_cpu_time()-t);}; {long t=util_cpu_time();F = irredundant(G, D);totals(t, 5, F,&( *cost));}; return F; }
/**Function******************************************************************** Synopsis [Computes the fraction of minterms in the on-set of all the positive cofactors of a BDD or ADD.] Description [Computes the fraction of minterms in the on-set of all the positive cofactors of DD. Returns the pointer to an array of doubles if successful; NULL otherwise. The array hs as many positions as there are BDD variables in the manager plus one. The last position of the array contains the fraction of the minterms in the ON-set of the function represented by the BDD or ADD. The other positions of the array hold the variable signatures.] SideEffects [None] ******************************************************************************/ double * Cudd_CofMinterm( DdManager * dd, DdNode * node) { st_table *table; double *values; double *result = NULL; int i, firstLevel; #ifdef DD_STATS long startTime; startTime = util_cpu_time(); num_calls = 0; table_mem = sizeof(st_table); #endif table = st_init_table(st_ptrcmp, st_ptrhash); if (table == NULL) { (void) fprintf(stdout,"out-of-memory, couldn't measure DD cofactors.\n"); return(NULL); } size = dd->size; values = ddCofMintermAux(dd, node, table); if (values != NULL) { result = ALLOC(double,size + 1); if (result != NULL) { #ifdef DD_STATS table_mem += (size + 1) * sizeof(double); #endif if (Cudd_IsConstant(node)) firstLevel = 1; else firstLevel = cuddI(dd,Cudd_Regular(node)->index); for (i = 0; i < size; i++) { if (i >= cuddI(dd,Cudd_Regular(node)->index)) { result[dd->invperm[i]] = values[i - firstLevel]; } else { result[dd->invperm[i]] = values[size - firstLevel]; } } result[size] = values[size - firstLevel]; } else { dd->errorCode = CUDD_MEMORY_OUT; } }
sm_row * sm_minimum_cover(sm_matrix *A, int *weight, int heuristic, int debug_level) /* set to 1 for a heuristic covering */ /* how deep in the recursion to provide info */ { stats_t stats; solution_t *best, *select; sm_row *prow, *sol; sm_col *pcol; sm_matrix *dup_A; int nelem, bound; double sparsity; /* Avoid sillyness */ if (A->nrows <= 0) { return sm_row_alloc(); /* easy to cover */ } /* Initialize debugging structure */ stats.start_time = util_cpu_time(); stats.debug = debug_level > 0; stats.max_print_depth = debug_level; stats.max_depth = -1; stats.nodes = 0; stats.component = stats.comp_count = 0; stats.gimpel = stats.gimpel_count = 0; stats.no_branching = heuristic != 0; stats.lower_bound = -1; /* Check the matrix sparsity */ nelem = 0; sm_foreach_row(A, prow) { nelem += prow->length; } sparsity = (double) nelem / (double) (A->nrows * A->ncols); /* Determine an upper bound on the solution */ bound = 1; sm_foreach_col(A, pcol) { bound += WEIGHT(weight, pcol->col_num); }
/**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 */
/* backwards compatibility */ long ptime() { return util_cpu_time(); }
/**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 Implementation of Rudell's sifting algorithm. @details Assumes that no dead nodes are present. <ol> <li> Order all the variables according to the number of entries in each unique table. <li> Sift the variable up and down, remembering each time the total size of the %DD heap. <li> Select the best permutation. <li> Repeat 3 and 4 for all variables. </ol> @return 1 if successful; 0 otherwise. @sideeffect None */ int cuddZddSifting( DdManager * table, int lower, int upper) { int i; IndexKey *var; int size; int x; int result; #ifdef DD_STATS int previousSize; #endif size = table->sizeZ; /* Find order in which to sift variables. */ var = ALLOC(IndexKey, size); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto cuddZddSiftingOutOfMem; } for (i = 0; i < size; i++) { x = table->permZ[i]; var[i].index = i; var[i].keys = table->subtableZ[x].keys; } util_qsort(var, size, sizeof(IndexKey), cuddZddUniqueCompare); /* Now sift. */ for (i = 0; i < ddMin(table->siftMaxVar, size); i++) { if (table->zddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDynZ = 0; /* prevent further reordering */ break; } if (table->terminationCallback != NULL && table->terminationCallback(table->tcbArg)) { table->autoDynZ = 0; /* prevent further reordering */ break; } x = table->permZ[var[i].index]; if (x < lower || x > upper) continue; #ifdef DD_STATS previousSize = table->keysZ; #endif result = cuddZddSiftingAux(table, x, lower, upper); if (!result) goto cuddZddSiftingOutOfMem; #ifdef DD_STATS if (table->keysZ < (unsigned) previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > (unsigned) previousSize) { (void) fprintf(table->out,"+"); /* should never happen */ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ , var[i].index); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } FREE(var); return(1); cuddZddSiftingOutOfMem: if (var != NULL) FREE(var); return(0); } /* end of cuddZddSifting */
/**Function******************************************************************** Synopsis [Implementation of the linear sifting algorithm for ZDDs.] Description [Implementation of the linear sifting algorithm for ZDDs. Assumes that no dead nodes are present. <ol> <li> Order all the variables according to the number of entries in each unique table. <li> Sift the variable up and down and applies the XOR transformation, remembering each time the total size of the DD heap. <li> Select the best permutation. <li> Repeat 3 and 4 for all variables. </ol> Returns 1 if successful; 0 otherwise.] SideEffects [None] SeeAlso [] ******************************************************************************/ int cuddZddLinearSifting( DdManager * table, int lower, int upper) { int i; int *var; int size; int x; int result; #ifdef DD_STATS int previousSize; #endif size = table->sizeZ; empty = table->zero; /* Find order in which to sift variables. */ var = NULL; zdd_entry = ALLOC(int, size); if (zdd_entry == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto cuddZddSiftingOutOfMem; } var = ALLOC(int, size); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto cuddZddSiftingOutOfMem; } for (i = 0; i < size; i++) { x = table->permZ[i]; zdd_entry[i] = table->subtableZ[x].keys; var[i] = i; } qsort((void *)var, size, sizeof(int), (DD_QSFP)cuddZddUniqueCompare); /* Now sift. */ for (i = 0; i < ddMin(table->siftMaxVar, size); i++) { if (table->zddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDynZ = 0; /* prevent further reordering */ break; } x = table->permZ[var[i]]; if (x < lower || x > upper) continue; #ifdef DD_STATS previousSize = table->keysZ; #endif result = cuddZddLinearAux(table, x, lower, upper); if (!result) goto cuddZddSiftingOutOfMem; #ifdef DD_STATS if (table->keysZ < (unsigned) previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > (unsigned) previousSize) { (void) fprintf(table->out,"+"); /* should never happen */ (void) fprintf(table->out,"\nSize increased from %d to %d while sifting variable %d\n", previousSize, table->keysZ , var[i]); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } FREE(var); FREE(zdd_entry); return(1); cuddZddSiftingOutOfMem: if (zdd_entry != NULL) FREE(zdd_entry); if (var != NULL) FREE(var); return(0); } /* end of cuddZddLinearSifting */
/**Function******************************************************************** Synopsis [Main dynamic reordering routine for ZDDs.] Description [Main dynamic reordering routine for ZDDs. Calls one of the possible reordering procedures: <ul> <li>Swapping <li>Sifting <li>Symmetric Sifting </ul> For sifting and symmetric sifting it is possible to request reordering to convergence.<p> The core of all methods is the reordering procedure cuddZddSwapInPlace() which swaps two adjacent variables. Returns 1 in case of success; 0 otherwise. In the case of symmetric sifting (with and without convergence) returns 1 plus the number of symmetric variables, in case of success.] SideEffects [Changes the variable order for all ZDDs and clears the cache.] ******************************************************************************/ int Cudd_zddReduceHeap( DdManager * table /* DD manager */, Cudd_ReorderingType heuristic /* method used for reordering */, int minsize /* bound below which no reordering occurs */) { DdHook *hook; int result; unsigned int nextDyn; #ifdef DD_STATS unsigned int initialSize; unsigned int finalSize; #endif long localTime; /* Don't reorder if there are too many dead nodes. */ if (table->keysZ - table->deadZ < (unsigned) minsize) return(1); if (heuristic == CUDD_REORDER_SAME) { heuristic = table->autoMethodZ; } if (heuristic == CUDD_REORDER_NONE) { return(1); } /* This call to Cudd_zddReduceHeap does initiate reordering. Therefore ** we count it. */ table->reorderings++; empty = table->zero; localTime = util_cpu_time(); /* Run the hook functions. */ hook = table->preReorderingHook; while (hook != NULL) { int res = (hook->f)(table, "ZDD", (void *)heuristic); if (res == 0) return(0); hook = hook->next; } /* Clear the cache and collect garbage. */ zddReorderPreprocess(table); zddTotalNumberSwapping = 0; #ifdef DD_STATS initialSize = table->keysZ; switch(heuristic) { case CUDD_REORDER_RANDOM: case CUDD_REORDER_RANDOM_PIVOT: (void) fprintf(table->out,"#:I_RANDOM "); break; case CUDD_REORDER_SIFT: case CUDD_REORDER_SIFT_CONVERGE: case CUDD_REORDER_SYMM_SIFT: case CUDD_REORDER_SYMM_SIFT_CONV: (void) fprintf(table->out,"#:I_SIFTING "); break; case CUDD_REORDER_LINEAR: case CUDD_REORDER_LINEAR_CONVERGE: (void) fprintf(table->out,"#:I_LINSIFT "); break; default: (void) fprintf(table->err,"Unsupported ZDD reordering method\n"); return(0); } (void) fprintf(table->out,"%8d: initial size",initialSize); #endif result = cuddZddTreeSifting(table,heuristic); #ifdef DD_STATS (void) fprintf(table->out,"\n"); finalSize = table->keysZ; (void) fprintf(table->out,"#:F_REORDER %8d: final size\n",finalSize); (void) fprintf(table->out,"#:T_REORDER %8g: total time (sec)\n", ((double)(util_cpu_time() - localTime)/1000.0)); (void) fprintf(table->out,"#:N_REORDER %8d: total swaps\n", zddTotalNumberSwapping); #endif if (result == 0) return(0); if (!zddReorderPostprocess(table)) return(0); if (table->realignZ) { if (!cuddBddAlignToZdd(table)) return(0); } nextDyn = table->keysZ * DD_DYN_RATIO; if (table->reorderings < 20 || nextDyn > table->nextDyn) table->nextDyn = nextDyn; else table->nextDyn += 20; table->reordered = 1; /* Run hook functions. */ hook = table->postReorderingHook; while (hook != NULL) { int res = (hook->f)(table, "ZDD", (void *)localTime); if (res == 0) return(0); hook = hook->next; } /* Update cumulative reordering time. */ table->reordTime += util_cpu_time() - localTime; return(result); } /* end of Cudd_zddReduceHeap */
/**Function******************************************************************** Synopsis [Symmetric sifting algorithm.] Description [Symmetric sifting algorithm. Assumes that no dead nodes are present. <ol> <li> Order all the variables according to the number of entries in each unique subtable. <li> Sift the variable up and down, remembering each time the total size of the DD heap and grouping variables that are symmetric. <li> Select the best permutation. <li> Repeat 3 and 4 for all variables. </ol> Returns 1 plus the number of symmetric variables if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddSymmSiftingConv] ******************************************************************************/ int cuddSymmSifting( DdManager * table, int lower, int upper) { int i; int *var; int size; int x; int result; int symvars; int symgroups; #ifdef DD_STATS int previousSize; #endif size = table->size; /* Find order in which to sift variables. */ var = NULL; entry = ALLOC(int,size); if (entry == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto ddSymmSiftingOutOfMem; } var = ALLOC(int,size); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto ddSymmSiftingOutOfMem; } for (i = 0; i < size; i++) { x = table->perm[i]; entry[i] = table->subtables[x].keys; var[i] = i; } qsort((void *)var,size,sizeof(int),(DD_QSFP)ddSymmUniqueCompare); /* Initialize the symmetry of each subtable to itself. */ for (i = lower; i <= upper; i++) { table->subtables[i].next = i; } for (i = 0; i < ddMin(table->siftMaxVar,size); i++) { if (ddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDyn = 0; /* prevent further reordering */ break; } x = table->perm[var[i]]; #ifdef DD_STATS previousSize = table->keys - table->isolated; #endif if (x < lower || x > upper) continue; if (table->subtables[x].next == (unsigned) x) { result = ddSymmSiftingAux(table,x,lower,upper); if (!result) goto ddSymmSiftingOutOfMem; #ifdef DD_STATS if (table->keys < (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"-"); } else if (table->keys > (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"+"); /* should never happen */ } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } } FREE(var); FREE(entry); ddSymmSummary(table, lower, upper, &symvars, &symgroups); #ifdef DD_STATS (void) fprintf(table->out, "\n#:S_SIFTING %8d: symmetric variables\n", symvars); (void) fprintf(table->out, "#:G_SIFTING %8d: symmetric groups", symgroups); #endif return(1+symvars); ddSymmSiftingOutOfMem: if (entry != NULL) FREE(entry); if (var != NULL) FREE(var); return(0); } /* end of cuddSymmSifting */
/**Function******************************************************************** Synopsis [Symmetric sifting to convergence algorithm.] Description [Symmetric sifting to convergence algorithm. Assumes that no dead nodes are present. <ol> <li> Order all the variables according to the number of entries in each unique subtable. <li> Sift the variable up and down, remembering each time the total size of the DD heap and grouping variables that are symmetric. <li> Select the best permutation. <li> Repeat 3 and 4 for all variables. <li> Repeat 1-4 until no further improvement. </ol> Returns 1 plus the number of symmetric variables if successful; 0 otherwise.] SideEffects [None] SeeAlso [cuddSymmSifting] ******************************************************************************/ int cuddSymmSiftingConv( DdManager * table, int lower, int upper) { int i; int *var; int size; int x; int result; int symvars; int symgroups; int classes; int initialSize; #ifdef DD_STATS int previousSize; #endif initialSize = table->keys - table->isolated; size = table->size; /* Find order in which to sift variables. */ var = NULL; entry = ALLOC(int,size); if (entry == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto ddSymmSiftingConvOutOfMem; } var = ALLOC(int,size); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto ddSymmSiftingConvOutOfMem; } for (i = 0; i < size; i++) { x = table->perm[i]; entry[i] = table->subtables[x].keys; var[i] = i; } qsort((void *)var,size,sizeof(int),(DD_QSFP)ddSymmUniqueCompare); /* Initialize the symmetry of each subtable to itself ** for first pass of converging symmetric sifting. */ for (i = lower; i <= upper; i++) { table->subtables[i].next = i; } for (i = 0; i < ddMin(table->siftMaxVar, table->size); i++) { if (ddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDyn = 0; /* prevent further reordering */ break; } x = table->perm[var[i]]; if (x < lower || x > upper) continue; /* Only sift if not in symmetry group already. */ if (table->subtables[x].next == (unsigned) x) { #ifdef DD_STATS previousSize = table->keys - table->isolated; #endif result = ddSymmSiftingAux(table,x,lower,upper); if (!result) goto ddSymmSiftingConvOutOfMem; #ifdef DD_STATS if (table->keys < (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"-"); } else if (table->keys > (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"+"); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } } /* Sifting now until convergence. */ while ((unsigned) initialSize > table->keys - table->isolated) { initialSize = table->keys - table->isolated; #ifdef DD_STATS (void) fprintf(table->out,"\n"); #endif /* Here we consider only one representative for each symmetry class. */ for (x = lower, classes = 0; x <= upper; x++, classes++) { while ((unsigned) x < table->subtables[x].next) { x = table->subtables[x].next; } /* Here x is the largest index in a group. ** Groups consist of adjacent variables. ** Hence, the next increment of x will move it to a new group. */ i = table->invperm[x]; entry[i] = table->subtables[x].keys; var[classes] = i; } qsort((void *)var,classes,sizeof(int),(DD_QSFP)ddSymmUniqueCompare); /* Now sift. */ for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) { if (ddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDyn = 0; /* prevent further reordering */ break; } x = table->perm[var[i]]; if ((unsigned) x >= table->subtables[x].next) { #ifdef DD_STATS previousSize = table->keys - table->isolated; #endif result = ddSymmSiftingConvAux(table,x,lower,upper); if (!result ) goto ddSymmSiftingConvOutOfMem; #ifdef DD_STATS if (table->keys < (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"-"); } else if (table->keys > (unsigned) previousSize + table->isolated) { (void) fprintf(table->out,"+"); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif } } /* for */ } ddSymmSummary(table, lower, upper, &symvars, &symgroups); #ifdef DD_STATS (void) fprintf(table->out, "\n#:S_SIFTING %8d: symmetric variables\n", symvars); (void) fprintf(table->out, "#:G_SIFTING %8d: symmetric groups", symgroups); #endif FREE(var); FREE(entry); return(1+symvars); ddSymmSiftingConvOutOfMem: if (entry != NULL) FREE(entry); if (var != NULL) FREE(var); return(0); } /* end of cuddSymmSiftingConv */
/**Function******************************************************************** Synopsis [Allocates the option structure and initializes it.] Description [] SideEffects [none] SeeAlso [ntrReadOptions] ******************************************************************************/ static NtrOptions * mainInit( ) { NtrOptions *option; /* Initialize option structure. */ option = ALLOC(NtrOptions,1); option->initialTime = util_cpu_time(); option->verify = FALSE; option->second = FALSE; option->file1 = NULL; option->file2 = NULL; option->traverse = FALSE; option->depend = FALSE; option->image = NTR_IMAGE_MONO; option->imageClip = 1.0; option->approx = NTR_UNDER_APPROX; option->threshold = -1; option->from = NTR_FROM_NEW; option->groupnsps = NTR_GROUP_NONE; option->closure = FALSE; option->closureClip = 1.0; option->envelope = FALSE; option->scc = FALSE; option->maxflow = FALSE; option->shortPath = NTR_SHORT_NONE; option->selectiveTrace = FALSE; option->zddtest = FALSE; option->printcover = FALSE; option->sinkfile = NULL; option->partition = FALSE; option->char2vect = FALSE; option->density = FALSE; option->quality = 1.0; option->decomp = FALSE; option->cofest = FALSE; option->clip = -1.0; option->dontcares = FALSE; option->closestCube = FALSE; option->clauses = FALSE; option->noBuild = FALSE; option->stateOnly = FALSE; option->node = NULL; option->locGlob = BNET_GLOBAL_DD; option->progress = FALSE; option->cacheSize = 32768; option->maxMemory = 0; /* set automatically */ option->maxMemHard = 0; /* don't set */ option->maxLive = ~0; /* very large number */ option->slots = CUDD_UNIQUE_SLOTS; option->ordering = PI_PS_FROM_FILE; option->orderPiPs = NULL; option->reordering = CUDD_REORDER_NONE; option->autoMethod = CUDD_REORDER_SIFT; option->autoDyn = 0; option->treefile = NULL; option->firstReorder = DD_FIRST_REORDER; option->countDead = FALSE; option->maxGrowth = 20; option->groupcheck = CUDD_GROUP_CHECK7; option->arcviolation = 10; option->symmviolation = 10; option->recomb = DD_DEFAULT_RECOMB; option->nodrop = TRUE; option->signatures = FALSE; option->verb = 0; option->gaOnOff = 0; option->populationSize = 0; /* use default */ option->numberXovers = 0; /* use default */ option->bdddump = FALSE; option->dumpFmt = 0; /* dot */ option->dumpfile = NULL; option->store = -1; /* do not store */ option->storefile = NULL; option->load = FALSE; option->loadfile = NULL; return(option); } /* end of mainInit */
/**Function******************************************************************** Synopsis [Repeated squaring algorithm for all-pairs shortest paths.] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ static DdNode * ntrSquare( DdManager *dd /* manager */, DdNode *D /* D(z,y): distance matrix */, DdNode **x /* array of x variables */, DdNode **y /* array of y variables */, DdNode **z /* array of z variables */, int vars /* number of variables in each of the three arrays */, int pr /* verbosity level */, int st /* use the selective trace algorithm */) { DdNode *zero; DdNode *I; /* identity matirix */ DdNode *w, *V, *P, *M, *R, *RT; DdNode *diff, *min, *minDiag; int n; int neg; long start_time; zero = Cudd_ReadZero(dd); /* Make a working copy of the original matrix. */ R = D; Cudd_Ref(R); I = Cudd_addXeqy(dd,vars,z,y); /* identity matrix */ Cudd_Ref(I); /* Make a copy of the matrix for the selective trace algorithm. */ diff = R; Cudd_Ref(diff); start_time = util_cpu_time(); for (n = vars; n >= 0; n--) { printf("Starting iteration %d at time %s\n",vars-n, util_print_time(util_cpu_time() - start_time)); /* Check for negative cycles: They are identified by negative ** elements on the diagonal. */ /* Extract values from the diagonal. */ Cudd_Ref(w = Cudd_addIte(dd,I,R,zero)); minDiag = Cudd_addFindMin(dd,w); /* no need to ref */ neg = Cudd_V(minDiag) < 0; Cudd_RecursiveDeref(dd,w); if (neg) { Cudd_RecursiveDeref(dd,diff); (void) printf("Negative cycle after %d iterations!\n",vars-n); break; } /* Prepare the first operand of matrix multiplication: ** diff(z,y) -> RT(x,y) -> V(x,z) */ /* RT(x,y) */ Cudd_Ref(RT = Cudd_addSwapVariables(dd,diff,x,z,vars)); Cudd_RecursiveDeref(dd,diff); /* V(x,z) */ Cudd_Ref(V = Cudd_addSwapVariables(dd,RT,y,z,vars)); Cudd_RecursiveDeref(dd,RT); if (pr > 0) { double pathcount; (void) printf("V"); Cudd_PrintDebug(dd,V,2*vars,pr); pathcount = Cudd_CountPath(V); (void) printf("Path count = %g\n", pathcount); } /* V(x,z) * R(z,y) -> P(x,y) */ Cudd_Ref(P = Cudd_addTriangle(dd,V,R,z,vars)); Cudd_RecursiveDeref(dd,V); /* P(x,y) => M(z,y) */ Cudd_Ref(M = Cudd_addSwapVariables(dd,P,x,z,vars)); Cudd_RecursiveDeref(dd,P); if (pr>0) {(void) printf("M"); Cudd_PrintDebug(dd,M,2*vars,pr);} /* min(z,y) */ Cudd_Ref(min = Cudd_addApply(dd,Cudd_addMinimum,R,M)); Cudd_RecursiveDeref(dd,M); if (R == min) { Cudd_RecursiveDeref(dd,min); if (pr>0) {printf("Done after %d iterations\n",vars-n+1); } break; } /* diff(z,y) */ if (st) { Cudd_Ref(diff = Cudd_addApply(dd,Cudd_addDiff,min,R)); } else { Cudd_Ref(diff = min); } Cudd_RecursiveDeref(dd,R); R = min; /* keep a copy of matrix at current iter. */ if (pr > 0) { double pathcount; (void) printf("R"); Cudd_PrintDebug(dd,R,2*vars,pr); pathcount = Cudd_CountPath(R); (void) printf("Path count = %g\n", pathcount); } if (n == 0) { (void) printf("Negative cycle!\n"); break; } } Cudd_RecursiveDeref(dd,I); Cudd_Deref(R); return(R); } /* end of ntrSquare */
/**Function******************************************************************** Synopsis [Floyd-Warshall algorithm for all-pair shortest paths.] Description [] SideEffects [] SeeAlso [] ******************************************************************************/ static DdNode * ntrWarshall( DdManager *dd, DdNode *D, DdNode **x, DdNode **y, int vars, int pr) { DdNode *one, *zero; DdNode *xminterm, *w, *V, *V2; DdNode *P, *R; int i; int nodes; int k,u; long start_time; if (vars > 30) nodes = 1000000000; else nodes = 1 << vars; one = DD_ONE(dd); zero = DD_ZERO(dd); Cudd_Ref(R = D); /* make copy of original matrix */ /* Extract pivot row and column from D */ start_time = util_cpu_time(); for (k = 0; k < nodes; k++) { if (k % 10000 == 0) { (void) printf("Starting iteration %d at time %s\n", k,util_print_time(util_cpu_time() - start_time)); } Cudd_Ref(xminterm = one); u = k; for (i = vars-1; i >= 0; i--) { if (u&1) { Cudd_Ref(w = Cudd_addIte(dd,x[i],xminterm,zero)); } else { Cudd_Ref(w = Cudd_addIte(dd,x[i],zero,xminterm)); } Cudd_RecursiveDeref(dd,xminterm); xminterm = w; u >>= 1; } Cudd_Ref(V = Cudd_Cofactor(dd,R,xminterm)); Cudd_RecursiveDeref(dd,xminterm); if (pr>2) {(void) printf("V"); Cudd_PrintDebug(dd,V,vars,pr);} Cudd_Ref(xminterm = one); u = k; for (i = vars-1; i >= 0; i--) { if (u&1) { Cudd_Ref(w = Cudd_addIte(dd,y[i],xminterm,zero)); } else { Cudd_Ref(w = Cudd_addIte(dd,y[i],zero,xminterm)); } Cudd_RecursiveDeref(dd,xminterm); xminterm = w; u >>= 1; } Cudd_Ref(V2 = Cudd_Cofactor(dd,R,xminterm)); Cudd_RecursiveDeref(dd,xminterm); if (pr>2) {(void) printf("V2"); Cudd_PrintDebug(dd,V2,vars,pr);} Cudd_Ref(P = Cudd_addOuterSum(dd,R,V,V2)); Cudd_RecursiveDeref(dd,V); Cudd_RecursiveDeref(dd,V2); Cudd_RecursiveDeref(dd,R); R = P; if (pr>2) {(void) printf("R"); Cudd_PrintDebug(dd,R,vars,pr);} } Cudd_Deref(R); return(R); } /* end of ntrWarshall */
/**Function******************************************************************** Synopsis [Sifts from treenode->low to treenode->high.] Description [Sifts from treenode->low to treenode->high. If croupcheck == CUDD_GROUP_CHECK7, it checks for group creation at the end of the initial sifting. If a group is created, it is then sifted again. After sifting one variable, the group that contains it is dissolved. Returns 1 in case of success; 0 otherwise.] SideEffects [None] ******************************************************************************/ static int zddGroupSifting( DdManager * table, int lower, int upper) { int *var; int i,j,x,xInit; int nvars; int classes; int result; int *sifted; #ifdef DD_STATS unsigned previousSize; #endif int xindex; nvars = table->sizeZ; /* Order variables to sift. */ entry = NULL; sifted = NULL; var = ALLOC(int,nvars); if (var == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto zddGroupSiftingOutOfMem; } entry = ALLOC(int,nvars); if (entry == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto zddGroupSiftingOutOfMem; } sifted = ALLOC(int,nvars); if (sifted == NULL) { table->errorCode = CUDD_MEMORY_OUT; goto zddGroupSiftingOutOfMem; } /* Here we consider only one representative for each group. */ for (i = 0, classes = 0; i < nvars; i++) { sifted[i] = 0; x = table->permZ[i]; if ((unsigned) x >= table->subtableZ[x].next) { entry[i] = table->subtableZ[x].keys; var[classes] = i; classes++; } } qsort((void *)var,classes,sizeof(int),(DD_QSFP)zddUniqueCompareGroup); /* Now sift. */ for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) { if (table->zddTotalNumberSwapping >= table->siftMaxSwap) break; if (util_cpu_time() - table->startTime > table->timeLimit) { table->autoDynZ = 0; /* prevent further reordering */ break; } xindex = var[i]; if (sifted[xindex] == 1) /* variable already sifted as part of group */ continue; x = table->permZ[xindex]; /* find current level of this variable */ if (x < lower || x > upper) continue; #ifdef DD_STATS previousSize = table->keysZ; #endif #ifdef DD_DEBUG /* x is bottom of group */ assert((unsigned) x >= table->subtableZ[x].next); #endif result = zddGroupSiftingAux(table,x,lower,upper); if (!result) goto zddGroupSiftingOutOfMem; #ifdef DD_STATS if (table->keysZ < previousSize) { (void) fprintf(table->out,"-"); } else if (table->keysZ > previousSize) { (void) fprintf(table->out,"+"); } else { (void) fprintf(table->out,"="); } fflush(table->out); #endif /* Mark variables in the group just sifted. */ x = table->permZ[xindex]; if ((unsigned) x != table->subtableZ[x].next) { xInit = x; do { j = table->invpermZ[x]; sifted[j] = 1; x = table->subtableZ[x].next; } while (x != xInit); } #ifdef DD_DEBUG if (pr > 0) (void) fprintf(table->out,"zddGroupSifting:"); #endif } /* for */ FREE(sifted); FREE(var); FREE(entry); return(1); zddGroupSiftingOutOfMem: if (entry != NULL) FREE(entry); if (var != NULL) FREE(var); if (sifted != NULL) FREE(sifted); return(0); } /* end of zddGroupSifting */
/**Function******************************************************************** Synopsis [SAT Based Incremental simulation] Description [This function performs incremental sat based simulation up to <tt>target_steps</tt>. Simulation starts from an initial state internally selected. It accepts a constraint to direct the simulation to paths satisfying such constraints. The constraints is assumed to be over state, input and next state variables. Thus, please carefully consider this information while providing constraints to this routine. The simulation stops if either the <tt>target_steps</tt> steps of simulation have been performed, or the simulation bumped in a deadlock (that might be due to the constraints that are too strong). Parameters: 'print_trace' : shows the generated trace 'changes_only' : shows only variables that actually change value between one step and it's next one] SideEffects [The possibly partial generated simulaiton trace is added to the trace manager for possible reuse.] SeeAlso [optional] ******************************************************************************/ int Bmc_StepWiseSimulation(BeFsm_ptr be_fsm, BddEnc_ptr bdd_enc, TraceManager_ptr trace_manager, int target_steps, be_ptr constraints, boolean time_shift, boolean print_trace, boolean changes_only, Simulation_Mode mode, boolean display_all) { #if NUSMV_HAVE_INCREMENTAL_SAT int steps; boolean no_deadlock; BeEnc_ptr be_enc = BE_ENC(NULL); Be_Manager_ptr be_mgr = (Be_Manager_ptr)NULL; SatIncSolver_ptr solver = SAT_INC_SOLVER(NULL); SatSolverGroup satGrp = (SatSolverGroup)-1; SatSolverResult satResult = SAT_SOLVER_UNAVAILABLE; Trace_ptr trace = bmc_simulate_get_curr_sim_trace(); int tr_num = bmc_simulate_get_curr_sim_trace_index(); be_ptr be_trans = (be_ptr)NULL; long time_statistics = util_cpu_time(); TRACE_CHECK_INSTANCE(trace); /* a trace was picked */ if (target_steps <= 0) return -1; /* Create the SAT solver instance */ solver = Sat_CreateIncSolver(get_sat_solver(OptsHandler_get_instance())); if (SAT_INC_SOLVER(NULL) == solver) { fprintf(nusmv_stderr, "Incremental sat solver '%s' is not available.\n", get_sat_solver(OptsHandler_get_instance())); return -1; } switch (mode) { case Random: bmc_simulate_enable_random_mode(SAT_SOLVER(solver)); break; case Interactive: /* Do nothing */ break; case Deterministic: /* Do nothing */ break; default: internal_error("%s: Invalid mode given", __func__); } no_deadlock = true; be_enc = BeFsm_get_be_encoding(be_fsm); be_mgr = BeEnc_get_be_manager(be_enc); /* 1. Add the transition relation into the solver permanently */ be_trans = BeFsm_get_invar(be_fsm); be_trans = Be_And(be_mgr, be_trans, BeEnc_shift_curr_to_next(be_enc, be_trans)); be_trans = Be_And(be_mgr, BeFsm_get_trans(be_fsm), be_trans); /* We force the constraints that can be over starting states, or over next states, or over the input. If the constraint is over the current state variables, then it might be the case the chosen next statre does not satisfy the constraint. */ if (time_shift) { constraints = BeEnc_shift_curr_to_next(be_enc, constraints); } be_trans = Be_And(be_mgr, be_trans, constraints); /* Necessary to re-use the routines for extracting the model */ be_trans = BeEnc_untimed_expr_to_timed(be_enc, be_trans, 0); bmc_simulate_add_be_into_inc_solver_positively(SAT_INC_SOLVER(solver), SatSolver_get_permanent_group(SAT_SOLVER(solver)), be_trans, be_enc); /* 2. Iteration adding last computed state as src state and extracting the pair (input,next_state), adding the pair to the computed trace, and then iterating from the so far computed next_state */ { for (steps = 0; ((steps < target_steps) && no_deadlock) ; steps++) { be_ptr be_src_state = (be_ptr)NULL; if (opt_verbose_level_gt(OptsHandler_get_instance(), 1)) { fprintf(nusmv_stderr, "Performing simulation step %d ...", steps+1); } /* 2.0. Extraction from the so far compute trace the last state. */ be_src_state = BeEnc_untimed_expr_to_timed(be_enc, TraceUtils_fetch_as_be(trace, Trace_last_iter(trace), TRACE_ITER_SF_VARS, be_enc, bdd_enc), 0); /* 2.2 Create the group to store the last state and, add the last state to the solver */ satGrp = SatIncSolver_create_group(solver); bmc_simulate_add_be_into_inc_solver_positively(SAT_INC_SOLVER(solver), satGrp, be_src_state, be_enc); /* 2.3. Call the solver on the instantiated problem */ satResult = SatSolver_solve_all_groups(SAT_SOLVER(solver)); switch (satResult) { case SAT_SOLVER_SATISFIABLE_PROBLEM: if (Interactive == mode) { Trace_ptr iTrace = bmc_simulate_interactive_step(SAT_SOLVER(solver), be_enc, bdd_enc, Trace_get_symbols(trace), true, display_all); Trace_concat(trace, &iTrace); } else { /* Append current computed state to the trace */ bmc_trace_utils_append_input_state(trace, be_enc, SatSolver_get_model(SAT_SOLVER(solver))); } break; case SAT_SOLVER_UNSATISFIABLE_PROBLEM: fprintf(nusmv_stderr, "The model reached a deadlock state: iteration %d.\n", steps); if (!Be_IsTrue(be_mgr, constraints)) { fprintf(nusmv_stderr, "This might be due to the constraints that are too strong.\n"); } no_deadlock = false; break; default: fprintf(nusmv_stderr, "At iteration %d, the solver returned an unexpected value: %d\n", steps, satResult); no_deadlock = false; break; } /* 2.4. Remove and destroy the group containing the last computed state */ SatIncSolver_destroy_group(solver, satGrp); if (opt_verbose_level_gt(OptsHandler_get_instance(), 1)) { fprintf(nusmv_stderr, "... done\n"); } if (opt_verbose_level_gt(OptsHandler_get_instance(), 0)) { fprintf(nusmv_stdout, " -- simulation of step %d has finished in %2.1f seconds\n", steps, (util_cpu_time() - time_statistics) / 1000.0); time_statistics = util_cpu_time(); } } /* (steps < target_steps) && no_deadlock) */ } /* iteration block */ /* 3. We clean the memory and we return */ SatIncSolver_destroy(solver); if (no_deadlock && print_trace) { TraceManager_execute_plugin(trace_manager, TRACE_OPT(NULL), (changes_only) ? 0 : 1, tr_num); } return steps; #else fprintf(nusmv_stderr, "%s: Relies on Incremental solving. " "No incremental SAT solver is available now\n", __func__); return -1; #endif }