int varcmp_offsets(const void *i1, const void *i2) { if (offsets.off(*((Ident *) i1)) < offsets.off(*((Ident *) i2))) return -1; else if (offsets.off(*((Ident *) i1)) > offsets.off(*((Ident *) i2))) return 1; else return 0; }
void Signature::make(IdentList &idents) { size = idents.size(); int *tab1 = new int[size]; int *tab2 = new int[size]; IdentList::iterator i; unsigned int x,y,s; for (i = idents.begin(), x = 0; i != idents.end(); i++, x++) tab1[x] = tab2[x] = offsets.off(*i); qsort((int *) tab2, size, sizeof(int), sortcmp); sign = new int[size]; hashvalue = 0; for (x = 0; x < size; x++) { for (y = 0, s = 0; tab2[y] != tab1[x]; y++) if (y < size && tab2[y] != tab2[y+1]) s++; sign[x] = s; hashvalue = hashvalue*x+sign[x]; } delete[] tab1; delete[] tab2; }
void st_dfa_replace_indices(DFA *a, IdentList *newvars, IdentList *oldvars, bool offnew, bool offold) { if (newvars && oldvars && newvars != oldvars) { invariant(newvars->size() == oldvars->size()); int *indexmap = new int[offsets.maxOffset()]; IdentList::iterator i, j; bool dif = false; for(i = newvars->begin(), j = oldvars->begin(); j != oldvars->end(); i++, j++) { int theold = offold ? offsets.off(*j) : *j; int thenew = offnew ? offsets.off(*i) : *i; indexmap[theold] = thenew; if (theold != thenew) dif = true; } if (dif) { Timer temp; if (options.time) { timer_replace_indices.start(); if (options.statistics) temp.start(); } if (options.statistics) cout << "Replacing indices\n"; dfaReplaceIndices(a, indexmap); num_replaces++; if (options.time) { timer_replace_indices.stop(); if (options.statistics) { temp.stop(); cout << " Time: "; temp.print(); } } } delete[] indexmap; if (options.intermediate) dfaPrintVerbose(a); } /*#warning update_largest(a);*/ }
void st_gta_replace_indices(GTA *g, IdentList *newvars, IdentList *oldvars, bool offnew, bool offold) { if (newvars && oldvars && newvars != oldvars) { invariant(newvars->size() == oldvars->size()); unsigned *indexmap = new unsigned[offsets.maxOffset()]; IdentList::iterator i, j; bool dif = false; for(i = newvars->begin(), j = oldvars->begin(); j != oldvars->end(); i++, j++) { int theold = offold ? offsets.off(*j) : *j; int thenew = offnew ? offsets.off(*i) : *i; indexmap[theold] = thenew; if (theold != thenew) dif = true; } if (dif) { Timer temp; if (options.time) { timer_replace_indices.start(); if (options.statistics) temp.start(); } if (options.statistics) cout << "Replacing indices\n"; gtaReplaceIndices(g, indexmap); num_replaces++; if (options.time) { timer_replace_indices.stop(); if (options.statistics) { temp.stop(); cout << " Time: "; temp.print(); } } } delete[] indexmap; } update_largest(g); }
DFA* st_dfa_allpos(DFA *dfa, Ident i) { DFA *t1, *t2; t1 = st_dfa_minimization(st_dfa_product(dfa, dfaAllPos(offsets.off(i)), dfaAND, dummyPos)); t2 = st_dfa_minimization(st_dfa_project(t1, i, dummyPos, false)); /*#warning update_largest(t2);*/ return t2; }
GTA * st_gta_allpos(GTA *gta, Ident i) { GTA *t1, *t2; IdentList *u = symbolTable.allRealUnivs(); SSSet set = stateSpaces(u); delete u; t1 = st_gta_minimization(st_gta_product(gta, gtaAllPos(offsets.off(i), set), gtaAND, dummyPos)); t2 = st_gta_minimization(st_gta_project(t1, i, dummyPos, false)); update_largest(t2); return t2; }
GTA * st_gta_project(GTA *g, Ident i, Pos &p, bool quotient) { Timer temp; if (options.time) { timer_project.start(); if (options.statistics) temp.start(); } if (options.statistics) { cout << "Right-quotient\n" << "Projecting #" << i; p.printsource(); cout << "\n "; print_stat(g); cout << " -> "; cout.flush(); } codeTable->begin(); GTA *result = gtaQuotientAndProject(g, offsets.off(i), quotient); codeTable->done(); num_projections++; num_right_quotients++; if (options.statistics) { print_stat(result); cout << "\n"; } if (options.time) { timer_project.stop(); if (options.statistics) { temp.stop(); cout << " Time: "; temp.print(); } } gtaFree(g); update_largest(result); return result; }
int main(int argc, char *argv[]) { std::set_new_handler(&mem_error); if (!ParseArguments(argc, argv)) { Usage(); exit(-1); } // Disable core dump struct rlimit r_core; r_core.rlim_cur = 0; r_core.rlim_max = 0; setrlimit(RLIMIT_CORE, &r_core); // Set demo limits if (options.demo) { struct rlimit r_cpu, r_as; memlimit = true; r_cpu.rlim_cur = 30; // max 30 secs. r_cpu.rlim_max = 30; setrlimit(RLIMIT_CPU, &r_cpu); r_as.rlim_cur = 20971520; // max 20MB r_as.rlim_max = 20971520; setrlimit(RLIMIT_DATA, &r_as); signal(SIGXCPU, &cpuLimit); } initTimer(); Timer timer_total; timer_total.start(); ///////// PARSING //////////////////////////////////////////////////////// if (options.printProgress) cout << "MONA v" << VERSION << "-" << RELEASE << " for WS1S/WS2S\n" "Copyright (C) 1997-2008 BRICS\n\n" "PARSING\n"; Timer timer_parsing; timer_parsing.start(); loadFile(inputFileName); yyparse(); MonaAST *ast = untypedAST->typeCheck(); lastPosVar = ast->lastPosVar; allPosVar = ast->allPosVar; timer_parsing.stop(); if (options.printProgress) { cout << "Time: "; timer_parsing.print(); } delete untypedAST; if (options.dump) { // Dump AST for main formula, verify formulas, and assertion cout << "Main formula:\n"; (ast->formula)->dump(); Deque<ASTForm *>::iterator vf; Deque<char *>::iterator vt; for (vf = ast->verifyformlist.begin(), vt = ast->verifytitlelist.begin(); vf != ast->verifyformlist.end(); vf++, vt++) { cout << "\n\nFormula " << *vt << ":\n"; (*vf)->dump(); } cout << "\n\nAssertions:\n"; (ast->assertion)->dump(); cout << "\n"; if (lastPosVar != -1) cout << "\nLastPos variable: " << symbolTable.lookupSymbol(lastPosVar) << "\n"; if (allPosVar != -1) cout << "\nAllPos variable: " << symbolTable.lookupSymbol(allPosVar) << "\n"; // Dump ASTs for predicates and macros PredLibEntry *pred = predicateLib.first(); while (pred != NULL) { if (pred->isMacro) cout << "\nMacro '"; else cout << "\nPredicate '"; cout << symbolTable.lookupSymbol(pred->name) << "':\n"; (pred->ast)->dump(); cout << "\n"; pred = predicateLib.next(); } // Dump restrictions if (symbolTable.defaultRestriction1) { cout << "\nDefault first-order restriction (" << symbolTable.lookupSymbol(symbolTable.defaultIdent1) << "):\n"; symbolTable.defaultRestriction1->dump(); cout << "\n"; } if (symbolTable.defaultRestriction2) { cout << "\nDefault second-order restriction (" << symbolTable.lookupSymbol(symbolTable.defaultIdent2) << "):\n"; symbolTable.defaultRestriction2->dump(); cout << "\n"; } Ident id; for (id = 0; id < (Ident) symbolTable.noIdents; id++) { Ident t; ASTForm *f = symbolTable.getRestriction(id, &t); if (f) { cout << "\nRestriction for #" << id << " (" << symbolTable.lookupSymbol(id) << "):"; if (t != -1) cout << " default\n"; else { cout << "\n"; f->dump(); cout << "\n"; } } } } if (options.mode != TREE && (options.graphvizSatisfyingEx || options.graphvizCounterEx || options.inheritedAcceptance)) cout << "Warning: options -gc, -gs, and -h are only used in tree mode\n"; if (options.mode == TREE && options.graphvizDFA) cout << "Warning: option -gw is only used in linear mode\n"; if (options.mode == TREE && (options.dump || options.whole) && !options.externalWhole) printGuide(); ///////// CODE GENERATION //////////////////////////////////////////////// if (options.printProgress) cout << "\nCODE GENERATION\n"; Timer timer_gencode; timer_gencode.start(); // Generate code codeTable = new CodeTable; VarCode formulaCode = ast->formula->makeCode(); VarCode assertionCode = ast->assertion->makeCode(); Deque<VarCode> verifyCode; /* #warning NEW: 'VERIFY' */ for (Deque<ASTForm *>::iterator i = ast->verifyformlist.begin(); i != ast->verifyformlist.end(); i++) verifyCode.push_back((*i)->makeCode()); // Implicitly assert restrictions for all global variables for (IdentList::iterator i = ast->globals.begin(); i != ast->globals.end(); i++) assertionCode = andList(assertionCode, getRestriction(*i, NULL)); // Restrict assertion if not trivial if (assertionCode.code->kind != cTrue) assertionCode = codeTable->insert (new Code_Restrict(assertionCode, assertionCode.code->pos)); // Add assertion to main formula and to all verify formulas for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) { assertionCode.code->refs++; *i = andList(*i, VarCode(copy(assertionCode.vars), assertionCode.code)); } formulaCode = andList(formulaCode, assertionCode); timer_gencode.stop(); if (options.printProgress) { codeTable->print_statistics(); /* if (options.dump && options.statistics) codeTable->print_sizes(); */ cout << "Time: "; timer_gencode.print(); } ///////// REORDER BDD OFFSETS //////////////////////////////////////////// if (options.reorder >= 1) { Timer timer_reorder; timer_reorder.start(); if (options.printProgress) cout << "\nREORDERING\n"; // reorder using heuristics offsets.reorder(); // regenerate DAG in new codetable CodeTable *oldCodeTable = codeTable, *newCodeTable = new CodeTable; IdentList emptylist; codeTable = newCodeTable; regenerate = true; // force making new nodes VarCode newcode = formulaCode.substCopy(&emptylist, &emptylist); Deque<VarCode> newverifycode; for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) newverifycode.push_back((*i).substCopy(&emptylist, &emptylist)); codeTable->clearSCTable(); regenerate = false; codeTable = oldCodeTable; formulaCode.remove(); for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) (*i).remove(); formulaCode = newcode; verifyCode.reset(); for (Deque<VarCode>::iterator i = newverifycode.begin(); i != newverifycode.end(); i++) verifyCode.push_back(*i); delete oldCodeTable; codeTable = newCodeTable; if (options.printProgress) { codeTable->print_statistics2(); cout << "Time: "; timer_reorder.print(); } } ///////// REDUCTION AND CODE DUMPING ///////////////////////////////////// if (options.optimize >= 1) { if (options.printProgress) cout << "\nREDUCTION\n"; Timer timer_reduction; timer_reduction.start(); // Reduce formulaCode.reduceAll(&verifyCode); timer_reduction.stop(); if (options.printProgress) { codeTable->print_reduction_statistics(); /* if (options.dump && options.statistics) codeTable->print_sizes(); */ cout << "Time: "; timer_reduction.print(); } } if (options.dump) { // Dump symboltable symbolTable.dump(); // Dump code cout << "\nMain formula:\n"; formulaCode.dump(); cout << "\n\n"; Deque<VarCode>::iterator i; Deque<char *>::iterator j; for (i = verifyCode.begin(), j = ast->verifytitlelist.begin(); i != verifyCode.end(); i++, j++) { cout << "Formula " << *j << ":\n"; (*i).dump(); cout << "\n\n"; } } if (options.graphvizDAG) { printf("digraph MONA_CODE_DAG {\n" " size = \"7.5,10.5\";\n" " main [shape = plaintext];\n" " main -> L%lx;\n", (unsigned long) formulaCode.code); formulaCode.code->viz(); Deque<VarCode>::iterator i; Deque<char *>::iterator j; for (i = verifyCode.begin(), j = ast->verifytitlelist.begin(); i != verifyCode.end(); i++, j++) { printf(" \"%s\" [shape = plaintext];\n" " \"%s\" -> L%lx;\n", *j, *j, (unsigned long) (*i).code); (*i).code->viz(); } formulaCode.unmark(); for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) (*i).unmark(); cout << "}\n"; } ///////// AUTOMATON CONSTRUCTION ///////////////////////////////////////// // Make variable lists Deque<char *> *verifytitlelist = ast->verifytitlelist.copy(); if (lastPosVar != -1) ast->globals.remove(lastPosVar); if (allPosVar != -1) ast->globals.remove(allPosVar); ast->globals.sort(); // sort by id (= index) int numVars = ast->globals.size(); int ix = 0; char **vnames = new char*[numVars]; unsigned *offs = new unsigned[numVars]; char *types = new char[numVars]; int **univs = new int*[numVars]; int *trees = new int[numVars]; SSSet *statespaces = new SSSet[numVars]; IdentList sign, freeVars; IdentList::iterator id; for (id = ast->globals.begin(); id != ast->globals.end(); id++, ix++) { statespaces[ix] = stateSpaces(*id); vnames[ix] = symbolTable.lookupSymbol(*id); offs[ix] = offsets.off(*id); sign.push_back(ix); freeVars.push_back(*id); switch (symbolTable.lookupType(*id)) { case VarnameTree: trees[ix] = 1; break; default: trees[ix] = 0; } IdentList *uu = symbolTable.lookupUnivs(*id); if (uu) { unsigned j; univs[ix] = new int[uu->size()+1]; for (j = 0; j < uu->size(); j++) univs[ix][j] = symbolTable.lookupUnivNumber(uu->get(j)); univs[ix][j] = -1; } else univs[ix] = 0; switch (symbolTable.lookupType(*id)) { case Varname0: types[ix] = 0; break; case Varname1: types[ix] = 1; break; default: types[ix] = 2; break; } } if (options.printProgress) cout << "\nAUTOMATON CONSTRUCTION\n"; Timer timer_automaton; timer_automaton.start(); DFA *dfa = 0; Deque<DFA *> dfalist; GTA *gta = 0; Deque<GTA *> gtalist; // Initialize bdd_init(); codeTable->init_print_progress(); if (options.mode != TREE) { // Generate DFAs dfa = formulaCode.DFATranslate(); if (lastPosVar != -1) dfa = st_dfa_lastpos(dfa, lastPosVar); if (allPosVar != -1) dfa = st_dfa_allpos(dfa, allPosVar); for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) { DFA *d = (*i).DFATranslate(); if (lastPosVar != -1) d = st_dfa_lastpos(d, lastPosVar); if (allPosVar != -1) d = st_dfa_allpos(d, allPosVar); dfalist.push_back(d); } } else { // Generate GTAs gta = formulaCode.GTATranslate(); if (allPosVar != -1) gta = st_gta_allpos(gta, allPosVar); for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) { GTA *g = (*i).GTATranslate(); if (allPosVar != -1) g = st_gta_allpos(g, allPosVar); gtalist.push_back(g); } } formulaCode.remove(); for (Deque<VarCode>::iterator i = verifyCode.begin(); i != verifyCode.end(); i++) (*i).remove(); timer_automaton.stop(); if (options.printProgress) { if (options.statistics) cout << "Total automaton construction time: "; else cout << "Time: "; timer_automaton.print(); } delete ast; delete codeTable; ///////// PRINT AUTOMATON //////////////////////////////////////////////// DFA *dfa2 = dfa; GTA *gta2 = gta; Deque<DFA *> *dfalist2 = &dfalist; Deque<GTA *> *gtalist2 = >alist; if (options.whole && !options.externalWhole) cout << "\n"; if (options.unrestrict) { // Unrestrict automata if (options.mode != TREE) { DFA *t = dfaCopy(dfa2); dfaUnrestrict(t); dfa2 = dfaMinimize(t); dfaFree(t); dfalist2 = new Deque<DFA *>; for (Deque<DFA *>::iterator i = dfalist.begin(); i != dfalist.end(); i++) { t = dfaCopy(*i); dfaUnrestrict(t); dfalist2->push_back(dfaMinimize(t)); dfaFree(t); } } else { GTA *t = gtaCopy(gta2); gtaUnrestrict(t); gta2 = gtaMinimize(t); gtaFree(t); gtalist2 = new Deque<GTA *>; for (Deque<GTA *>::iterator i = gtalist.begin(); i != gtalist.end(); i++) { t = gtaCopy(*i); gtaUnrestrict(t); gtalist2->push_back(gtaMinimize(t)); gtaFree(t); } } } if (options.whole) // Print whole automaton if (options.mode != TREE) { if (options.externalWhole) { if (!dfalist.empty()) cout << "Main formula:\n"; DFA *t = dfaCopy(dfa2); st_dfa_replace_indices(t, &sign, &freeVars, false, true); dfaExport(t, 0, numVars, vnames, types); dfaFree(t); Deque<DFA *>::iterator i; Deque<char *>::iterator j; for (i = dfalist2->begin(), j = verifytitlelist->begin(); i != dfalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; t = dfaCopy(*i); st_dfa_replace_indices(t, &sign, &freeVars, false, true); dfaExport(t, 0, numVars, vnames, types); dfaFree(t); } } else if (options.graphvizDFA) { dfaPrintGraphviz(dfa2, numVars, offs); for (Deque<DFA *>::iterator i = dfalist2->begin(); i != dfalist2->end(); i++) dfaPrintGraphviz(*i, numVars, offs); } else { if (!dfalist.empty()) cout << "Main formula:\n"; dfaPrint(dfa2, numVars, vnames, offs); Deque<DFA *>::iterator i; Deque<char *>::iterator j; for (i = dfalist2->begin(), j = verifytitlelist->begin(); i != dfalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; dfaPrint(*i, numVars, vnames, offs); } } } else { if (options.externalWhole) { if (!gtalist.empty()) cout << "Main formula:\n"; GTA *t = gtaCopy(gta2); st_gta_replace_indices(t, &sign, &freeVars, false, true); gtaExport(t, 0, numVars, vnames, types, statespaces, options.inheritedAcceptance); gtaFree(t); Deque<GTA *>::iterator i; Deque<char *>::iterator j; for (i = gtalist2->begin(), j = verifytitlelist->begin(); i != gtalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; t = gtaCopy(*i); st_gta_replace_indices(t, &sign, &freeVars, false, true); gtaExport(t, 0, numVars, vnames, types, statespaces, options.inheritedAcceptance); gtaFree(t); } } else { if (!gtalist.empty()) cout << "Main formula:\n"; gtaPrint(gta2, offs, numVars, vnames, options.inheritedAcceptance); Deque<GTA *>::iterator i; Deque<char *>::iterator j; for (i = gtalist2->begin(), j = verifytitlelist->begin(); i != gtalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; gtaPrint(*i, offs, numVars, vnames, options.inheritedAcceptance); } } } else if (options.analysis && !options.graphvizSatisfyingEx && !options.graphvizCounterEx && options.printProgress) { // Print summary only if (options.mode != TREE) { if (!dfalist.empty()) cout << "Main formula:"; dfaPrintVitals(dfa2); Deque<DFA *>::iterator i; Deque<char *>::iterator j; for (i = dfalist2->begin(), j = verifytitlelist->begin(); i != dfalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":"; dfaPrintVitals(*i); } } else { if (!gtalist.empty()) cout << "Main formula:"; gtaPrintTotalSize(gta2); Deque<GTA *>::iterator i; Deque<char *>::iterator j; for (i = gtalist2->begin(), j = verifytitlelist->begin(); i != gtalist2->end(); i++, j++) { cout << "\nFormula " << *j << ":"; gtaPrintTotalSize(*i); } } } if (dfa2 != dfa) { dfaFree(dfa2); for (Deque<DFA *>::iterator i = dfalist2->begin(); i != dfalist2->end(); i++) dfaFree(*i); delete dfalist2; } if (gta2 != gta) { gtaFree(gta2); for (Deque<GTA *>::iterator i = gtalist2->begin(); i != gtalist2->end(); i++) gtaFree(*i); delete gtalist2; } ///////// AUTOMATON ANALYSIS ///////////////////////////////////////////// if (options.analysis) { if (options.printProgress) cout << "\nANALYSIS\n"; if (options.mode != TREE) { if (!dfalist.empty()) cout << "Main formula:\n"; dfaAnalyze(dfa, numVars, vnames, offs, types, options.treemodeOutput); Deque<DFA *>::iterator i; Deque<char *>::iterator j; for (i = dfalist.begin(), j = verifytitlelist->begin(); i != dfalist.end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; dfaAnalyze(*i, numVars, vnames, offs, types, options.treemodeOutput); } } else { if (numTypes == 0 || options.treemodeOutput) { if (!gtalist.empty()) cout << "Main formula:\n"; gtaAnalyze(gta, numVars, vnames, offs, options.graphvizSatisfyingEx, options.graphvizCounterEx); Deque<GTA *>::iterator i; Deque<char *>::iterator j; for (i = gtalist.begin(), j = verifytitlelist->begin(); i != gtalist.end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; gtaAnalyze(*i, numVars, vnames, offs, options.graphvizSatisfyingEx, options.graphvizCounterEx); } } else { if (options.graphvizSatisfyingEx || options.graphvizCounterEx) cout << "Graphviz output of typed trees not implemented.\n"; if (!gtalist.empty()) cout << "Main formula:\n"; gtaTypeAnalyze(gta, numVars, vnames, types, offs, univs, trees); Deque<GTA *>::iterator i; Deque<char *>::iterator j; for (i = gtalist.begin(), j = verifytitlelist->begin(); i != gtalist.end(); i++, j++) { cout << "\nFormula " << *j << ":\n"; gtaTypeAnalyze(*i, numVars, vnames, types, offs, univs, trees); } } } } ///////// CLEAN UP /////////////////////////////////////////////////////// if (options.mode != TREE) { dfaFree(dfa); for (Deque<DFA *>::iterator i = dfalist.begin(); i != dfalist.end(); i++) dfaFree(*i); } else { gtaFree(gta); for (Deque<GTA *>::iterator i = gtalist.begin(); i != gtalist.end(); i++) gtaFree(*i); freeGuide(); } delete verifytitlelist; Deque<FileSource *>::iterator i; for (i = source.begin(); i != source.end(); i++) delete *i; for (ix = 0; ix < numVars; ix++) { delete[] univs[ix]; mem_free(statespaces[ix]); } delete[] statespaces; delete[] vnames; delete[] offs; delete[] types; delete[] univs; delete[] trees; freeTreetypes(); if (options.statistics) print_statistics(); if (options.time) { timer_total.stop(); cout << "\nTotal time: "; timer_total.print(); print_timing(); } else if (options.printProgress) { timer_total.stop(); cout << "\nTotal time: "; timer_total.print(); } #ifdef MAXALLOCATED cout << "Maximum space allocated: " << (maxallocated+524288)/1048576 << " MB\n"; #endif }
DFA* st_dfa_project(DFA *a, Ident i, Pos &p, bool quotient) { Timer temp1, temp2; int a_ns = a->ns; if (options.time) { timer_right_quotient.start(); if (options.statistics) temp1.start(); } if (options.statistics) cout << "Right-quotient\n"; if (quotient) { codeTable->begin(); dfaRightQuotient(a, offsets.off(i)); codeTable->done(); num_right_quotients++; } if (options.time) { timer_right_quotient.stop(); if (options.statistics) { temp1.stop(); cout << " Time: "; temp1.print(); } } if (options.time) { timer_project.start(); if (options.statistics) temp2.start(); } if (options.statistics) { cout << "Projecting #" << i; p.printsource(); cout << "\n (" << a_ns << "," << bdd_size(a->bddm) << ") -> "; cout.flush(); } codeTable->begin(); DFA *result = dfaProject(a, offsets.off(i)); codeTable->done(); num_projections++; if (options.statistics) cout << "(" << result->ns << "," << bdd_size(result->bddm) << ")\n"; if (options.time) { timer_project.stop(); if (options.statistics) { temp2.stop(); cout << " Time: "; temp2.print(); } } dfaFree(a); /*#warning update_largest(result);*/ return result; }