Ejemplo n.º 1
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;
}
Ejemplo n.º 2
0
IdentList*
intersection(IdentList *i1, IdentList *i2)
  // make sorted intersection of sorted identlists
{
  if (!i1 || !i2)
    return NULL;

  IdentList *r = new IdentList;

  Ident *id1 = i1->begin();
  Ident *id2 = i2->begin();
  
  while (id1 != i1->end() && id2 != i2->end()) {
    if (*id1 < *id2) 
      id1++;
    else if (*id1 > *id2) 
      id2++;
    else {
      r->push_back(*id1);
      id1++;
      id2++;
    }
  }

  if (r->empty()) {
    delete r;
    r = NULL;
  }
  return r;
}
Ejemplo n.º 3
0
ASTForm* FullAntiPrenexer::nonDistributiveRule(QuantifierClass *qForm) {
    static_assert(std::is_base_of<ASTForm_q, QuantifierClass>::value, "QuantifierClass is not derived from 'ASTForm_q' class");
    static_assert(std::is_base_of<ASTForm_ff, BinopClass>::value, "BinopClass is not derived from 'ASTForm_ff' class");

    // Ex . f1 op f2 -> (Ex X. f1) op f2
    // Ex . f2 op f2 -> f1 op (Ex X. f2)
    BinopClass *binopForm = static_cast<BinopClass*>(qForm->f);
    ASTForm *tempResult;

    IdentList *bound = qForm->vl;
    IdentList left, right, middle;
    IdentList free1, bound1;
    IdentList free2, bound2;
    binopForm->f1->freeVars(&free1, &bound1);
    binopForm->f2->freeVars(&free2, &bound2);

    for (auto var = bound->begin(); var != bound->end(); ++var) {
        bool varInLeft = free1.exists(*var);
        bool varInRight = free2.exists(*var);

        // Ex var. f1 op f2     | var in f1 && var in f2
        if (varInLeft && varInRight) {
            middle.push_back(*var);
        // (Ex var. f1) op f2   | var notin f2
        } else if(varInLeft) {
            left.push_back(*var);
        // f1 op (Ex var. f2)   | var notin f1
        } else if(varInRight) {
            right.push_back(*var);
        } // f1 op f2           | var notin f1 && var notin f2
    }

    qForm->f = nullptr;
    delete qForm;

    if(!left.empty()) {
        tempResult = new QuantifierClass(nullptr, new IdentList(left), binopForm->f1, binopForm->f1->pos);
        binopForm->f1 = static_cast<ASTForm*>(tempResult->accept(*this));
    }

    if(!right.empty()) {
        tempResult = new QuantifierClass(nullptr, new IdentList(right), binopForm->f2, binopForm->f2->pos);
        binopForm->f2 = static_cast<ASTForm*>(tempResult->accept(*this));
    }

    if(!middle.empty()) {
        tempResult = new QuantifierClass(nullptr, new IdentList(middle), binopForm, binopForm->pos);
        return tempResult;
    } else {
        return binopForm;
    }
}
Ejemplo n.º 4
0
IdentList *
subst(IdentList *i1, IdentList *i2, IdentList *i3, Ident except)
{ // map i1 using i2->i3 (but leave 'except' unchanged)
  invariant(i1 && i2 && i3 && i2->size() == i3->size());

  IdentList *res = new IdentList;
  for (IdentList::iterator j1 = i1->begin(); j1 != i1->end(); j1++) 
    if (*j1 == except)
      res->push_back(*j1);
    else
      res->push_back(subst(*j1, i2, i3));
  return res;
}
Ejemplo n.º 5
0
/**
 * Adds constraints for first-order variables to be singletons, i.e. contain
 * only one element
 *
 * @return: restricted formula
 */
ASTForm* ASTForm::restrictFormula() {
	ASTForm* restrictedFormula = this;

	// For all used first-order variables FirstOrder(x) is appended to formulae
	IdentList free, bound;
	ASTForm_FirstOrder* singleton;
	this->freeVars(&free, &bound);
	IdentList *allVars = ident_union(&free, &bound);
	if (allVars != 0) {
		Ident* it = allVars->begin();
		while(it != allVars->end()) {
			// only variables that are not already singletoned are appended to formula
			if (symbolTable.lookupType(*it) == Varname1) {
				singleton = new ASTForm_FirstOrder(new ASTTerm1_Var1((*it), Pos()), Pos());
				restrictedFormula = new ASTForm_And(singleton, restrictedFormula, Pos());
			}
			++it;
		}
	}
	return restrictedFormula;
}
Ejemplo n.º 6
0
IdentList*
ident_union(IdentList *i1, IdentList *i2) 
  // merge sorted identlists into union
{
  if ((!i1 || i1->empty()) && (!i2 || i2->empty()))
    return NULL;
  if (!i1)
    return new IdentList(*i2);
  if (!i2)
    return new IdentList(*i1);

  IdentList *r = new IdentList;

  Ident *id1 = i1->begin();
  Ident *id2 = i2->begin();
  
  while (id1 != i1->end() && id2 != i2->end()) {
    if (*id1 < *id2) {
      r->push_back(*id1);
      id1++;
    }
    else if (*id1 > *id2) {
      r->push_back(*id2);
      id2++;
    }
    else {
      r->push_back(*id1);
      id1++;
      id2++;
    }
  }
  while (id1 != i1->end()) {
    r->push_back(*id1);
    id1++;
  }
  while (id2 != i2->end()) {
    r->push_back(*id2);
    id2++;
  }

  return r;
}
Ejemplo n.º 7
0
void
MonaUntypedAST::makeGTAGuide()
{
  IdentList *univs = symbolTable.allUnivs();

  if (numTypes > 0) { 
    // convert types to guide
    if (!univs || univs->empty()) {
      cout << "Error: Types declared but no universes (or trees)\n"
	   << "Execution aborted\n";
      exit(-1);
    }
    if (univs->size() == 1) {
      // boolean and universe state space must be different
      Name name = Name("<dummy>", dummyPos);
      symbolTable.insertUniv(&name, NULL, true); 
      delete univs;
      univs = symbolTable.allUnivs();
    }
    guide_declaration = new Guide_Declaration(new GuideFuncList, dummyPos);
    typedUnivs2guide(univs->size(), univs, 0, "");
  }

  if (guide_declaration) { // guide is declared
    /*#warning NOT REQUIRING UNIVERSES*/
    /*
    if (!univs || univs->empty()) {
      cout << "Error: Guide declared but no universes\n"
	   << "Execution aborted\n";
      exit(-1);
    }
    */

    // fill tables
    unsigned numUnivs = univs->size();
    char **univPos = (char **) mem_alloc(sizeof(char *)*numUnivs);
    char **univName = (char **) mem_alloc(sizeof(char *)*numUnivs);
    IdentList::iterator id;
    int i;
    for (id = univs->begin(), i = 0; id != univs->end(); id++, i++) {
      univName[i] = symbolTable.lookupSymbol(*id);
      univPos[i] = symbolTable.lookupPos(*id);
    }
    unsigned numSs = guide_declaration->funcList->size();
    SsId *muLeft = (SsId *) mem_alloc(sizeof(SsId)*numSs);
    SsId *muRight = (SsId *) mem_alloc(sizeof(SsId)*numSs);
    char **ssName = (char **) mem_alloc(sizeof(char *)*numSs);
    SsKind *ssKind = 0;
    int *ssType = 0;
    if (numTypes > 0) {
      ssKind = (SsKind *) mem_alloc(sizeof(SsKind)*numSs);
      ssType = (int *) mem_alloc(sizeof(int)*numSs);
    }
    GuideFuncList::iterator g;
    for (g = guide_declaration->funcList->begin(), i = 0;
	 g != guide_declaration->funcList->end(); g++, i++) {
      muLeft[i] = symbolTable.lookupNumber((*g)->name2);
      muRight[i] = symbolTable.lookupNumber((*g)->name3);
      ssName[i] = (*g)->name1->str;
      if (numTypes > 0) {
	switch((*g)->kind) {
	case SS_UNIVHAT:
	  ssKind[i] = gtaSSUNIVHAT;
	  break;
	case SS_ORHAT: 
	  ssKind[i] = gtaSSORHAT;
	  break;
	case SS_ORLEAF: 
	  ssKind[i] = gtaSSORLEAF;
	  break;
	case SS_AND: 
	  ssKind[i] = gtaSSAND;
	  break;
	case SS_DUMMY:
	  ssKind[i] = gtaSSDUMMY;
	  break;
	default: ;
	}
	Ident sstype = 
	  symbolTable.lookupSSType(symbolTable.lookupIdent((*g)->name1));
	if (sstype != -1) {
	  char *sstypename = symbolTable.lookupSymbol(sstype);
	  int j;
	  for (j = 0; j < numTypes; j++)
	    if (treetypes[j].name == sstypename) {
	      ssType[i] = j;
	      break;
	    }
	  invariant(j < numTypes);
	}
	else
	  ssType[i] = -1;
      }
    }
    
    makeGuide(numSs, muLeft, muRight, ssName, numUnivs, 
	      univPos, univName, ssType, ssKind);
    
    if (!checkDisjoint()) {
      cout << "Illegal guide and universe declarations:\n"
	   << "Universes must have disjoint state spaces\n"
	   << "Execution aborted\n";
      exit(-1);
    }
    if (!checkAllUsed()) {
      cout << "Illegal guide and universe declarations:\n"
	   << "All state spaces must be reachable\n"
	   << "Execution aborted\n";
      exit(-1);
    }
    if (!checkAllCovered()) {
      cout << "Illegal guide and universe declarations:\n"
	   << "Every infinite path in the guide must belong to a universe\n"
	   << "Execution aborted\n";
      exit(-1);
    }
  }

  else { // no guide declared, make default
    if (!univs || univs->empty()) {
      // make one universe
      Name name = Name("<univ>", dummyPos);
      symbolTable.insertUniv(&name, (char *) NULL); 
      delete univs;
      univs = symbolTable.allUnivs();
    }
      
    if (univs->size() == 1) {
      // boolean and universe state space must be different
      Name name = Name("<dummy>", dummyPos);
      symbolTable.insertUniv(&name, NULL, true); 
      delete univs;
      univs = symbolTable.allUnivs();
    }
      
    // fill name table
    unsigned numUnivs = univs->size();
    char **univName = (char **) mem_alloc(sizeof(char *)*numUnivs);
    Ident *id;
    int u;
    for (id = univs->begin(), u = 0; id != univs->end(); id++, u++)
      univName[u] = symbolTable.lookupSymbol(*id);
      
    makeDefaultGuide(numUnivs, univName);
  }
  delete univs;
}
Ejemplo n.º 8
0
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 = &gtalist;

  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
}