diff options
Diffstat (limited to 'stp/AST/ToSAT.cpp')
-rw-r--r-- | stp/AST/ToSAT.cpp | 1385 |
1 files changed, 1385 insertions, 0 deletions
diff --git a/stp/AST/ToSAT.cpp b/stp/AST/ToSAT.cpp new file mode 100644 index 00000000..7a164c9c --- /dev/null +++ b/stp/AST/ToSAT.cpp @@ -0,0 +1,1385 @@ +/******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ +// -*- c++ -*- +#include "AST.h" +#include "ASTUtil.h" +#include "../simplifier/bvsolver.h" +#include <math.h> + + +namespace BEEV { + /* FUNCTION: lookup or create a new MINISAT literal + * lookup or create new MINISAT Vars from the global MAP + * _ASTNode_to_SATVar. + */ + const MINISAT::Var BeevMgr::LookupOrCreateSATVar(MINISAT::Solver& newS, const ASTNode& n) { + ASTtoSATMap::iterator it; + MINISAT::Var v; + + //look for the symbol in the global map from ASTNodes to ints. if + //not found, create a S.newVar(), else use the existing one. + if((it = _ASTNode_to_SATVar.find(n)) == _ASTNode_to_SATVar.end()) { + v = newS.newVar(); + _ASTNode_to_SATVar[n] = v; + + //ASSUMPTION: I am assuming that the newS.newVar() call increments v + //by 1 each time it is called, and the initial value of a + //MINISAT::Var is 0. + _SATVar_to_AST.push_back(n); + } + else + v = it->second; + return v; + } + + /* FUNCTION: convert ASTClauses to MINISAT clauses and solve. + * Accepts ASTClauses and converts them to MINISAT clauses. Then adds + * the newly minted MINISAT clauses to the local SAT instance, and + * calls solve(). If solve returns unsat, then stop and return + * unsat. else continue. + */ + // FIXME: Still need to deal with TRUE/FALSE in clauses! + bool BeevMgr::toSATandSolve(MINISAT::Solver& newS, BeevMgr::ClauseList& cll) + { + CountersAndStats("SAT Solver"); + + //iterate through the list (conjunction) of ASTclauses cll + BeevMgr::ClauseList::const_iterator i = cll.begin(), iend = cll.end(); + + if(i == iend) + FatalError("toSATandSolve: Nothing to Solve",ASTUndefined); + + //turnOffSubsumption + newS.turnOffSubsumption(); + + // (*i) is an ASTVec-ptr which denotes an ASTclause + for(; i!=iend; i++) { + //Clause for the SATSolver + MINISAT::vec<MINISAT::Lit> satSolverClause; + + //now iterate through the internals of the ASTclause itself + ASTVec::const_iterator j = (*i)->begin(), jend = (*i)->end(); + //j is a disjunct in the ASTclause (*i) + for(;j!=jend;j++) { + + bool negate = (NOT == j->GetKind()) ? true : false; + ASTNode n = negate ? (*j)[0] : *j; + + //Lookup or create the MINISAT::Var corresponding to the Booelan + //ASTNode Variable, and push into sat Solver clause + MINISAT::Var v = LookupOrCreateSATVar(newS,n); + MINISAT::Lit l(v, negate); + satSolverClause.push(l); + } + newS.addClause(satSolverClause); + // clause printing. + // (printClause<MINISAT::vec<MINISAT::Lit> >)(satSolverClause); + // cout << " 0 "; + // cout << endl; + + if(newS.okay()) { + continue; + } + else { + PrintStats(newS.stats); + return false; + } + + if(!newS.simplifyDB(false)) { + PrintStats(newS.stats); + return false; + } + } + + // if input is UNSAT return false, else return true + if(!newS.simplifyDB(false)) { + PrintStats(newS.stats); + return false; + } + + //PrintActivityLevels_Of_SATVars("Before SAT:",newS); + //ChangeActivityLevels_Of_SATVars(newS); + //PrintActivityLevels_Of_SATVars("Before SAT and after initial bias:",newS); + newS.solve(); + //PrintActivityLevels_Of_SATVars("After SAT",newS); + + PrintStats(newS.stats); + if (newS.okay()) + return true; + else + return false; + } + + // GLOBAL FUNCTION: Prints statistics from the MINISAT Solver + void BeevMgr::PrintStats(MINISAT::SolverStats& s) { + if(!stats) + return; + double cpu_time = MINISAT::cpuTime(); + MINISAT::int64 mem_used = MINISAT::memUsed(); + reportf("restarts : %"I64_fmt"\n", s.starts); + reportf("conflicts : %-12"I64_fmt" (%.0f /sec)\n", s.conflicts , s.conflicts /cpu_time); + reportf("decisions : %-12"I64_fmt" (%.0f /sec)\n", s.decisions , s.decisions /cpu_time); + reportf("propagations : %-12"I64_fmt" (%.0f /sec)\n", s.propagations, s.propagations/cpu_time); + reportf("conflict literals : %-12"I64_fmt" (%4.2f %% deleted)\n", + s.tot_literals, + (s.max_literals - s.tot_literals)*100 / (double)s.max_literals); + if (mem_used != 0) reportf("Memory used : %.2f MB\n", mem_used / 1048576.0); + reportf("CPU time : %g s\n", cpu_time); + } + + // Prints Satisfying assignment directly, for debugging. + void BeevMgr::PrintSATModel(MINISAT::Solver& newS) { + if(!newS.okay()) + FatalError("PrintSATModel: NO COUNTEREXAMPLE TO PRINT",ASTUndefined); + // FIXME: Don't put tests like this in the print functions. The print functions + // should print unconditionally. Put a conditional around the call if you don't + // want them to print + if(!(stats && print_nodes)) + return; + + int num_vars = newS.nVars(); + cout << "Satisfying assignment: " << endl; + for (int i = 0; i < num_vars; i++) { + if (newS.model[i] == MINISAT::l_True) { + ASTNode s = _SATVar_to_AST[i]; + cout << s << endl; + } + else if (newS.model[i] == MINISAT::l_False) { + ASTNode s = _SATVar_to_AST[i]; + cout << CreateNode(NOT, s) << endl; + } + } + } + + + // Looks up truth value of ASTNode SYMBOL in MINISAT satisfying assignment. + // Returns ASTTrue if true, ASTFalse if false or undefined. + ASTNode BeevMgr::SymbolTruthValue(MINISAT::Solver &newS, ASTNode form) + { + MINISAT::Var satvar = _ASTNode_to_SATVar[form]; + if (newS.model[satvar] == MINISAT::l_True) { + return ASTTrue; + } + else if (newS.model[satvar] == MINISAT::l_False){ + // False + return ASTFalse; + } + else { + return (rand() > 4096) ? ASTTrue : ASTFalse; + } + } + + + // This function is for debugging problems with BitBlast and especially + // ToCNF. It evaluates the bit-blasted formula in the satisfying + // assignment. While doing that, it checks that every subformula has + // the same truth value as its representative literal, if it has one. + // If this condition is violated, it halts immediately (on the leftmost + // lowest term). + // Use CreateSimpForm to evaluate, even though it's expensive, so that + // we can use the partial truth assignment. + ASTNode BeevMgr::CheckBBandCNF(MINISAT::Solver& newS, ASTNode form) + { + // Clear memo table (in case newS has changed). + CheckBBandCNFMemo.clear(); + // Call recursive version that does the work. + return CheckBBandCNF_int(newS, form); + } + + // Recursive body CheckBBandCNF + // FIXME: Modify this to just check if result is true, and print mismatch + // if not. Might have a trace flag for the other stuff. + ASTNode BeevMgr::CheckBBandCNF_int(MINISAT::Solver& newS, ASTNode form) + { + + // cout << "++++++++++++++++" << endl << "CheckBBandCNF_int form = " << + // form << endl; + + ASTNodeMap::iterator memoit = CheckBBandCNFMemo.find(form); + if (memoit != CheckBBandCNFMemo.end()) { + // found it. Return memoized value. + return memoit->second; + } + + ASTNode result; // return value, to memoize. + + Kind k = form.GetKind(); + switch (k) { + case TRUE: + case FALSE: { + return form; + break; + } + case SYMBOL: + case BVGETBIT: { + // Look up the truth value + // ASTNode -> Sat -> Truthvalue -> ASTTrue or ASTFalse; + // FIXME: Could make up a fresh var in undefined case. + + result = SymbolTruthValue(newS, form); + + cout << "================" << endl << "Checking BB formula:" << form << endl; + cout << "----------------" << endl << "Result:" << result << endl; + + break; + } + default: { + // Evaluate the children recursively. + ASTVec eval_children; + ASTVec ch = form.GetChildren(); + ASTVec::iterator itend = ch.end(); + for(ASTVec::iterator it = ch.begin(); it < itend; it++) { + eval_children.push_back(CheckBBandCNF_int(newS, *it)); + } + result = CreateSimpForm(k, eval_children); + + cout << "================" << endl << "Checking BB formula:" << form << endl; + cout << "----------------" << endl << "Result:" << result << endl; + + ASTNode replit_eval; + // Compare with replit, if there is one. + ASTNodeMap::iterator replit_it = RepLitMap.find(form); + if (replit_it != RepLitMap.end()) { + ASTNode replit = RepLitMap[form]; + // Replit is symbol or not symbol. + if (SYMBOL == replit.GetKind()) { + replit_eval = SymbolTruthValue(newS, replit); + } + else { + // It's (NOT sym). Get value of sym and complement. + replit_eval = CreateSimpNot(SymbolTruthValue(newS, replit[0])); + } + + cout << "----------------" << endl << "Rep lit: " << replit << endl; + cout << "----------------" << endl << "Rep lit value: " << replit_eval << endl; + + if (result != replit_eval) { + // Hit the panic button. + FatalError("Truth value of BitBlasted formula disagrees with representative literal in CNF."); + } + } + else { + cout << "----------------" << endl << "No rep lit" << endl; + } + + } + } + + return (CheckBBandCNFMemo[form] = result); + } + + /*FUNCTION: constructs counterexample from MINISAT counterexample + * step1 : iterate through MINISAT counterexample and assemble the + * bits for each AST term. Store it in a map from ASTNode to vector + * of bools (bits). + * + * step2: Iterate over the map from ASTNodes->Vector-of-Bools and + * populate the CounterExampleMap data structure (ASTNode -> BVConst) + */ + void BeevMgr::ConstructCounterExample(MINISAT::Solver& newS) { + //iterate over MINISAT counterexample and construct a map from AST + //terms to vector of bools. We need this iteration step because + //MINISAT might return the various bits of a term out of + //order. Therfore, we need to collect all the bits and assemble + //them properly + + if(!newS.okay()) + return; + if(!construct_counterexample) + return; + + CopySolverMap_To_CounterExample(); + for (int i = 0; i < newS.nVars(); i++) { + //Make sure that the MINISAT::Var is defined + if (newS.model[i] != MINISAT::l_Undef) { + + //mapping from MINISAT::Vars to ASTNodes. We do not need to + //print MINISAT vars or CNF vars. + ASTNode s = _SATVar_to_AST[i]; + + //assemble the counterexample here + if(s.GetKind() == BVGETBIT && s[0].GetKind() == SYMBOL) { + ASTNode symbol = s[0]; + unsigned int symbolWidth = symbol.GetValueWidth(); + + //'v' is the map from bit-index to bit-value + hash_map<unsigned,bool> * v; + if(_ASTNode_to_Bitvector.find(symbol) == _ASTNode_to_Bitvector.end()) + _ASTNode_to_Bitvector[symbol] = new hash_map<unsigned,bool>(symbolWidth); + + //v holds the map from bit-index to bit-value + v = _ASTNode_to_Bitvector[symbol]; + + //kk is the index of BVGETBIT + unsigned int kk = GetUnsignedConst(s[1]); + + //Collect the bits of 'symbol' and store in v. Store in reverse order. + if(newS.model[i]==MINISAT::l_True) + (*v)[(symbolWidth-1) - kk] = true; + else + (*v)[(symbolWidth-1) - kk] = false; + } + else { + if(s.GetKind() == SYMBOL && s.GetType() == BOOLEAN_TYPE) { + const char * zz = s.GetName(); + //if the variables are not cnf variables then add them to the counterexample + if(0 != strncmp("cnf",zz,3) && 0 != strcmp("*TrueDummy*",zz)) { + if(newS.model[i]==MINISAT::l_True) + CounterExampleMap[s] = ASTTrue; + else + CounterExampleMap[s] = ASTFalse; + } + } + } + } + } + + //iterate over the ASTNode_to_Bitvector data-struct and construct + //the the aggregate value of the bitvector, and populate the + //CounterExampleMap datastructure + for(ASTtoBitvectorMap::iterator it=_ASTNode_to_Bitvector.begin(),itend=_ASTNode_to_Bitvector.end(); + it!=itend;it++) { + ASTNode var = it->first; + //debugging + //cerr << var; + if(SYMBOL != var.GetKind()) + FatalError("ConstructCounterExample: error while constructing counterexample: not a variable: ",var); + + //construct the bitvector value + hash_map<unsigned,bool> * w = it->second; + ASTNode value = BoolVectoBVConst(w, var.GetValueWidth()); + //debugging + //cerr << value; + + //populate the counterexample datastructure. add only scalars + //variables which were declared in the input and newly + //introduced variables for array reads + CounterExampleMap[var] = value; + } + + //In this loop, we compute the value of each array read, the + //corresponding ITE against the counterexample generated above. + for(ASTNodeMap::iterator it=_arrayread_ite.begin(),itend=_arrayread_ite.end(); + it!=itend;it++){ + //the array read + ASTNode arrayread = it->first; + ASTNode value_ite = _arrayread_ite[arrayread]; + + //convert it to a constant array-read and store it in the + //counter-example. First convert the index into a constant. then + //construct the appropriate array-read and store it in the + //counterexample + ASTNode arrayread_index = TermToConstTermUsingModel(arrayread[1]); + ASTNode key = CreateTerm(READ,arrayread.GetValueWidth(),arrayread[0],arrayread_index); + + //Get the ITE corresponding to the array-read and convert it + //to a constant against the model + ASTNode value = TermToConstTermUsingModel(value_ite); + //save the result in the counter_example + if(!CheckSubstitutionMap(key)) + CounterExampleMap[key] = value; + } + } //End of ConstructCounterExample + + // FUNCTION: accepts a non-constant term, and returns the + // corresponding constant term with respect to a model. + // + // term READ(A,i) is treated as follows: + // + //1. If (the boolean variable 'ArrayReadFlag' is true && ArrayRead + //1. has value in counterexample), then return the value of the + //1. arrayread. + // + //2. If (the boolean variable 'ArrayReadFlag' is true && ArrayRead + //2. doesn't have value in counterexample), then return the + //2. arrayread itself (normalized such that arrayread has a constant + //2. index) + // + //3. If (the boolean variable 'ArrayReadFlag' is false) && ArrayRead + //3. has a value in the counterexample then return the value of the + //3. arrayread. + // + //4. If (the boolean variable 'ArrayReadFlag' is false) && ArrayRead + //4. doesn't have a value in the counterexample then return 0 as the + //4. value of the arrayread. + ASTNode BeevMgr::TermToConstTermUsingModel(const ASTNode& t, bool ArrayReadFlag) { + Begin_RemoveWrites = false; + SimplifyWrites_InPlace_Flag = false; + //ASTNode term = SimplifyTerm(t); + ASTNode term = t; + Kind k = term.GetKind(); + + + //cerr << "Input to TermToConstTermUsingModel: " << term << endl; + if(!is_Term_kind(k)) { + FatalError("TermToConstTermUsingModel: The input is not a term: ",term); + } + if(k == WRITE) { + FatalError("TermToConstTermUsingModel: The input has wrong kind: WRITE : ",term); + } + if(k == SYMBOL && BOOLEAN_TYPE == term.GetType()) { + FatalError("TermToConstTermUsingModel: The input has wrong kind: Propositional variable : ",term); + } + + ASTNodeMap::iterator it1; + if((it1 = CounterExampleMap.find(term)) != CounterExampleMap.end()) { + ASTNode val = it1->second; + if(BVCONST != val.GetKind()) { + //CounterExampleMap has two maps rolled into + //one. SubstitutionMap and SolverMap. + // + //recursion is fine here. There are two maps that are checked + //here. One is the substitutionmap. We garuntee that the value + //of a key in the substitutionmap is always a constant. + // + //in the SolverMap we garuntee that "term" does not occur in + //the value part of the map + if(term == val) { + FatalError("TermToConstTermUsingModel: The input term is stored as-is " + "in the CounterExample: Not ok: ",term); + } + return TermToConstTermUsingModel(val,ArrayReadFlag); + } + else { + return val; + } + } + + ASTNode output; + switch(k) { + case BVCONST: + output = term; + break; + case SYMBOL: { + if(term.GetType() == ARRAY_TYPE) { + return term; + } + + //when all else fails set symbol values to some constant by + //default. if the variable is queried the second time then add 1 + //to and return the new value. + ASTNode zero = CreateZeroConst(term.GetValueWidth()); + output = zero; + break; + } + case READ: { + ASTNode arrName = term[0]; + ASTNode index = term[1]; + if(0 == arrName.GetIndexWidth()) { + FatalError("TermToConstTermUsingModel: array has 0 index width: ",arrName); + } + + //READ over a WRITE + if(WRITE == arrName.GetKind()) { + ASTNode wrtterm = Expand_ReadOverWrite_UsingModel(term, ArrayReadFlag); + if(wrtterm == term) { + FatalError("TermToConstTermUsingModel: Read_Over_Write term must be expanded into an ITE", term); + } + ASTNode rtterm = TermToConstTermUsingModel(wrtterm,ArrayReadFlag); + return rtterm; + } + //READ over an ITE + if(ITE == arrName.GetKind()) { + arrName = TermToConstTermUsingModel(arrName,ArrayReadFlag); + } + + ASTNode modelentry; + if(CounterExampleMap.find(index) != CounterExampleMap.end()) { + //index has a const value in the CounterExampleMap + ASTNode indexVal = CounterExampleMap[index]; + modelentry = CreateTerm(READ, arrName.GetValueWidth(), arrName, indexVal); + } + else { + //index does not have a const value in the CounterExampleMap. compute it. + ASTNode indexconstval = TermToConstTermUsingModel(index,ArrayReadFlag); + //update model with value of the index + //CounterExampleMap[index] = indexconstval; + modelentry = CreateTerm(READ,arrName.GetValueWidth(), arrName,indexconstval); + } + //modelentry is now an arrayread over a constant index + BVTypeCheck(modelentry); + + //if a value exists in the CounterExampleMap then return it + if(CounterExampleMap.find(modelentry) != CounterExampleMap.end()) { + output = TermToConstTermUsingModel(CounterExampleMap[modelentry],ArrayReadFlag); + } + else if(ArrayReadFlag) { + //return the array read over a constantindex + output = modelentry; + } + else { + //when all else fails set symbol values to some constant by + //default. if the variable is queried the second time then add 1 + //to and return the new value. + ASTNode zero = CreateZeroConst(modelentry.GetValueWidth()); + output = zero; + } + break; + } + case ITE: { + ASTNode condcompute = ComputeFormulaUsingModel(term[0]); + if(ASTTrue == condcompute) { + output = TermToConstTermUsingModel(term[1],ArrayReadFlag); + } + else if(ASTFalse == condcompute) { + output = TermToConstTermUsingModel(term[2],ArrayReadFlag); + } + else { + cerr << "TermToConstTermUsingModel: termITE: value of conditional is wrong: " << condcompute << endl; + FatalError(" TermToConstTermUsingModel: termITE: cannot compute ITE conditional against model: ",term); + } + break; + } + default: { + ASTVec c = term.GetChildren(); + ASTVec o; + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode ff = TermToConstTermUsingModel(*it,ArrayReadFlag); + o.push_back(ff); + } + output = CreateTerm(k,term.GetValueWidth(),o); + //output is a CONST expression. compute its value and store it + //in the CounterExampleMap + ASTNode oo = BVConstEvaluator(output); + //the return value + output = oo; + break; + } + } + + //when this flag is false, we should compute the arrayread to a + //constant. this constant is stored in the counter_example + //datastructure + if(!ArrayReadFlag) { + CounterExampleMap[term] = output; + } + + //cerr << "Output to TermToConstTermUsingModel: " << output << endl; + return output; + } //End of TermToConstTermUsingModel + + //Expands read-over-write by evaluating (readIndex=writeIndex) for + //every writeindex until, either it evaluates to TRUE or all + //(readIndex=writeIndex) evaluate to FALSE + ASTNode BeevMgr::Expand_ReadOverWrite_UsingModel(const ASTNode& term, bool arrayread_flag) { + if(READ != term.GetKind() && + WRITE != term[0].GetKind()) { + FatalError("RemovesWrites: Input must be a READ over a WRITE",term); + } + + ASTNode output; + ASTNodeMap::iterator it1; + if((it1 = CounterExampleMap.find(term)) != CounterExampleMap.end()) { + ASTNode val = it1->second; + if(BVCONST != val.GetKind()) { + //recursion is fine here. There are two maps that are checked + //here. One is the substitutionmap. We garuntee that the value + //of a key in the substitutionmap is always a constant. + if(term == val) { + FatalError("TermToConstTermUsingModel: The input term is stored as-is " + "in the CounterExample: Not ok: ",term); + } + return TermToConstTermUsingModel(val,arrayread_flag); + } + else { + return val; + } + } + + unsigned int width = term.GetValueWidth(); + ASTNode writeA = ASTTrue; + ASTNode newRead = term; + ASTNode readIndex = TermToConstTermUsingModel(newRead[1],false); + //iteratively expand read-over-write, and evaluate against the + //model at every iteration + do { + ASTNode write = newRead[0]; + writeA = write[0]; + ASTNode writeIndex = TermToConstTermUsingModel(write[1],false); + ASTNode writeVal = TermToConstTermUsingModel(write[2],false); + + ASTNode cond = ComputeFormulaUsingModel(CreateSimplifiedEQ(writeIndex,readIndex)); + if(ASTTrue == cond) { + //found the write-value. return it + output = writeVal; + CounterExampleMap[term] = output; + return output; + } + + newRead = CreateTerm(READ,width,writeA,readIndex); + } while(READ == newRead.GetKind() && WRITE == newRead[0].GetKind()); + + output = TermToConstTermUsingModel(newRead,arrayread_flag); + + //memoize + CounterExampleMap[term] = output; + return output; + } //Exand_ReadOverWrite_To_ITE_UsingModel() + + /* FUNCTION: accepts a non-constant formula, and checks if the + * formula is ASTTrue or ASTFalse w.r.t to a model + */ + ASTNode BeevMgr::ComputeFormulaUsingModel(const ASTNode& form) { + ASTNode in = form; + Kind k = form.GetKind(); + if(!(is_Form_kind(k) && BOOLEAN_TYPE == form.GetType())) { + FatalError(" ComputeConstFormUsingModel: The input is a non-formula: ", form); + } + + //cerr << "Input to ComputeFormulaUsingModel:" << form << endl; + ASTNodeMap::iterator it1; + if((it1 = ComputeFormulaMap.find(form)) != ComputeFormulaMap.end()) { + ASTNode res = it1->second; + if(ASTTrue == res || ASTFalse == res) { + return res; + } + else { + FatalError("ComputeFormulaUsingModel: The value of a formula must be TRUE or FALSE:", form); + } + } + + ASTNode t0,t1; + ASTNode output = ASTFalse; + switch(k) { + case TRUE: + case FALSE: + output = form; + break; + case SYMBOL: + if(BOOLEAN_TYPE != form.GetType()) + FatalError(" ComputeFormulaUsingModel: Non-Boolean variables are not formulas",form); + if(CounterExampleMap.find(form) != CounterExampleMap.end()) { + ASTNode counterexample_val = CounterExampleMap[form]; + if(!VarSeenInTerm(form,counterexample_val)) { + output = ComputeFormulaUsingModel(counterexample_val); + } + else { + output = counterexample_val; + } + } + else + output = ASTFalse; + break; + case EQ: + case NEQ: + case BVLT: + case BVLE: + case BVGT: + case BVGE: + case BVSLT: + case BVSLE: + case BVSGT: + case BVSGE: + //convert form[0] into a constant term + t0 = TermToConstTermUsingModel(form[0],false); + //convert form[0] into a constant term + t1 = TermToConstTermUsingModel(form[1],false); + output = BVConstEvaluator(CreateNode(k,t0,t1)); + + //evaluate formula to false if bvdiv execption occurs while + //counterexample is being checked during refinement. + if(bvdiv_exception_occured && + counterexample_checking_during_refinement) { + output = ASTFalse; + } + break; + case NAND: { + ASTNode o = ASTTrue; + for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++) + if(ASTFalse == ComputeFormulaUsingModel(*it)) { + o = ASTFalse; + break; + } + if(o == ASTTrue) + output = ASTFalse; + else + output = ASTTrue; + break; + } + case NOR: { + ASTNode o = ASTFalse; + for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++) + if(ASTTrue == ComputeFormulaUsingModel(*it)) { + o = ASTTrue; + break; + } + if(o == ASTTrue) + output = ASTFalse; + else + output = ASTTrue; + break; + } + case NOT: + if(ASTTrue == ComputeFormulaUsingModel(form[0])) + output = ASTFalse; + else + output = ASTTrue; + break; + case OR: + for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++) + if(ASTTrue == ComputeFormulaUsingModel(*it)) + output = ASTTrue; + break; + case AND: + output = ASTTrue; + for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++) { + if(ASTFalse == ComputeFormulaUsingModel(*it)) { + output = ASTFalse; + break; + } + } + break; + case XOR: + t0 = ComputeFormulaUsingModel(form[0]); + t1 = ComputeFormulaUsingModel(form[1]); + if((ASTTrue == t0 && ASTTrue == t1) || (ASTFalse == t0 && ASTFalse == t1)) + output = ASTFalse; + else + output = ASTTrue; + break; + case IFF: + t0 = ComputeFormulaUsingModel(form[0]); + t1 = ComputeFormulaUsingModel(form[1]); + if((ASTTrue == t0 && ASTTrue == t1) || (ASTFalse == t0 && ASTFalse == t1)) + output = ASTTrue; + else + output = ASTFalse; + break; + case IMPLIES: + t0 = ComputeFormulaUsingModel(form[0]); + t1 = ComputeFormulaUsingModel(form[1]); + if((ASTFalse == t0) || (ASTTrue == t0 && ASTTrue == t1)) + output = ASTTrue; + else + output = ASTFalse; + break; + case ITE: + t0 = ComputeFormulaUsingModel(form[0]); + if(ASTTrue == t0) + output = ComputeFormulaUsingModel(form[1]); + else if(ASTFalse == t0) + output = ComputeFormulaUsingModel(form[2]); + else + FatalError("ComputeFormulaUsingModel: ITE: something is wrong with the formula: ",form); + break; + default: + FatalError(" ComputeFormulaUsingModel: the kind has not been implemented", ASTUndefined); + break; + } + + //cout << "ComputeFormulaUsingModel output is:" << output << endl; + ComputeFormulaMap[form] = output; + return output; + } + + void BeevMgr::CheckCounterExample(bool t) { + // FIXME: Code is more useful if enable flags are check OUTSIDE the method. + // If I want to check a counterexample somewhere, I don't want to have to set + // the flag in order to make it actualy happen! + + if(!check_counterexample) { + return; + } + + //input is valid, no counterexample to check + if(ValidFlag) + return; + + //t is true if SAT solver generated a counterexample, else it is false + if(!t) + FatalError("CheckCounterExample: No CounterExample to check", ASTUndefined); + const ASTVec c = GetAsserts(); + for(ASTVec::const_iterator it=c.begin(),itend=c.end();it!=itend;it++) + if(ASTFalse == ComputeFormulaUsingModel(*it)) + FatalError("CheckCounterExample:counterexample bogus:"\ + "assert evaluates to FALSE under counterexample: NOT OK",*it); + + if(ASTTrue == ComputeFormulaUsingModel(_current_query)) + FatalError("CheckCounterExample:counterexample bogus:"\ + "query evaluates to TRUE under counterexample: NOT OK",_current_query); + } + + /* FUNCTION: prints a counterexample for INVALID inputs. iterate + * through the CounterExampleMap data structure and print it to + * stdout + */ + void BeevMgr::PrintCounterExample(bool t, std::ostream& os) { + //global command-line option + // FIXME: This should always print the counterexample. If you want + // to turn it off, check the switch at the point of call. + if(!print_counterexample) + return; + + //input is valid, no counterexample to print + if(ValidFlag) + return; + + //if this option is true then print the way dawson wants using a + //different printer. do not use this printer. + if(print_arrayval_declaredorder) + return; + + //t is true if SAT solver generated a counterexample, else it is + //false + if(!t) { + cerr << "PrintCounterExample: No CounterExample to print: " << endl; + return; + } + + //os << "\nCOUNTEREXAMPLE: \n" << endl; + ASTNodeMap::iterator it = CounterExampleMap.begin(); + ASTNodeMap::iterator itend = CounterExampleMap.end(); + for(;it!=itend;it++) { + ASTNode f = it->first; + ASTNode se = it->second; + + if(ARRAY_TYPE == se.GetType()) { + FatalError("TermToConstTermUsingModel: entry in counterexample is an arraytype. bogus:",se); + } + + //skip over introduced variables + if(f.GetKind() == SYMBOL && (_introduced_symbols.find(f) != _introduced_symbols.end())) + continue; + if(f.GetKind() == SYMBOL || + (f.GetKind() == READ && f[0].GetKind() == SYMBOL && f[1].GetKind() == BVCONST)) { + os << "ASSERT( "; + f.PL_Print(os,0); + os << " = "; + if(BITVECTOR_TYPE == se.GetType()) { + TermToConstTermUsingModel(se,false).PL_Print(os,0); + } + else { + se.PL_Print(os,0); + } + os << " );" << endl; + } + } + //os << "\nEND OF COUNTEREXAMPLE" << endl; + } //End of PrintCounterExample + + /* iterate through the CounterExampleMap data structure and print it + * to stdout. this function prints only the declared array variables + * IN the ORDER in which they were declared. It also assumes that + * the variables are of the form 'varname_number'. otherwise it will + * not print anything. This function was specifically written for + * Dawson Engler's group (bug finding research group at Stanford) + */ + void BeevMgr::PrintCounterExample_InOrder(bool t) { + //global command-line option to print counterexample. we do not + //want both counterexample printers to print at the sametime. + // FIXME: This should always print the counterexample. If you want + // to turn it off, check the switch at the point of call. + if(print_counterexample) + return; + + //input is valid, no counterexample to print + if(ValidFlag) + return; + + //print if the commandline option is '-q'. allows printing the + //counterexample in order. + if(!print_arrayval_declaredorder) + return; + + //t is true if SAT solver generated a counterexample, else it is + //false + if(!t) { + cerr << "PrintCounterExample: No CounterExample to print: " << endl; + return; + } + + //vector to store the integer values + std::vector<int> out_int; + cout << "% "; + for(ASTVec::iterator it=_special_print_set.begin(),itend=_special_print_set.end(); + it!=itend;it++) { + if(ARRAY_TYPE == it->GetType()) { + //get the name of the variable + const char * c = it->GetName(); + std::string ss(c); + if(!(0 == strncmp(ss.c_str(),"ini_",4))) + continue; + reverse(ss.begin(),ss.end()); + + //cout << "debugging: " << ss; + size_t pos = ss.find('_',0); + if(!(0 < pos && pos < ss.size())) + continue; + + //get the associated length + std::string sss = ss.substr(0,pos); + reverse(sss.begin(),sss.end()); + int n = atoi(sss.c_str()); + + it->PL_Print(cout,2); + for(int j=0;j < n; j++) { + ASTNode index = CreateBVConst(it->GetIndexWidth(),j); + ASTNode readexpr = CreateTerm(READ,it->GetValueWidth(),*it,index); + ASTNode val = GetCounterExample(t, readexpr); + //cout << "ASSERT( "; + //cout << " = "; + out_int.push_back(GetUnsignedConst(val)); + //cout << "\n"; + } + } + } + cout << endl; + for(unsigned int jj=0; jj < out_int.size();jj++) + cout << out_int[jj] << endl; + cout << endl; + } //End of PrintCounterExample_InOrder + + /* FUNCTION: queries the CounterExampleMap object with 'expr' and + * returns the corresponding counterexample value. + */ + ASTNode BeevMgr::GetCounterExample(bool t, const ASTNode& expr) { + //input is valid, no counterexample to get + if(ValidFlag) + return ASTUndefined; + + if(BOOLEAN_TYPE == expr.GetType()) { + return ComputeFormulaUsingModel(expr); + } + + if(BVCONST == expr.GetKind()) { + return expr; + } + + ASTNodeMap::iterator it; + ASTNode output; + if((it = CounterExampleMap.find(expr)) != CounterExampleMap.end()) + output = TermToConstTermUsingModel(CounterExampleMap[expr],false); + else + output = CreateZeroConst(expr.GetValueWidth()); + return output; + } //End of GetCounterExample + + // FIXME: Don't use numeric codes. Use an enum type! + //Acceps a query, calls the SAT solver and generates Valid/InValid. + //if returned 0 then input is INVALID + //if returned 1 then input is VALID + //if returned 2 then ERROR + int BeevMgr::TopLevelSAT( const ASTNode& inputasserts, const ASTNode& query) { + /******start solving**********/ + ASTNode q = CreateNode(AND, inputasserts, CreateNode(NOT,query)); + ASTNode orig_input = q; + ASTNodeStats("input asserts and query: ", q); + + ASTNode newq = q; + //round of substitution, solving, and simplification. ensures that + //DAG is minimized as much as possibly, and ideally should + //garuntee that all liketerms in BVPLUSes have been combined. + BVSolver bvsolver(this); + SimplifyWrites_InPlace_Flag = false; + Begin_RemoveWrites = false; + start_abstracting = false; + TermsAlreadySeenMap.clear(); + do { + q = newq; + newq = CreateSubstitutionMap(newq); + //ASTNodeStats("after pure substitution: ", newq); + newq = SimplifyFormula_TopLevel(newq,false); + //ASTNodeStats("after simplification: ", newq); + //newq = bvsolver.TopLevelBVSolve(newq); + //ASTNodeStats("after solving: ", newq); + }while(q!=newq); + + ASTNodeStats("Before SimplifyWrites_Inplace begins: ", newq); + SimplifyWrites_InPlace_Flag = true; + Begin_RemoveWrites = false; + start_abstracting = false; + TermsAlreadySeenMap.clear(); + do { + q = newq; + //newq = CreateSubstitutionMap(newq); + //ASTNodeStats("after pure substitution: ", newq); + newq = SimplifyFormula_TopLevel(newq,false); + //ASTNodeStats("after simplification: ", newq); + newq = bvsolver.TopLevelBVSolve(newq); + //ASTNodeStats("after solving: ", newq); + }while(q!=newq); + ASTNodeStats("After SimplifyWrites_Inplace: ", newq); + + start_abstracting = (arraywrite_refinement) ? true : false; + SimplifyWrites_InPlace_Flag = false; + Begin_RemoveWrites = (start_abstracting) ? false : true; + if(start_abstracting) { + ASTNodeStats("before abstraction round begins: ", newq); + } + + TermsAlreadySeenMap.clear(); + do { + q = newq; + //newq = CreateSubstitutionMap(newq); + //Begin_RemoveWrites = true; + //ASTNodeStats("after pure substitution: ", newq); + newq = SimplifyFormula_TopLevel(newq,false); + //ASTNodeStats("after simplification: ", newq); + //newq = bvsolver.TopLevelBVSolve(newq); + //ASTNodeStats("after solving: ", newq); + }while(q!=newq); + + if(start_abstracting) { + ASTNodeStats("After abstraction: ", newq); + } + start_abstracting = false; + SimplifyWrites_InPlace_Flag = false; + Begin_RemoveWrites = false; + + newq = TransformFormula(newq); + ASTNodeStats("after transformation: ", newq); + TermsAlreadySeenMap.clear(); + + int res; + //solver instantiated here + MINISAT::Solver newS; + if(arrayread_refinement) { + counterexample_checking_during_refinement = true; + } + + //call SAT and check the result + res = CallSAT_ResultCheck(newS,newq,orig_input); + if(2 != res) { + CountersAndStats("print_func_stats"); + return res; + } + + res = SATBased_ArrayReadRefinement(newS,newq,orig_input); + if(2 != res) { + CountersAndStats("print_func_stats"); + return res; + } + + res = SATBased_ArrayWriteRefinement(newS,orig_input); + if(2 != res) { + CountersAndStats("print_func_stats"); + return res; + } + + res = SATBased_ArrayReadRefinement(newS,newq,orig_input); + if(2 != res) { + CountersAndStats("print_func_stats"); + return res; + } + + FatalError("TopLevelSAT: reached the end without proper conclusion:" + "either a divide by zero in the input or a bug in STP"); + //bogus return to make the compiler shut up + return 2; + } //End of TopLevelSAT + + //go over the list of indices for each array, and generate Leibnitz + //axioms. Then assert these axioms into the SAT solver. Check if the + //addition of the new constraints has made the bogus counterexample + //go away. if yes, return the correct answer. if no, continue adding + //Leibnitz axioms systematically. + // FIXME: What it really does is, for each array, loop over each index i. + // inside that loop, it finds all the true and false axioms with i as first + // index. When it's got them all, it adds the false axioms to the formula + // and re-solves, and returns if the result is correct. Otherwise, it + // goes on to the next index. + // If it gets through all the indices without a correct result (which I think + // is impossible, but this is pretty confusing), it then solves with all + // the true axioms, too. + // This is not the most obvious way to do it, and I don't know how it + // compares with other approaches (e.g., one false axiom at a time or + // all the false axioms each time). + int BeevMgr::SATBased_ArrayReadRefinement(MINISAT::Solver& newS, + const ASTNode& q, const ASTNode& orig_input) { + if(!arrayread_refinement) + FatalError("SATBased_ArrayReadRefinement: Control should not reach here"); + + ASTVec FalseAxiomsVec, RemainingAxiomsVec; + RemainingAxiomsVec.push_back(ASTTrue); + FalseAxiomsVec.push_back(ASTTrue); + + //in these loops we try to construct Leibnitz axioms and add it to + //the solve(). We add only those axioms that are false in the + //current counterexample. we keep adding the axioms until there + //are no more axioms to add + // + //for each array, fetch its list of indices seen so far + for(ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(), iset_end = _arrayname_readindices.end(); + iset!=iset_end;iset++) { + ASTVec listOfIndices = iset->second; + //loop over the list of indices for the array and create LA, and add to q + for(ASTVec::iterator it=listOfIndices.begin(),itend=listOfIndices.end();it!=itend;it++) { + if(BVCONST == it->GetKind()) { + continue; + } + + ASTNode the_index = *it; + //get the arrayname + ASTNode ArrName = iset->first; + // if(SYMBOL != ArrName.GetKind()) + // FatalError("SATBased_ArrayReadRefinement: arrname is not a SYMBOL",ArrName); + ASTNode arr_read1 = CreateTerm(READ, ArrName.GetValueWidth(), ArrName, the_index); + //get the variable corresponding to the array_read1 + ASTNode arrsym1 = _arrayread_symbol[arr_read1]; + if(!(SYMBOL == arrsym1.GetKind() || BVCONST == arrsym1.GetKind())) + FatalError("TopLevelSAT: refinementloop:term arrsym1 corresponding to READ must be a var", arrsym1); + + //we have nonconst index here. create Leibnitz axiom for it + //w.r.t every index in listOfIndices + for(ASTVec::iterator it1=listOfIndices.begin(),itend1=listOfIndices.end(); + it1!=itend1;it1++) { + ASTNode compare_index = *it1; + //do not compare with yourself + if(the_index == compare_index) + continue; + + //prepare for SAT LOOP + //first construct the antecedent for the LA axiom + ASTNode eqOfIndices = + (exprless(the_index,compare_index)) ? + CreateSimplifiedEQ(the_index,compare_index) : CreateSimplifiedEQ(compare_index,the_index); + + ASTNode arr_read2 = CreateTerm(READ, ArrName.GetValueWidth(), ArrName, compare_index); + //get the variable corresponding to the array_read2 + ASTNode arrsym2 = _arrayread_symbol[arr_read2]; + if(!(SYMBOL == arrsym2.GetKind() || BVCONST == arrsym2.GetKind())) + FatalError("TopLevelSAT: refinement loop:" + "term arrsym2 corresponding to READ must be a var", arrsym2); + + ASTNode eqOfReads = CreateSimplifiedEQ(arrsym1,arrsym2); + //construct appropriate Leibnitz axiom + ASTNode LeibnitzAxiom = CreateNode(IMPLIES, eqOfIndices, eqOfReads); + if(ASTFalse == ComputeFormulaUsingModel(LeibnitzAxiom)) + //FalseAxioms = CreateNode(AND,FalseAxioms,LeibnitzAxiom); + FalseAxiomsVec.push_back(LeibnitzAxiom); + else + //RemainingAxioms = CreateNode(AND,RemainingAxioms,LeibnitzAxiom); + RemainingAxiomsVec.push_back(LeibnitzAxiom); + } + ASTNode FalseAxioms = (FalseAxiomsVec.size()>1) ? CreateNode(AND,FalseAxiomsVec) : FalseAxiomsVec[0]; + ASTNodeStats("adding false readaxioms to SAT: ", FalseAxioms); + int res2 = CallSAT_ResultCheck(newS,FalseAxioms,orig_input); + if(2!=res2) { + return res2; + } + } + } + ASTNode RemainingAxioms = (RemainingAxiomsVec.size()>1) ? CreateNode(AND,RemainingAxiomsVec):RemainingAxiomsVec[0]; + ASTNodeStats("adding remaining readaxioms to SAT: ", RemainingAxioms); + return CallSAT_ResultCheck(newS,RemainingAxioms,orig_input); + } //end of SATBased_ArrayReadRefinement + + ASTNode BeevMgr::Create_ArrayWriteAxioms(const ASTNode& term, const ASTNode& newvar) { + if(READ != term.GetKind() && WRITE != term[0].GetKind()) { + FatalError("Create_ArrayWriteAxioms: Input must be a READ over a WRITE",term); + } + + ASTNode lhs = newvar; + ASTNode rhs = term; + ASTNode arraywrite_axiom = CreateSimplifiedEQ(lhs,rhs); + return arraywrite_axiom; + }//end of Create_ArrayWriteAxioms() + + int BeevMgr::SATBased_ArrayWriteRefinement(MINISAT::Solver& newS, const ASTNode& orig_input) { + ASTNode writeAxiom; + ASTNodeMap::iterator it = ReadOverWrite_NewName_Map.begin(); + ASTNodeMap::iterator itend = ReadOverWrite_NewName_Map.end(); + //int count = 0; + //int num_write_axioms = ReadOverWrite_NewName_Map.size(); + + ASTVec FalseAxioms, RemainingAxioms; + FalseAxioms.push_back(ASTTrue); + RemainingAxioms.push_back(ASTTrue); + for(;it!=itend;it++) { + //Guided refinement starts here + ComputeFormulaMap.clear(); + writeAxiom = Create_ArrayWriteAxioms(it->first,it->second); + if(ASTFalse == ComputeFormulaUsingModel(writeAxiom)) { + writeAxiom = TransformFormula(writeAxiom); + FalseAxioms.push_back(writeAxiom); + } + else { + writeAxiom = TransformFormula(writeAxiom); + RemainingAxioms.push_back(writeAxiom); + } + } + + writeAxiom = (FalseAxioms.size() != 1) ? CreateNode(AND,FalseAxioms) : FalseAxioms[0]; + ASTNodeStats("adding false writeaxiom to SAT: ", writeAxiom); + int res2 = CallSAT_ResultCheck(newS,writeAxiom,orig_input); + if(2!=res2) { + return res2; + } + + writeAxiom = (RemainingAxioms.size() != 1) ? CreateNode(AND,RemainingAxioms) : RemainingAxioms[0]; + ASTNodeStats("adding remaining writeaxiom to SAT: ", writeAxiom); + res2 = CallSAT_ResultCheck(newS,writeAxiom,orig_input); + if(2!=res2) { + return res2; + } + + return 2; + } //end of SATBased_ArrayWriteRefinement + + //Check result after calling SAT FIXME: Document arguments in + //comments, and give them meaningful names. How is anyone supposed + //to know what "q" is? + int BeevMgr::CallSAT_ResultCheck(MINISAT::Solver& newS, + const ASTNode& q, const ASTNode& orig_input) { + //Bitblast, CNF, call SAT now + ASTNode BBFormula = BBForm(q); + //ASTNodeStats("after bitblasting", BBFormula); + ClauseList *cllp = ToCNF(BBFormula); + // if(stats && print_nodes) { + // cout << "\nClause list" << endl; + // PrintClauseList(cout, *cllp); + // cerr << "\n finished printing clauselist\n"; + // } + + bool sat = toSATandSolve(newS,*cllp); + // Temporary debugging call. + // CheckBBandCNF(newS, BBFormula); + + DeleteClauseList(cllp); + if(!sat) { + PrintOutput(true); + return 1; + } + else if(newS.okay()) { + CounterExampleMap.clear(); + ConstructCounterExample(newS); + if (stats && print_nodes) { + PrintSATModel(newS); + } + //check if the counterexample is good or not + ComputeFormulaMap.clear(); + if(counterexample_checking_during_refinement) + bvdiv_exception_occured = false; + ASTNode orig_result = ComputeFormulaUsingModel(orig_input); + if(!(ASTTrue == orig_result || ASTFalse == orig_result)) + FatalError("TopLevelSat: Original input must compute to true or false against model"); + +// if(!arrayread_refinement && !(ASTTrue == orig_result)) { +// print_counterexample = true; +// PrintCounterExample(true); +// FatalError("counterexample bogus : arrayread_refinement is switched off: " +// "EITHER all LA axioms have not been added OR bitblaster() or ToCNF()" +// "or satsolver() or counterexamplechecker() have a bug"); +// } + + // if the counterexample is indeed a good one, then return + // invalid + if(ASTTrue == orig_result) { + CheckCounterExample(newS.okay()); + PrintOutput(false); + PrintCounterExample(newS.okay()); + PrintCounterExample_InOrder(newS.okay()); + return 0; + } + // counterexample is bogus: flag it + else { + if(stats && print_nodes) { + cout << "Supposedly bogus one: \n"; + bool tmp = print_counterexample; + print_counterexample = true; + PrintCounterExample(true); + print_counterexample = tmp; + } + + return 2; + } + } + else { + PrintOutput(true); + return -100; + } + } //end of CALLSAT_ResultCheck + + + //FUNCTION: this function accepts a boolvector and returns a BVConst + ASTNode BeevMgr::BoolVectoBVConst(hash_map<unsigned,bool> * w, unsigned int l) { + unsigned len = w->size(); + if(l < len) + FatalError("BoolVectorBVConst : length of bitvector does not match hash_map size:",ASTUndefined,l); + std::string cc; + for(unsigned int jj = 0; jj < l; jj++) { + if((*w)[jj] == true) + cc += '1'; + else if((*w)[jj] == false) + cc += '0'; + else + cc += '0'; + } + return CreateBVConst(cc.c_str(),2); + } + + void BeevMgr::PrintActivityLevels_Of_SATVars(char * init_msg, MINISAT::Solver& newS) { + if(!print_sat_varorder) + return; + + ASTtoSATMap::iterator itbegin = _ASTNode_to_SATVar.begin(); + ASTtoSATMap::iterator itend = _ASTNode_to_SATVar.end(); + + cout << init_msg; + cout << ": Printing activity levels of variables\n"; + for(ASTtoSATMap::iterator it=itbegin;it!=itend;it++){ + cout << (it->second) << " : "; + (it->first).PL_Print(cout,0); + cout << " : "; + cout << newS.returnActivity(it->second) << endl; + } + } + + //this function biases the activity levels of MINISAT variables. + void BeevMgr::ChangeActivityLevels_Of_SATVars(MINISAT::Solver& newS) { + if(!variable_activity_optimize) + return; + + ASTtoSATMap::iterator itbegin = _ASTNode_to_SATVar.begin(); + ASTtoSATMap::iterator itend = _ASTNode_to_SATVar.end(); + + unsigned int index=1; + double base = 2; + for(ASTtoSATMap::iterator it=itbegin;it!=itend;it++){ + ASTNode n = it->first; + + if(BVGETBIT == n.GetKind() || NOT == n.GetKind()) { + if(BVGETBIT == n.GetKind()) + index = GetUnsignedConst(n[1]); + else if (NOT == n.GetKind() && BVGETBIT == n[0].GetKind()) + index = GetUnsignedConst(n[0][1]); + else + index = 0; + double initial_activity = pow(base,(double)index); + newS.updateInitialActivity(it->second,initial_activity); + } + else { + double initial_activity = pow(base,pow(base,(double)index)); + newS.updateInitialActivity(it->second,initial_activity); + } + } + } + + //This function prints the output of the STP solver + void BeevMgr::PrintOutput(bool true_iff_valid) { + //self-explanatory + if(true_iff_valid) { + ValidFlag = true; + if(print_output) { + if(smtlib_parser_enable) + cout << "unsat\n"; + else + cout << "Valid.\n"; + } + } + else { + ValidFlag = false; + if(print_output) { + if(smtlib_parser_enable) + cout << "sat\n"; + else + cout << "Invalid.\n"; + } + } + } +}; //end of namespace BEEV |