diff options
Diffstat (limited to 'stp')
51 files changed, 23432 insertions, 0 deletions
diff --git a/stp/AST/AST.cpp b/stp/AST/AST.cpp new file mode 100644 index 00000000..ab290395 --- /dev/null +++ b/stp/AST/AST.cpp @@ -0,0 +1,1587 @@ +/******************************************************************** + * 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" +namespace BEEV { + //some global variables that are set through commandline options. it + //is best that these variables remain global. Default values set + //here + // + //collect statistics on certain functions + bool stats = false; + //print DAG nodes + bool print_nodes = false; + //tentative global var to allow for variable activity optimization + //in the SAT solver. deprecated. + bool variable_activity_optimize = false; + //run STP in optimized mode + bool optimize = true; + //do sat refinement, i.e. underconstraint the problem, and feed to + //SAT. if this works, great. else, add a set of suitable constraints + //to re-constraint the problem correctly, and call SAT again, until + //all constraints have been added. + bool arrayread_refinement = true; + //flag to control write refinement + bool arraywrite_refinement = true; + //check the counterexample against the original input to STP + bool check_counterexample = false; + //construct the counterexample in terms of original variable based + //on the counterexample returned by SAT solver + bool construct_counterexample = true; + bool print_counterexample = false; + //if this option is true then print the way dawson wants using a + //different printer. do not use this printer. + bool print_arrayval_declaredorder = false; + //flag to decide whether to print "valid/invalid" or not + bool print_output = false; + //do linear search in the array values of an input array. experimental + bool linear_search = false; + //print the variable order chosen by the sat solver while it is + //solving. + bool print_sat_varorder = false; + //turn on word level bitvector solver + bool wordlevel_solve = true; + //turn off XOR flattening + bool xor_flatten = false; + + //the smtlib parser has been turned on + bool smtlib_parser_enable = false; + //print the input back + bool print_STPinput_back = false; + + //global BEEVMGR for the parser + BeevMgr * globalBeevMgr_for_parser; + + void (*vc_error_hdlr)(const char* err_msg) = NULL; + /** This is reusable empty vector, for representing empty children arrays */ + ASTVec _empty_ASTVec; + //////////////////////////////////////////////////////////////// + // ASTInternal members + //////////////////////////////////////////////////////////////// + /** Trivial but virtual destructor */ + ASTInternal::~ASTInternal() { } + + //////////////////////////////////////////////////////////////// + // ASTInterior members + //////////////////////////////////////////////////////////////// + /** Copy constructor */ + // ASTInterior::ASTInterior(const ASTInterior &int_node) + // { + // _kind = int_node._kind; + // _children = int_node._children; + // } + + /** Trivial but virtual destructor */ + ASTInterior::~ASTInterior() { } + + // FIXME: Darn it! I think this ends up copying the children twice! + /** Either return an old node or create it if it doesn't exist. + Note that nodes are physically allocated in the hash table. */ + + // There is an inelegance here that I don't know how to solve. I'd + // like to heap allocate and do some other initialization on keys only + // if they aren't in the hash table. It would be great if the + // "insert" method took a "creator" class so that I could do that + // between when it notices that the key is not there and when it + // inserts it. Alternatively, it would be great if I could insert the + // temporary key and replace it if it actually got inserted. But STL + // hash_set doesn't have the creator feature and paternalistically + // declares that keys are immutable, even though (it seems to me) that + // they could be mutated if the hash value and eq values did not + // change. + + ASTInterior *BeevMgr::LookupOrCreateInterior(ASTInterior *n_ptr) { + ASTInteriorSet::iterator it; + + if ((it = _interior_unique_table.find(n_ptr)) == _interior_unique_table.end()) { + // Make a new ASTInterior node + // We want (NOT alpha) always to have alpha.nodenum + 1. + if (n_ptr->GetKind() == NOT) { + n_ptr->SetNodeNum(n_ptr->GetChildren()[0].GetNodeNum()+1); + } + else { + n_ptr->SetNodeNum(NewNodeNum()); + } + pair<ASTInteriorSet::const_iterator, bool> p = _interior_unique_table.insert(n_ptr); + return *(p.first); + } + else + // Delete the temporary node, and return the found node. + delete n_ptr; + return *it; + } + + size_t ASTInterior::ASTInteriorHasher::operator() (const ASTInterior *int_node_ptr) const { + //size_t hashval = 0; + size_t hashval = ((size_t) int_node_ptr->GetKind()); + const ASTVec &ch = int_node_ptr->GetChildren(); + ASTVec::const_iterator iend = ch.end(); + for (ASTVec::const_iterator i = ch.begin(); i != iend; i++) { + //Using "One at a time hash" by Bob Jenkins + hashval += i->Hash(); + hashval += (hashval << 10); + hashval ^= (hashval >> 6); + } + + hashval += (hashval << 3); + hashval ^= (hashval >> 11); + hashval += (hashval << 15); + return hashval; + //return hashval += ((size_t) int_node_ptr->GetKind()); + } + + + void ASTInterior::CleanUp() { + // cout << "Deleting node " << this->GetNodeNum() << endl; + _bm._interior_unique_table.erase(this); + delete this; + } + + //////////////////////////////////////////////////////////////// + // ASTNode members + //////////////////////////////////////////////////////////////// + //ASTNode constructors are inlined in AST.h + bool ASTNode::IsAlreadyPrinted() const { + BeevMgr &bm = GetBeevMgr(); + return (bm.AlreadyPrintedSet.find(*this) != bm.AlreadyPrintedSet.end()); + } + + void ASTNode::MarkAlreadyPrinted() const { + // FIXME: Fetching BeevMgr is annoying. Can we put this in lispprinter class? + BeevMgr &bm = GetBeevMgr(); + bm.AlreadyPrintedSet.insert(*this); + } + + // Get the name from a symbol (char *). It's an error if kind != SYMBOL + const char * const ASTNode::GetName() const { + if (GetKind() != SYMBOL) + FatalError("GetName: Called GetName on a non-symbol: ", *this); + return ((ASTSymbol *) _int_node_ptr)->GetName(); + } + + // Print in lisp format + ostream &ASTNode::LispPrint(ostream &os, int indentation) const { + // Clear the PrintMap + BeevMgr& bm = GetBeevMgr(); + bm.AlreadyPrintedSet.clear(); + return LispPrint_indent(os, indentation); + } + + // Print newline and indentation, then print the thing. + ostream &ASTNode::LispPrint_indent(ostream &os, + int indentation) const + { + os << endl << spaces(indentation); + LispPrint1(os, indentation); + return os; + } + + /** Internal function to print in lisp format. Assume newline + and indentation printed already before first line. Recursive + calls will have newline & indent, though */ + ostream &ASTNode::LispPrint1(ostream &os, int indentation) const { + if (!IsDefined()) { + os << "<undefined>"; + return os; + } + Kind kind = GetKind(); + // FIXME: figure out how to avoid symbols with same names as kinds. +// if (kind == READ) { +// const ASTVec &children = GetChildren(); +// children[0].LispPrint1(os, indentation); +// os << "[" << children[1] << "]"; +// } else + if(kind == BVGETBIT) { + const ASTVec &children = GetChildren(); + // child 0 is a symbol. Print without the NodeNum. + os << GetNodeNum() << ":"; + + + + children[0]._int_node_ptr->nodeprint(os); + //os << "{" << children[1].GetBVConst() << "}"; + os << "{"; + children[1]._int_node_ptr->nodeprint(os); + os << "}"; + } else if (kind == NOT) { + const ASTVec &children = GetChildren(); + os << GetNodeNum() << ":"; + os << "(NOT "; + children[0].LispPrint1(os, indentation); + os << ")"; + } + else if (Degree() == 0) { + // Symbol or a kind with no children print as index:NAME if shared, + // even if they have been printed before. + os << GetNodeNum() << ":"; + _int_node_ptr->nodeprint(os); + // os << "(" << _int_node_ptr->_ref_count << ")"; + // os << "{" << GetValueWidth() << "}"; + } + else if (IsAlreadyPrinted()) { + // print non-symbols as "[index]" if seen before. + os << "[" << GetNodeNum() << "]"; + // << "(" << _int_node_ptr->_ref_count << ")"; + } + else { + MarkAlreadyPrinted(); + const ASTVec &children = GetChildren(); + os << GetNodeNum() << ":" + //<< "(" << _int_node_ptr->_ref_count << ")" + << "(" << kind << " "; + // os << "{" << GetValueWidth() << "}"; + ASTVec::const_iterator iend = children.end(); + for (ASTVec::const_iterator i = children.begin(); i != iend; i++) { + i->LispPrint_indent(os, indentation+2); + } + os << ")"; + } + return os; + } + + //print in PRESENTATION LANGUAGE + // + //two pass algorithm: + // + //1. In the first pass, letize this Node, N: i.e. if a node + //1. appears more than once in N, then record this fact. + // + //2. In the second pass print a "global let" and then print N + //2. as follows: Every occurence of a node occuring more than + //2. once is replaced with the corresponding let variable. + ostream& ASTNode::PL_Print(ostream &os, + int indentation) const { + // Clear the PrintMap + BeevMgr& bm = GetBeevMgr(); + bm.PLPrintNodeSet.clear(); + bm.NodeLetVarMap.clear(); + bm.NodeLetVarVec.clear(); + bm.NodeLetVarMap1.clear(); + + //pass 1: letize the node + LetizeNode(); + + //pass 2: + // + //2. print all the let variables and their counterpart expressions + //2. as follows (LET var1 = expr1, var2 = expr2, ... + // + //3. Then print the Node itself, replacing every occurence of + //3. expr1 with var1, expr2 with var2, ... + //os << "("; + if(0 < bm.NodeLetVarMap.size()) { + //ASTNodeMap::iterator it=bm.NodeLetVarMap.begin(); + //ASTNodeMap::iterator itend=bm.NodeLetVarMap.end(); + std::vector<pair<ASTNode,ASTNode> >::iterator it = bm.NodeLetVarVec.begin(); + std::vector<pair<ASTNode,ASTNode> >::iterator itend = bm.NodeLetVarVec.end(); + + os << "(LET "; + //print the let var first + it->first.PL_Print1(os,indentation,false); + os << " = "; + //print the expr + it->second.PL_Print1(os,indentation,false); + + //update the second map for proper printing of LET + bm.NodeLetVarMap1[it->second] = it->first; + + for(it++;it!=itend;it++) { + os << "," << endl; + //print the let var first + it->first.PL_Print1(os,indentation,false); + os << " = "; + //print the expr + it->second.PL_Print1(os,indentation,false); + + //update the second map for proper printing of LET + bm.NodeLetVarMap1[it->second] = it->first; + } + + os << " IN " << endl; + PL_Print1(os,indentation, true); + os << ") "; + } + else + PL_Print1(os,indentation, false); + //os << " )"; + os << " "; + return os; + } //end of PL_Print() + + //traverse "*this", and construct "let variables" for terms that + //occur more than once in "*this". + void ASTNode::LetizeNode(void) const { + Kind kind = this->GetKind(); + + if(kind == SYMBOL || + kind == BVCONST || + kind == FALSE || + kind == TRUE) + return; + + //FIXME: this is ugly. + BeevMgr& bm = GetBeevMgr(); + const ASTVec &c = this->GetChildren(); + for(ASTVec::const_iterator it=c.begin(),itend=c.end();it!=itend;it++){ + ASTNode ccc = *it; + if(bm.PLPrintNodeSet.find(ccc) == bm.PLPrintNodeSet.end()){ + //If branch: if *it is not in NodeSet then, + // + //1. add it to NodeSet + // + //2. Letize its childNodes + + //FIXME: Fetching BeevMgr is annoying. Can we put this in + //some kind of a printer class + bm.PLPrintNodeSet.insert(ccc); + //debugging + //cerr << ccc; + ccc.LetizeNode(); + } + else{ + Kind k = ccc.GetKind(); + if(k == SYMBOL || + k == BVCONST || + k == FALSE || + k == TRUE) + continue; + + //0. Else branch: Node has been seen before + // + //1. Check if the node has a corresponding letvar in the + //1. NodeLetVarMap. + // + //2. if no, then create a new var and add it to the + //2. NodeLetVarMap + if(bm.NodeLetVarMap.find(ccc) == bm.NodeLetVarMap.end()) { + //Create a new symbol. Get some name. if it conflicts with a + //declared name, too bad. + int sz = bm.NodeLetVarMap.size(); + ostringstream oss; + oss << "let_k_" << sz; + + ASTNode CurrentSymbol = bm.CreateSymbol(oss.str().c_str()); + CurrentSymbol.SetValueWidth(this->GetValueWidth()); + CurrentSymbol.SetIndexWidth(this->GetIndexWidth()); + /* If for some reason the variable being created here is + * already declared by the user then the printed output will + * not be a legal input to the system. too bad. I refuse to + * check for this. [Vijay is the author of this comment.] + */ + + bm.NodeLetVarMap[ccc] = CurrentSymbol; + std::pair<ASTNode,ASTNode> node_letvar_pair(CurrentSymbol,ccc); + bm.NodeLetVarVec.push_back(node_letvar_pair); + } + } + } + } //end of LetizeNode() + + void ASTNode::PL_Print1(ostream& os, + int indentation, + bool letize) const { + //os << spaces(indentation); + //os << endl << spaces(indentation); + if (!IsDefined()) { + os << "<undefined>"; + return; + } + + //if this node is present in the letvar Map, then print the letvar + BeevMgr &bm = GetBeevMgr(); + + //this is to print letvars for shared subterms inside the printing + //of "(LET v0 = term1, v1=term1@term2,... + if((bm.NodeLetVarMap1.find(*this) != bm.NodeLetVarMap1.end()) && !letize) { + (bm.NodeLetVarMap1[*this]).PL_Print1(os,indentation,letize); + return; + } + + //this is to print letvars for shared subterms inside the actual + //term to be printed + if((bm.NodeLetVarMap.find(*this) != bm.NodeLetVarMap.end()) && letize) { + (bm.NodeLetVarMap[*this]).PL_Print1(os,indentation,letize); + return; + } + + //otherwise print it normally + Kind kind = GetKind(); + const ASTVec &c = GetChildren(); + switch(kind) { + case BVGETBIT: + c[0].PL_Print1(os,indentation,letize); + os << "{"; + c[1].PL_Print1(os,indentation,letize); + os << "}"; + break; + case BITVECTOR: + os << "BITVECTOR("; + unsigned char * str; + str = CONSTANTBV::BitVector_to_Hex(c[0].GetBVConst()); + os << str << ")"; + CONSTANTBV::BitVector_Dispose(str); + break; + case BOOLEAN: + os << "BOOLEAN"; + break; + case FALSE: + case TRUE: + os << kind; + break; + case BVCONST: + case SYMBOL: + _int_node_ptr->nodeprint(os); + break; + case READ: + c[0].PL_Print1(os, indentation,letize); + os << "["; + c[1].PL_Print1(os,indentation,letize); + os << "]"; + break; + case WRITE: + os << "("; + c[0].PL_Print1(os,indentation,letize); + os << " WITH ["; + c[1].PL_Print1(os,indentation,letize); + os << "] := "; + c[2].PL_Print1(os,indentation,letize); + os << ")"; + os << endl; + break; + case BVUMINUS: + os << kind << "( "; + c[0].PL_Print1(os,indentation,letize); + os << ")"; + break; + case NOT: + os << "NOT("; + c[0].PL_Print1(os,indentation,letize); + os << ") " << endl; + break; + case BVNEG: + os << " ~("; + c[0].PL_Print1(os,indentation,letize); + os << ")"; + break; + case BVCONCAT: + os << "("; + c[0].PL_Print1(os,indentation,letize); + os << " @ "; + c[1].PL_Print1(os,indentation,letize); + os << ")" << endl; + break; + case BVOR: + os << "("; + c[0].PL_Print1(os,indentation,letize); + os << " | "; + c[1].PL_Print1(os,indentation,letize); + os << ")"; + break; + case BVAND: + os << "("; + c[0].PL_Print1(os,indentation,letize); + os << " & "; + c[1].PL_Print1(os,indentation,letize); + os << ")"; + break; + case BVEXTRACT: + c[0].PL_Print1(os,indentation,letize); + os << "["; + os << GetUnsignedConst(c[1]); + os << ":"; + os << GetUnsignedConst(c[2]); + os << "]"; + break; + case BVLEFTSHIFT: + os << "("; + c[0].PL_Print1(os,indentation,letize); + os << " << "; + os << GetUnsignedConst(c[1]); + os << ")"; + break; + case BVRIGHTSHIFT: + os << "("; + c[0].PL_Print1(os,indentation,letize); + os << " >> "; + os << GetUnsignedConst(c[1]); + os << ")"; + break; + case BVMULT: + case BVSUB: + case BVPLUS: + case SBVDIV: + case SBVMOD: + case BVDIV: + case BVMOD: + os << kind << "("; + os << this->GetValueWidth(); + for(ASTVec::const_iterator it=c.begin(),itend=c.end();it!=itend;it++) { + os << ", " << endl; + it->PL_Print1(os,indentation,letize); + } + os << ")" << endl; + break; + case ITE: + os << "IF("; + c[0].PL_Print1(os,indentation,letize); + os << ")" << endl; + os << "THEN "; + c[1].PL_Print1(os,indentation,letize); + os << endl << "ELSE "; + c[2].PL_Print1(os,indentation,letize); + os << endl << "ENDIF"; + break; + case BVLT: + case BVLE: + case BVGT: + case BVGE: + case BVXOR: + case BVNAND: + case BVNOR: + case BVXNOR: + os << kind << "("; + c[0].PL_Print1(os,indentation,letize); + os << ","; + c[1].PL_Print1(os,indentation,letize); + os << ")" << endl; + break; + case BVSLT: + os << "SBVLT" << "("; + c[0].PL_Print1(os,indentation,letize); + os << ","; + c[1].PL_Print1(os,indentation,letize); + os << ")" << endl; + break; + case BVSLE: + os << "SBVLE" << "("; + c[0].PL_Print1(os,indentation,letize); + os << ","; + c[1].PL_Print1(os,indentation,letize); + os << ")" << endl; + break; + case BVSGT: + os << "SBVGT" << "("; + c[0].PL_Print1(os,indentation,letize); + os << ","; + c[1].PL_Print1(os,indentation,letize); + os << ")" << endl; + break; + case BVSGE: + os << "SBVGE" << "("; + c[0].PL_Print1(os,indentation,letize); + os << ","; + c[1].PL_Print1(os,indentation,letize); + os << ")" << endl; + break; + case EQ: + c[0].PL_Print1(os,indentation,letize); + os << " = "; + c[1].PL_Print1(os,indentation,letize); + os << endl; + break; + case NEQ: + c[0].PL_Print1(os,indentation,letize); + os << " /= "; + c[1].PL_Print1(os,indentation,letize); + os << endl; + break; + case AND: + case OR: + case NAND: + case NOR: + case XOR: { + os << "("; + c[0].PL_Print1(os,indentation,letize); + ASTVec::const_iterator it=c.begin(); + ASTVec::const_iterator itend=c.end(); + + it++; + for(;it!=itend;it++) { + os << " " << kind << " "; + it->PL_Print1(os,indentation,letize); + os << endl; + } + os << ")"; + break; + } + case IFF: + os << "("; + os << "("; + c[0].PL_Print1(os,indentation,letize); + os << ")"; + os << " <=> "; + os << "("; + c[1].PL_Print1(os,indentation,letize); + os << ")"; + os << ")"; + os << endl; + break; + case IMPLIES: + os << "("; + os << "("; + c[0].PL_Print1(os,indentation,letize); + os << ")"; + os << " => "; + os << "("; + c[1].PL_Print1(os,indentation,letize); + os << ")"; + os << ")"; + os << endl; + break; + case BVSX: + os << kind << "("; + c[0].PL_Print1(os,indentation,letize); + os << ","; + os << this->GetValueWidth(); + os << ")" << endl; + break; + default: + //remember to use LispPrinter here. Otherwise this function will + //go into an infinite loop. Recall that "<<" is overloaded to + //the lisp printer. FatalError uses lispprinter + FatalError("PL_Print1: printing not implemented for this kind: ",*this); + break; + } + } //end of PL_Print1() + + //////////////////////////////////////////////////////////////// + // BeevMgr members + //////////////////////////////////////////////////////////////// + ASTNode BeevMgr::CreateNode(Kind kind, const ASTVec & back_children) { + // create a new node. Children will be modified. + ASTInterior *n_ptr = new ASTInterior(kind, *this); + + // insert all of children at end of new_children. + ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); + return n; + } + + ASTNode BeevMgr::CreateNode(Kind kind, + const ASTNode& child0, + const ASTVec & back_children) { + + ASTInterior *n_ptr = new ASTInterior(kind, *this); + ASTVec &front_children = n_ptr->_children; + front_children.push_back(child0); + ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); + return n; + } + + ASTNode BeevMgr::CreateNode(Kind kind, + const ASTNode& child0, + const ASTNode& child1, + const ASTVec & back_children) { + + ASTInterior *n_ptr = new ASTInterior(kind, *this); + ASTVec &front_children = n_ptr->_children; + front_children.push_back(child0); + front_children.push_back(child1); + ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); + return n; + } + + + ASTNode BeevMgr::CreateNode(Kind kind, + const ASTNode& child0, + const ASTNode& child1, + const ASTNode& child2, + const ASTVec & back_children) { + ASTInterior *n_ptr = new ASTInterior(kind, *this); + ASTVec &front_children = n_ptr->_children; + front_children.push_back(child0); + front_children.push_back(child1); + front_children.push_back(child2); + ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); + return n; + } + + + ASTInterior *BeevMgr::CreateInteriorNode(Kind kind, + // children array of this node will be modified. + ASTInterior *n_ptr, + const ASTVec & back_children) { + + // insert back_children at end of front_children + ASTVec &front_children = n_ptr->_children; + + front_children.insert(front_children.end(), back_children.begin(), back_children.end()); + + // check for undefined nodes. + ASTVec::const_iterator it_end = front_children.end(); + for (ASTVec::const_iterator it = front_children.begin(); it != it_end; it++) { + if (it->IsNull()) + FatalError("CreateInteriorNode: Undefined childnode in CreateInteriorNode: ", ASTUndefined); + } + + return LookupOrCreateInterior(n_ptr); + } + + /** Trivial but virtual destructor */ + ASTSymbol::~ASTSymbol() {} + + ostream &operator<<(ostream &os, const ASTNodeMap &nmap) + { + ASTNodeMap::const_iterator iend = nmap.end(); + for (ASTNodeMap::const_iterator i = nmap.begin(); i!=iend; i++) { + os << "Key: " << i->first << endl; + os << "Value: " << i->second << endl; + } + return os; + } + + //////////////////////////////////////////////////////////////// + // BeevMgr member functions to create ASTSymbol and ASTBVConst + //////////////////////////////////////////////////////////////// + ASTNode BeevMgr::CreateSymbol(const char * const name) + { + ASTSymbol temp_sym(name, *this); + ASTNode n(LookupOrCreateSymbol(temp_sym)); + return n; + } + +#ifndef NATIVE_C_ARITH + //Create a ASTBVConst node + ASTNode BeevMgr::CreateBVConst(unsigned int width, + unsigned long long int bvconst){ + if(width > (sizeof(unsigned long long int)<<3) || width <= 0) + FatalError("CreateBVConst: trying to create a bvconst of width: ", ASTUndefined, width); + + + CBV bv = CONSTANTBV::BitVector_Create(width, true); + unsigned long c_val = (0x00000000ffffffffLL) & bvconst; + unsigned int copied = 0; + + // sizeof(unsigned long) returns the number of bytes in unsigned + // long. In order to convert it to bits, we need to shift left by + // 3. Hence, sizeof(unsigned long) << 3 + + //The algo below works as follows: It starts by copying the + //lower-order bits of the input "bvconst" in chunks of size = + //number of bits in unsigned long. The variable "copied" keeps + //track of the number of chunks copied so far + + while(copied + (sizeof(unsigned long)<<3) < width){ + CONSTANTBV::BitVector_Chunk_Store(bv, sizeof(unsigned long)<<3,copied,c_val); + bvconst = bvconst >> (sizeof(unsigned long) << 3); + c_val = (0x00000000ffffffffLL) & bvconst; + copied += sizeof(unsigned long) << 3; + } + CONSTANTBV::BitVector_Chunk_Store(bv,width - copied,copied,c_val); + return CreateBVConst(bv,width); + } + + //Create a ASTBVConst node from std::string + ASTNode BeevMgr::CreateBVConst(const char* const strval, int base) { + size_t width = strlen((const char *)strval); + if(!(2 == base || 10 == base || 16 == base)){ + FatalError("CreateBVConst: unsupported base: ",ASTUndefined,base); + } + //FIXME Tim: Earlier versions of the code assume that the length of + //binary strings is 32 bits. + if(10 == base) width = 32; + if(16 == base) width = width * 4; + + //checking if the input is in the correct format + CBV bv = CONSTANTBV::BitVector_Create(width,true); + CONSTANTBV::ErrCode e; + if(2 == base){ + e = CONSTANTBV::BitVector_from_Bin(bv, (unsigned char*)strval); + }else if(10 == base){ + e = CONSTANTBV::BitVector_from_Dec(bv, (unsigned char*)strval); + }else if(16 == base){ + e = CONSTANTBV::BitVector_from_Hex(bv, (unsigned char*)strval); + }else{ + e = CONSTANTBV::ErrCode_Pars; + } + + if(0 != e) { + cerr << "CreateBVConst: " << BitVector_Error(e); + FatalError("",ASTUndefined); + } + + //FIXME + return CreateBVConst(bv, width); + } + + + //FIXME Code currently assumes that it will destroy the bitvector passed to it + ASTNode BeevMgr::CreateBVConst(CBV bv, unsigned width){ + ASTBVConst temp_bvconst(bv, width, *this); + ASTNode n(LookupOrCreateBVConst(temp_bvconst)); + + CONSTANTBV::BitVector_Destroy(bv); + + return n; + } + + ASTNode BeevMgr::CreateZeroConst(unsigned width) { + CBV z = CONSTANTBV::BitVector_Create(width, true); + return CreateBVConst(z, width); + } + + ASTNode BeevMgr::CreateOneConst(unsigned width) { + CBV o = CONSTANTBV::BitVector_Create(width, true); + CONSTANTBV::BitVector_increment(o); + + return CreateBVConst(o,width); + } + + ASTNode BeevMgr::CreateTwoConst(unsigned width) { + CBV two = CONSTANTBV::BitVector_Create(width, true); + CONSTANTBV::BitVector_increment(two); + CONSTANTBV::BitVector_increment(two); + + return CreateBVConst(two,width); + } + + ASTNode BeevMgr::CreateMaxConst(unsigned width) { + CBV max = CONSTANTBV::BitVector_Create(width, false); + CONSTANTBV::BitVector_Fill(max); + + return CreateBVConst(max,width); + } + + //To ensure unique BVConst nodes, lookup the node in unique-table + //before creating a new one. + ASTBVConst *BeevMgr::LookupOrCreateBVConst(ASTBVConst &s) { + ASTBVConst *s_ptr = &s; // it's a temporary key. + + // Do an explicit lookup to see if we need to create a copy of the string. + ASTBVConstSet::const_iterator it; + if ((it = _bvconst_unique_table.find(s_ptr)) == _bvconst_unique_table.end()) { + // Make a new ASTBVConst with duplicated string (can't assign + // _name because it's const). Can cast the iterator to + // non-const -- carefully. + + ASTBVConst * s_copy = new ASTBVConst(s); + s_copy->SetNodeNum(NewNodeNum()); + + pair<ASTBVConstSet::const_iterator, bool> p = _bvconst_unique_table.insert(s_copy); + return *p.first; + } + else{ + // return symbol found in table. + return *it; + } + } + + // Inline because we need to wait until unique_table is defined + void ASTBVConst::CleanUp() { + // cout << "Deleting node " << this->GetNodeNum() << endl; + _bm._bvconst_unique_table.erase(this); + delete this; + } + + // Get the value of bvconst from a bvconst. It's an error if kind != BVCONST + CBV const ASTNode::GetBVConst() const { + if(GetKind() != BVCONST) + FatalError("GetBVConst: non bitvector-constant: ",*this); + return ((ASTBVConst *) _int_node_ptr)->GetBVConst(); + } +#else + //Create a ASTBVConst node + ASTNode BeevMgr::CreateBVConst(const unsigned int width, + const unsigned long long int bvconst) { + if(width > 64 || width <= 0) + FatalError("Fatal Error: CreateBVConst: trying to create a bvconst of width:", ASTUndefined, width); + + //64 bit mask + unsigned long long int mask = 0xffffffffffffffffLL; + mask = mask >> (64 - width); + + unsigned long long int bv = bvconst; + bv = bv & mask; + + ASTBVConst temp_bvconst(bv, *this); + temp_bvconst._value_width = width; + ASTNode n(LookupOrCreateBVConst(temp_bvconst)); + n.SetValueWidth(width); + n.SetIndexWidth(0); + return n; + } + //Create a ASTBVConst node from std::string + ASTNode BeevMgr::CreateBVConst(const char* strval, int base) { + if(!(base == 2 || base == 16 || base == 10)) + FatalError("CreateBVConst: This base is not supported: ", ASTUndefined, base); + + if(10 != base) { + unsigned int width = (base == 2) ? strlen(strval) : strlen(strval)*4; + unsigned long long int val = strtoull(strval, NULL, base); + ASTNode bvcon = CreateBVConst(width, val); + return bvcon; + } + else { + //this is an ugly hack to accomodate SMTLIB format + //restrictions. SMTLIB format represents bitvector constants in + //base 10 (what a terrible idea, but i have no choice but to + //support it), and make an implicit assumption that the length + //is 32 (another terrible idea). + unsigned width = 32; + unsigned long long int val = strtoull(strval, NULL, base); + ASTNode bvcon = CreateBVConst(width, val); + return bvcon; + } + } + + //To ensure unique BVConst nodes, lookup the node in unique-table + //before creating a new one. + ASTBVConst *BeevMgr::LookupOrCreateBVConst(ASTBVConst &s) { + ASTBVConst *s_ptr = &s; // it's a temporary key. + + // Do an explicit lookup to see if we need to create a copy of the + // string. + ASTBVConstSet::const_iterator it; + if ((it = _bvconst_unique_table.find(s_ptr)) == _bvconst_unique_table.end()) { + // Make a new ASTBVConst. Can cast the iterator to non-const -- + // carefully. + unsigned int width = s_ptr->_value_width; + ASTBVConst * s_ptr1 = new ASTBVConst(s_ptr->GetBVConst(), *this); + s_ptr1->SetNodeNum(NewNodeNum()); + s_ptr1->_value_width = width; + pair<ASTBVConstSet::const_iterator, bool> p = _bvconst_unique_table.insert(s_ptr1); + return *p.first; + } + else + // return BVConst found in table. + return *it; + } + + // Inline because we need to wait until unique_table is defined + void ASTBVConst::CleanUp() { + // cout << "Deleting node " << this->GetNodeNum() << endl; + _bm._bvconst_unique_table.erase(this); + delete this; + } + + // Get the value of bvconst from a bvconst. It's an error if kind + // != BVCONST + unsigned long long int ASTNode::GetBVConst() const { + if(GetKind() != BVCONST) + FatalError("GetBVConst: non bitvector-constant: ", *this); + return ((ASTBVConstTmp *) _int_node_ptr)->GetBVConst(); + } + + ASTNode BeevMgr::CreateZeroConst(unsigned width) { + return CreateBVConst(width,0); + } + + ASTNode BeevMgr::CreateOneConst(unsigned width) { + return CreateBVConst(width,1); + } + + ASTNode BeevMgr::CreateTwoConst(unsigned width) { + return CreateBVConst(width,2); + } + + ASTNode BeevMgr::CreateMaxConst(unsigned width) { + std::string s; + s.insert(s.end(),width,'1'); + return CreateBVConst(s.c_str(),2); + } + +#endif + + // FIXME: _name is now a constant field, and this assigns to it + // because it tries not to copy the string unless it needs to. How + // do I avoid copying children in ASTInterior? Perhaps I don't! + + // Note: There seems to be a limitation of hash_set, in that insert + // returns a const iterator to the value. That prevents us from + // modifying the name (in a hash-preserving way) after the symbol is + // inserted. FIXME: Is there a way to do this with insert? Need a + // function to make a new object in the middle of insert. Read STL + // documentation. + + ASTSymbol *BeevMgr::LookupOrCreateSymbol(ASTSymbol& s) { + ASTSymbol *s_ptr = &s; // it's a temporary key. + + // Do an explicit lookup to see if we need to create a copy of the string. + ASTSymbolSet::const_iterator it; + if ((it = _symbol_unique_table.find(s_ptr)) == _symbol_unique_table.end()) { + // Make a new ASTSymbol with duplicated string (can't assign + // _name because it's const). Can cast the iterator to + // non-const -- carefully. + //std::string strname(s_ptr->GetName()); + ASTSymbol * s_ptr1 = new ASTSymbol(strdup(s_ptr->GetName()), *this); + s_ptr1->SetNodeNum(NewNodeNum()); + s_ptr1->_value_width = s_ptr->_value_width; + pair<ASTSymbolSet::const_iterator, bool> p = _symbol_unique_table.insert(s_ptr1); + return *p.first; + } + else + // return symbol found in table. + return *it; + } + + bool BeevMgr::LookupSymbol(ASTSymbol& s) { + ASTSymbol* s_ptr = &s; // it's a temporary key. + + if(_symbol_unique_table.find(s_ptr) == _symbol_unique_table.end()) + return false; + else + return true; + } + + // Inline because we need to wait until unique_table is defined + void ASTSymbol::CleanUp() { + // cout << "Deleting node " << this->GetNodeNum() << endl; + _bm._symbol_unique_table.erase(this); + //FIXME This is a HUGE free to invoke. + //TEST IT! + free((char*) this->_name); + delete this; + } + + //////////////////////////////////////////////////////////////// + // + // IO manipulators for Lisp format printing of AST. + // + //////////////////////////////////////////////////////////////// + + // FIXME: Additional controls + // * Print node numbers (addresses/nums) + // * Printlength limit + // * Printdepth limit + + /** Print a vector of ASTNodes in lisp format */ + ostream &LispPrintVec(ostream &os, const ASTVec &v, int indentation) + { + // Print the children + ASTVec::const_iterator iend = v.end(); + for (ASTVec::const_iterator i = v.begin(); i != iend; i++) { + i->LispPrint_indent(os, indentation); + } + return os; + } + + // FIXME: Made non-ref in the hope that it would work better. + void lp(ASTNode node) + { + cout << lisp(node) << endl; + } + + void lpvec(const ASTVec &vec) + { + vec[0].GetBeevMgr().AlreadyPrintedSet.clear(); + LispPrintVec(cout, vec, 0); + cout << endl; + } + + // Copy constructor. Maintain _ref_count + ASTNode::ASTNode(const ASTNode &n) : _int_node_ptr(n._int_node_ptr) { +#ifndef SMTLIB + if (n._int_node_ptr) { + n._int_node_ptr->IncRef(); + } +#endif + } + + + /* FUNCTION: Typechecker for terms and formulas + * + * TypeChecker: Assumes that the immediate Children of the input + * ASTNode have been typechecked. This function is suitable in + * scenarios like where you are building the ASTNode Tree, and you + * typecheck as you go along. It is not suitable as a general + * typechecker + */ + void BeevMgr::BVTypeCheck(const ASTNode& n) { + Kind k = n.GetKind(); + //The children of bitvector terms are in turn bitvectors. + ASTVec v = n.GetChildren(); + if(is_Term_kind(k)) { + switch(k) { + case BVCONST: + if(BITVECTOR_TYPE != n.GetType()) + FatalError("BVTypeCheck: The term t does not typecheck, where t = \n",n); + break; + case SYMBOL: + return; + case ITE: + if(BOOLEAN_TYPE != n[0].GetType() && + BITVECTOR_TYPE != n[1].GetType() && + BITVECTOR_TYPE != n[2].GetType()) + FatalError("BVTypeCheck: The term t does not typecheck, where t = \n",n); + if(n[1].GetValueWidth() != n[2].GetValueWidth()) + FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n",n); + if(n[1].GetIndexWidth() != n[2].GetIndexWidth()) + FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n",n); + break; + case READ: + if(n[0].GetIndexWidth() != n[1].GetValueWidth()) { + cerr << "Length of indexwidth of array: " << n[0] << " is : " << n[0].GetIndexWidth() << endl; + cerr << "Length of the actual index is: " << n[1] << " is : " << n[1].GetValueWidth() << endl; + FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n",n); + } + break; + case WRITE: + if(n[0].GetIndexWidth() != n[1].GetValueWidth()) + FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n",n); + if(n[0].GetValueWidth() != n[2].GetValueWidth()) + FatalError("BVTypeCheck: valuewidth of array != length of actual value in the term t = \n",n); + break; + case BVOR: + case BVAND: + case BVXOR: + case BVNOR: + case BVNAND: + case BVXNOR: + case BVPLUS: + case BVMULT: + case BVDIV: + case BVMOD: + case BVSUB: { + if(!(v.size() >= 2)) + FatalError("BVTypeCheck:bitwise Booleans and BV arith operators must have atleast two arguments\n",n); + unsigned int width = n.GetValueWidth(); + for(ASTVec::iterator it=v.begin(),itend=v.end();it!=itend;it++){ + if(width != it->GetValueWidth()) { + cerr << "BVTypeCheck:Operands of bitwise-Booleans and BV arith operators must be of equal length\n"; + cerr << n << endl; + cerr << "width of term:" << width << endl; + cerr << "width of offending operand:" << it->GetValueWidth() << endl; + FatalError("BVTypeCheck:Offending operand:\n",*it); + } + if(BITVECTOR_TYPE != it->GetType()) + FatalError("BVTypeCheck: ChildNodes of bitvector-terms must be bitvectors\n",n); + } + break; + } + case BVSX: + //in BVSX(n[0],len), the length of the BVSX term must be + //greater than the length of n[0] + if(n[0].GetValueWidth() >= n.GetValueWidth()) { + FatalError("BVTypeCheck: BVSX(t,bvsx_len) : length of 't' must be <= bvsx_len\n",n); + } + break; + default: + for(ASTVec::iterator it=v.begin(),itend=v.end();it!=itend;it++) + if(BITVECTOR_TYPE != it->GetType()) { + cerr << "The type is: " << it->GetType() << endl; + FatalError("BVTypeCheck:ChildNodes of bitvector-terms must be bitvectors\n",n); + } + break; + } + + switch(k) { + case BVCONCAT: + if(n.Degree() != 2) + FatalError("BVTypeCheck: should have exactly 2 args\n",n); + if(n.GetValueWidth() != n[0].GetValueWidth() + n[1].GetValueWidth()) + FatalError("BVTypeCheck:BVCONCAT: lengths do not add up\n",n); + break; + case BVUMINUS: + case BVNEG: + if(n.Degree() != 1) + FatalError("BVTypeCheck: should have exactly 1 args\n",n); + break; + case BVEXTRACT: + if(n.Degree() != 3) + FatalError("BVTypeCheck: should have exactly 3 args\n",n); + if(!(BVCONST == n[1].GetKind() && BVCONST == n[2].GetKind())) + FatalError("BVTypeCheck: indices should be BVCONST\n",n); + if(n.GetValueWidth() != GetUnsignedConst(n[1])- GetUnsignedConst(n[2])+1) + FatalError("BVTypeCheck: length mismatch\n",n); + break; + case BVLEFTSHIFT: + case BVRIGHTSHIFT: + if(n.Degree() != 2) + FatalError("BVTypeCheck: should have exactly 2 args\n",n); + break; + //case BVVARSHIFT: + //case BVSRSHIFT: + break; + default: + break; + } + } + else { + if(!(is_Form_kind(k) && BOOLEAN_TYPE == n.GetType())) + FatalError("BVTypeCheck: not a formula:",n); + switch(k){ + case TRUE: + case FALSE: + case SYMBOL: + return; + case EQ: + case NEQ: + if(!(n[0].GetValueWidth() == n[1].GetValueWidth() && + n[0].GetIndexWidth() == n[1].GetIndexWidth())) { + cerr << "valuewidth of lhs of EQ: " << n[0].GetValueWidth() << endl; + cerr << "valuewidth of rhs of EQ: " << n[1].GetValueWidth() << endl; + cerr << "indexwidth of lhs of EQ: " << n[0].GetIndexWidth() << endl; + cerr << "indexwidth of rhs of EQ: " << n[1].GetIndexWidth() << endl; + FatalError("BVTypeCheck: terms in atomic formulas must be of equal length",n); + } + break; + case BVLT: + case BVLE: + case BVGT: + case BVGE: + case BVSLT: + case BVSLE: + case BVSGT: + case BVSGE: + if(BITVECTOR_TYPE != n[0].GetType() && BITVECTOR_TYPE != n[1].GetType()) + FatalError("BVTypeCheck: terms in atomic formulas must be bitvectors",n); + if(n[0].GetValueWidth() != n[1].GetValueWidth()) + FatalError("BVTypeCheck: terms in atomic formulas must be of equal length",n); + if(n[0].GetIndexWidth() != n[1].GetIndexWidth()) + FatalError("BVTypeCheck: terms in atomic formulas must be of equal length",n); + break; + case NOT: + if(1 != n.Degree()) + FatalError("BVTypeCheck: NOT formula can have exactly one childNode",n); + break; + case AND: + case OR: + case XOR: + case NAND: + case NOR: + if(2 > n.Degree()) + FatalError("BVTypeCheck: AND/OR/XOR/NAND/NOR: must have atleast 2 ChildNodes",n); + break; + case IFF: + case IMPLIES: + if(2 != n.Degree()) + FatalError("BVTypeCheck:IFF/IMPLIES must have exactly 2 ChildNodes",n); + break; + case ITE: + if(3 != n.Degree()) + FatalError("BVTypeCheck:ITE must have exactly 3 ChildNodes",n); + break; + default: + FatalError("BVTypeCheck: Unrecognized kind: ",ASTUndefined); + break; + } + } + } //End of TypeCheck function + + //add an assertion to the current logical context + void BeevMgr::AddAssert(const ASTNode& assert) { + if(!(is_Form_kind(assert.GetKind()) && BOOLEAN_TYPE == assert.GetType())) { + FatalError("AddAssert:Trying to assert a non-formula:",assert); + } + + ASTVec * v; + //if the stack of ASTVec is not empty, then take the top ASTVec + //and add the input assert to it + if(!_asserts.empty()) { + v = _asserts.back(); + //v->push_back(TransformFormula(assert)); + v->push_back(assert); + } + else { + //else create a logical context, and add it to the top of the + //stack + v = new ASTVec(); + //v->push_back(TransformFormula(assert)); + v->push_back(assert); + _asserts.push_back(v); + } + } + + void BeevMgr::Push(void) { + ASTVec * v; + v = new ASTVec(); + _asserts.push_back(v); + } + + void BeevMgr::Pop(void) { + if(!_asserts.empty()) { + ASTVec * c = _asserts.back(); + //by calling the clear function we ensure that the ref count is + //decremented for the ASTNodes stored in c + c->clear(); + delete c; + _asserts.pop_back(); + } + } + + void BeevMgr::AddQuery(const ASTNode& q) { + //_current_query = TransformFormula(q); + //cerr << "\nThe current query is: " << q << endl; + _current_query = q; + } + + const ASTNode BeevMgr::PopQuery() { + ASTNode q = _current_query; + _current_query = ASTTrue; + return q; + } + + const ASTNode BeevMgr::GetQuery() { + return _current_query; + } + + const ASTVec BeevMgr::GetAsserts(void) { + vector<ASTVec *>::iterator it = _asserts.begin(); + vector<ASTVec *>::iterator itend = _asserts.end(); + + ASTVec v; + for(;it!=itend;it++) { + if(!(*it)->empty()) + v.insert(v.end(),(*it)->begin(),(*it)->end()); + } + return v; + } + + //Create a new variable of ValueWidth 'n' + ASTNode BeevMgr::NewArrayVar(unsigned int index, unsigned int value) { + std:: string c("v"); + char d[32]; + sprintf(d,"%d",_symbol_count++); + std::string ccc(d); + c += "_writearray_" + ccc; + + ASTNode CurrentSymbol = CreateSymbol(c.c_str()); + CurrentSymbol.SetValueWidth(value); + CurrentSymbol.SetIndexWidth(index); + return CurrentSymbol; + } //end of NewArrayVar() + + + //Create a new variable of ValueWidth 'n' + ASTNode BeevMgr::NewVar(unsigned int value) { + std:: string c("v"); + char d[32]; + sprintf(d,"%d",_symbol_count++); + std::string ccc(d); + c += "_new_stp_var_" + ccc; + + ASTNode CurrentSymbol = CreateSymbol(c.c_str()); + CurrentSymbol.SetValueWidth(value); + CurrentSymbol.SetIndexWidth(0); + _introduced_symbols.insert(CurrentSymbol); + return CurrentSymbol; + } //end of NewVar() + + //prints statistics for the ASTNode + void BeevMgr::ASTNodeStats(const char * c, const ASTNode& a){ + if(!stats) + return; + + StatInfoSet.clear(); + //print node size: + cout << endl << "Printing: " << c; + if(print_nodes) { + //a.PL_Print(cout,0); + //cout << endl; + cout << a << endl; + } + cout << "Node size is: "; + cout << NodeSize(a) << endl << endl; + } + + unsigned int BeevMgr::NodeSize(const ASTNode& a, bool clearStatInfo) { + if(clearStatInfo) + StatInfoSet.clear(); + + ASTNodeSet::iterator it; + if((it = StatInfoSet.find(a)) != StatInfoSet.end()) + //has already been counted + return 0; + + //record that you have seen this node already + StatInfoSet.insert(a); + + //leaf node has a size of 1 + if(a.Degree() == 0) + return 1; + + unsigned newn = 1; + ASTVec c = a.GetChildren(); + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) + newn += NodeSize(*it); + return newn; + } + + void BeevMgr::ClearAllTables(void) { + //clear all tables before calling toplevelsat + _ASTNode_to_SATVar.clear(); + _SATVar_to_AST.clear(); + + for(ASTtoBitvectorMap::iterator it=_ASTNode_to_Bitvector.begin(), + itend=_ASTNode_to_Bitvector.end();it!=itend;it++) { + delete it->second; + } + _ASTNode_to_Bitvector.clear(); + + /* OLD Destructor + * for(ASTNodeToVecMap::iterator ivec = BBTermMemo.begin(), + ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { + ivec->second.clear(); + }*/ + + /*What should I do here? For ASTNodes? + * for(ASTNodeMap::iterator ivec = BBTermMemo.begin(), + ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { + ivec->second.clear(); + }*/ + BBTermMemo.clear(); + BBFormMemo.clear(); + NodeLetVarMap.clear(); + NodeLetVarMap1.clear(); + PLPrintNodeSet.clear(); + AlreadyPrintedSet.clear(); + SimplifyMap.clear(); + SimplifyNegMap.clear(); + SolverMap.clear(); + AlwaysTrueFormMap.clear(); + _arrayread_ite.clear(); + _arrayread_symbol.clear(); + _introduced_symbols.clear(); + TransformMap.clear(); + _letid_expr_map.clear(); + CounterExampleMap.clear(); + ComputeFormulaMap.clear(); + StatInfoSet.clear(); + + // for(std::vector<ASTVec *>::iterator it=_asserts.begin(), + // itend=_asserts.end();it!=itend;it++) { + // (*it)->clear(); + // } + _asserts.clear(); + for(ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(), + iset_end = _arrayname_readindices.end(); + iset!=iset_end;iset++) { + iset->second.clear(); + } + + _arrayname_readindices.clear(); + _interior_unique_table.clear(); + _symbol_unique_table.clear(); + _bvconst_unique_table.clear(); + } + + void BeevMgr::ClearAllCaches(void) { + //clear all tables before calling toplevelsat + _ASTNode_to_SATVar.clear(); + _SATVar_to_AST.clear(); + + + for(ASTtoBitvectorMap::iterator it=_ASTNode_to_Bitvector.begin(), + itend=_ASTNode_to_Bitvector.end();it!=itend;it++) { + delete it->second; + } + _ASTNode_to_Bitvector.clear(); + + /*OLD destructor + * for(ASTNodeToVecMap::iterator ivec = BBTermMemo.begin(), + ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { + ivec->second.clear(); + }*/ + + /*What should I do here? + *for(ASTNodeMap::iterator ivec = BBTermMemo.begin(), + ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { + ivec->second.clear(); + }*/ + BBTermMemo.clear(); + BBFormMemo.clear(); + NodeLetVarMap.clear(); + NodeLetVarMap1.clear(); + PLPrintNodeSet.clear(); + AlreadyPrintedSet.clear(); + SimplifyMap.clear(); + SimplifyNegMap.clear(); + SolverMap.clear(); + AlwaysTrueFormMap.clear(); + _arrayread_ite.clear(); + _arrayread_symbol.clear(); + _introduced_symbols.clear(); + TransformMap.clear(); + _letid_expr_map.clear(); + CounterExampleMap.clear(); + ComputeFormulaMap.clear(); + StatInfoSet.clear(); + + for(ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(), + iset_end = _arrayname_readindices.end(); + iset!=iset_end;iset++) { + iset->second.clear(); + } + + _arrayname_readindices.clear(); + //_interior_unique_table.clear(); + //_symbol_unique_table.clear(); + //_bvconst_unique_table.clear(); + } + + void BeevMgr::CopySolverMap_To_CounterExample(void) { + if(!SolverMap.empty()) { + CounterExampleMap.insert(SolverMap.begin(),SolverMap.end()); + } + } + + void FatalError(const char * str, const ASTNode& a, int w) { + if(a.GetKind() != UNDEFINED) { + cerr << "Fatal Error: " << str << endl << a << endl; + cerr << w << endl; + } + else { + cerr << "Fatal Error: " << str << endl; + cerr << w << endl; + } + if (vc_error_hdlr) + vc_error_hdlr(str); + exit(-1); + //assert(0); + } + + void FatalError(const char * str) { + cerr << "Fatal Error: " << str << endl; + if (vc_error_hdlr) + vc_error_hdlr(str); + exit(-1); + //assert(0); + } + + //Variable Order Printer: A global function which converts a MINISAT + //var into a ASTNODE var. It then prints this var along with + //variable order dcisions taken by MINISAT. + void Convert_MINISATVar_To_ASTNode_Print(int minisat_var, + int decision_level, int polarity) { + BEEV::ASTNode vv = globalBeevMgr_for_parser->_SATVar_to_AST[minisat_var]; + cout << spaces(decision_level); + if(polarity) { + cout << "!"; + } + vv.PL_Print(cout,0); + cout << endl; + } + + void SortByExprNum(ASTVec& v) { + sort(v.begin(), v.end(), exprless); + } + + bool isAtomic(Kind kind) { + if(TRUE == kind || + FALSE == kind || + EQ == kind || + NEQ == kind || + BVLT == kind || + BVLE == kind || + BVGT == kind || + BVGE == kind || + BVSLT == kind || + BVSLE == kind || + BVSGT == kind || + BVSGE == kind || + SYMBOL == kind || + BVGETBIT == kind) + return true; + return false; + } + + BeevMgr::~BeevMgr() { + ClearAllTables(); + } +}; // end namespace + diff --git a/stp/AST/AST.h b/stp/AST/AST.h new file mode 100644 index 00000000..53ed7016 --- /dev/null +++ b/stp/AST/AST.h @@ -0,0 +1,1805 @@ +// -*- c++ -*- +/******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ + +#ifndef AST_H +#define AST_H +#include <vector> +#ifdef EXT_HASH_MAP +#include <ext/hash_set> +#include <ext/hash_map> +#else +#include <hash_set> +#include <hash_map> +#endif +#include <iostream> +#include <sstream> +#include <string> +#include <map> +#include <set> +#include "ASTUtil.h" +#include "ASTKind.h" +#include "../sat/Solver.h" +#include "../sat/SolverTypes.h" +#include <cstdlib> +#ifndef NATIVE_C_ARITH +#include "../constantbv/constantbv.h" +#endif +/***************************************************************************** + * LIST OF CLASSES DECLARED IN THIS FILE: + * + * class BeevMgr; + * class ASTNode; + * class ASTInternal; + * class ASTInterior; + * class ASTSymbol; + * class ASTBVConst; + *****************************************************************************/ +namespace BEEV { + using namespace std; + using namespace MINISAT; +#ifdef EXT_HASH_MAP + using namespace __gnu_cxx; +#endif + + //return types for the GetType() function in ASTNode class + enum types { + BOOLEAN_TYPE = 0, + BITVECTOR_TYPE, + ARRAY_TYPE, + UNKNOWN_TYPE + }; + + class BeevMgr; + class ASTNode; + class ASTInternal; + class ASTInterior; + class ASTSymbol; + class ASTBVConst; + class BVSolver; + + //Vector of ASTNodes, used for child nodes among other things. + typedef vector<ASTNode> ASTVec; + extern ASTVec _empty_ASTVec; + extern BeevMgr * globalBeevMgr_for_parser; + + typedef unsigned int * CBV; + + /***************************************************************************/ + /* Class ASTNode: Smart pointer to actual ASTNode internal datastructure. */ + /***************************************************************************/ + class ASTNode { + friend class BeevMgr; + friend class vector<ASTNode>; + //Print the arguments in lisp format. + friend ostream &LispPrintVec(ostream &os, + const ASTVec &v, int indentation = 0); + + private: + // FIXME: make this into a reference? + ASTInternal * _int_node_ptr; // The real data. + + // Usual constructor. + ASTNode(ASTInternal *in); + + //Check if it points to a null node + bool IsNull () const { return _int_node_ptr == NULL; } + + //Equal iff ASTIntNode pointers are the same. + friend bool operator==(const ASTNode node1, const ASTNode node2){ + return ((size_t) node1._int_node_ptr) == ((size_t) node2._int_node_ptr); + } + + /* FIXME: Nondeterministic code *** */ + /** questionable pointer comparison function */ + friend bool operator<(const ASTNode node1, const ASTNode node2){ + return ((size_t) node1._int_node_ptr) < ((size_t) node2._int_node_ptr); + } + + public: + // This is for sorting by expression number (used in Boolean + //optimization) + friend bool exprless(const ASTNode n1, const ASTNode n2) { + Kind k1 = n1.GetKind(); + Kind k2 = n2.GetKind(); + + if(BVCONST == k1 && BVCONST != k2){ + return true; + } + if(BVCONST != k1 && BVCONST == k2){ + return false; + } + + if(SYMBOL == k1 && SYMBOL != k2) { + return true; + } + + if(SYMBOL != k1 && SYMBOL == k2) { + return false; + } + + return (n1.GetNodeNum() < n2.GetNodeNum()); + }//end of exprless + + // Internal lisp-form printer that does not clear _node_print_table + ostream &LispPrint1(ostream &os, int indentation) const; + + ostream &LispPrint_indent(ostream &os, int indentation) const; + + // For lisp DAG printing. Has it been printed already, so we can + // just print the node number? + bool IsAlreadyPrinted() const; + void MarkAlreadyPrinted() const; + + public: + // Default constructor. This gets used when declaring an ASTVec + // of a given size, in the hash table, etc. For faster + // refcounting, create a symbol node for NULL. Give it a big + // initial refcount. Never free it. also check, for ref-count + // overflow? + ASTNode() : _int_node_ptr(NULL) { }; + + // Copy constructor + ASTNode(const ASTNode &n); + + // Destructor + ~ASTNode(); + + // Assignment (for ref counting) + ASTNode& operator=(const ASTNode& n); + + BeevMgr &GetBeevMgr() const; + + // Access node number + int GetNodeNum() const; + + // Access kind. Inlined later because of declaration ordering problems. + Kind GetKind() const; + + // access Children + const ASTVec &GetChildren() const; + + // Return the number of child nodes + size_t Degree() const{ + return GetChildren().size(); + }; + + // Get indexth childNode. + const ASTNode operator[](size_t index) const { + return GetChildren()[index]; + }; + + // Get begin() iterator for child nodes + ASTVec::const_iterator begin() const{ + return GetChildren().begin(); + }; + + // Get end() iterator for child nodes + ASTVec::const_iterator end() const{ + return GetChildren().end(); + }; + + //Get back() element for child nodes + const ASTNode back() const{ + return GetChildren().back(); + }; + + // Get the name from a symbol (char *). It's an error if kind != SYMBOL + const char * const GetName() const; + + //Get the BVCONST value +#ifndef NATIVE_C_ARITH + const CBV GetBVConst() const; +#else + unsigned long long int GetBVConst() const; +#endif + + /*ASTNode is of type BV <==> ((indexwidth=0)&&(valuewidth>0)) + * + *ASTNode is of type ARRAY <==> ((indexwidth>0)&&(valuewidth>0)) + * + *ASTNode is of type BOOLEAN <==> ((indexwidth=0)&&(valuewidth=0)) + * + *both indexwidth and valuewidth should never be less than 0 + */ + unsigned int GetIndexWidth () const; + + // FIXME: This function is dangerous. Try to eliminate it's use. + void SetIndexWidth (unsigned int iw) const; + + unsigned int GetValueWidth () const; + + // FIXME: This function is dangerous. Try to eliminate it's use. + void SetValueWidth (unsigned int vw) const; + + //return the type of the ASTNode + //0 iff BOOLEAN + //1 iff BITVECTOR + //2 iff ARRAY + + /*ASTNode is of type BV <==> ((indexwidth=0)&&(valuewidth>0)) + * + *ASTNode is of type ARRAY <==> ((indexwidth>0)&&(valuewidth>0)) + * + *ASTNode is of type BOOLEAN <==> ((indexwidth=0)&&(valuewidth=0)) + * + *both indexwidth and valuewidth should never be less than 0 + */ + types GetType(void) const; + + // Hash is pointer value of _int_node_ptr. + const size_t Hash() const{ + return (size_t) _int_node_ptr; + //return GetNodeNum(); + } + + // lisp-form printer + ostream& LispPrint(ostream &os, int indentation = 0) const; + + //Presentation Language Printer + ostream& PL_Print(ostream &os, int indentation = 0) const; + + void PL_Print1(ostream &os, int indentation = 0, bool b = false) const; + + //Construct let variables for shared subterms + void LetizeNode(void) const; + + // Attempt to define something that will work in the gdb + friend void lp(ASTNode &node); + friend void lpvec(const ASTVec &vec); + + friend ostream &operator<<(ostream &os, const ASTNode &node) { + node.LispPrint(os, 0); + return os; + }; + + // Check whether the ASTNode points to anything. Undefined nodes + // are created by the default constructor. In binding table (for + // lambda args, etc.), undefined nodes are used to represent + // deleted entries. + bool IsDefined() const { return _int_node_ptr != NULL; } + + /* Hasher class for STL hash_maps and hash_sets that use ASTNodes + * as keys. Needs to be public so people can define hash tables + * (and use ASTNodeMap class)*/ + class ASTNodeHasher { + public: + size_t operator() (const ASTNode& n) const{ + return (size_t) n._int_node_ptr; + //return (size_t)n.GetNodeNum(); + }; + }; //End of ASTNodeHasher + + /* Equality for ASTNode hash_set and hash_map. Returns true iff + * internal pointers are the same. Needs to be public so people + * can define hash tables (and use ASTNodeSet class)*/ + class ASTNodeEqual { + public: + bool operator()(const ASTNode& n1, const ASTNode& n2) const{ + return (n1._int_node_ptr == n2._int_node_ptr); + } + }; //End of ASTNodeEqual + }; //End of Class ASTNode + + void FatalError(const char * str, const ASTNode& a, int w = 0); + void FatalError(const char * str); + void SortByExprNum(ASTVec& c); + bool exprless(const ASTNode n1, const ASTNode n2); + bool isAtomic(Kind k); + + /***************************************************************************/ + /* Class ASTInternal:Abstract base class for internal node representation.*/ + /* Requires Kind and ChildNodes so same traversal works */ + /* on all nodes. */ + /***************************************************************************/ + class ASTInternal { + + friend class ASTNode; + + protected: + + // reference count. + int _ref_count; + + // Kind. It's a type tag and the operator. + Kind _kind; + + // The vector of children (*** should this be in ASTInterior? ***) + ASTVec _children; + + // Manager object. Having this backpointer means it's easy to + // find the manager when we need it. + BeevMgr &_bm; + + //Nodenum is a unique positive integer for the node. The nodenum + //of a node should always be greater than its descendents (which + //is easily achieved by incrementing the number each time a new + //node is created). + int _node_num; + + // Length of bitvector type for array index. The term is an + // array iff this is positive. Otherwise, the term is a bitvector + // or a bit. + unsigned int _index_width; + + // Length of bitvector type for scalar value or array element. + // If this is one, the term represents a single bit (same as a bitvector + // of length 1). It must be 1 or greater. + unsigned int _value_width; + + // Increment refcount. +#ifndef SMTLIB + void IncRef() { ++_ref_count; } +#else + void IncRef() { } +#endif + + // DecRef is a potentially expensive, because it has to delete + // the node from the unique table, in addition to freeing it. + // FIXME: Consider putting in a backpointer (iterator) to the hash + // table entry so it can be deleted without looking it up again. + void DecRef(); + + virtual const Kind GetKind() const { return _kind; } + + virtual ASTVec const &GetChildren() const { return _children; } + + int GetNodeNum() const { return _node_num; } + + void SetNodeNum(int nn) { _node_num = nn; }; + + // Constructor (bm only) + ASTInternal(BeevMgr &bm, int nodenum = 0) : + _ref_count(0), + _kind(UNDEFINED), + _bm(bm), + _node_num(nodenum), + _index_width(0), + _value_width(0) { } + + // Constructor (kind only, empty children, int nodenum) + ASTInternal(Kind kind, BeevMgr &bm, int nodenum = 0) : + _ref_count(0), + _kind(kind), + _bm(bm), + _node_num(nodenum), + _index_width(0), + _value_width(0) { } + + // Constructor (kind and children). This copies the contents of + // the child nodes. + // FIXME: is there a way to avoid repeating these? + ASTInternal(Kind kind, const ASTVec &children, BeevMgr &bm, int nodenum = 0) : + _ref_count(0), + _kind(kind), + _children(children), + _bm(bm), + _node_num(nodenum), + _index_width(0), + _value_width(0) { } + + // Copy constructor. This copies the contents of the child nodes + // array, along with everything else. Assigning the smart pointer, + // ASTNode, does NOT invoke this; This should only be used for + // temporary hash keys before uniquefication. + // FIXME: I don't think children need to be copied. + ASTInternal(const ASTInternal &int_node, int nodenum = 0) : + _ref_count(0), + _kind(int_node._kind), + _children(int_node._children), + _bm(int_node._bm), + _node_num(int_node._node_num), + _index_width(int_node._index_width), + _value_width(int_node._value_width) { } + + // Copying assign operator. Also copies contents of children. + ASTInternal& operator=(const ASTInternal &int_node); + + // Cleanup function for removing from hash table + virtual void CleanUp() = 0; + + // Destructor (does nothing, but is declared virtual here. + virtual ~ASTInternal(); + + // Abstract virtual print function for internal node. + virtual void nodeprint(ostream& os) { os << "*"; }; + }; //End of Class ASTInternal + + // FIXME: Should children be only in interior node type? + /*************************************************************************** + Class ASTInterior: Internal representation of an interior + ASTNode. Generally, these nodes should have at least one + child + ***************************************************************************/ + class ASTInterior : public ASTInternal { + + friend class BeevMgr; + friend class ASTNodeHasher; + friend class ASTNodeEqual; + + private: + + // Hasher for ASTInterior pointer nodes + class ASTInteriorHasher { + public: + size_t operator()(const ASTInterior *int_node_ptr) const; + }; + + // Equality for ASTInterior nodes + class ASTInteriorEqual { + public: + bool operator()(const ASTInterior *int_node_ptr1, + const ASTInterior *int_node_ptr2) const{ + return (*int_node_ptr1 == *int_node_ptr2); + } + }; + + // Used in Equality class for hash tables + friend bool operator==(const ASTInterior &int_node1, + const ASTInterior &int_node2){ + return (int_node1._kind == int_node2._kind) && + (int_node1._children == int_node2._children); + } + + // Call this when deleting a node that has been stored in the + // the unique table + virtual void CleanUp(); + + // Returns kinds. "lispprinter" handles printing of parenthesis + // and childnodes. + virtual void nodeprint(ostream& os) { + os << _kind_names[_kind]; + } + public: + + // FIXME: This should not be public, but has to be because the + // ASTInterior hash table insists on it. I can't seem to make the + // private destructor visible to hash_set. It does not even work + // to put "friend class hash_set<ASTInterior, ...>" in here. + + // Basic constructors + ASTInterior(Kind kind, BeevMgr &bm) : + ASTInternal(kind, bm) { } + + ASTInterior(Kind kind, ASTVec &children, BeevMgr &bm) : + ASTInternal(kind, children, bm) { } + + //Copy constructor. This copies the contents of the child nodes + //array, along with everything else. Assigning the smart pointer, + //ASTNode, does NOT invoke this. + ASTInterior(const ASTInterior &int_node) : ASTInternal(int_node) { } + + // Destructor (does nothing, but is declared virtual here. + virtual ~ASTInterior(); + + }; //End of ASTNodeInterior + + + /***************************************************************************/ + /* Class ASTSymbol: Class to represent internals of Symbol node. */ + /***************************************************************************/ + class ASTSymbol : public ASTInternal{ + friend class BeevMgr; + friend class ASTNode; + friend class ASTNodeHasher; + friend class ASTNodeEqual; + + private: + // The name of the symbol + const char * const _name; + + class ASTSymbolHasher{ + public: + size_t operator() (const ASTSymbol *sym_ptr) const{ + hash<char*> h; + return h(sym_ptr->_name); + }; + }; + + // Equality for ASTInternal nodes + class ASTSymbolEqual{ + public: + bool operator()(const ASTSymbol *sym_ptr1, const ASTSymbol *sym_ptr2) const{ + return (*sym_ptr1 == *sym_ptr2); + } + }; + + friend bool operator==(const ASTSymbol &sym1, const ASTSymbol &sym2){ + return (strcmp(sym1._name, sym2._name) == 0); + } + + const char * const GetName() const{return _name;} + + // Print function for symbol -- return name */ + virtual void nodeprint(ostream& os) { os << _name;} + + // Call this when deleting a node that has been stored in the + // the unique table + virtual void CleanUp(); + + public: + + // Default constructor + ASTSymbol(BeevMgr &bm) : ASTInternal(bm), _name(NULL) { } + + // Constructor. This does NOT copy its argument. + ASTSymbol(const char * const name, BeevMgr &bm) : ASTInternal(SYMBOL, bm), + _name(name) { } + + // Destructor (does nothing, but is declared virtual here. + virtual ~ASTSymbol(); + + // Copy constructor + // FIXME: seems to be calling default constructor for astinternal + ASTSymbol(const ASTSymbol &sym) : + ASTInternal(sym._kind, sym._children, sym._bm), + _name(sym._name) { } + }; //End of ASTSymbol + + + /***************************************************************************/ + /* Class ASTBVConst: Class to represent internals of a bitvectorconst */ + /***************************************************************************/ + +#ifndef NATIVE_C_ARITH + + class ASTBVConst : public ASTInternal { + friend class BeevMgr; + friend class ASTNode; + friend class ASTNodeHasher; + friend class ASTNodeEqual; + + private: + //This is the private copy of a bvconst currently + //This should not be changed at any point + CBV _bvconst; + + class ASTBVConstHasher{ + public: + size_t operator() (const ASTBVConst * bvc) const { + return CONSTANTBV::BitVector_Hash(bvc->_bvconst); + }; + }; + + class ASTBVConstEqual{ + public: + bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const { + if( bvc1->_value_width != bvc2->_value_width){ + return false; + } + return (0==CONSTANTBV::BitVector_Compare(bvc1->_bvconst,bvc2->_bvconst)); + } + }; + + //FIXME Keep an eye on this function + ASTBVConst(CBV bv, unsigned int width, BeevMgr &bm) : + ASTInternal(BVCONST, bm) + { + _bvconst = CONSTANTBV::BitVector_Clone(bv); + _value_width = width; + } + + friend bool operator==(const ASTBVConst &bvc1, const ASTBVConst &bvc2){ + if(bvc1._value_width != bvc2._value_width) + return false; + return (0==CONSTANTBV::BitVector_Compare(bvc1._bvconst,bvc2._bvconst)); + } + // Call this when deleting a node that has been stored in the + // the unique table + virtual void CleanUp(); + + // Print function for bvconst -- return _bvconst value in bin format + virtual void nodeprint(ostream& os) { + unsigned char *res; + const char *prefix; + + if (_value_width%4 == 0) { + res = CONSTANTBV::BitVector_to_Hex(_bvconst); + prefix = "0hex"; + } else { + res = CONSTANTBV::BitVector_to_Bin(_bvconst); + prefix = "0bin"; + } + if (NULL == res) { + os << "nodeprint: BVCONST : could not convert to string" << _bvconst; + FatalError(""); + } + os << prefix << res; + CONSTANTBV::BitVector_Dispose(res); + } + + // Copy constructor. + ASTBVConst(const ASTBVConst &sym) : + ASTInternal(sym._kind, sym._children, sym._bm) + { + _bvconst = CONSTANTBV::BitVector_Clone(sym._bvconst); + _value_width = sym._value_width; + } + + public: + virtual ~ASTBVConst(){ + CONSTANTBV::BitVector_Destroy(_bvconst); + } + + CBV GetBVConst() const {return _bvconst;} + }; //End of ASTBVConst + + //FIXME This function is DEPRICATED + //Do not use in the future + inline unsigned int GetUnsignedConst(const ASTNode n) { + if(32 < n.GetValueWidth()) + FatalError("GetUnsignedConst: cannot convert bvconst of length greater than 32 to unsigned int:"); + + return (unsigned int) *((unsigned int *)n.GetBVConst()); + } +#else + class ASTBVConst : public ASTInternal { + friend class BeevMgr; + friend class ASTNode; + friend class ASTNodeHasher; + friend class ASTNodeEqual; + + private: + // the bitvector contents. bitvector contents will be in two + // modes. one mode where all bitvectors are NATIVE and in this + // mode we use native unsigned long long int to represent the + // 32/64 bitvectors. The other for arbitrary length bitvector + // operations. + const unsigned long long int _bvconst; + + class ASTBVConstHasher{ + public: + size_t operator() (const ASTBVConst * bvc) const{ + //Thomas Wang's 64 bit Mix Function + unsigned long long int key(bvc->_bvconst); + key += ~(key << 32); + key ^= (key >> 22); + key += ~(key << 13); + key ^= (key >> 8); + key += (key << 3); + key ^= (key >> 15); + key += ~(key << 27); + key ^= (key >> 31); + + size_t return_key = key; + return return_key; + }; + }; + + class ASTBVConstEqual{ + public: + bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const { + return ((bvc1->_bvconst == bvc2->_bvconst) + && (bvc1->_value_width == bvc2->_value_width)); + } + }; + + // Call this when deleting a node that has been stored in the + // the unique table + virtual void CleanUp(); + public: + // Default constructor + ASTBVConst(const unsigned long long int bv, BeevMgr &bm) : + ASTInternal(BVCONST, bm), _bvconst(bv) { + } + + // Copy constructor. FIXME: figure out how this is supposed to + // work. + ASTBVConst(const ASTBVConst &sym) : + ASTInternal(sym._kind, sym._children, sym._bm), + _bvconst(sym._bvconst) { + _value_width = sym._value_width; + } + + // Destructor (does nothing, but is declared virtual here) + virtual ~ASTBVConst() { } + + friend bool operator==(const ASTBVConst &sym1, const ASTBVConst &sym2){ + return ((sym1._bvconst == sym2._bvconst) && + (sym1._value_width == sym2._value_width)); + } + + // Print function for bvconst -- return _bvconst value in binary format + virtual void nodeprint(ostream& os) { + string s = "0bin"; + unsigned long long int bitmask = 0x8000000000000000LL; + bitmask = bitmask >> (64-_value_width); + + for (; bitmask > 0; bitmask >>= 1) + s += (_bvconst & bitmask) ? '1' : '0'; + os << s; + } + + unsigned long long int GetBVConst() const {return _bvconst;} + }; //End of ASTBVConst + + //return value of bvconst + inline unsigned int GetUnsignedConst(const ASTNode n) { + if(32 < n.GetValueWidth()) + FatalError("GetUnsignedConst: cannot convert bvconst of length greater than 32 to unsigned int:"); + return (unsigned int)n.GetBVConst(); + } +#endif +/* +#else + // the bitvector contents. bitvector contents will be in two + // modes. one mode where all bitvectors are NATIVE and in this mode + // we use native unsigned long long int to represent the 32/64 + // bitvectors. The other for arbitrary length bitvector operations. + + //BVCONST defined for arbitrary length bitvectors + class ASTBVConst : public ASTInternal{ + friend class BeevMgr; + friend class ASTNode; + friend class ASTNodeHasher; + friend class ASTNodeEqual; + + private: + const char * const _bvconst; + + class ASTBVConstHasher{ + public: + size_t operator() (const ASTBVConst * bvc) const{ + hash<char*> h; + return h(bvc->_bvconst); + }; + }; + + class ASTBVConstEqual{ + public: + bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const { + if(bvc1->_value_width != bvc2->_value_width) + return false; + return (0 == strncmp(bvc1->_bvconst,bvc2->_bvconst,bvc1->_value_width)); + } + }; + + ASTBVConst(const char * bv, BeevMgr &bm) : + ASTInternal(BVCONST, bm), _bvconst(bv) { + //_value_width = strlen(bv); + } + + friend bool operator==(const ASTBVConst &bvc1, const ASTBVConst &bvc2){ + if(bvc1._value_width != bvc2._value_width) + return false; + return (0 == strncmp(bvc1._bvconst,bvc2._bvconst,bvc1._value_width)); + } + + // Call this when deleting a node that has been stored in the + // the unique table + virtual void CleanUp(); + + // Print function for bvconst -- return _bvconst value in binary format + virtual void nodeprint(ostream& os) { + if(_value_width%4 == 0) { + unsigned int * iii = CONSTANTBV::BitVector_Create(_value_width,true); + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(iii,(unsigned char*)_bvconst); + //error printing + if(0 != e) { + os << "nodeprint: BVCONST : wrong hex value: " << BitVector_Error(e); + FatalError(""); + } + unsigned char * ccc = CONSTANTBV::BitVector_to_Hex(iii); + os << "0hex" << ccc; + CONSTANTBV::BitVector_Destroy(iii); + } + else { + std::string s(_bvconst,_value_width); + s = "0bin" + s; + os << s; + } + } + + // Copy constructor. + ASTBVConst(const ASTBVConst &sym) : ASTInternal(sym._kind, sym._children, sym._bm),_bvconst(sym._bvconst) { + //checking if the input is in the correct format + for(unsigned int jj=0;jj<sym._value_width;jj++) + if(!(sym._bvconst[jj] == '0' || sym._bvconst[jj] == '1')) { + cerr << "Fatal Error: wrong input to ASTBVConst copy constructor:" << sym._bvconst << endl; + FatalError(""); + } + _value_width = sym._value_width; + } + public: + // Destructor (does nothing, but is declared virtual here) + virtual ~ASTBVConst(){} + + const char * const GetBVConst() const {return _bvconst;} + }; //End of ASTBVConst + + unsigned int * ConvertToCONSTANTBV(const char * s); + + //return value of bvconst + inline unsigned int GetUnsignedConst(const ASTNode n) { + if(32 < n.GetValueWidth()) + FatalError("GetUnsignedConst: cannot convert bvconst of length greater than 32 to unsigned int:"); + std::string s(n.GetBVConst(), n.GetValueWidth()); + unsigned int output = strtoul(s.c_str(),NULL,2); + return output; + } //end of ASTBVConst class +#endif +*/ + /*************************************************************************** + * Typedef ASTNodeMap: This is a hash table from ASTNodes to ASTNodes. + * It is very convenient for attributes that are not speed-critical + **************************************************************************/ + // These are generally useful for storing ASTNodes or attributes thereof + // Hash table from ASTNodes to ASTNodes + typedef hash_map<ASTNode, ASTNode, + ASTNode::ASTNodeHasher, + ASTNode::ASTNodeEqual> ASTNodeMap; + + // Function to dump contents of ASTNodeMap + ostream &operator<<(ostream &os, const ASTNodeMap &nmap); + + /*************************************************************************** + Typedef ASTNodeSet: This is a hash set of ASTNodes. Very useful + for representing things like "visited nodes" + ***************************************************************************/ + typedef hash_set<ASTNode, + ASTNode::ASTNodeHasher, + ASTNode::ASTNodeEqual> ASTNodeSet; + + typedef hash_multiset<ASTNode, + ASTNode::ASTNodeHasher, + ASTNode::ASTNodeEqual> ASTNodeMultiSet; + + //external parser table for declared symbols. + //FIXME: move to a more appropriate place + extern ASTNodeSet _parser_symbol_table; + + /*************************************************************************** + Class LispPrinter: iomanipulator for printing ASTNode or ASTVec + ***************************************************************************/ + class LispPrinter { + + public: + ASTNode _node; + + // number of spaces to print before first real character of + // object. + int _indentation; + + // FIXME: pass ASTNode by reference + // Constructor to build the LispPrinter object + LispPrinter(ASTNode node, int indentation): _node(node), _indentation(indentation) { } + + friend ostream &operator<<(ostream &os, const LispPrinter &lp){ + return lp._node.LispPrint(os, lp._indentation); + }; + + }; //End of ListPrinter + + //This is the IO manipulator. It builds an object of class + //"LispPrinter" that has a special overloaded "<<" operator. + inline LispPrinter lisp(const ASTNode &node, int indentation = 0){ + LispPrinter lp(node, indentation); + return lp; + } + + /***************************************************************************/ + /* Class LispVecPrinter:iomanipulator for printing vector of ASTNodes */ + /***************************************************************************/ + class LispVecPrinter { + + public: + const ASTVec * _vec; + // number of spaces to print before first real + // character of object. + int _indentation; + + // Constructor to build the LispPrinter object + LispVecPrinter(const ASTVec &vec, int indentation){ + _vec = &vec; _indentation = indentation; + } + + friend ostream &operator<<(ostream &os, const LispVecPrinter &lvp){ + LispPrintVec(os, *lvp._vec, lvp._indentation); + return os; + }; + }; //End of Class ListVecPrinter + + //iomanipulator. builds an object of class "LisPrinter" that has a + //special overloaded "<<" operator. + inline LispVecPrinter lisp(const ASTVec &vec, int indentation = 0){ + LispVecPrinter lvp(vec, indentation); + return lvp; + } + + + /***************************************************************** + * INLINE METHODS from various classed, declared here because of + * dependencies on classes that are declared later. + *****************************************************************/ + // ASTNode accessor function. + inline Kind ASTNode::GetKind() const { + //cout << "GetKind: " << _int_node_ptr; + return _int_node_ptr->GetKind(); + } + + // FIXME: should be const ASTVec const? + // Declared here because of same ordering problem as GetKind. + inline const ASTVec &ASTNode::GetChildren() const { + return _int_node_ptr->GetChildren(); + } + + // Access node number + inline int ASTNode::GetNodeNum() const { + return _int_node_ptr->_node_num; + } + + inline unsigned int ASTNode::GetIndexWidth () const { + return _int_node_ptr->_index_width; + } + + inline void ASTNode::SetIndexWidth (unsigned int iw) const { + _int_node_ptr->_index_width = iw; + } + + inline unsigned int ASTNode::GetValueWidth () const { + return _int_node_ptr->_value_width; + } + + inline void ASTNode::SetValueWidth (unsigned int vw) const { + _int_node_ptr->_value_width = vw; + } + + //return the type of the ASTNode: 0 iff BOOLEAN; 1 iff BITVECTOR; 2 + //iff ARRAY; 3 iff UNKNOWN; + inline types ASTNode::GetType() const { + if((GetIndexWidth() == 0) && (GetValueWidth() == 0)) //BOOLEAN + return BOOLEAN_TYPE; + if((GetIndexWidth() == 0) && (GetValueWidth() > 0)) //BITVECTOR + return BITVECTOR_TYPE; + if((GetIndexWidth() > 0) && (GetValueWidth() > 0)) //ARRAY + return ARRAY_TYPE; + return UNKNOWN_TYPE; + } + + // Constructor; creates a new pointer, increments refcount of + // pointed-to object. +#ifndef SMTLIB + inline ASTNode::ASTNode(ASTInternal *in) : _int_node_ptr(in) { + if (in) in->IncRef(); + } +#else + inline ASTNode::ASTNode(ASTInternal *in) : _int_node_ptr(in) { }; +#endif + + // Assignment. Increment refcount of new value, decrement refcount + // of old value and destroy if this was the last pointer. FIXME: + // accelerate this by creating an intnode with a ref counter instead + // of pointing to NULL. Need a special check in CleanUp to make + // sure the null node never gets freed. + +#ifndef SMTLIB + inline ASTNode& ASTNode::operator=(const ASTNode& n) { + if (n._int_node_ptr) { + n._int_node_ptr->IncRef(); + } + if (_int_node_ptr) { + _int_node_ptr->DecRef(); + } + _int_node_ptr = n._int_node_ptr; + return *this; + } +#else + inline ASTNode& ASTNode::operator=(const ASTNode& n) { + _int_node_ptr = n._int_node_ptr; + return *this; + } +#endif + +#ifndef SMTLIB + inline void ASTInternal::DecRef() + { + if (--_ref_count == 0) { + // Delete node from unique table and kill it. + CleanUp(); + } + } + + // Destructor + inline ASTNode::~ASTNode() + { + if (_int_node_ptr) { + _int_node_ptr->DecRef(); + } + }; +#else + // No refcounting + inline void ASTInternal::DecRef() + { + } + + // Destructor + inline ASTNode::~ASTNode() + { + }; +#endif + + inline BeevMgr& ASTNode::GetBeevMgr() const { return _int_node_ptr->_bm; } + + /*************************************************************************** + * Class BeevMgr. This holds all "global" variables for the system, such as + * unique tables for the various kinds of nodes. + ***************************************************************************/ + class BeevMgr { + friend class ASTNode; // ASTNode modifies AlreadyPrintedSet + // in BeevMgr + friend class ASTInterior; + friend class ASTBVConst; + friend class ASTSymbol; + + // FIXME: The values appear to be the same regardless of the value of SMTLIB + // initial hash table sizes, to save time on resizing. +#ifdef SMTLIB + static const int INITIAL_INTERIOR_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_SYMBOL_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_BVCONST_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_BBTERM_MEMO_TABLE_SIZE = 100; + static const int INITIAL_BBFORM_MEMO_TABLE_SIZE = 100; + + static const int INITIAL_SIMPLIFY_MAP_SIZE = 100; + static const int INITIAL_SOLVER_MAP_SIZE = 100; + static const int INITIAL_ARRAYREAD_SYMBOL_SIZE = 100; + static const int INITIAL_INTRODUCED_SYMBOLS_SIZE = 100; +#else + // these are the STL defaults + static const int INITIAL_INTERIOR_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_SYMBOL_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_BVCONST_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_BBTERM_MEMO_TABLE_SIZE = 100; + static const int INITIAL_BBFORM_MEMO_TABLE_SIZE = 100; + + static const int INITIAL_SIMPLIFY_MAP_SIZE = 100; + static const int INITIAL_SOLVER_MAP_SIZE = 100; + static const int INITIAL_ARRAYREAD_SYMBOL_SIZE = 100; + static const int INITIAL_INTRODUCED_SYMBOLS_SIZE = 100; +#endif + + private: + // Typedef for unique Interior node table. + typedef hash_set<ASTInterior *, + ASTInterior::ASTInteriorHasher, + ASTInterior::ASTInteriorEqual> ASTInteriorSet; + + // Typedef for unique Symbol node (leaf) table. + typedef hash_set<ASTSymbol *, + ASTSymbol::ASTSymbolHasher, + ASTSymbol::ASTSymbolEqual> ASTSymbolSet; + + // Unique tables to share nodes whenever possible. + ASTInteriorSet _interior_unique_table; + //The _symbol_unique_table is also the symbol table to be used + //during parsing/semantic analysis + ASTSymbolSet _symbol_unique_table; + + //Typedef for unique BVConst node (leaf) table. + typedef hash_set<ASTBVConst *, + ASTBVConst::ASTBVConstHasher, + ASTBVConst::ASTBVConstEqual> ASTBVConstSet; + + //table to uniquefy bvconst + ASTBVConstSet _bvconst_unique_table; + + // type of memo table. + typedef hash_map<ASTNode, ASTVec, + ASTNode::ASTNodeHasher, + ASTNode::ASTNodeEqual> ASTNodeToVecMap; + + typedef hash_map<ASTNode,ASTNodeSet, + ASTNode::ASTNodeHasher, + ASTNode::ASTNodeEqual> ASTNodeToSetMap; + + // Memo table for bit blasted terms. If a node has already been + // bitblasted, it is mapped to a vector of Boolean formulas for + // the bits. + + //OLD: ASTNodeToVecMap BBTermMemo; + ASTNodeMap BBTermMemo; + + // Memo table for bit blasted formulas. If a node has already + // been bitblasted, it is mapped to a node representing the + // bitblasted equivalent + ASTNodeMap BBFormMemo; + + //public: + // Get vector of Boolean formulas for sum of two + // vectors of Boolean formulas + void BBPlus2(ASTVec& sum, const ASTVec& y, ASTNode cin); + // Increment + ASTVec BBInc(ASTVec& x); + // Add one bit to a vector of bits. + ASTVec BBAddOneBit(ASTVec& x, ASTNode cin); + // Bitwise complement + ASTVec BBNeg(const ASTVec& x); + // Unary minus + ASTVec BBUminus(const ASTVec& x); + // Multiply. + ASTVec BBMult(const ASTVec& x, const ASTVec& y); + // AND each bit of vector y with single bit b and return the result. + // (used in BBMult) + ASTVec BBAndBit(const ASTVec& y, ASTNode b); + // Returns ASTVec for result - y. This destroys "result". + void BBSub(ASTVec& result, const ASTVec& y); + // build ITE's (ITE cond then[i] else[i]) for each i. + ASTVec BBITE(const ASTNode& cond, + const ASTVec& thn, const ASTVec& els); + // Build a vector of zeros. + ASTVec BBfill(unsigned int width, ASTNode fillval); + // build an EQ formula + ASTNode BBEQ(const ASTVec& left, const ASTVec& right); + + // This implements a variant of binary long division. + // q and r are "out" parameters. rwidth puts a bound on the + // recursion depth. Unsigned only, for now. + void BBDivMod(const ASTVec &y, + const ASTVec &x, + ASTVec &q, + ASTVec &r, + unsigned int rwidth); + + // Return formula for majority function of three formulas. + ASTNode Majority(const ASTNode& a, const ASTNode& b, const ASTNode& c); + + // Internal bit blasting routines. + ASTNode BBBVLE(const ASTVec& x, const ASTVec& y, bool is_signed); + + // Return bit-blasted form for BVLE, BVGE, BVGT, SBLE, etc. + ASTNode BBcompare(const ASTNode& form); + + // Left and right shift one. Writes into x. + void BBLShift(ASTVec& x); + void BBRShift(ASTVec& x); + + public: + // Simplifying create functions + ASTNode CreateSimpForm(Kind kind, ASTVec &children); + ASTNode CreateSimpForm(Kind kind, const ASTNode& child0); + ASTNode CreateSimpForm(Kind kind, + const ASTNode& child0, + const ASTNode& child1); + ASTNode CreateSimpForm(Kind kind, + const ASTNode& child0, + const ASTNode& child1, + const ASTNode& child2); + + ASTNode CreateSimpNot(const ASTNode& form); + + // These are for internal use only. + // FIXME: Find a way to make this local to SimpBool, so they're + // not in AST.h + ASTNode CreateSimpXor(const ASTNode& form1, + const ASTNode& form2); + ASTNode CreateSimpXor(ASTVec &children); + ASTNode CreateSimpAndOr(bool isAnd, + const ASTNode& form1, + const ASTNode& form2); + ASTNode CreateSimpAndOr(bool IsAnd, ASTVec &children); + ASTNode CreateSimpFormITE(const ASTNode& child0, + const ASTNode& child1, + const ASTNode& child2); + + + // Declarations of BitBlaster functions (BitBlast.cpp) + public: + // Adds or removes a NOT as necessary to negate a literal. + ASTNode Negate(const ASTNode& form); + + // Bit blast a bitvector term. The term must have a kind for a + // bitvector term. Result is a ref to a vector of formula nodes + // representing the boolean formula. + const ASTNode BBTerm(const ASTNode& term); + + const ASTNode BBForm(const ASTNode& formula); + + // Declarations of CNF conversion (ToCNF.cpp) + public: + // ToCNF converts a bit-blasted Boolean formula to Conjunctive + // Normal Form, suitable for many SAT solvers. Our CNF representation + // is an STL vector of STL vectors, for independence from any particular + // SAT solver's representation. There needs to be a separate driver to + // convert our clauselist to the representation used by the SAT solver. + // Currently, there is only one such solver and its driver is "ToSAT" + + // Datatype for clauses + typedef ASTVec * ClausePtr; + + // Datatype for Clauselists + typedef vector<ClausePtr> ClauseList; + + // Convert a Boolean formula to an equisatisfiable CNF formula. + ClauseList *ToCNF(const ASTNode& form); + + // Print function for debugging + void PrintClauseList(ostream& os, ClauseList& cll); + + // Free the clause list and all its clauses. + void DeleteClauseList(BeevMgr::ClauseList *cllp); + + // Map from formulas to representative literals, for debugging. + ASTNodeMap RepLitMap; + + private: + // Global for assigning new node numbers. + int _max_node_num; + + const ASTNode ASTFalse, ASTTrue, ASTUndefined; + + // I just did this so I could put it in as a fake return value in + // methods that return a ASTNode &, to make -Wall shut up. + ASTNode dummy_node; + + //BeevMgr Constructor, Destructor and other misc. functions + public: + + int NewNodeNum() { _max_node_num += 2; return _max_node_num; } + + // Table for DAG printing. + ASTNodeSet AlreadyPrintedSet; + + //Tables for Presentation language printing + + //Nodes seen so far + ASTNodeSet PLPrintNodeSet; + + //Map from ASTNodes to LetVars + ASTNodeMap NodeLetVarMap; + + //This is a vector which stores the Node to LetVars pairs. It + //allows for sorted printing, as opposed to NodeLetVarMap + std::vector<pair<ASTNode,ASTNode> > NodeLetVarVec; + + //a partial Map from ASTNodes to LetVars. Needed in order to + //correctly print shared subterms inside the LET itself + ASTNodeMap NodeLetVarMap1; + + //functions to lookup nodes from the memo tables. these should be + //private. + private: + //Destructively appends back_child nodes to front_child nodes. + //If back_child nodes is NULL, no appending is done. back_child + //nodes are not modified. Then it returns the hashed copy of the + //node, which is created if necessary. + ASTInterior *CreateInteriorNode(Kind kind, + ASTInterior *new_node, + // this is destructively modified. + const ASTVec & back_children = _empty_ASTVec); + + // Create unique ASTInterior node. + ASTInterior *LookupOrCreateInterior(ASTInterior *n); + + // Create unique ASTSymbol node. + ASTSymbol *LookupOrCreateSymbol(ASTSymbol& s); + + // Called whenever we want to make sure that the Symbol is + // declared during semantic analysis + bool LookupSymbol(ASTSymbol& s); + + // Called by ASTNode constructors to uniqueify ASTBVConst + ASTBVConst *LookupOrCreateBVConst(ASTBVConst& s); + + //Public functions for CreateNodes and Createterms + public: + // Create and return an ASTNode for a symbol + ASTNode CreateSymbol(const char * const name); + + // Create and return an ASTNode for a symbol + // Width is number of bits. + ASTNode CreateBVConst(unsigned int width, unsigned long long int bvconst); + ASTNode CreateZeroConst(unsigned int width); + ASTNode CreateOneConst(unsigned int width); + ASTNode CreateTwoConst(unsigned int width); + ASTNode CreateMaxConst(unsigned int width); + + // Create and return an ASTNode for a symbol + // Optional base was a problem because 0 could be an int or char *, + // so CreateBVConst was ambiguous. + ASTNode CreateBVConst(const char *strval, int base); + + //FIXME This is a dangerous function + ASTNode CreateBVConst(CBV bv, unsigned width); + + // Create and return an interior ASTNode + ASTNode CreateNode(Kind kind, const ASTVec &children = _empty_ASTVec); + + ASTNode CreateNode(Kind kind, + const ASTNode& child0, + const ASTVec &children = _empty_ASTVec); + + ASTNode CreateNode(Kind kind, + const ASTNode& child0, + const ASTNode& child1, + const ASTVec &children = _empty_ASTVec); + + ASTNode CreateNode(Kind kind, + const ASTNode& child0, + const ASTNode& child1, + const ASTNode& child2, + const ASTVec &children = _empty_ASTVec); + + // Create and return an ASTNode for a term + inline ASTNode CreateTerm(Kind kind, + unsigned int width, + const ASTVec &children = _empty_ASTVec) { + if(!is_Term_kind(kind)) + FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind); + ASTNode n = CreateNode(kind, children); + n.SetValueWidth(width); + + //by default we assume that the term is a Bitvector. If + //necessary the indexwidth can be changed later + n.SetIndexWidth(0); + return n; + } + + inline ASTNode CreateTerm(Kind kind, + unsigned int width, + const ASTNode& child0, + const ASTVec &children = _empty_ASTVec) { + if(!is_Term_kind(kind)) + FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind); + ASTNode n = CreateNode(kind, child0, children); + n.SetValueWidth(width); + return n; + } + + inline ASTNode CreateTerm(Kind kind, + unsigned int width, + const ASTNode& child0, + const ASTNode& child1, + const ASTVec &children = _empty_ASTVec) { + if(!is_Term_kind(kind)) + FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind); + ASTNode n = CreateNode(kind, child0, child1, children); + n.SetValueWidth(width); + return n; + } + + inline ASTNode CreateTerm(Kind kind, + unsigned int width, + const ASTNode& child0, + const ASTNode& child1, + const ASTNode& child2, + const ASTVec &children = _empty_ASTVec) { + if(!is_Term_kind(kind)) + FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind); + ASTNode n = CreateNode(kind, child0, child1, child2, children); + n.SetValueWidth(width); + return n; + } + + ASTNode SimplifyFormula_NoRemoveWrites(const ASTNode& a, bool pushNeg); + ASTNode SimplifyFormula_TopLevel(const ASTNode& a, bool pushNeg); + ASTNode SimplifyFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyTerm_TopLevel(const ASTNode& b); + ASTNode SimplifyTerm(const ASTNode& a); + void CheckSimplifyInvariant(const ASTNode& a, const ASTNode& output); + private: + //memo table for simplifcation + ASTNodeMap SimplifyMap; + ASTNodeMap SimplifyNegMap; + ASTNodeMap SolverMap; + ASTNodeSet AlwaysTrueFormMap; + ASTNodeMap MultInverseMap; + + public: + ASTNode SimplifyAtomicFormula(const ASTNode& a, bool pushNeg); + ASTNode CreateSimplifiedEQ(const ASTNode& t1, const ASTNode& t2); + ASTNode ITEOpt_InEqs(const ASTNode& in1); + ASTNode CreateSimplifiedTermITE(const ASTNode& t1, const ASTNode& t2, const ASTNode& t3); + ASTNode CreateSimplifiedINEQ(Kind k, const ASTNode& a0, const ASTNode& a1, bool pushNeg); + ASTNode SimplifyNotFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyAndOrFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyXorFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyNandFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyNorFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyImpliesFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyIffFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyIteFormula(const ASTNode& a, bool pushNeg); + ASTNode FlattenOneLevel(const ASTNode& a); + ASTNode FlattenAndOr(const ASTNode& a); + ASTNode CombineLikeTerms(const ASTNode& a); + ASTNode LhsMinusRhs(const ASTNode& eq); + ASTNode DistributeMultOverPlus(const ASTNode& a, + bool startdistribution=false); + ASTNode ConvertBVSXToITE(const ASTNode& a); + //checks if the input constant is odd or not + bool BVConstIsOdd(const ASTNode& c); + //computes the multiplicatve inverse of the input + ASTNode MultiplicativeInverse(const ASTNode& c); + + void ClearAllTables(void); + void ClearAllCaches(void); + int BeforeSAT_ResultCheck(const ASTNode& q); + int CallSAT_ResultCheck(MINISAT::Solver& newS, + const ASTNode& q, const ASTNode& orig_input); + int SATBased_ArrayReadRefinement(MINISAT::Solver& newS, + const ASTNode& q, const ASTNode& orig_input); + int SATBased_ArrayWriteRefinement(MINISAT::Solver& newS, const ASTNode& orig_input); + //creates array write axiom only for the input term or formula, if + //necessary. If there are no axioms to produce then it simply + //generates TRUE + ASTNode Create_ArrayWriteAxioms(const ASTNode& array_readoverwrite_term, const ASTNode& array_newname); + ASTVec ArrayWrite_RemainingAxioms; + //variable indicates that counterexample will now be checked by + //the counterexample checker, and hence simplifyterm must switch + //off certain optimizations. In particular, array write + //optimizations + bool start_abstracting; + bool Begin_RemoveWrites; + bool SimplifyWrites_InPlace_Flag; + + void CopySolverMap_To_CounterExample(void); + //int LinearSearch(const ASTNode& orig_input); + //Datastructures and functions needed for counterexample + //generation, and interface with MINISAT + private: + /* MAP: This is a map from ASTNodes to MINISAT::Vars. + * + * The map is populated while ASTclauses are read from the AST + * ClauseList returned by CNF converter. For every new boolean + * variable in ASTClause a new MINISAT::Var is created (these vars + * typedefs for ints) + */ + typedef hash_map<ASTNode, MINISAT::Var, + ASTNode::ASTNodeHasher, + ASTNode::ASTNodeEqual> ASTtoSATMap; + ASTtoSATMap _ASTNode_to_SATVar; + + public: + //converts the clause to SAT and calls SAT solver + bool toSATandSolve(MINISAT::Solver& S, ClauseList& cll); + + ///print SAT solver statistics + void PrintStats(MINISAT::SolverStats& stats); + + //accepts query and returns the answer. if query is valid, return + //true, else return false. Automatically constructs counterexample + //for invalid queries, and prints them upon request. + int TopLevelSAT(const ASTNode& query, const ASTNode& asserts); + + // Debugging function to find problems in BitBlast and ToCNF. + // See body in ToSAT.cpp for more explanation. + ASTNode CheckBBandCNF(MINISAT::Solver& newS, ASTNode form); + + // Internal recursive body of above. + ASTNode CheckBBandCNF_int(MINISAT::Solver& newS, ASTNode form); + + // Helper function for CheckBBandCNF + ASTNode SymbolTruthValue(MINISAT::Solver &newS, ASTNode form); + + //looksup a MINISAT var from the minisat-var memo-table. if none + //exists, then creates one. + const MINISAT::Var LookupOrCreateSATVar(MINISAT::Solver& S, const ASTNode& n); + + // Memo table for CheckBBandCNF debugging function + ASTNodeMap CheckBBandCNFMemo; + + + //Data structures for Array Read Transformations + private: + /* MAP: This is a map from Array Names to list of array-read + * indices in the input. This map is used by the TransformArray() + * function + * + * This map is useful in converting array reads into nested ITE + * constructs. Suppose there are two array reads in the input + * Read(A,i) and Read(A,j). Then Read(A,i) is replaced with a + * symbolic constant, say v1, and Read(A,j) is replaced with the + * following ITE: + * + * ITE(i=j,v1,v2) + */ + //CAUTION: I tried using a set instead of vector for + //readindicies. for some odd reason the performance went down + //considerably. this is totally inexplicable. + ASTNodeToVecMap _arrayname_readindices; + + /* MAP: This is a map from Array Names to nested ITE constructs, + * which are built as described below. This map is used by the + * TransformArray() function + * + * This map is useful in converting array reads into nested ITE + * constructs. Suppose there are two array reads in the input + * Read(A,i) and Read(A,j). Then Read(A,i) is replaced with a + * symbolic constant, say v1, and Read(A,j) is replaced with the + * following ITE: + * + * ITE(i=j,v1,v2) + */ + ASTNodeMap _arrayread_ite; + + /*MAP: This is a map from array-reads to symbolic constants. This + *map is used by the TransformArray() + */ + ASTNodeMap _arrayread_symbol; + + ASTNodeSet _introduced_symbols; + + /*Memoization map for TransformFormula/TransformTerm/TransformArray function + */ + ASTNodeMap TransformMap; + + //count to keep track of new symbolic constants introduced + //corresponding to Array Reads + unsigned int _symbol_count; + + //Formula/Term Transformers. Let Expr Manager, Type Checker + public: + //Functions that Transform ASTNodes + ASTNode TransformFormula(const ASTNode& query); + ASTNode TransformTerm(const ASTNode& term); + ASTNode TransformArray(const ASTNode& term); + ASTNode TranslateSignedDivMod(const ASTNode& term); + + //LET Management + private: + // MAP: This map is from bound IDs that occur in LETs to + // expression. The map is useful in checking replacing the IDs + // with the corresponding expressions. + ASTNodeMap _letid_expr_map; + public: + + ASTNode ResolveID(const ASTNode& var); + + //Functions that are used to manage LET expressions + void LetExprMgr(const ASTNode& var, const ASTNode& letExpr); + + //Delete Letid Map + void CleanupLetIDMap(void); + + //Allocate LetID map + void InitializeLetIDMap(void); + + //Substitute Let-vars with LetExprs + ASTNode SubstituteLetExpr(ASTNode inExpr); + + /* MAP: This is a map from MINISAT::Vars to ASTNodes + * + * This is a reverse map, useful in constructing + * counterexamples. MINISAT returns a model in terms of MINISAT + * Vars, and this map helps us convert it to a model over ASTNode + * variables. + */ + vector<ASTNode> _SATVar_to_AST; + + private: + /* MAP: This is a map from ASTNodes to vectors of bits + * + * This map is used in constructing and printing + * counterexamples. MINISAT returns values for each bit (a + * BVGETBIT Node), and this maps allows us to assemble the bits + * into bitvectors. + */ + typedef hash_map<ASTNode, hash_map<unsigned int, bool> *, + ASTNode::ASTNodeHasher, + ASTNode::ASTNodeEqual> ASTtoBitvectorMap; + ASTtoBitvectorMap _ASTNode_to_Bitvector; + + //Data structure that holds the counter-model + ASTNodeMap CounterExampleMap; + + //Checks if the counter_example is ok. In order for the + //counter_example to be ok, Every assert must evaluate to true + //w.r.t couner_example and the query must evaluate to + //false. Otherwise the counter_example is bogus. + void CheckCounterExample(bool t); + + //Converts a vector of bools to a BVConst + ASTNode BoolVectoBVConst(hash_map<unsigned,bool> * w, unsigned int l); + + //accepts a term and turns it into a constant-term w.r.t counter_example + ASTNode TermToConstTermUsingModel(const ASTNode& term, bool ArrayReadFlag = true); + ASTNode Expand_ReadOverWrite_UsingModel(const ASTNode& term, bool ArrayReadFlag = true); + //Computes the truth value of a formula w.r.t counter_example + ASTNode ComputeFormulaUsingModel(const ASTNode& form); + + //Replaces WRITE(Arr,i,val) with ITE(j=i, val, READ(Arr,j)) + ASTNode RemoveWrites_TopLevel(const ASTNode& term); + ASTNode RemoveWrites(const ASTNode& term); + ASTNode SimplifyWrites_InPlace(const ASTNode& term); + ASTNode ReadOverWrite_To_ITE(const ASTNode& term); + + ASTNode NewArrayVar(unsigned int index, unsigned int value); + ASTNode NewVar(unsigned int valuewidth); + //For ArrayWrite Abstraction: map from read-over-write term to + //newname. + ASTNodeMap ReadOverWrite_NewName_Map; + //For ArrayWrite Refinement: Map new arraynames to Read-Over-Write + //terms + ASTNodeMap NewName_ReadOverWrite_Map; + + public: + //print the STP solver output + void PrintOutput(bool true_iff_valid); + + //Converts MINISAT counterexample into an AST memotable (i.e. the + //function populates the datastructure CounterExampleMap) + void ConstructCounterExample(MINISAT::Solver& S); + + //Prints the counterexample to stdout + void PrintCounterExample(bool t,std::ostream& os=cout); + + //Prints the counterexample to stdout + void PrintCounterExample_InOrder(bool t); + + //queries the counterexample, and returns the value corresponding + //to e + ASTNode GetCounterExample(bool t, const ASTNode& e); + + int CounterExampleSize(void) const {return CounterExampleMap.size();} + + //FIXME: This is bloody dangerous function. Hack attack to take + //care of requests from users who want to store complete + //counter-examples in their own data structures. + ASTNodeMap GetCompleteCounterExample() {return CounterExampleMap;} + + // prints MINISAT assigment one bit at a time, for debugging. + void PrintSATModel(MINISAT::Solver& S); + + //accepts constant input and normalizes it. + ASTNode BVConstEvaluator(const ASTNode& t); + + //FUNCTION TypeChecker: Assumes that the immediate Children of the + //input ASTNode have been typechecked. This function is suitable + //in scenarios like where you are building the ASTNode Tree, and + //you typecheck as you go along. It is not suitable as a general + //typechecker + void BVTypeCheck(const ASTNode& n); + + private: + //stack of Logical Context. each entry in the stack is a logical + //context. A logical context is a vector of assertions. The + //logical context is represented by a ptr to a vector of + //assertions in that logical context. Logical contexts are created + //by PUSH/POP + std::vector<ASTVec *> _asserts; + //The query for the current logical context. + ASTNode _current_query; + + //this flag, when true, indicates that counterexample is being + //checked by the counterexample checker + bool counterexample_checking_during_refinement; + + //this flag indicates as to whether the input has been determined to + //be valid or not by this tool + bool ValidFlag; + + //this flag, when true, indicates that a BVDIV divide by zero + //exception occured. However, the program must not exit with a + //fatalerror. Instead, it should evaluate the whole formula (which + //contains the BVDIV term) to be FALSE. + bool bvdiv_exception_occured; + + public: + //set of functions that manipulate Logical Contexts. + // + //add an assertion to the current logical context + void AddAssert(const ASTNode& assert); + void Push(void); + void Pop(void); + void AddQuery(const ASTNode& q); + const ASTNode PopQuery(); + const ASTNode GetQuery(); + const ASTVec GetAsserts(void); + + //reports node size. Second arg is "clearstatinfo", whatever that is. + unsigned int NodeSize(const ASTNode& a, bool t = false); + + private: + //This memo map is used by the ComputeFormulaUsingModel() + ASTNodeMap ComputeFormulaMap; + //Map for statiscal purposes + ASTNodeSet StatInfoSet; + + + ASTNodeMap TermsAlreadySeenMap; + ASTNode CreateSubstitutionMap(const ASTNode& a); + public: + //prints statistics for the ASTNode. can add a prefix string c + void ASTNodeStats(const char * c, const ASTNode& a); + + //substitution + bool CheckSubstitutionMap(const ASTNode& a, ASTNode& output); + bool CheckSubstitutionMap(const ASTNode& a); + bool UpdateSubstitutionMap(const ASTNode& e0, const ASTNode& e1); + //if (a > b) in the termorder, then return 1 + //elseif (a < b) in the termorder, then return -1 + //else return 0 + int TermOrder(const ASTNode& a, const ASTNode& b); + //fill the arrayname_readindices vector if e0 is a READ(Arr,index) + //and index is a BVCONST + void FillUp_ArrReadIndex_Vec(const ASTNode& e0, const ASTNode& e1); + bool VarSeenInTerm(const ASTNode& var, const ASTNode& term); + + //functions for checking and updating simplifcation map + bool CheckSimplifyMap(const ASTNode& key, ASTNode& output, bool pushNeg); + void UpdateSimplifyMap(const ASTNode& key, const ASTNode& value, bool pushNeg); + bool CheckAlwaysTrueFormMap(const ASTNode& key); + void UpdateAlwaysTrueFormMap(const ASTNode& val); + bool CheckMultInverseMap(const ASTNode& key, ASTNode& output); + void UpdateMultInverseMap(const ASTNode& key, const ASTNode& value); + + //Map for solved variables + bool CheckSolverMap(const ASTNode& a, ASTNode& output); + bool CheckSolverMap(const ASTNode& a); + bool UpdateSolverMap(const ASTNode& e0, const ASTNode& e1); + public: + //FIXME: HACK_ATTACK. this vector was hacked into the code to + //support a special request by Dawson' group. They want the + //counterexample to be printed in the order of variables declared. + //TO BE COMMENTED LATER (say by 1st week of march,2006) + ASTVec _special_print_set; + + //prints the initial activity levels of variables + void PrintActivityLevels_Of_SATVars(char * init_msg, MINISAT::Solver& newS); + + //this function biases the activity levels of MINISAT variables. + void ChangeActivityLevels_Of_SATVars(MINISAT::Solver& n); + + // Constructor + BeevMgr() : _interior_unique_table(INITIAL_INTERIOR_UNIQUE_TABLE_SIZE), + _symbol_unique_table(INITIAL_SYMBOL_UNIQUE_TABLE_SIZE), + _bvconst_unique_table(INITIAL_BVCONST_UNIQUE_TABLE_SIZE), + BBTermMemo(INITIAL_BBTERM_MEMO_TABLE_SIZE), + BBFormMemo(INITIAL_BBFORM_MEMO_TABLE_SIZE), + _max_node_num(0), + ASTFalse(CreateNode(FALSE)), + ASTTrue(CreateNode(TRUE)), + ASTUndefined(CreateNode(UNDEFINED)), + SimplifyMap(INITIAL_SIMPLIFY_MAP_SIZE), + SimplifyNegMap(INITIAL_SIMPLIFY_MAP_SIZE), + SolverMap(INITIAL_SOLVER_MAP_SIZE), + _arrayread_symbol(INITIAL_ARRAYREAD_SYMBOL_SIZE), + _introduced_symbols(INITIAL_INTRODUCED_SYMBOLS_SIZE), + _symbol_count(0) { + _current_query = ASTUndefined; + ValidFlag = false; + bvdiv_exception_occured = false; + counterexample_checking_during_refinement = false; + start_abstracting = false; + Begin_RemoveWrites = false; + SimplifyWrites_InPlace_Flag = false; + }; + + //destructor + ~BeevMgr(); + }; //End of Class BeevMgr + + + class CompleteCounterExample { + ASTNodeMap counterexample; + BeevMgr * bv; + public: + CompleteCounterExample(ASTNodeMap a, BeevMgr* beev) : counterexample(a), bv(beev){} + ASTNode GetCounterExample(ASTNode e) { + if(BOOLEAN_TYPE == e.GetType() && SYMBOL != e.GetKind()) { + FatalError("You must input a term or propositional variables\n",e); + } + if(counterexample.find(e) != counterexample.end()) { + return counterexample[e]; + } + else { + if(SYMBOL == e.GetKind() && BOOLEAN_TYPE == e.GetType()) { + return bv->CreateNode(BEEV::FALSE); + } + + if(SYMBOL == e.GetKind()) { + ASTNode z = bv->CreateZeroConst(e.GetValueWidth()); + return z; + } + + return e; + } + } + }; + +}; // end namespace BEEV +#endif diff --git a/stp/AST/ASTKind.kinds b/stp/AST/ASTKind.kinds new file mode 100644 index 00000000..03112eb8 --- /dev/null +++ b/stp/AST/ASTKind.kinds @@ -0,0 +1,71 @@ +#Please refer LICENSE FILE in the home directory for licensing information +# name minkids maxkids cat1 cat2 ... +Categories: Term Form + +# Leaf nodes. +UNDEFINED 0 0 +SYMBOL 0 0 Term Form + +# These always produce terms +BVCONST 0 0 Term +BVNEG 1 1 Term +BVCONCAT 2 - Term +BVOR 1 - Term +BVAND 1 - Term +BVXOR 1 - Term +BVNAND 1 - Term +BVNOR 1 - Term +BVXNOR 1 - Term +BVEXTRACT 3 3 Term +BVLEFTSHIFT 3 3 Term +BVRIGHTSHIFT 3 3 Term +BVSRSHIFT 3 3 Term +BVVARSHIFT 3 3 Term +BVPLUS 1 - Term +BVSUB 2 2 Term +BVUMINUS 1 1 Term +BVMULTINVERSE 1 1 Term +BVMULT 1 - Term +BVDIV 2 2 Term +BVMOD 2 2 Term +SBVDIV 2 2 Term +SBVMOD 2 2 Term +BVSX 1 1 Term +BOOLVEC 0 - Term + +# Formula OR term, depending on context +ITE 3 3 Term Form + +# These produce formulas. +BVGETBIT 2 2 Form +BVLT 2 2 Form +BVLE 2 2 Form +BVGT 2 2 Form +BVGE 2 2 Form +BVSLT 2 2 Form +BVSLE 2 2 Form +BVSGT 2 2 Form +BVSGE 2 2 Form +EQ 2 2 Form +NEQ 2 2 Form +FALSE 0 0 Form +TRUE 0 0 Form +NOT 1 1 Form +AND 1 - Form +OR 1 - Form +NAND 1 - Form +NOR 1 - Form +XOR 1 - Form +IFF 1 - Form +IMPLIES 2 2 Form + +# array operations +READ 2 2 Term +WRITE 3 3 Term + +#Types: These kinds are used only in the API. Once processed inside +#the API, they are never used again in the system +ARRAY 0 0 +BITVECTOR 0 0 +BOOLEAN 0 0 + diff --git a/stp/AST/ASTUtil.cpp b/stp/AST/ASTUtil.cpp new file mode 100644 index 00000000..bc36812c --- /dev/null +++ b/stp/AST/ASTUtil.cpp @@ -0,0 +1,45 @@ +/******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ +// -*- c++ -*- + +#include "ASTUtil.h" +#include <ostream> + +namespace BEEV { + ostream &operator<<(ostream &os, const Spacer &sp) { + // Instead of wrapping lines with hundreds of spaces, prints + // a "+" at the beginning of the line for each wrap-around. + // so lines print like: +14+ (XOR ... + int blanks = sp._spaces % 60; + int wraps = sp._spaces / 60; + if (wraps > 0) { + os << "+" << wraps; + } + for (int i = 0; i < blanks; i++) + os << " "; + return os; + } + + //this function accepts the name of a function (as a char *), and + //records some stats about it. if the input is "print_func_stats", + //the function will then print the stats that it has collected. + void CountersAndStats(const char * functionname) { + if(!stats) + return; + static function_counters s; + + if(!strcmp(functionname,"print_func_stats")) { + cout << endl; + for(hash_map<const char*,int,hash<const char*>,eqstr>::iterator it=s.begin(),itend=s.end(); + it!=itend;it++) + cout << "Number of times the function: " << it->first << ": is called: " << it->second << endl; + return; + } + s[functionname] += 1; + } +};// end of namespace diff --git a/stp/AST/ASTUtil.h b/stp/AST/ASTUtil.h new file mode 100644 index 00000000..0ed6bfa2 --- /dev/null +++ b/stp/AST/ASTUtil.h @@ -0,0 +1,107 @@ +/******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ +// -*- c++ -*- + +#ifndef ASTUTIL_H +#define ASTUTIL_H + +#include <cstring> +#include <iostream> +#include <vector> +#ifdef EXT_HASH_MAP +#include <ext/hash_set> +#include <ext/hash_map> +#else +#include <hash_set> +#include <hash_map> +#endif + +using namespace std; +namespace BEEV { +#ifdef EXT_HASH_MAP + using namespace __gnu_cxx; +#endif + //some global variables that are set through commandline options. it + //is best that these variables remain global. Default values set + //here + // + //collect statistics on certain functions + extern bool stats; + //print DAG nodes + extern bool print_nodes; + //tentative global var to allow for variable activity optimization + //in the SAT solver. deprecated. + extern bool variable_activity_optimize; + //run STP in optimized mode + extern bool optimize; + //do sat refinement, i.e. underconstraint the problem, and feed to + //SAT. if this works, great. else, add a set of suitable constraints + //to re-constraint the problem correctly, and call SAT again, until + //all constraints have been added. + extern bool arrayread_refinement; + //switch to control write refinements + extern bool arraywrite_refinement; + //check the counterexample against the original input to STP + extern bool check_counterexample; + //construct the counterexample in terms of original variable based + //on the counterexample returned by SAT solver + extern bool construct_counterexample; + extern bool print_counterexample; + //if this option is true then print the way dawson wants using a + //different printer. do not use this printer. + extern bool print_arrayval_declaredorder; + //flag to decide whether to print "valid/invalid" or not + extern bool print_output; + //do linear search in the array values of an input array. experimental + extern bool linear_search; + //print the variable order chosen by the sat solver while it is + //solving. + extern bool print_sat_varorder; + //turn on word level bitvector solver + extern bool wordlevel_solve; + //XOR flattening optimizations. + extern bool xor_flatten; + //this flag indicates that the BVSolver() succeeded + extern bool toplevel_solved; + //the smtlib parser has been turned on + extern bool smtlib_parser_enable; + //print the input back + extern bool print_STPinput_back; + + extern void (*vc_error_hdlr)(const char* err_msg); + /*Spacer class is basically just an int, but the new class allows + overloading of << with a special definition that prints the int as + that many spaces. */ + class Spacer { + public: + int _spaces; + Spacer(int spaces) { _spaces = spaces; } + friend ostream& operator<<(ostream& os, const Spacer &ind); + }; + + inline Spacer spaces(int width) { + Spacer sp(width); + return sp; + } + + struct eqstr { + bool operator()(const char* s1, const char* s2) const { + return strcmp(s1, s2) == 0; + } + }; + + typedef hash_map<const char*,int, + hash<const char *>,eqstr> function_counters; + void CountersAndStats(const char * functionname); + + //global function which accepts an integer and looks up the + //corresponding ASTNode and prints a char* of that ASTNode + void Convert_MINISATVar_To_ASTNode_Print(int minisat_var, + int decision, int polarity=0); +}; // end namespace. +#endif diff --git a/stp/AST/BitBlast.cpp b/stp/AST/BitBlast.cpp new file mode 100644 index 00000000..de78ec74 --- /dev/null +++ b/stp/AST/BitBlast.cpp @@ -0,0 +1,812 @@ +/******************************************************************** + * AUTHORS: David L. Dill, Vijay Ganesh + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ +// -*- c++ -*- + +// BitBlast -- convert bitvector terms and formulas to boolean +// formulas. A term is something that can represent a multi-bit +// bitvector, such as BVPLUS or BVXOR (or a BV variable or constant). +// A formula (form) represents a boolean value, such as EQ or BVLE. +// Bit blasting a term representing an n-bit bitvector with BBTerm +// yields a vector of n boolean formulas (returning ASTVec). +// Bit blasting a formula returns a single boolean formula (type ASTNode). + +// A bitblasted term is a vector of ASTNodes for formulas. +// The 0th element of the vector corresponds to bit 0 -- the low-order bit. + +#include "AST.h" +namespace BEEV { + // extern void lpvec(ASTVec &vec); + +// FIXME: Assert no zero-length bit vectors!!! +// FIXME: Need top-level functions that create and destroy the memo tables. +// FIXME: Check resource limits and generate an exception when exceeded. +// FIXME: THis does a lot of unnecessary copying of vectors. +// Had to be careful not to modify memoized vectors! +// FIXME: Might be some redundant variables. + +// accepts a term, and returns a vector of bitblasted bits(ASTVec) + +ASTNode ASTJunk; +const ASTNode BeevMgr::BBTerm(const ASTNode& term) { + //CHANGED TermMemo is now an ASTNodeMap. Based on BBFormMemo + ASTNodeMap::iterator it = BBTermMemo.find(term); + if (it != BBTermMemo.end()) { + // already there. Just return it. + return it->second; + } + +// ASTNode& result = ASTJunk; + ASTNode result; + + Kind k = term.GetKind(); + if (!is_Term_kind(k)) + FatalError("BBTerm: Illegal kind to BBTerm",term); + + ASTVec::const_iterator kids_end = term.end(); + unsigned int num_bits = term.GetValueWidth(); + switch (k) { + case BVNEG: { + // bitwise complement + // bitblast the child. + //FIXME Uses a tempory const ASTNode + const ASTNode& bbkids = BBTerm(term[0]); + result = CreateNode(BOOLVEC, BBNeg(bbkids.GetChildren())); + break; + } + case BVSRSHIFT: + case BVVARSHIFT: + FatalError("BBTerm: These kinds have not been implemented in the BitBlaster: ", term); + break; + case ITE: { + // Term version of ITE. + + // Blast the args + // FIXME Uses temporary const ASTNodes and an ASTVec& + const ASTNode& cond = BBForm(term[0]); + const ASTNode& thn = BBTerm(term[1]); + const ASTNode& els = BBTerm(term[2]); + result = + CreateNode(BOOLVEC, BBITE(cond, thn.GetChildren(), els.GetChildren())); + break; + } + case BVSX: { + // Replicate high-order bit as many times as necessary. + // Arg 0 is expression to be sign extended. + const ASTNode& arg = term[0]; + unsigned long result_width = term.GetValueWidth(); + unsigned long arg_width = arg.GetValueWidth(); + //FIXME Uses a temporary const ASTNode reference + const ASTNode& bbarg = BBTerm(arg); + + if (result_width == arg_width) { + //nothing to sign extend + break; + } + else { + //we need to sign extend + const ASTNode& msbX = bbarg.back(); + //const ASTNode& msb1 = msbX; + + ASTVec ccc = msbX.GetChildren(); + const ASTNode& msb = CreateSimpForm(msbX.GetKind(),ccc); + + // Old version + // ASTNode msb = bbarg.back(); + // const ASTNode msb1 = msb; + + // ASTVec ccc = msb.GetChildren(); + // msb = CreateSimpForm(msb.GetKind(),ccc); + + // DD 1/14/07 Simplify silently drops all but first two args of XOR. + // I expanded XOR to N args with flattening optimization. + // This bug took 2 days to track down! + + // msb = SimplifyFormula(msb,false); + + // cout << "!!!!!!!!!!!!!!!!" << endl + // << "Simplify msb:" << msb2 << endl + // << "Simplify result:" << msb << endl; + + //FIXME Dynamically allocate the result vector? + //Is this doing multiple copies? + //ASTVec& tmp_res = *(new ASTVec(result_width)); + ASTVec tmp_res(result_width); + + //FIXME Should these be gotten from result? + ASTVec::const_iterator bb_it = bbarg.begin(); + ASTVec::iterator res_it = tmp_res.begin(); + ASTVec::iterator res_ext = res_it+arg_width; // first bit of extended part + ASTVec::iterator res_end = tmp_res.end(); + // copy LSBs directly from bbvec + for( ; res_it < res_ext; (res_it++, bb_it++)) { + *res_it = *bb_it; + } + // repeat MSB to fill up rest of result. + for( ; res_it < res_end; (res_it++, bb_it++)) { + *res_it = msb; + } + + //Temporary debugging code + // cout << "Sign extending:" << endl + // << " Vec "; + // lpvec( bbarg.GetChildren() ); + // cout << " Extended to "; + // lp(result); + // cout << endl; + + result = CreateNode(BOOLVEC, tmp_res); + + break; + } + } + case BVEXTRACT: { + // bitblast the child, then extract the relevant bits. + // Note: This could be optimized by not bitblasting the bits + // that aren't fetched. But that would be tricky, especially + // with memo-ization. + + //FIXME Using const ASTNode w/out reference + const ASTNode& bbkids = BBTerm(term[0]); + unsigned int high = GetUnsignedConst(term[1]); + unsigned int low = GetUnsignedConst(term[2]); + + ASTVec::const_iterator bbkfit = bbkids.begin(); + // I should have used pointers to ASTVec, to avoid this crock + + //FIXME Creates a new local ASTVec and does the CreateNode from that + result = CreateNode(BOOLVEC, ASTVec(bbkfit+low, bbkfit+high+1)); + break; + } + case BVCONCAT: { + //FIXME Using temporary const ASTNodes + const ASTNode& vec1 = BBTerm(term[0]); + const ASTNode& vec2 = BBTerm(term[1]); + + //FIXME This has to be an unnessecary copy and a memory leak + //Leaking ASTVec tmp_res = *(new ASTVec(vec2.GetChildren())); + ASTVec tmp_res(vec2.GetChildren()); + tmp_res.insert(tmp_res.end(), vec1.begin(), vec1.end()); + result = CreateNode(BOOLVEC, tmp_res); + break; + } + case BVPLUS: { + // ASSERT: at least one child. + // ASSERT: all children and result are the same size. + // Previous phase must make sure this is true. + // Add children pairwise and accumulate in BBsum + + // FIXME: Unnecessary array copies. + ASTVec::const_iterator it = term.begin(); + ASTVec tmp_res = BBTerm(*it).GetChildren(); + for (++it; it < kids_end; it++) { + const ASTVec& tmp = BBTerm(*it).GetChildren(); + BBPlus2(tmp_res, tmp, ASTFalse); + } + + result = CreateNode(BOOLVEC, tmp_res); + break; + } + case BVUMINUS: { + //FIXME Using const ASTNode reference + const ASTNode& bbkid = BBTerm(term[0]); + result = CreateNode(BOOLVEC, BBUminus(bbkid.GetChildren())); + break; + } + case BVSUB: { + // complement of subtrahend + // copy, since BBSub writes into it. + + //FIXME: Unnecessary array copies? + ASTVec tmp_res = BBTerm(term[0]).GetChildren(); + + const ASTVec& bbkid1 = BBTerm(term[1]).GetChildren(); + BBSub(tmp_res, bbkid1); + result = CreateNode(BOOLVEC, tmp_res); + break; + } + case BVMULT: { + // ASSERT 2 arguments, same length, result is same length. + + const ASTNode& t0 = term[0]; + const ASTNode& t1 = term[1]; + + const ASTNode& mpcd1 = BBTerm(t0); + const ASTNode& mpcd2 = BBTerm(t1); + //Reverese the order of the nodes w/out the need for temporaries + //This is needed because t0 an t1 must be const + if ((BVCONST != t0.GetKind()) && (BVCONST == t1.GetKind())) { + result = CreateNode(BOOLVEC, + BBMult(mpcd2.GetChildren(), mpcd1.GetChildren()) ); + }else{ + result = CreateNode(BOOLVEC, + BBMult(mpcd1.GetChildren(), mpcd2.GetChildren()) ); + } + break; + } + case BVDIV: + case BVMOD: { + const ASTNode& dvdd = BBTerm(term[0]); + const ASTNode& dvsr = BBTerm(term[1]); + unsigned int width = dvdd.Degree(); + ASTVec q(width); + ASTVec r(width); + BBDivMod(dvdd.GetChildren(), dvsr.GetChildren(), q, r, width); + if (k == BVDIV) + result = CreateNode(BOOLVEC, q); + else + result = CreateNode(BOOLVEC, r); + break; + } + // n-ary bitwise operators. + case BVXOR: + case BVXNOR: + case BVAND: + case BVOR: + case BVNOR: + case BVNAND: { + // Add children pairwise and accumulate in BBsum + ASTVec::const_iterator it = term.begin(); + Kind bk = UNDEFINED; // Kind of individual bit op. + switch (k) { + case BVXOR: bk = XOR; break; + case BVXNOR: bk = IFF; break; + case BVAND: bk = AND; break; + case BVOR: bk = OR; break; + case BVNOR: bk = NOR; break; + case BVNAND: bk = NAND; break; + default: + FatalError("BBTerm: Illegal kind to BBTerm",term); + break; + } + + // Sum is destructively modified in the loop, so make a copy of value + // returned by BBTerm. + ASTNode temp = BBTerm(*it); + ASTVec sum(temp.GetChildren()); // First operand. + + // Iterate over remaining bitvector term operands + for (++it; it < kids_end; it++) { + //FIXME FIXME FIXME: Why does using a temp. var change the behavior? + temp = BBTerm(*it); + const ASTVec& y = temp.GetChildren(); + + // Iterate over bits + // FIXME: Why is this not using an iterator??? + int n = y.size(); + for (int i = 0; i < n; i++) { + sum[i] = CreateSimpForm(bk, sum[i], y[i]); + } + } + result = CreateNode(BOOLVEC, sum); + break; + } + case SYMBOL: { + // ASSERT: IndexWidth = 0? Semantic analysis should check. + //Leaking ASTVec& bbvec = *(new ASTVec); + + //FIXME Why is isn't this ASTVEC bbvec(num_bits) ? + ASTVec bbvec; + for (unsigned int i = 0; i < num_bits; i++) { + ASTNode bit_node = + CreateNode(BVGETBIT, term, CreateBVConst(32,i)); + bbvec.push_back(bit_node); + } + result = CreateNode(BOOLVEC, bbvec); + break; + } + case BVCONST: { + ASTVec tmp_res(num_bits); +#ifndef NATIVE_C_ARITH + CBV bv = term.GetBVConst(); + for(unsigned int i = 0; i < num_bits; i++){ + tmp_res[i] = CONSTANTBV::BitVector_bit_test(bv,i) ? ASTTrue : ASTFalse; + } +#else + const unsigned long long int c = term.GetBVConst(); + unsigned long long int bitmask = 0x00000000000000001LL; + for (unsigned int i = 0; i < num_bits; i++, bitmask <<= 1) + tmp_res[i] = ((c & (bitmask)) ? ASTTrue : ASTFalse); +#endif + result = CreateNode(BOOLVEC, tmp_res); + break; + } + case BOOLVEC: { + cerr << "Hit a boolvec! what to do?" << endl; + break; + } + default: + FatalError("BBTerm: Illegal kind to BBTerm",term); + } + + //if(result == ASTJunk) + // cout<<"result does not change"<<endl; + // cout << "================" << endl << "BBTerm:" << term << endl; + // cout << "----------------" << endl << "BBTerm result:"; + // lpvec(result); + // cout << endl; + + return (BBTermMemo[term] = result); + +} + +// bit blast a formula (boolean term). Result is one bit wide, +// so it returns a single ASTNode. +// FIXME: Add IsNegated flag. +const ASTNode BeevMgr::BBForm(const ASTNode& form) +{ + + ASTNodeMap::iterator it = BBFormMemo.find(form); + if (it != BBFormMemo.end()) { + // already there. Just return it. + return it->second; + } + + ASTNode result = ASTUndefined; + + Kind k = form.GetKind(); + if (!is_Form_kind(k)) { + FatalError("BBForm: Illegal kind: ",form); + } + + // Not returning until end, and memoizing everything, makes it easier + // to trace coherently. + + // Various special cases + switch (k) { + case TRUE: + case FALSE: { + result = form; + break; + } + + case SYMBOL: + if (form.GetType() != BOOLEAN_TYPE) { + FatalError("BBForm: Symbol represents more than one bit", form); + } + + result = form; + break; + + case BVGETBIT: { + // exactly two children + const ASTNode bbchild = BBTerm(form[0]); + unsigned int index = GetUnsignedConst(form[1]); + result = bbchild[index]; + break; + } + + case NOT: + result = CreateSimpNot(BBForm(form[0])); + break; + + case ITE: + // FIXME: SHould this be CreateSimpITE? + result = CreateNode(ITE, BBForm(form[0]), BBForm(form[1]), BBForm(form[2])); + break; + + case AND: + case OR: + case NAND: + case NOR: + case IFF: + case XOR: + case IMPLIES: { + ASTVec bbkids; // bit-blasted children (formulas) + + // FIXME: Put in fast exits for AND/OR/NAND/NOR/IMPLIES + ASTVec::const_iterator kids_end = form.end(); + for (ASTVec::const_iterator it = form.begin(); it != kids_end; it++) { + bbkids.push_back(BBForm(*it)); + } + result = CreateSimpForm(k, bbkids); + break; + } + + case NEQ: { + ASTNode bbkid = BBForm(CreateNode(EQ, form.GetChildren())); + result = CreateSimpNot(bbkid); + break; + } + + case EQ: { + // Common code for binary operations + // FIXME: This ought to be in a semantic analysis phase. + const ASTNode left = BBTerm(form[0]); + const ASTNode right = BBTerm(form[1]); + if (left.Degree() != right.Degree()) { + cerr << "BBForm: Size mismatch" << endl << form[0] << endl << form[1] << endl; + FatalError("",ASTUndefined); + } + result = BBEQ(left.GetChildren(), right.GetChildren()); + break; + } + + case BVLE: + case BVGE: + case BVGT: + case BVLT: + case BVSLE: + case BVSGE: + case BVSGT: + case BVSLT: { + result = BBcompare(form); + break; + } + default: + FatalError("BBForm: Illegal kind: ", form); + break; + } + + // cout << "================" << endl + // << "BBForm: " << form << endl + // << "----------------" << endl + // << "BBForm Result: " << result << endl; + + return (BBFormMemo[form] = result); +} + +// Bit blast a sum of two equal length BVs. +// Update sum vector destructively with new sum. +void BeevMgr::BBPlus2(ASTVec& sum, const ASTVec& y, ASTNode cin) +{ +// cout << "Bitblasting plus. Operand 1: " << endl; +// lpvec(sum); +// cout << endl << " operand 2: " << endl; +// lpvec(y); +// cout << endl << "carry: " << endl << cin << endl; + + + int n = sum.size(); + // ASSERT: y.size() == x.size() + // FIXME: Don't bother computing i+1 carry, which is discarded. + for (int i = 0; i < n; i++) { + ASTNode nextcin = Majority(sum[i], y[i], cin); + sum[i] = CreateSimpForm(XOR, CreateSimpForm(XOR, sum[i], y[i]), cin); + cin = nextcin; + } + +// cout << "----------------" << endl << "Result: " << endl; +// lpvec(sum); +// cout << endl; + +} + +// Stores result - x in result, destructively +void BeevMgr::BBSub(ASTVec& result, const ASTVec& y) +{ + ASTVec compsubtrahend = BBNeg(y); + BBPlus2(result, compsubtrahend, ASTTrue); +} + +// Add one bit +ASTVec BeevMgr::BBAddOneBit(ASTVec& x, ASTNode cin) +{ + ASTVec result = ASTVec(0); + ASTVec::const_iterator itend = x.end(); + for (ASTVec::const_iterator it = x.begin(); it < itend; it++) { + ASTNode nextcin = CreateSimpForm(AND, *it, cin); + result.push_back(CreateSimpForm(XOR, *it, cin)); + cin = nextcin; + } + // FIXME: unnecessary array copy on return? + return result; +} + +// Increment bit-blasted vector and return result. +ASTVec BeevMgr::BBInc(ASTVec& x) +{ + return BBAddOneBit(x, ASTTrue); +} + +// Return formula for majority function of three bits. +// Pass arguments by reference to reduce refcounting. +ASTNode BeevMgr::Majority(const ASTNode& a, const ASTNode& b,const ASTNode& c) +{ + // Checking explicitly for constant a, b and c could + // be more efficient, because they are repeated in the logic. + if (ASTTrue == a) { + return CreateSimpForm(OR, b, c); + } + else if (ASTFalse == a) { + return CreateSimpForm(AND, b, c); + } + else if (ASTTrue == b) { + return CreateSimpForm(OR, a, c); + } + else if (ASTFalse == b) { + return CreateSimpForm(AND, a, c); + } + else if (ASTTrue == c) { + return CreateSimpForm(OR, a, b); + } + else if (ASTFalse == c) { + return CreateSimpForm(AND, a, b); + } + // there are lots more simplifications, but I'm not sure they're + // worth doing explicitly (e.g., a = b, a = ~b, etc.) + else { + return + CreateSimpForm(OR, + CreateSimpForm(AND, a, b), + CreateSimpForm(AND, b, c), + CreateSimpForm(AND, a, c)); + } +} + + +// Bitwise complement +ASTVec BeevMgr::BBNeg(const ASTVec& x) +{ + ASTVec result = ASTVec(0); // FIXME: faster to preallocate n entries? + // Negate each bit. + ASTVec::const_iterator xend = x.end(); + for (ASTVec::const_iterator it = x.begin(); it < xend; it++) { + result.push_back(CreateSimpNot(*it)); + } + // FIXME: unecessary array copy when it returns? + return result; +} + +// Compute unary minus +ASTVec BeevMgr::BBUminus(const ASTVec& x) +{ + ASTVec xneg = BBNeg(x); + return BBInc(xneg); +} + +// Multiply two bitblasted numbers +ASTVec BeevMgr::BBMult(const ASTVec& x, const ASTVec& y) +{ + ASTVec ycopy(y); + ASTVec::const_iterator xend = x.end(); + ASTVec::const_iterator xit = x.begin(); + // start prod with first partial product. + // FIXME: This is unnecessary. Clean it up. + ASTVec prod = ASTVec(BBAndBit(y, *xit)); + // start loop at next bit. + for(xit++; xit < xend; xit++) { + // shift first + BBLShift(ycopy); + + if (ASTFalse == *xit) { + // If this bit is zero, the partial product will + // be zero. No reason to add that in. + continue; + } + + ASTVec pprod = BBAndBit(ycopy, *xit); + // accumulate in the product. + BBPlus2(prod, pprod, ASTFalse); + } + return prod; +} + +// This implements a variant of binary long division. +// q and r are "out" parameters. rwidth puts a bound on the +// recursion depth. +void BeevMgr::BBDivMod(const ASTVec &y, const ASTVec &x, ASTVec &q, ASTVec &r, unsigned int rwidth) +{ + unsigned int width = y.size(); + if (rwidth == 0) { + // When we have shifted the entire width, y is guaranteed to be 0. + q = BBfill(width, ASTFalse); + r = BBfill(width, ASTFalse); + } + else { + ASTVec q1, r1; + ASTVec yrshift1(y); + BBRShift(yrshift1); + + // recursively divide y/2 by x. + BBDivMod(yrshift1, x, q1, r1, rwidth-1); + + ASTVec q1lshift1(q1); + BBLShift(q1lshift1); + + ASTVec r1lshift1(r1); + BBLShift(r1lshift1); + + ASTVec r1lshift1plusyodd = BBAddOneBit(r1lshift1, y[0]); + ASTVec rminusx(r1lshift1plusyodd); + BBSub(rminusx, x); + + // Adjusted q, r values when when r is too large. + ASTNode rtoolarge = BBBVLE(x, r1lshift1plusyodd, false); + ASTVec ygtrxqval = BBITE(rtoolarge, BBInc(q1lshift1), q1lshift1); + ASTVec ygtrxrval = BBITE(rtoolarge, rminusx, r1lshift1plusyodd); + + // q & r values when y >= x + ASTNode yeqx = BBEQ(y, x); + // *** Problem: the bbfill for qval is wrong. Should be 1, not -1. + ASTVec one = BBfill(width, ASTFalse); + one[0] = ASTTrue; + ASTVec notylessxqval = BBITE(yeqx, one, ygtrxqval); + ASTVec notylessxrval = BBITE(yeqx, BBfill(width, ASTFalse), ygtrxrval); + // y < x <=> not x >= y. + ASTNode ylessx = CreateSimpNot(BBBVLE(x, y, false)); + // final values of q and r + q = BBITE(ylessx, BBfill(width, ASTFalse), notylessxqval); + r = BBITE(ylessx, y, notylessxrval); + } +} + +// build ITE's (ITE cond then[i] else[i]) for each i. +ASTVec BeevMgr::BBITE(const ASTNode& cond, const ASTVec& thn, const ASTVec& els) +{ + // Fast exits. + if (ASTTrue == cond) { + return thn; + } + else if (ASTFalse == cond) { + return els; + } + + ASTVec result(0); + ASTVec::const_iterator th_it_end = thn.end(); + ASTVec::const_iterator el_it = els.begin(); + for (ASTVec::const_iterator th_it = thn.begin(); th_it < th_it_end; th_it++, el_it++) { + result.push_back(CreateSimpForm(ITE, cond, *th_it, *el_it)); + } + return result; +} +// AND each bit of vector y with single bit b and return the result. +ASTVec BeevMgr::BBAndBit(const ASTVec& y, ASTNode b) +{ + ASTVec result(0); + + if (ASTTrue == b) { + return y; + } + // FIXME: put in fast exits when b is constant 0. + + ASTVec::const_iterator yend = y.end(); + for(ASTVec::const_iterator yit = y.begin(); yit < yend; yit++) { + result.push_back(CreateSimpForm(AND, *yit, b)); + } + return result; +} + + +// Workhorse for comparison routines. This does a signed BVLE if is_signed +// is true, else it's unsigned. All other comparison operators can be reduced +// to this by swapping args or complementing the result bit. +// FIXME: If this were done MSB first, it would enable a fast exit sometimes +// when the MSB is constant, deciding the result without looking at the rest +// of the bits. +ASTNode BeevMgr::BBBVLE(const ASTVec& left, const ASTVec& right, bool is_signed) +{ + // "thisbit" represents BVLE of the suffixes of the BVs + // from that position . if R < L, return TRUE, else if L < R + // return FALSE, else return BVLE of lower-order bits. MSB is + // treated separately, because signed comparison is done by + // complementing the MSB of each BV, then doing an unsigned + // comparison. + ASTVec::const_iterator lit = left.begin(); + ASTVec::const_iterator litend = left.end(); + ASTVec::const_iterator rit = right.begin(); + ASTNode prevbit = ASTTrue; + for ( ; lit < litend-1; lit++, rit++) { + ASTNode neglit = CreateSimpNot(*lit); + ASTNode thisbit = + CreateSimpForm(OR, + CreateSimpForm(AND,neglit,*rit), // TRUE if l < r + CreateSimpForm(AND, + CreateSimpForm(OR, neglit, *rit), // false if not equal + prevbit)); // else prevbit + prevbit = thisbit; + } + + // Handle MSB -- negate MSBs if signed comparison + // FIXME: make into refs after it's debugged. + ASTNode lmsb = *lit; + ASTNode rmsb = *rit; + if (is_signed) { + lmsb = CreateSimpNot(*lit); + rmsb = CreateSimpNot(*rit); + } + + ASTNode neglmsb = CreateSimpNot(lmsb); + ASTNode msb = + CreateSimpForm(OR, + CreateSimpForm(AND,neglmsb, rmsb), // TRUE if l < r + CreateSimpForm(AND, + CreateSimpForm(OR, neglmsb, rmsb), // false if not equal + prevbit)); // else prevbit + return msb; +} + +// Left shift by 1 within fixed field inserting zeros at LSB. +// Writes result into first argument. +// Fixme: generalize to n bits +void BeevMgr::BBLShift(ASTVec& x) +{ + // left shift x (destructively) within width. + // loop backwards so that copy to self works correctly. (DON'T use STL insert!) + ASTVec::iterator xbeg = x.begin(); + for(ASTVec::iterator xit = x.end()-1; xit > xbeg; xit--) { + *xit = *(xit-1); + } + *xbeg = ASTFalse; // new LSB is zero. + // cout << "Shifted result" << endl; + // lpvec(x); +} + +// Right shift by 1 within fixed field, inserting new zeros at MSB. +// Writes result into first argument. +// Fixme: generalize to n bits. +void BeevMgr::BBRShift(ASTVec& x) +{ + ASTVec::iterator xend = x.end() - 1; + ASTVec::iterator xit = x.begin(); + for( ; xit < xend; xit++) { + *xit = *(xit+1); + } + *xit = ASTFalse; // new MSB is zero. +} + + +// Return bit-blasted form for BVLE, BVGE, BVGT, SBLE, etc. +ASTNode BeevMgr::BBcompare(const ASTNode& form) { + const ASTNode lnode = BBTerm(form[0]); + const ASTNode rnode = BBTerm(form[1]); + const ASTVec& left = lnode.GetChildren(); + const ASTVec& right = rnode.GetChildren(); + + //const ASTVec& left = BBTerm(form[0]).GetChildren(); + //const ASTVec& right = BBTerm(form[1]).GetChildren(); + + Kind k = form.GetKind(); + switch(k) { + case BVLE: { return BBBVLE(left, right, false); break; } + case BVGE: { return BBBVLE(right, left, false); break; } + case BVGT: { return CreateSimpNot(BBBVLE(left, right, false)); break; } + case BVLT: { return CreateSimpNot(BBBVLE(right, left, false)); break; } + case BVSLE: { return BBBVLE(left, right, true); break; } + case BVSGE: { return BBBVLE(right, left, true); break; } + case BVSGT: { return CreateSimpNot(BBBVLE(left, right, true)); break; } + case BVSLT: { return CreateSimpNot(BBBVLE(right, left, true)); break; } + default: + cerr << "BBCompare: Illegal kind" << form << endl; + FatalError("",ASTUndefined); + } + return ASTUndefined; +} + + +// return a vector with n copies of fillval +ASTVec BeevMgr::BBfill(unsigned int width, ASTNode fillval) +{ + ASTVec zvec(width, fillval); + return zvec; +} + +ASTNode BeevMgr::BBEQ(const ASTVec& left, const ASTVec& right) +{ + ASTVec andvec; + ASTVec::const_iterator lit = left.begin(); + ASTVec::const_iterator litend = left.end(); + ASTVec::const_iterator rit = right.begin(); + + if(left.size() > 1) { + for(; lit != litend; lit++, rit++) { + ASTNode biteq = CreateSimpForm(IFF, *lit, *rit); + // fast path exit + if (biteq == ASTFalse) { + return ASTFalse; + } + else { + andvec.push_back(biteq); + } + } + ASTNode n = CreateSimpForm(AND, andvec); + return n; + } + else + return CreateSimpForm(IFF,*lit,*rit); +} +} // BEEV namespace diff --git a/stp/AST/Makefile b/stp/AST/Makefile new file mode 100644 index 00000000..0218510b --- /dev/null +++ b/stp/AST/Makefile @@ -0,0 +1,54 @@ +include ../Makefile.common + +SRCS = AST.cpp ASTKind.cpp ASTUtil.cpp BitBlast.cpp SimpBool.cpp ToCNF.cpp ToSAT.cpp Transform.cpp +OBJS = $(SRCS:.cpp=.o) + +#Make the ast library for use by other modules +libast.a: $(OBJS) + -rm -rf $@ + $(AR) rc libast.a $(OBJS) + $(RANLIB) libast.a + +ASTKind.o: ASTKind.h ASTKind.cpp + $(CXX) $(CXXFLAGS) -c -o ASTKind.o ASTKind.cpp + +# ASTKind.h and ASTKind.cpp are automatically generated +ASTKind.h ASTKind.cpp: ASTKind.kinds genkinds.pl + ./genkinds.pl + +# cnftest: cnftest.o ToCNF.o AST.o ASTUtil.o ASTKind.o BitBlast.o AST.h +# $(CC) $(LDFLAGS) ToCNF.o BitBlast.o ASTKind.o ASTUtil.o AST.o cnftest.o -o cnftest + +# bbtest: $(OBJS) +# $(CC) $(LDFLAGS) BitBlast.o ASTKind.o ASTUtil.o AST.o bbtest.o -o bbtest + +# asttest: $(OBJS) +# $(CC) $(LDFLAGS) ASTKind.o ASTUtil.o AST.o asttest.o -lstdc++ -o asttest + +clean: + rm -rf *.o *~ bbtest asttest cnftest *.a ASTKind.h ASTKind.cpp .#* + +depend: + makedepend -Y -- $(CFLAGS) -- $(SRCS) +# DO NOT DELETE + +AST.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h +AST.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h +AST.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h +ASTUtil.o: ASTUtil.h +BitBlast.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h +BitBlast.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h +BitBlast.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h +SimpBool.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h +SimpBool.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h +SimpBool.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h +ToCNF.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h +ToCNF.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h +ToCNF.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h +ToSAT.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h +ToSAT.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h +ToSAT.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h +ToSAT.o: ../simplifier/bvsolver.h ../AST/AST.h +Transform.o: AST.h ASTUtil.h ASTKind.h ../sat/Solver.h ../sat/SolverTypes.h +Transform.o: ../sat/Global.h ../sat/VarOrder.h ../sat/Solver.h ../sat/Heap.h +Transform.o: ../AST/ASTUtil.h ../sat/SolverTypes.h ../constantbv/constantbv.h diff --git a/stp/AST/STLport_config.h b/stp/AST/STLport_config.h new file mode 100644 index 00000000..9b7bc14f --- /dev/null +++ b/stp/AST/STLport_config.h @@ -0,0 +1,20 @@ +/******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ +// -*- c++ -*- + +// STLport debug checking, if we use STLport threads flag is to get +// rid of link errors, since iostreams compiles with threads. alloc +// and uninitialized are extra checks Later on, if used with Purify or +// Valgrind, may want to set flags to prevent reporting of false +// leaks. For some reason, _STLP_THREADS works on the command line +// but not here (?) +#define _STLP_THREADS +#define _STLP_DEBUG 1 +#define _STLP_DEBUG_LEVEL _STLP_STANDARD_DBG_LEVEL +#define _STLP_DEBUG_ALLOC 1 +#define _STLP_DEBUG_UNINITIALIZED 1 diff --git a/stp/AST/SimpBool.cpp b/stp/AST/SimpBool.cpp new file mode 100644 index 00000000..67f9825d --- /dev/null +++ b/stp/AST/SimpBool.cpp @@ -0,0 +1,408 @@ +/******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: April, 2006 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ + +// -*- c++ -*- + +// Simplifying create methods for Boolean operations. +// These are only very simple local simplifications. + +// This is somewhat redundant with Vijay's simplifier code. They +// need to be merged. +// FIXME: control with optimize flag. + +static bool _trace_simpbool = 0; +static bool _disable_simpbool = 0; + +#include "AST.h" + +// SMTLIB experimental hack. Try allocating a single stack here for +// children to reduce growing of vectors. +//BEEV::ASTVec child_stack; + +namespace BEEV { + + ASTNode BeevMgr::CreateSimpForm(Kind kind, ASTVec &children = _empty_ASTVec) { + if (_disable_simpbool) { + return CreateNode(kind, children); + } + else { + switch (kind) { + case NOT: return CreateSimpNot(children[0]); break; + case AND: return CreateSimpAndOr(1, children); break; + case OR: return CreateSimpAndOr(0, children); break; + case NAND: return CreateSimpNot(CreateSimpAndOr(1, children)); break; + case NOR: return CreateSimpNot(CreateSimpAndOr(0, children)); break; + case IFF: { + // Not sure children can ever be empty, but what the heck. + // if (children.size() == 0) { + // return ASTTrue; + // } + // Convert IFF to XOR ASAP. IFF is not associative, so this makes + // flattening much easier. + children[0] = CreateSimpNot(children[0]); + return CreateSimpXor(children); break; + } + case XOR: + return CreateSimpXor(children); break; + // FIXME: Earlier, check that this only has two arguments + case IMPLIES: return CreateSimpAndOr(0, CreateSimpNot(children[0]), children[1]); break; + case ITE: return CreateSimpFormITE(children[0], children[1], children[2]); + default: return CreateNode(kind, children); + } + } + } + + // specialized versions + + ASTNode BeevMgr::CreateSimpForm(Kind kind, + const ASTNode& child0) { + ASTVec children; + //child_stack.clear(); // could just reset top pointer. + children.push_back(child0); + //child_stack.push_back(child0); + return CreateSimpForm(kind, children); + //return CreateSimpForm(kind, child_stack); + } + + ASTNode BeevMgr::CreateSimpForm(Kind kind, + const ASTNode& child0, + const ASTNode& child1) { + ASTVec children; + //child_stack.clear(); // could just reset top pointer. + children.push_back(child0); + //child_stack.push_back(child0); + children.push_back(child1); + //child_stack.push_back(child1); + return CreateSimpForm(kind, children); + //return CreateSimpForm(kind, child_stack); + } + + + ASTNode BeevMgr::CreateSimpForm(Kind kind, + const ASTNode& child0, + const ASTNode& child1, + const ASTNode& child2) { + ASTVec children; + //child_stack.clear(); // could just reset top pointer. + children.push_back(child0); + //child_stack.push_back(child0); + children.push_back(child1); + //child_stack.push_back(child1); + children.push_back(child2); + //child_stack.push_back(child2); + return CreateSimpForm(kind, children); + //return CreateSimpForm(kind, child_stack); + } + + ASTNode BeevMgr::CreateSimpNot(const ASTNode& form) { + Kind k = form.GetKind(); + switch (k) { + case FALSE: { return ASTTrue; } + case TRUE: { return ASTFalse; } + case NOT: { return form[0]; } // NOT NOT cancellation + case XOR: { + // Push negation down in this case. + // FIXME: Separate pre-pass to push negation down? + // CreateSimp should be local, and this isn't. + // It isn't memoized. Arg. + ASTVec children = form.GetChildren(); + children[0] = CreateSimpNot(children[0]); + return CreateSimpXor(children); + } + default: { return CreateNode(NOT, form); } + } + } + + // I don't think this is even called, since it called + // CreateSimpAndOr instead of CreateSimpXor until 1/9/07 with no + // ill effects. Calls seem to go to the version that takes a vector + // of children. + ASTNode BeevMgr::CreateSimpXor(const ASTNode& form1, const ASTNode& form2) { + ASTVec children; + children.push_back(form1); + children.push_back(form2); + return CreateSimpXor(children); + } + + + ASTNode BeevMgr::CreateSimpAndOr(bool IsAnd, const ASTNode& form1, const ASTNode& form2) { + ASTVec children; + children.push_back(form1); + children.push_back(form2); + return CreateSimpAndOr(IsAnd, children); + } + + ASTNode BeevMgr::CreateSimpAndOr(bool IsAnd, ASTVec &children) { + + if (_trace_simpbool) { + cout << "========" << endl << "CreateSimpAndOr " << (IsAnd ? "AND " : "OR ") ; + lpvec(children); + cout << endl; + } + + ASTVec new_children; + + // sort so that identical nodes occur in sequential runs, followed by + // their negations. + + SortByExprNum(children); + + ASTNode annihilator = (IsAnd ? ASTFalse : ASTTrue); + ASTNode identity = (IsAnd ? ASTTrue : ASTFalse); + + ASTNode retval; + + ASTVec::const_iterator it_end = children.end(); + ASTVec::const_iterator next_it; + for(ASTVec::const_iterator it = children.begin(); it != it_end; it = next_it) { + next_it = it + 1; + bool nextexists = (next_it < it_end); + + if (*it == annihilator) { + retval = annihilator; + if (_trace_simpbool) { + cout << "returns " << retval << endl; + } + return retval; + } + else if (*it == identity) { + // just drop it + } + else if (nextexists && (*next_it == *it)) { + // drop it + // cout << "Dropping [" << it->GetNodeNum() << "]" << endl; + } + else if (nextexists && (next_it->GetKind() == NOT) && ((*next_it)[0] == *it)) { + // form and negation -- return FALSE for AND, TRUE for OR. + retval = annihilator; + // cout << "X and/or NOT X" << endl; + if (_trace_simpbool) { + cout << "returns " << retval << endl; + } + return retval; + } + else { + // add to children + new_children.push_back(*it); + } + } + + // If we get here, we saw no annihilators, and children should + // be only the non-True nodes. + if (new_children.size() < 2) { + if (0 == new_children.size()) { + retval = identity; + } + else { + // there is just one child + retval = new_children[0]; + } + } + else { + // 2 or more children. Create a new node. + retval = CreateNode(IsAnd ? AND : OR, new_children); + } + if (_trace_simpbool) { + cout << "returns " << retval << endl; + } + return retval; + } + + + // Constant children are accumulated in "accumconst". + ASTNode BeevMgr::CreateSimpXor(ASTVec &children) { + + if (_trace_simpbool) { + cout << "========" << endl + << "CreateSimpXor "; + lpvec(children); + cout << endl; + } + + // Change this not to init to children if flattening code is present. + // ASTVec flat_children = children; // empty vector + + ASTVec flat_children; // empty vector + + ASTVec::const_iterator it_end = children.end(); + + if (xor_flatten) { + + bool fflag = 0; // ***Temp debugging + + // Experimental flattening code. + + for(ASTVec::iterator it = children.begin(); it != it_end; it++) { + Kind ck = it->GetKind(); + const ASTVec &gchildren = it->GetChildren(); + if (XOR == ck) { + fflag = 1; + // append grandchildren to children + flat_children.insert(flat_children.end(), gchildren.begin(), gchildren.end()); + } + else { + flat_children.push_back(*it); + } + } + + if (_trace_simpbool && fflag) { + cout << "========" << endl; + cout << "Flattening: " << endl; + lpvec(children); + + cout << "--------" << endl; + cout << "Flattening result: " << endl; + lpvec(flat_children); + } + } + else { + flat_children = children; + } + + + // sort so that identical nodes occur in sequential runs, followed by + // their negations. + SortByExprNum(flat_children); + + ASTNode retval; + + // This is the C Boolean value of all constant args seen. It is initially + // 0. TRUE children cause it to change value. + bool accumconst = 0; + + ASTVec new_children; + + it_end = flat_children.end(); + ASTVec::iterator next_it; + for(ASTVec::iterator it = flat_children.begin(); it != it_end; it++) { + next_it = it + 1; + bool nextexists = (next_it < it_end); + + if (ASTTrue == *it) { + accumconst = !accumconst; + } + else if (ASTFalse == *it) { + // Ignore it + } + else if (nextexists && (*next_it == *it)) { + // x XOR x = FALSE. Skip current, write "false" into next_it + // so that it gets tossed, too. + *next_it = ASTFalse; + } + else if (nextexists && (next_it->GetKind() == NOT) && ((*next_it)[0] == *it)) { + // x XOR NOT x = TRUE. Skip current, write "true" into next_it + // so that it gets tossed, too. + *next_it = ASTTrue; + } + else if (NOT == it->GetKind()) { + // If child is (NOT alpha), we can flip accumconst and use alpha. + // This is ok because (NOT alpha) == TRUE XOR alpha + accumconst = !accumconst; + // CreateSimpNot just takes child of not. + new_children.push_back(CreateSimpNot(*it)); + } + else { + new_children.push_back(*it); + } + } + + // Children should be non-constant. + if (new_children.size() < 2) { + if (0 == new_children.size()) { + // XOR(TRUE, FALSE) -- accumconst will be 1. + if (accumconst) { + retval = ASTTrue; + } + else { + retval = ASTFalse; + } + } + else { + // there is just one child + // XOR(x, TRUE) -- accumconst will be 1. + if (accumconst) { + retval = CreateSimpNot(new_children[0]); + } + else { + retval = new_children[0]; + } + } + } + else { + // negate first child if accumconst == 1 + if (accumconst) { + new_children[0] = CreateSimpNot(new_children[0]); + } + retval = CreateNode(XOR, new_children); + } + + if (_trace_simpbool) { + cout << "returns " << retval << endl; + } + return retval; + } + + // FIXME: How do I know whether ITE is a formula or not? + ASTNode BeevMgr::CreateSimpFormITE(const ASTNode& child0, + const ASTNode& child1, + const ASTNode& child2) { + + ASTNode retval; + + if (_trace_simpbool) { + cout << "========" << endl << "CreateSimpFormITE " + << child0 + << child1 + << child2 << endl; + } + + if (ASTTrue == child0) { + retval = child1; + } + else if (ASTFalse == child0) { + retval = child2; + } + else if (child1 == child2) { + retval = child1; + } + // ITE(x, TRUE, y ) == x OR y + else if (ASTTrue == child1) { + retval = CreateSimpAndOr(0, child0, child2); + } + // ITE(x, FALSE, y ) == (!x AND y) + else if (ASTFalse == child1) { + retval = CreateSimpAndOr(1, CreateSimpNot(child0), child2); + } + // ITE(x, y, TRUE ) == (!x OR y) + else if (ASTTrue == child2) { + retval = CreateSimpAndOr(0, CreateSimpNot(child0), child1); + } + // ITE(x, y, FALSE ) == (x AND y) + else if (ASTFalse == child2) { + retval = CreateSimpAndOr(1, child0, child1); + } + // ITE (x, !y, y) == x XOR y +// else if (NOT == child1.GetKind() && (child1[0] == child2)) { +// retval = CreateSimpXor(child0, child2); +// } +// // ITE (x, y, !y) == x IFF y. I think other cases are covered +// // by XOR/IFF optimizations +// else if (NOT == child2.GetKind() && (child2[0] == child1)) { +// retval = CreateSimpXor(CreateSimpNot(child0), child2); +// } + else { + retval = CreateNode(ITE, child0, child1, child2); + } + + if (_trace_simpbool) { + cout << "returns " << retval << endl; + } + + return retval; + } +} // BEEV namespace diff --git a/stp/AST/ToCNF.cpp b/stp/AST/ToCNF.cpp new file mode 100644 index 00000000..2a18b3f5 --- /dev/null +++ b/stp/AST/ToCNF.cpp @@ -0,0 +1,506 @@ +/******************************************************************** + * AUTHORS: David L. Dill, Vijay Ganesh + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ +// -*- c++ -*- + +// THEORY: This code translates an arbitrary Boolean DAG, generated by +// the BitBlast.cpp, to an equi-satisfiable CNF formula. There are +// four kinds of variables in the CNF formula: (1) propositional +// variables from the original formula; (2) BVGETBIT formulas from the +// original formula (a precondition is that the BVGETBIT can only be +// applied to bitvector-valued variables, array reads, or +// uninterpreted functions); (3) TRUE; or (4) representative variables +// (see below). Each literal in the CNF formula is one of these or +// its negation. + +// It is convenient (though not perfectly efficient) to be able to add +// TRUE and FALSE constants to clauses, which is not allowed in CNF. +// So, there is a "dummy variable" representing TRUE, which is used in +// its place (so FALSE is represented by the negation of the dummy +// var). The CNF formula has a unit clause containing this dummy +// variable, so that any satisfying assignment must make the dummy var +// TRUE. + +// Every sub-formula of the input formula has a "representative +// literal." A truth assignment satisfies the CNF formula iff the +// restriction of that assignment to the original variables satisfies +// the original formula, AND the rep lits have the same truth values +// as the subformulas they represent in the original formula. In the +// trivial cases, the representative literal is the input variable, or +// dummy true var, or its negation. Representative literals may be +// negated variables -- essentially, only AND formulas are translated, +// and everything else is handled by rewriting or negating formulas. +// The representative for (NOT alpha) is the negation of the +// representative for alpha. + +// The translation is performed by ToCNF_int, which traverses the original +// formula. ToCNF adds clauses that constrain the representative variables +// to be equal to the truth values of the formulas they represent. +// ToCNF always returns a literal whose value must be equivalent to the formula +// it translated. In trivial cases, this literal is a literal from the original +// formula, or the dummy true/false literals. If the formula is of the form +// (not alpha), ToCNF_int negates the literal representing alpha (which may +// itself be a negative literal) and returns it. Otherwise, ToCNF_int assigns +// a new rep var, adds the clauses, and returns the new var. ToCNF_int is +// memoized so that it doesn't assign more than one variable to a subformula, +// and to prevent exponential numbers of redundant visits to shared subformulas. + +// In reality, only AND/OR/NOT formulas are translated directly. Everything +// else (XOR, IFF, IMPLIES) is rewritten on-the-fly into these forms. I +// could have done that in bit-blasting, but I thought that, in the future, +// we might be able to translate these operations differently in different +// contexts to optimize the CNF formula. + +// FIXME: Inspection of the clauses is kind of horrifying. In +// addition to true/false, there are duplicate literals and duplicate +// clauses all over the place. +#include "AST.h" +static bool CNF_trace = false; +namespace BEEV { +/** Statistics class. Total number of variables is best tracked in + ToSAT. Number of clauses is just cll.size() */ + +class CNFstats { +public: + int _num_new_rep_vars; + int _num_clauses; + + // constructor + CNFstats() : _num_new_rep_vars(0), _num_clauses(0) {} + + void printStats() { + if(stats) { + cout << "ToCNF statistics:" << endl; + cout << "Number of new representative variables: " + << _num_new_rep_vars << endl; + cout << "Number of new clauses: " + << _num_clauses << endl; + } + } + +}; + + +/** This class contains private data and function members for the + CNF conversion */ +class CNFMgr { + + friend class BeevMgr; + +public: + + // Needed in the body of BeevMgr::ToCNF. It's not visible outside + // this file, though. + ASTNode dummy_true_var; + + // CNF Pre-pass + ASTNodeMap ToCNFPrePassMemo; + + // CNF Memo Table. + ASTNodeMap CNFMemo; + + +private: + + // Pointer back to BeevMgr with the node tables, etc. + BeevMgr *bm; + + // For ToCNF conversion. This holds a dummy variable representing + // "True". It is added as a unit clause, so that it will be assigned + // to true and propagated immediately by any CNF solver. + + ASTNode dummy_false_var; // not of dummy_true_var + + CNFstats stats; + + // constructor + CNFMgr(BeevMgr *bmgr) + { + bm = bmgr; + + // Dummy variable so TRUE can be a literal. + dummy_true_var = bm->CreateSymbol("*TrueDummy*"); + dummy_false_var = bm->CreateSimpNot(dummy_true_var); + } + + // Returns true iff result has been memoized. + // if it returns true, result is returned in by-ref parameter "result" + // Consider just putitng this in-line. + bool CNFIsMemoized(ASTNode &form, ASTNode &result) + { + ASTNodeMap::iterator it = CNFMemo.find(form); + if (it != CNFMemo.end()) { + result = it->second; //already there. Just return it. + return true; + } + else { + return false; + } + } + + + // Convert a big XOR to a bunch of AND/ORs. Assumes subformulas have + // already been converted. + ASTNode convertXORs(ASTVec children) + { + ASTNode accum = children[0]; + ASTVec::iterator itend = children.end(); + for (ASTVec::iterator it = children.begin()+1; it < itend; it++) { + // a XOR b -> (a | b) & (!a | !b) + + // For each XOR node with k children, creates approximately + // 5*(k-1) nodes. AND + 2 OR + 2 NOT. + + ASTNode or1 = bm->CreateNode(OR, accum, *it); + ASTNode or2 = bm->CreateNode(OR, bm->CreateSimpNot(accum), bm->CreateSimpNot(*it)); + accum = bm->CreateNode(AND, or1, or2); + + } + + return accum; + } + + + // Do preliminary transformations on bitblasted formula to make + // CNF conversion easier. + // Converts XORs to AND/OR form. + ASTNode ToCNFPrePass(const ASTNode &form) + { + + // Check memo table + ASTNodeMap::iterator mem_it = ToCNFPrePassMemo.find(form); + if (mem_it != ToCNFPrePassMemo.end()) { + return mem_it->second; + } + + ASTNode result; + + ASTVec new_children; + ASTVec::const_iterator endit = form.end(); + for (ASTVec::const_iterator it = form.begin(); it != endit; it++) { + ASTNode ch = ToCNFPrePass(*it); + new_children.push_back(ch); + } + + Kind k = form.GetKind(); + + switch (k) { + case FALSE: + case TRUE: + case SYMBOL: + case BVGETBIT: { + result = form; + break; + } + case XOR: { + // convertXORs can only be called once per XOR node. + result = convertXORs(new_children); + + // cout << "convertXORs num args: " << new_children.size() << endl; + // temporary node for node count. + // ASTNode tmp = bm->CreateNode(XOR, new_children ); + // cout << "convertXORs size of [" << form.GetNodeNum() << "] " << bm->NodeSize(form, true) << endl; + // cout << "convertXORs before size: " << bm->NodeSize(tmp, true) << endl; + // cout << "convertXORs after size: " << bm->NodeSize(result, true) << endl; + break; + } + default: { + // Be cautious about using CreateSimpForm -- It makes big xors! + result = bm->CreateNode(k, new_children); + } + } + +// cout << "================" << endl +// << "ToCNFPrePass:" << form << endl +// << "----------------" << endl +// << "ToCNFPrePass Result:" << result << endl; + + return (ToCNFPrePassMemo[form] = result); + + } + + // Memoize and return formula value + ASTNode CNFMemoize(ASTNode& form, ASTNode result) + { + CNFMemo[form] = result; + return result; + } + + + // Create a representative variable for an original formula. + // The convention is that the variable will have the same truth + // value as the expression numbered "num." + ASTNode RepLit(const char *name, int exprnum) + { + // FIXME: can this be done more efficiently with string type? + ostringstream oss; + oss << name << "{" << exprnum << "}"; + ASTNode t = bm->CreateSymbol(oss.str().c_str()); + + // Track how many we're generating. + stats._num_new_rep_vars++; + + //ASTNode is of type BOOLEAN <==> ((indexwidth=0)&&(valuewidth=0)) + t.SetIndexWidth(0); + t.SetValueWidth(0); + return t; + } + + // Handle the cases where it's necessary to do n children. + // This code translates ANDs, and converts NAND, NOR, OR by negating + // the inputs or outputs of the AND. + ASTNode ToCNF_AndLike(Kind k, BeevMgr::ClauseList& cll, ASTNode form) + { + // Build vectors of positive and negative rep lits for children + ASTVec kidlits(0); + ASTVec negkidlits(0); + ASTVec::const_iterator kids_end = form.end(); + for (ASTVec::const_iterator it = form.begin(); it != kids_end; it++) { + ASTNode kidreplit = ToCNF_int(cll, *it); + kidlits.push_back(kidreplit); + negkidlits.push_back(bm->CreateSimpNot(kidreplit)); + } + + ASTNode replit; + // translate the AND, negating inputs as appropriate. + if (k == OR || k == NOR) { + replit = ToCNF_AND(cll, form.GetNodeNum(), negkidlits, kidlits); + } + else { + replit = ToCNF_AND(cll, form.GetNodeNum(), kidlits, negkidlits); + } + + // Reduce NAND/OR to AND by negating result. + if (k == NAND || k == OR) { + return CNFMemoize(form, bm->CreateSimpNot(replit)); + } + else { + return CNFMemoize(form, replit); + } + } + + ASTNode ToCNF_AND(BeevMgr::ClauseList& cll, int nodenum, ASTVec& kidlits, ASTVec& negkidlits) + { + // Translate an AND, given rep lits for children + // Build clauses for (replit <-> a AND b AND c) + + ASTNode replit = RepLit("cnf", nodenum); + ASTNode notreplit = bm->CreateSimpNot(replit); + + if (CNF_trace) { + cout << "Translating AND" << endl << "-----------------------" << endl + << "Rep lit =" << replit << endl + << "-----------------------"; + } + + // (a AND b AND c -> replit) == (~a OR ~b OR ~c OR replit) + BeevMgr::ClausePtr clp = new ASTVec(negkidlits); + clp->push_back(replit); + + if (CNF_trace) { + LispPrintVec(cout, *clp, 0); + cout << endl << "-----------------------" << endl; + } + + cll.push_back(clp); + + // (replit -> (a AND b AND c)) == + // (~replit OR a) AND (~replit OR b) AND (~replit OR c) + ASTVec::const_iterator kidlits_end = kidlits.end(); + for (ASTVec::iterator it = kidlits.begin(); it != kidlits_end; it++) { + clp = new ASTVec(); + clp->push_back(notreplit); + clp->push_back(*it); + + if (CNF_trace) { + LispPrintVec(cout, *clp, 0); + cout << endl << "-----------------------" << endl; + } + + cll.push_back(clp); + } + + return replit; + } + +public: + + /** Builds clauses globally and returns a literal. + The literal can be a leaf from the expression, or a rep var + made up to represent the subexpression. */ + ASTNode ToCNF_int(BeevMgr::BeevMgr::ClauseList& cll, ASTNode form) { + // FIXME: assert indexwidth= 0, valuewidth = 1 + + // FIXME: rewriting is top-down, which is not efficient. + // It rewrites the top node of the tree, then does the children. + // Either rewrite in a separate pass, or translate children + // before rewriting somehow (might require handling rep lits + // as though they were real lits, which is probably ok). + + // Return memoized value if seen before. + ASTNode result; + Kind k = form.GetKind(); + + if (CNFIsMemoized(form, result)) { + return result; + } + + switch (k) { + // handle the trivial cases here. If none apply, call the + // heavy-duty function. If a constant or literal, just return + // without creating a clause. + case FALSE: { + result = dummy_false_var; + break; + } + case TRUE: { + result = dummy_true_var; + break; + } + case SYMBOL: + case BVGETBIT: { + result = form; + break; + } + + case NOT: { + ASTNode replit = ToCNF_int(cll, form[0]); + result = bm->CreateSimpNot(replit); + break; + } + + // For these, I can't think of anything better than expanding into ANDs/ORs + case ITE: { + // (ite a b c) == (~a OR b) AND (a OR c) + ASTNode l = bm->CreateNode(OR, bm->CreateSimpNot(form[0]), form[1]); + ASTNode r = bm->CreateNode(OR, form[0], form[2]); + ASTNode andor = bm->CreateNode(AND, l, r); + if (CNF_trace) { + cout << "Rewriting " << form << endl + << "to" << andor << endl + << "-------------------" << endl; + } + result = ToCNF_int(cll, andor); + break; + } + case IMPLIES: { + // Just rewrite into (~a OR b) + ASTNode l = bm->CreateSimpNot(form[0]); + ASTNode andor = bm->CreateNode(OR, l, form[1]); + if (CNF_trace) { + cout << "Rewriting " << form << endl + << "to" << andor << endl + << "-------------------" << endl; + } + result = ToCNF_int(cll, andor); + break; + } + case XOR: { + FatalError("ToCNF_int: XORs should have been converted to AND/OR by this point."); + break; + } + + case IFF: { + FatalError("BitBlaster failed to eliminate all IFFs."); + break; + } + + case AND: + case OR: + case NOR: + case NAND: { + result = ToCNF_AndLike(k, cll, form); + break; + } + default: + cerr << "ToCNF: can't handle this kind: " << k << endl; + FatalError(""); + } + + if (CNF_trace) { + cout << "ToCNF_int: Literal " << result << " represents formula " << + form << endl << "---------------" << endl; + } + + return CNFMemoize(form, result); + } //end of ToCNF_int() + + +}; // end of CNFMgr class + + // These are the bodies of functions in the BeevMgr that are part of + // the public interface. + + // Debug printing function. + void BeevMgr::PrintClauseList(ostream& os, BeevMgr::ClauseList& cll) + { + int num_clauses = cll.size(); + os << "Clauses: " << endl << "=========================================" << endl; + for(int i=0; i < num_clauses; i++) { + os << "Clause " << i << endl + << "-------------------------------------------" << endl; + LispPrintVec(os, *cll[i], 0); + os << endl + << "-------------------------------------------" << endl; + } + } + + void BeevMgr::DeleteClauseList(BeevMgr::ClauseList *cllp) + { + BeevMgr::ClauseList::const_iterator iend = cllp->end(); + for (BeevMgr::ClauseList::const_iterator i = cllp->begin(); i < iend; i++) { + delete *i; + } + delete cllp; + } + + // Top level conversion function + BeevMgr::ClauseList *BeevMgr::ToCNF(const ASTNode& form) + { + + // FIXME: This is leaked as well. + CNFMgr *cm = new CNFMgr(this); + + // Prepass + ASTNode form1 = cm->ToCNFPrePass(form); + + // cout << "Number of nodes after ToCNFPrePass" << NodeSize(form1, true) << endl; + + // cout << "ToCNF: After ToCNFPrePass" << form1 << endl; + + // FIXME: Assert CNFMemo is empty. + + // The clause list we will be building up. + // FIXME: This is never freed. + ClauseList *cllp = new ClauseList(); + + BeevMgr::ClausePtr dummy_true_unit_clause = new ASTVec(); + dummy_true_unit_clause->push_back(cm->dummy_true_var); + cllp->push_back(dummy_true_unit_clause); + + // This is where the translation happens. + ASTNode toplit = cm->ToCNF_int(*cllp, form1); + + // Add the top literal as a unit clause, since it must + // be true when original formula is satsfied. + BeevMgr::ClausePtr clp = new ASTVec(0); + clp->push_back(toplit); + cllp->push_back(clp); + + cm->stats._num_clauses = cllp->size(); + cm->stats.printStats(); + + RepLitMap = cm->CNFMemo; // Save memo table for debugging (DD 1/13/07). + + cm->CNFMemo.clear(); // Important to do this so nodes get freed. + + delete cm; + + return cllp; + } + +} // end namespace 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 diff --git a/stp/AST/Transform.cpp b/stp/AST/Transform.cpp new file mode 100644 index 00000000..598b831e --- /dev/null +++ b/stp/AST/Transform.cpp @@ -0,0 +1,492 @@ +/******************************************************************** + * 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 <stdlib.h> +#include <stdio.h> +namespace BEEV { + + //Translates signed BVDIV/BVMOD into unsigned variety + ASTNode BeevMgr::TranslateSignedDivMod(const ASTNode& in) { + if(!(SBVMOD == in.GetKind() || SBVDIV == in.GetKind())) { + FatalError("TranslateSignedDivMod: input must be signed DIV/MOD\n",in); + } + + ASTNode dividend = in[0]; + ASTNode divisor = in[1]; + unsigned len = in.GetValueWidth(); + if(SBVMOD == in.GetKind()) { + //if(TopBit(dividend)==1) + // + //then -BVMOD(-dividend,abs(divisor)) + // + //else BVMOD(dividend,abs(divisor)) + + //create the condition for the dividend + ASTNode hi1 = CreateBVConst(32,len-1); + ASTNode one = CreateOneConst(1); + ASTNode cond = CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)); + + //create the condition and conditional for the divisor + ASTNode cond_divisor = CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1)); + ASTNode pos_divisor = CreateTerm(ITE,len,cond_divisor,CreateTerm(BVUMINUS,len,divisor),divisor); + + //create the modulus term for each case + ASTNode modnode = CreateTerm(BVMOD,len,dividend,pos_divisor); + ASTNode minus_modnode = CreateTerm(BVMOD,len,CreateTerm(BVUMINUS,len,dividend),pos_divisor); + minus_modnode = CreateTerm(BVUMINUS,len,minus_modnode); + + //put everything together, simplify, and return + ASTNode n = CreateTerm(ITE,len,cond,minus_modnode,modnode); + return SimplifyTerm_TopLevel(n); + } + + //now handle the BVDIV case + //if topBit(dividend) is 1 and topBit(divisor) is 0 + // + //then output is -BVDIV(-dividend,divisor) + // + //elseif topBit(dividend) is 0 and topBit(divisor) is 1 + // + //then output is -BVDIV(dividend,-divisor) + // + //elseif topBit(dividend) is 1 and topBit(divisor) is 1 + // + // then output is BVDIV(-dividend,-divisor) + // + //else simply output BVDIV(dividend,divisor) + ASTNode hi1 = CreateBVConst(32,len-1); + ASTNode zero = CreateZeroConst(1); + ASTNode one = CreateOneConst(1); + ASTNode divnode = CreateTerm(BVDIV, len, dividend, divisor); + + ASTNode cond1 = CreateNode(AND, + CreateNode(EQ,zero,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), + CreateNode(EQ,one, CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); + ASTNode minus_divnode1 = CreateTerm(BVDIV,len, + dividend, + CreateTerm(BVUMINUS,len,divisor)); + minus_divnode1 = CreateTerm(BVUMINUS,len,minus_divnode1); + + ASTNode cond2 = CreateNode(AND, + CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), + CreateNode(EQ,zero,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); + ASTNode minus_divnode2 = CreateTerm(BVDIV,len, + CreateTerm(BVUMINUS,len,dividend), + divisor); + minus_divnode2 = CreateTerm(BVUMINUS,len,minus_divnode2); + + ASTNode cond3 = CreateNode(AND, + CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), + CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); + ASTNode minus_divnode3 = CreateTerm(BVDIV,len, + CreateTerm(BVUMINUS,len,dividend), + CreateTerm(BVUMINUS,len,divisor)); + ASTNode n = CreateTerm(ITE,len, + cond1, + minus_divnode1, + CreateTerm(ITE,len, + cond2, + minus_divnode2, + CreateTerm(ITE,len, + cond3, + minus_divnode3, + divnode))); + return SimplifyTerm_TopLevel(n); + }//end of TranslateSignedDivMod() + + ASTNode BeevMgr::TransformFormula(const ASTNode& form) { + ASTNode result; + + ASTNode simpleForm = form; + Kind k = simpleForm.GetKind(); + if(!(is_Form_kind(k) && BOOLEAN_TYPE == simpleForm.GetType())) { + //FIXME: "You have inputted a NON-formula"? + FatalError("TransformFormula: You have input a NON-formula",simpleForm); + } + + ASTNodeMap::iterator iter; + if((iter = TransformMap.find(simpleForm)) != TransformMap.end()) + return iter->second; + + switch(k) { + case TRUE: + case FALSE: { + result = simpleForm; + break; + } + case NOT: { + ASTVec c; + c.push_back(TransformFormula(simpleForm[0])); + result = CreateNode(NOT,c); + break; + } + case BVLT: + case BVLE: + case BVGT: + case BVGE: + case BVSLT: + case BVSLE: + case BVSGT: + case BVSGE: + case NEQ: { + ASTVec c; + c.push_back(TransformTerm(simpleForm[0])); + c.push_back(TransformTerm(simpleForm[1])); + result = CreateNode(k,c); + break; + } + case EQ: { + ASTNode term1 = TransformTerm(simpleForm[0]); + ASTNode term2 = TransformTerm(simpleForm[1]); + result = CreateSimplifiedEQ(term1,term2); + break; + } + case AND: + case OR: + case NAND: + case NOR: + case IFF: + case XOR: + case ITE: + case IMPLIES: { + ASTVec vec; + ASTNode o; + for (ASTVec::const_iterator it = simpleForm.begin(),itend=simpleForm.end(); it != itend; it++){ + o = TransformFormula(*it); + vec.push_back(o); + } + + result = CreateNode(k, vec); + break; + } + default: + if(k == SYMBOL && BOOLEAN_TYPE == simpleForm.GetType()) + result = simpleForm; + else { + cerr << "The input is: " << simpleForm << endl; + cerr << "The valuewidth of input is : " << simpleForm.GetValueWidth() << endl; + FatalError("TransformFormula: Illegal kind: ",ASTUndefined, k); + } + break; + } + //BVTypeCheck(result); + TransformMap[simpleForm] = result; + return result; + } //End of TransformFormula + + ASTNode BeevMgr::TransformTerm(const ASTNode& inputterm) { + ASTNode result; + ASTNode term = inputterm; + + Kind k = term.GetKind(); + if(!is_Term_kind(k)) + FatalError("TransformTerm: Illegal kind: You have input a nonterm:", inputterm, k); + ASTNodeMap::iterator iter; + if((iter = TransformMap.find(term)) != TransformMap.end()) + return iter->second; + switch(k) { + case SYMBOL: { + // ASTNodeMap::iterator itsym; +// if((itsym = CounterExampleMap.find(term)) != CounterExampleMap.end()) +// result = itsym->second; +// else + result = term; + break; + } + case BVCONST: + result = term; + break; + case WRITE: + FatalError("TransformTerm: this kind is not supported",term); + break; + case READ: + result = TransformArray(term); + break; + case ITE: { + ASTNode cond = term[0]; + ASTNode thn = term[1]; + ASTNode els = term[2]; + cond = TransformFormula(cond); + thn = TransformTerm(thn); + els = TransformTerm(els); + //result = CreateTerm(ITE,term.GetValueWidth(),cond,thn,els); + result = CreateSimplifiedTermITE(cond,thn,els); + result.SetIndexWidth(term.GetIndexWidth()); + break; + } + default: { + ASTVec c = term.GetChildren(); + ASTVec::iterator it = c.begin(); + ASTVec::iterator itend = c.end(); + unsigned width = term.GetValueWidth(); + unsigned indexwidth = term.GetIndexWidth(); + ASTVec o; + for(;it!=itend;it++) { + o.push_back(TransformTerm(*it)); + } + + result = CreateTerm(k,width,o); + result.SetIndexWidth(indexwidth); + + if(SBVDIV == result.GetKind() || SBVMOD == result.GetKind()) { + result = TranslateSignedDivMod(result); + } + break; + } + } + + TransformMap[term] = result; + if(term.GetValueWidth() != result.GetValueWidth()) + FatalError("TransformTerm: result and input terms are of different length", result); + if(term.GetIndexWidth() != result.GetIndexWidth()) { + cerr << "TransformTerm: input term is : " << term << endl; + FatalError("TransformTerm: result and input terms have different index length", result); + } + return result; + } //End of TransformTerm + + /* This function transforms Array Reads, Read over Writes, Read over + * ITEs into flattened form. + * + * Transform1: Suppose there are two array reads in the input + * Read(A,i) and Read(A,j) over the same array. Then Read(A,i) is + * replaced with a symbolic constant, say v1, and Read(A,j) is + * replaced with the following ITE: + * + * ITE(i=j,v1,v2) + * + * Transform2: + * + * Transform3: + */ + ASTNode BeevMgr::TransformArray(const ASTNode& term) { + ASTNode result = term; + + unsigned int width = term.GetValueWidth(); + Kind k = term.GetKind(); + if (!is_Term_kind(k)) + FatalError("TransformArray: Illegal kind: You have input a nonterm:", ASTUndefined, k); + ASTNodeMap::iterator iter; + if((iter = TransformMap.find(term)) != TransformMap.end()) + return iter->second; + + switch(k) { + //'term' is of the form READ(arrName, readIndex) + case READ: { + ASTNode arrName = term[0]; + switch (arrName.GetKind()) { + case SYMBOL: { + /* input is of the form: READ(A, readIndex) + * + * output is of the from: A1, if this is the first READ over A + * + * ITE(previous_readIndex=readIndex,A1,A2) + * + * ..... + */ + + // Recursively transform read index, which may also contain reads. + ASTNode readIndex = TransformTerm(term[1]); + ASTNode processedTerm = CreateTerm(READ,width,arrName,readIndex); + + //check if the 'processedTerm' has a corresponding ITE construct + //already. if so, return it. else continue processing. + ASTNodeMap::iterator it; + if((it = _arrayread_ite.find(processedTerm)) != _arrayread_ite.end()) { + result = it->second; + break; + } + //Constructing Symbolic variable corresponding to 'processedTerm' + ASTNode CurrentSymbol; + ASTNodeMap::iterator it1; + // First, check if read index is constant and it has a constant value in the substitution map. + if(CheckSubstitutionMap(processedTerm,CurrentSymbol)) { + _arrayread_symbol[processedTerm] = CurrentSymbol; + } + // Check if it already has an abstract variable. + else if((it1 = _arrayread_symbol.find(processedTerm)) != _arrayread_symbol.end()) { + CurrentSymbol = it1->second; + } + else { + // Make up a new abstract variable. + // FIXME: Make this into a method (there already may BE a method) and + // get rid of the fixed-length buffer! + //build symbolic name corresponding to array read. The symbolic + //name has 2 components: stringname, and a count + const char * b = arrName.GetName(); + std::string c(b); + char d[32]; + sprintf(d,"%d",_symbol_count++); + std::string ccc(d); + c += "array_" + ccc; + + CurrentSymbol = CreateSymbol(c.c_str()); + CurrentSymbol.SetValueWidth(processedTerm.GetValueWidth()); + CurrentSymbol.SetIndexWidth(processedTerm.GetIndexWidth()); + _arrayread_symbol[processedTerm] = CurrentSymbol; + } + + //list of array-read indices corresponding to arrName, seen while + //traversing the AST tree. we need this list to construct the ITEs + // Dill: we hope to make this irrelevant. Harmless for now. + ASTVec readIndices = _arrayname_readindices[arrName]; + + //construct the ITE structure for this array-read + ASTNode ite = CurrentSymbol; + _introduced_symbols.insert(CurrentSymbol); + BVTypeCheck(ite); + + if(arrayread_refinement) { + // ite is really a variable here; it is an ite in the + // else-branch + result = ite; + } + else { + // Full Seshia transform if we're not doing read refinement. + //do not loop if the current readIndex is a BVCONST + // if(BVCONST == term[1].GetKind() && !SeenNonConstReadIndex && optimize) { + // result = ite; + // } + // else { + //else part: SET the SeenNonConstReadIndex var, and do the hard work + //SeenNonConstReadIndex = true; + ASTVec::reverse_iterator it2=readIndices.rbegin(); + ASTVec::reverse_iterator it2end=readIndices.rend(); + for(;it2!=it2end;it2++) { + ASTNode cond = CreateSimplifiedEQ(readIndex,*it2); + if(ASTFalse == cond) + continue; + + ASTNode arrRead = CreateTerm(READ,width,arrName,*it2); + //Good idea to TypeCheck internally constructed nodes + BVTypeCheck(arrRead); + + ASTNode arrayreadSymbol = _arrayread_symbol[arrRead]; + if(arrayreadSymbol.IsNull()) + FatalError("TransformArray:symbolic variable for processedTerm, p," + "does not exist:p = ",arrRead); + ite = CreateSimplifiedTermITE(cond,arrayreadSymbol,ite); + } + result = ite; + //} + } + + _arrayname_readindices[arrName].push_back(readIndex); + //save the ite corresponding to 'processedTerm' + _arrayread_ite[processedTerm] = result; + break; + } //end of READ over a SYMBOL + case WRITE:{ + /* The input to this case is: READ((WRITE A i val) j) + * + * The output of this case is: ITE( (= i j) val (READ A i)) + */ + + /* 1. arrName or term[0] is infact a WRITE(A,i,val) expression + * + * 2. term[1] is the read-index j + * + * 3. arrName[0] is the new arrName i.e. A. A can be either a + SYMBOL or a nested WRITE. no other possibility + * + * 4. arrName[1] is the WRITE index i.e. i + * + * 5. arrName[2] is the WRITE value i.e. val (val can inturn + * be an array read) + */ + ASTNode readIndex = TransformTerm(term[1]); + ASTNode writeIndex = TransformTerm(arrName[1]); + ASTNode writeVal = TransformTerm(arrName[2]); + + if(!(SYMBOL == arrName[0].GetKind() || + WRITE == arrName[0].GetKind())) + FatalError("TransformArray: An array write is being attempted on a non-array:",term); + if(ARRAY_TYPE != arrName[0].GetType()) + FatalError("TransformArray: An array write is being attempted on a non-array:",term); + + ASTNode cond = CreateSimplifiedEQ(writeIndex,readIndex); + //TypeCheck internally created node + BVTypeCheck(cond); + ASTNode readTerm = CreateTerm(READ,width,arrName[0],readIndex); + //TypeCheck internally created node + BVTypeCheck(readTerm); + ASTNode readPushedIn = TransformArray(readTerm); + //TypeCheck internally created node + BVTypeCheck(readPushedIn); + //result = CreateTerm(ITE, arrName[0].GetValueWidth(),cond,writeVal,readPushedIn); + result = CreateSimplifiedTermITE(cond,writeVal,readPushedIn); + + //Good idea to typecheck terms created inside the system + BVTypeCheck(result); + break; + } //end of READ over a WRITE + case ITE: { + /* READ((ITE cond thn els) j) + * + * is transformed into + * + * (ITE cond (READ thn j) (READ els j)) + */ + + //(ITE cond thn els) + ASTNode term0 = term[0]; + //READINDEX j + ASTNode j = TransformTerm(term[1]); + + ASTNode cond = term0[0]; + //first array + ASTNode t01 = term0[1]; + //second array + ASTNode t02 = term0[2]; + + cond = TransformFormula(cond); + ASTNode thn = TransformTerm(t01); + ASTNode els = TransformTerm(t02); + + if(!(t01.GetValueWidth() == t02.GetValueWidth() && + t01.GetValueWidth() == thn.GetValueWidth() && + t01.GetValueWidth() == els.GetValueWidth())) + FatalError("TransformArray: length of THENbranch != length of ELSEbranch in the term t = \n",term); + + if(!(t01.GetIndexWidth() == t02.GetIndexWidth() && + t01.GetIndexWidth() == thn.GetIndexWidth() && + t01.GetIndexWidth() == els.GetIndexWidth())) + FatalError("TransformArray: length of THENbranch != length of ELSEbranch in the term t = \n",term); + + //(READ thn j) + ASTNode thnRead = CreateTerm(READ,width,thn,j); + BVTypeCheck(thnRead); + thnRead = TransformArray(thnRead); + + //(READ els j) + ASTNode elsRead = CreateTerm(READ,width,els,j); + BVTypeCheck(elsRead); + elsRead = TransformArray(elsRead); + + //(ITE cond (READ thn j) (READ els j)) + result = CreateSimplifiedTermITE(cond,thnRead,elsRead); + BVTypeCheck(result); + break; + } + default: + FatalError("TransformArray: The READ is NOT over SYMBOL/WRITE/ITE",term); + break; + } + break; + } //end of READ switch + default: + FatalError("TransformArray: input term is of wrong kind: ",ASTUndefined); + break; + } + + TransformMap[term] = result; + return result; + } //end of TransformArray() +} //end of namespace BEEV diff --git a/stp/AST/asttest.cpp b/stp/AST/asttest.cpp new file mode 100644 index 00000000..57f3d20c --- /dev/null +++ b/stp/AST/asttest.cpp @@ -0,0 +1,29 @@ +#include "AST.h" + +using namespace BEEV; + +int main() +{ + + BeevMgr * bm = new BeevMgr(); + ASTNode s1 = bm->CreateSymbol("foo"); + s1 = bm->CreateSymbol("foo1"); + s1 = bm->CreateSymbol("foo2"); + ASTNode s2 = bm->CreateSymbol("bar"); + cout << "s1" << s1 << endl; + cout << "s2" << s2 << endl; + + ASTNode b1 = bm->CreateBVConst(5,12); + ASTNode b2 = bm->CreateBVConst(6,36); + cout << "b1: " << b1 << endl; + cout << "b2: " << b2 << endl; + + ASTNode a1 = bm->CreateNode(EQ, s1, s2); + ASTNode a2 = bm->CreateNode(AND, s1, s2); + a1 = bm->CreateNode(OR, s1, s2); + ASTNode a3 = bm->CreateNode(IMPLIES, a1, a2); + ASTNode a4 = bm->CreateNode(IMPLIES, s1, a2); + cout << "a3" << a3 << endl; + cout << "a4" << a4 << endl; + return 0; +} diff --git a/stp/AST/bbtest.cpp b/stp/AST/bbtest.cpp new file mode 100644 index 00000000..83aa6a4e --- /dev/null +++ b/stp/AST/bbtest.cpp @@ -0,0 +1,96 @@ +#include "AST.h" + +using namespace BEEV; + +int main() +{ + const int size = 32; + + BeevMgr *bm = new BeevMgr(); + ASTNode s1 = bm->CreateSymbol("x"); + s1.SetValueWidth(size); + cout << "s1" << s1 << endl; + ASTNode s2 = bm->CreateSymbol("y"); + s2.SetValueWidth(size); + cout << "s2" << s2 << endl; + ASTNode s3 = bm->CreateSymbol("z"); + s3.SetValueWidth(size); + cout << "s3" << s3 << endl; + + ASTNode c1 = bm->CreateBVConst(size,0); + cout << "c1" << c1 << endl; + ASTVec bbc1 = bm->BBTerm(c1); + cout << "bitblasted c1 " << endl; + LispPrintVec(cout, bbc1, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode c2 = bm->CreateBVConst(size,1); + c2.SetValueWidth(size); + cout << "c2" << c2 << endl; + ASTVec bbc2 = bm->BBTerm(c2); + cout << "bitblasted c2 " << endl; + LispPrintVec(cout, bbc2, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode c3 = bm->CreateBVConst(size, 0xFFFFFFFF); + c3.SetValueWidth(size); + cout << "c3" << c3 << endl; + ASTVec bbc3 = bm->BBTerm(c3); + cout << "bitblasted c3 " << endl; + LispPrintVec(cout, bbc3, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode c4 = bm->CreateBVConst(size, 0xAAAAAAAA); + c4.SetValueWidth(size); + cout << "c4" << c4 << endl; + ASTVec bbc4 = bm->BBTerm(c4); + cout << "bitblasted c4 " << endl; + LispPrintVec(cout, bbc4, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + +// ASTNode b1 = bm->CreateBVConst(12); +// ASTNode b2 = bm->CreateBVConst(36); +// cout << "b1: " << b1 << endl; +// cout << "b2: " << b2 << endl; + + ASTNode a1 = bm->CreateNode(BVPLUS, s1, s2); + a1.SetValueWidth(size); + + ASTVec& bba1 = bm->BBTerm(a1); + cout << "bitblasted a1 " << endl; + LispPrintVec(cout, bba1, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode a2 = bm->CreateNode(BVPLUS, s1, s2, s3); + a1.SetValueWidth(2); + + ASTVec& bba2 = bm->BBTerm(a2); + cout << "bitblasted a2 " << endl; + LispPrintVec(cout, bba2, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode a3 = bm->CreateNode(BVXOR, s1, s2); + a3.SetValueWidth(2); + + ASTVec& bba3 = bm->BBTerm(a3); + cout << "bitblasted a3 " << endl; + LispPrintVec(cout, bba3, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode a4 = bm->CreateNode(EQ, s1, s2); + ASTNode bba4 = bm->BBForm(a4); + cout << "bitblasted a4 " << endl << bba4 << endl; + + ASTNode a5 = bm->CreateNode(BVLE, s1, s2); + ASTNode bba5 = bm->BBForm(a5); + cout << "bitblasted a5 " << endl << bba5 << endl; + + return 0; +} diff --git a/stp/AST/cnftest.cpp b/stp/AST/cnftest.cpp new file mode 100644 index 00000000..7ce270c8 --- /dev/null +++ b/stp/AST/cnftest.cpp @@ -0,0 +1,47 @@ +// -*- c++ -*- + +// Test program for CNF conversion. + +#include "AST.h" + +using namespace BEEV; + +int main() +{ + const int size = 1; + + BeevMgr *bm = new BeevMgr(); + ASTNode s1 = bm->CreateSymbol("x"); + s1.SetValueWidth(size); + + cout << "s1" << s1 << endl; + ASTNode s2 = bm->CreateSymbol("y"); + s2.SetValueWidth(size); + + cout << "s2" << s2 << endl; + ASTNode s3 = bm->CreateSymbol("z"); + s3.SetValueWidth(size); + + cout << "s3" << s3 << endl; + + ASTNode bbs1 = bm->BBForm(s1); + cout << "bitblasted s1" << endl << bbs1 << endl; + bm->PrintClauseList(cout, bm->ToCNF(bbs1)); + + ASTNode a2 = bm->CreateNode(AND, s1, s2); + ASTNode bba2 = bm->BBForm(a2); + cout << "bitblasted a2" << endl << bba2 << endl; + bm->PrintClauseList(cout, bm->ToCNF(bba2)); + + ASTNode a3 = bm->CreateNode(OR, s1, s2); + ASTNode bba3 = bm->BBForm(a3); + cout << "bitblasted a3" << endl << bba3 << endl; + bm->PrintClauseList(cout, bm->ToCNF(bba3)); + + ASTNode a4 = bm->CreateNode(EQ, s1, s2); + ASTNode bba4 = bm->BBForm(a4); + cout << "bitblasted a4 " << endl << bba4 << endl; + + bm->PrintClauseList(cout, bm->ToCNF(bba4)); + +} diff --git a/stp/AST/genkinds.pl b/stp/AST/genkinds.pl new file mode 100755 index 00000000..7944832b --- /dev/null +++ b/stp/AST/genkinds.pl @@ -0,0 +1,123 @@ +#!/usr/bin/perl -w + +#AUTHORS: Vijay Ganesh, David L. Dill BEGIN DATE: November, 2005 +#LICENSE: Please view LICENSE file in the home dir of this Program +#given a file containing kind names, one per line produces .h and .cpp +#files for the kinds. + +#globals +@kindnames = (); +$minkids = 0; +$maxkids = 0; +@cat_bits = (); +@category_names = (); +%cat_index = (); + +$now = localtime time; + +sub read_kind_defs { + open(KFILE, "< ASTKind.kinds") || die "Cannot open .kinds file: $!\n"; + @kindlines = <KFILE>; + close(KFILE) +} + +# create lists of things indexed by kinds. +sub split_fields { + my $kind_cat_bits; + # matches anything with three whitespace-delimited alphanumeric fields, + # followed by rest of line. Automatically ignores lines beginning with '#' and blank lines. + for (@kindlines) { + if (/Categories:\s+(.*)/) { + @category_names = split(/\s+/, $1); + $i = 0; + for (@category_names) { + $cat_index{$_} = $i++; + # print "cat_index{$_} = $i\n"; + } + } + elsif (/^(\w+)\s+(\w+)\s+(\w+|-)\s+(.*)/) { + push(@kindnames, $1); + push(@minkids, $2); + push(@maxkids, $3); + @kind_cats = split(/\s+/, $4); + # build a bit vector of categories. + $kind_cat_bits = 0; + for (@kind_cats) { + $kind_cat_bits |= (1 << int($cat_index{$_})); + } + push(@cat_bits, $kind_cat_bits); + } + } +} + +sub gen_h_file { + open(HFILE, "> ASTKind.h") || die "Cannot open .h file: $!\n"; + + print HFILE + "// -*- c++ -*-\n", + "#ifndef TESTKINDS_H\n", + "#define TESTKINDS_H\n", + "// Generated automatically by genkinds.pl from ASTKind.kinds $now.\n", + "// Do not edit\n", + "namespace BEEV {\n typedef enum {\n"; + + for (@kindnames) { + print HFILE " $_,\n"; + } + + print HFILE + "} Kind;\n\n", + "extern unsigned char _kind_categories[];\n\n"; + + # For category named "cat", generate functions "bool is_cat_kind(k);" + + + for (@category_names) { + my $catname = $_; + my $kind_cat_bit = (1 << int($cat_index{$catname})); + print HFILE "inline bool is_", $catname, "_kind(Kind k) { return (_kind_categories[k] & $kind_cat_bit); }\n\n" + } + + print HFILE + "extern const char *_kind_names[];\n\n", + "/** Prints symbolic name of kind */\n", + "inline ostream& operator<<(ostream &os, const Kind &kind) { os << _kind_names[kind]; return os; }\n", + "\n\n", + "}; // end namespace\n", + "\n\n#endif\n"; + + close(HFILE); +} + +# generate the .cpp file + +sub gen_cpp_file { + open(CPPFILE, "> ASTKind.cpp") || die "Cannot open .h file: $!\n"; + + print CPPFILE + "// Generated automatically by genkinds.h from ASTKind.kinds $now.\n", + "// Do not edit\n", + "namespace BEEV {\n", + "const char * _kind_names[] = {\n"; + for (@kindnames) { + print CPPFILE " \"$_\",\n"; + } + print CPPFILE "};\n\n"; + + # category bits + print CPPFILE + "unsigned char _kind_categories[] = {\n"; + for (@cat_bits) { + print CPPFILE " $_,\n"; + } + print CPPFILE + "};\n", + "\n}; // end namespace\n"; + + close(CPPFILE); +} + +&read_kind_defs; +&split_fields; +&gen_h_file; +&gen_cpp_file; diff --git a/stp/INSTALL b/stp/INSTALL new file mode 100644 index 00000000..12cee121 --- /dev/null +++ b/stp/INSTALL @@ -0,0 +1,10 @@ +1. To install STP perform the following steps on your Unix/GNU-Linux/MacOS X commandline: + +./configure --with-prefix=$HOME (or another installation directory) +make clean +make +make install + +2. To test the system after installation: + +make regressall \ No newline at end of file diff --git a/stp/LICENSE b/stp/LICENSE new file mode 100644 index 00000000..41029509 --- /dev/null +++ b/stp/LICENSE @@ -0,0 +1,17 @@ +/*****************************************************************************/ +/* AUTHORS: Vijay Ganesh, David L. Dill DATE: Nov 2005 */ +/*****************************************************************************/ +/* Copyright (C) 2005 by the Board of Trustees of Leland Stanford */ +/* Junior University. */ +/* */ +/* License to use, copy, modify, sell and/or distribute this software */ +/* and its documentation for any purpose is hereby granted without */ +/* royalty, subject to the terms and conditions defined in the \ref */ +/* LICENSE file provided with this distribution. In particular: */ +/* */ +/* - The above copyright notice and this permission notice must appear */ +/* in all copies of the software and related documentation. */ +/* */ +/* - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES, */ +/* EXPRESSED OR IMPLIED. USE IT AT YOUR OWN RISK. */ +/*****************************************************************************/ diff --git a/stp/Makefile b/stp/Makefile new file mode 100644 index 00000000..f66644a5 --- /dev/null +++ b/stp/Makefile @@ -0,0 +1,64 @@ + # STP (Simple Theorem Prover) top level makefile + # + # To make in debug mode, type 'make "CLFAGS=-ggdb" + # To make in optimized mode, type 'make "CFLAGS=-O2" + +include Makefile.common + +BINARIES=bin/stp +LIBS=AST/libast.a sat/libsatsolver.a simplifier/libsimplifier.a bitvec/libconsteval.a constantbv/libconstantbv.a c_interface/libcinterface.a +DIRS=AST sat simplifier bitvec c_interface constantbv parser + +# NB: the TAGS target is a hack to get around this recursive make nonsense +# we want all the source and header files generated before we make tags +.PHONY: all +all: lib/libstp.a bin/stp include/stp/c_interface.h + +AST/libast.a: + @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@` +sat/libsatsolver.a: AST/libast.a + @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@` +simplifier/libsimplifier.a: AST/libast.a + @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@` +bitvec/libconsteval.a: AST/libast.a + @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@` +constantbv/libconstantbv.a: AST/libast.a + @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@` +c_interface/libcinterface.a: AST/libast.a + @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@` +parser/parser: $(LIBS) + @$(MAKE) -q -C `dirname $@` || $(MAKE) -C `dirname $@` + +lib/libstp.a: parser/parser $(LIBS) + @mkdir -p lib + rm -f $@ + @for dir in $(DIRS); do \ + $(AR) rc $@ $$dir/*.o; \ + done + $(RANLIB) $@ + +bin/stp: parser/parser $(LIBS) + @mkdir -p bin + @cp parser/parser $@ + +include/stp/c_interface.h: $(LIBS) + @mkdir -p include/stp + @cp c_interface/c_interface.h $@ + +.PHONY: clean +clean: + rm -rf *~ + rm -rf *.a + rm -rf lib/*.a + rm -rf bin/*~ + rm -rf bin/stp + rm -rf *.log + rm -f TAGS + $(MAKE) clean -C AST + $(MAKE) clean -C sat + $(MAKE) clean -C simplifier + $(MAKE) clean -C bitvec + $(MAKE) clean -C parser + $(MAKE) clean -C c_interface + $(MAKE) clean -C constantbv + diff --git a/stp/Makefile.common.in b/stp/Makefile.common.in new file mode 100644 index 00000000..a88e35ed --- /dev/null +++ b/stp/Makefile.common.in @@ -0,0 +1,16 @@ +# -*- Makefile -*- + +CFLAGS := @CFLAGS@ +CXXFLAGS := @CXXFLAGS@ -O2 +LDFLAGS := @LDFLAGS@ -lstdc++ + +# use the darmin test as a proxy for detecting Mac OS X +ifneq ($(shell uname -s), Darwin) + CFLAGS += -static +endif + +CXXFLAGS += -Wall -DEXT_HASH_MAP + +LEX := flex +YACC := bison -d -y --debug -v +RANLIB := ranlib diff --git a/stp/README b/stp/README new file mode 100644 index 00000000..da0f9b96 --- /dev/null +++ b/stp/README @@ -0,0 +1,26 @@ +/******************************************************************** + * PROGRAM NAME: STP (Simple Theorem Prover) + * + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ + +Install +------- +See INSTALL file in the home dir of this program + +Authors +------- +Vijay Ganesh, Stanford University, Stanford, CA, USA +David L. Dill, Stanford University, Stanford, CA, USA +Tim King, Stanford University, Stanford, CA, USA + +Makefiles and configuration scripts +------------------------------------ +Cristian Cadar, Stanford University, Stanford, CA, USA +Paul Twohey, Stanford University, Stanford, CA, USA +Sergey Berezin, ATG Synopsys, Mountain View, CA, USA +Clark Barrett, New York University, New York, NY, USA diff --git a/stp/bitvec/Makefile b/stp/bitvec/Makefile new file mode 100644 index 00000000..eb6e1121 --- /dev/null +++ b/stp/bitvec/Makefile @@ -0,0 +1,11 @@ +include ../Makefile.common + +SRCS = consteval.cpp +OBJS = $(SRCS:.cpp=.o) + +libconsteval.a: $(OBJS) + $(AR) rc $@ $^ + $(RANLIB) $@ + +clean: + rm -rf *.o *~ *.a .#* diff --git a/stp/bitvec/consteval.cpp b/stp/bitvec/consteval.cpp new file mode 100644 index 00000000..7cb8dfcb --- /dev/null +++ b/stp/bitvec/consteval.cpp @@ -0,0 +1,1044 @@ +/******************************************************************** + * 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/AST.h" +#include "../AST/ASTUtil.h" +namespace BEEV { + + //error printing + static void BVConstEvaluatorError(CONSTANTBV::ErrCode e, const ASTNode& t){ + std::string ss("BVConstEvaluator:"); + ss += (const char*)BitVector_Error(e); + FatalError(ss.c_str(), t); + } + +#ifndef NATIVE_C_ARITH + ASTNode BeevMgr::BVConstEvaluator(const ASTNode& t) { + ASTNode OutputNode; + Kind k = t.GetKind(); + + if(CheckSolverMap(t,OutputNode)) + return OutputNode; + OutputNode = t; + + unsigned int inputwidth = t.GetValueWidth(); + unsigned int outputwidth = inputwidth; + CBV output = NULL; + + CBV tmp0 = NULL; + CBV tmp1 = NULL; + + //saving some typing. BVPLUS does not use these variables. if the + //input BVPLUS has two nodes, then we want to avoid setting these + //variables. + if(1 == t.Degree() ){ + tmp0 = BVConstEvaluator(t[0]).GetBVConst(); + }else if(2 == t.Degree() && k != BVPLUS ) { + tmp0 = BVConstEvaluator(t[0]).GetBVConst(); + tmp1 = BVConstEvaluator(t[1]).GetBVConst(); + } + + switch(k) { + case UNDEFINED: + case READ: + case WRITE: + case SYMBOL: + FatalError("BVConstEvaluator: term is not a constant-term",t); + break; + case BVCONST: + //FIXME Handle this special case better + OutputNode = t; + break; + case BVNEG:{ + output = CONSTANTBV::BitVector_Create(inputwidth,true); + CONSTANTBV::Set_Complement(output,tmp0); + OutputNode = CreateBVConst(output,outputwidth); + break; + } + case BVSX: { + output = CONSTANTBV::BitVector_Create(inputwidth,true); + //unsigned * out0 = BVConstEvaluator(t[0]).GetBVConst(); + unsigned t0_width = t[0].GetValueWidth(); + if(inputwidth == t0_width) { + CONSTANTBV::BitVector_Copy(output, tmp0); + OutputNode = CreateBVConst(output, outputwidth); + } + else { + bool topbit_sign = (CONSTANTBV::BitVector_Sign(tmp0) < 0 ); + + if(topbit_sign){ + CONSTANTBV::BitVector_Fill(output); + } + CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, 0, t0_width); + OutputNode = CreateBVConst(output, outputwidth); + } + break; + } + case BVAND: { + output = CONSTANTBV::BitVector_Create(inputwidth,true); + CONSTANTBV::Set_Intersection(output,tmp0,tmp1); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVOR: { + output = CONSTANTBV::BitVector_Create(inputwidth,true); + CONSTANTBV::Set_Union(output,tmp0,tmp1); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVXOR: { + output = CONSTANTBV::BitVector_Create(inputwidth,true); + CONSTANTBV::Set_ExclusiveOr(output,tmp0,tmp1); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVSUB: { + output = CONSTANTBV::BitVector_Create(inputwidth,true); + bool carry = false; + CONSTANTBV::BitVector_sub(output,tmp0,tmp1,&carry); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVUMINUS: { + output = CONSTANTBV::BitVector_Create(inputwidth,true); + CONSTANTBV::BitVector_Negate(output, tmp0); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVEXTRACT: { + output = CONSTANTBV::BitVector_Create(inputwidth,true); + tmp0 = BVConstEvaluator(t[0]).GetBVConst(); + unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1])); + unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2])); + unsigned int len = hi-low+1; + + CONSTANTBV::BitVector_Destroy(output); + output = CONSTANTBV::BitVector_Create(len, false); + CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, low, len); + outputwidth = len; + OutputNode = CreateBVConst(output, outputwidth); + break; + } + //FIXME Only 2 inputs? + case BVCONCAT: { + output = CONSTANTBV::BitVector_Create(inputwidth,true); + unsigned t0_width = t[0].GetValueWidth(); + unsigned t1_width = t[1].GetValueWidth(); + CONSTANTBV::BitVector_Destroy(output); + + output = CONSTANTBV::BitVector_Concat(tmp0, tmp1); + outputwidth = t0_width + t1_width; + OutputNode = CreateBVConst(output, outputwidth); + + break; + } + case BVMULT: { + output = CONSTANTBV::BitVector_Create(inputwidth,true); + CBV tmp = CONSTANTBV::BitVector_Create(2*inputwidth,true); + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Multiply(tmp,tmp0,tmp1); + + if(0 != e) { + BVConstEvaluatorError(e,t); + } + //FIXME WHAT IS MY OUTPUT???? THE SECOND HALF of tmp? + //CONSTANTBV::BitVector_Interval_Copy(output, tmp, 0, inputwidth, inputwidth); + CONSTANTBV::BitVector_Interval_Copy(output, tmp, 0, 0, inputwidth); + OutputNode = CreateBVConst(output, outputwidth); + CONSTANTBV::BitVector_Destroy(tmp); + break; + } + case BVPLUS: { + output = CONSTANTBV::BitVector_Create(inputwidth,true); + bool carry = false; + ASTVec c = t.GetChildren(); + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + CBV kk = BVConstEvaluator(*it).GetBVConst(); + CONSTANTBV::BitVector_add(output,output,kk,&carry); + carry = false; + //CONSTANTBV::BitVector_Destroy(kk); + } + OutputNode = CreateBVConst(output, outputwidth); + break; + } + //FIXME ANOTHER SPECIAL CASE + case SBVDIV: + case SBVMOD:{ + OutputNode = BVConstEvaluator(TranslateSignedDivMod(t)); + break; + } + case BVDIV: + case BVMOD: { + CBV quotient = CONSTANTBV::BitVector_Create(inputwidth,true); + CBV remainder = CONSTANTBV::BitVector_Create(inputwidth,true); + + // tmp0 is dividend, tmp1 is the divisor + //All parameters to BitVector_Div_Pos must be distinct unlike BitVector_Divide + //FIXME the contents of the second parameter to Div_Pos is destroyed + //As tmp0 is currently the same as the copy belonging to an ASTNode t[0] + //this must be copied. + tmp0 = CONSTANTBV::BitVector_Clone(tmp0); + CONSTANTBV::ErrCode e= CONSTANTBV::BitVector_Div_Pos(quotient,tmp0,tmp1,remainder); + CONSTANTBV::BitVector_Destroy(tmp0); + + if(0 != e) { + //error printing + if(counterexample_checking_during_refinement) { + output = CONSTANTBV::BitVector_Create(inputwidth,true); + OutputNode = CreateBVConst(output, outputwidth); + bvdiv_exception_occured = true; + + // CONSTANTBV::BitVector_Destroy(output); + break; + } + else { + BVConstEvaluatorError(e,t); + } + } //end of error printing + + //FIXME Not very standard in the current scheme + if(BVDIV == k){ + OutputNode = CreateBVConst(quotient, outputwidth); + CONSTANTBV::BitVector_Destroy(remainder); + }else{ + OutputNode = CreateBVConst(remainder, outputwidth); + CONSTANTBV::BitVector_Destroy(quotient); + } + + break; + } + case ITE: + if(ASTTrue == t[0]) + OutputNode = BVConstEvaluator(t[1]); + else if(ASTFalse == t[0]) + OutputNode = BVConstEvaluator(t[2]); + else + FatalError("BVConstEvaluator: ITE condiional must be either TRUE or FALSE:",t); + break; + case EQ: + if(CONSTANTBV::BitVector_equal(tmp0,tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case NEQ: + if(!CONSTANTBV::BitVector_equal(tmp0,tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVLT: + if(-1 == CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVLE: { + int comp = CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1); + if(comp <= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVGT: + if(1 == CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVGE: { + int comp = CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1); + if(comp >= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSLT: + if(-1 == CONSTANTBV::BitVector_Compare(tmp0,tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVSLE: { + signed int comp = CONSTANTBV::BitVector_Compare(tmp0,tmp1); + if(comp <= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSGT: + if(1 == CONSTANTBV::BitVector_Compare(tmp0,tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVSGE: { + int comp = CONSTANTBV::BitVector_Compare(tmp0,tmp1); + if(comp >= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + default: + FatalError("BVConstEvaluator: The input kind is not supported yet:",t); + break; + } +/* + if(BVCONST != k){ + cerr<<inputwidth<<endl; + cerr<<"------------------------"<<endl; + t.LispPrint(cerr); + cerr<<endl; + OutputNode.LispPrint(cerr); + cerr<<endl<<"------------------------"<<endl; + } +*/ + UpdateSolverMap(t,OutputNode); + //UpdateSimplifyMap(t,OutputNode,false); + return OutputNode; + } +#else + //accepts 64 bit BVConst and sign extends it + static unsigned long long int SXBVConst64(const ASTNode& t) { + unsigned long long int c = t.GetBVConst(); + unsigned int len = t.GetValueWidth(); + + unsigned long long int mask = 1; + mask = mask << len-1; + + bool TopBit = (c & mask) ? true : false; + if(!TopBit) return c; + + unsigned long long int sign = 0xffffffffffffffffLL; + sign = sign << len-1; + + return (c | sign); + } + + //FIXME: Ideally I would like the ASTNodes to be able to operate on + //themselves (add, sub, concat, etc.) rather than doing a + //GetBVConst() and then do the operation externally. For now, + //this is the fastest path to completion. + ASTNode BeevMgr::BVConstEvaluator(const ASTNode& t) { + //cerr << "inside begin bcconstevaluator: " << t << endl; + + ASTNode OutputNode; + if(CheckSolverMap(t,OutputNode)) + return OutputNode; + OutputNode = ASTUndefined; + + Kind k = t.GetKind(); + unsigned long long int output = 0; + unsigned inputwidth = t.GetValueWidth(); + ASTNode t0 = ASTUndefined; + ASTNode t1 = ASTUndefined; + if(2 == t.Degree()) { + t0 = BVConstEvaluator(t[0]); + t1 = BVConstEvaluator(t[1]); + } + switch(k) { + case READ: + case UNDEFINED: + case WRITE: + case SYMBOL: + cerr << t; + FatalError("BVConstEvaluator: term is not a constant-term",t); + break; + case BVCONST: + return t; + break; + case BVNEG: + //compute bitwise negation in C + output = ~(BVConstEvaluator(t[0]).GetBVConst()); + break; + case BVSX: + output = SXBVConst64(BVConstEvaluator(t[0])); + break; + case BVAND: + output = t0.GetBVConst() & t1.GetBVConst(); + break; + case BVOR: + output = t0.GetBVConst() | t1.GetBVConst(); + break; + case BVXOR: + output = t0.GetBVConst() ^ t1.GetBVConst(); + break; + case BVSUB: + output = t0.GetBVConst() - t1.GetBVConst(); + break; + case BVUMINUS: + output = ~(BVConstEvaluator(t[0]).GetBVConst()) + 1; + break; + case BVEXTRACT: { + unsigned long long int val = BVConstEvaluator(t[0]).GetBVConst(); + unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1])); + unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2])); + + if(!(0 <= hi <= 64)) + FatalError("ConstantEvaluator: hi bit in BVEXTRACT is > 32bits",t); + if(!(0 <= low <= hi <= 64)) + FatalError("ConstantEvaluator: low bit in BVEXTRACT is > 32bits or hi",t); + + //64 bit mask. + unsigned long long int mask1 = 0xffffffffffffffffLL; + mask1 >>= 64-(hi+1); + + //extract val[hi:0] + val &= mask1; + //extract val[hi:low] + val >>= low; + output = val; + break; + } + case BVCONCAT: { + unsigned long long int q = BVConstEvaluator(t0).GetBVConst(); + unsigned long long int r = BVConstEvaluator(t1).GetBVConst(); + + unsigned int qlen = t[0].GetValueWidth(); + unsigned int rlen = t[1].GetValueWidth(); + unsigned int slen = t.GetValueWidth(); + if(!(0 < qlen + rlen <= 64)) + FatalError("BVConstEvaluator:" + "lengths of childnodes of BVCONCAT are > 64:",t); + + //64 bit mask for q + unsigned long long int qmask = 0xffffffffffffffffLL; + qmask >>= 64-qlen; + //zero the useless bits of q + q &= qmask; + + //64 bit mask for r + unsigned long long int rmask = 0xffffffffffffffffLL; + rmask >>= 64-rlen; + //zero the useless bits of r + r &= rmask; + + //concatenate + q <<= rlen; + q |= r; + + //64 bit mask for output s + unsigned long long int smask = 0xffffffffffffffffLL; + smask >>= 64-slen; + + //currently q has the output + output = q; + output &= smask; + break; + } + case BVMULT: { + output = t0.GetBVConst() * t1.GetBVConst(); + + //64 bit mask + unsigned long long int mask = 0xffffffffffffffffLL; + mask = mask >> (64 - inputwidth); + output &= mask; + break; + } + case BVPLUS: { + ASTVec c = t.GetChildren(); + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) + output += BVConstEvaluator(*it).GetBVConst(); + + //64 bit mask + unsigned long long int mask = 0xffffffffffffffffLL; + mask = mask >> (64 -inputwidth); + output &= mask; + break; + } + case SBVDIV: + case SBVMOD: { + output = BVConstEvaluator(TranslateSignedDivMod(t)).GetBVConst(); + break; + } + case BVDIV: { + if(0 == t1.GetBVConst()) { + //if denominator is 0 then + // (if refinement is ON then output is set to 0) + // (else produce a fatal error) + if(counterexample_checking_during_refinement) { + output = 0; + bvdiv_exception_occured = true; + break; + } + else { + FatalError("BVConstEvaluator: divide by zero not allowed:",t); + } + } + + output = t0.GetBVConst() / t1.GetBVConst(); + //64 bit mask + unsigned long long int mask = 0xffffffffffffffffLL; + mask = mask >> (64 - inputwidth); + output &= mask; + break; + } + case BVMOD: { + if(0 == t1.GetBVConst()) { + //if denominator is 0 then + // (if refinement is ON then output is set to 0) + // (else produce a fatal error) + if(counterexample_checking_during_refinement) { + output = 0; + bvdiv_exception_occured = true; + break; + } + else { + FatalError("BVConstEvaluator: divide by zero not allowed:",t); + } + } + + output = t0.GetBVConst() % t1.GetBVConst(); + //64 bit mask + unsigned long long int mask = 0xffffffffffffffffLL; + mask = mask >> (64 - inputwidth); + output &= mask; + break; + } + case ITE: + if(ASTTrue == t[0]) + OutputNode = BVConstEvaluator(t[1]); + else if(ASTFalse == t[0]) + OutputNode = BVConstEvaluator(t[2]); + else + FatalError("BVConstEvaluator:" + "ITE condiional must be either TRUE or FALSE:",t); + break; + case EQ: + if(t0.GetBVConst() == t1.GetBVConst()) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case NEQ: + if(t0.GetBVConst() != t1.GetBVConst()) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + break; + case BVLT: { + unsigned long long n0 = t0.GetBVConst(); + unsigned long long n1 = t1.GetBVConst(); + if(n0 < n1) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVLE: + if(t0.GetBVConst() <= t1.GetBVConst()) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVGT: + if(t0.GetBVConst() > t1.GetBVConst()) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVGE: + if(t0.GetBVConst() >= t1.GetBVConst()) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVSLT: { + signed long long int n0 = SXBVConst64(t0); + signed long long int n1 = SXBVConst64(t1); + if(n0 < n1) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSLE: { + signed long long int n0 = SXBVConst64(t0); + signed long long int n1 = SXBVConst64(t1); + if(n0 <= n1) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSGT: { + signed long long int n0 = SXBVConst64(t0); + signed long long int n1 = SXBVConst64(t1); + if(n0 > n1) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSGE: { + signed long long int n0 = SXBVConst64(t0); + signed long long int n1 = SXBVConst64(t1); + if(n0 >= n1) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + default: + FatalError("BVConstEvaluator: The input kind is not supported yet:",t); + break; + } + + if(ASTTrue != OutputNode && ASTFalse != OutputNode) + OutputNode = CreateBVConst(inputwidth, output); + UpdateSolverMap(t,OutputNode); + //UpdateSimplifyMap(t,OutputNode,false); + return OutputNode; + } //End of BVConstEvaluator +#endif +//In the block below is the old string based version +//It is included here as an easy reference while the current code is being worked on. + +/* + ASTNode BeevMgr::BVConstEvaluator(const ASTNode& t) { + ASTNode OutputNode; + Kind k = t.GetKind(); + + if(CheckSolverMap(t,OutputNode)) + return OutputNode; + OutputNode = t; + + unsigned int inputwidth = t.GetValueWidth(); + unsigned * output = CONSTANTBV::BitVector_Create(inputwidth,true); + unsigned * One = CONSTANTBV::BitVector_Create(inputwidth,true); + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(One, (unsigned char*)"1"); + //error printing + if(0 != e) { + std::string ss("BVConstEvaluator:"); + ss += (const char*)BitVector_Error(e); + FatalError(ss.c_str(), t); + } + + unsigned * Zero = CONSTANTBV::BitVector_Create(inputwidth,true); + unsigned int * iii = One; + unsigned int * jjj = Zero; + + //saving some typing. BVPLUS does not use these variables. if the + //input BVPLUS has two nodes, then we want to avoid setting these + //variables. + if(2 == t.Degree() && k != BVPLUS && k != BVCONCAT) { + iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); + jjj = ConvertToCONSTANTBV(BVConstEvaluator(t[1]).GetBVConst()); + } + + char * cccc; + switch(k) { + case UNDEFINED: + case READ: + case WRITE: + case SYMBOL: + FatalError("BVConstEvaluator: term is not a constant-term",t); + break; + case BVCONST: + OutputNode = t; + break; + case BVNEG:{ + //AARON + if (iii != One) free(iii); + //AARON + + iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); + CONSTANTBV::Set_Complement(output,iii); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + break; + } + case BVSX: { + unsigned * out0 = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); + unsigned t0_width = t[0].GetValueWidth(); + if(inputwidth == t0_width) { + cccc = (char *)CONSTANTBV::BitVector_to_Bin(out0); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + CONSTANTBV::BitVector_Destroy(out0); + } + else { + // FIXME: (Dill) I'm guessing that BitVector sign returns 1 if the + // number is positive, 0 if 0, and -1 if negative. But I'm only + // guessing. + signed int topbit_sign = (CONSTANTBV::BitVector_Sign(out0) < 0); + //out1 is the sign-extension bits + unsigned * out1 = CONSTANTBV::BitVector_Create(inputwidth-t0_width,true); + if(topbit_sign) + CONSTANTBV::BitVector_Fill(out1); + + //AARON + CONSTANTBV::BitVector_Destroy(output); + //AARON + + output = CONSTANTBV::BitVector_Concat(out1,out0); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + CONSTANTBV::BitVector_Destroy(out0); + CONSTANTBV::BitVector_Destroy(out1); + } + break; + } + case BVAND: { + CONSTANTBV::Set_Intersection(output,iii,jjj); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case BVOR: { + CONSTANTBV::Set_Union(output,iii,jjj); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case BVXOR: { + CONSTANTBV::Set_ExclusiveOr(output,iii,jjj); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case BVSUB: { + bool carry = false; + CONSTANTBV::BitVector_sub(output,iii,jjj,&carry); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case BVUMINUS: { + bool carry = false; + + //AARON + if (iii != One) free(iii); + //AARON + + iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); + CONSTANTBV::Set_Complement(output,iii); + CONSTANTBV::BitVector_add(output,output,One,&carry); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case BVEXTRACT: { + string s(BVConstEvaluator(t[0]).GetBVConst()); + unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1])); + unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2])); + + //length of substr to chop + unsigned int len = hi-low+1; + //distance from MSB + hi = s.size()-1 - hi; + string ss = s.substr(hi,len); + OutputNode = CreateBVConst(ss.c_str(),2); + break; + } + case BVCONCAT: { + string s(BVConstEvaluator(t[0]).GetBVConst()); + string r(BVConstEvaluator(t[1]).GetBVConst()); + + string q(s+r); + OutputNode = CreateBVConst(q.c_str(),2); + break; + } + case BVMULT: { + unsigned * output1 = CONSTANTBV::BitVector_Create(2*inputwidth,true); + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Multiply(output1,iii,jjj); + //error printing + if(0 != e) { + std::string ss("BVConstEvaluator:"); + ss += (const char*)BitVector_Error(e); + //destroy all the CONSTANTBV bitvectors + CONSTANTBV::BitVector_Destroy(iii); + CONSTANTBV::BitVector_Destroy(jjj); + CONSTANTBV::BitVector_Destroy(One); + CONSTANTBV::BitVector_Destroy(Zero); + FatalError(ss.c_str(), t); + } + + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output1); + std::string s(cccc); + + //AARON + free(cccc); + //AARON + + s = s.substr(inputwidth,inputwidth); + OutputNode = CreateBVConst(s.c_str(),2); + CONSTANTBV::BitVector_Destroy(output1); + break; + } + case BVPLUS: { + bool carry = false; + ASTVec c = t.GetChildren(); + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + unsigned int * kk = ConvertToCONSTANTBV(BVConstEvaluator(*it).GetBVConst()); + CONSTANTBV::BitVector_add(output,output,kk,&carry); + carry = false; + CONSTANTBV::BitVector_Destroy(kk); + } + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case SBVDIV: + case SBVMOD: { + OutputNode = BVConstEvaluator(TranslateSignedDivMod(t)); + break; + } + case BVDIV: { + unsigned * quotient = CONSTANTBV::BitVector_Create(inputwidth,true); + unsigned * remainder = CONSTANTBV::BitVector_Create(inputwidth,true); + // iii is dividend, jjj is the divisor + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient,iii,jjj,remainder); + + if(0 != e) { + //error printing + if(counterexample_checking_during_refinement) { + OutputNode = CreateZeroConst(inputwidth); + bvdiv_exception_occured = true; + break; + } + else { + std::string ss("BVConstEvaluator:"); + ss += (const char*)BitVector_Error(e); + //destroy all the CONSTANTBV bitvectors + CONSTANTBV::BitVector_Destroy(iii); + CONSTANTBV::BitVector_Destroy(jjj); + CONSTANTBV::BitVector_Destroy(One); + CONSTANTBV::BitVector_Destroy(Zero); + + //AARON + iii = jjj = One = Zero = NULL; + //AARON + + FatalError(ss.c_str(), t); + } + } //end of error printing + + cccc = (char *)CONSTANTBV::BitVector_to_Bin(quotient); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + CONSTANTBV::BitVector_Destroy(quotient); + CONSTANTBV::BitVector_Destroy(remainder); + //AARON + + break; + } + case BVMOD: { + unsigned * quotient = CONSTANTBV::BitVector_Create(inputwidth,true); + unsigned * remainder = CONSTANTBV::BitVector_Create(inputwidth,true); + // iii is dividend, jjj is the divisor + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient,iii,jjj,remainder); + + if(0 != e) { + //error printing + if(counterexample_checking_during_refinement) { + OutputNode = CreateZeroConst(inputwidth); + bvdiv_exception_occured = true; + break; + } + else { + std::string ss("BVConstEvaluator:"); + ss += (const char*)BitVector_Error(e); + //destroy all the CONSTANTBV bitvectors + CONSTANTBV::BitVector_Destroy(iii); + CONSTANTBV::BitVector_Destroy(jjj); + CONSTANTBV::BitVector_Destroy(One); + CONSTANTBV::BitVector_Destroy(Zero); + + //AARON + iii = jjj = One = Zero = NULL; + //AARON + + FatalError(ss.c_str(), t); + } + } //end of errory printing + + cccc = (char *)CONSTANTBV::BitVector_to_Bin(remainder); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + CONSTANTBV::BitVector_Destroy(quotient); + CONSTANTBV::BitVector_Destroy(remainder); + //AARON + + break; + } + case ITE: + if(ASTTrue == t[0]) + OutputNode = BVConstEvaluator(t[1]); + else if(ASTFalse == t[0]) + OutputNode = BVConstEvaluator(t[2]); + else + FatalError("BVConstEvaluator: ITE condiional must be either TRUE or FALSE:",t); + break; + case EQ: + if(CONSTANTBV::BitVector_equal(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case NEQ: + if(!CONSTANTBV::BitVector_equal(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVLT: + if(-1 == CONSTANTBV::BitVector_Lexicompare(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVLE: { + int comp = CONSTANTBV::BitVector_Lexicompare(iii,jjj); + if(comp <= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVGT: + if(1 == CONSTANTBV::BitVector_Lexicompare(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVGE: { + int comp = CONSTANTBV::BitVector_Lexicompare(iii,jjj); + if(comp >= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSLT: + if(-1 == CONSTANTBV::BitVector_Compare(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVSLE: { + signed int comp = CONSTANTBV::BitVector_Compare(iii,jjj); + if(comp <= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSGT: + if(1 == CONSTANTBV::BitVector_Compare(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVSGE: { + int comp = CONSTANTBV::BitVector_Compare(iii,jjj); + if(comp >= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + default: + FatalError("BVConstEvaluator: The input kind is not supported yet:",t); + break; + } + + + + // //destroy all the CONSTANTBV bitvectors +// CONSTANTBV::BitVector_Destroy(iii); +// CONSTANTBV::BitVector_Destroy(jjj); +// CONSTANTBV::BitVector_Destroy(output); + +// if(k == BVNEG || k == BVUMINUS) +// CONSTANTBV::BitVector_Destroy(One); +// else if(k == BVAND || k == BVOR || k == BVXOR || k == BVSUB || +// k == BVMULT || k == EQ || k == NEQ || k == BVLT || +// k == BVLE || k == BVGT || k == BVGE || k == BVSLT || +// k == BVSLE || k == BVSGT || k == BVSGE) { +// CONSTANTBV::BitVector_Destroy(One); +// CONSTANTBV::BitVector_Destroy(Zero); +// } + + //AARON + if (output != NULL) CONSTANTBV::BitVector_Destroy(output); + if (One != NULL) CONSTANTBV::BitVector_Destroy(One); + if (Zero != NULL) CONSTANTBV::BitVector_Destroy(Zero); + if (iii != NULL && iii != One) CONSTANTBV::BitVector_Destroy(iii); + if (jjj != NULL && jjj != Zero) CONSTANTBV::BitVector_Destroy(jjj); + //AARON + + UpdateSolverMap(t,OutputNode); + //UpdateSimplifyMap(t,OutputNode,false); + return OutputNode; + } + + + unsigned int * ConvertToCONSTANTBV(const char * s) { + unsigned int length = strlen(s); + unsigned char * ccc = (unsigned char *)s; + unsigned * iii = CONSTANTBV::BitVector_Create(length,true); + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(iii,ccc); + //error printing + if(0 != e) { + cerr << "ConverToCONSTANTBV: wrong bin value: " << BitVector_Error(e); + FatalError(""); + } + + return iii; + } +*/ +}; //end of namespace BEEV diff --git a/stp/c_interface/Makefile b/stp/c_interface/Makefile new file mode 100644 index 00000000..cf6b09d1 --- /dev/null +++ b/stp/c_interface/Makefile @@ -0,0 +1,13 @@ +include ../Makefile.common + +SRCS = c_interface.cpp +OBJS = $(SRCS:.cpp=.o) + +libcinterface.a: $(OBJS) + $(AR) rc $@ $^ + $(RANLIB) $@ + +clean: + rm -rf *.o *~ *.a .#* + +c_interface.o: c_interface.h diff --git a/stp/c_interface/c_interface.cpp b/stp/c_interface/c_interface.cpp new file mode 100644 index 00000000..f4e53114 --- /dev/null +++ b/stp/c_interface/c_interface.cpp @@ -0,0 +1,1548 @@ +/******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ +// -*- c++ -*- +#include "c_interface.h" + +#include <cstdlib> +#include <cassert> +#include <ostream> +#include <iostream> +#include "fdstream.h" +#include "../AST/AST.h" + +//These typedefs lower the effort of using the keyboard to type (too +//many overloaded meanings of the word type) +typedef BEEV::ASTNode node; +typedef BEEV::ASTNode* nodestar; +typedef BEEV::BeevMgr* bmstar; +typedef BEEV::ASTVec nodelist; +typedef BEEV::CompleteCounterExample* CompleteCEStar; +BEEV::ASTVec *decls = NULL; +//vector<BEEV::ASTNode *> created_exprs; +bool cinterface_exprdelete_on = false; + +void vc_setFlags(char c) { + std::string helpstring = "Usage: stp [-option] [infile]\n\n"; + helpstring += "-r : switch refinement off (optimizations are ON by default)\n"; + helpstring += "-w : switch wordlevel solver off (optimizations are ON by default)\n"; + helpstring += "-a : switch optimizations off (optimizations are ON by default)\n"; + helpstring += "-s : print function statistics\n"; + helpstring += "-v : print nodes \n"; + helpstring += "-c : construct counterexample\n"; + helpstring += "-d : check counterexample\n"; + helpstring += "-p : print counterexample\n"; + helpstring += "-h : help\n"; + + switch(c) { + case 'a' : + BEEV::optimize = false; + BEEV::wordlevel_solve = false; + break; + case 'b': + BEEV::print_STPinput_back = true; + break; + case 'c': + BEEV::construct_counterexample = true; + break; + case 'd': + BEEV::construct_counterexample = true; + BEEV::check_counterexample = true; + break; + case 'e': + BEEV::variable_activity_optimize = true; + break; + case 'f': + BEEV::smtlib_parser_enable = true; + break; + case 'h': + cout << helpstring; + BEEV::FatalError(""); + break; + case 'l' : + BEEV::linear_search = true; + break; + case 'n': + BEEV::print_output = true; + break; + case 'p': + BEEV::print_counterexample = true; + break; + case 'q': + BEEV::print_arrayval_declaredorder = true; + break; + case 'r': + BEEV::arrayread_refinement = false; + break; + case 's' : + BEEV::stats = true; + break; + case 'u': + BEEV::arraywrite_refinement = true; + break; + case 'v' : + BEEV::print_nodes = true; + break; + case 'w': + BEEV::wordlevel_solve = false; + break; + case 'x': + cinterface_exprdelete_on = true; + break; + case 'z': + BEEV::print_sat_varorder = true; + break; + default: + std::string s = "C_interface: vc_setFlags: Unrecognized commandline flag:\n"; + s += helpstring; + BEEV::FatalError(s.c_str()); + break; + } +} + +//Create a validity Checker. This is the global BeevMgr +VC vc_createValidityChecker(void) { + vc_setFlags('d'); +#ifdef NATIVE_C_ARITH +#else + CONSTANTBV::ErrCode c = CONSTANTBV::BitVector_Boot(); + if(0 != c) { + cout << CONSTANTBV::BitVector_Error(c) << endl; + return 0; + } +#endif + bmstar bm = new BEEV::BeevMgr(); + decls = new BEEV::ASTVec(); + //created_exprs.clear(); + return (VC)bm; +} + +// Expr I/O +void vc_printExpr(VC vc, Expr e) { + //do not print in lisp mode + //bmstar b = (bmstar)vc; + BEEV::ASTNode q = (*(nodestar)e); + // b->Begin_RemoveWrites = true; + // BEEV::ASTNode q = b->SimplifyFormula_TopLevel(*((nodestar)e),false); + // b->Begin_RemoveWrites = false; + q.PL_Print(cout); +} + +void vc_printExprFile(VC vc, Expr e, int fd) { + fdostream os(fd); + ((nodestar)e)->PL_Print(os); + //os.flush(); +} + +static void vc_printVarDeclsToStream(VC vc, ostream &os) { + for(BEEV::ASTVec::iterator i = decls->begin(),iend=decls->end();i!=iend;i++) { + node a = *i; + switch(a.GetType()) { + case BEEV::BITVECTOR_TYPE: + a.PL_Print(os); + os << " : BITVECTOR(" << a.GetValueWidth() << ");" << endl; + break; + case BEEV::ARRAY_TYPE: + a.PL_Print(os); + os << " : ARRAY " << "BITVECTOR(" << a.GetIndexWidth() << ") OF "; + os << "BITVECTOR(" << a.GetValueWidth() << ");" << endl; + break; + case BEEV::BOOLEAN_TYPE: + a.PL_Print(os); + os << " : BOOLEAN;" << endl; + break; + default: + BEEV::FatalError("vc_printDeclsToStream: Unsupported type",a); + break; + } + } +} + +void vc_printVarDecls(VC vc) { + vc_printVarDeclsToStream(vc, cout); +} + +static void vc_printAssertsToStream(VC vc, ostream &os, int simplify_print) { + bmstar b = (bmstar)vc; + BEEV::ASTVec v = b->GetAsserts(); + for(BEEV::ASTVec::iterator i=v.begin(),iend=v.end();i!=iend;i++) { + b->Begin_RemoveWrites = true; + BEEV::ASTNode q = (simplify_print == 1) ? b->SimplifyFormula_TopLevel(*i,false) : *i; + q = (simplify_print == 1) ? b->SimplifyFormula_TopLevel(q,false) : q; + b->Begin_RemoveWrites = false; + os << "ASSERT( "; + q.PL_Print(os); + os << ");" << endl; + } +} + +void vc_printAsserts(VC vc, int simplify_print) { + vc_printAssertsToStream(vc, cout, simplify_print); +} + +void vc_printQueryStateToBuffer(VC vc, Expr e, char **buf, unsigned long *len, int simplify_print){ + assert(vc); + assert(e); + assert(buf); + assert(len); + bmstar b = (bmstar)vc; + + // formate the state of the query + stringstream os; + vc_printVarDeclsToStream(vc, os); + os << "%----------------------------------------------------" << endl; + vc_printAssertsToStream(vc, os, simplify_print); + os << "%----------------------------------------------------" << endl; + os << "QUERY( "; + b->Begin_RemoveWrites = true; + BEEV::ASTNode q = (simplify_print == 1) ? b->SimplifyFormula_TopLevel(*((nodestar)e),false) : *(nodestar)e; + b->Begin_RemoveWrites = false; + q.PL_Print(os); + os << " );" << endl; + + // convert to a c buffer + string s = os.str(); + const char *cstr = s.c_str(); + unsigned long size = s.size() + 1; // number of chars + terminating null + *buf = (char *)malloc(size); + if (!(*buf)) { + fprintf(stderr, "malloc(%lu) failed.", size); + assert(*buf); + } + *len = size; + memcpy(*buf, cstr, size); +} + +void vc_printCounterExampleToBuffer(VC vc, char **buf, unsigned long *len) { + assert(vc); + assert(buf); + assert(len); + bmstar b = (bmstar)vc; + + // formate the state of the query + std::ostringstream os; + BEEV::print_counterexample = true; + os << "COUNTEREXAMPLE BEGIN: \n"; + b->PrintCounterExample(true,os); + os << "COUNTEREXAMPLE END: \n"; + + // convert to a c buffer + string s = os.str(); + const char *cstr = s.c_str(); + unsigned long size = s.size() + 1; // number of chars + terminating null + *buf = (char *)malloc(size); + if (!(*buf)) { + fprintf(stderr, "malloc(%lu) failed.", size); + assert(*buf); + } + *len = size; + memcpy(*buf, cstr, size); +} + +void vc_printExprToBuffer(VC vc, Expr e, char **buf, unsigned long * len) { + stringstream os; + //bmstar b = (bmstar)vc; + BEEV::ASTNode q = *((nodestar)e); + // b->Begin_RemoveWrites = true; + // BEEV::ASTNode q = b->SimplifyFormula_TopLevel(*((nodestar)e),false); + // b->Begin_RemoveWrites = false; + q.PL_Print(os); + //((nodestar)e)->PL_Print(os); + string s = os.str(); + const char * cstr = s.c_str(); + unsigned long size = s.size() + 1; // number of chars + terminating null + *buf = (char *)malloc(size); + *len = size; + memcpy(*buf, cstr, size); +} + +void vc_printQuery(VC vc){ + ostream& os = std::cout; + bmstar b = (bmstar)vc; + os << "QUERY("; + //b->Begin_RemoveWrites = true; + //BEEV::ASTNode q = b->SimplifyFormula_TopLevel(b->GetQuery(),false); + BEEV::ASTNode q = b->GetQuery(); + //b->Begin_RemoveWrites = false; + q.PL_Print(os); + // b->GetQuery().PL_Print(os); + os << ");" << endl; +} + +///////////////////////////////////////////////////////////////////////////// +// Array-related methods // +///////////////////////////////////////////////////////////////////////////// +//! Create an array type +Type vc_arrayType(VC vc, Type typeIndex, Type typeData) { + bmstar b = (bmstar)vc; + nodestar ti = (nodestar)typeIndex; + nodestar td = (nodestar)typeData; + + if(!(ti->GetKind() == BEEV::BITVECTOR && (*ti)[0].GetKind() == BEEV::BVCONST)) + BEEV::FatalError("Tyring to build array whose indextype i is not a BITVECTOR, where i = ",*ti); + if(!(td->GetKind() == BEEV::BITVECTOR && (*td)[0].GetKind() == BEEV::BVCONST)) + BEEV::FatalError("Trying to build an array whose valuetype v is not a BITVECTOR. where a = ",*td); + nodestar output = new node(b->CreateNode(BEEV::ARRAY,(*ti)[0],(*td)[0])); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return (Type)output; +} + +//! Create an expression for the value of array at the given index +Expr vc_readExpr(VC vc, Expr array, Expr index) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)array; + nodestar i = (nodestar)index; + + b->BVTypeCheck(*a); + b->BVTypeCheck(*i); + node o = b->CreateTerm(BEEV::READ,a->GetValueWidth(),*a,*i); + b->BVTypeCheck(o); + + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +// //! Array update; equivalent to "array WITH [index] := newValue" +Expr vc_writeExpr(VC vc, Expr array, Expr index, Expr newValue) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)array; + nodestar i = (nodestar)index; + nodestar n = (nodestar)newValue; + + b->BVTypeCheck(*a); + b->BVTypeCheck(*i); + b->BVTypeCheck(*n); + node o = b->CreateTerm(BEEV::WRITE,a->GetValueWidth(),*a,*i,*n); + o.SetIndexWidth(a->GetIndexWidth()); + b->BVTypeCheck(o); + + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +///////////////////////////////////////////////////////////////////////////// +// Context-related methods // +///////////////////////////////////////////////////////////////////////////// +//! Assert a new formula in the current context. +/*! The formula must have Boolean type. */ +void vc_assertFormula(VC vc, Expr e) { + nodestar a = (nodestar)e; + bmstar b = (bmstar)vc; + + if(!BEEV::is_Form_kind(a->GetKind())) + BEEV::FatalError("Trying to assert a NON formula: ",*a); + + b->BVTypeCheck(*a); + b->AddAssert(*a); +} + +//! Check validity of e in the current context. +/*! If the result is true, then the resulting context is the same as + * the starting context. If the result is false, then the resulting + * context is a context in which e is false. e must have Boolean + * type. */ +int vc_query(VC vc, Expr e) { + nodestar a = (nodestar)e; + bmstar b = (bmstar)vc; + + if(!BEEV::is_Form_kind(a->GetKind())) + BEEV::FatalError("CInterface: Trying to QUERY a NON formula: ",*a); + + b->BVTypeCheck(*a); + b->AddQuery(*a); + + const BEEV::ASTVec v = b->GetAsserts(); + node o; + if(!v.empty()) { + if(v.size()==1) + return b->TopLevelSAT(v[0],*a); + else + return b->TopLevelSAT(b->CreateNode(BEEV::AND,v),*a); + } + else + return b->TopLevelSAT(b->CreateNode(BEEV::TRUE),*a); +} + +void vc_push(VC vc) { + bmstar b = (bmstar)vc; + b->ClearAllCaches(); + b->Push(); +} + +void vc_pop(VC vc) { + bmstar b = (bmstar)vc; + b->Pop(); +} + +void vc_printCounterExample(VC vc) { + bmstar b = (bmstar)vc; + BEEV::print_counterexample = true; + cout << "COUNTEREXAMPLE BEGIN: \n"; + b->PrintCounterExample(true); + cout << "COUNTEREXAMPLE END: \n"; +} + +// //! Return the counterexample after a failed query. +// /*! This method should only be called after a query which returns +// * false. It will try to return the simplest possible set of +// * assertions which are sufficient to make the queried expression +// * false. The caller is responsible for freeing the array when +// * finished with it. +// */ + +Expr vc_getCounterExample(VC vc, Expr e) { + nodestar a = (nodestar)e; + bmstar b = (bmstar)vc; + + bool t = false; + if(b->CounterExampleSize()) + t = true; + nodestar output = new node(b->GetCounterExample(t, *a)); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +int vc_counterexample_size(VC vc) { + bmstar b = (bmstar)vc; + return b->CounterExampleSize(); +} + +WholeCounterExample vc_getWholeCounterExample(VC vc) { + bmstar b = (bmstar)vc; + CompleteCEStar c = + new BEEV::CompleteCounterExample(b->GetCompleteCounterExample(), b); + return c; +} + +Expr vc_getTermFromCounterExample(VC vc, Expr e, CompleteCEStar cc) { + //bmstar b = (bmstar)vc; + nodestar n = (nodestar)e; + CompleteCEStar c = (CompleteCEStar)cc; + + nodestar output = new node(c->GetCounterExample(*n)); + return output; +} + +int vc_getBVLength(VC vc, Expr ex) { + nodestar e = (nodestar)ex; + + if(BEEV::BITVECTOR_TYPE != e->GetType()) { + BEEV::FatalError("c_interface: vc_GetBVLength: Input expression must be a bit-vector"); + } + + return e->GetValueWidth(); +} // end of vc_getBVLength + +///////////////////////////////////////////////////////////////////////////// +// Expr Creation methods // +///////////////////////////////////////////////////////////////////////////// +//! Create a variable with a given name and type +/*! The type cannot be a function type. */ +Expr vc_varExpr1(VC vc, char* name, + int indexwidth, int valuewidth) { + bmstar b = (bmstar)vc; + + node o = b->CreateSymbol(name); + o.SetIndexWidth(indexwidth); + o.SetValueWidth(valuewidth); + + nodestar output = new node(o); + ////if(cinterface_exprdelete_on) created_exprs.push_back(output); + b->BVTypeCheck(*output); + + //store the decls in a vector for printing purposes + decls->push_back(o); + return output; +} + +Expr vc_varExpr(VC vc, char * name, Type type) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)type; + + node o = b->CreateSymbol(name); + switch(a->GetKind()) { + case BEEV::BITVECTOR: + o.SetIndexWidth(0); + o.SetValueWidth(GetUnsignedConst((*a)[0])); + break; + case BEEV::ARRAY: + o.SetIndexWidth(GetUnsignedConst((*a)[0])); + o.SetValueWidth(GetUnsignedConst((*a)[1])); + break; + case BEEV::BOOLEAN: + o.SetIndexWidth(0); + o.SetValueWidth(0); + break; + default: + BEEV::FatalError("CInterface: vc_varExpr: Unsupported type",*a); + break; + } + nodestar output = new node(o); + ////if(cinterface_exprdelete_on) created_exprs.push_back(output); + b->BVTypeCheck(*output); + + //store the decls in a vector for printing purposes + decls->push_back(o); + return output; +} + +//! Create an equality expression. The two children must have the +//same type. +Expr vc_eqExpr(VC vc, Expr ccc0, Expr ccc1) { + bmstar b = (bmstar)vc; + + nodestar a = (nodestar)ccc0; + nodestar aa = (nodestar)ccc1; + b->BVTypeCheck(*a); + b->BVTypeCheck(*aa); + node o = b->CreateNode(BEEV::EQ,*a,*aa); + + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_boolType(VC vc) { + bmstar b = (bmstar)vc; + + node o = b->CreateNode(BEEV::BOOLEAN); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +///////////////////////////////////////////////////////////////////////////// +// BOOLEAN EXPR Creation methods // +///////////////////////////////////////////////////////////////////////////// +// The following functions create Boolean expressions. The children +// provided as arguments must be of type Boolean. +Expr vc_trueExpr(VC vc) { + bmstar b = (bmstar)vc; + node c = b->CreateNode(BEEV::TRUE); + + nodestar d = new node(c); + //if(cinterface_exprdelete_on) created_exprs.push_back(d); + return d; +} + +Expr vc_falseExpr(VC vc) { + bmstar b = (bmstar)vc; + node c = b->CreateNode(BEEV::FALSE); + + nodestar d = new node(c); + //if(cinterface_exprdelete_on) created_exprs.push_back(d); + return d; +} + +Expr vc_notExpr(VC vc, Expr ccc) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)ccc; + + node o = b->CreateNode(BEEV::NOT,*a); + b->BVTypeCheck(o); + + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_andExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + node o = b->CreateNode(BEEV::AND,*l,*r); + b->BVTypeCheck(o); + + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_orExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + node o = b->CreateNode(BEEV::OR,*l,*r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_andExprN(VC vc, Expr* cc, int n) { + bmstar b = (bmstar)vc; + nodestar * c = (nodestar *)cc; + nodelist d; + + for(int i =0; i < n; i++) + d.push_back(*c[i]); + + node o = b->CreateNode(BEEV::AND,d); + b->BVTypeCheck(o); + + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + + +Expr vc_orExprN(VC vc, Expr* cc, int n) { + bmstar b = (bmstar)vc; + nodestar * c = (nodestar *)cc; + nodelist d; + + for(int i =0; i < n; i++) + d.push_back(*c[i]); + + node o = b->CreateNode(BEEV::OR,d); + b->BVTypeCheck(o); + + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_iteExpr(VC vc, Expr cond, Expr thenpart, Expr elsepart){ + bmstar b = (bmstar)vc; + nodestar c = (nodestar)cond; + nodestar t = (nodestar)thenpart; + nodestar e = (nodestar)elsepart; + + b->BVTypeCheck(*c); + b->BVTypeCheck(*t); + b->BVTypeCheck(*e); + node o; + //if the user asks for a formula then produce a formula, else + //prodcue a term + if(BEEV::BOOLEAN_TYPE == t->GetType()) + o = b->CreateNode(BEEV::ITE,*c,*t,*e); + else { + o = b->CreateTerm(BEEV::ITE,t->GetValueWidth(),*c,*t,*e); + o.SetIndexWidth(t->GetIndexWidth()); + } + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_impliesExpr(VC vc, Expr antecedent, Expr consequent){ + bmstar b = (bmstar)vc; + nodestar c = (nodestar)antecedent; + nodestar t = (nodestar)consequent; + + b->BVTypeCheck(*c); + b->BVTypeCheck(*t); + node o; + + o = b->CreateNode(BEEV::IMPLIES,*c,*t); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_iffExpr(VC vc, Expr e0, Expr e1){ + bmstar b = (bmstar)vc; + nodestar c = (nodestar)e0; + nodestar t = (nodestar)e1; + + b->BVTypeCheck(*c); + b->BVTypeCheck(*t); + node o; + + o = b->CreateNode(BEEV::IFF,*c,*t); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_boolToBVExpr(VC vc, Expr form) { + bmstar b = (bmstar)vc; + nodestar c = (nodestar)form; + + b->BVTypeCheck(*c); + if(!is_Form_kind(c->GetKind())) + BEEV::FatalError("CInterface: vc_BoolToBVExpr: You have input a NON formula:",*c); + + node o; + node one = b->CreateOneConst(1); + node zero = b->CreateZeroConst(1); + o = b->CreateTerm(BEEV::ITE,1,*c,one,zero); + + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +///////////////////////////////////////////////////////////////////////////// +// BITVECTOR EXPR Creation methods // +///////////////////////////////////////////////////////////////////////////// +Type vc_bvType(VC vc, int num_bits) { + bmstar b = (bmstar)vc; + + if(!(0 < num_bits)) + BEEV::FatalError("CInterface: number of bits in a bvtype must be a positive integer:", + b->CreateNode(BEEV::UNDEFINED)); + + node e = b->CreateBVConst(32, num_bits); + nodestar output = new node(b->CreateNode(BEEV::BITVECTOR,e)); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Type vc_bv32Type(VC vc) { + return vc_bvType(vc,32); +} + + +Expr vc_bvConstExprFromStr(VC vc, char* binary_repr) { + bmstar b = (bmstar)vc; + + node n = b->CreateBVConst(binary_repr,2); + b->BVTypeCheck(n); + nodestar output = new node(n); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvConstExprFromInt(VC vc, + int n_bits, + unsigned int value) { + bmstar b = (bmstar)vc; + + unsigned long long int v = (unsigned long long int)value; + node n = b->CreateBVConst(n_bits, v); + b->BVTypeCheck(n); + nodestar output = new node(n); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvConstExprFromLL(VC vc, + int n_bits, + unsigned long long value) { + bmstar b = (bmstar)vc; + + node n = b->CreateBVConst(n_bits, value); + b->BVTypeCheck(n); + nodestar output = new node(n); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvConcatExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = + b->CreateTerm(BEEV::BVCONCAT, + l->GetValueWidth()+ r->GetValueWidth(),*l,*r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvPlusExpr(VC vc, int n_bits, Expr left, Expr right){ + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateTerm(BEEV::BVPLUS,n_bits, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + + +Expr vc_bv32PlusExpr(VC vc, Expr left, Expr right) { + return vc_bvPlusExpr(vc, 32, left, right); +} + + +Expr vc_bvMinusExpr(VC vc, int n_bits, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateTerm(BEEV::BVSUB,n_bits, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + + +Expr vc_bv32MinusExpr(VC vc, Expr left, Expr right) { + return vc_bvMinusExpr(vc, 32, left, right); +} + + +Expr vc_bvMultExpr(VC vc, int n_bits, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateTerm(BEEV::BVMULT,n_bits, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvDivExpr(VC vc, int n_bits, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateTerm(BEEV::BVDIV,n_bits, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvModExpr(VC vc, int n_bits, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateTerm(BEEV::BVMOD,n_bits, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_sbvDivExpr(VC vc, int n_bits, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateTerm(BEEV::SBVDIV,n_bits, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_sbvModExpr(VC vc, int n_bits, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateTerm(BEEV::SBVMOD,n_bits, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bv32MultExpr(VC vc, Expr left, Expr right) { + return vc_bvMultExpr(vc, 32, left, right); +} + + +// unsigned comparators +Expr vc_bvLtExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateNode(BEEV::BVLT, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvLeExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateNode(BEEV::BVLE, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvGtExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateNode(BEEV::BVGT, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvGeExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateNode(BEEV::BVGE, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +// signed comparators +Expr vc_sbvLtExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateNode(BEEV::BVSLT, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_sbvLeExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateNode(BEEV::BVSLE, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_sbvGtExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateNode(BEEV::BVSGT, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_sbvGeExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateNode(BEEV::BVSGE, *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvUMinusExpr(VC vc, Expr ccc) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)ccc; + b->BVTypeCheck(*a); + + node o = b->CreateTerm(BEEV::BVUMINUS, a->GetValueWidth(), *a); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +// bitwise operations: these are terms not formulas +Expr vc_bvAndExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateTerm(BEEV::BVAND, (*l).GetValueWidth(), *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvOrExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateTerm(BEEV::BVOR, (*l).GetValueWidth(), *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvXorExpr(VC vc, Expr left, Expr right) { + bmstar b = (bmstar)vc; + nodestar l = (nodestar)left; + nodestar r = (nodestar)right; + + b->BVTypeCheck(*l); + b->BVTypeCheck(*r); + node o = b->CreateTerm(BEEV::BVXOR, (*l).GetValueWidth(), *l, *r); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvNotExpr(VC vc, Expr ccc) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)ccc; + + b->BVTypeCheck(*a); + node o = b->CreateTerm(BEEV::BVNEG, a->GetValueWidth(), *a); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvLeftShiftExpr(VC vc, int sh_amt, Expr ccc) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)ccc; + b->BVTypeCheck(*a); + + //convert leftshift to bvconcat + if(0 != sh_amt) { + node len = b->CreateBVConst(sh_amt, 0); + node o = b->CreateTerm(BEEV::BVCONCAT, a->GetValueWidth() + sh_amt, *a, len); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; + } + else + return a; +} + +Expr vc_bvRightShiftExpr(VC vc, int sh_amt, Expr ccc) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)ccc; + b->BVTypeCheck(*a); + + unsigned int w = a->GetValueWidth(); + //the amount by which you are rightshifting + //is less-than/equal-to the length of input + //bitvector + if(0 < (unsigned)sh_amt && (unsigned)sh_amt <= w) { + node len = b->CreateBVConst(sh_amt, 0); + node hi = b->CreateBVConst(32,w-1); + node low = b->CreateBVConst(32,sh_amt); + node extract = b->CreateTerm(BEEV::BVEXTRACT,w-sh_amt,*a,hi,low); + + node n = b->CreateTerm(BEEV::BVCONCAT, w,len, extract); + b->BVTypeCheck(n); + nodestar output = new node(n); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; + } + else if(sh_amt == 0) + return a; + else { + if(0== w) + BEEV::FatalError("CInterface: vc_bvRightShiftExpr: cannot have a bitvector of length 0:",*a); + nodestar output = new node(b->CreateBVConst(w,0)); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; + } +} + +/* Same as vc_bvLeftShift only that the answer in 32 bits long */ +Expr vc_bv32LeftShiftExpr(VC vc, int sh_amt, Expr child) { + return vc_bvExtract(vc, vc_bvLeftShiftExpr(vc, sh_amt, child), 31, 0); +} + +/* Same as vc_bvRightShift only that the answer in 32 bits long */ +Expr vc_bv32RightShiftExpr(VC vc, int sh_amt, Expr child) { + return vc_bvExtract(vc, vc_bvRightShiftExpr(vc, sh_amt, child), 31, 0); +} + + +Expr vc_bvVar32LeftShiftExpr(VC vc, Expr sh_amt, Expr child) { + Expr ifpart; + Expr thenpart; + Expr elsepart = vc_trueExpr(vc); + Expr ite = vc_trueExpr(vc); + + for(int count=32; count >= 0; count--){ + if(count != 32) { + ifpart = vc_eqExpr(vc, sh_amt, + vc_bvConstExprFromInt(vc, 32, count)); + thenpart = vc_bvExtract(vc, + vc_bvLeftShiftExpr(vc, count, child), + 31, 0); + + ite = vc_iteExpr(vc,ifpart,thenpart,elsepart); + elsepart = ite; + } + else + elsepart = vc_bvConstExprFromInt(vc,32, 0); + } + return ite; +} + +Expr vc_bvVar32DivByPowOfTwoExpr(VC vc, Expr child, Expr rhs) { + Expr ifpart; + Expr thenpart; + Expr elsepart = vc_trueExpr(vc); + Expr ite = vc_trueExpr(vc); + + for(int count=32; count >= 0; count--){ + if(count != 32) { + ifpart = vc_eqExpr(vc, rhs, + vc_bvConstExprFromInt(vc, 32, 1 << count)); + thenpart = vc_bvRightShiftExpr(vc, count, child); + ite = vc_iteExpr(vc,ifpart,thenpart,elsepart); + elsepart = ite; + } else { + elsepart = vc_bvConstExprFromInt(vc,32, 0); + } + } + return ite; +} + +Expr vc_bvVar32RightShiftExpr(VC vc, Expr sh_amt, Expr child) { + Expr ifpart; + Expr thenpart; + Expr elsepart = vc_trueExpr(vc); + Expr ite = vc_trueExpr(vc); + + for(int count=32; count >= 0; count--){ + if(count != 32) { + ifpart = vc_eqExpr(vc, sh_amt, + vc_bvConstExprFromInt(vc, 32, count)); + thenpart = vc_bvRightShiftExpr(vc, count, child); + ite = vc_iteExpr(vc,ifpart,thenpart,elsepart); + elsepart = ite; + } else { + elsepart = vc_bvConstExprFromInt(vc,32, 0); + } + } + return ite; +} + +Expr vc_bvExtract(VC vc, Expr ccc, int hi_num, int low_num) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)ccc; + b->BVTypeCheck(*a); + + node hi = b->CreateBVConst(32,hi_num); + node low = b->CreateBVConst(32,low_num); + node o = b->CreateTerm(BEEV::BVEXTRACT,hi_num-low_num+1,*a,hi,low); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvBoolExtract(VC vc, Expr ccc, int bit_num) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)ccc; + b->BVTypeCheck(*a); + + node bit = b->CreateBVConst(32,bit_num); + //node o = b->CreateNode(BEEV::BVGETBIT,*a,bit); + node zero = b->CreateBVConst(1,0); + node oo = b->CreateTerm(BEEV::BVEXTRACT,1,*a,bit,bit); + node o = b->CreateNode(BEEV::EQ,oo,zero); + b->BVTypeCheck(o); + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +Expr vc_bvSignExtend(VC vc, Expr ccc, int nbits) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)ccc; + + //width of the expr which is being sign extended. nbits is the + //resulting length of the signextended expr + b->BVTypeCheck(*a); + + unsigned exprlen = a->GetValueWidth(); + unsigned outputlen = nbits; + node n; + if(exprlen >= outputlen) { + //extract + node hi = b->CreateBVConst(32,outputlen-1); + node low = b->CreateBVConst(32,0); + n = b->CreateTerm(BEEV::BVEXTRACT,nbits,*a,hi,low); + b->BVTypeCheck(n); + } + else { + //sign extend + BEEV::ASTNode width = b->CreateBVConst(32,nbits); + n = b->CreateTerm(BEEV::BVSX,nbits,*a, width); + } + + b->BVTypeCheck(n); + nodestar output = new node(n); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; +} + +//! Return an int from a constant bitvector expression +int getBVInt(Expr e) { + //bmstar b = (bmstar)vc; + nodestar a = (nodestar)e; + + if(BEEV::BVCONST != a->GetKind()) + BEEV::FatalError("CInterface: getBVInt: Attempting to extract int value from a NON-constant BITVECTOR: ",*a); + return (int)GetUnsignedConst(*a); +} + +//! Return an unsigned int from a constant bitvector expression +unsigned int getBVUnsigned(Expr e) { + //bmstar b = (bmstar)vc; + nodestar a = (nodestar)e; + + if(BEEV::BVCONST != a->GetKind()) + BEEV::FatalError("getBVUnsigned: Attempting to extract int value from a NON-constant BITVECTOR: ",*a); + return (unsigned int)GetUnsignedConst(*a); +} + +//! Return an unsigned long long int from a constant bitvector expression +unsigned long long int getBVUnsignedLongLong(Expr e) { + //bmstar b = (bmstar)vc; + nodestar a = (nodestar)e; + + if(BEEV::BVCONST != a->GetKind()) + BEEV::FatalError("getBVUnsigned: Attempting to extract int value from a NON-constant BITVECTOR: ",*a); +#ifdef NATIVE_C_ARITH + return (unsigned long long int)a->GetBVConst(); +#else + unsigned* bv = a->GetBVConst(); + + char * str_bv = (char *)CONSTANTBV::BitVector_to_Bin(bv); + unsigned long long int tmp = strtoull(str_bv,NULL,2); + CONSTANTBV::BitVector_Dispose((unsigned char *)str_bv); + return tmp; +#endif +} + + +Expr vc_simplify(VC vc, Expr e) { + bmstar b = (bmstar)vc; + nodestar a = (nodestar)e; + + if(BEEV::BOOLEAN_TYPE == a->GetType()) { + nodestar output = new node(b->SimplifyFormula_TopLevel(*a,false)); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + b->Begin_RemoveWrites = true; + output = new node(b->SimplifyFormula_TopLevel(*output,false)); + b->Begin_RemoveWrites = false; + return output; + } + else { + nodestar output = new node(b->SimplifyTerm(*a)); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + b->Begin_RemoveWrites = true; + output = new node(b->SimplifyTerm(*output)); + b->Begin_RemoveWrites = false; + return output; + } +} + +/* C pointer support: C interface to support C memory arrays in CVCL */ +Expr vc_bvCreateMemoryArray(VC vc, char * arrayName) { + Type bv8 = vc_bvType(vc,8); + Type bv32 = vc_bvType(vc,32); + + Type malloced_mem0 = vc_arrayType(vc,bv32,bv8); + return vc_varExpr(vc, arrayName, malloced_mem0); +} + +Expr vc_bvReadMemoryArray(VC vc, + Expr array, + Expr byteIndex, int numOfBytes) { + if(!(numOfBytes > 0)) + BEEV::FatalError("numOfBytes must be greater than 0"); + + if(numOfBytes == 1) + return vc_readExpr(vc,array,byteIndex); + else { + int count = 1; + Expr a = vc_readExpr(vc,array,byteIndex); + while(--numOfBytes > 0) { + Expr b = vc_readExpr(vc,array, + /*vc_simplify(vc, */ + vc_bvPlusExpr(vc, 32, + byteIndex, + vc_bvConstExprFromInt(vc,32,count)))/*)*/; + a = vc_bvConcatExpr(vc,b,a); + count++; + } + return a; + } +} + +Expr vc_bvWriteToMemoryArray(VC vc, + Expr array, Expr byteIndex, + Expr element, int numOfBytes) { + if(!(numOfBytes > 0)) + BEEV::FatalError("numOfBytes must be greater than 0"); + + int newBitsPerElem = numOfBytes*8; + if(numOfBytes == 1) + return vc_writeExpr(vc, array, byteIndex, element); + else { + int count = 1; + int hi = newBitsPerElem - 1; + int low = newBitsPerElem - 8; + int low_elem = 0; + int hi_elem = low_elem + 7; + Expr c = vc_bvExtract(vc, element, hi_elem, low_elem); + Expr newarray = vc_writeExpr(vc, array, byteIndex, c); + while(--numOfBytes > 0) { + hi = low-1; + low = low-8; + + low_elem = low_elem + 8; + hi_elem = low_elem + 7; + + c = vc_bvExtract(vc, element, hi_elem, low_elem); + newarray = + vc_writeExpr(vc, newarray, + vc_bvPlusExpr(vc, 32, byteIndex, vc_bvConstExprFromInt(vc,32,count)), + c); + count++; + } + return newarray; + } +} + +Expr vc_bv32ConstExprFromInt(VC vc, unsigned int value){ + return vc_bvConstExprFromInt(vc, 32, value); +} + + +#if 0 +static char *val_to_binary_str(unsigned nbits, unsigned long long val) { + char s[65]; + + assert(nbits < sizeof s); + strcpy(s, ""); + while(nbits-- > 0) { + if((val >> nbits) & 1) + strcat(s, "1"); + else + strcat(s, "0"); + } + return strdup(s); +} +#endif + +char* exprString(Expr e){ + stringstream ss; + ((nodestar)e)->PL_Print(ss,0); + string s = ss.str(); + char *copy = strdup(s.c_str()); + return copy; +} + +char* typeString(Type t){ + stringstream ss; + ((nodestar)t)->PL_Print(ss,0); + + string s = ss.str(); + char *copy = strdup(s.c_str()); + return copy; +} + +Expr getChild(Expr e, int i){ + nodestar a = (nodestar)e; + + BEEV::ASTVec c = a->GetChildren(); + if(0 <= (unsigned)i && (unsigned)i < c.size()) { + BEEV::ASTNode o = c[i]; + nodestar output = new node(o); + //if(cinterface_exprdelete_on) created_exprs.push_back(output); + return output; + } + else + BEEV::FatalError("getChild: Error accessing childNode in expression: ",*a); + return a; +} + +void vc_registerErrorHandler(void (*error_hdlr)(const char* err_msg)) { + BEEV::vc_error_hdlr = error_hdlr; +} + + +int vc_getHashQueryStateToBuffer(VC vc, Expr query) { + assert(vc); + assert(query); + bmstar b = (bmstar)vc; + nodestar qry = (nodestar)query; + BEEV::ASTVec v = b->GetAsserts(); + BEEV::ASTNode out = b->CreateNode(BEEV::AND,b->CreateNode(BEEV::NOT,*qry),v); + return out.Hash(); +} + +Type vc_getType(VC vc, Expr ex) { + nodestar e = (nodestar)ex; + + switch(e->GetType()) { + case BEEV::BOOLEAN_TYPE: + return vc_boolType(vc); + break; + case BEEV::BITVECTOR_TYPE: + return vc_bvType(vc,e->GetValueWidth()); + break; + case BEEV::ARRAY_TYPE: { + Type typeindex = vc_bvType(vc,e->GetIndexWidth()); + Type typedata = vc_bvType(vc,e->GetValueWidth()); + return vc_arrayType(vc,typeindex,typedata); + break; + } + default: + BEEV::FatalError("c_interface: vc_GetType: expression with bad typing: please check your expression construction"); + return vc_boolType(vc); + break; + } +}// end of vc_gettype() + +//!if e is TRUE then return 1; if e is FALSE then return 0; otherwise +//return -1 +int vc_isBool(Expr e) { + nodestar input = (nodestar)e; + if(BEEV::TRUE == input->GetKind()) { + return 1; + } + + if(BEEV::FALSE == input->GetKind()) { + return 0; + } + + return -1; +} + +void vc_Destroy(VC vc) { + bmstar b = (bmstar)vc; + // for(std::vector<BEEV::ASTNode *>::iterator it=created_exprs.begin(), + // itend=created_exprs.end();it!=itend;it++) { + // BEEV::ASTNode * aaa = *it; + // delete aaa; + // } + delete decls; + delete b; +} + +void vc_DeleteExpr(Expr e) { + nodestar input = (nodestar)e; + //bmstar b = (bmstar)vc; + delete input; +} + +exprkind_t getExprKind(Expr e) { + nodestar input = (nodestar)e; + return (exprkind_t)(input->GetKind()); +} + +int getDegree (Expr e) { + nodestar input = (nodestar)e; + return input->Degree(); +} + +int getBVLength(Expr ex) { + nodestar e = (nodestar)ex; + + if(BEEV::BITVECTOR_TYPE != e->GetType()) { + BEEV::FatalError("c_interface: vc_GetBVLength: Input expression must be a bit-vector"); + } + + return e->GetValueWidth(); +} + +type_t getType (Expr ex) { + nodestar e = (nodestar)ex; + + return (type_t)(e->GetType()); +} + +int getVWidth (Expr ex) { + nodestar e = (nodestar)ex; + + return e->GetValueWidth(); +} + +int getIWidth (Expr ex) { + nodestar e = (nodestar)ex; + + return e->GetIndexWidth(); +} + +void vc_printCounterExampleFile(VC vc, int fd) { + fdostream os(fd); + bmstar b = (bmstar)vc; + BEEV::print_counterexample = true; + os << "COUNTEREXAMPLE BEGIN: \n"; + b->PrintCounterExample(true, os); + os << "COUNTEREXAMPLE END: \n"; +} + +const char* exprName(Expr e){ + return ((nodestar)e)->GetName(); +} + +int getExprID (Expr ex) { + BEEV::ASTNode q = (*(nodestar)ex); + + return q.GetNodeNum(); +} diff --git a/stp/c_interface/c_interface.h b/stp/c_interface/c_interface.h new file mode 100644 index 00000000..a2fa8cd7 --- /dev/null +++ b/stp/c_interface/c_interface.h @@ -0,0 +1,401 @@ +/******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: November, 2005 + * + * License to use, copy, modify, sell and/or distribute this software + * and its documentation for any purpose is hereby granted without + * royalty, subject to the terms and conditions defined in the \ref + * LICENSE file provided with this distribution. In particular: + * + * - The above copyright notice and this permission notice must appear + * in all copies of the software and related documentation. + * + * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES, + * EXPRESSED OR IMPLIED. USE IT AT YOUR OWN RISK. + ********************************************************************/ +// -*- c++ -*- +#ifndef _cvcl__include__c_interface_h_ +#define _cvcl__include__c_interface_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef STP_STRONG_TYPING +#else + //This gives absolutely no pointer typing at compile-time. Most C + //users prefer this over stronger typing. User is the king. A + //stronger typed interface is in the works. + typedef void* VC; + typedef void* Expr; + typedef void* Type; + typedef void* WholeCounterExample; +#endif + + // o : optimizations + // c : check counterexample + // p : print counterexample + // h : help + // s : stats + // v : print nodes + void vc_setFlags(char c); + + //! Flags can be NULL + VC vc_createValidityChecker(void); + + // Basic types + Type vc_boolType(VC vc); + + //! Create an array type + Type vc_arrayType(VC vc, Type typeIndex, Type typeData); + + ///////////////////////////////////////////////////////////////////////////// + // Expr manipulation methods // + ///////////////////////////////////////////////////////////////////////////// + + //! Create a variable with a given name and type + /*! The type cannot be a function type. The var name can contain + only variables, numerals and underscore. If you use any other + symbol, you will get a segfault. */ + Expr vc_varExpr(VC vc, char * name, Type type); + + //The var name can contain only variables, numerals and + //underscore. If you use any other symbol, you will get a segfault. + Expr vc_varExpr1(VC vc, char* name, + int indexwidth, int valuewidth); + + //! Get the expression and type associated with a name. + /*! If there is no such Expr, a NULL Expr is returned. */ + //Expr vc_lookupVar(VC vc, char* name, Type* type); + + //! Get the type of the Expr. + Type vc_getType(VC vc, Expr e); + + int vc_getBVLength(VC vc, Expr e); + + //! Create an equality expression. The two children must have the same type. + Expr vc_eqExpr(VC vc, Expr child0, Expr child1); + + // Boolean expressions + + // The following functions create Boolean expressions. The children + // provided as arguments must be of type Boolean (except for the + // function vc_iteExpr(). In the case of vc_iteExpr() the + // conditional must always be Boolean, but the ifthenpart + // (resp. elsepart) can be bit-vector or Boolean type. But, the + // ifthenpart and elsepart must be both of the same type) + Expr vc_trueExpr(VC vc); + Expr vc_falseExpr(VC vc); + Expr vc_notExpr(VC vc, Expr child); + Expr vc_andExpr(VC vc, Expr left, Expr right); + Expr vc_andExprN(VC vc, Expr* children, int numOfChildNodes); + Expr vc_orExpr(VC vc, Expr left, Expr right); + Expr vc_orExprN(VC vc, Expr* children, int numOfChildNodes); + Expr vc_impliesExpr(VC vc, Expr hyp, Expr conc); + Expr vc_iffExpr(VC vc, Expr left, Expr right); + //The output type of vc_iteExpr can be Boolean (formula-level ite) + //or bit-vector (word-level ite) + Expr vc_iteExpr(VC vc, Expr conditional, Expr ifthenpart, Expr elsepart); + + //Boolean to single bit BV Expression + Expr vc_boolToBVExpr(VC vc, Expr form); + + // Arrays + + //! Create an expression for the value of array at the given index + Expr vc_readExpr(VC vc, Expr array, Expr index); + + //! Array update; equivalent to "array WITH [index] := newValue" + Expr vc_writeExpr(VC vc, Expr array, Expr index, Expr newValue); + + // Expr I/O + //! Expr vc_parseExpr(VC vc, char* s); + + //! Prints 'e' to stdout. + void vc_printExpr(VC vc, Expr e); + + //! Prints 'e' into an open file descriptor 'fd' + void vc_printExprFile(VC vc, Expr e, int fd); + + //! Prints state of 'vc' into malloc'd buffer '*buf' and stores the + // length into '*len'. It is the responsibility of the caller to + // free the buffer. + //void vc_printStateToBuffer(VC vc, char **buf, unsigned long *len); + + //! Prints 'e' to malloc'd buffer '*buf'. Sets '*len' to the length of + // the buffer. It is the responsibility of the caller to free the buffer. + void vc_printExprToBuffer(VC vc, Expr e, char **buf, unsigned long * len); + + //! Prints counterexample to stdout. + void vc_printCounterExample(VC vc); + + //! Prints variable declarations to stdout. + void vc_printVarDecls(VC vc); + + //! Prints asserts to stdout. The flag simplify_print must be set to + //"1" if you wish simplification to occur dring printing. It must be + //set to "0" otherwise + void vc_printAsserts(VC vc, int simplify_print); + + //! Prints the state of the query to malloc'd buffer '*buf' and + //stores ! the length of the buffer to '*len'. It is the + //responsibility of the caller to free the buffer. The flag + //simplify_print must be set to "1" if you wish simplification to + //occur dring printing. It must be set to "0" otherwise + void vc_printQueryStateToBuffer(VC vc, Expr e, + char **buf, unsigned long *len, int simplify_print); + + //! Similar to vc_printQueryStateToBuffer() + void vc_printCounterExampleToBuffer(VC vc, char **buf,unsigned long *len); + + //! Prints query to stdout. + void vc_printQuery(VC vc); + + ///////////////////////////////////////////////////////////////////////////// + // Context-related methods // + ///////////////////////////////////////////////////////////////////////////// + + //! Assert a new formula in the current context. + /*! The formula must have Boolean type. */ + void vc_assertFormula(VC vc, Expr e); + + //! Simplify e with respect to the current context + Expr vc_simplify(VC vc, Expr e); + + //! Check validity of e in the current context. e must be a FORMULA + // + //if returned 0 then input is INVALID. + // + //if returned 1 then input is VALID + // + //if returned 2 then ERROR + int vc_query(VC vc, Expr e); + + //! Return the counterexample after a failed query. + Expr vc_getCounterExample(VC vc, Expr e); + + //! get size of counterexample, i.e. the number of variables/array + //locations in the counterexample. + int vc_counterexample_size(VC vc); + + //! Checkpoint the current context and increase the scope level + void vc_push(VC vc); + + //! Restore the current context to its state at the last checkpoint + void vc_pop(VC vc); + + //! Return an int from a constant bitvector expression + int getBVInt(Expr e); + //! Return an unsigned int from a constant bitvector expression + unsigned int getBVUnsigned(Expr e); + //! Return an unsigned long long int from a constant bitvector expressions + unsigned long long int getBVUnsignedLongLong(Expr e); + + /**************************/ + /* BIT VECTOR OPERATIONS */ + /**************************/ + Type vc_bvType(VC vc, int no_bits); + Type vc_bv32Type(VC vc); + + Expr vc_bvConstExprFromStr(VC vc, char* binary_repr); + Expr vc_bvConstExprFromInt(VC vc, int n_bits, unsigned int value); + Expr vc_bvConstExprFromLL(VC vc, int n_bits, unsigned long long value); + Expr vc_bv32ConstExprFromInt(VC vc, unsigned int value); + + Expr vc_bvConcatExpr(VC vc, Expr left, Expr right); + Expr vc_bvPlusExpr(VC vc, int n_bits, Expr left, Expr right); + Expr vc_bv32PlusExpr(VC vc, Expr left, Expr right); + Expr vc_bvMinusExpr(VC vc, int n_bits, Expr left, Expr right); + Expr vc_bv32MinusExpr(VC vc, Expr left, Expr right); + Expr vc_bvMultExpr(VC vc, int n_bits, Expr left, Expr right); + Expr vc_bv32MultExpr(VC vc, Expr left, Expr right); + // left divided by right i.e. left/right + Expr vc_bvDivExpr(VC vc, int n_bits, Expr left, Expr right); + // left modulo right i.e. left%right + Expr vc_bvModExpr(VC vc, int n_bits, Expr left, Expr right); + // signed left divided by right i.e. left/right + Expr vc_sbvDivExpr(VC vc, int n_bits, Expr left, Expr right); + // signed left modulo right i.e. left%right + Expr vc_sbvModExpr(VC vc, int n_bits, Expr left, Expr right); + + Expr vc_bvLtExpr(VC vc, Expr left, Expr right); + Expr vc_bvLeExpr(VC vc, Expr left, Expr right); + Expr vc_bvGtExpr(VC vc, Expr left, Expr right); + Expr vc_bvGeExpr(VC vc, Expr left, Expr right); + + Expr vc_sbvLtExpr(VC vc, Expr left, Expr right); + Expr vc_sbvLeExpr(VC vc, Expr left, Expr right); + Expr vc_sbvGtExpr(VC vc, Expr left, Expr right); + Expr vc_sbvGeExpr(VC vc, Expr left, Expr right); + + Expr vc_bvUMinusExpr(VC vc, Expr child); + + // bitwise operations: these are terms not formulas + Expr vc_bvAndExpr(VC vc, Expr left, Expr right); + Expr vc_bvOrExpr(VC vc, Expr left, Expr right); + Expr vc_bvXorExpr(VC vc, Expr left, Expr right); + Expr vc_bvNotExpr(VC vc, Expr child); + + Expr vc_bvLeftShiftExpr(VC vc, int sh_amt, Expr child); + Expr vc_bvRightShiftExpr(VC vc, int sh_amt, Expr child); + /* Same as vc_bvLeftShift only that the answer in 32 bits long */ + Expr vc_bv32LeftShiftExpr(VC vc, int sh_amt, Expr child); + /* Same as vc_bvRightShift only that the answer in 32 bits long */ + Expr vc_bv32RightShiftExpr(VC vc, int sh_amt, Expr child); + Expr vc_bvVar32LeftShiftExpr(VC vc, Expr sh_amt, Expr child); + Expr vc_bvVar32RightShiftExpr(VC vc, Expr sh_amt, Expr child); + Expr vc_bvVar32DivByPowOfTwoExpr(VC vc, Expr child, Expr rhs); + + Expr vc_bvExtract(VC vc, Expr child, int high_bit_no, int low_bit_no); + + //accepts a bitvector and position, and returns a boolean + //corresponding to that position. More precisely, it return the + //equation (x[bit_no:bit_no] = 0) + //FIXME = 1 ? + Expr vc_bvBoolExtract(VC vc, Expr x, int bit_no); + Expr vc_bvSignExtend(VC vc, Expr child, int nbits); + + /*C pointer support: C interface to support C memory arrays in CVCL */ + Expr vc_bvCreateMemoryArray(VC vc, char * arrayName); + Expr vc_bvReadMemoryArray(VC vc, + Expr array, Expr byteIndex, int numOfBytes); + Expr vc_bvWriteToMemoryArray(VC vc, + Expr array, Expr byteIndex, + Expr element, int numOfBytes); + Expr vc_bv32ConstExprFromInt(VC vc, unsigned int value); + + // return a string representation of the Expr e. The caller is responsible + // for deallocating the string with free() + char* exprString(Expr e); + + // return a string representation of the Type t. The caller is responsible + // for deallocating the string with free() + char* typeString(Type t); + + Expr getChild(Expr e, int i); + + //1.if input expr is TRUE then the function returns 1; + // + //2.if input expr is FALSE then function returns 0; + // + //3.otherwise the function returns -1 + int vc_isBool(Expr e); + + /* Register the given error handler to be called for each fatal error.*/ + void vc_registerErrorHandler(void (*error_hdlr)(const char* err_msg)); + + int vc_getHashQueryStateToBuffer(VC vc, Expr query); + + //destroys the STP instance, and removes all the created expressions + void vc_Destroy(VC vc); + + //deletes the expression e + void vc_DeleteExpr(Expr e); + + //Get the whole counterexample from the current context + WholeCounterExample vc_getWholeCounterExample(VC vc); + + //Get the value of a term expression from the CounterExample + Expr vc_getTermFromCounterExample(VC vc, Expr e, WholeCounterExample c); + + //Kinds of Expr + enum exprkind_t{ + UNDEFINED, + SYMBOL, + BVCONST, + BVNEG, + BVCONCAT, + BVOR, + BVAND, + BVXOR, + BVNAND, + BVNOR, + BVXNOR, + BVEXTRACT, + BVLEFTSHIFT, + BVRIGHTSHIFT, + BVSRSHIFT, + BVVARSHIFT, + BVPLUS, + BVSUB, + BVUMINUS, + BVMULTINVERSE, + BVMULT, + BVDIV, + BVMOD, + SBVDIV, + SBVMOD, + BVSX, + BOOLVEC, + ITE, + BVGETBIT, + BVLT, + BVLE, + BVGT, + BVGE, + BVSLT, + BVSLE, + BVSGT, + BVSGE, + EQ, + NEQ, + FALSE, + TRUE, + NOT, + AND, + OR, + NAND, + NOR, + XOR, + IFF, + IMPLIES, + READ, + WRITE, + ARRAY, + BITVECTOR, + BOOLEAN + }; + + // type of expression + enum type_t { + BOOLEAN_TYPE = 0, + BITVECTOR_TYPE, + ARRAY_TYPE, + UNKNOWN_TYPE + }; + + // get the kind of the expression + exprkind_t getExprKind (Expr e); + + // get the number of children nodes + int getDegree (Expr e); + + // get the bv length + int getBVLength(Expr e); + + // get expression type + type_t getType (Expr e); + + // get value bit width + int getVWidth (Expr e); + + // get index bit width + int getIWidth (Expr e); + + // Prints counterexample to an open file descriptor 'fd' + void vc_printCounterExampleFile(VC vc, int fd); + + // get name of expression. must be a variable. + const char* exprName(Expr e); + + // get the node ID of an Expr. + int getExprID (Expr ex); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/stp/c_interface/fdstream.h b/stp/c_interface/fdstream.h new file mode 100644 index 00000000..2cff613c --- /dev/null +++ b/stp/c_interface/fdstream.h @@ -0,0 +1,186 @@ +/*! @brief The following code declares classes to read from and write to + * file descriptore or file handles. + * + * See + * http://www.josuttis.com/cppcode + * for details and the latest version. + * + * - open: + * - integrating BUFSIZ on some systems? + * - optimized reading of multiple characters + * - stream for reading AND writing + * - i18n + * + * (C) Copyright Nicolai M. Josuttis 2001. + * Permission to copy, use, modify, sell and distribute this software + * is granted provided this copyright notice appears in all copies. + * This software is provided "as is" without express or implied + * warranty, and with no claim as to its suitability for any purpose. + * + * Version: Jul 28, 2002 + * History: + * Jul 28, 2002: bugfix memcpy() => memmove() + * fdinbuf::underflow(): cast for return statements + * Aug 05, 2001: first public version + */ +#ifndef BOOST_FDSTREAM_HPP +#define BOOST_FDSTREAM_HPP + +#include <istream> +#include <ostream> +#include <streambuf> + + +// for EOF: +#include <cstdio> +// for memmove(): +#include <cstring> + + +// low-level read and write functions +#ifdef _MSC_VER +# include <io.h> +#else +# include <unistd.h> +//extern "C" { +// int write (int fd, const char* buf, int num); +// int read (int fd, char* buf, int num); +//} +#endif + + +// BEGIN namespace BOOST +namespace std { + + +/************************************************************ + * fdostream + * - a stream that writes on a file descriptor + ************************************************************/ + + +class fdoutbuf : public std::streambuf { + protected: + int fd; // file descriptor + public: + // constructor + fdoutbuf (int _fd) : fd(_fd) { + } + protected: + // write one character + virtual int_type overflow (int_type c) { + if (c != EOF) { + char z = c; + if (write (fd, &z, 1) != 1) { + return EOF; + } + } + return c; + } + // write multiple characters + virtual + std::streamsize xsputn (const char* s, + std::streamsize num) { + return write(fd,s,num); + } +}; + +class fdostream : public std::ostream { + protected: + fdoutbuf buf; + public: + fdostream (int fd) : std::ostream(0), buf(fd) { + rdbuf(&buf); + } +}; + + +/************************************************************ + * fdistream + * - a stream that reads on a file descriptor + ************************************************************/ + +class fdinbuf : public std::streambuf { + protected: + int fd; // file descriptor + protected: + /* data buffer: + * - at most, pbSize characters in putback area plus + * - at most, bufSize characters in ordinary read buffer + */ + static const int pbSize = 4; // size of putback area + static const int bufSize = 1024; // size of the data buffer + char buffer[bufSize+pbSize]; // data buffer + + public: + /* constructor + * - initialize file descriptor + * - initialize empty data buffer + * - no putback area + * => force underflow() + */ + fdinbuf (int _fd) : fd(_fd) { + setg (buffer+pbSize, // beginning of putback area + buffer+pbSize, // read position + buffer+pbSize); // end position + } + + protected: + // insert new characters into the buffer + virtual int_type underflow () { +#ifndef _MSC_VER + using std::memmove; +#endif + + // is read position before end of buffer? + if (gptr() < egptr()) { + return traits_type::to_int_type(*gptr()); + } + + /* process size of putback area + * - use number of characters read + * - but at most size of putback area + */ + int numPutback; + numPutback = gptr() - eback(); + if (numPutback > pbSize) { + numPutback = pbSize; + } + + /* copy up to pbSize characters previously read into + * the putback area + */ + memmove (buffer+(pbSize-numPutback), gptr()-numPutback, + numPutback); + + // read at most bufSize new characters + int num; + num = read (fd, buffer+pbSize, bufSize); + if (num <= 0) { + // ERROR or EOF + return EOF; + } + + // reset buffer pointers + setg (buffer+(pbSize-numPutback), // beginning of putback area + buffer+pbSize, // read position + buffer+pbSize+num); // end of buffer + + // return next character + return traits_type::to_int_type(*gptr()); + } +}; + +class fdistream : public std::istream { + protected: + fdinbuf buf; + public: + fdistream (int fd) : std::istream(0), buf(fd) { + rdbuf(&buf); + } +}; + + +} // END namespace boost + +#endif /*BOOST_FDSTREAM_HPP*/ diff --git a/stp/constantbv/Makefile b/stp/constantbv/Makefile new file mode 100644 index 00000000..cd94ad94 --- /dev/null +++ b/stp/constantbv/Makefile @@ -0,0 +1,13 @@ +include ../Makefile.common + +SRCS = constantbv.cpp +OBJS = $(SRCS:.cpp=.o) + +libconstantbv.a: $(OBJS) + $(AR) rc $@ $^ + $(RANLIB) $@ + +clean: + rm -rf *.o *~ *.a .#* + +constantbv.o: constantbv.h diff --git a/stp/constantbv/constantbv.cpp b/stp/constantbv/constantbv.cpp new file mode 100644 index 00000000..65698981 --- /dev/null +++ b/stp/constantbv/constantbv.cpp @@ -0,0 +1,3571 @@ +/*****************************************************************************/ +/* AUTHOR: */ +/*****************************************************************************/ +/* */ +/* Steffen Beyer */ +/* mailto:sb@engelschall.com */ +/* http://www.engelschall.com/u/sb/download/ */ +/* */ +/*****************************************************************************/ +/* COPYRIGHT: */ +/*****************************************************************************/ +/* */ +/* Copyright (c) 1995 - 2004 by Steffen Beyer. */ +/* All rights reserved. */ +/* */ +/*****************************************************************************/ +/* LICENSE: */ +/*****************************************************************************/ +/* */ +/* This library is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public */ +/* License as published by the Free Software Foundation; either */ +/* version 2 of the License, || (at your option) any later version. */ +/* */ +/* This library is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY || FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ +/* Library General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Library General Public */ +/* License along with this library; if not, write to the */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* || download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* MODULE NAME: constantbv.cpp MODULE TYPE:constantbv*/ +/*****************************************************************************/ +/* MODULE IMPORTS: */ +/*****************************************************************************/ +#include <stdio.h> +#include <stdlib.h> /* MODULE TYPE: (sys) */ +#include <limits.h> /* MODULE TYPE: (sys) */ +#include <string.h> /* MODULE TYPE: (sys) */ +#include <ctype.h> /* MODULE TYPE: (sys) */ +#include "constantbv.h" + +namespace CONSTANTBV { +/*****************************************************************************/ +/* MODULE IMPLEMENTATION: */ +/*****************************************************************************/ + /**********************************************/ + /* global implementation-intrinsic constants: */ + /**********************************************/ + +#define BIT_VECTOR_HIDDEN_WORDS 3 + + /*****************************************************************/ + /* global machine-dependent constants (set by "BitVector_Boot"): */ + /*****************************************************************/ + +static unsigned int BITS; /* = # of bits in machine word (must be power of 2) */ +static unsigned int MODMASK; /* = BITS - 1 (mask for calculating modulo BITS) */ +static unsigned int LOGBITS; /* = ld(BITS) (logarithmus dualis) */ +static unsigned int FACTOR; /* = ld(BITS / 8) (ld of # of bytes) */ + +static unsigned int LSB = 1; /* = mask for least significant bit */ +static unsigned int MSB; /* = mask for most significant bit */ + +static unsigned int LONGBITS; /* = # of bits in unsigned long */ + +static unsigned int LOG10; /* = logarithm to base 10 of BITS - 1 */ +static unsigned int EXP10; /* = largest possible power of 10 in signed int */ + + /********************************************************************/ + /* global bit mask table for fast access (set by "BitVector_Boot"): */ + /********************************************************************/ + +static unsigned int * BITMASKTAB; + + /*****************************/ + /* global macro definitions: */ + /*****************************/ + +#define BIT_VECTOR_ZERO_WORDS(target,count) \ + while (count-- > 0) *target++ = 0; + +#define BIT_VECTOR_FILL_WORDS(target,fill,count) \ + while (count-- > 0) *target++ = fill; + +#define BIT_VECTOR_FLIP_WORDS(target,flip,count) \ + while (count-- > 0) *target++ ^= flip; + +#define BIT_VECTOR_COPY_WORDS(target,source,count) \ + while (count-- > 0) *target++ = *source++; + +#define BIT_VECTOR_BACK_WORDS(target,source,count) \ + { target += count; source += count; while (count-- > 0) *--target = *--source; } + +#define BIT_VECTOR_CLR_BIT(address,index) \ + *(address+(index>>LOGBITS)) &= ~ BITMASKTAB[index & MODMASK]; + +#define BIT_VECTOR_SET_BIT(address,index) \ + *(address+(index>>LOGBITS)) |= BITMASKTAB[index & MODMASK]; + +#define BIT_VECTOR_TST_BIT(address,index) \ + ((*(address+(index>>LOGBITS)) & BITMASKTAB[index & MODMASK]) != 0) + +#define BIT_VECTOR_FLP_BIT(address,index,mask) \ + (mask = BITMASKTAB[index & MODMASK]), \ + (((*(addr+(index>>LOGBITS)) ^= mask) & mask) != 0) + +#define BIT_VECTOR_DIGITIZE(type,value,digit) \ + value = (type) ((digit = value) / 10); \ + digit -= value * 10; \ + digit += (type) '0'; + + /*********************************************************/ + /* private low-level functions (potentially dangerous!): */ + /*********************************************************/ + +static unsigned int power10(unsigned int x) { + unsigned int y = 1; + + while (x-- > 0) y *= 10; + return(y); +} + +static void BIT_VECTOR_zro_words(unsigned int * addr, unsigned int count) { + BIT_VECTOR_ZERO_WORDS(addr,count) +} + +static void BIT_VECTOR_cpy_words(unsigned int * target, + unsigned int * source, unsigned int count) { + BIT_VECTOR_COPY_WORDS(target,source,count) +} + +static void BIT_VECTOR_mov_words(unsigned int * target, + unsigned int * source, unsigned int count) { + if (target != source) { + if (target < source) BIT_VECTOR_COPY_WORDS(target,source,count) + else BIT_VECTOR_BACK_WORDS(target,source,count) + } +} + +static void BIT_VECTOR_ins_words(unsigned int * addr, + unsigned int total, unsigned int count, boolean clear) { + unsigned int length; + + if ((total > 0) && (count > 0)) { + if (count > total) count = total; + length = total - count; + if (length > 0) BIT_VECTOR_mov_words(addr+count,addr,length); + if (clear) BIT_VECTOR_zro_words(addr,count); + } +} + +static void BIT_VECTOR_del_words(unsigned int * addr, + unsigned int total, unsigned int count, boolean clear) { + unsigned int length; + + if ((total > 0) && (count > 0)) { + if (count > total) count = total; + length = total - count; + if (length > 0) BIT_VECTOR_mov_words(addr,addr+count,length); + if (clear) BIT_VECTOR_zro_words(addr+length,count); + } +} + +static void BIT_VECTOR_reverse(unsigned char * string, unsigned int length) { + unsigned char * last; + unsigned char temp; + + if (length > 1) { + last = string + length - 1; + while (string < last) { + temp = *string; + *string = *last; + *last = temp; + string++; + last--; + } + } +} + +static unsigned int BIT_VECTOR_int2str(unsigned char * string, unsigned int value) { + unsigned int length; + unsigned int digit; + unsigned char * work; + + work = string; + if (value > 0) { + length = 0; + while (value > 0) { + BIT_VECTOR_DIGITIZE(unsigned int,value,digit) + *work++ = (unsigned char) digit; + length++; + } + BIT_VECTOR_reverse(string,length); + } + else { + length = 1; + *work++ = (unsigned char) '0'; + } + return(length); +} + +static unsigned int BIT_VECTOR_str2int(unsigned char * string, unsigned int *value) { + unsigned int length; + unsigned int digit; + + *value = 0; + length = 0; + digit = (unsigned int) *string++; + /* separate because isdigit() is likely a macro! */ + while (isdigit((int)digit) != 0) { + length++; + digit -= (unsigned int) '0'; + if (*value) *value *= 10; + *value += digit; + digit = (unsigned int) *string++; + } + return(length); +} + + /********************************************/ + /* routine to convert error code to string: */ + /********************************************/ + +unsigned char * BitVector_Error(ErrCode error) { + switch (error) { + case ErrCode_Ok: return( (unsigned char *) NULL ); break; + case ErrCode_Type: return( (unsigned char *) ERRCODE_TYPE ); break; + case ErrCode_Bits: return( (unsigned char *) ERRCODE_BITS ); break; + case ErrCode_Word: return( (unsigned char *) ERRCODE_WORD ); break; + case ErrCode_Long: return( (unsigned char *) ERRCODE_LONG ); break; + case ErrCode_Powr: return( (unsigned char *) ERRCODE_POWR ); break; + case ErrCode_Loga: return( (unsigned char *) ERRCODE_LOGA ); break; + case ErrCode_Null: return( (unsigned char *) ERRCODE_NULL ); break; + case ErrCode_Indx: return( (unsigned char *) ERRCODE_INDX ); break; + case ErrCode_Ordr: return( (unsigned char *) ERRCODE_ORDR ); break; + case ErrCode_Size: return( (unsigned char *) ERRCODE_SIZE ); break; + case ErrCode_Pars: return( (unsigned char *) ERRCODE_PARS ); break; + case ErrCode_Ovfl: return( (unsigned char *) ERRCODE_OVFL ); break; + case ErrCode_Same: return( (unsigned char *) ERRCODE_SAME ); break; + case ErrCode_Expo: return( (unsigned char *) ERRCODE_EXPO ); break; + case ErrCode_Zero: return( (unsigned char *) ERRCODE_ZERO ); break; + default: return( (unsigned char *) ERRCODE_OOPS ); break; + } +} + + /*****************************************/ + /* automatic self-configuration routine: */ + /*****************************************/ + + /*******************************************************/ + /* */ + /* MUST be called once prior to any other function */ + /* to initialize the machine dependent constants */ + /* of this package! (But call only ONCE, or you */ + /* will suffer memory leaks!) */ + /* */ + /*******************************************************/ + +ErrCode BitVector_Boot(void) { + unsigned long longsample = 1L; + unsigned int sample = LSB; + unsigned int lsb; + + if (sizeof(unsigned int) > sizeof(size_t)) return(ErrCode_Type); + + BITS = 1; + while (sample <<= 1) BITS++; /* determine # of bits in a machine word */ + + if (BITS != (sizeof(unsigned int) << 3)) return(ErrCode_Bits); + + if (BITS < 16) return(ErrCode_Word); + + LONGBITS = 1; + while (longsample <<= 1) LONGBITS++; /* = # of bits in an unsigned long */ + + if (BITS > LONGBITS) return(ErrCode_Long); + + LOGBITS = 0; + sample = BITS; + lsb = (sample & LSB); + while ((sample >>= 1) && (! lsb)) { + LOGBITS++; + lsb = (sample & LSB); + } + + if (sample) return(ErrCode_Powr); /* # of bits is not a power of 2! */ + + if (BITS != (LSB << LOGBITS)) return(ErrCode_Loga); + + MODMASK = BITS - 1; + FACTOR = LOGBITS - 3; /* ld(BITS / 8) = ld(BITS) - ld(8) = ld(BITS) - 3 */ + MSB = (LSB << MODMASK); + + BITMASKTAB = (unsigned int * ) malloc((size_t) (BITS << FACTOR)); + + if (BITMASKTAB == NULL) return(ErrCode_Null); + + for ( sample = 0; sample < BITS; sample++ ) { + BITMASKTAB[sample] = (LSB << sample); + } + + LOG10 = (unsigned int) (MODMASK * 0.30103); /* = (BITS - 1) * ( ln 2 / ln 10 ) */ + EXP10 = power10(LOG10); + + return(ErrCode_Ok); +} + +unsigned int BitVector_Size(unsigned int bits) { /* bit vector size (# of words) */ + unsigned int size; + + size = bits >> LOGBITS; + if (bits & MODMASK) size++; + return(size); +} + +unsigned int BitVector_Mask(unsigned int bits) /* bit vector mask (unused bits) */ +{ + unsigned int mask; + + mask = bits & MODMASK; + if (mask) mask = (unsigned int) ~(~0L << mask); else mask = (unsigned int) ~0L; + return(mask); +} + +unsigned char * BitVector_Version(void) +{ + return((unsigned char *)"6.4"); +} + +unsigned int BitVector_Word_Bits(void) +{ + return(BITS); +} + +unsigned int BitVector_Long_Bits(void) +{ + return(LONGBITS); +} + +/********************************************************************/ +/* */ +/* WARNING: Do not "free()" constant character strings, i.e., */ +/* don't call "BitVector_Dispose()" for strings returned */ +/* by "BitVector_Error()" or "BitVector_Version()"! */ +/* */ +/* ONLY call this function for strings allocated with "malloc()", */ +/* i.e., the strings returned by the functions "BitVector_to_*()" */ +/* and "BitVector_Block_Read()"! */ +/* */ +/********************************************************************/ + +void BitVector_Dispose(unsigned char * string) /* free string */ +{ + if (string != NULL) free((void *) string); +} + +void BitVector_Destroy(unsigned int * addr) /* free bitvec */ +{ + if (addr != NULL) + { + addr -= BIT_VECTOR_HIDDEN_WORDS; + free((void *) addr); + } +} + +void BitVector_Destroy_List(unsigned int * * list, unsigned int count) /* free list */ +{ + unsigned int * * slot; + + if (list != NULL) + { + slot = list; + while (count-- > 0) + { + BitVector_Destroy(*slot++); + } + free((void *) list); + } +} + +unsigned int * BitVector_Create(unsigned int bits, boolean clear) /* malloc */ +{ + unsigned int size; + unsigned int mask; + unsigned int bytes; + unsigned int * addr; + unsigned int * zero; + + size = BitVector_Size(bits); + mask = BitVector_Mask(bits); + bytes = (size + BIT_VECTOR_HIDDEN_WORDS) << FACTOR; + addr = (unsigned int * ) malloc((size_t) bytes); + if (addr != NULL) + { + *addr++ = bits; + *addr++ = size; + *addr++ = mask; + if (clear) + { + zero = addr; + BIT_VECTOR_ZERO_WORDS(zero,size) + } + } + return(addr); +} + +unsigned int * * BitVector_Create_List(unsigned int bits, boolean clear, unsigned int count) +{ + unsigned int * * list = NULL; + unsigned int * * slot; + unsigned int * addr; + unsigned int i; + + if (count > 0) + { + list = (unsigned int * * ) malloc(sizeof(unsigned int * ) * count); + if (list != NULL) + { + slot = list; + for ( i = 0; i < count; i++ ) + { + addr = BitVector_Create(bits,clear); + if (addr == NULL) + { + BitVector_Destroy_List(list,i); + return(NULL); + } + *slot++ = addr; + } + } + } + return(list); +} + +unsigned int * BitVector_Resize(unsigned int * oldaddr, unsigned int bits) /* realloc */ +{ + unsigned int bytes; + unsigned int oldsize; + unsigned int oldmask; + unsigned int newsize; + unsigned int newmask; + unsigned int * newaddr; + unsigned int * source; + unsigned int * target; + + oldsize = size_(oldaddr); + oldmask = mask_(oldaddr); + newsize = BitVector_Size(bits); + newmask = BitVector_Mask(bits); + if (oldsize > 0) *(oldaddr+oldsize-1) &= oldmask; + if (newsize <= oldsize) + { + newaddr = oldaddr; + bits_(newaddr) = bits; + size_(newaddr) = newsize; + mask_(newaddr) = newmask; + if (newsize > 0) *(newaddr+newsize-1) &= newmask; + } + else + { + bytes = (newsize + BIT_VECTOR_HIDDEN_WORDS) << FACTOR; + newaddr = (unsigned int * ) malloc((size_t) bytes); + if (newaddr != NULL) + { + *newaddr++ = bits; + *newaddr++ = newsize; + *newaddr++ = newmask; + target = newaddr; + source = oldaddr; + newsize -= oldsize; + BIT_VECTOR_COPY_WORDS(target,source,oldsize) + BIT_VECTOR_ZERO_WORDS(target,newsize) + } + BitVector_Destroy(oldaddr); + } + return(newaddr); +} + +unsigned int * BitVector_Shadow(unsigned int * addr) /* makes new, same size but empty */ +{ + return( BitVector_Create(bits_(addr),true) ); +} + +unsigned int * BitVector_Clone(unsigned int * addr) /* makes exact duplicate */ +{ + unsigned int bits; + unsigned int * twin; + + bits = bits_(addr); + twin = BitVector_Create(bits,false); + if ((twin != NULL) && (bits > 0)) + BIT_VECTOR_cpy_words(twin,addr,size_(addr)); + return(twin); +} + +unsigned int * BitVector_Concat(unsigned int * X, unsigned int * Y) /* returns concatenation */ +{ + /* BEWARE that X = most significant part, Y = least significant part! */ + + unsigned int bitsX; + unsigned int bitsY; + unsigned int bitsZ; + unsigned int * Z; + + bitsX = bits_(X); + bitsY = bits_(Y); + bitsZ = bitsX + bitsY; + Z = BitVector_Create(bitsZ,false); + if ((Z != NULL) && (bitsZ > 0)) + { + BIT_VECTOR_cpy_words(Z,Y,size_(Y)); + BitVector_Interval_Copy(Z,X,bitsY,0,bitsX); + *(Z+size_(Z)-1) &= mask_(Z); + } + return(Z); +} + +void BitVector_Copy(unsigned int * X, unsigned int * Y) /* X = Y */ +{ + unsigned int sizeX = size_(X); + unsigned int sizeY = size_(Y); + unsigned int maskX = mask_(X); + unsigned int maskY = mask_(Y); + unsigned int fill = 0; + unsigned int * lastX; + unsigned int * lastY; + + if ((X != Y) && (sizeX > 0)) + { + lastX = X + sizeX - 1; + if (sizeY > 0) + { + lastY = Y + sizeY - 1; + if ( (*lastY & (maskY & ~ (maskY >> 1))) == 0 ) *lastY &= maskY; + else + { + fill = (unsigned int) ~0L; + *lastY |= ~ maskY; + } + while ((sizeX > 0) && (sizeY > 0)) + { + *X++ = *Y++; + sizeX--; + sizeY--; + } + *lastY &= maskY; + } + while (sizeX-- > 0) *X++ = fill; + *lastX &= maskX; + } +} + +void BitVector_Empty(unsigned int * addr) /* X = {} clr all */ +{ + unsigned int size = size_(addr); + + BIT_VECTOR_ZERO_WORDS(addr,size) +} + +void BitVector_Fill(unsigned int * addr) /* X = ~{} set all */ +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int fill = (unsigned int) ~0L; + + if (size > 0) + { + BIT_VECTOR_FILL_WORDS(addr,fill,size) + *(--addr) &= mask; + } +} + +void BitVector_Flip(unsigned int * addr) /* X = ~X flip all */ +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int flip = (unsigned int) ~0L; + + if (size > 0) + { + BIT_VECTOR_FLIP_WORDS(addr,flip,size) + *(--addr) &= mask; + } +} + +void BitVector_Primes(unsigned int * addr) +{ + unsigned int bits = bits_(addr); + unsigned int size = size_(addr); + unsigned int * work; + unsigned int temp; + unsigned int i,j; + + if (size > 0) + { + temp = 0xAAAA; + i = BITS >> 4; + while (--i > 0) + { + temp <<= 16; + temp |= 0xAAAA; + } + i = size; + work = addr; + *work++ = temp ^ 0x0006; + while (--i > 0) *work++ = temp; + for ( i = 3; (j = i * i) < bits; i += 2 ) + { + for ( ; j < bits; j += i ) BIT_VECTOR_CLR_BIT(addr,j) + } + *(addr+size-1) &= mask_(addr); + } +} + +void BitVector_Reverse(unsigned int * X, unsigned int * Y) +{ + unsigned int bits = bits_(X); + unsigned int mask; + unsigned int bit; + unsigned int value; + + if (bits > 0) + { + if (X == Y) BitVector_Interval_Reverse(X,0,bits-1); + else if (bits == bits_(Y)) + { +/* mask = mask_(Y); */ +/* mask &= ~ (mask >> 1); */ + mask = BITMASKTAB[(bits-1) & MODMASK]; + Y += size_(Y) - 1; + value = 0; + bit = LSB; + while (bits-- > 0) + { + if ((*Y & mask) != 0) + { + value |= bit; + } + if (! (mask >>= 1)) + { + Y--; + mask = MSB; + } + if (! (bit <<= 1)) + { + *X++ = value; + value = 0; + bit = LSB; + } + } + if (bit > LSB) *X = value; + } + } +} + +void BitVector_Interval_Empty(unsigned int * addr, unsigned int lower, unsigned int upper) +{ /* X = X \ [lower..upper] */ + unsigned int bits = bits_(addr); + unsigned int size = size_(addr); + unsigned int * loaddr; + unsigned int * hiaddr; + unsigned int lobase; + unsigned int hibase; + unsigned int lomask; + unsigned int himask; + unsigned int diff; + + if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper)) + { + lobase = lower >> LOGBITS; + hibase = upper >> LOGBITS; + diff = hibase - lobase; + loaddr = addr + lobase; + hiaddr = addr + hibase; + + lomask = (unsigned int) (~0L << (lower & MODMASK)); + himask = (unsigned int) ~((~0L << (upper & MODMASK)) << 1); + + if (diff == 0) + { + *loaddr &= ~ (lomask & himask); + } + else + { + *loaddr++ &= ~ lomask; + while (--diff > 0) + { + *loaddr++ = 0; + } + *hiaddr &= ~ himask; + } + } +} + +void BitVector_Interval_Fill(unsigned int * addr, unsigned int lower, unsigned int upper) +{ /* X = X + [lower..upper] */ + unsigned int bits = bits_(addr); + unsigned int size = size_(addr); + unsigned int fill = (unsigned int) ~0L; + unsigned int * loaddr; + unsigned int * hiaddr; + unsigned int lobase; + unsigned int hibase; + unsigned int lomask; + unsigned int himask; + unsigned int diff; + + if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper)) + { + lobase = lower >> LOGBITS; + hibase = upper >> LOGBITS; + diff = hibase - lobase; + loaddr = addr + lobase; + hiaddr = addr + hibase; + + lomask = (unsigned int) (~0L << (lower & MODMASK)); + himask = (unsigned int) ~((~0L << (upper & MODMASK)) << 1); + + if (diff == 0) + { + *loaddr |= (lomask & himask); + } + else + { + *loaddr++ |= lomask; + while (--diff > 0) + { + *loaddr++ = fill; + } + *hiaddr |= himask; + } + *(addr+size-1) &= mask_(addr); + } +} + +void BitVector_Interval_Flip(unsigned int * addr, unsigned int lower, unsigned int upper) +{ /* X = X ^ [lower..upper] */ + unsigned int bits = bits_(addr); + unsigned int size = size_(addr); + unsigned int flip = (unsigned int) ~0L; + unsigned int * loaddr; + unsigned int * hiaddr; + unsigned int lobase; + unsigned int hibase; + unsigned int lomask; + unsigned int himask; + unsigned int diff; + + if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper)) + { + lobase = lower >> LOGBITS; + hibase = upper >> LOGBITS; + diff = hibase - lobase; + loaddr = addr + lobase; + hiaddr = addr + hibase; + + lomask = (unsigned int) (~0L << (lower & MODMASK)); + himask = (unsigned int) ~((~0L << (upper & MODMASK)) << 1); + + if (diff == 0) + { + *loaddr ^= (lomask & himask); + } + else + { + *loaddr++ ^= lomask; + while (--diff > 0) + { + *loaddr++ ^= flip; + } + *hiaddr ^= himask; + } + *(addr+size-1) &= mask_(addr); + } +} + +void BitVector_Interval_Reverse(unsigned int * addr, unsigned int lower, unsigned int upper) +{ + unsigned int bits = bits_(addr); + unsigned int * loaddr; + unsigned int * hiaddr; + unsigned int lomask; + unsigned int himask; + + if ((bits > 0) && (lower < bits) && (upper < bits) && (lower < upper)) + { + loaddr = addr + (lower >> LOGBITS); + hiaddr = addr + (upper >> LOGBITS); + lomask = BITMASKTAB[lower & MODMASK]; + himask = BITMASKTAB[upper & MODMASK]; + for ( bits = upper - lower + 1; bits > 1; bits -= 2 ) + { + if (((*loaddr & lomask) != 0) ^ ((*hiaddr & himask) != 0)) + { + *loaddr ^= lomask; /* swap bits only if they differ! */ + *hiaddr ^= himask; + } + if (! (lomask <<= 1)) + { + lomask = LSB; + loaddr++; + } + if (! (himask >>= 1)) + { + himask = MSB; + hiaddr--; + } + } + } +} + +boolean BitVector_interval_scan_inc(unsigned int * addr, unsigned int start, + unsigned int * min, unsigned int * max) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int offset; + unsigned int bitmask; + unsigned int value; + boolean empty; + + if ((size == 0) || (start >= bits_(addr))) return(false); + + *min = start; + *max = start; + + offset = start >> LOGBITS; + + *(addr+size-1) &= mask; + + addr += offset; + size -= offset; + + bitmask = BITMASKTAB[start & MODMASK]; + mask = ~ (bitmask | (bitmask - 1)); + + value = *addr++; + if ((value & bitmask) == 0) + { + value &= mask; + if (value == 0) + { + offset++; + empty = true; + while (empty && (--size > 0)) + { + if ((value = *addr++)) empty = false; else offset++; + } + if (empty) return(false); + } + start = offset << LOGBITS; + bitmask = LSB; + mask = value; + while (! (mask & LSB)) + { + bitmask <<= 1; + mask >>= 1; + start++; + } + mask = ~ (bitmask | (bitmask - 1)); + *min = start; + *max = start; + } + value = ~ value; + value &= mask; + if (value == 0) + { + offset++; + empty = true; + while (empty && (--size > 0)) + { + if ((value = ~ *addr++)) empty = false; else offset++; + } + if (empty) value = LSB; + } + start = offset << LOGBITS; + while (! (value & LSB)) + { + value >>= 1; + start++; + } + *max = --start; + return(true); +} + +boolean BitVector_interval_scan_dec(unsigned int * addr, unsigned int start, + unsigned int * min, unsigned int * max) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int offset; + unsigned int bitmask; + unsigned int value; + boolean empty; + + if ((size == 0) || (start >= bits_(addr))) return(false); + + *min = start; + *max = start; + + offset = start >> LOGBITS; + + if (offset >= size) return(false); + + *(addr+size-1) &= mask; + + addr += offset; + size = ++offset; + + bitmask = BITMASKTAB[start & MODMASK]; + mask = (bitmask - 1); + + value = *addr--; + if ((value & bitmask) == 0) + { + value &= mask; + if (value == 0) + { + offset--; + empty = true; + while (empty && (--size > 0)) + { + if ((value = *addr--)) empty = false; else offset--; + } + if (empty) return(false); + } + start = offset << LOGBITS; + bitmask = MSB; + mask = value; + while (! (mask & MSB)) + { + bitmask >>= 1; + mask <<= 1; + start--; + } + mask = (bitmask - 1); + *max = --start; + *min = start; + } + value = ~ value; + value &= mask; + if (value == 0) + { + offset--; + empty = true; + while (empty && (--size > 0)) + { + if ((value = ~ *addr--)) empty = false; else offset--; + } + if (empty) value = MSB; + } + start = offset << LOGBITS; + while (! (value & MSB)) + { + value <<= 1; + start--; + } + *min = start; + return(true); +} + +void BitVector_Interval_Copy(unsigned int * X, unsigned int * Y, unsigned int Xoffset, + unsigned int Yoffset, unsigned int length) +{ + unsigned int bitsX = bits_(X); + unsigned int bitsY = bits_(Y); + unsigned int source = 0; /* silence compiler warning */ + unsigned int target = 0; /* silence compiler warning */ + unsigned int s_lo_base; + unsigned int s_hi_base; + unsigned int s_lo_bit; + unsigned int s_hi_bit; + unsigned int s_base; + unsigned int s_lower = 0; /* silence compiler warning */ + unsigned int s_upper = 0; /* silence compiler warning */ + unsigned int s_bits; + unsigned int s_min; + unsigned int s_max; + unsigned int t_lo_base; + unsigned int t_hi_base; + unsigned int t_lo_bit; + unsigned int t_hi_bit; + unsigned int t_base; + unsigned int t_lower = 0; /* silence compiler warning */ + unsigned int t_upper = 0; /* silence compiler warning */ + unsigned int t_bits; + unsigned int t_min; + unsigned int mask; + unsigned int bits; + unsigned int select; + boolean ascending; + boolean notfirst; + unsigned int * Z = X; + + if ((length > 0) && (Xoffset < bitsX) && (Yoffset < bitsY)) + { + if ((Xoffset + length) > bitsX) length = bitsX - Xoffset; + if ((Yoffset + length) > bitsY) length = bitsY - Yoffset; + + ascending = (Xoffset <= Yoffset); + + s_lo_base = Yoffset >> LOGBITS; + s_lo_bit = Yoffset & MODMASK; + Yoffset += --length; + s_hi_base = Yoffset >> LOGBITS; + s_hi_bit = Yoffset & MODMASK; + + t_lo_base = Xoffset >> LOGBITS; + t_lo_bit = Xoffset & MODMASK; + Xoffset += length; + t_hi_base = Xoffset >> LOGBITS; + t_hi_bit = Xoffset & MODMASK; + + if (ascending) + { + s_base = s_lo_base; + t_base = t_lo_base; + } + else + { + s_base = s_hi_base; + t_base = t_hi_base; + } + s_bits = 0; + t_bits = 0; + Y += s_base; + X += t_base; + notfirst = false; + while (true) + { + if (t_bits == 0) + { + if (notfirst) + { + *X = target; + if (ascending) + { + if (t_base == t_hi_base) break; + t_base++; + X++; + } + else + { + if (t_base == t_lo_base) break; + t_base--; + X--; + } + } + select = ((t_base == t_hi_base) << 1) | (t_base == t_lo_base); + switch (select) + { + case 0: + t_lower = 0; + t_upper = BITS - 1; + t_bits = BITS; + target = 0; + break; + case 1: + t_lower = t_lo_bit; + t_upper = BITS - 1; + t_bits = BITS - t_lo_bit; + mask = (unsigned int) (~0L << t_lower); + target = *X & ~ mask; + break; + case 2: + t_lower = 0; + t_upper = t_hi_bit; + t_bits = t_hi_bit + 1; + mask = (unsigned int) ((~0L << t_upper) << 1); + target = *X & mask; + break; + case 3: + t_lower = t_lo_bit; + t_upper = t_hi_bit; + t_bits = t_hi_bit - t_lo_bit + 1; + mask = (unsigned int) (~0L << t_lower); + mask &= (unsigned int) ~((~0L << t_upper) << 1); + target = *X & ~ mask; + break; + } + } + if (s_bits == 0) + { + if (notfirst) + { + if (ascending) + { + if (s_base == s_hi_base) break; + s_base++; + Y++; + } + else + { + if (s_base == s_lo_base) break; + s_base--; + Y--; + } + } + source = *Y; + select = ((s_base == s_hi_base) << 1) | (s_base == s_lo_base); + switch (select) + { + case 0: + s_lower = 0; + s_upper = BITS - 1; + s_bits = BITS; + break; + case 1: + s_lower = s_lo_bit; + s_upper = BITS - 1; + s_bits = BITS - s_lo_bit; + break; + case 2: + s_lower = 0; + s_upper = s_hi_bit; + s_bits = s_hi_bit + 1; + break; + case 3: + s_lower = s_lo_bit; + s_upper = s_hi_bit; + s_bits = s_hi_bit - s_lo_bit + 1; + break; + } + } + notfirst = true; + if (s_bits > t_bits) + { + bits = t_bits - 1; + if (ascending) + { + s_min = s_lower; + s_max = s_lower + bits; + } + else + { + s_max = s_upper; + s_min = s_upper - bits; + } + t_min = t_lower; + } + else + { + bits = s_bits - 1; + if (ascending) t_min = t_lower; + else t_min = t_upper - bits; + s_min = s_lower; + s_max = s_upper; + } + bits++; + mask = (unsigned int) (~0L << s_min); + mask &= (unsigned int) ~((~0L << s_max) << 1); + if (s_min == t_min) target |= (source & mask); + else + { + if (s_min < t_min) target |= (source & mask) << (t_min-s_min); + else target |= (source & mask) >> (s_min-t_min); + } + if (ascending) + { + s_lower += bits; + t_lower += bits; + } + else + { + s_upper -= bits; + t_upper -= bits; + } + s_bits -= bits; + t_bits -= bits; + } + *(Z+size_(Z)-1) &= mask_(Z); + } +} + + +unsigned int * BitVector_Interval_Substitute(unsigned int * X, unsigned int * Y, + unsigned int Xoffset, unsigned int Xlength, + unsigned int Yoffset, unsigned int Ylength) +{ + unsigned int Xbits = bits_(X); + unsigned int Ybits = bits_(Y); + unsigned int limit; + unsigned int diff; + + if ((Xoffset <= Xbits) && (Yoffset <= Ybits)) + { + limit = Xoffset + Xlength; + if (limit > Xbits) + { + limit = Xbits; + Xlength = Xbits - Xoffset; + } + if ((Yoffset + Ylength) > Ybits) + { + Ylength = Ybits - Yoffset; + } + if (Xlength == Ylength) + { + if ((Ylength > 0) && ((X != Y) || (Xoffset != Yoffset))) + { + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + } + else /* Xlength != Ylength */ + { + if (Xlength > Ylength) + { + diff = Xlength - Ylength; + if (Ylength > 0) BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + if (limit < Xbits) BitVector_Delete(X,Xoffset+Ylength,diff,false); + if ((X = BitVector_Resize(X,Xbits-diff)) == NULL) return(NULL); + } + else /* Ylength > Xlength ==> Ylength > 0 */ + { + diff = Ylength - Xlength; + if (X != Y) + { + if ((X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL); + if (limit < Xbits) BitVector_Insert(X,limit,diff,false); + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* in-place */ + { + if ((Y = X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL); + if (limit >= Xbits) + { + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* limit < Xbits */ + { + BitVector_Insert(X,limit,diff,false); + if ((Yoffset+Ylength) <= limit) + { + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* overlaps or lies above critical area */ + { + if (limit <= Yoffset) + { + Yoffset += diff; + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + else /* Yoffset < limit */ + { + Xlength = limit - Yoffset; + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Xlength); + Yoffset = Xoffset + Ylength; /* = limit + diff */ + Xoffset += Xlength; + Ylength -= Xlength; + BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); + } + } + } + } + } + } + } + return(X); +} + +boolean BitVector_is_empty(unsigned int * addr) /* X == {} ? */ +{ + unsigned int size = size_(addr); + boolean r = true; + + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while (r && (size-- > 0)) r = ( *addr++ == 0 ); + } + return(r); +} + +boolean BitVector_is_full(unsigned int * addr) /* X == ~{} ? */ +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + boolean r = false; + unsigned int * last; + + if (size > 0) + { + r = true; + last = addr + size - 1; + *last |= ~ mask; + while (r && (size-- > 0)) r = ( ~ *addr++ == 0 ); + *last &= mask; + } + return(r); +} + +boolean BitVector_equal(unsigned int * X, unsigned int * Y) /* X == Y ? */ +{ + unsigned int size = size_(X); + unsigned int mask = mask_(X); + boolean r = false; + + if (bits_(X) == bits_(Y)) + { + r = true; + if (size > 0) + { + *(X+size-1) &= mask; + *(Y+size-1) &= mask; + while (r && (size-- > 0)) r = (*X++ == *Y++); + } + } + return(r); +} + +/* X <,=,> Y ? : unsigned */ +signed int BitVector_Lexicompare(unsigned int * X, unsigned int * Y) { + unsigned int bitsX = bits_(X); + unsigned int bitsY = bits_(Y); + unsigned int size = size_(X); + boolean r = true; + + if (bitsX == bitsY) { + if (size > 0) { + X += size; + Y += size; + while (r && (size-- > 0)) r = (*(--X) == *(--Y)); + } + if (r) return((signed int) 0); + else { + if (*X < *Y) return((signed int) -1); else return((signed int) 1); + } + } + else { + if (bitsX < bitsY) return((signed int) -1); else return((signed int) 1); + } +} + +signed int BitVector_Compare(unsigned int * X, unsigned int * Y) /* X <,=,> Y ? */ +{ /* signed */ + unsigned int bitsX = bits_(X); + unsigned int bitsY = bits_(Y); + unsigned int size = size_(X); + unsigned int mask = mask_(X); + unsigned int sign; + boolean r = true; + + if (bitsX == bitsY) + { + if (size > 0) + { + X += size; + Y += size; + mask &= ~ (mask >> 1); + if ((sign = (*(X-1) & mask)) != (*(Y-1) & mask)) + { + if (sign) return((signed int) -1); else return((signed int) 1); + } + while (r && (size-- > 0)) r = (*(--X) == *(--Y)); + } + if (r) return((signed int) 0); + else + { + if (*X < *Y) return((signed int) -1); else return((signed int) 1); + } + } + else + { + if (bitsX < bitsY) return((signed int) -1); else return((signed int) 1); + } +} + +size_t BitVector_Hash(unsigned int * addr) +{ + unsigned int bits = bits_(addr); + unsigned int size = size_(addr); + unsigned int value; + unsigned int count; + unsigned int digit; + unsigned int length; + + size_t result = 0; + + length = bits >> 2; + if (bits & 0x0003) length++; + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while ((size-- > 0) && (length > 0)) + { + value = *addr++; + count = BITS >> 2; + while ((count-- > 0) && (length > 0)) + { + digit = value & 0x000F; + if (digit > 9) digit += (unsigned int) 'A' - 10; + else digit += (unsigned int) '0'; + result = 5*result + digit; length--; + if ((count > 0) && (length > 0)) value >>= 4; + } + } + } + return result; +} + + +unsigned char * BitVector_to_Hex(unsigned int * addr) +{ + unsigned int bits = bits_(addr); + unsigned int size = size_(addr); + unsigned int value; + unsigned int count; + unsigned int digit; + unsigned int length; + unsigned char * string; + + length = bits >> 2; + if (bits & 0x0003) length++; + string = (unsigned char *) malloc((size_t) (length+1)); + if (string == NULL) return(NULL); + string += length; + *string = (unsigned char) '\0'; + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while ((size-- > 0) && (length > 0)) + { + value = *addr++; + count = BITS >> 2; + while ((count-- > 0) && (length > 0)) + { + digit = value & 0x000F; + if (digit > 9) digit += (unsigned int) 'A' - 10; + else digit += (unsigned int) '0'; + *(--string) = (unsigned char) digit; length--; + if ((count > 0) && (length > 0)) value >>= 4; + } + } + } + return(string); +} + +ErrCode BitVector_from_Hex(unsigned int * addr, unsigned char * string) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + boolean ok = true; + unsigned int length; + unsigned int value; + unsigned int count; + int digit; + + if (size > 0) + { + length = strlen((char *) string); + string += length; + while (size-- > 0) + { + value = 0; + for ( count = 0; (ok && (length > 0) && (count < BITS)); count += 4 ) + { + digit = (int) *(--string); length--; + /* separate because toupper() is likely a macro! */ + digit = toupper(digit); + if ((ok = (isxdigit(digit) != 0))) + { + if (digit >= (int) 'A') digit -= (int) 'A' - 10; + else digit -= (int) '0'; + value |= (((unsigned int) digit) << count); + } + } + *addr++ = value; + } + *(--addr) &= mask; + } + if (ok) return(ErrCode_Ok); + else return(ErrCode_Pars); +} + +unsigned char * BitVector_to_Bin(unsigned int * addr) +{ + unsigned int size = size_(addr); + unsigned int value; + unsigned int count; + unsigned int digit; + unsigned int length; + unsigned char * string; + + length = bits_(addr); + string = (unsigned char *) malloc((size_t) (length+1)); + if (string == NULL) return(NULL); + string += length; + *string = (unsigned char) '\0'; + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while (size-- > 0) + { + value = *addr++; + count = BITS; + if (count > length) count = length; + while (count-- > 0) + { + digit = value & 0x0001; + digit += (unsigned int) '0'; + *(--string) = (unsigned char) digit; length--; + if (count > 0) value >>= 1; + } + } + } + return(string); +} + +ErrCode BitVector_from_Bin(unsigned int * addr, unsigned char * string) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + boolean ok = true; + unsigned int length; + unsigned int value; + unsigned int count; + int digit; + + if (size > 0) + { + length = strlen((char *) string); + string += length; + while (size-- > 0) + { + value = 0; + for ( count = 0; (ok && (length > 0) && (count < BITS)); count++ ) + { + digit = (int) *(--string); length--; + switch (digit) + { + case (int) '0': + break; + case (int) '1': + value |= BITMASKTAB[count]; + break; + default: + ok = false; + break; + } + } + *addr++ = value; + } + *(--addr) &= mask; + } + if (ok) return(ErrCode_Ok); + else return(ErrCode_Pars); +} + +unsigned char * BitVector_to_Dec(unsigned int * addr) +{ + unsigned int bits = bits_(addr); + unsigned int length; + unsigned int digits; + unsigned int count; + unsigned int q; + unsigned int r; + boolean loop; + unsigned char * result; + unsigned char * string; + unsigned int * quot; + unsigned int * rest; + unsigned int * temp; + unsigned int * base; + signed int sign; + + length = (unsigned int) (bits / 3.3); /* digits = bits * ln(2) / ln(10) */ + length += 2; /* compensate for truncating & provide space for minus sign */ + result = (unsigned char *) malloc((size_t) (length+1)); /* remember the '\0'! */ + if (result == NULL) return(NULL); + string = result; + sign = BitVector_Sign(addr); + if ((bits < 4) || (sign == 0)) + { + if (bits > 0) digits = *addr; else digits = (unsigned int) 0; + if (sign < 0) digits = ((unsigned int)(-((signed int)digits))) & mask_(addr); + *string++ = (unsigned char) digits + (unsigned char) '0'; + digits = 1; + } + else + { + quot = BitVector_Create(bits,false); + if (quot == NULL) + { + BitVector_Dispose(result); + return(NULL); + } + rest = BitVector_Create(bits,false); + if (rest == NULL) + { + BitVector_Dispose(result); + BitVector_Destroy(quot); + return(NULL); + } + temp = BitVector_Create(bits,false); + if (temp == NULL) + { + BitVector_Dispose(result); + BitVector_Destroy(quot); + BitVector_Destroy(rest); + return(NULL); + } + base = BitVector_Create(bits,true); + if (base == NULL) + { + BitVector_Dispose(result); + BitVector_Destroy(quot); + BitVector_Destroy(rest); + BitVector_Destroy(temp); + return(NULL); + } + if (sign < 0) BitVector_Negate(quot,addr); + else BitVector_Copy(quot,addr); + digits = 0; + *base = EXP10; + loop = (bits >= BITS); + do + { + if (loop) + { + BitVector_Copy(temp,quot); + if (BitVector_Div_Pos(quot,temp,base,rest)) + { + BitVector_Dispose(result); /* emergency exit */ + BitVector_Destroy(quot); + BitVector_Destroy(rest); /* should never occur */ + BitVector_Destroy(temp); /* under normal operation */ + BitVector_Destroy(base); + return(NULL); + } + loop = ! BitVector_is_empty(quot); + q = *rest; + } + else q = *quot; + count = LOG10; + while (((loop && (count-- > 0)) || ((! loop) && (q != 0))) && + (digits < length)) + { + if (q != 0) + { + BIT_VECTOR_DIGITIZE(unsigned int,q,r) + } + else r = (unsigned int) '0'; + *string++ = (unsigned char) r; + digits++; + } + } + while (loop && (digits < length)); + BitVector_Destroy(quot); + BitVector_Destroy(rest); + BitVector_Destroy(temp); + BitVector_Destroy(base); + } + if ((sign < 0) && (digits < length)) + { + *string++ = (unsigned char) '-'; + digits++; + } + *string = (unsigned char) '\0'; + BIT_VECTOR_reverse(result,digits); + return(result); +} + +ErrCode BitVector_from_Dec(unsigned int * addr, unsigned char * string) +{ + ErrCode error = ErrCode_Ok; + unsigned int bits = bits_(addr); + unsigned int mask = mask_(addr); + boolean init = (bits > BITS); + boolean minus; + boolean shift; + boolean carry; + unsigned int * term; + unsigned int * base; + unsigned int * prod; + unsigned int * rank; + unsigned int * temp; + unsigned int accu; + unsigned int powr; + unsigned int count; + unsigned int length; + int digit; + + if (bits > 0) + { + length = strlen((char *) string); + if (length == 0) return(ErrCode_Pars); + digit = (int) *string; + if ((minus = (digit == (int) '-')) || + (digit == (int) '+')) + { + string++; + if (--length == 0) return(ErrCode_Pars); + } + string += length; + term = BitVector_Create(BITS,false); + if (term == NULL) + { + return(ErrCode_Null); + } + base = BitVector_Create(BITS,false); + if (base == NULL) + { + BitVector_Destroy(term); + return(ErrCode_Null); + } + prod = BitVector_Create(bits,init); + if (prod == NULL) + { + BitVector_Destroy(term); + BitVector_Destroy(base); + return(ErrCode_Null); + } + rank = BitVector_Create(bits,init); + if (rank == NULL) + { + BitVector_Destroy(term); + BitVector_Destroy(base); + BitVector_Destroy(prod); + return(ErrCode_Null); + } + temp = BitVector_Create(bits,false); + if (temp == NULL) + { + BitVector_Destroy(term); + BitVector_Destroy(base); + BitVector_Destroy(prod); + BitVector_Destroy(rank); + return(ErrCode_Null); + } + BitVector_Empty(addr); + *base = EXP10; + shift = false; + while ((! error) && (length > 0)) + { + accu = 0; + powr = 1; + count = LOG10; + while ((! error) && (length > 0) && (count-- > 0)) + { + digit = (int) *(--string); length--; + /* separate because isdigit() is likely a macro! */ + if (isdigit(digit) != 0) + { + accu += ((unsigned int) digit - (unsigned int) '0') * powr; + powr *= 10; + } + else error = ErrCode_Pars; + } + if (! error) + { + if (shift) + { + *term = accu; + BitVector_Copy(temp,rank); + error = BitVector_Mul_Pos(prod,temp,term,false); + } + else + { + *prod = accu; + if ((! init) && ((accu & ~ mask) != 0)) error = ErrCode_Ovfl; + } + if (! error) + { + carry = false; + BitVector_compute(addr,addr,prod,false,&carry); + /* ignores sign change (= overflow) but ! */ + /* numbers too large (= carry) for resulting bit vector */ + if (carry) error = ErrCode_Ovfl; + else + { + if (length > 0) + { + if (shift) + { + BitVector_Copy(temp,rank); + error = BitVector_Mul_Pos(rank,temp,base,false); + } + else + { + *rank = *base; + shift = true; + } + } + } + } + } + } + BitVector_Destroy(term); + BitVector_Destroy(base); + BitVector_Destroy(prod); + BitVector_Destroy(rank); + BitVector_Destroy(temp); + if (! error && minus) + { + BitVector_Negate(addr,addr); + if ((*(addr + size_(addr) - 1) & mask & ~ (mask >> 1)) == 0) + error = ErrCode_Ovfl; + } + } + return(error); +} + +unsigned char * BitVector_to_Enum(unsigned int * addr) +{ + unsigned int bits = bits_(addr); + unsigned int sample; + unsigned int length; + unsigned int digits; + unsigned int factor; + unsigned int power; + unsigned int start; + unsigned int min; + unsigned int max; + unsigned char * string; + unsigned char * target; + boolean comma; + + if (bits > 0) + { + sample = bits - 1; /* greatest possible index */ + length = 2; /* account for index 0 && terminating '\0' */ + digits = 1; /* account for intervening dashes && commas */ + factor = 1; + power = 10; + while (sample >= (power-1)) + { + length += ++digits * factor * 6; /* 9,90,900,9000,... (9*2/3 = 6) */ + factor = power; + power *= 10; + } + if (sample > --factor) + { + sample -= factor; + factor = (unsigned int) ( sample / 3 ); + factor = (factor << 1) + (sample - (factor * 3)); + length += ++digits * factor; + } + } + else length = 1; + string = (unsigned char *) malloc((size_t) length); + if (string == NULL) return(NULL); + start = 0; + comma = false; + target = string; + while ((start < bits) && BitVector_interval_scan_inc(addr,start,&min,&max)) + { + start = max + 2; + if (comma) *target++ = (unsigned char) ','; + if (min == max) + { + target += BIT_VECTOR_int2str(target,min); + } + else + { + if (min+1 == max) + { + target += BIT_VECTOR_int2str(target,min); + *target++ = (unsigned char) ','; + target += BIT_VECTOR_int2str(target,max); + } + else + { + target += BIT_VECTOR_int2str(target,min); + *target++ = (unsigned char) '-'; + target += BIT_VECTOR_int2str(target,max); + } + } + comma = true; + } + *target = (unsigned char) '\0'; + return(string); +} + +ErrCode BitVector_from_Enum(unsigned int * addr, unsigned char * string) +{ + ErrCode error = ErrCode_Ok; + unsigned int bits = bits_(addr); + unsigned int state = 1; + unsigned int token; + unsigned int index = 0; + unsigned int start = 0; /* silence compiler warning */ + + if (bits > 0) + { + BitVector_Empty(addr); + while ((! error) && (state != 0)) + { + token = (unsigned int) *string; + /* separate because isdigit() is likely a macro! */ + if (isdigit((int)token) != 0) + { + string += BIT_VECTOR_str2int(string,&index); + if (index < bits) token = (unsigned int) '0'; + else error = ErrCode_Indx; + } + else string++; + if (! error) + switch (state) + { + case 1: + switch (token) + { + case (unsigned int) '0': + state = 2; + break; + case (unsigned int) '\0': + state = 0; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 2: + switch (token) + { + case (unsigned int) '-': + start = index; + state = 3; + break; + case (unsigned int) ',': + BIT_VECTOR_SET_BIT(addr,index) + state = 5; + break; + case (unsigned int) '\0': + BIT_VECTOR_SET_BIT(addr,index) + state = 0; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 3: + switch (token) + { + case (unsigned int) '0': + if (start < index) + BitVector_Interval_Fill(addr,start,index); + else if (start == index) + BIT_VECTOR_SET_BIT(addr,index) + else error = ErrCode_Ordr; + state = 4; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 4: + switch (token) + { + case (unsigned int) ',': + state = 5; + break; + case (unsigned int) '\0': + state = 0; + break; + default: + error = ErrCode_Pars; + break; + } + break; + case 5: + switch (token) + { + case (unsigned int) '0': + state = 2; + break; + default: + error = ErrCode_Pars; + break; + } + break; + } + } + } + return(error); +} + +void BitVector_Bit_Off(unsigned int * addr, unsigned int index) /* X = X \ {x} */ +{ + if (index < bits_(addr)) BIT_VECTOR_CLR_BIT(addr,index) +} + +void BitVector_Bit_On(unsigned int * addr, unsigned int index) /* X = X + {x} */ +{ + if (index < bits_(addr)) BIT_VECTOR_SET_BIT(addr,index) +} + +boolean BitVector_bit_flip(unsigned int * addr, unsigned int index) /* X=(X+{x})\(X*{x}) */ +{ + unsigned int mask; + + if (index < bits_(addr)) return( BIT_VECTOR_FLP_BIT(addr,index,mask) ); + else return( false ); +} + +boolean BitVector_bit_test(unsigned int * addr, unsigned int index) /* {x} in X ? */ +{ + if (index < bits_(addr)) return( BIT_VECTOR_TST_BIT(addr,index) ); + else return( false ); +} + +void BitVector_Bit_Copy(unsigned int * addr, unsigned int index, boolean bit) +{ + if (index < bits_(addr)) + { + if (bit) BIT_VECTOR_SET_BIT(addr,index) + else BIT_VECTOR_CLR_BIT(addr,index) + } +} + +void BitVector_LSB(unsigned int * addr, boolean bit) +{ + if (bits_(addr) > 0) + { + if (bit) *addr |= LSB; + else *addr &= ~ LSB; + } +} + +void BitVector_MSB(unsigned int * addr, boolean bit) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + + if (size-- > 0) + { + if (bit) *(addr+size) |= mask & ~ (mask >> 1); + else *(addr+size) &= ~ mask | (mask >> 1); + } +} + +boolean BitVector_lsb_(unsigned int * addr) +{ + if (size_(addr) > 0) return( (*addr & LSB) != 0 ); + else return( false ); +} + +boolean BitVector_msb_(unsigned int * addr) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + + if (size-- > 0) + return( (*(addr+size) & (mask & ~ (mask >> 1))) != 0 ); + else + return( false ); +} + +boolean BitVector_rotate_left(unsigned int * addr) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int msb; + boolean carry_in; + boolean carry_out = false; + + if (size > 0) + { + msb = mask & ~ (mask >> 1); + carry_in = ((*(addr+size-1) & msb) != 0); + while (size-- > 1) + { + carry_out = ((*addr & MSB) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + carry_in = carry_out; + addr++; + } + carry_out = ((*addr & msb) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + *addr &= mask; + } + return(carry_out); +} + +boolean BitVector_rotate_right(unsigned int * addr) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int msb; + boolean carry_in; + boolean carry_out = false; + + if (size > 0) + { + msb = mask & ~ (mask >> 1); + carry_in = ((*addr & LSB) != 0); + addr += size-1; + *addr &= mask; + carry_out = ((*addr & LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= msb; + carry_in = carry_out; + addr--; + size--; + while (size-- > 0) + { + carry_out = ((*addr & LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= MSB; + carry_in = carry_out; + addr--; + } + } + return(carry_out); +} + +boolean BitVector_shift_left(unsigned int * addr, boolean carry_in) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int msb; + boolean carry_out = carry_in; + + if (size > 0) + { + msb = mask & ~ (mask >> 1); + while (size-- > 1) + { + carry_out = ((*addr & MSB) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + carry_in = carry_out; + addr++; + } + carry_out = ((*addr & msb) != 0); + *addr <<= 1; + if (carry_in) *addr |= LSB; + *addr &= mask; + } + return(carry_out); +} + +boolean BitVector_shift_right(unsigned int * addr, boolean carry_in) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int msb; + boolean carry_out = carry_in; + + if (size > 0) + { + msb = mask & ~ (mask >> 1); + addr += size-1; + *addr &= mask; + carry_out = ((*addr & LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= msb; + carry_in = carry_out; + addr--; + size--; + while (size-- > 0) + { + carry_out = ((*addr & LSB) != 0); + *addr >>= 1; + if (carry_in) *addr |= MSB; + carry_in = carry_out; + addr--; + } + } + return(carry_out); +} + +void BitVector_Move_Left(unsigned int * addr, unsigned int bits) +{ + unsigned int count; + unsigned int words; + + if (bits > 0) + { + count = bits & MODMASK; + words = bits >> LOGBITS; + if (bits >= bits_(addr)) BitVector_Empty(addr); + else + { + while (count-- > 0) BitVector_shift_left(addr,0); + BitVector_Word_Insert(addr,0,words,true); + } + } +} + +void BitVector_Move_Right(unsigned int * addr, unsigned int bits) +{ + unsigned int count; + unsigned int words; + + if (bits > 0) + { + count = bits & MODMASK; + words = bits >> LOGBITS; + if (bits >= bits_(addr)) BitVector_Empty(addr); + else + { + while (count-- > 0) BitVector_shift_right(addr,0); + BitVector_Word_Delete(addr,0,words,true); + } + } +} + +void BitVector_Insert(unsigned int * addr, unsigned int offset, unsigned int count, boolean clear) +{ + unsigned int bits = bits_(addr); + unsigned int last; + + if ((count > 0) && (offset < bits)) + { + last = offset + count; + if (last < bits) + { + BitVector_Interval_Copy(addr,addr,last,offset,(bits-last)); + } + else last = bits; + if (clear) BitVector_Interval_Empty(addr,offset,(last-1)); + } +} + +void BitVector_Delete(unsigned int * addr, unsigned int offset, unsigned int count, boolean clear) +{ + unsigned int bits = bits_(addr); + unsigned int last; + + if ((count > 0) && (offset < bits)) + { + last = offset + count; + if (last < bits) + { + BitVector_Interval_Copy(addr,addr,offset,last,(bits-last)); + } + else count = bits - offset; + if (clear) BitVector_Interval_Empty(addr,(bits-count),(bits-1)); + } +} + +boolean BitVector_increment(unsigned int * addr) /* X++ */ +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int * last = addr + size - 1; + boolean carry = true; + + if (size > 0) + { + *last |= ~ mask; + while (carry && (size-- > 0)) + { + carry = (++(*addr++) == 0); + } + *last &= mask; + } + return(carry); +} + +boolean BitVector_decrement(unsigned int * addr) /* X-- */ +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int * last = addr + size - 1; + boolean carry = true; + + if (size > 0) + { + *last &= mask; + while (carry && (size-- > 0)) + { + carry = (*addr == 0); + --(*addr++); + } + *last &= mask; + } + return(carry); +} + +boolean BitVector_compute(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean minus, boolean *carry) +{ + unsigned int size = size_(X); + unsigned int mask = mask_(X); + unsigned int vv = 0; + unsigned int cc; + unsigned int mm; + unsigned int yy; + unsigned int zz; + unsigned int lo; + unsigned int hi; + + if (size > 0) + { + if (minus) cc = (*carry == 0); + else cc = (*carry != 0); + /* deal with (size-1) least significant full words first: */ + while (--size > 0) + { + yy = *Y++; + if (minus) zz = (unsigned int) ~ ( Z ? *Z++ : 0 ); + else zz = (unsigned int) ( Z ? *Z++ : 0 ); + lo = (yy & LSB) + (zz & LSB) + cc; + hi = (yy >> 1) + (zz >> 1) + (lo >> 1); + cc = ((hi & MSB) != 0); + *X++ = (hi << 1) | (lo & LSB); + } + /* deal with most significant word (may be used only partially): */ + yy = *Y & mask; + if (minus) zz = (unsigned int) ~ ( Z ? *Z : 0 ); + else zz = (unsigned int) ( Z ? *Z : 0 ); + zz &= mask; + if (mask == LSB) /* special case, only one bit used */ + { + vv = cc; + lo = yy + zz + cc; + cc = (lo >> 1); + vv ^= cc; + *X = lo & LSB; + } + else + { + if (~ mask) /* not all bits are used, but more than one */ + { + mm = (mask >> 1); + vv = (yy & mm) + (zz & mm) + cc; + mm = mask & ~ mm; + lo = yy + zz + cc; + cc = (lo >> 1); + vv ^= cc; + vv &= mm; + cc &= mm; + *X = lo & mask; + } + else /* other special case, all bits are used */ + { + mm = ~ MSB; + lo = (yy & mm) + (zz & mm) + cc; + vv = lo & MSB; + hi = ((yy & MSB) >> 1) + ((zz & MSB) >> 1) + (vv >> 1); + cc = hi & MSB; + vv ^= cc; + *X = (hi << 1) | (lo & mm); + } + } + if (minus) *carry = (cc == 0); + else *carry = (cc != 0); + } + return(vv != 0); +} + +boolean BitVector_add(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean *carry) +{ + return(BitVector_compute(X,Y,Z,false,carry)); +} + +boolean BitVector_sub(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean *carry) +{ + return(BitVector_compute(X,Y,Z,true,carry)); +} + +boolean BitVector_inc(unsigned int * X, unsigned int * Y) +{ + boolean carry = true; + + return(BitVector_compute(X,Y,NULL,false,&carry)); +} + +boolean BitVector_dec(unsigned int * X, unsigned int * Y) +{ + boolean carry = true; + + return(BitVector_compute(X,Y,NULL,true,&carry)); +} + +void BitVector_Negate(unsigned int * X, unsigned int * Y) +{ + unsigned int size = size_(X); + unsigned int mask = mask_(X); + boolean carry = true; + + if (size > 0) + { + while (size-- > 0) + { + *X = ~ *Y++; + if (carry) + { + carry = (++(*X) == 0); + } + X++; + } + *(--X) &= mask; + } +} + +void BitVector_Absolute(unsigned int * X, unsigned int * Y) +{ + unsigned int size = size_(Y); + unsigned int mask = mask_(Y); + + if (size > 0) + { + if (*(Y+size-1) & (mask & ~ (mask >> 1))) BitVector_Negate(X,Y); + else BitVector_Copy(X,Y); + } +} + +// FIXME: What the hell does the return value of this mean? +// It returns 0, 1, or -1 under mysterious circumstances. +signed int BitVector_Sign(unsigned int * addr) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int * last = addr + size - 1; + boolean r = true; + + if (size > 0) + { + *last &= mask; + while (r && (size-- > 0)) r = ( *addr++ == 0 ); + } + if (r) return((signed int) 0); + else + { + if (*last & (mask & ~ (mask >> 1))) return((signed int) -1); + else return((signed int) 1); + } +} + +ErrCode BitVector_Mul_Pos(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean strict) +{ + unsigned int mask; + unsigned int limit; + unsigned int count; + signed long last; + unsigned int * sign; + boolean carry; + boolean overflow; + boolean ok = true; + + /* + Requirements: + - X, Y && Z must be distinct + - X && Y must have equal sizes (whereas Z may be any size!) + - Z should always contain the SMALLER of the two factors Y && Z + Constraints: + - The contents of Y (&& of X, of course) are destroyed + (only Z is preserved!) + */ + + if ((X == Y) || (X == Z) || (Y == Z)) return(ErrCode_Same); + if (bits_(X) != bits_(Y)) return(ErrCode_Size); + BitVector_Empty(X); + if (BitVector_is_empty(Y)) return(ErrCode_Ok); /* exit also taken if bits_(Y)==0 */ + if ((last = Set_Max(Z)) < 0L) return(ErrCode_Ok); + limit = (unsigned int) last; + sign = Y + size_(Y) - 1; + mask = mask_(Y); + *sign &= mask; + mask &= ~ (mask >> 1); + for ( count = 0; (ok && (count <= limit)); count++ ) + { + if ( BIT_VECTOR_TST_BIT(Z,count) ) + { + carry = false; + overflow = BitVector_compute(X,X,Y,false,&carry); + if (strict) ok = ! (carry || overflow); + else ok = ! carry; + } + if (ok && (count < limit)) + { + carry = BitVector_shift_left(Y,0); + if (strict) + { + overflow = ((*sign & mask) != 0); + ok = ! (carry || overflow); + } + else ok = ! carry; + } + } + if (ok) return(ErrCode_Ok); else return(ErrCode_Ovfl); +} + +ErrCode BitVector_Multiply(unsigned int * X, unsigned int * Y, unsigned int * Z) +{ + ErrCode error = ErrCode_Ok; + unsigned int bit_x = bits_(X); + unsigned int bit_y = bits_(Y); + unsigned int bit_z = bits_(Z); + unsigned int size; + unsigned int mask; + unsigned int msb; + unsigned int * ptr_y; + unsigned int * ptr_z; + boolean sgn_x; + boolean sgn_y; + boolean sgn_z; + boolean zero; + unsigned int * A; + unsigned int * B; + + /* + Requirements: + - Y && Z must have equal sizes + - X must have at least the same size as Y && Z but may be larger (!) + Features: + - The contents of Y && Z are preserved + - X may be identical with Y or Z (or both!) + (in-place multiplication is possible!) + */ + + if ((bit_y != bit_z) || (bit_x < bit_y)) return(ErrCode_Size); + if (BitVector_is_empty(Y) || BitVector_is_empty(Z)) + { + BitVector_Empty(X); + } + else + { + A = BitVector_Create(bit_y,false); + if (A == NULL) return(ErrCode_Null); + B = BitVector_Create(bit_z,false); + if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } + size = size_(Y); + mask = mask_(Y); + msb = (mask & ~ (mask >> 1)); + sgn_y = (((*(Y+size-1) &= mask) & msb) != 0); + sgn_z = (((*(Z+size-1) &= mask) & msb) != 0); + sgn_x = sgn_y ^ sgn_z; + if (sgn_y) BitVector_Negate(A,Y); else BitVector_Copy(A,Y); + if (sgn_z) BitVector_Negate(B,Z); else BitVector_Copy(B,Z); + ptr_y = A + size; + ptr_z = B + size; + zero = true; + while (zero && (size-- > 0)) + { + zero &= (*(--ptr_y) == 0); + zero &= (*(--ptr_z) == 0); + } + if (*ptr_y > *ptr_z) + { + if (bit_x > bit_y) + { + A = BitVector_Resize(A,bit_x); + if (A == NULL) { BitVector_Destroy(B); return(ErrCode_Null); } + } + error = BitVector_Mul_Pos(X,A,B,true); + } + else + { + if (bit_x > bit_z) + { + B = BitVector_Resize(B,bit_x); + if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } + } + error = BitVector_Mul_Pos(X,B,A,true); + } + if ((! error) && sgn_x) BitVector_Negate(X,X); + BitVector_Destroy(A); + BitVector_Destroy(B); + } + return(error); +} + +ErrCode BitVector_Div_Pos(unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R) +{ + unsigned int bits = bits_(Q); + unsigned int mask; + unsigned int * addr; + signed long last; + boolean flag; + boolean copy = false; /* flags whether valid rest is in R (0) || X (1) */ + + /* + Requirements: + - All bit vectors must have equal sizes + - Q, X, Y && R must all be distinct bit vectors + - Y must be non-zero (of course!) + Constraints: + - The contents of X (&& Q && R, of course) are destroyed + (only Y is preserved!) + */ + + if ((bits != bits_(X)) || (bits != bits_(Y)) || (bits != bits_(R))) + return(ErrCode_Size); + if ((Q == X) || (Q == Y) || (Q == R) || (X == Y) || (X == R) || (Y == R)) + return(ErrCode_Same); + if (BitVector_is_empty(Y)) + return(ErrCode_Zero); + + BitVector_Empty(R); + BitVector_Copy(Q,X); + if ((last = Set_Max(Q)) < 0L) return(ErrCode_Ok); + bits = (unsigned int) ++last; + while (bits-- > 0) + { + addr = Q + (bits >> LOGBITS); + mask = BITMASKTAB[bits & MODMASK]; + flag = ((*addr & mask) != 0); + if (copy) + { + BitVector_shift_left(X,flag); + flag = false; + BitVector_compute(R,X,Y,true,&flag); + } + else + { + BitVector_shift_left(R,flag); + flag = false; + BitVector_compute(X,R,Y,true,&flag); + } + if (flag) *addr &= ~ mask; + else + { + *addr |= mask; + copy = ! copy; + } + } + if (copy) BitVector_Copy(R,X); + return(ErrCode_Ok); +} + +ErrCode BitVector_Divide(unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R) +{ + ErrCode error = ErrCode_Ok; + unsigned int bits = bits_(Q); + unsigned int size = size_(Q); + unsigned int mask = mask_(Q); + unsigned int msb = (mask & ~ (mask >> 1)); + boolean sgn_q; + boolean sgn_x; + boolean sgn_y; + unsigned int * A; + unsigned int * B; + + /* + Requirements: + - All bit vectors must have equal sizes + - Q && R must be two distinct bit vectors + - Y must be non-zero (of course!) + Features: + - The contents of X && Y are preserved + - Q may be identical with X || Y (or both) + (in-place division is possible!) + - R may be identical with X || Y (or both) + (but not identical with Q!) + */ + + if ((bits != bits_(X)) || (bits != bits_(Y)) || (bits != bits_(R))) + return(ErrCode_Size); + if (Q == R) + return(ErrCode_Same); + if (BitVector_is_empty(Y)) + return(ErrCode_Zero); + + if (BitVector_is_empty(X)) + { + BitVector_Empty(Q); + BitVector_Empty(R); + } + else + { + A = BitVector_Create(bits,false); + if (A == NULL) return(ErrCode_Null); + B = BitVector_Create(bits,false); + if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } + size--; + sgn_x = (((*(X+size) &= mask) & msb) != 0); + sgn_y = (((*(Y+size) &= mask) & msb) != 0); + sgn_q = sgn_x ^ sgn_y; + if (sgn_x) BitVector_Negate(A,X); else BitVector_Copy(A,X); + if (sgn_y) BitVector_Negate(B,Y); else BitVector_Copy(B,Y); + if (! (error = BitVector_Div_Pos(Q,A,B,R))) + { + if (sgn_q) BitVector_Negate(Q,Q); + if (sgn_x) BitVector_Negate(R,R); + } + BitVector_Destroy(A); + BitVector_Destroy(B); + } + return(error); +} + +ErrCode BitVector_GCD(unsigned int * X, unsigned int * Y, unsigned int * Z) +{ + ErrCode error = ErrCode_Ok; + unsigned int bits = bits_(X); + unsigned int size = size_(X); + unsigned int mask = mask_(X); + unsigned int msb = (mask & ~ (mask >> 1)); + boolean sgn_a; + boolean sgn_b; + boolean sgn_r; + unsigned int * Q; + unsigned int * R; + unsigned int * A; + unsigned int * B; + unsigned int * T; + + /* + Requirements: + - All bit vectors must have equal sizes + Features: + - The contents of Y && Z are preserved + - X may be identical with Y || Z (or both) + (in-place is possible!) + - GCD(0,z) == GCD(z,0) == z + - negative values are h&&led correctly + */ + + if ((bits != bits_(Y)) || (bits != bits_(Z))) return(ErrCode_Size); + if (BitVector_is_empty(Y)) + { + if (X != Z) BitVector_Copy(X,Z); + return(ErrCode_Ok); + } + if (BitVector_is_empty(Z)) + { + if (X != Y) BitVector_Copy(X,Y); + return(ErrCode_Ok); + } + Q = BitVector_Create(bits,false); + if (Q == NULL) + { + return(ErrCode_Null); + } + R = BitVector_Create(bits,false); + if (R == NULL) + { + BitVector_Destroy(Q); + return(ErrCode_Null); + } + A = BitVector_Create(bits,false); + if (A == NULL) + { + BitVector_Destroy(Q); + BitVector_Destroy(R); + return(ErrCode_Null); + } + B = BitVector_Create(bits,false); + if (B == NULL) + { + BitVector_Destroy(Q); + BitVector_Destroy(R); + BitVector_Destroy(A); + return(ErrCode_Null); + } + size--; + sgn_a = (((*(Y+size) &= mask) & msb) != 0); + sgn_b = (((*(Z+size) &= mask) & msb) != 0); + if (sgn_a) BitVector_Negate(A,Y); else BitVector_Copy(A,Y); + if (sgn_b) BitVector_Negate(B,Z); else BitVector_Copy(B,Z); + while (! error) + { + if (! (error = BitVector_Div_Pos(Q,A,B,R))) + { + if (BitVector_is_empty(R)) break; + T = A; sgn_r = sgn_a; + A = B; sgn_a = sgn_b; + B = R; sgn_b = sgn_r; + R = T; + } + } + if (! error) + { + if (sgn_b) BitVector_Negate(X,B); else BitVector_Copy(X,B); + } + BitVector_Destroy(Q); + BitVector_Destroy(R); + BitVector_Destroy(A); + BitVector_Destroy(B); + return(error); +} + +ErrCode BitVector_GCD2(unsigned int * U, unsigned int * V, unsigned int * W, unsigned int * X, unsigned int * Y) +{ + ErrCode error = ErrCode_Ok; + unsigned int bits = bits_(U); + unsigned int size = size_(U); + unsigned int mask = mask_(U); + unsigned int msb = (mask & ~ (mask >> 1)); + boolean minus; + boolean carry; + boolean sgn_q; + boolean sgn_r; + boolean sgn_a; + boolean sgn_b; + boolean sgn_x; + boolean sgn_y; + unsigned int * * L; + unsigned int * Q; + unsigned int * R; + unsigned int * A; + unsigned int * B; + unsigned int * T; + unsigned int * X1; + unsigned int * X2; + unsigned int * X3; + unsigned int * Y1; + unsigned int * Y2; + unsigned int * Y3; + unsigned int * Z; + + /* + Requirements: + - All bit vectors must have equal sizes + - U, V, && W must all be distinct bit vectors + Features: + - The contents of X && Y are preserved + - U, V && W may be identical with X || Y (or both, + provided that U, V && W are mutually distinct) + (i.e., in-place is possible!) + - GCD(0,z) == GCD(z,0) == z + - negative values are h&&led correctly + */ + + if ((bits != bits_(V)) || + (bits != bits_(W)) || + (bits != bits_(X)) || + (bits != bits_(Y))) + { + return(ErrCode_Size); + } + if ((U == V) || (U == W) || (V == W)) + { + return(ErrCode_Same); + } + if (BitVector_is_empty(X)) + { + if (U != Y) BitVector_Copy(U,Y); + BitVector_Empty(V); + BitVector_Empty(W); + *W = 1; + return(ErrCode_Ok); + } + if (BitVector_is_empty(Y)) + { + if (U != X) BitVector_Copy(U,X); + BitVector_Empty(V); + BitVector_Empty(W); + *V = 1; + return(ErrCode_Ok); + } + if ((L = BitVector_Create_List(bits,false,11)) == NULL) + { + return(ErrCode_Null); + } + Q = L[0]; + R = L[1]; + A = L[2]; + B = L[3]; + X1 = L[4]; + X2 = L[5]; + X3 = L[6]; + Y1 = L[7]; + Y2 = L[8]; + Y3 = L[9]; + Z = L[10]; + size--; + sgn_a = (((*(X+size) &= mask) & msb) != 0); + sgn_b = (((*(Y+size) &= mask) & msb) != 0); + if (sgn_a) BitVector_Negate(A,X); else BitVector_Copy(A,X); + if (sgn_b) BitVector_Negate(B,Y); else BitVector_Copy(B,Y); + BitVector_Empty(X1); + BitVector_Empty(X2); + *X1 = 1; + BitVector_Empty(Y1); + BitVector_Empty(Y2); + *Y2 = 1; + sgn_x = false; + sgn_y = false; + while (! error) + { + if ((error = BitVector_Div_Pos(Q,A,B,R))) + { + break; + } + if (BitVector_is_empty(R)) + { + break; + } + sgn_q = sgn_a ^ sgn_b; + + if (sgn_x) BitVector_Negate(Z,X2); else BitVector_Copy(Z,X2); + if ((error = BitVector_Mul_Pos(X3,Z,Q,true))) + { + break; + } + minus = ! (sgn_x ^ sgn_q); + carry = 0; + if (BitVector_compute(X3,X1,X3,minus,&carry)) + { + error = ErrCode_Ovfl; + break; + } + sgn_x = (((*(X3+size) &= mask) & msb) != 0); + + if (sgn_y) BitVector_Negate(Z,Y2); else BitVector_Copy(Z,Y2); + if ((error = BitVector_Mul_Pos(Y3,Z,Q,true))) + { + break; + } + minus = ! (sgn_y ^ sgn_q); + carry = 0; + if (BitVector_compute(Y3,Y1,Y3,minus,&carry)) + { + error = ErrCode_Ovfl; + break; + } + sgn_y = (((*(Y3+size) &= mask) & msb) != 0); + + T = A; sgn_r = sgn_a; + A = B; sgn_a = sgn_b; + B = R; sgn_b = sgn_r; + R = T; + + T = X1; + X1 = X2; + X2 = X3; + X3 = T; + + T = Y1; + Y1 = Y2; + Y2 = Y3; + Y3 = T; + } + if (! error) + { + if (sgn_b) BitVector_Negate(U,B); else BitVector_Copy(U,B); + BitVector_Copy(V,X2); + BitVector_Copy(W,Y2); + } + BitVector_Destroy_List(L,11); + return(error); +} + +ErrCode BitVector_Power(unsigned int * X, unsigned int * Y, unsigned int * Z) +{ + ErrCode error = ErrCode_Ok; + unsigned int bits = bits_(X); + boolean first = true; + signed long last; + unsigned int limit; + unsigned int count; + unsigned int * T; + + /* + Requirements: + - X must have at least the same size as Y but may be larger (!) + - X may not be identical with Z + - Z must be positive + Features: + - The contents of Y && Z are preserved + */ + + if (X == Z) return(ErrCode_Same); + if (bits < bits_(Y)) return(ErrCode_Size); + if (BitVector_msb_(Z)) return(ErrCode_Expo); + if ((last = Set_Max(Z)) < 0L) + { + if (bits < 2) return(ErrCode_Ovfl); + BitVector_Empty(X); + *X |= LSB; + return(ErrCode_Ok); /* anything ^ 0 == 1 */ + } + if (BitVector_is_empty(Y)) + { + if (X != Y) BitVector_Empty(X); + return(ErrCode_Ok); /* 0 ^ anything ! zero == 0 */ + } + T = BitVector_Create(bits,false); + if (T == NULL) return(ErrCode_Null); + limit = (unsigned int) last; + for ( count = 0; ((!error) && (count <= limit)); count++ ) + { + if ( BIT_VECTOR_TST_BIT(Z,count) ) + { + if (first) + { + first = false; + if (count) { BitVector_Copy(X,T); } + else { if (X != Y) BitVector_Copy(X,Y); } + } + else error = BitVector_Multiply(X,T,X); /* order important because T > X */ + } + if ((!error) && (count < limit)) + { + if (count) error = BitVector_Multiply(T,T,T); + else error = BitVector_Multiply(T,Y,Y); + } + } + BitVector_Destroy(T); + return(error); +} + +void BitVector_Block_Store(unsigned int * addr, unsigned char * buffer, unsigned int length) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int value; + unsigned int count; + + /* provide translation for independence of endian-ness: */ + if (size > 0) + { + while (size-- > 0) + { + value = 0; + for ( count = 0; (length > 0) && (count < BITS); count += 8 ) + { + value |= (((unsigned int) *buffer++) << count); length--; + } + *addr++ = value; + } + *(--addr) &= mask; + } +} + +unsigned char * BitVector_Block_Read(unsigned int * addr, unsigned int * length) +{ + unsigned int size = size_(addr); + unsigned int value; + unsigned int count; + unsigned char * buffer; + unsigned char * target; + + /* provide translation for independence of endian-ness: */ + *length = size << FACTOR; + buffer = (unsigned char *) malloc((size_t) ((*length)+1)); + if (buffer == NULL) return(NULL); + target = buffer; + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while (size-- > 0) + { + value = *addr++; + count = BITS >> 3; + while (count-- > 0) + { + *target++ = (unsigned char) (value & 0x00FF); + if (count > 0) value >>= 8; + } + } + } + *target = (unsigned char) '\0'; + return(buffer); +} + +void BitVector_Word_Store(unsigned int * addr, unsigned int offset, unsigned int value) +{ + unsigned int size = size_(addr); + + if (size > 0) + { + if (offset < size) *(addr+offset) = value; + *(addr+size-1) &= mask_(addr); + } +} + +unsigned int BitVector_Word_Read(unsigned int * addr, unsigned int offset) +{ + unsigned int size = size_(addr); + + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + if (offset < size) return( *(addr+offset) ); + } + return( (unsigned int) 0 ); +} + +void BitVector_Word_Insert(unsigned int * addr, unsigned int offset, unsigned int count, + boolean clear) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int * last = addr+size-1; + + if (size > 0) + { + *last &= mask; + if (offset > size) offset = size; + BIT_VECTOR_ins_words(addr+offset,size-offset,count,clear); + *last &= mask; + } +} + +void BitVector_Word_Delete(unsigned int * addr, unsigned int offset, unsigned int count, + boolean clear) +{ + unsigned int size = size_(addr); + unsigned int mask = mask_(addr); + unsigned int * last = addr+size-1; + + if (size > 0) + { + *last &= mask; + if (offset > size) offset = size; + BIT_VECTOR_del_words(addr+offset,size-offset,count,clear); + *last &= mask; + } +} + +void BitVector_Chunk_Store(unsigned int * addr, unsigned int chunksize, unsigned int offset, + unsigned long value) +{ + unsigned int bits = bits_(addr); + unsigned int mask; + unsigned int temp; + + if ((chunksize > 0) && (offset < bits)) + { + if (chunksize > LONGBITS) chunksize = LONGBITS; + if ((offset + chunksize) > bits) chunksize = bits - offset; + addr += offset >> LOGBITS; + offset &= MODMASK; + while (chunksize > 0) + { + mask = (unsigned int) (~0L << offset); + bits = offset + chunksize; + if (bits < BITS) + { + mask &= (unsigned int) ~(~0L << bits); + bits = chunksize; + } + else bits = BITS - offset; + temp = (unsigned int) (value << offset); + temp &= mask; + *addr &= ~ mask; + *addr++ |= temp; + value >>= bits; + chunksize -= bits; + offset = 0; + } + } +} + +unsigned long BitVector_Chunk_Read(unsigned int * addr, unsigned int chunksize, unsigned int offset) +{ + unsigned int bits = bits_(addr); + unsigned int chunkbits = 0; + unsigned long value = 0L; + unsigned long temp; + unsigned int mask; + + if ((chunksize > 0) && (offset < bits)) + { + if (chunksize > LONGBITS) chunksize = LONGBITS; + if ((offset + chunksize) > bits) chunksize = bits - offset; + addr += offset >> LOGBITS; + offset &= MODMASK; + while (chunksize > 0) + { + bits = offset + chunksize; + if (bits < BITS) + { + mask = (unsigned int) ~(~0L << bits); + bits = chunksize; + } + else + { + mask = (unsigned int) ~0L; + bits = BITS - offset; + } + temp = (unsigned long) ((*addr++ & mask) >> offset); + value |= temp << chunkbits; + chunkbits += bits; + chunksize -= bits; + offset = 0; + } + } + return(value); +} + + /*******************/ + /* set operations: */ + /*******************/ + +void Set_Union(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y + Z */ +{ + unsigned int bits = bits_(X); + unsigned int size = size_(X); + unsigned int mask = mask_(X); + + if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ | *Z++; + *(--X) &= mask; + } +} + +void Set_Intersection(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y * Z */ +{ + unsigned int bits = bits_(X); + unsigned int size = size_(X); + unsigned int mask = mask_(X); + + if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ & *Z++; + *(--X) &= mask; + } +} + +void Set_Difference(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y \ Z */ +{ + unsigned int bits = bits_(X); + unsigned int size = size_(X); + unsigned int mask = mask_(X); + + if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ & ~ *Z++; + *(--X) &= mask; + } +} + +void Set_ExclusiveOr(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X=(Y+Z)\(Y*Z) */ +{ + unsigned int bits = bits_(X); + unsigned int size = size_(X); + unsigned int mask = mask_(X); + + if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z))) + { + while (size-- > 0) *X++ = *Y++ ^ *Z++; + *(--X) &= mask; + } +} + +void Set_Complement(unsigned int * X, unsigned int * Y) /* X = ~Y */ +{ + unsigned int size = size_(X); + unsigned int mask = mask_(X); + + if ((size > 0) && (bits_(X) == bits_(Y))) + { + while (size-- > 0) *X++ = ~ *Y++; + *(--X) &= mask; + } +} + + /******************/ + /* set functions: */ + /******************/ + +boolean Set_subset(unsigned int * X, unsigned int * Y) /* X subset Y ? */ +{ + unsigned int size = size_(X); + boolean r = false; + + if ((size > 0) && (bits_(X) == bits_(Y))) + { + r = true; + while (r && (size-- > 0)) r = ((*X++ & ~ *Y++) == 0); + } + return(r); +} + +unsigned int Set_Norm(unsigned int * addr) /* = | X | */ +{ + unsigned char * byte; + unsigned int bytes; + unsigned int n; + + byte = (unsigned char *) addr; + bytes = size_(addr) << FACTOR; + n = 0; + while (bytes-- > 0) + { + n += BitVector_BYTENORM[*byte++]; + } + return(n); +} + +unsigned int Set_Norm2(unsigned int * addr) /* = | X | */ +{ + unsigned int size = size_(addr); + unsigned int w0,w1; + unsigned int n,k; + + n = 0; + while (size-- > 0) + { + k = 0; + w1 = ~ (w0 = *addr++); + while (w0 && w1) + { + w0 &= w0 - 1; + w1 &= w1 - 1; + k++; + } + if (w0 == 0) n += k; + else n += BITS - k; + } + return(n); +} + +unsigned int Set_Norm3(unsigned int * addr) /* = | X | */ +{ + unsigned int size = size_(addr); + unsigned int count = 0; + unsigned int c; + + while (size-- > 0) + { + c = *addr++; + while (c) + { + c &= c - 1; + count++; + } + } + return(count); +} + +signed long Set_Min(unsigned int * addr) /* = min(X) */ +{ + boolean empty = true; + unsigned int size = size_(addr); + unsigned int i = 0; + unsigned int c = 0; /* silence compiler warning */ + + while (empty && (size-- > 0)) + { + if ((c = *addr++)) empty = false; else i++; + } + if (empty) return((signed long) LONG_MAX); /* plus infinity */ + i <<= LOGBITS; + while (! (c & LSB)) + { + c >>= 1; + i++; + } + return((signed long) i); +} + +signed long Set_Max(unsigned int * addr) /* = max(X) */ +{ + boolean empty = true; + unsigned int size = size_(addr); + unsigned int i = size; + unsigned int c = 0; /* silence compiler warning */ + + addr += size-1; + while (empty && (size-- > 0)) + { + if ((c = *addr--)) empty = false; else i--; + } + if (empty) return((signed long) LONG_MIN); /* minus infinity */ + i <<= LOGBITS; + while (! (c & MSB)) + { + c <<= 1; + i--; + } + return((signed long) --i); +} + + /**********************************/ + /* matrix-of-booleans operations: */ + /**********************************/ + +void Matrix_Multiplication(unsigned int * X, unsigned int rowsX, unsigned int colsX, + unsigned int * Y, unsigned int rowsY, unsigned int colsY, + unsigned int * Z, unsigned int rowsZ, unsigned int colsZ) +{ + unsigned int i; + unsigned int j; + unsigned int k; + unsigned int indxX; + unsigned int indxY; + unsigned int indxZ; + unsigned int termX; + unsigned int termY; + unsigned int sum; + + if ((colsY == rowsZ) && (rowsX == rowsY) && (colsX == colsZ) && + (bits_(X) == rowsX*colsX) && + (bits_(Y) == rowsY*colsY) && + (bits_(Z) == rowsZ*colsZ)) + { + for ( i = 0; i < rowsY; i++ ) + { + termX = i * colsX; + termY = i * colsY; + for ( j = 0; j < colsZ; j++ ) + { + indxX = termX + j; + sum = 0; + for ( k = 0; k < colsY; k++ ) + { + indxY = termY + k; + indxZ = k * colsZ + j; + if ( BIT_VECTOR_TST_BIT(Y,indxY) & + BIT_VECTOR_TST_BIT(Z,indxZ) ) sum ^= 1; + } + if (sum) BIT_VECTOR_SET_BIT(X,indxX) + else BIT_VECTOR_CLR_BIT(X,indxX) + } + } + } +} + +void Matrix_Product(unsigned int * X, unsigned int rowsX, unsigned int colsX, + unsigned int * Y, unsigned int rowsY, unsigned int colsY, + unsigned int * Z, unsigned int rowsZ, unsigned int colsZ) +{ + unsigned int i; + unsigned int j; + unsigned int k; + unsigned int indxX; + unsigned int indxY; + unsigned int indxZ; + unsigned int termX; + unsigned int termY; + unsigned int sum; + + if ((colsY == rowsZ) && (rowsX == rowsY) && (colsX == colsZ) && + (bits_(X) == rowsX*colsX) && + (bits_(Y) == rowsY*colsY) && + (bits_(Z) == rowsZ*colsZ)) + { + for ( i = 0; i < rowsY; i++ ) + { + termX = i * colsX; + termY = i * colsY; + for ( j = 0; j < colsZ; j++ ) + { + indxX = termX + j; + sum = 0; + for ( k = 0; k < colsY; k++ ) + { + indxY = termY + k; + indxZ = k * colsZ + j; + if ( BIT_VECTOR_TST_BIT(Y,indxY) & + BIT_VECTOR_TST_BIT(Z,indxZ) ) sum |= 1; + } + if (sum) BIT_VECTOR_SET_BIT(X,indxX) + else BIT_VECTOR_CLR_BIT(X,indxX) + } + } + } +} + +void Matrix_Closure(unsigned int * addr, unsigned int rows, unsigned int cols) +{ + unsigned int i; + unsigned int j; + unsigned int k; + unsigned int ii; + unsigned int ij; + unsigned int ik; + unsigned int kj; + unsigned int termi; + unsigned int termk; + + if ((rows == cols) && (bits_(addr) == rows*cols)) + { + for ( i = 0; i < rows; i++ ) + { + ii = i * cols + i; + BIT_VECTOR_SET_BIT(addr,ii) + } + for ( k = 0; k < rows; k++ ) + { + termk = k * cols; + for ( i = 0; i < rows; i++ ) + { + termi = i * cols; + ik = termi + k; + for ( j = 0; j < rows; j++ ) + { + ij = termi + j; + kj = termk + j; + if ( BIT_VECTOR_TST_BIT(addr,ik) & + BIT_VECTOR_TST_BIT(addr,kj) ) + BIT_VECTOR_SET_BIT(addr,ij) + } + } + } + } +} + +void Matrix_Transpose(unsigned int * X, unsigned int rowsX, unsigned int colsX, + unsigned int * Y, unsigned int rowsY, unsigned int colsY) +{ + unsigned int i; + unsigned int j; + unsigned int ii; + unsigned int ij; + unsigned int ji; + unsigned int addii; + unsigned int addij; + unsigned int addji; + unsigned int bitii; + unsigned int bitij; + unsigned int bitji; + unsigned int termi; + unsigned int termj; + boolean swap; + + /* BEWARE that "in-place" is ONLY possible if the matrix is quadratic!! */ + + if ((rowsX == colsY) && (colsX == rowsY) && + (bits_(X) == rowsX*colsX) && + (bits_(Y) == rowsY*colsY)) + { + if (rowsY == colsY) /* in-place is possible! */ + { + for ( i = 0; i < rowsY; i++ ) + { + termi = i * colsY; + for ( j = 0; j < i; j++ ) + { + termj = j * colsX; + ij = termi + j; + ji = termj + i; + addij = ij >> LOGBITS; + addji = ji >> LOGBITS; + bitij = BITMASKTAB[ij & MODMASK]; + bitji = BITMASKTAB[ji & MODMASK]; + swap = ((*(Y+addij) & bitij) != 0); + if ((*(Y+addji) & bitji) != 0) + *(X+addij) |= bitij; + else + *(X+addij) &= ~ bitij; + if (swap) + *(X+addji) |= bitji; + else + *(X+addji) &= ~ bitji; + } + ii = termi + i; + addii = ii >> LOGBITS; + bitii = BITMASKTAB[ii & MODMASK]; + if ((*(Y+addii) & bitii) != 0) + *(X+addii) |= bitii; + else + *(X+addii) &= ~ bitii; + } + } + else /* rowsX != colsX, in-place is ~ possible! */ + { + for ( i = 0; i < rowsY; i++ ) + { + termi = i * colsY; + for ( j = 0; j < colsY; j++ ) + { + termj = j * colsX; + ij = termi + j; + ji = termj + i; + addij = ij >> LOGBITS; + addji = ji >> LOGBITS; + bitij = BITMASKTAB[ij & MODMASK]; + bitji = BITMASKTAB[ji & MODMASK]; + if ((*(Y+addij) & bitij) != 0) + *(X+addji) |= bitji; + else + *(X+addji) &= ~ bitji; + } + } + } + } +} +}; //end of namespace CONSTANTBV diff --git a/stp/constantbv/constantbv.h b/stp/constantbv/constantbv.h new file mode 100644 index 00000000..47e0c56f --- /dev/null +++ b/stp/constantbv/constantbv.h @@ -0,0 +1,316 @@ +#ifndef MODULE_BIT_VECTOR +#define MODULE_BIT_VECTOR +/*****************************************************************************/ +/* AUTHOR: */ +/*****************************************************************************/ +/* */ +/* Steffen Beyer */ +/* mailto:sb@engelschall.com */ +/* http://www.engelschall.com/u/sb/download/ */ +/* */ +/*****************************************************************************/ +/* COPYRIGHT: */ +/*****************************************************************************/ +/* */ +/* Copyright (c) 1995 - 2004 by Steffen Beyer. */ +/* All rights reserved. */ +/* */ +/*****************************************************************************/ +/* LICENSE: */ +/*****************************************************************************/ +/* */ +/* This library is free software; you can redistribute it and/or */ +/* modify it under the terms of the GNU Library General Public */ +/* License as published by the Free Software Foundation; either */ +/* version 2 of the License, or (at your option) any later version. */ +/* */ +/* This library is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ +/* Library General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU Library General Public */ +/* License along with this library; if not, write to the */ +/* Free Software Foundation, Inc., */ +/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* */ +/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */ +/* */ +/*****************************************************************************/ + + +/*****************************************************************************/ +/* MODULE NAME: BitVector.h MODULE TYPE: (adt) */ +/*****************************************************************************/ +/* MODULE IMPORTS: */ +/*****************************************************************************/ +#include <stdlib.h> /* MODULE TYPE: (sys) */ +#include <limits.h> /* MODULE TYPE: (sys) */ +#include <string.h> /* MODULE TYPE: (sys) */ +#include <ctype.h> /* MODULE TYPE: (sys) */ +/*****************************************************************************/ +/* MODULE INTERFACE: */ +/*****************************************************************************/ + +namespace CONSTANTBV { + +#ifdef __cplusplus + extern "C" { + typedef bool boolean; +#else + typedef enum { false = (0!=0), true = (0==0) } boolean; +#endif + + typedef enum { + ErrCode_Ok = 0, /* everything went allright */ + ErrCode_Type, /* types word and size_t have incompatible sizes */ + ErrCode_Bits, /* bits of word and sizeof(word) are inconsistent */ + ErrCode_Word, /* size of word is less than 16 bits */ + ErrCode_Long, /* size of word is greater than size of long */ + ErrCode_Powr, /* number of bits of word is not a power of two */ + ErrCode_Loga, /* error in calculation of logarithm */ + ErrCode_Null, /* unable to allocate memory */ + ErrCode_Indx, /* index out of range */ + ErrCode_Ordr, /* minimum > maximum index */ + ErrCode_Size, /* bit vector size mismatch */ + ErrCode_Pars, /* input string syntax error */ + ErrCode_Ovfl, /* numeric overflow error */ + ErrCode_Same, /* operands must be distinct */ + ErrCode_Expo, /* exponent must be positive */ + ErrCode_Zero /* division by zero error */ + } ErrCode; + + + /* ===> MISCELLANEOUS BASIC FUNCTIONS: <=== */ + unsigned char * BitVector_Error(ErrCode error); /* return string for err code */ + ErrCode BitVector_Boot (void); /* 0 = ok, 1..7 = error */ + unsigned int BitVector_Size(unsigned int bits); /* bit vector size (# of words) */ + unsigned int BitVector_Mask(unsigned int bits); /* bit vector mask (unused bits) */ + + /* ===> CLASS METHODS: <=== */ + unsigned char * BitVector_Version(void); /* return version string */ + unsigned int BitVector_Word_Bits(void); /* return # of bits in machine word */ + unsigned int BitVector_Long_Bits(void); /* return # of bits in unsigned long */ + + /* ===> CONSTRUCTOR METHODS: <=== */ + unsigned int * BitVector_Create (unsigned int bits, boolean clear); /* malloc */ + unsigned int ** BitVector_Create_List (unsigned int bits, boolean clear, unsigned int count); + unsigned int * BitVector_Resize (unsigned int * oldaddr, unsigned int bits); /* realloc */ + unsigned int * BitVector_Shadow (unsigned int * addr); /* make new same size but empty */ + unsigned int * BitVector_Clone (unsigned int * addr); /* make exact duplicate */ + unsigned int * BitVector_Concat (unsigned int * X, unsigned int * Y); /* return concatenation */ + + /* ===> DESTRUCTOR METHODS: <=== */ + void BitVector_Dispose (unsigned char * string); /* string */ + void BitVector_Destroy (unsigned int * addr); /* bitvec */ + void BitVector_Destroy_List (unsigned int * * list, unsigned int count); /* list */ + + /* ===> OBJECT METHODS: <=== */ + + /* ===> bit vector hash: */ + size_t BitVector_Hash (unsigned int * X); + + /* ===> bit vector copy function: */ + void BitVector_Copy (unsigned int * X, unsigned int * Y); /* X := Y */ + + /* ===> bit vector initialization: */ + void BitVector_Empty (unsigned int * addr); /* X = {} */ + void BitVector_Fill (unsigned int * addr); /* X = ~{} */ + void BitVector_Flip (unsigned int * addr); /* X = ~X */ + void BitVector_Primes (unsigned int * addr); + + /* ===> miscellaneous functions: */ + void BitVector_Reverse (unsigned int * X, unsigned int * Y); + + /* ===> bit vector interval operations and functions: */ + void BitVector_Interval_Empty (unsigned int * addr, unsigned int lower, unsigned int upper); + void BitVector_Interval_Fill (unsigned int * addr, unsigned int lower, unsigned int upper); + void BitVector_Interval_Flip (unsigned int * addr, unsigned int lower, unsigned int upper); + void BitVector_Interval_Reverse (unsigned int * addr, unsigned int lower, unsigned int upper); + + boolean BitVector_interval_scan_inc (unsigned int * addr, unsigned int start, + unsigned int * min, unsigned int * max); + boolean BitVector_interval_scan_dec (unsigned int * addr, unsigned int start, + unsigned int * min, unsigned int * max); + void BitVector_Interval_Copy (unsigned int * X, unsigned int * Y, + unsigned int Xoffset, unsigned int Yoffset, unsigned int length); + unsigned int * BitVector_Interval_Substitute(unsigned int * X, unsigned int * Y, + unsigned int Xoffset, unsigned int Xlength, + unsigned int Yoffset, unsigned int Ylength); + + /* ===> bit vector test functions: */ + boolean BitVector_is_empty (unsigned int * addr); /* X == {} ? */ + boolean BitVector_is_full (unsigned int * addr); /* X == ~{} ? */ + boolean BitVector_equal (unsigned int * X, unsigned int * Y); /* X == Y ? */ + signed int BitVector_Lexicompare (unsigned int * X, unsigned int * Y); /* X <,=,> Y ? */ + signed int BitVector_Compare (unsigned int * X, unsigned int * Y); /* X <,=,> Y ? */ + + /* ===> bit vector string conversion functions: */ + unsigned char * BitVector_to_Hex (unsigned int * addr); + ErrCode BitVector_from_Hex (unsigned int * addr, unsigned char * string); + unsigned char * BitVector_to_Bin (unsigned int * addr); + ErrCode BitVector_from_Bin (unsigned int * addr, unsigned char * string); + unsigned char * BitVector_to_Dec (unsigned int * addr); + ErrCode BitVector_from_Dec (unsigned int * addr, unsigned char * string); + unsigned char * BitVector_to_Enum (unsigned int * addr); + ErrCode BitVector_from_Enum (unsigned int * addr, unsigned char * string); + + /* ===> bit vector bit operations, functions & tests: */ + void BitVector_Bit_Off (unsigned int * addr, unsigned int index); /* X = X \ {x} */ + void BitVector_Bit_On (unsigned int * addr, unsigned int index); /* X = X + {x} */ + boolean BitVector_bit_flip (unsigned int * addr, unsigned int index); /* (X+{x})\(X*{x}) */ + boolean BitVector_bit_test (unsigned int * addr, unsigned int index); /* {x} in X ? */ + void BitVector_Bit_Copy (unsigned int * addr, unsigned int index, boolean bit); + + /* ===> bit vector bit shift & rotate functions: */ + void BitVector_LSB (unsigned int * addr, boolean bit); + void BitVector_MSB (unsigned int * addr, boolean bit); + boolean BitVector_lsb_ (unsigned int * addr); + boolean BitVector_msb_ (unsigned int * addr); + boolean BitVector_rotate_left (unsigned int * addr); + boolean BitVector_rotate_right (unsigned int * addr); + boolean BitVector_shift_left (unsigned int * addr, boolean carry_in); + boolean BitVector_shift_right (unsigned int * addr, boolean carry_in); + void BitVector_Move_Left (unsigned int * addr, unsigned int bits); + void BitVector_Move_Right (unsigned int * addr, unsigned int bits); + + /* ===> bit vector insert/delete bits: */ + void BitVector_Insert (unsigned int * addr, + unsigned int offset, unsigned int count, boolean clear); + void BitVector_Delete (unsigned int * addr, + unsigned int offset, unsigned int count, boolean clear); + + /* ===> bit vector arithmetic: */ + boolean BitVector_increment (unsigned int * addr); /* X++ */ + boolean BitVector_decrement (unsigned int * addr); /* X-- */ + boolean BitVector_compute (unsigned int * X, unsigned int * Y, + unsigned int * Z, boolean minus, boolean *carry); + boolean BitVector_add (unsigned int * X, + unsigned int * Y, unsigned int * Z, boolean *carry); + boolean BitVector_sub (unsigned int * X, + unsigned int * Y, unsigned int * Z, boolean *carry); /* X = Y-Z*/ + boolean BitVector_inc (unsigned int * X, unsigned int * Y); + boolean BitVector_dec (unsigned int * X, unsigned int * Y); + + void BitVector_Negate (unsigned int * X, unsigned int * Y); + void BitVector_Absolute (unsigned int * X, unsigned int * Y); + signed int BitVector_Sign (unsigned int * addr); + ErrCode BitVector_Mul_Pos (unsigned int * X, + unsigned int * Y, unsigned int * Z, boolean strict); + ErrCode BitVector_Multiply (unsigned int * X, unsigned int * Y, unsigned int * Z); + ErrCode BitVector_Div_Pos (unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R); + ErrCode BitVector_Divide (unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R); + ErrCode BitVector_GCD (unsigned int * X, unsigned int * Y, unsigned int * Z); + ErrCode BitVector_GCD2 (unsigned int * U, unsigned int * V, unsigned int * W, /* O */ + unsigned int * X, unsigned int * Y); /* I */ + ErrCode BitVector_Power (unsigned int * X, unsigned int * Y, unsigned int * Z); + + /* ===> direct memory access functions: */ + void BitVector_Block_Store (unsigned int * addr, + unsigned char * buffer, unsigned int length); + unsigned char * BitVector_Block_Read (unsigned int * addr, unsigned int * length); + + /* ===> word array functions: */ + void BitVector_Word_Store (unsigned int * addr, unsigned int offset, unsigned int value); + unsigned int BitVector_Word_Read (unsigned int * addr, unsigned int offset); + void BitVector_Word_Insert (unsigned int * addr, + unsigned int offset, unsigned int count, boolean clear); + void BitVector_Word_Delete (unsigned int * addr, + unsigned int offset, unsigned int count, boolean clear); + + /* ===> arbitrary size chunk functions: */ + void BitVector_Chunk_Store (unsigned int * addr, unsigned int chunksize, + unsigned int offset, unsigned long value); + unsigned long BitVector_Chunk_Read (unsigned int * addr, + unsigned int chunksize,unsigned int offset); + + /* ===> set operations: */ + void Set_Union (unsigned int * X, unsigned int * Y, unsigned int * Z); /* X = Y + Z */ + void Set_Intersection (unsigned int * X, unsigned int * Y, unsigned int * Z); /* X = Y * Z */ + void Set_Difference (unsigned int * X, unsigned int * Y, unsigned int * Z); /* X = Y \ Z */ + void Set_ExclusiveOr (unsigned int * X, unsigned int * Y, unsigned int * Z); /*(Y+Z)\(Y*Z)*/ + void Set_Complement (unsigned int * X, unsigned int * Y); /* X = ~Y */ + + /* ===> set functions: */ + boolean Set_subset (unsigned int * X, unsigned int * Y); /* X in Y ? */ + unsigned int Set_Norm (unsigned int * addr); /* = | X | */ + unsigned int Set_Norm2 (unsigned int * addr); /* = | X | */ + unsigned int Set_Norm3 (unsigned int * addr); /* = | X | */ + signed long Set_Min (unsigned int * addr); /* = min(X) */ + signed long Set_Max (unsigned int * addr); /* = max(X) */ + + /* ===> matrix-of-booleans operations: */ + void Matrix_Multiplication (unsigned int * X, unsigned int rowsX, unsigned int colsX, + unsigned int * Y, unsigned int rowsY, unsigned int colsY, + unsigned int * Z, unsigned int rowsZ, unsigned int colsZ); + void Matrix_Product (unsigned int * X, unsigned int rowsX, unsigned int colsX, + unsigned int * Y, unsigned int rowsY, unsigned int colsY, + unsigned int * Z, unsigned int rowsZ, unsigned int colsZ); + void Matrix_Closure (unsigned int * addr, unsigned int rows, unsigned int cols); + void Matrix_Transpose (unsigned int * X, unsigned int rowsX, unsigned int colsX, + unsigned int * Y, unsigned int rowsY, unsigned int colsY); + + /*****************************************************************************/ + /* MODULE RESOURCES: */ + /*****************************************************************************/ +#define bits_(BitVector) *(BitVector-3) +#define size_(BitVector) *(BitVector-2) +#define mask_(BitVector) *(BitVector-1) + +#define ERRCODE_TYPE "sizeof(word) > sizeof(size_t)" +#define ERRCODE_BITS "bits(word) != sizeof(word)*8" +#define ERRCODE_WORD "bits(word) < 16" +#define ERRCODE_LONG "bits(word) > bits(long)" +#define ERRCODE_POWR "bits(word) != 2^x" +#define ERRCODE_LOGA "bits(word) != 2^ld(bits(word))" +#define ERRCODE_NULL "unable to allocate memory" +#define ERRCODE_INDX "index out of range" +#define ERRCODE_ORDR "minimum > maximum index" +#define ERRCODE_SIZE "bit vector size mismatch" +#define ERRCODE_PARS "input string syntax error" +#define ERRCODE_OVFL "numeric overflow error" +#define ERRCODE_SAME "result vector(s) must be distinct" +#define ERRCODE_EXPO "exponent must be positive" +#define ERRCODE_ZERO "division by zero error" +#define ERRCODE_OOPS "unexpected internal error - please contact author" + + const unsigned int BitVector_BYTENORM[256] = { + 0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03, + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, /* 0x00 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x10 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x20 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x30 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x40 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x50 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x60 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0x70 */ + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x80 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x90 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xA0 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xB0 */ + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xC0 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xD0 */ + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xE0 */ + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, + 0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08 /* 0xF0 */ + }; +#ifdef __cplusplus + }; +#endif +}; //end of namespace CONSTANTBV +#endif + diff --git a/stp/parser/Makefile b/stp/parser/Makefile new file mode 100644 index 00000000..8211c825 --- /dev/null +++ b/stp/parser/Makefile @@ -0,0 +1,27 @@ +include ../Makefile.common + +SRCS = lexPL.cpp parsePL.cpp let-funcs.cpp main.cpp +OBJS = $(SRCS:.cpp=.o) +LIBS = -L../AST -last -L../sat -lsatsolver -L../simplifier -lsimplifier -L../bitvec -lconsteval -L../constantbv -lconstantbv + +all: parser + +parser: lexPL.o parsePL.o let-funcs.o main.o + $(CXX) $(CFLAGS) $(LDFLAGS) lexPL.o parsePL.o main.o let-funcs.o $(LIBS) -o parser + +main.o: parsePL_defs.h + +lexPL.cpp: PL.lex parsePL_defs.h ../AST/AST.h + $(LEX) -o lexPL.cpp PL.lex + +parsePL_defs.h: y.tab.h + @cp y.tab.h parsePL_defs.h +parsePL.cpp: y.tab.c + @cp y.tab.c parsePL.cpp + +y.tab.c y.tab.h: PL.y + $(YACC) PL.y + + +clean: + rm -rf *.o parsePL_defs.h *~ lexPL.cpp parsePL.cpp *.output parser y.tab.* lex.yy.c .#* diff --git a/stp/parser/PL.lex b/stp/parser/PL.lex new file mode 100644 index 00000000..e9358a0e --- /dev/null +++ b/stp/parser/PL.lex @@ -0,0 +1,128 @@ +%{ +/******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ +#include <iostream> +#include "../AST/AST.h" +#include "parsePL_defs.h" + +extern char *yytext; +extern int yyerror (const char *msg); +%} + +%option noyywrap +%option nounput +%option noreject +%option noyymore +%option yylineno +%x COMMENT +%x STRING_LITERAL +LETTER ([a-zA-Z]) +HEX ([0-9a-fA-F]) +BITS ([0-1]) +DIGIT ([0-9]) +OPCHAR (['?\_$]) +ANYTHING ({LETTER}|{DIGIT}|{OPCHAR}) +%% + +[()[\]{},.;:'!#?_=] { return yytext[0];} + +[\n] { /*Skip new line */ } +[ \t\r\f] { /* skip whitespace */ } +0b{BITS}+ { yylval.node = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(yytext+2, 2)); return BVCONST_TOK;} +0bin{BITS}+ { yylval.node = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(yytext+4, 2)); return BVCONST_TOK;} +0h{HEX}+ { yylval.node = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(yytext+2, 16)); return BVCONST_TOK;} +0hex{HEX}+ { yylval.node = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(yytext+4, 16)); return BVCONST_TOK;} +{DIGIT}+ { yylval.uintval = strtoul(yytext, NULL, 10); return NUMERAL_TOK;} + +"%" { BEGIN COMMENT;} +<COMMENT>"\n" { BEGIN INITIAL; /* return to normal mode */} +<COMMENT>. { /* stay in comment mode */} + +"ARRAY" { return ARRAY_TOK; } +"OF" { return OF_TOK; } +"WITH" { return WITH_TOK; } +"AND" { return AND_TOK;} +"NAND" { return NAND_TOK;} +"NOR" { return NOR_TOK;} +"NOT" { return NOT_TOK; } +"OR" { return OR_TOK; } +"/=" { return NEQ_TOK; } + ":=" { return ASSIGN_TOK;} +"=>" { return IMPLIES_TOK; } +"<=>" { return IFF_TOK; } +"XOR" { return XOR_TOK; } +"IF" { return IF_TOK; } +"THEN" { return THEN_TOK; } +"ELSE" { return ELSE_TOK; } +"ELSIF" { return ELSIF_TOK; } +"END" { return END_TOK; } +"ENDIF" { return ENDIF_TOK; } +"BV" { return BV_TOK;} +"BITVECTOR" { return BV_TOK;} +"BOOLEAN" { return BOOLEAN_TOK;} +"<<" { return BVLEFTSHIFT_TOK;} +">>" { return BVRIGHTSHIFT_TOK;} +"BVPLUS" { return BVPLUS_TOK;} +"BVSUB" { return BVSUB_TOK;} +"BVUMINUS" { return BVUMINUS_TOK;} +"BVMULT" { return BVMULT_TOK;} +"BVDIV" { return BVDIV_TOK;} +"BVMOD" { return BVMOD_TOK;} +"SBVDIV" { return SBVDIV_TOK;} +"SBVMOD" { return SBVMOD_TOK;} +"~" { return BVNEG_TOK;} +"&" { return BVAND_TOK;} +"|" { return BVOR_TOK;} +"BVXOR" { return BVXOR_TOK;} +"BVNAND" { return BVNAND_TOK;} +"BVNOR" { return BVNOR_TOK;} +"BVXNOR" { return BVXNOR_TOK;} +"@" { return BVCONCAT_TOK;} +"BVLT" { return BVLT_TOK;} +"BVGT" { return BVGT_TOK;} +"BVLE" { return BVLE_TOK;} +"BVGE" { return BVGE_TOK;} +"BVSLT" { return BVSLT_TOK;} +"BVSGT" { return BVSGT_TOK;} +"BVSLE" { return BVSLE_TOK;} +"BVSGE" { return BVSGE_TOK;} +"BVSX" { return BVSX_TOK;} +"SBVLT" { return BVSLT_TOK;} +"SBVGT" { return BVSGT_TOK;} +"SBVLE" { return BVSLE_TOK;} +"SBVGE" { return BVSGE_TOK;} +"SX" { return BVSX_TOK;} +"BOOLEXTRACT" { return BOOLEXTRACT_TOK;} +"BOOLBV" { return BOOL_TO_BV_TOK;} +"ASSERT" { return ASSERT_TOK; } +"QUERY" { return QUERY_TOK; } +"FALSE" { return FALSELIT_TOK;} +"TRUE" { return TRUELIT_TOK;} +"IN" { return IN_TOK;} +"LET" { return LET_TOK;} +"COUNTEREXAMPLE" { return COUNTEREXAMPLE_TOK;} +"COUNTERMODEL" { return COUNTEREXAMPLE_TOK;} + "PUSH" { return PUSH_TOK;} + "POP" { return POP_TOK;} + +(({LETTER})|(_)({ANYTHING}))({ANYTHING})* { + BEEV::ASTNode nptr = BEEV::globalBeevMgr_for_parser->CreateSymbol(yytext); + + // Check valuesize to see if it's a prop var. I don't like doing + // type determination in the lexer, but it's easier than rewriting + // the whole grammar to eliminate the term/formula distinction. + yylval.node = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->ResolveID(nptr)); + //yylval.node = new BEEV::ASTNode(nptr); + if ((yylval.node)->GetType() == BEEV::BOOLEAN_TYPE) + return FORMID_TOK; + else + return TERMID_TOK; +} + +. { yyerror("Illegal input character."); } +%% diff --git a/stp/parser/PL.y b/stp/parser/PL.y new file mode 100644 index 00000000..aa58aa4c --- /dev/null +++ b/stp/parser/PL.y @@ -0,0 +1,1006 @@ +%{ +/******************************************************************** + * 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/AST.h" +using namespace std; + + // Suppress the bogus warning suppression in bison (it generates + // compile error) +#undef __GNUC_MINOR__ + + extern int yylex(void); + extern char* yytext; + extern int yylineno; + int yyerror(const char *s) { + cout << "syntax error: line " << yylineno << "\n" << s << endl; + BEEV::FatalError(""); + return 1; /* Dill: don't know what it should return */ + }; + +#define YYLTYPE_IS_TRIVIAL 1 +#define YYMAXDEPTH 10485760 +#define YYERROR_VERBOSE 1 +#define YY_EXIT_FAILURE -1 +%} + +%union { + + unsigned int uintval; /* for numerals in types. */ + struct { + //stores the indexwidth and valuewidth + //indexwidth is 0 iff type is bitvector. positive iff type is + //array, and stores the width of the indexing bitvector + unsigned int indexwidth; + //width of the bitvector type + unsigned int valuewidth; + } indexvaluewidth; + + //ASTNode,ASTVec + BEEV::ASTNode *node; + BEEV::ASTVec *vec; + + //Hash_Map to hold Array Updates during parse A map from array index + //to array values. To support the WITH construct + BEEV::ASTNodeMap * Index_To_UpdateValue; +}; + +%start cmd + +%token AND_TOK "AND" +%token OR_TOK "OR" +%token NOT_TOK "NOT" +%token XOR_TOK "XOR" +%token NAND_TOK "NAND" +%token NOR_TOK "NOR" +%token IMPLIES_TOK "=>" +%token IFF_TOK "<=>" + +%token IF_TOK "IF" +%token THEN_TOK "THEN" +%token ELSE_TOK "ELSE" +%token ELSIF_TOK "ELSIF" +%token END_TOK "END" +%token ENDIF_TOK "ENDIF" +%token NEQ_TOK "/=" +%token ASSIGN_TOK ":=" + +%token BV_TOK "BV" +%token BVLEFTSHIFT_TOK "<<" +%token BVRIGHTSHIFT_TOK ">>" +%token BVPLUS_TOK "BVPLUS" +%token BVSUB_TOK "BVSUB" +%token BVUMINUS_TOK "BVUMINUS" +%token BVMULT_TOK "BVMULT" + +%token BVDIV_TOK "BVDIV" +%token BVMOD_TOK "BVMOD" +%token SBVDIV_TOK "SBVDIV" +%token SBVMOD_TOK "SBVMOD" + + +%token BVNEG_TOK "~" +%token BVAND_TOK "&" +%token BVOR_TOK "|" +%token BVXOR_TOK "BVXOR" +%token BVNAND_TOK "BVNAND" +%token BVNOR_TOK "BVNOR" +%token BVXNOR_TOK "BVXNOR" +%token BVCONCAT_TOK "@" + +%token BVLT_TOK "BVLT" +%token BVGT_TOK "BVGT" +%token BVLE_TOK "BVLE" +%token BVGE_TOK "BVGE" + +%token BVSLT_TOK "BVSLT" +%token BVSGT_TOK "BVSGT" +%token BVSLE_TOK "BVSLE" +%token BVSGE_TOK "BVSGE" +%token BOOL_TO_BV_TOK "BOOLBV" +%token BVSX_TOK "BVSX" +%token BOOLEXTRACT_TOK "BOOLEXTRACT" +%token ASSERT_TOK "ASSERT" +%token QUERY_TOK "QUERY" + +%token BOOLEAN_TOK "BOOLEAN" +%token ARRAY_TOK "ARRAY" +%token OF_TOK "OF" +%token WITH_TOK "WITH" + +%token TRUELIT_TOK "TRUE" +%token FALSELIT_TOK "FALSE" + +%token IN_TOK "IN" +%token LET_TOK "LET" +//%token COUNTEREXAMPLE_TOK "COUNTEREXAMPLE" +%token PUSH_TOK "PUSH" +%token POP_TOK "POP" + +%left IN_TOK +%left XOR_TOK +%left IFF_TOK +%right IMPLIES_TOK +%left OR_TOK +%left AND_TOK +%left NAND_TOK +%left NOR_TOK +%left NOT_TOK +%left BVCONCAT_TOK +%left BVOR_TOK +%left BVAND_TOK +%left BVXOR_TOK +%left BVNAND_TOK +%left BVNOR_TOK +%left BVXNOR_TOK +%left BVNEG_TOK +%left BVLEFTSHIFT_TOK BVRIGHTSHIFT_TOK +%left WITH_TOK + +%nonassoc '=' NEQ_TOK ASSIGN_TOK +%nonassoc BVLT_TOK BVLE_TOK BVGT_TOK BVGE_TOK +%nonassoc BVUMINUS_TOK BVPLUS_TOK BVSUB_TOK BVSX_TOK +%nonassoc '[' +%nonassoc '{' '.' '(' +%nonassoc BV_TOK + +%type <vec> Exprs FORM_IDs reverseFORM_IDs +%type <vec> Asserts +%type <node> Expr Formula IfExpr ElseRestExpr IfForm ElseRestForm Assert Query ArrayUpdateExpr +%type <Index_To_UpdateValue> Updates + +%type <indexvaluewidth> BvType BoolType ArrayType Type + +%token <node> BVCONST_TOK +%token <node> TERMID_TOK FORMID_TOK COUNTEREXAMPLE_TOK +%token <uintval> NUMERAL_TOK + +%% + +cmd : other_cmd + | other_cmd counterexample + ; + +counterexample : COUNTEREXAMPLE_TOK ';' + { + BEEV::print_counterexample = true; + BEEV::globalBeevMgr_for_parser->PrintCounterExample(true); + } + ; + +other_cmd : other_cmd1 + | Query + { + BEEV::globalBeevMgr_for_parser->TopLevelSAT(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::TRUE),*$1); + delete $1; + } + | VarDecls Query + { + BEEV::globalBeevMgr_for_parser->TopLevelSAT(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::TRUE),*$2); + delete $2; + } + | other_cmd1 Query + { + BEEV::ASTVec aaa = BEEV::globalBeevMgr_for_parser->GetAsserts(); + if(aaa.size() == 0) + yyerror("Fatal Error: parsing: GetAsserts() call: no assertions: "); + if(aaa.size() == 1) + BEEV::globalBeevMgr_for_parser->TopLevelSAT(aaa[0],*$2); + else + BEEV::globalBeevMgr_for_parser->TopLevelSAT(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::AND,aaa),*$2); + delete $2; + } + ; + +other_cmd1 : VarDecls Asserts + { + delete $2; + } + | Asserts + { + delete $1; + } + | other_cmd1 VarDecls Asserts + { + delete $3; + } + ; + +/* push : PUSH_TOK */ +/* { */ +/* BEEV::globalBeevMgr_for_parser->Push(); */ +/* } */ +/* | */ +/* ; */ + +/* pop : POP_TOK */ +/* { */ +/* BEEV::globalBeevMgr_for_parser->Pop(); */ +/* } */ +/* | */ +/* ; */ + +Asserts : Assert + { + $$ = new BEEV::ASTVec; + $$->push_back(*$1); + BEEV::globalBeevMgr_for_parser->AddAssert(*$1); + delete $1; + } + | Asserts Assert + { + $1->push_back(*$2); + BEEV::globalBeevMgr_for_parser->AddAssert(*$2); + $$ = $1; + delete $2; + } + ; + +Assert : ASSERT_TOK Formula ';' { $$ = $2; } + ; + +Query : QUERY_TOK Formula ';' { BEEV::globalBeevMgr_for_parser->AddQuery(*$2); $$ = $2;} + ; + + +/* Grammar for Variable Declaration */ +VarDecls : VarDecl ';' + { + } + | VarDecls VarDecl ';' + { + } + ; + +VarDecl : FORM_IDs ':' Type + { + for(BEEV::ASTVec::iterator i=$1->begin(),iend=$1->end();i!=iend;i++) { + BEEV::_parser_symbol_table.insert(*i); + i->SetIndexWidth($3.indexwidth); + i->SetValueWidth($3.valuewidth); + + //FIXME: HACK_ATTACK. this vector was hacked into the code to + //support a special request by Dawson' group. They want the + //counterexample to be printed in the order of variables declared. + BEEV::globalBeevMgr_for_parser->_special_print_set.push_back(*i); + } + delete $1; + } + | FORM_IDs ':' Type '=' Expr + { + //do type checking. if doesn't pass then abort + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$5); + if($3.indexwidth != $5->GetIndexWidth()) + yyerror("Fatal Error: parsing: LET Expr: Type check fail: "); + if($3.valuewidth != $5->GetValueWidth()) + yyerror("Fatal Error: parsing: LET Expr: Type check fail: "); + + for(BEEV::ASTVec::iterator i=$1->begin(),iend=$1->end();i!=iend;i++) { + //set the valuewidth of the identifier + i->SetValueWidth($5->GetValueWidth()); + i->SetIndexWidth($5->GetIndexWidth()); + + BEEV::globalBeevMgr_for_parser->LetExprMgr(*i,*$5); + delete $5; + } + } + | FORM_IDs ':' Type '=' Formula + { + //do type checking. if doesn't pass then abort + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$5); + if($3.indexwidth != $5->GetIndexWidth()) + yyerror("Fatal Error: parsing: LET Expr: Type check fail: "); + if($3.valuewidth != $5->GetValueWidth()) + yyerror("Fatal Error: parsing: LET Expr: Type check fail: "); + + for(BEEV::ASTVec::iterator i=$1->begin(),iend=$1->end();i!=iend;i++) { + //set the valuewidth of the identifier + i->SetValueWidth($5->GetValueWidth()); + i->SetIndexWidth($5->GetIndexWidth()); + + BEEV::globalBeevMgr_for_parser->LetExprMgr(*i,*$5); + delete $5; + } + } + ; + +reverseFORM_IDs : FORMID_TOK + { + $$ = new BEEV::ASTVec; + $$->push_back(*$1); + delete $1; + } + | FORMID_TOK ',' reverseFORM_IDs + { + $3->push_back(*$1); + $$ = $3; + delete $1; + } + ; + +FORM_IDs : reverseFORM_IDs + { + $$ = new BEEV::ASTVec($1->rbegin(),$1->rend()); + delete $1; + } + ; + +/* Grammar for Types */ +Type : BvType { $$ = $1; } + | BoolType { $$ = $1; } + | ArrayType { $$ = $1; } + ; + +BvType : BV_TOK '(' NUMERAL_TOK ')' + { + /*((indexwidth is 0) && (valuewidth>0)) iff type is BV*/ + $$.indexwidth = 0; + unsigned int length = $3; + if(length > 0) { + $$.valuewidth = length; + } + else + BEEV::FatalError("Fatal Error: parsing: BITVECTORS must be of positive length: \n"); + } + ; +BoolType : BOOLEAN_TOK + { + $$.indexwidth = 0; + $$.valuewidth = 0; + } + ; +ArrayType : ARRAY_TOK BvType OF_TOK BvType + { + $$.indexwidth = $2.valuewidth; + $$.valuewidth = $4.valuewidth; + } + ; + +/*Grammar for ITEs which are a type of Term*/ +IfExpr : IF_TOK Formula THEN_TOK Expr ElseRestExpr + { + unsigned int width = $4->GetValueWidth(); + if (width != $5->GetValueWidth()) + yyerror("Width mismatch in IF-THEN-ELSE"); + if($4->GetIndexWidth() != $5->GetIndexWidth()) + yyerror("Width mismatch in IF-THEN-ELSE"); + + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$2); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$4); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$5); + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::ITE, width, *$2, *$4, *$5)); + $$->SetIndexWidth($5->GetIndexWidth()); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$$); + delete $2; + delete $4; + delete $5; + } + ; + +ElseRestExpr : ELSE_TOK Expr ENDIF_TOK { $$ = $2; } + | ELSIF_TOK Expr THEN_TOK Expr ElseRestExpr + { + unsigned int width = $2->GetValueWidth(); + if (width != $4->GetValueWidth() || width != $5->GetValueWidth()) + yyerror("Width mismatch in IF-THEN-ELSE"); + if ($2->GetIndexWidth() != $4->GetValueWidth() || $2->GetIndexWidth() != $5->GetValueWidth()) + yyerror("Width mismatch in IF-THEN-ELSE"); + + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$2); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$4); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$5); + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::ITE, width, *$2, *$4, *$5)); + $$->SetIndexWidth($5->GetIndexWidth()); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$$); + delete $2; + delete $4; + delete $5; + } + ; + +/* Grammar for formulas */ +Formula : '(' Formula ')' { $$ = $2; } + | FORMID_TOK { $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->ResolveID(*$1)); delete $1;} + | BOOLEXTRACT_TOK '(' Expr ',' NUMERAL_TOK ')' + { + unsigned int width = $3->GetValueWidth(); + if(0 > (unsigned)$5 || width <= (unsigned)$5) + yyerror("Fatal Error: BOOLEXTRACT: trying to boolextract a bit which beyond range"); + + BEEV::ASTNode hi = BEEV::globalBeevMgr_for_parser->CreateBVConst(32, $5); + BEEV::ASTNode low = BEEV::globalBeevMgr_for_parser->CreateBVConst(32, $5); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVEXTRACT,1,*$3,hi,low)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + BEEV::ASTNode zero = BEEV::globalBeevMgr_for_parser->CreateBVConst(1,0); + BEEV::ASTNode * out = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::EQ,*n,zero)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*out); + + $$ = out; + delete $3; + } + | Expr '=' Expr + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::EQ, *$1, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $1; + delete $3; + } + | Expr NEQ_TOK Expr + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::NEQ, *$1, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $1; + delete $3; + } + | NOT_TOK Formula + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::NOT, *$2)); + delete $2; + } + | Formula OR_TOK Formula %prec OR_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::OR, *$1, *$3)); + delete $1; + delete $3; + } + | Formula NOR_TOK Formula + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::NOR, *$1, *$3)); + delete $1; + delete $3; + } + | Formula AND_TOK Formula %prec AND_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::AND, *$1, *$3)); + delete $1; + delete $3; + } + | Formula NAND_TOK Formula + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::NAND, *$1, *$3)); + delete $1; + delete $3; + } + | Formula IMPLIES_TOK Formula + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::IMPLIES, *$1, *$3)); + delete $1; + delete $3; + } + | Formula IFF_TOK Formula + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::IFF, *$1, *$3)); + delete $1; + delete $3; + } + | Formula XOR_TOK Formula + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::XOR, *$1, *$3)); + delete $1; + delete $3; + } + | BVLT_TOK '(' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVLT, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $5; + } + | BVGT_TOK '(' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVGT, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $5; + } + | BVLE_TOK '(' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVLE, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $5; + } + | BVGE_TOK '(' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVGE, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $5; + } + | BVSLT_TOK '(' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVSLT, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $5; + } + | BVSGT_TOK '(' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVSGT, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $5; + } + | BVSLE_TOK '(' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVSLE, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $5; + } + | BVSGE_TOK '(' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVSGE, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $5; + } + | IfForm + | TRUELIT_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::TRUE)); + $$->SetIndexWidth(0); + $$->SetValueWidth(0); + } + | FALSELIT_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::FALSE)); + $$->SetIndexWidth(0); + $$->SetValueWidth(0); + } + + | LET_TOK LetDecls IN_TOK Formula + { + $$ = $4; + //Cleanup the LetIDToExprMap + BEEV::globalBeevMgr_for_parser->CleanupLetIDMap(); + } + ; + +/*Grammar for ITEs which are Formulas */ +IfForm : IF_TOK Formula THEN_TOK Formula ElseRestForm + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::ITE, *$2, *$4, *$5)); + delete $2; + delete $4; + delete $5; + } + ; + +ElseRestForm : ELSE_TOK Formula ENDIF_TOK { $$ = $2; } + | ELSIF_TOK Formula THEN_TOK Formula ElseRestForm + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::ITE, *$2, *$4, *$5)); + delete $2; + delete $4; + delete $5; + } + ; + +/*Grammar for a list of expressions*/ +Exprs : Expr + { + $$ = new BEEV::ASTVec; + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$1); + $$->push_back(*$1); + delete $1; + } + | Exprs ',' Expr + { + $1->push_back(*$3); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$3); + $$ = $1; + delete $3; + } + ; + +/* Grammar for Expr */ +Expr : TERMID_TOK { $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->ResolveID(*$1)); delete $1;} + | '(' Expr ')' { $$ = $2; } + | BVCONST_TOK { $$ = $1; } + | BOOL_TO_BV_TOK '(' Formula ')' + { + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$3); + BEEV::ASTNode one = BEEV::globalBeevMgr_for_parser->CreateBVConst(1,1); + BEEV::ASTNode zero = BEEV::globalBeevMgr_for_parser->CreateBVConst(1,0); + + //return ITE(*$3, length(1), 0bin1, 0bin0) + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::ITE,1,*$3,one,zero)); + delete $3; + } + | Expr '[' Expr ']' + { + // valuewidth is same as array, indexwidth is 0. + unsigned int width = $1->GetValueWidth(); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::READ, width, *$1, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $1; + delete $3; + } + | Expr '(' Expr ')' //array read but in the form of a uninterpreted function application + { + // valuewidth is same as array, indexwidth is 0. + unsigned int width = $1->GetValueWidth(); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::READ, width, *$1, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $1; + delete $3; + } + | Expr '[' NUMERAL_TOK ':' NUMERAL_TOK ']' + { + int width = $3 - $5 + 1; + if (width < 0) + yyerror("Negative width in extract"); + + if((unsigned)$3 >= $1->GetValueWidth() || (unsigned)$5 < 0) + yyerror("Parsing: Wrong width in BVEXTRACT\n"); + + BEEV::ASTNode hi = BEEV::globalBeevMgr_for_parser->CreateBVConst(32, $3); + BEEV::ASTNode low = BEEV::globalBeevMgr_for_parser->CreateBVConst(32, $5); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVEXTRACT, width, *$1,hi,low)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $1; + } + | BVNEG_TOK Expr + { + unsigned int width = $2->GetValueWidth(); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVNEG, width, *$2)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + } + | Expr BVAND_TOK Expr + { + unsigned int width = $1->GetValueWidth(); + if (width != $3->GetValueWidth()) { + yyerror("Width mismatch in AND"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVAND, width, *$1, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $1; + delete $3; + } + | Expr BVOR_TOK Expr + { + unsigned int width = $1->GetValueWidth(); + if (width != $3->GetValueWidth()) { + yyerror("Width mismatch in OR"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVOR, width, *$1, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $1; + delete $3; + } + | BVXOR_TOK '(' Expr ',' Expr ')' + { + unsigned int width = $3->GetValueWidth(); + if (width != $5->GetValueWidth()) { + yyerror("Width mismatch in XOR"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVXOR, width, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $5; + } + | BVNAND_TOK '(' Expr ',' Expr ')' + { + unsigned int width = $3->GetValueWidth(); + if (width != $5->GetValueWidth()) { + yyerror("Width mismatch in NAND"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVNAND, width, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $3; + delete $5; + } + | BVNOR_TOK '(' Expr ',' Expr ')' + { + unsigned int width = $3->GetValueWidth(); + if (width != $5->GetValueWidth()) { + yyerror("Width mismatch in NOR"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVNOR, width, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $3; + delete $5; + } + | BVXNOR_TOK '(' Expr ',' Expr ')' + { + unsigned int width = $3->GetValueWidth(); + if (width != $5->GetValueWidth()) { + yyerror("Width mismatch in NOR"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVXNOR, width, *$3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $3; + delete $5; + } + | BVSX_TOK '(' Expr ',' NUMERAL_TOK ')' + { + //width of the expr which is being sign + //extended. $5 is the resulting length of the + //signextended expr + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$3); + if($3->GetValueWidth() == $5) { + $$ = $3; + } + else { + BEEV::ASTNode width = BEEV::globalBeevMgr_for_parser->CreateBVConst(32,$5); + BEEV::ASTNode *n = + new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVSX, $5,*$3,width)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + } + } + | Expr BVCONCAT_TOK Expr + { + unsigned int width = $1->GetValueWidth() + $3->GetValueWidth(); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVCONCAT, width, *$1, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $1; + delete $3; + } + | Expr BVLEFTSHIFT_TOK NUMERAL_TOK + { + BEEV::ASTNode zero_bits = BEEV::globalBeevMgr_for_parser->CreateZeroConst($3); + BEEV::ASTNode * n = + new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVCONCAT, + $1->GetValueWidth() + $3, *$1, zero_bits)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $1; + } + | Expr BVRIGHTSHIFT_TOK NUMERAL_TOK + { + BEEV::ASTNode len = BEEV::globalBeevMgr_for_parser->CreateZeroConst($3); + unsigned int w = $1->GetValueWidth(); + + //the amount by which you are rightshifting + //is less-than/equal-to the length of input + //bitvector + if((unsigned)$3 < w) { + BEEV::ASTNode hi = BEEV::globalBeevMgr_for_parser->CreateBVConst(32,w-1); + BEEV::ASTNode low = BEEV::globalBeevMgr_for_parser->CreateBVConst(32,$3); + BEEV::ASTNode extract = BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVEXTRACT,w-$3,*$1,hi,low); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVCONCAT, w,len, extract)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + } + else + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateZeroConst(w)); + + delete $1; + } + | BVPLUS_TOK '(' NUMERAL_TOK ',' Exprs ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVPLUS, $3, *$5)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $5; + } + | BVSUB_TOK '(' NUMERAL_TOK ',' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVSUB, $3, *$5, *$7)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $5; + delete $7; + } + | BVUMINUS_TOK '(' Expr ')' + { + unsigned width = $3->GetValueWidth(); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVUMINUS,width,*$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + } + | BVMULT_TOK '(' NUMERAL_TOK ',' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVMULT, $3, *$5, *$7)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $5; + delete $7; + } + | BVDIV_TOK '(' NUMERAL_TOK ',' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVDIV, $3, *$5, *$7)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $5; + delete $7; + } + | BVMOD_TOK '(' NUMERAL_TOK ',' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVMOD, $3, *$5, *$7)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $5; + delete $7; + } + | SBVDIV_TOK '(' NUMERAL_TOK ',' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::SBVDIV, $3, *$5, *$7)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $5; + delete $7; + } + | SBVMOD_TOK '(' NUMERAL_TOK ',' Expr ',' Expr ')' + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::SBVMOD, $3, *$5, *$7)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $5; + delete $7; + } + | IfExpr { $$ = $1; } + | ArrayUpdateExpr + | LET_TOK LetDecls IN_TOK Expr + { + $$ = $4; + //Cleanup the LetIDToExprMap + //BEEV::globalBeevMgr_for_parser->CleanupLetIDMap(); + } + ; + +/*Grammar for Array Update Expr*/ +ArrayUpdateExpr : Expr WITH_TOK Updates + { + BEEV::ASTNode * result; + unsigned int width = $1->GetValueWidth(); + + BEEV::ASTNodeMap::iterator it = $3->begin(); + BEEV::ASTNodeMap::iterator itend = $3->end(); + result = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::WRITE, + width, + *$1, + (*it).first, + (*it).second)); + result->SetIndexWidth($1->GetIndexWidth()); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*result); + for(it++;it!=itend;it++) { + result = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::WRITE, + width, + *result, + (*it).first, + (*it).second)); + result->SetIndexWidth($1->GetIndexWidth()); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*result); + } + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*result); + $$ = result; + delete $3; + } + ; + +Updates : '[' Expr ']' ASSIGN_TOK Expr + { + $$ = new BEEV::ASTNodeMap(); + (*$$)[*$2] = *$5; + } + | Updates WITH_TOK '[' Expr ']' ASSIGN_TOK Expr + { + (*$1)[*$4] = *$7; + } + ; + +/*Grammar for LET Expr*/ +LetDecls : LetDecl + | LetDecls ',' LetDecl + ; + +LetDecl : FORMID_TOK '=' Expr + { + //Expr must typecheck + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$3); + + //set the valuewidth of the identifier + $1->SetValueWidth($3->GetValueWidth()); + $1->SetIndexWidth($3->GetIndexWidth()); + + //populate the hashtable from LET-var --> + //LET-exprs and then process them: + // + //1. ensure that LET variables do not clash + //1. with declared variables. + // + //2. Ensure that LET variables are not + //2. defined more than once + BEEV::globalBeevMgr_for_parser->LetExprMgr(*$1,*$3); + delete $1; + delete $3; + } + | FORMID_TOK ':' Type '=' Expr + { + //do type checking. if doesn't pass then abort + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$5); + + if($3.indexwidth != $5->GetIndexWidth()) + yyerror("Fatal Error: parsing: LET Expr: Type check fail: "); + if($3.valuewidth != $5->GetValueWidth()) + yyerror("Fatal Error: parsing: LET Expr: Type check fail: "); + + //set the valuewidth of the identifier + $1->SetValueWidth($5->GetValueWidth()); + $1->SetIndexWidth($5->GetIndexWidth()); + + BEEV::globalBeevMgr_for_parser->LetExprMgr(*$1,*$5); + delete $1; + delete $5; + } + | FORMID_TOK '=' Formula + { + //Expr must typecheck + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$3); + + //set the valuewidth of the identifier + $1->SetValueWidth($3->GetValueWidth()); + $1->SetIndexWidth($3->GetIndexWidth()); + + //Do LET-expr management + BEEV::globalBeevMgr_for_parser->LetExprMgr(*$1,*$3); + delete $1; + delete $3; + } + | FORMID_TOK ':' Type '=' Formula + { + //do type checking. if doesn't pass then abort + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$5); + + if($3.indexwidth != $5->GetIndexWidth()) + yyerror("Fatal Error: parsing: LET Expr: Type check fail: "); + if($3.valuewidth != $5->GetValueWidth()) + yyerror("Fatal Error: parsing: LET Expr: Type check fail: "); + + //set the valuewidth of the identifier + $1->SetValueWidth($5->GetValueWidth()); + $1->SetIndexWidth($5->GetIndexWidth()); + + //Do LET-expr management + BEEV::globalBeevMgr_for_parser->LetExprMgr(*$1,*$5); + delete $1; + delete $5; + } + ; + +%% diff --git a/stp/parser/let-funcs.cpp b/stp/parser/let-funcs.cpp new file mode 100644 index 00000000..1de10492 --- /dev/null +++ b/stp/parser/let-funcs.cpp @@ -0,0 +1,85 @@ +/******************************************************************** + * 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/AST.h" +#include <stdlib.h> + +namespace BEEV { + //external parser table for declared symbols. Only symbols which are + //declared are stored here. + ASTNodeSet _parser_symbol_table; + + // FUNC: This function maintains a map between LET-var names and + // LET-expressions + // + //1. if the Let-var is already defined in the LET scope, then the + //1. function returns an error. + // + //2. if the Let-var is already declared variable in the input, then + //2. the function returns an error + // + //3. otherwise add the <var,letExpr> pair to the _letid_expr table. + void BeevMgr::LetExprMgr(const ASTNode& var, const ASTNode& letExpr) { + ASTNodeMap::iterator it; + if(((it = _letid_expr_map.find(var)) != _letid_expr_map.end()) && + it->second != ASTUndefined) { + FatalError("LetExprMgr:The LET-var v has already been defined in this LET scope: v =", var); + } + + if(_parser_symbol_table.find(var) != _parser_symbol_table.end()) { + FatalError("LetExprMgr:This var is already declared. cannot redeclare as a letvar: v =", var); + } + + _letid_expr_map[var] = letExpr; + } + + //this function looksup the "var to letexpr map" and returns the + //corresponding letexpr. if there is no letexpr, then it simply + //returns the var. + ASTNode BeevMgr::ResolveID(const ASTNode& v) { + if(v.GetKind() != SYMBOL) { + return v; + } + + if(_parser_symbol_table.find(v) != _parser_symbol_table.end()) { + return v; + } + + ASTNodeMap::iterator it; + if((it =_letid_expr_map.find(v)) != _letid_expr_map.end()) { + if(it->second == ASTUndefined) + FatalError("Unresolved Identifier: ",v); + else + return it->second; + } + + //this is to mark the let-var as undefined. the let var is defined + //only after the LetExprMgr has completed its work, and until then + //'v' is undefined. + // + //declared variables also get stored in this map, but there value + //is ASTUndefined. This is really a hack. I don't know how to get + //rid of this hack. + _letid_expr_map[v] = ASTUndefined; + return v; + } + + // This function simply cleans up the LetID -> LetExpr Map. + void BeevMgr::CleanupLetIDMap(void) { + ASTNodeMap::iterator it = _letid_expr_map.begin(); + ASTNodeMap::iterator itend = _letid_expr_map.end(); + for(;it!=itend;it++) { + if(it->second != ASTUndefined) { + it->first.SetValueWidth(0); + it->first.SetIndexWidth(0); + } + } + _letid_expr_map.clear(); + } +}; diff --git a/stp/parser/main.cpp b/stp/parser/main.cpp new file mode 100644 index 00000000..ed251ed3 --- /dev/null +++ b/stp/parser/main.cpp @@ -0,0 +1,181 @@ +/******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ +// -*- c++ -*- + +#include <iostream> +#include <sstream> +#include <string> +#include <algorithm> +#include <ctime> +#include <unistd.h> +#include <signal.h> +//#include <zlib.h> +#include <stdio.h> +#include "../AST/AST.h" +#include "parsePL_defs.h" +#include "../sat/Solver.h" +#include "../sat/SolverTypes.h" +#include "../sat/VarOrder.h" + +#include <unistd.h> + +#ifdef EXT_HASH_MAP + using namespace __gnu_cxx; +#endif + +/* GLOBAL FUNCTION: parser + */ +extern int yyparse(); +//extern int smtlibparse(); + +/* GLOBAL VARS: Some global vars for the Main function. + * + */ +const char * prog = "stp"; +int linenum = 1; +const char * usage = "Usage: %s [-option] [infile]\n"; +std::string helpstring = "\n\n"; + +// Amount of memory to ask for at beginning of main. +static const intptr_t INITIAL_MEMORY_PREALLOCATION_SIZE = 4000000; + +// Used only in smtlib lexer/parser +BEEV::ASTNode SingleBitOne; +BEEV::ASTNode SingleBitZero; + +/****************************************************************************** + * MAIN FUNCTION: + * + * step 0. Parse the input into an ASTVec. + * step 1. Do BV Rewrites + * step 2. Bitblasts the ASTNode. + * step 3. Convert to CNF + * step 4. Convert to SAT + * step 5. Call SAT to determine if input is SAT or UNSAT + ******************************************************************************/ +int main(int argc, char ** argv) { + char * infile; + extern FILE *yyin; + + // Grab some memory from the OS upfront to reduce system time when individual + // hash tables are being allocated + + if (sbrk(INITIAL_MEMORY_PREALLOCATION_SIZE) == ((void *) -1)) { + // FIXME: figure out how to get and print the real error message. + BEEV::FatalError("Initial allocation of memory failed."); + } + + //populate the help string + helpstring += "-r : switch refinement off (optimizations are ON by default)\n"; + helpstring += "-w : switch wordlevel solver off (optimizations are ON by default)\n"; + helpstring += "-a : switch optimizations off (optimizations are ON by default)\n"; + helpstring += "-s : print function statistics\n"; + helpstring += "-v : print nodes \n"; + helpstring += "-c : construct counterexample\n"; + helpstring += "-d : check counterexample\n"; + helpstring += "-p : print counterexample\n"; + helpstring += "-x : flatten nested XORs\n"; + helpstring += "-h : help\n"; + + for(int i=1; i < argc;i++) { + if(argv[i][0] == '-') + switch(argv[i][1]) { + case 'a' : + BEEV::optimize = false; + BEEV::wordlevel_solve = false; + break; + case 'b': + BEEV::print_STPinput_back = true; + break; + case 'c': + BEEV::construct_counterexample = true; + break; + case 'd': + BEEV::construct_counterexample = true; + BEEV::check_counterexample = true; + break; + case 'e': + BEEV::variable_activity_optimize = true; + break; + case 'f': + BEEV::smtlib_parser_enable = true; + break; + case 'h': + fprintf(stderr,usage,prog); + cout << helpstring; + //BEEV::FatalError(""); + return -1; + break; + case 'l' : + BEEV::linear_search = true; + break; + case 'n': + BEEV::print_output = true; + break; + case 'p': + BEEV::print_counterexample = true; + break; + case 'q': + BEEV::print_arrayval_declaredorder = true; + break; + case 'r': + BEEV::arrayread_refinement = false; + break; + case 's' : + BEEV::stats = true; + break; + case 'u': + BEEV::arraywrite_refinement = false; + break; + case 'v' : + BEEV::print_nodes = true; + break; + case 'w': + BEEV::wordlevel_solve = false; + break; + case 'x': + BEEV::xor_flatten = true; + break; + case 'z': + BEEV::print_sat_varorder = true; + break; + default: + fprintf(stderr,usage,prog); + cout << helpstring; + //BEEV::FatalError(""); + return -1; + break; + } + else { + infile = argv[i]; + yyin = fopen(infile,"r"); + if(yyin == NULL) { + fprintf(stderr,"%s: Error: cannot open %s\n",prog,infile); + BEEV::FatalError(""); + } + } + } + +#ifdef NATIVE_C_ARITH +#else + CONSTANTBV::ErrCode c = CONSTANTBV::BitVector_Boot(); + if(0 != c) { + cout << CONSTANTBV::BitVector_Error(c) << endl; + return 0; + } +#endif + + //want to print the output always from the commandline. + BEEV::print_output = true; + BEEV::globalBeevMgr_for_parser = new BEEV::BeevMgr(); + + SingleBitOne = BEEV::globalBeevMgr_for_parser->CreateOneConst(1); + SingleBitZero = BEEV::globalBeevMgr_for_parser->CreateZeroConst(1); + //BEEV::smtlib_parser_enable = true; + yyparse(); +}//end of Main diff --git a/stp/parser/smtlib.lex b/stp/parser/smtlib.lex new file mode 100644 index 00000000..a03ae94e --- /dev/null +++ b/stp/parser/smtlib.lex @@ -0,0 +1,232 @@ +%{ + /******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: July, 2006 + * + * This file is modified version of the CVCL's smtlib.lex file. Please + * see CVCL license below + ********************************************************************/ + + /******************************************************************** + * \file smtlib.lex + * + * Author: Sergey Berezin, Clark Barrett + * + * Created: Apr 30 2005 + * + * <hr> + * Copyright (C) 2004 by the Board of Trustees of Leland Stanford + * Junior University and by New York University. + * + * License to use, copy, modify, sell and/or distribute this software + * and its documentation for any purpose is hereby granted without + * royalty, subject to the terms and conditions defined in the \ref + * LICENSE file provided with this distribution. In particular: + * + * - The above copyright notice and this permission notice must appear + * in all copies of the software and related documentation. + * + * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES, + * EXPRESSED OR IMPLIED. USE IT AT YOUR OWN RISK. + * + * <hr> + ********************************************************************/ + // -*- c++ -*- +#include <iostream> +#include "../AST/AST.h" +#include "parsePL_defs.h" + + extern char *yytext; + extern int yyerror (char *msg); + + // File-static (local to this file) variables and functions + static std::string _string_lit; + + static char escapeChar(char c) { + switch(c) { + case 'n': return '\n'; + case 't': return '\t'; + default: return c; + } + } + + extern BEEV::ASTNode SingleBitOne; + extern BEEV::ASTNode SingleBitZero; + +/* Changed for smtlib speedup */ +/* bv{DIGIT}+ { yylval.node = new BEEV::ASTNode(BEEV::_bm->CreateBVConst(yytext+2, 10)); return BVCONST_TOK;} */ + +%} + +%option noyywrap +%option nounput +%option noreject +%option noyymore +%option yylineno + +%x COMMENT +%x STRING_LITERAL +%x USER_VALUE + +LETTER ([a-zA-Z]) +DIGIT ([0-9]) +OPCHAR (['\.\_]) +ANYTHING ({LETTER}|{DIGIT}|{OPCHAR}) + +%% +[ \n\t\r\f] { /* sk'ip whitespace */ } +{DIGIT}+ { yylval.uintval = strtoul(yytext, NULL, 10); return NUMERAL_TOK; } + + +bv{DIGIT}+ { yylval.ullval = strtoull(yytext+2, NULL, 10); return BVCONST_TOK; } + +bit{DIGIT}+ { + char c = yytext[3]; + if (c == '1') { + yylval.node = new BEEV::ASTNode(SingleBitOne); + } + else { + yylval.node = new BEEV::ASTNode(SingleBitZero); + } + return BITCONST_TOK; + }; + + +";" { BEGIN COMMENT; } +<COMMENT>"\n" { BEGIN INITIAL; /* return to normal mode */} +<COMMENT>. { /* stay in comment mode */ } + +<INITIAL>"\"" { BEGIN STRING_LITERAL; + _string_lit.erase(_string_lit.begin(), + _string_lit.end()); } +<STRING_LITERAL>"\\". { /* escape characters (like \n or \") */ + _string_lit.insert(_string_lit.end(), + escapeChar(yytext[1])); } +<STRING_LITERAL>"\"" { BEGIN INITIAL; /* return to normal mode */ + yylval.str = new std::string(_string_lit); + return STRING_TOK; } +<STRING_LITERAL>. { _string_lit.insert(_string_lit.end(),*yytext); } + + +<INITIAL>"{" { BEGIN USER_VALUE; + _string_lit.erase(_string_lit.begin(), + _string_lit.end()); } +<USER_VALUE>"\\"[{}] { /* escape characters */ + _string_lit.insert(_string_lit.end(),yytext[1]); } + +<USER_VALUE>"}" { BEGIN INITIAL; /* return to normal mode */ + yylval.str = new std::string(_string_lit); + return USER_VAL_TOK; } +<USER_VALUE>"\n" { _string_lit.insert(_string_lit.end(),'\n');} +<USER_VALUE>. { _string_lit.insert(_string_lit.end(),*yytext); } + +"BitVec" { return BITVEC_TOK;} +"Array" { return ARRAY_TOK;} +"true" { return TRUE_TOK; } +"false" { return FALSE_TOK; } +"not" { return NOT_TOK; } +"implies" { return IMPLIES_TOK; } +"ite" { return ITE_TOK;} +"if_then_else" { return IF_THEN_ELSE_TOK; } +"and" { return AND_TOK; } +"or" { return OR_TOK; } +"xor" { return XOR_TOK; } +"iff" { return IFF_TOK; } +"let" { return LET_TOK; } +"flet" { return FLET_TOK; } +"notes" { return NOTES_TOK; } +"cvc_command" { return CVC_COMMAND_TOK; } +"sorts" { return SORTS_TOK; } +"funs" { return FUNS_TOK; } +"preds" { return PREDS_TOK; } +"extensions" { return EXTENSIONS_TOK; } +"definition" { return DEFINITION_TOK; } +"axioms" { return AXIOMS_TOK; } +"logic" { return LOGIC_TOK; } +"sat" { return SAT_TOK; } +"unsat" { return UNSAT_TOK; } +"unknown" { return UNKNOWN_TOK; } +"assumption" { return ASSUMPTION_TOK; } +"formula" { return FORMULA_TOK; } +"status" { return STATUS_TOK; } +"difficulty" { return DIFFICULTY_TOK; } +"benchmark" { return BENCHMARK_TOK; } +"source" { return SOURCE_TOK;} +"category" { return CATEGORY_TOK;} +"extrasorts" { return EXTRASORTS_TOK; } +"extrafuns" { return EXTRAFUNS_TOK; } +"extrapreds" { return EXTRAPREDS_TOK; } +"language" { return LANGUAGE_TOK; } +"distinct" { return DISTINCT_TOK; } +"select" { return SELECT_TOK; } +"store" { return STORE_TOK; } +":" { return COLON_TOK; } +"\[" { return LBRACKET_TOK; } +"\]" { return RBRACKET_TOK; } +"(" { return LPAREN_TOK; } +")" { return RPAREN_TOK; } +"$" { return DOLLAR_TOK; } +"?" { return QUESTION_TOK; } +"=" {return EQ_TOK;} + +"nand" { return NAND_TOK;} +"nor" { return NOR_TOK;} +"/=" { return NEQ_TOK; } + ":=" { return ASSIGN_TOK;} +"shift_left0" { return BVLEFTSHIFT_TOK;} +"bvshl" { return BVLEFTSHIFT_1_TOK;} +"shift_right0" { return BVRIGHTSHIFT_TOK;} +"bvlshr" { return BVRIGHTSHIFT_1_TOK;} +"bvadd" { return BVPLUS_TOK;} +"bvsub" { return BVSUB_TOK;} +"bvnot" { return BVNOT_TOK;} +"bvmul" { return BVMULT_TOK;} +"bvdiv" { return BVDIV_TOK;} +"bvmod" { return BVMOD_TOK;} +"bvneg" { return BVNEG_TOK;} +"bvand" { return BVAND_TOK;} +"bvor" { return BVOR_TOK;} +"bvxor" { return BVXOR_TOK;} +"bvnand" { return BVNAND_TOK;} +"bvnor" { return BVNOR_TOK;} +"bvxnor" { return BVXNOR_TOK;} +"concat" { return BVCONCAT_TOK;} +"extract" { return BVEXTRACT_TOK;} +"bvlt" { return BVLT_TOK;} +"bvgt" { return BVGT_TOK;} +"bvleq" { return BVLE_TOK;} +"bvgeq" { return BVGE_TOK;} +"bvult" { return BVLT_TOK;} +"bvugt" { return BVGT_TOK;} +"bvuleq" { return BVLE_TOK;} +"bvugeq" { return BVGE_TOK;} +"bvule" { return BVLE_TOK;} +"bvuge" { return BVGE_TOK;} + +"bvslt" { return BVSLT_TOK;} +"bvsgt" { return BVSGT_TOK;} +"bvsleq" { return BVSLE_TOK;} +"bvsgeq" { return BVSGE_TOK;} +"bvsle" { return BVSLE_TOK;} +"bvsge" { return BVSGE_TOK;} + +"sign_extend" { return BVSX_TOK;} +"boolextract" { return BOOLEXTRACT_TOK;} +"boolbv" { return BOOL_TO_BV_TOK;} + +(({LETTER})|(_)({ANYTHING}))({ANYTHING})* { + BEEV::ASTNode nptr = BEEV::globalBeevMgr_for_parser->CreateSymbol(yytext); + + // Check valuesize to see if it's a prop var. I don't like doing + // type determination in the lexer, but it's easier than rewriting + // the whole grammar to eliminate the term/formula distinction. + yylval.node = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->ResolveID(nptr)); + //yylval.node = new BEEV::ASTNode(nptr); + if ((yylval.node)->GetType() == BEEV::BOOLEAN_TYPE) + return FORMID_TOK; + else + return TERMID_TOK; +} +. { yyerror("Illegal input character."); } +%% diff --git a/stp/parser/smtlib.y b/stp/parser/smtlib.y new file mode 100644 index 00000000..0aa22dee --- /dev/null +++ b/stp/parser/smtlib.y @@ -0,0 +1,1036 @@ +%{ + /******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: July, 2006 + * + * This file is modified version of the CVCL's smtlib.y file. Please + * see CVCL license below + ********************************************************************/ + + /******************************************************************** + * + * \file smtlib.y + * + * Author: Sergey Berezin, Clark Barrett + * + * Created: Apr 30 2005 + * + * <hr> + * Copyright (C) 2004 by the Board of Trustees of Leland Stanford + * Junior University and by New York University. + * + * License to use, copy, modify, sell and/or distribute this software + * and its documentation for any purpose is hereby granted without + * royalty, subject to the terms and conditions defined in the \ref + * LICENSE file provided with this distribution. In particular: + * + * - The above copyright notice and this permission notice must appear + * in all copies of the software and related documentation. + * + * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES, + * EXPRESSED OR IMPLIED. USE IT AT YOUR OWN RISK. + * + * <hr> + ********************************************************************/ + // -*- c++ -*- + +#include "../AST/AST.h" + using namespace std; + + // Suppress the bogus warning suppression in bison (it generates + // compile error) +#undef __GNUC_MINOR__ + + extern char* yytext; + extern int yylineno; + + //int yylineno; + + extern int yylex(void); + + int yyerror(char *s) { + //yylineno = 0; + cout << "syntax error: line " << yylineno << "\n" << s << endl; + cout << " token: " << yytext << endl; + BEEV::FatalError(""); + return 1; + } + + BEEV::ASTNode query; +#define YYLTYPE_IS_TRIVIAL 1 +#define YYMAXDEPTH 104857600 +#define YYERROR_VERBOSE 1 +#define YY_EXIT_FAILURE -1 +%} + +%union { + // FIXME: Why is this not an UNSIGNED int? + int uintval; /* for numerals in types. */ + + // for BV32 BVCONST + unsigned long long ullval; + + struct { + //stores the indexwidth and valuewidth + //indexwidth is 0 iff type is bitvector. positive iff type is + //array, and stores the width of the indexing bitvector + unsigned int indexwidth; + //width of the bitvector type + unsigned int valuewidth; + } indexvaluewidth; + + //ASTNode,ASTVec + BEEV::ASTNode *node; + BEEV::ASTVec *vec; + std::string *str; +}; + +%start cmd + +%type <indexvaluewidth> sort_symb sort_symbs +%type <node> status +%type <vec> bench_attributes an_formulas + +%type <node> benchmark bench_name bench_attribute +%type <node> an_term an_nonbvconst_term an_formula + +%type <node> var fvar logic_name +%type <str> user_value + +%token <uintval> NUMERAL_TOK +%token <ullval> BVCONST_TOK +%token <node> BITCONST_TOK +%token <node> FORMID_TOK TERMID_TOK +%token <str> STRING_TOK +%token <str> USER_VAL_TOK +%token SOURCE_TOK +%token CATEGORY_TOK +%token DIFFICULTY_TOK +%token BITVEC_TOK +%token ARRAY_TOK +%token SELECT_TOK +%token STORE_TOK +%token TRUE_TOK +%token FALSE_TOK +%token NOT_TOK +%token IMPLIES_TOK +%token ITE_TOK +%token IF_THEN_ELSE_TOK +%token AND_TOK +%token OR_TOK +%token XOR_TOK +%token IFF_TOK +%token EXISTS_TOK +%token FORALL_TOK +%token LET_TOK +%token FLET_TOK +%token NOTES_TOK +%token CVC_COMMAND_TOK +%token SORTS_TOK +%token FUNS_TOK +%token PREDS_TOK +%token EXTENSIONS_TOK +%token DEFINITION_TOK +%token AXIOMS_TOK +%token LOGIC_TOK +%token COLON_TOK +%token LBRACKET_TOK +%token RBRACKET_TOK +%token LPAREN_TOK +%token RPAREN_TOK +%token SAT_TOK +%token UNSAT_TOK +%token UNKNOWN_TOK +%token ASSUMPTION_TOK +%token FORMULA_TOK +%token STATUS_TOK +%token BENCHMARK_TOK +%token EXTRASORTS_TOK +%token EXTRAFUNS_TOK +%token EXTRAPREDS_TOK +%token LANGUAGE_TOK +%token DOLLAR_TOK +%token QUESTION_TOK +%token DISTINCT_TOK +%token SEMICOLON_TOK +%token EOF_TOK +%token EQ_TOK +/*BV SPECIFIC TOKENS*/ +%token NAND_TOK +%token NOR_TOK +%token NEQ_TOK +%token ASSIGN_TOK +%token BV_TOK +%token BOOLEAN_TOK +%token BVLEFTSHIFT_TOK +%token BVLEFTSHIFT_1_TOK +%token BVRIGHTSHIFT_TOK +%token BVRIGHTSHIFT_1_TOK +%token BVPLUS_TOK +%token BVSUB_TOK +%token BVNOT_TOK //bvneg in CVCL +%token BVMULT_TOK +%token BVDIV_TOK +%token BVMOD_TOK +%token BVNEG_TOK //bvuminus in CVCL +%token BVAND_TOK +%token BVOR_TOK +%token BVXOR_TOK +%token BVNAND_TOK +%token BVNOR_TOK +%token BVXNOR_TOK +%token BVCONCAT_TOK +%token BVLT_TOK +%token BVGT_TOK +%token BVLE_TOK +%token BVGE_TOK +%token BVSLT_TOK +%token BVSGT_TOK +%token BVSLE_TOK +%token BVSGE_TOK +%token BVSX_TOK +%token BOOLEXTRACT_TOK +%token BOOL_TO_BV_TOK +%token BVEXTRACT_TOK + +%left LBRACKET_TOK RBRACKET_TOK + +%% + +cmd: + benchmark + { + if($1 != NULL) { + BEEV::globalBeevMgr_for_parser->TopLevelSAT(*$1,query); + delete $1; + } + YYACCEPT; + } +; + +benchmark: + LPAREN_TOK BENCHMARK_TOK bench_name bench_attributes RPAREN_TOK + { + if($4 != NULL){ + if($4->size() > 1) + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::AND,*$4)); + else + $$ = new BEEV::ASTNode((*$4)[0]); + delete $4; + } + else { + $$ = NULL; + } + } +/* | EOF_TOK */ +/* { */ +/* } */ +; + +bench_name: + FORMID_TOK + { + } +; + +bench_attributes: + bench_attribute + { + $$ = new BEEV::ASTVec; + if ($1 != NULL) { + $$->push_back(*$1); + BEEV::globalBeevMgr_for_parser->AddAssert(*$1); + delete $1; + } + } + | bench_attributes bench_attribute + { + if ($1 != NULL && $2 != NULL) { + $1->push_back(*$2); + BEEV::globalBeevMgr_for_parser->AddAssert(*$2); + $$ = $1; + delete $2; + } + } +; + +bench_attribute: + COLON_TOK ASSUMPTION_TOK an_formula + { + //assumptions are like asserts + $$ = $3; + } + | COLON_TOK FORMULA_TOK an_formula + { + //the query + query = BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::NOT,*$3); + BEEV::globalBeevMgr_for_parser->AddQuery(query); + //dummy true + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::TRUE)); + + + } + | COLON_TOK STATUS_TOK status + { + $$ = NULL; + } + | COLON_TOK LOGIC_TOK logic_name + { + if (!(0 == strcmp($3->GetName(),"QF_UFBV") || + 0 == strcmp($3->GetName(),"QF_AUFBV"))) { + yyerror("Wrong input logic:"); + } + $$ = NULL; + } + | COLON_TOK EXTRAFUNS_TOK LPAREN_TOK var_decls RPAREN_TOK + { + $$ = NULL; + } + | COLON_TOK EXTRAPREDS_TOK LPAREN_TOK var_decls RPAREN_TOK + { + $$ = NULL; + } + | annotation + { + $$ = NULL; + } +; + +logic_name: + FORMID_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK + { + $$ = $1; + } + | FORMID_TOK + { + $$ = $1; + } +; + +status: + SAT_TOK { $$ = NULL; } + | UNSAT_TOK { $$ = NULL; } + | UNKNOWN_TOK { $$ = NULL; } +; + + +/* annotations: */ +/* annotation */ +/* { */ +/* } */ +/* | annotations annotation */ +/* { */ +/* } */ +/* ; */ + +annotation: + attribute + { + } + | attribute user_value + { + } +; + +user_value: + USER_VAL_TOK + { + //cerr << "Printing user_value: " << *$1 << endl; + } +; + +attribute: + COLON_TOK SOURCE_TOK + { + } + | COLON_TOK CATEGORY_TOK + { + } + | COLON_TOK DIFFICULTY_TOK +; + +sort_symbs: + sort_symb + { + //a single sort symbol here means either a BitVec or a Boolean + $$.indexwidth = $1.indexwidth; + $$.valuewidth = $1.valuewidth; + } + | sort_symb sort_symb + { + //two sort symbols mean f: type --> type + $$.indexwidth = $1.valuewidth; + $$.valuewidth = $2.valuewidth; + } +; + +var_decls: + var_decl + { + } +// | LPAREN_TOK var_decl RPAREN_TOK + | + var_decls var_decl + { + } +; + +var_decl: + LPAREN_TOK FORMID_TOK sort_symbs RPAREN_TOK + { + BEEV::_parser_symbol_table.insert(*$2); + //Sort_symbs has the indexwidth/valuewidth. Set those fields in + //var + $2->SetIndexWidth($3.indexwidth); + $2->SetValueWidth($3.valuewidth); + } + | LPAREN_TOK FORMID_TOK RPAREN_TOK + { + BEEV::_parser_symbol_table.insert(*$2); + //Sort_symbs has the indexwidth/valuewidth. Set those fields in + //var + $2->SetIndexWidth(0); + $2->SetValueWidth(0); + } +; + +an_formulas: + an_formula + { + $$ = new BEEV::ASTVec; + if ($1 != NULL) { + $$->push_back(*$1); + delete $1; + } + } + | + an_formulas an_formula + { + if ($1 != NULL && $2 != NULL) { + $1->push_back(*$2); + $$ = $1; + delete $2; + } + } +; + +an_formula: + TRUE_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::TRUE)); + $$->SetIndexWidth(0); + $$->SetValueWidth(0); + } + | FALSE_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::FALSE)); + $$->SetIndexWidth(0); + $$->SetValueWidth(0); + } + | fvar + { + $$ = $1; + } + | LPAREN_TOK EQ_TOK an_term an_term RPAREN_TOK + //| LPAREN_TOK EQ_TOK an_term an_term annotations RPAREN_TOK + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateSimplifiedEQ(*$3, *$4)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $4; + } + | LPAREN_TOK BVSLT_TOK an_term an_term RPAREN_TOK + //| LPAREN_TOK BVSLT_TOK an_term an_term annotations RPAREN_TOK + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVSLT, *$3, *$4)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $4; + } + | LPAREN_TOK BVSLE_TOK an_term an_term RPAREN_TOK + //| LPAREN_TOK BVSLE_TOK an_term an_term annotations RPAREN_TOK + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVSLE, *$3, *$4)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $4; + } + | LPAREN_TOK BVSGT_TOK an_term an_term RPAREN_TOK + //| LPAREN_TOK BVSGT_TOK an_term an_term annotations RPAREN_TOK + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVSGT, *$3, *$4)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $4; + } + | LPAREN_TOK BVSGE_TOK an_term an_term RPAREN_TOK + //| LPAREN_TOK BVSGE_TOK an_term an_term annotations RPAREN_TOK + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVSGE, *$3, *$4)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $4; + } + | LPAREN_TOK BVLT_TOK an_term an_term RPAREN_TOK + //| LPAREN_TOK BVLT_TOK an_term an_term annotations RPAREN_TOK + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVLT, *$3, *$4)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $4; + } + | LPAREN_TOK BVLE_TOK an_term an_term RPAREN_TOK + //| LPAREN_TOK BVLE_TOK an_term an_term annotations RPAREN_TOK + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVLE, *$3, *$4)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $4; + } + | LPAREN_TOK BVGT_TOK an_term an_term RPAREN_TOK + //| LPAREN_TOK BVGT_TOK an_term an_term annotations RPAREN_TOK + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVGT, *$3, *$4)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $4; + } + | LPAREN_TOK BVGE_TOK an_term an_term RPAREN_TOK + //| LPAREN_TOK BVGE_TOK an_term an_term annotations RPAREN_TOK + { + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::BVGE, *$3, *$4)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $3; + delete $4; + } + | LPAREN_TOK an_formula RPAREN_TOK + { + $$ = $2; + } + | LPAREN_TOK NOT_TOK an_formula RPAREN_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::NOT, *$3)); + delete $3; + } + | LPAREN_TOK IMPLIES_TOK an_formula an_formula RPAREN_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::IMPLIES, *$3, *$4)); + delete $3; + delete $4; + } + | LPAREN_TOK IF_THEN_ELSE_TOK an_formula an_formula an_formula RPAREN_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::ITE, *$3, *$4, *$5)); + delete $3; + delete $4; + delete $5; + } + | LPAREN_TOK AND_TOK an_formulas RPAREN_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::AND, *$3)); + delete $3; + } + | LPAREN_TOK OR_TOK an_formulas RPAREN_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::OR, *$3)); + delete $3; + } + | LPAREN_TOK XOR_TOK an_formula an_formula RPAREN_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::XOR, *$3, *$4)); + delete $3; + delete $4; + } + | LPAREN_TOK IFF_TOK an_formula an_formula RPAREN_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateNode(BEEV::IFF, *$3, *$4)); + delete $3; + delete $4; + } + | letexpr_mgmt an_formula RPAREN_TOK + //| letexpr_mgmt an_formula annotations RPAREN_TOK + { + $$ = $2; + //Cleanup the LetIDToExprMap + BEEV::globalBeevMgr_for_parser->CleanupLetIDMap(); + } +; + +letexpr_mgmt: + LPAREN_TOK LET_TOK LPAREN_TOK QUESTION_TOK FORMID_TOK an_term RPAREN_TOK + { + //Expr must typecheck + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$6); + + //set the valuewidth of the identifier + $5->SetValueWidth($6->GetValueWidth()); + $5->SetIndexWidth($6->GetIndexWidth()); + + //populate the hashtable from LET-var --> + //LET-exprs and then process them: + // + //1. ensure that LET variables do not clash + //1. with declared variables. + // + //2. Ensure that LET variables are not + //2. defined more than once + BEEV::globalBeevMgr_for_parser->LetExprMgr(*$5,*$6); + delete $5; + delete $6; + } + | LPAREN_TOK FLET_TOK LPAREN_TOK DOLLAR_TOK FORMID_TOK an_formula RPAREN_TOK + { + //Expr must typecheck + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$6); + + //set the valuewidth of the identifier + $5->SetValueWidth($6->GetValueWidth()); + $5->SetIndexWidth($6->GetIndexWidth()); + + //Do LET-expr management + BEEV::globalBeevMgr_for_parser->LetExprMgr(*$5,*$6); + delete $5; + delete $6; + } + +/* an_terms: */ +/* an_term */ +/* { */ +/* } */ +/* | an_terms an_term */ +/* { */ +/* } */ +/* ; */ + +an_term: + BVCONST_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(64, $1)); + } + | BVCONST_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst($3, $1)); + } + | an_nonbvconst_term + ; + +an_nonbvconst_term: + BITCONST_TOK { $$ = $1; } + | var + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->ResolveID(*$1)); + delete $1; + } + | LPAREN_TOK an_term RPAREN_TOK + //| LPAREN_TOK an_term annotations RPAREN_TOK + { + $$ = $2; + //$$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->SimplifyTerm(*$2)); + //delete $2; + } + | LPAREN_TOK TERMID_TOK an_term RPAREN_TOK + { + //ARRAY READ + // valuewidth is same as array, indexwidth is 0. + BEEV::ASTNode in = *$2; + BEEV::ASTNode m = *$3; + unsigned int width = in.GetValueWidth(); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::READ, width, in, m)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + delete $3; + } + | SELECT_TOK an_term an_term + { + //ARRAY READ + // valuewidth is same as array, indexwidth is 0. + BEEV::ASTNode array = *$2; + BEEV::ASTNode index = *$3; + unsigned int width = array.GetValueWidth(); + BEEV::ASTNode * n = + new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::READ, width, array, index)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + delete $3; + } + | STORE_TOK an_term an_term an_term + { + //ARRAY WRITE + unsigned int width = $4->GetValueWidth(); + BEEV::ASTNode array = *$2; + BEEV::ASTNode index = *$3; + BEEV::ASTNode writeval = *$4; + BEEV::ASTNode write_term = BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::WRITE,width,array,index,writeval); + write_term.SetIndexWidth($2->GetIndexWidth()); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(write_term); + BEEV::ASTNode * n = new BEEV::ASTNode(write_term); + $$ = n; + delete $2; + delete $3; + delete $4; + } +/* | BVEXTRACT_TOK LBRACKET_TOK NUMERAL_TOK COLON_TOK NUMERAL_TOK RBRACKET_TOK BVCONST_TOK */ +/* { */ +/* // This special case is when we have an extract on top of a constant bv, which happens */ +/* // almost all the time in the smt syntax. */ + +/* // $3 is high, $5 is low. They are ints (why not unsigned? See uintval) */ +/* int hi = $3; */ +/* int low = $5; */ +/* int width = hi - low + 1; */ + +/* if (width < 0) */ +/* yyerror("Negative width in extract"); */ + +/* unsigned long long int val = $7; */ + +/* // cut and past from BV32 const evaluator */ + +/* unsigned long long int mask1 = 0xffffffffffffffffLL; */ + +/* mask1 >>= 64-(hi+1); */ + +/* //extract val[hi:0] */ +/* val &= mask1; */ +/* //extract val[hi:low] */ +/* val >>= low; */ + +/* // val is the desired BV32. */ +/* BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(width, val)); */ +/* $$ = n; */ +/* } */ + | BVEXTRACT_TOK LBRACKET_TOK NUMERAL_TOK COLON_TOK NUMERAL_TOK RBRACKET_TOK an_term + { + int width = $3 - $5 + 1; + if (width < 0) + yyerror("Negative width in extract"); + + if((unsigned)$3 >= $7->GetValueWidth() || (unsigned)$5 < 0) + yyerror("Parsing: Wrong width in BVEXTRACT\n"); + + BEEV::ASTNode hi = BEEV::globalBeevMgr_for_parser->CreateBVConst(32, $3); + BEEV::ASTNode low = BEEV::globalBeevMgr_for_parser->CreateBVConst(32, $5); + BEEV::ASTNode output = BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVEXTRACT, width, *$7,hi,low); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->SimplifyTerm(output)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $7; + } + | ITE_TOK an_formula an_term an_term + { + unsigned int width = $3->GetValueWidth(); + if (width != $4->GetValueWidth()) { + cerr << *$3; + cerr << *$4; + yyerror("Width mismatch in IF-THEN-ELSE"); + } + if($3->GetIndexWidth() != $4->GetIndexWidth()) + yyerror("Width mismatch in IF-THEN-ELSE"); + + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$2); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$3); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$4); + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateSimplifiedTermITE(*$2, *$3, *$4)); + //$$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::ITE,width,*$2, *$3, *$4)); + $$->SetIndexWidth($4->GetIndexWidth()); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$$); + delete $2; + delete $3; + delete $4; + } + | BVCONCAT_TOK an_term an_term + { + unsigned int width = $2->GetValueWidth() + $3->GetValueWidth(); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVCONCAT, width, *$2, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + + delete $2; + delete $3; + } + | BVNOT_TOK an_term + { + //this is the BVNEG (term) in the CVCL language + unsigned int width = $2->GetValueWidth(); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVNEG, width, *$2)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + } + | BVNEG_TOK an_term + { + //this is the BVUMINUS term in CVCL langauge + unsigned width = $2->GetValueWidth(); + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVUMINUS,width,*$2)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + } + | BVAND_TOK an_term an_term + { + unsigned int width = $2->GetValueWidth(); + if (width != $3->GetValueWidth()) { + yyerror("Width mismatch in AND"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVAND, width, *$2, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + delete $3; + } + | BVOR_TOK an_term an_term + { + unsigned int width = $2->GetValueWidth(); + if (width != $3->GetValueWidth()) { + yyerror("Width mismatch in OR"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVOR, width, *$2, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + delete $3; + } + | BVXOR_TOK an_term an_term + { + unsigned int width = $2->GetValueWidth(); + if (width != $3->GetValueWidth()) { + yyerror("Width mismatch in XOR"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVXOR, width, *$2, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + delete $3; + } + | BVSUB_TOK an_term an_term + { + unsigned int width = $2->GetValueWidth(); + if (width != $3->GetValueWidth()) { + yyerror("Width mismatch in BVSUB"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVSUB, width, *$2, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + delete $3; + } + | BVPLUS_TOK an_term an_term + { + unsigned int width = $2->GetValueWidth(); + if (width != $3->GetValueWidth()) { + yyerror("Width mismatch in BVPLUS"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVPLUS, width, *$2, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + delete $3; + + } + | BVMULT_TOK an_term an_term + { + unsigned int width = $2->GetValueWidth(); + if (width != $3->GetValueWidth()) { + yyerror("Width mismatch in BVMULT"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVMULT, width, *$2, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + delete $3; + } + | BVNAND_TOK an_term an_term + { + unsigned int width = $2->GetValueWidth(); + if (width != $3->GetValueWidth()) { + yyerror("Width mismatch in BVNAND"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVNAND, width, *$2, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + delete $3; + } + | BVNOR_TOK an_term an_term + { + unsigned int width = $2->GetValueWidth(); + if (width != $3->GetValueWidth()) { + yyerror("Width mismatch in BVNOR"); + } + BEEV::ASTNode * n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVNOR, width, *$2, *$3)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $2; + delete $3; + } + | BVLEFTSHIFT_TOK an_term NUMERAL_TOK + { + unsigned int w = $2->GetValueWidth(); + if((unsigned)$3 < w) { + BEEV::ASTNode trailing_zeros = BEEV::globalBeevMgr_for_parser->CreateBVConst($3, 0); + BEEV::ASTNode hi = BEEV::globalBeevMgr_for_parser->CreateBVConst(32, w-$3-1); + BEEV::ASTNode low = BEEV::globalBeevMgr_for_parser->CreateBVConst(32,0); + BEEV::ASTNode m = BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVEXTRACT,w-$3,*$2,hi,low); + BEEV::ASTNode * n = + new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVCONCAT,w,m,trailing_zeros)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + } + else + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(w,0)); + delete $2; + } + | BVLEFTSHIFT_1_TOK an_term an_term + { + unsigned int w = $2->GetValueWidth(); + unsigned int shift_amt = GetUnsignedConst(*$3); + if((unsigned)shift_amt < w) { + BEEV::ASTNode trailing_zeros = BEEV::globalBeevMgr_for_parser->CreateBVConst(shift_amt, 0); + BEEV::ASTNode hi = BEEV::globalBeevMgr_for_parser->CreateBVConst(32, w-shift_amt-1); + BEEV::ASTNode low = BEEV::globalBeevMgr_for_parser->CreateBVConst(32,0); + BEEV::ASTNode m = BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVEXTRACT,w-shift_amt,*$2,hi,low); + BEEV::ASTNode * n = + new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVCONCAT,w,m,trailing_zeros)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + } + else { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(w,0)); + } + delete $2; + //delete $3; + } + | BVRIGHTSHIFT_TOK an_term NUMERAL_TOK + { + BEEV::ASTNode leading_zeros = BEEV::globalBeevMgr_for_parser->CreateBVConst($3, 0); + unsigned int w = $2->GetValueWidth(); + + //the amount by which you are rightshifting + //is less-than/equal-to the length of input + //bitvector + if((unsigned)$3 < w) { + BEEV::ASTNode hi = BEEV::globalBeevMgr_for_parser->CreateBVConst(32,w-1); + BEEV::ASTNode low = BEEV::globalBeevMgr_for_parser->CreateBVConst(32,$3); + BEEV::ASTNode extract = BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVEXTRACT,w-$3,*$2,hi,low); + BEEV::ASTNode * n = + new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVCONCAT, w,leading_zeros, extract)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + } + else { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(w,0)); + } + delete $2; + } + | BVRIGHTSHIFT_1_TOK an_term an_term + { + unsigned int shift_amt = GetUnsignedConst(*$3); + BEEV::ASTNode leading_zeros = BEEV::globalBeevMgr_for_parser->CreateBVConst(shift_amt, 0); + unsigned int w = $2->GetValueWidth(); + + //the amount by which you are rightshifting + //is less-than/equal-to the length of input + //bitvector + if((unsigned)shift_amt < w) { + BEEV::ASTNode hi = BEEV::globalBeevMgr_for_parser->CreateBVConst(32,w-1); + BEEV::ASTNode low = BEEV::globalBeevMgr_for_parser->CreateBVConst(32,shift_amt); + BEEV::ASTNode extract = BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVEXTRACT,w-shift_amt,*$2,hi,low); + BEEV::ASTNode * n = + new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVCONCAT, w,leading_zeros, extract)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + } + else { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateBVConst(w,0)); + } + delete $2; + } + | BVSX_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK an_term + { + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*$5); + unsigned w = $5->GetValueWidth() + $3; + BEEV::ASTNode width = BEEV::globalBeevMgr_for_parser->CreateBVConst(32,w); + BEEV::ASTNode *n = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->CreateTerm(BEEV::BVSX,w,*$5,width)); + BEEV::globalBeevMgr_for_parser->BVTypeCheck(*n); + $$ = n; + delete $5; + } +; + +sort_symb: + BITVEC_TOK LBRACKET_TOK NUMERAL_TOK RBRACKET_TOK + { + // Just return BV width. If sort is BOOL, width is 0. + // Otherwise, BITVEC[w] returns w. + // + //((indexwidth is 0) && (valuewidth>0)) iff type is BV + $$.indexwidth = 0; + unsigned int length = $3; + if(length > 0) { + $$.valuewidth = length; + } + else { + BEEV::FatalError("Fatal Error: parsing: BITVECTORS must be of positive length: \n"); + } + } + | ARRAY_TOK LBRACKET_TOK NUMERAL_TOK COLON_TOK NUMERAL_TOK RBRACKET_TOK + { + unsigned int index_len = $3; + unsigned int value_len = $5; + if(index_len > 0) { + $$.indexwidth = $3; + } + else { + BEEV::FatalError("Fatal Error: parsing: BITVECTORS must be of positive length: \n"); + } + + if(value_len > 0) { + $$.valuewidth = $5; + } + else { + BEEV::FatalError("Fatal Error: parsing: BITVECTORS must be of positive length: \n"); + } + } +; + +var: + FORMID_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->ResolveID(*$1)); + delete $1; + } + | TERMID_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->ResolveID(*$1)); + delete $1; + } + | QUESTION_TOK TERMID_TOK + { + $$ = $2; + } +; + +fvar: + DOLLAR_TOK FORMID_TOK + { + $$ = $2; + } + | FORMID_TOK + { + $$ = new BEEV::ASTNode(BEEV::globalBeevMgr_for_parser->ResolveID(*$1)); + delete $1; + } +; +%% diff --git a/stp/sat/Global.h b/stp/sat/Global.h new file mode 100644 index 00000000..a428975c --- /dev/null +++ b/stp/sat/Global.h @@ -0,0 +1,255 @@ +/****************************************************************************************[Global.h] +MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Global_h +#define Global_h + +#include <cassert> +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <new> + +// PKT: needs to be outside namespace MINISAT or mac os x compilation breaks +#ifdef _MSC_VER +#else +#include <unistd.h> +#endif + +namespace MINISAT { +//================================================================================================= +// Basic Types & Minor Things: + +// DWD: This is needed on darwin. +typedef unsigned int uint; + +#ifdef _MSC_VER + +typedef INT64 int64; +typedef UINT64 uint64; +typedef INT_PTR intp; +typedef UINT_PTR uintp; +#define I64_fmt "I64d" +#else + +typedef long long int64; +typedef unsigned long long uint64; +typedef __PTRDIFF_TYPE__ intp; +typedef unsigned __PTRDIFF_TYPE__ uintp; +#define I64_fmt "lld" +#endif + +template<class T> static inline T min(T x, T y) { return (x < y) ? x : y; } +template<class T> static inline T max(T x, T y) { return (x > y) ? x : y; } + +template <bool> struct STATIC_ASSERTION_FAILURE; +template <> struct STATIC_ASSERTION_FAILURE<true>{}; +#define TEMPLATE_FAIL STATIC_ASSERTION_FAILURE<false>() + + +//================================================================================================= +// 'malloc()'-style memory allocation -- never returns NULL; aborts instead: + + +template<class T> static inline T* xmalloc(size_t size) { + T* tmp = (T*)malloc(size * sizeof(T)); + assert(size == 0 || tmp != NULL); + return tmp; } + +template<class T> static inline T* xrealloc(T* ptr, size_t size) { + T* tmp = (T*)realloc((void*)ptr, size * sizeof(T)); + assert(size == 0 || tmp != NULL); + return tmp; } + +template<class T> static inline void xfree(T *ptr) { + if (ptr != NULL) free((void*)ptr); } + + +//================================================================================================= +// Random numbers: + + +// Returns a random float 0 <= x < 1. Seed must never be 0. +static inline double drand(double& seed) { + seed *= 1389796; + int q = (int)(seed / 2147483647); + seed -= (double)q * 2147483647; + return seed / 2147483647; } + +// Returns a random integer 0 <= x < size. Seed must never be 0. +static inline int irand(double& seed, int size) { + return (int)(drand(seed) * size); } + + +//================================================================================================= +// 'vec' -- automatically resizable arrays (via 'push()' method): + + +// NOTE! Don't use this vector on datatypes that cannot be re-located in memory (with realloc) + +template<class T> +class vec { + T* data; + int sz; + int cap; + + void init(int size, const T& pad); + void grow(int min_cap); + +public: + // Types: + typedef int Key; + typedef T Datum; + + // Constructors: + vec(void) : data(NULL) , sz(0) , cap(0) { } + vec(int size) : data(NULL) , sz(0) , cap(0) { growTo(size); } + vec(int size, const T& pad) : data(NULL) , sz(0) , cap(0) { growTo(size, pad); } + vec(T* array, int size) : data(array), sz(size), cap(size) { } // (takes ownership of array -- will be deallocated with 'xfree()') + ~vec(void) { clear(true); } + + // Ownership of underlying array: + T* release (void) { T* ret = data; data = NULL; sz = 0; cap = 0; return ret; } + operator T* (void) { return data; } // (unsafe but convenient) + operator const T* (void) const { return data; } + + // Size operations: + int size (void) const { return sz; } + void shrink (int nelems) { assert(nelems <= sz); for (int i = 0; i < nelems; i++) sz--, data[sz].~T(); } + void pop (void) { sz--, data[sz].~T(); } + void growTo (int size); + void growTo (int size, const T& pad); + void clear (bool dealloc = false); + void capacity (int size) { grow(size); } + + // Stack interface: + void push (void) { if (sz == cap) grow(sz+1); new (&data[sz]) T() ; sz++; } + void push (const T& elem) { if (sz == cap) grow(sz+1); new (&data[sz]) T(elem); sz++; } + const T& last (void) const { return data[sz-1]; } + T& last (void) { return data[sz-1]; } + + // Vector interface: + const T& operator [] (int index) const { return data[index]; } + T& operator [] (int index) { return data[index]; } + + // Don't allow copying (error prone): + vec<T>& operator = (vec<T>& other) { TEMPLATE_FAIL; } + vec (vec<T>& other) { TEMPLATE_FAIL; } + + // Duplicatation (preferred instead): + void copyTo(vec<T>& copy) const { copy.clear(); copy.growTo(sz); for (int i = 0; i < sz; i++) new (©[i]) T(data[i]); } + void moveTo(vec<T>& dest) { dest.clear(true); dest.data = data; dest.sz = sz; dest.cap = cap; data = NULL; sz = 0; cap = 0; } +}; + +template<class T> +void vec<T>::grow(int min_cap) { + if (min_cap <= cap) return; + if (cap == 0) cap = (min_cap >= 2) ? min_cap : 2; + else do cap = (cap*3+1) >> 1; while (cap < min_cap); + data = xrealloc(data, cap); } + +template<class T> +void vec<T>::growTo(int size, const T& pad) { + if (sz >= size) return; + grow(size); + for (int i = sz; i < size; i++) new (&data[i]) T(pad); + sz = size; } + +template<class T> +void vec<T>::growTo(int size) { + if (sz >= size) return; + grow(size); + for (int i = sz; i < size; i++) new (&data[i]) T(); + sz = size; } + +template<class T> +void vec<T>::clear(bool dealloc) { + if (data != NULL){ + for (int i = 0; i < sz; i++) data[i].~T(); + sz = 0; + if (dealloc) xfree(data), data = NULL, cap = 0; } } + + +//================================================================================================= +// Useful functions on vectors + + +template<class V, class T> +void remove(V& ts, const T& t) +{ + int j = 0; + for (; j < ts.size() && ts[j] != t; j++); + assert(j < ts.size()); + for (; j < ts.size()-1; j++) ts[j] = ts[j+1]; + ts.pop(); +} + + +template<class V, class T> +bool find(V& ts, const T& t) +{ + int j = 0; + for (; j < ts.size() && ts[j] != t; j++); + return j < ts.size(); +} + +//================================================================================================= +// Lifted booleans: + + +class lbool { + int value; + explicit lbool(int v) : value(v) { } + +public: + lbool() : value(0) { } + lbool(bool x) : value((int)x*2-1) { } + int toInt(void) const { return value; } + + bool operator == (const lbool& other) const { return value == other.value; } + bool operator != (const lbool& other) const { return value != other.value; } + lbool operator ~ (void) const { return lbool(-value); } + + friend int toInt (lbool l); + friend lbool toLbool(int v); +}; +inline int toInt (lbool l) { return l.toInt(); } +inline lbool toLbool(int v) { return lbool(v); } + +const lbool l_True = toLbool( 1); +const lbool l_False = toLbool(-1); +const lbool l_Undef = toLbool( 0); + + +//================================================================================================= +// Relation operators -- extend definitions from '==' and '<' + + +#ifndef __SGI_STL_INTERNAL_RELOPS // (be aware of SGI's STL implementation...) +#define __SGI_STL_INTERNAL_RELOPS +template <class T> static inline bool operator != (const T& x, const T& y) { return !(x == y); } +template <class T> static inline bool operator > (const T& x, const T& y) { return y < x; } +template <class T> static inline bool operator <= (const T& x, const T& y) { return !(y < x); } +template <class T> static inline bool operator >= (const T& x, const T& y) { return !(x < y); } +#endif + + +//================================================================================================= +}; +#endif diff --git a/stp/sat/Heap.h b/stp/sat/Heap.h new file mode 100644 index 00000000..acfa1c1e --- /dev/null +++ b/stp/sat/Heap.h @@ -0,0 +1,151 @@ +/******************************************************************************************[Heap.h] +MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Heap_h +#define Heap_h + +#include "../AST/ASTUtil.h" +namespace MINISAT { + +//================================================================================================= + + +static inline int left (int i) { return i+i; } +static inline int right (int i) { return i+i + 1; } +static inline int parent(int i) { return i >> 1; } + +template<class C> +class Heap { + public: + C comp; + vec<int> heap; // heap of ints + vec<int> indices; // int -> index in heap + + inline void percolateUp(int i) + { + int x = heap[i]; + while (parent(i) != 0 && comp(x,heap[parent(i)])){ + heap[i] = heap[parent(i)]; + indices[heap[i]] = i; + i = parent(i); + } + heap [i] = x; + indices[x] = i; + } + + inline void percolateDown(int i) + { + int x = heap[i]; + while (left(i) < heap.size()){ + int child = right(i) < heap.size() && comp(heap[right(i)],heap[left(i)]) ? right(i) : left(i); + if (!comp(heap[child],x)) break; + heap[i] = heap[child]; + indices[heap[i]] = i; + i = child; + } + heap [i] = x; + indices[x] = i; + } + + bool ok(int n) const { + return n >= 0 && n < (int)indices.size(); } + + public: + Heap(C c) : comp(c) { heap.push(-1); } + + void setBounds (int size) { assert(size >= 0); indices.growTo(size,0); } + void increase (int n) { assert(ok(n)); assert(inHeap(n)); percolateUp(indices[n]); } + bool inHeap (int n) const { assert(ok(n)); return indices[n] != 0; } + int size () const { return heap.size()-1; } + bool empty () const { return size() == 0; } + + + void insert(int n) { + assert(!inHeap(n)); + assert(ok(n)); + indices[n] = heap.size(); + heap.push(n); + percolateUp(indices[n]); + } + + + int getmin() { + //printing heap + if(BEEV::print_sat_varorder) { + // fprintf(stderr, "Vijay: heap before getmin: "); + // for (uint i = 1; i < (uint)heap.size(); i++) + // fprintf(stderr, "%d ", heap[i]); + // fprintf(stderr, "\n"); + } + + int r = heap[1]; + heap[1] = heap.last(); + indices[heap[1]] = 1; + indices[r] = 0; + heap.pop(); + if (heap.size() > 1) + percolateDown(1); + return r; + } + + // fool proof variant of insert/increase + void update (int n) { + //fprintf(stderr, "update heap: "); + //for (uint i = 1; i < (uint)heap.size(); i++) + // fprintf(stderr, "%d ", heap[i]); + //fprintf(stderr, "\n"); + setBounds(n+1); + if (!inHeap(n)) + insert(n); + else { + percolateUp(indices[n]); + percolateDown(indices[n]); + } + } + + + bool heapProperty() { + return heapProperty(1); } + + + bool heapProperty(int i) { + return i >= heap.size() + || ((parent(i) == 0 || !comp(heap[i],heap[parent(i)])) && heapProperty(left(i)) && heapProperty(right(i))); } + + template <class F> void filter(const F& filt) { + int i,j; + for (i = j = 1; i < heap.size(); i++) + if (filt(heap[i])){ + heap[j] = heap[i]; + indices[heap[i]] = j++; + }else + indices[heap[i]] = 0; + + heap.shrink(i - j); + for (int i = heap.size() / 2; i >= 1; i--) + percolateDown(i); + + assert(heapProperty()); + } + +}; + +//================================================================================================= +}; +#endif diff --git a/stp/sat/LICENSE b/stp/sat/LICENSE new file mode 100644 index 00000000..590930bc --- /dev/null +++ b/stp/sat/LICENSE @@ -0,0 +1,20 @@ +MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/stp/sat/Makefile b/stp/sat/Makefile new file mode 100644 index 00000000..8298e05a --- /dev/null +++ b/stp/sat/Makefile @@ -0,0 +1,16 @@ +include ../Makefile.common + +SRCS = Solver.C Simplifier.C +OBJS = $(SRCS:.C=.o) + +libsatsolver.a: $(OBJS) + $(AR) rc $@ $^ + $(RANLIB) $@ + +Solver.o: Solver.C Solver.h Sort.h SolverTypes.h VarOrder.h Global.h Heap.h +Simplifier.o: Simplifier.C Solver.h Sort.h SolverTypes.h VarOrder.h Global.h Heap.h + +clean: + rm -rf *.o *~ *.a depend.mak .#* +depend: + makedepend -- $(CFLAGS) -- $(SRCS) diff --git a/stp/sat/Simplifier.C b/stp/sat/Simplifier.C new file mode 100644 index 00000000..1c192e20 --- /dev/null +++ b/stp/sat/Simplifier.C @@ -0,0 +1,542 @@ +/************************************************************************************[Simplifier.C] +MiniSat -- Copyright (c) 2003-2006, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#include "Solver.h" + +namespace MINISAT { + +static const int grow = 0; + +//#define WEAKEN +//#define MATING +//#define ASSYMM + +bool Solver::assymmetricBranching(Clause& c) +{ + assert(decisionLevel() == 0); + + //fprintf(stderr, "assymmetric branching on clause: "); printClause(c); fprintf(stderr, "\n"); + if (satisfied(c)){ + //fprintf(stderr, "subsumed.\n"); + return true; } + + int old; + vec<Lit> copy; for (int i = 0; i < c.size(); i++) copy.push(c[i]); + + do { + assert(copy.size() == c.size()); + + old = copy.size(); + + //fprintf(stderr, "checking that clause is normalized\n"); + //for (int i = 0; i < copy.size(); i++) + // assert(value(copy[i]) == l_Undef); + + for (int i = 0; i < copy.size(); i++){ + trail_lim.push(trail.size()); + //fprintf(stderr, " -- trying to delete literal "); printLit(copy[i]); + for (int j = 0; j < copy.size(); j++) + if (j != i) + check(enqueue(~copy[j])); + + if (propagate() != NULL){ + //fprintf(stderr, " succeeded\n"); + cancelUntil(0); + Lit l = copy[i]; + assert(find(copy, l)); + remove(copy, l); + if (!strengthen(c, l)) + return false; + i--; + + if (c.size() == 1) + return propagate() == NULL; + else + assert(qhead == trail.size()); + } + else + //fprintf(stderr, " failed\n"); + + cancelUntil(0); + } + + //} while (false); + } while (copy.size() < old); + + return true; +} + +// Returns FALSE if clause is always satisfied ('out_clause' should not be used). +//bool Solver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause) +bool Solver::merge(const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause) +{ + stats.merges++; + + bool ps_smallest = _ps.size() < _qs.size(); + const Clause& ps = ps_smallest ? _qs : _ps; + const Clause& qs = ps_smallest ? _ps : _qs; + + for (int i = 0; i < qs.size(); i++){ + if (var(qs[i]) != v){ + for (int j = 0; j < ps.size(); j++) + if (var(ps[j]) == var(qs[i])) { + if (ps[j] == ~qs[i]) + return false; + else + goto next; + } + out_clause.push(qs[i]); + } + next:; + } + + for (int i = 0; i < ps.size(); i++) + if (var(ps[i]) != v) + out_clause.push(ps[i]); + + return true; +} + + +void Solver::gather(vec<Clause*>& clauses) +{ + //fprintf(stderr, "Gathering clauses for backwards subsumption\n"); + int ntouched = 0; + assert(touched.size() == occurs.size()); + clauses.clear(); + for (int i = 0; i < touched.size(); i++) + if (touched[i]){ + const vec<Clause*>& cs = getOccurs(i); + ntouched++; + for (int j = 0; j < cs.size(); j++) + if (cs[j]->mark() == 0){ + clauses.push(cs[j]); + cs[j]->mark(2); + } + touched[i] = 0; + } + + //fprintf(stderr, "Touched variables %d of %d yields %d clauses to check\n", ntouched, touched.size(), clauses.size()); + for (int i = 0; i < clauses.size(); i++) + clauses[i]->mark(0); +} + + +/*_________________________________________________________________________________________________ +| +| subsumes : (_c : ClauseId) (c : Clause&) (_d : ClauseId) (d : Clause&) -> bool +| +| Description: +| Checks if c subsumes d, and at the same time, if c can be used to simplify d by subsumption +| resolution. +| +| Input: +| Indices into the 'clauses' vector _c, _d, and references to the corresponding clauses c, d. +| +| Result: +| lit_Error - No subsumption or simplification +| lit_Undef - Clause c subsumes d +| l - The literal l can be deleted from d +|________________________________________________________________________________________________@*/ +inline Lit Solver::subsumes(const Clause& c, const Clause& d) +{ + stats.subsumption_checks++; + if (d.size() < c.size() || (c.abstraction() & ~d.abstraction()) != 0) + return lit_Error; + + Lit ret = lit_Undef; + + for (int i = 0; i < c.size(); i++) { + // search for c[i] or ~c[i] + for (int j = 0; j < d.size(); j++) + if (c[i] == d[j]) + goto ok; + else if (ret == lit_Undef && c[i] == ~d[j]){ + ret = c[i]; + goto ok; + } + + // did not find it + stats.subsumption_misses++; + return lit_Error; + ok:; + } + + return ret; +} + + +// Backward subsumption + backward subsumption resolution +bool Solver::backwardSubsumptionCheck() +{ + while (subsumption_queue.size() > 0 || qhead < trail.size()){ + + // if propagation queue is non empty, take the first literal and + // create a dummy unit clause + if (qhead < trail.size()){ + Lit l = trail[qhead++]; + (*bwdsub_tmpunit)[0] = l; + assert(bwdsub_tmpunit->mark() == 0); + subsumption_queue.push(bwdsub_tmpunit); + } + Clause& c = *subsumption_queue.last(); subsumption_queue.pop(); + + if (c.mark()) + continue; + + if (c.size() == 1 && !enqueue(c[0])) + return false; + + // (1) find best variable to scan + Var best = var(c[0]); + for (int i = 1; i < c.size(); i++) + if (occurs[var(c[i])].size() < occurs[best].size()) + best = var(c[i]); + + // (2) search all candidates + const vec<Clause*>& cs = getOccurs(best); + + for (int j = 0; j < cs.size(); j++) + if (cs[j] != &c){ + if (cs[j]->mark()) + continue; + if (c.mark()) + break; + + //fprintf(stderr, "backward candidate "); printClause(*cs[j]); fprintf(stderr, "\n"); + Lit l = subsumes(c, *cs[j]); + if (l == lit_Undef){ + //fprintf(stderr, "clause backwards subsumed\n"); + //fprintf(stderr, " >> clause %d: ", cs[j]->mark()); printClause(*cs[j]); fprintf(stderr, "\n"); + //fprintf(stderr, " >> clause %d: ", c.mark()); printClause(c); fprintf(stderr, "\n"); + removeClause(*cs[j], false); + }else if (l != lit_Error){ + //fprintf(stderr, "backwards subsumption resolution\n"); + //fprintf(stderr, " >> clause %d: ", cs[j]->mark()); printClause(*cs[j]); fprintf(stderr, "\n"); + //fprintf(stderr, " >> clause %d: ", c.mark()); printClause(c); fprintf(stderr, "\n"); + + assert(cs[j]->size() > 1); + assert(find(*cs[j], ~l)); + + subsumption_queue.push(cs[j]); + if (!strengthen(*cs[j], ~l)) + return false; + + // did current candidate get deleted from cs? then check candidate at index j again + if (var(l) == best) + j--; + } + } + } + + return true; +} + + +bool Solver::eliminateVar(Var v, bool fail) +{ + assert(hasVarProp(v, p_frozen)); + + vec<Clause*> pos, neg; + const vec<Clause*>& cls = getOccurs(v); + + if (value(v) != l_Undef || cls.size() == 0) + return true; + + //fprintf(stderr, "trying to eliminate var %d\n", v+1); + for (int i = 0; i < cls.size(); i++){ + //fprintf(stderr, "clause: "); printClause(*cls[i]); fprintf(stderr, "\n"); + if (find(*cls[i], Lit(v))) + pos.push(cls[i]); + else{ + assert(find(*cls[i], ~Lit(v))); + neg.push(cls[i]); + } + } + +#ifdef WEAKEN + vec<int> posc(pos.size(), 0); + vec<int> negc(neg.size(), 0); +#endif + // check if number of clauses decreases + int cnt = 0; + vec<Lit> resolvent; + for (int i = 0; i < pos.size(); i++) + for (int j = 0; j < neg.size(); j++){ + resolvent.clear(); + if (merge(*pos[i], *neg[j], v, resolvent)){ + cnt++; +#ifdef WEAKEN + posc[i]++; + negc[j]++; +#endif + } +#ifndef WEAKEN + if (cnt > cls.size() + grow) + return true; +#else +#ifdef MATING + if (cnt > cls.size() + grow) + if (posc[i] > 0) + break; +#endif +#endif + assert(pos.size() <= n_occ[toInt(Lit(v))]); + assert(neg.size() <= n_occ[toInt(~Lit(v))]); + } + +#ifdef WEAKEN +#ifdef MATING + for (int i = 0; i < neg.size(); i++) + if (negc[i] == 0) + for (int j = 0; j < pos.size(); j++){ + resolvent.clear(); + if (merge(*neg[i], *pos[j], v, resolvent)){ + negc[i]++; + break; + } + } +#endif + for (int i = 0; i < pos.size(); i++) + if (posc[i] == 0) + removeClause(*pos[i], false); + + for (int i = 0; i < neg.size(); i++) + if (negc[i] == 0) + removeClause(*neg[i], false); + + if (cnt > cls.size() + grow) + return true; +#endif + //if (pos.size() != n_occ[toInt(Lit(v))]) + // fprintf(stderr, "pos.size() = %d, n_occ[toInt(Lit(v))] = %d\n", pos.size(), n_occ[toInt(Lit(v))]); + assert(pos.size() == n_occ[toInt(Lit(v))]); + //if (neg.size() != n_occ[toInt(~Lit(v))]) + // fprintf(stderr, "neg.size() = %d, n_occ[toInt(Lit(v))] = %d\n", neg.size(), n_occ[toInt(Lit(v))]); + assert(neg.size() == n_occ[toInt(~Lit(v))]); + assert(cnt <= cls.size() + grow); + setVarProp(v, p_decisionvar, false); + + // produce clauses in cross product + int top = clauses.size(); + for (int i = 0; i < pos.size(); i++) + for (int j = 0; j < neg.size(); j++){ + resolvent.clear(); +#ifdef WEAKEN + if (pos[i]->mark() == 1) + break; + if (neg[j]->mark() == 1) + continue; +#endif + + if (merge(*pos[i], *neg[j], v, resolvent)){ + int i, j; + for (i = j = 0; i < resolvent.size(); i++) + if (value(resolvent[i]) == l_True) + goto next; + else if (value(resolvent[i]) == l_Undef) + resolvent[j++] = resolvent[i]; + resolvent.shrink(i - j); + + if (resolvent.size() == 1){ + if (!enqueue(resolvent[0])) + return false; + }else{ + int apa = clauses.size(); + check(newClause(resolvent, false, true)); + assert(apa + 1 == clauses.size()); + } + } + next:; + } + + if (fail){ + fprintf(stderr, "eliminated var %d, %d <= %d\n", v+1, cnt, cls.size()); + fprintf(stderr, "previous clauses:\n"); + for (int i = 0; i < cls.size(); i++){ + printClause(*cls[i]); + fprintf(stderr, "\n"); + } + + fprintf(stderr, "new clauses:\n"); + for (int i = top; i < clauses.size(); i++){ + printClause(*clauses[i]); + fprintf(stderr, "\n"); + } + + assert(0); } + + //fprintf(stderr, "eliminated var %d, %d <= %d\n", v+1, cnt, cls.size()); + //fprintf(stderr, "previous clauses:\n"); + //for (int i = 0; i < cls.size(); i++){ + // printClause(*cls[i]); + // fprintf(stderr, "\n"); + //} + // + //fprintf(stderr, "new clauses:\n"); + //for (int i = top; i < clauses.size(); i++){ + // printClause(*clauses[i]); + // fprintf(stderr, "\n"); + //} + + // delete + store old clauses + eliminated_var.push(v); + eliminated_lim.push(eliminated.size()); + for (int i = 0; i < cls.size(); i++){ + eliminated.push(Clause_new(*cls[i])); + +#ifdef WEAKEN + if (cls[i]->mark() == 0) +#endif + removeClause(*cls[i], false); + + } + + assert(subsumption_queue.size() == 0); + for (int i = top; i < clauses.size(); i++) +#ifdef ASSYMM + if (clauses[i]->mark() == 0) + if (!assymmetricBranching(*clauses[i])) + return false; + else + subsumption_queue.push(clauses[i]); +#else + if (clauses[i]->mark() == 0) + subsumption_queue.push(clauses[i]); +#endif + + return backwardSubsumptionCheck(); +} + + +void Solver::extendModel() +{ + assert(eliminated_var.size() == eliminated_lim.size()); + for (int i = eliminated_var.size()-1; i >= 0; i--){ + Var v = eliminated_var[i]; + Lit l = lit_Undef; + + //fprintf(stderr, "extending var %d\n", v+1); + + for (int j = eliminated_lim[i]; j < (i+1 >= eliminated_lim.size() ? eliminated.size() : eliminated_lim[i+1]); j++){ + assert(j < eliminated.size()); + Clause& c = *eliminated[j]; + + //fprintf(stderr, "checking clause: "); printClause(c); fprintf(stderr, "\n"); + + for (int k = 0; k < c.size(); k++) + if (var(c[k]) == v) + l = c[k]; + else if (value(c[k]) != l_False) + goto next; + + assert(l != lit_Undef); + //fprintf(stderr, "Fixing var %d to %d\n", v+1, !sign(l)); + + assigns[v] = toInt(lbool(!sign(l))); + break; + + next:; + } + + if (value(v) == l_Undef) + assigns[v] = toInt(l_True); + } +} + + +bool Solver::eliminate() +{ + assert(subsumption); + + int cnt = 0; + //fprintf(stderr, "eliminating variables\n"); + +#ifdef INVARIANTS + // check that all clauses are simplified + fprintf(stderr, "Checking that all clauses are normalized prior to variable elimination\n"); + for (int i = 0; i < clauses.size(); i++) + if (clauses[i]->mark() == 0){ + Clause& c = *clauses[i]; + for (int j = 0; j < c.size(); j++) + assert(value(c[j]) == l_Undef); + } + fprintf(stderr, "done.\n"); +#endif + + for (;;){ + gather(subsumption_queue); + + if (subsumption_queue.size() == 0 && heap.size() == 0) + break; + + //fprintf(stderr, "backwards subsumption: %10d\n", subsumption_queue.size()); + if (!backwardSubsumptionCheck()) + return false; + + //fprintf(stderr, "variable elimination: %10d\n", heap.size()); + cnt = 0; + for (;;){ + assert(!heap.empty() || heap.size() == 0); + if (heap.empty()) + break; + + Var elim = heap.getmin(); + + assert(hasVarProp(elim, p_frozen)); + + //for (int i = 1; i < heap.heap.size(); i++) + // assert(heap.comp(elim, heap.heap[i]) || !heap.comp(elim, heap.heap[i])); + + //if (cnt++ % 100 == 0) + // fprintf(stderr, "left %10d\r", heap.size()); + + if (!eliminateVar(elim)) + return false; + } + } +#ifdef INVARIANTS + // check that no more subsumption is possible + fprintf(stderr, "Checking that no more subsumption is possible\n"); + cnt = 0; + for (int i = 0; i < clauses.size(); i++){ + if (cnt++ % 1000 == 0) + fprintf(stderr, "left %10d\r", clauses.size() - i); + for (int j = 0; j < i; j++) + assert(clauses[i]->mark() || + clauses[j]->mark() || + subsumes(*clauses[i], *clauses[j]) == lit_Error); + } + fprintf(stderr, "done.\n"); + + // check that no more elimination is possible + fprintf(stderr, "Checking that no more elimination is possible\n"); + for (int i = 0; i < nVars(); i++){ + if (hasVarProp(i, p_frozen)) + eliminateVar(i, true); + } + fprintf(stderr, "done.\n"); + +#endif + + assert(qhead == trail.size()); + + return true; +} +}; diff --git a/stp/sat/Solver.C b/stp/sat/Solver.C new file mode 100644 index 00000000..0fcb6149 --- /dev/null +++ b/stp/sat/Solver.C @@ -0,0 +1,811 @@ +/****************************************************************************************[Solver.C] +MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#include "Solver.h" +#include "Sort.h" +#include <cmath> + +namespace MINISAT { +//================================================================================================= +// Operations on clauses: + + +/*_________________________________________________________________________________________________ +| +| newClause : (ps : const vec<Lit>&) (learnt : bool) -> [void] +| +| Description: +| Allocate and add a new clause to the SAT solvers clause database. +| +| Input: +| ps - The new clause as a vector of literals. +| learnt - Is the clause a learnt clause? For learnt clauses, 'ps[0]' is assumed to be the +| asserting literal. An appropriate 'enqueue()' operation will be performed on this +| literal. One of the watches will always be on this literal, the other will be set to +| the literal with the highest decision level. +| +| Effect: +| Activity heuristics are updated. +|________________________________________________________________________________________________@*/ +bool Solver::newClause(const vec<Lit>& ps_, bool learnt, bool normalized) +{ + vec<Lit> qs; + if (!learnt && !normalized){ + assert(decisionLevel() == 0); + ps_.copyTo(qs); // Make a copy of the input vector. + + // Remove duplicates: + sortUnique(qs); + + // Check if clause is satisfied: + for (int i = 0; i < qs.size()-1; i++){ + if (qs[i] == ~qs[i+1]) + return true; } + for (int i = 0; i < qs.size(); i++){ + if (value(qs[i]) == l_True) + return true; } + + // Remove false literals: + int i, j; + for (i = j = 0; i < qs.size(); i++) + if (value(qs[i]) != l_False) + qs[j++] = qs[i]; + qs.shrink(i - j); + } + const vec<Lit>& ps = learnt || normalized ? ps_ : qs; // 'ps' is now the (possibly) reduced vector of literals. + + if (ps.size() == 0) + return false; + else if (ps.size() == 1){ + assert(decisionLevel() == 0); + return enqueue(ps[0]); + }else{ + // Allocate clause: + Clause* c = Clause_new(ps, learnt); + + if (learnt){ + // Put the second watch on the first literal with highest decision level: + // (requires that this method is called at the level where the clause is asserting!) + int i; + for (i = 1; i < ps.size() && position(trailpos[var(ps[i])]) < trail_lim.last(); i++) + ; + (*c)[1] = ps[i]; + (*c)[i] = ps[1]; + + // Bump, enqueue, store clause: + claBumpActivity(*c); // (newly learnt clauses should be considered active) + check(enqueue((*c)[0], c)); + learnts.push(c); + stats.learnts_literals += c->size(); + }else{ + // Store clause: + clauses.push(c); + stats.clauses_literals += c->size(); + + if (subsumption){ + c->calcAbstraction(); + for (int i = 0; i < c->size(); i++){ + assert(!find(occurs[var((*c)[i])], c)); + occurs[var((*c)[i])].push(c); + n_occ[toInt((*c)[i])]++; + touched[var((*c)[i])] = 1; + + if (heap.inHeap(var((*c)[i]))) + updateHeap(var((*c)[i])); + } + } + + } + // Watch clause: + watches[toInt(~(*c)[0])].push(c); + watches[toInt(~(*c)[1])].push(c); + } + + return true; +} + + +// Disposes a clauses and removes it from watcher lists. NOTE! +// Low-level; does NOT change the 'clauses' and 'learnts' vector. +// +void Solver::removeClause(Clause& c, bool dealloc) +{ + //fprintf(stderr, "delete %d: ", _c); printClause(c); fprintf(stderr, "\n"); + assert(c.mark() == 0); + + if (c.size() > 1){ + assert(find(watches[toInt(~c[0])], &c)); + assert(find(watches[toInt(~c[1])], &c)); + remove(watches[toInt(~c[0])], &c); + remove(watches[toInt(~c[1])], &c); } + + if (c.learnt()) stats.learnts_literals -= c.size(); + else stats.clauses_literals -= c.size(); + + if (subsumption && !c.learnt()){ + for (int i = 0; i < c.size(); i++){ + if (dealloc){ + assert(find(occurs[var(c[i])], &c)); + remove(occurs[var(c[i])], &c); + } + n_occ[toInt(c[i])]--; + updateHeap(var(c[i])); + } + } + + if (dealloc) + xfree(&c); + else + c.mark(1); +} + + +bool Solver::satisfied(Clause& c) const +{ + for (int i = 0; i < c.size(); i++) + if (value(c[i]) == l_True) + return true; + return false; } + + +bool Solver::strengthen(Clause& c, Lit l) +{ + assert(decisionLevel() == 0); + assert(c.size() > 1); + assert(c.mark() == 0); + + assert(toInt(~c[0]) < watches.size()); + assert(toInt(~c[1]) < watches.size()); + + assert(find(watches[toInt(~c[0])], &c)); + assert(find(watches[toInt(~c[1])], &c)); + assert(find(c,l)); + + if (c.learnt()) stats.learnts_literals -= 1; + else stats.clauses_literals -= 1; + + if (c[0] == l || c[1] == l){ + assert(find(watches[toInt(~l)], &c)); + remove(c,l); + remove(watches[toInt(~l)], &c); + if (c.size() > 1){ + assert(!find(watches[toInt(~c[1])], &c)); + watches[toInt(~c[1])].push(&c); } + else { + assert(find(watches[toInt(~c[0])], &c)); + remove(watches[toInt(~c[0])], &c); + removeClause(c, false); + } + } + else + remove(c,l); + + assert(c.size() == 1 || find(watches[toInt(~c[0])], &c)); + assert(c.size() == 1 || find(watches[toInt(~c[1])], &c)); + + if (subsumption){ + assert(find(occurs[var(l)], &c)); + remove(occurs[var(l)], &c); + assert(!find(occurs[var(l)], &c)); + + c.calcAbstraction(); + + n_occ[toInt(l)]--; + updateHeap(var(l)); + } + + return c.size() == 1 ? enqueue(c[0]) : true; +} + + +//================================================================================================= +// Minor methods: + + +// Creates a new SAT variable in the solver. If 'decision_var' is cleared, variable will not be +// used as a decision variable (NOTE! This has effects on the meaning of a SATISFIABLE result). +// +Var Solver::newVar(bool polarity, bool dvar) { + int index; + index = nVars(); + watches .push(); // (list for positive literal) + watches .push(); // (list for negative literal) + reason .push(NULL); + assigns .push(toInt(l_Undef)); + trailpos .push(TrailPos(0,0)); + activity .push(0); + order .newVar(polarity,dvar); + seen .push(0); + touched .push(0); + if (subsumption){ + occurs .push(); + n_occ .push(0); + n_occ .push(0); + heap .setBounds(index+1); + } + return index; } + + +// Returns FALSE if immediate conflict. +bool Solver::assume(Lit p) { + trail_lim.push(trail.size()); + return enqueue(p); } + + +// Revert to the state at given level. +void Solver::cancelUntil(int level) { + if (decisionLevel() > level){ + for (int c = trail.size()-1; c >= trail_lim[level]; c--){ + Var x = var(trail[c]); + assigns[x] = toInt(l_Undef); + reason [x] = NULL; + order.undo(x); } + qhead = trail_lim[level]; + trail.shrink(trail.size() - trail_lim[level]); + trail_lim.shrink(trail_lim.size() - level); + } +} + + +//================================================================================================= +// Major methods: + + +/*_________________________________________________________________________________________________ +| +| analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&) -> [void] +| +| Description: +| Analyze conflict and produce a reason clause. +| +| Pre-conditions: +| * 'out_learnt' is assumed to be cleared. +| * Current decision level must be greater than root level. +| +| Post-conditions: +| * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'. +| +| Effect: +| Will undo part of the trail, upto but not beyond the assumption of the current decision level. +|________________________________________________________________________________________________@*/ +void Solver::analyze(Clause* confl, vec<Lit>& out_learnt, int& out_btlevel) +{ + int pathC = 0; + int btpos = -1; + Lit p = lit_Undef; + + // Generate conflict clause: + // + out_learnt.push(); // (leave room for the asserting literal) + int index = trail.size()-1; + do{ + assert(confl != NULL); // (otherwise should be UIP) + Clause& c = *confl; + + if (c.learnt()) + claBumpActivity(c); + + for (int j = (p == lit_Undef) ? 0 : 1; j < c.size(); j++){ + Lit q = c[j]; + if (!seen[var(q)] && position(trailpos[var(q)]) >= trail_lim[0]){ + varBumpActivity(q); + seen[var(q)] = 1; + if (position(trailpos[var(q)]) >= trail_lim.last()) + pathC++; + else{ + out_learnt.push(q); + btpos = max(btpos, position(trailpos[var(q)])); + } + } + } + + // Select next clause to look at: + while (!seen[var(trail[index--])]); + p = trail[index+1]; + confl = reason[var(p)]; + seen[var(p)] = 0; + pathC--; + + }while (pathC > 0); + out_learnt[0] = ~p; + + // Find correct backtrack level + for (out_btlevel = trail_lim.size()-1; out_btlevel > 0 && trail_lim[out_btlevel-1] > btpos; out_btlevel--) + ; + + int i, j; + if (expensive_ccmin){ + // Simplify conflict clause (a lot): + // + uint min_level = 0; + for (i = 1; i < out_learnt.size(); i++) + min_level |= abstractLevel(trailpos[var(out_learnt[i])]); // (maintain an abstraction of levels involved in conflict) + + out_learnt.copyTo(analyze_toclear); + for (i = j = 1; i < out_learnt.size(); i++) + if (reason[var(out_learnt[i])] == NULL || !analyze_removable(out_learnt[i], min_level)) + out_learnt[j++] = out_learnt[i]; + }else{ + // Simplify conflict clause (a little): + // + out_learnt.copyTo(analyze_toclear); + for (i = j = 1; i < out_learnt.size(); i++){ + Clause& c = *reason[var(out_learnt[i])]; + for (int k = 1; k < c.size(); k++) + if (!seen[var(c[k])] && position(trailpos[var(c[k])]) >= trail_lim[0]){ + out_learnt[j++] = out_learnt[i]; + break; } + } + } + + stats.max_literals += out_learnt.size(); + out_learnt.shrink(i - j); + stats.tot_literals += out_learnt.size(); + + for (int j = 0; j < analyze_toclear.size(); j++) seen[var(analyze_toclear[j])] = 0; // ('seen[]' is now cleared) +} + + +// Check if 'p' can be removed. 'min_level' is used to abort early if visiting literals at a level that cannot be removed. +// +bool Solver::analyze_removable(Lit p, uint min_level) +{ + analyze_stack.clear(); analyze_stack.push(p); + int top = analyze_toclear.size(); + while (analyze_stack.size() > 0){ + assert(reason[var(analyze_stack.last())] != NULL); + Clause& c = *reason[var(analyze_stack.last())]; analyze_stack.pop(); + + for (int i = 1; i < c.size(); i++){ + Lit p = c[i]; + TrailPos tp = trailpos[var(p)]; + if (!seen[var(p)] && position(tp) >= trail_lim[0]){ + if (reason[var(p)] != NULL && (abstractLevel(tp) & min_level) != 0){ + seen[var(p)] = 1; + analyze_stack.push(p); + analyze_toclear.push(p); + }else{ + for (int j = top; j < analyze_toclear.size(); j++) + seen[var(analyze_toclear[j])] = 0; + analyze_toclear.shrink(analyze_toclear.size() - top); + return false; + } + } + } + } + + return true; +} + + +/*_________________________________________________________________________________________________ +| +| analyzeFinal : (p : Lit) -> [void] +| +| Description: +| Specialized analysis procedure to express the final conflict in terms of assumptions. +| Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and +| stores the result in 'out_conflict'. +|________________________________________________________________________________________________@*/ +void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict) +{ + out_conflict.clear(); + out_conflict.push(p); + + if (decisionLevel() == 0) + return; + + seen[var(p)] = 1; + + int start = position(trailpos[var(p)]); + for (int i = start; i >= trail_lim[0]; i--){ + Var x = var(trail[i]); + if (seen[x]){ + if (reason[x] == NULL){ + assert(position(trailpos[x]) >= trail_lim[0]); + out_conflict.push(~trail[i]); + }else{ + Clause& c = *reason[x]; + for (int j = 1; j < c.size(); j++) + if (position(trailpos[var(c[j])]) >= trail_lim[0]) + seen[var(c[j])] = 1; + } + seen[x] = 0; + } + } +} + + +/*_________________________________________________________________________________________________ +| +| enqueue : (p : Lit) (from : Clause*) -> [bool] +| +| Description: +| Puts a new fact on the propagation queue as well as immediately updating the variable's value. +| Should a conflict arise, FALSE is returned. +| +| Input: +| p - The fact to enqueue +| from - [Optional] Fact propagated from this (currently) unit clause. Stored in 'reason[]'. +| Default value is NULL (no reason). +| +| Output: +| TRUE if fact was enqueued without conflict, FALSE otherwise. +|________________________________________________________________________________________________@*/ +bool Solver::enqueue(Lit p, Clause* from) +{ + + if (value(p) != l_Undef) + return value(p) != l_False; + else{ + assigns [var(p)] = toInt(lbool(!sign(p))); + trailpos[var(p)] = TrailPos(trail.size(),decisionLevel()); + reason [var(p)] = from; + trail.push(p); + return true; + } +} + + +/*_________________________________________________________________________________________________ +| +| propagate : [void] -> [Clause*] +| +| Description: +| Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned, +| otherwise NULL. +| +| Post-conditions: +| * the propagation queue is empty, even if there was a conflict. +|________________________________________________________________________________________________@*/ +Clause* Solver::propagate() +{ + if (decisionLevel() == 0 && subsumption) + return backwardSubsumptionCheck() ? NULL : propagate_tmpempty; + + Clause* confl = NULL; + //fprintf(stderr, "propagate, qhead = %d, qtail = %d\n", qhead, qtail); + while (qhead < trail.size()){ + stats.propagations++; + simpDB_props--; + + Lit p = trail[qhead++]; // 'p' is enqueued fact to propagate. + vec<Clause*>& ws = watches[toInt(p)]; + Clause **i, **j, **end; + + for (i = j = (Clause**)ws, end = i + ws.size(); i != end;){ + Clause& c = **i++; + + // Make sure the false literal is data[1]: + Lit false_lit = ~p; + if (c[0] == false_lit) + c[0] = c[1], c[1] = false_lit; + + assert(c[1] == false_lit); + + // If 0th watch is true, then clause is already satisfied. + Lit first = c[0]; + if (value(first) == l_True){ + *j++ = &c; + }else{ + // Look for new watch: + for (int k = 2; k < c.size(); k++) + if (value(c[k]) != l_False){ + c[1] = c[k]; c[k] = false_lit; + watches[toInt(~c[1])].push(&c); + goto FoundWatch; } + + // Did not find watch -- clause is unit under assignment: + *j++ = &c; + if (!enqueue(first, &c)){ + confl = &c; + qhead = trail.size(); + // Copy the remaining watches: + while (i < end) + *j++ = *i++; + } + FoundWatch:; + } + } + ws.shrink(i - j); + } + + return confl; +} + + +/*_________________________________________________________________________________________________ +| +| reduceDB : () -> [void] +| +| Description: +| Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked +| clauses are clauses that are reason to some assignment. Binary clauses are never removed. +|________________________________________________________________________________________________@*/ +struct reduceDB_lt { bool operator () (Clause* x, Clause* y) { return x->size() > 2 && (y->size() == 2 || x->activity() < y->activity()); } }; +void Solver::reduceDB() +{ + int i, j; + double extra_lim = cla_inc / learnts.size(); // Remove any clause below this activity + + sort(learnts, reduceDB_lt()); + for (i = j = 0; i < learnts.size() / 2; i++){ + if (learnts[i]->size() > 2 && !locked(*learnts[i])) + removeClause(*learnts[i]); + else + learnts[j++] = learnts[i]; + } + for (; i < learnts.size(); i++){ + if (learnts[i]->size() > 2 && !locked(*learnts[i]) && learnts[i]->activity() < extra_lim) + removeClause(*learnts[i]); + else + learnts[j++] = learnts[i]; + } + learnts.shrink(i - j); +} + + +/*_________________________________________________________________________________________________ +| +| simplifyDB : [void] -> [bool] +| +| Description: +| Simplify the clause database according to the current top-level assigment. Currently, the only +| thing done here is the removal of satisfied clauses, but more things can be put here. +|________________________________________________________________________________________________@*/ +bool Solver::simplifyDB(bool expensive) +{ + assert(decisionLevel() == 0); + if (!ok || propagate() != NULL) + return ok = false; + + if (nAssigns() == simpDB_assigns || + (!subsumption && simpDB_props > 0)) // (nothing has changed or preformed a simplification too recently) + return true; + + if (subsumption){ + if (expensive && !eliminate()) + return ok = false; + + // Move this cleanup code to its own method ? + int i , j; + vec<Var> dirty; + for (i = 0; i < clauses.size(); i++) + if (clauses[i]->mark() == 1){ + Clause& c = *clauses[i]; + for (int k = 0; k < c.size(); k++) + if (!seen[var(c[k])]){ + seen[var(c[k])] = 1; + dirty.push(var(c[k])); + } + } + + for (i = 0; i < dirty.size(); i++){ + cleanOcc(dirty[i]); + seen[dirty[i]] = 0; + } + + for (i = j = 0; i < clauses.size(); i++) + if (clauses[i]->mark() == 1) + xfree(clauses[i]); + else + clauses[j++] = clauses[i]; + clauses.shrink(i - j); + } + + // Remove satisfied clauses: + for (int type = 0; type < (subsumption ? 1 : 2); type++){ // (only scan learnt clauses if subsumption is on) + vec<Clause*>& cs = type ? learnts : clauses; + int j = 0; + for (int i = 0; i < cs.size(); i++){ + assert(cs[i]->mark() == 0); + if (satisfied(*cs[i])) + removeClause(*cs[i]); + else + cs[j++] = cs[i]; + } + cs.shrink(cs.size()-j); + } + order.cleanup(); + + simpDB_assigns = nAssigns(); + simpDB_props = stats.clauses_literals + stats.learnts_literals; // (shouldn't depend on 'stats' really, but it will do for now) + + return true; +} + + +/*_________________________________________________________________________________________________ +| +| search : (nof_conflicts : int) (nof_learnts : int) (params : const SearchParams&) -> [lbool] +| +| Description: +| Search for a model the specified number of conflicts, keeping the number of learnt clauses +| below the provided limit. NOTE! Use negative value for 'nof_conflicts' or 'nof_learnts' to +| indicate infinity. +| +| Output: +| 'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If +| all variables are decision variables, this means that the clause set is satisfiable. 'l_False' +| if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached. +|________________________________________________________________________________________________@*/ +lbool Solver::search(int nof_conflicts, int nof_learnts) +{ + assert(ok); + int backtrack_level; + int conflictC = 0; + vec<Lit> learnt_clause; + + stats.starts++; + var_decay = 1 / params.var_decay; + cla_decay = 1 / params.clause_decay; + + for (;;){ + Clause* confl = propagate(); + if (confl != NULL){ + // CONFLICT + stats.conflicts++; conflictC++; + if (decisionLevel() == 0) return l_False; + + learnt_clause.clear(); + analyze(confl, learnt_clause, backtrack_level); + cancelUntil(backtrack_level); + newClause(learnt_clause, true); + varDecayActivity(); + claDecayActivity(); + + }else{ + // NO CONFLICT + + if (nof_conflicts >= 0 && conflictC >= nof_conflicts){ + // Reached bound on number of conflicts: + progress_estimate = progressEstimate(); + cancelUntil(0); + return l_Undef; } + + // Simplify the set of problem clauses: + if (decisionLevel() == 0 && !simplifyDB()) + return l_False; + + if (nof_learnts >= 0 && learnts.size()-nAssigns() >= nof_learnts) + // Reduce the set of learnt clauses: + reduceDB(); + + Lit next = lit_Undef; + + if (decisionLevel() < assumptions.size()){ + // Perform user provided assumption: + next = assumptions[decisionLevel()]; + if (value(next) == l_False){ + analyzeFinal(~next, conflict); + return l_False; } + }else{ + // New variable decision: + stats.decisions++; + next = order.select(params.random_var_freq, decisionLevel()); + } + if (next == lit_Undef) + // Model found: + return l_True; + + check(assume(next)); + } + } +} + + +// Return search-space coverage. Not extremely reliable. +// +double Solver::progressEstimate() +{ + double progress = 0; + double F = 1.0 / nVars(); + + for (int i = 0; i <= decisionLevel(); i++){ + int beg = i == 0 ? 0 : trail_lim[i - 1]; + int end = i == decisionLevel() ? trail.size() : trail_lim[i]; + progress += pow(F, i) * (end - beg); + } + + return progress / nVars(); +} + + +// Divide all variable activities by 1e100. +// +void Solver::varRescaleActivity() +{ + for (int i = 0; i < nVars(); i++) + activity[i] *= 1e-100; + var_inc *= 1e-100; +} + + +// Divide all constraint activities by 1e100. +// +void Solver::claRescaleActivity() +{ + for (int i = 0; i < learnts.size(); i++) + learnts[i]->activity() *= 1e-20; + cla_inc *= 1e-20; +} + + +/*_________________________________________________________________________________________________ +| +| solve : (assumps : const vec<Lit>&) -> [bool] +| +| Description: +| Top-level solve. +|________________________________________________________________________________________________@*/ +bool Solver::solve(const vec<Lit>& assumps) +{ + model.clear(); + conflict.clear(); + + if (!simplifyDB(true)) return false; + + + double nof_conflicts = params.restart_first; + double nof_learnts = nClauses() * params.learntsize_factor; + lbool status = l_Undef; + assumps.copyTo(assumptions); + + if (verbosity >= 1){ + reportf("==================================[MINISAT]====================================\n"); + reportf("| Conflicts | ORIGINAL | LEARNT | Progress |\n"); + reportf("| | Vars Clauses Literals | Limit Clauses Lit/Cl | |\n"); + reportf("===============================================================================\n"); + } + + // Search: + while (status == l_Undef){ + if (verbosity >= 1) + //reportf("| %9d | %7d %8d | %7d %7d %8d %7.1f | %6.3f %% |\n", (int)stats.conflicts, nClauses(), (int)stats.clauses_literals, (int)nof_learnts, nLearnts(), (int)stats.learnts_literals, (double)stats.learnts_literals/nLearnts(), progress_estimate*100); + reportf("| %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n", (int)stats.conflicts, order.size(), nClauses(), (int)stats.clauses_literals, (int)nof_learnts, nLearnts(), (double)stats.learnts_literals/nLearnts(), progress_estimate*100); + status = search((int)nof_conflicts, (int)nof_learnts); + nof_conflicts *= params.restart_inc; + nof_learnts *= params.learntsize_inc; + } + + if (verbosity >= 1) + reportf("==============================================================================\n"); + + if (status == l_True){ + // Copy model: + extendModel(); +#if 1 + //fprintf(stderr, "Verifying model.\n"); + for (int i = 0; i < clauses.size(); i++) + assert(satisfied(*clauses[i])); + for (int i = 0; i < eliminated.size(); i++) + assert(satisfied(*eliminated[i])); +#endif + model.growTo(nVars()); + for (int i = 0; i < nVars(); i++) model[i] = value(i); + }else{ + assert(status == l_False); + if (conflict.size() == 0) + ok = false; + } + + cancelUntil(0); + return status == l_True; +} +};//end of MINISAT namespace diff --git a/stp/sat/Solver.h b/stp/sat/Solver.h new file mode 100644 index 00000000..829194cc --- /dev/null +++ b/stp/sat/Solver.h @@ -0,0 +1,359 @@ +/****************************************************************************************[Solver.h] +MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Solver_h +#define Solver_h + +#include "SolverTypes.h" +#include "VarOrder.h" + +namespace MINISAT { +// Redfine if you want output to go somewhere else: +#define reportf(format, args...) ( printf(format , ## args), fflush(stdout) ) + + +//================================================================================================= +// Solver -- the main class: +struct SolverStats { + int64 starts, decisions, propagations, conflicts; + int64 clauses_literals, learnts_literals, max_literals, tot_literals; + int64 subsumption_checks, subsumption_misses, merges; + SolverStats() : + starts(0), decisions(0), propagations(0), conflicts(0) + , clauses_literals(0), learnts_literals(0), max_literals(0), tot_literals(0) + , subsumption_checks(0), subsumption_misses(0), merges(0) + { } +}; + + +struct SearchParams { + double var_decay, clause_decay, random_var_freq; + double restart_inc, learntsize_inc, learntsize_factor; + int restart_first; + + SearchParams(double v = 0.95, double c = 0.999, double r = 0.02, + double ri = 1.5, double li = 1.1, double lf = (double)1/(double)3, + int rf = 100) : + var_decay(v), clause_decay(c), random_var_freq(r), + restart_inc(ri), learntsize_inc(li), learntsize_factor(lf), + restart_first(rf) { } +}; + + struct ElimLt { + const vec<int>& n_occ; + + ElimLt(const vec<int>& no) : n_occ(no) {} + int cost (Var x) const { return n_occ[toInt(Lit(x))] * n_occ[toInt(~Lit(x))]; } + bool operator()(Var x, Var y) const { return cost(x) < cost(y); } + }; + +class Solver { +protected: + // Solver state: + bool ok; // If FALSE,the constraints are already unsatisfiable. + // No part of solver state may be used! + vec<Clause*> clauses; // List of problem clauses. + vec<Clause*> learnts; // List of learnt clauses. + int n_bin_clauses; // Keep track of number of binary clauses "inlined" into the watcher lists (we do this primarily to get identical behavior to the version without the binary clauses trick). + double cla_inc; // Amount to bump next clause with. + double cla_decay; // INVERSE decay factor for clause activity: stores 1/decay. + + vec<double> activity; // A heuristic measurement of the activity of a variable. + double var_inc; // Amount to bump next variable with. + double var_decay; // INVERSE decay factor for variable activity: stores 1/decay. Use negative value for static variable order. + VarOrder order; // Keeps track of the decision variable order. + vec<char> properties; // TODO: describe!!! + + vec<vec<Clause*> > watches; // 'watches[lit]' is a list of constraints watching 'lit' (will go there if literal becomes true). + vec<char> assigns; // The current assignments (lbool:s stored as char:s). + vec<Lit> trail; // Assignment stack; stores all assigments made in the order they were made. + vec<int> trail_lim; // Separator indices for different decision levels in 'trail'. + vec<Clause*> reason; // 'reason[var]' is the clause that implied the variables current value, or 'NULL' if none. + vec<TrailPos> trailpos; // 'trailpos[var]' contains the position in the trail at wich the assigment was made. + int qhead; // Head of queue (as index into the trail -- no more explicit propagation queue in MiniSat). + int simpDB_assigns; // Number of top-level assignments since last execution of 'simplifyDB()'. + int64 simpDB_props; // Remaining number of propagations that must be made before next execution of 'simplifyDB()'. + vec<Lit> assumptions; // Current set of assumptions provided to solve by the user. + + bool subsumption; + vec<char> touched; + vec<vec<Clause*> > occurs; + vec<int> n_occ; + Heap<ElimLt> heap; + vec<Clause*> subsumption_queue; + + vec<Clause*> eliminated; + vec<int> eliminated_lim; + vec<Var> eliminated_var; + + // Temporaries (to reduce allocation overhead). Each variable is prefixed by the method in which it is + // used, exept 'seen' wich is used in several places. + // + vec<char> seen; + vec<Lit> analyze_stack; + vec<Lit> analyze_toclear; + Clause* propagate_tmpempty; + Clause* propagate_tmpbin; + Clause* analyze_tmpbin; + Clause* bwdsub_tmpunit; + + vec<Lit> addBinary_tmp; + vec<Lit> addTernary_tmp; + + // Main internal methods: + // + bool assume (Lit p); + void cancelUntil (int level); + void record (const vec<Lit>& clause); + + void analyze (Clause* confl, vec<Lit>& out_learnt, int& out_btlevel); // (bt = backtrack) + bool analyze_removable(Lit p, uint min_level); // (helper method for 'analyze()') + void analyzeFinal (Lit p, vec<Lit>& out_conflict); + bool enqueue (Lit fact, Clause* from = NULL); + Clause* propagate (); + void reduceDB (); + Lit pickBranchLit (); + lbool search (int nof_conflicts, int nof_learnts); + double progressEstimate (); + + // Variable properties: + void setVarProp (Var v, uint prop, bool b) { order.setVarProp(v, prop, b); } + bool hasVarProp (Var v, uint prop) const { return order.hasVarProp(v, prop); } + void updateHeap (Var v) { + if (hasVarProp(v, p_frozen)) + heap.update(v); } + + // Simplification methods: + // + void cleanOcc (Var v) { + assert(subsumption); + vec<Clause*>& occ = occurs[v]; + int i, j; + for (i = j = 0; i < occ.size(); i++) + if (occ[i]->mark() != 1) + occ[j++] = occ[i]; + occ.shrink(i - j); + } + + vec<Clause*>& getOccurs (Var x) { cleanOcc(x); return occurs[x]; } + void gather (vec<Clause*>& clauses); + Lit subsumes (const Clause& c, const Clause& d); + bool assymmetricBranching (Clause& c); + bool merge (const Clause& _ps, const Clause& _qs, Var v, vec<Lit>& out_clause); + + bool backwardSubsumptionCheck (); + bool eliminateVar (Var v, bool fail = false); + bool eliminate (); + void extendModel (); + + // Activity: + // + void varBumpActivity(Lit p) { + if (var_decay < 0) return; // (negative decay means static variable order -- don't bump) + if ( (activity[var(p)] += var_inc) > 1e100 ) varRescaleActivity(); + order.update(var(p)); } + void varDecayActivity () { if (var_decay >= 0) var_inc *= var_decay; } + void varRescaleActivity(); + void claDecayActivity () { cla_inc *= cla_decay; } + void claRescaleActivity(); + + // Operations on clauses: + // + bool newClause(const vec<Lit>& ps, bool learnt = false, bool normalized = false); + void claBumpActivity (Clause& c) { if ( (c.activity() += cla_inc) > 1e20 ) claRescaleActivity(); } + bool locked (const Clause& c) const { return reason[var(c[0])] == &c; } + bool satisfied (Clause& c) const; + bool strengthen (Clause& c, Lit l); + void removeClause (Clause& c, bool dealloc = true); + + int decisionLevel() const { return trail_lim.size(); } + +public: + Solver() : ok (true) + , n_bin_clauses (0) + , cla_inc (1) + , cla_decay (1) + , var_inc (1) + , var_decay (1) + , order (assigns, activity) + , qhead (0) + , simpDB_assigns (-1) + , simpDB_props (0) + , subsumption (true) + , heap (n_occ) + , params () + , expensive_ccmin (true) + , verbosity (0) + , progress_estimate(0) + { + vec<Lit> dummy(2,lit_Undef); + propagate_tmpbin = Clause_new(dummy); + analyze_tmpbin = Clause_new(dummy); + dummy.pop(); + bwdsub_tmpunit = Clause_new(dummy); + dummy.pop(); + propagate_tmpempty = Clause_new(dummy); + addBinary_tmp .growTo(2); + addTernary_tmp.growTo(3); + } + + ~Solver() { + xfree(propagate_tmpbin); + xfree(analyze_tmpbin); + xfree(bwdsub_tmpunit); + xfree(propagate_tmpempty); + for (int i = 0; i < eliminated.size(); i++) xfree(eliminated[i]); + for (int i = 0; i < learnts.size(); i++) xfree(learnts[i]); + for (int i = 0; i < clauses.size(); i++) xfree(clauses[i]); } + + // Helpers: (semi-internal) + // + lbool value(Var x) const { return toLbool(assigns[x]); } + lbool value(Lit p) const { return sign(p) ? ~toLbool(assigns[var(p)]) : toLbool(assigns[var(p)]); } + + int nAssigns() { return trail.size(); } + int nClauses() { return clauses.size(); } + int nLearnts() { return learnts.size(); } + int nConflicts() { return (int)stats.conflicts; } + + // Statistics: (read-only member variable) + // + SolverStats stats; + + // Mode of operation: + // + SearchParams params; // Restart frequency etc. + bool expensive_ccmin; // Controls conflict clause minimization. TRUE by default. + int verbosity; // Verbosity level. 0=silent, 1=some progress report, 2=everything + + // Problem specification: + // + Var newVar (bool polarity = true, bool dvar = true); + int nVars () { return assigns.size(); } + bool addUnit (Lit p) { return ok && (ok = enqueue(p)); } + bool addBinary (Lit p, Lit q) { addBinary_tmp [0] = p; addBinary_tmp [1] = q; return addClause(addBinary_tmp); } + bool addTernary(Lit p, Lit q, Lit r) { addTernary_tmp[0] = p; addTernary_tmp[1] = q; addTernary_tmp[2] = r; return addClause(addTernary_tmp); } + bool addClause (const vec<Lit>& ps) { if (ok && !newClause(ps)) ok = false; return ok; } + + // Variable mode: + // + void freezeVar (Var v) { setVarProp(v, p_frozen, true); updateHeap(v); } + + // Solving: + // + bool okay () { return ok; } // FALSE means solver is in a conflicting state + bool simplifyDB (bool expensive = true); + bool solve (const vec<Lit>& assumps); + bool solve () { vec<Lit> tmp; return solve(tmp); } + void turnOffSubsumption() { + subsumption = false; + occurs.clear(true); + n_occ.clear(true); + } + + double progress_estimate; // Set by 'search()'. + vec<lbool> model; // If problem is satisfiable, this vector contains the model (if any). + vec<Lit> conflict; // If problem is unsatisfiable (possibly under assumptions), this vector represent the conflict clause expressed in the assumptions. + + double returnActivity(int i) { return activity[i];} + void updateInitialActivity(int i, double act) {activity[i] = act; order.heap.update(i);} +}; + + +//================================================================================================= +// Debug: + + +#define L_LIT "%sx%d" +#define L_lit(p) sign(p)?"~":"", var(p) + +// Just like 'assert()' but expression will be evaluated in the release version as well. +inline void check(bool expr) { assert(expr); } + +static void printLit(Lit l) +{ + fprintf(stderr, "%s%d", sign(l) ? "-" : "", var(l)+1); +} + +template<class C> +static void printClause(const C& c) +{ + for (int i = 0; i < c.size(); i++){ + printLit(c[i]); + fprintf(stderr, " "); + } +} + +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#ifdef _MSC_VER + +#include <ctime> + +static inline double cpuTime(void) { + return (double)clock() / CLOCKS_PER_SEC; } + +static inline int64 memUsed() { + return 0; } + +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#else + +#include <sys/time.h> +#include <sys/resource.h> + +static inline double cpuTime(void) { + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000; } + +#if defined(__linux__) || defined(__CYGWIN__) +static inline int memReadStat(int field) +{ + char name[256]; + pid_t pid = getpid(); + sprintf(name, "/proc/%d/statm", pid); + FILE* in = fopen(name, "rb"); + if (in == NULL) return 0; + int value; + for (; field >= 0; field--) { + int res = fscanf(in, "%d", &value); + (void) res; + } + fclose(in); + return value; +} + +static inline int64 memUsed() { return (int64)memReadStat(0) * (int64)getpagesize(); } +#else +// use this by default. Mac OS X (Darwin) does not define an os type +//defined(__FreeBSD__) + +static inline int64 memUsed(void) { + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return ru.ru_maxrss*1024; } + +#endif + +//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +#endif + +//================================================================================================= +}; +#endif diff --git a/stp/sat/SolverTypes.h b/stp/sat/SolverTypes.h new file mode 100644 index 00000000..2b98b8ca --- /dev/null +++ b/stp/sat/SolverTypes.h @@ -0,0 +1,127 @@ +/***********************************************************************************[SolverTypes.h] +MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + + +#ifndef SolverTypes_h +#define SolverTypes_h + +#include "Global.h" + +namespace MINISAT { + +//================================================================================================= +// Variables, literals, clause IDs: + + +// NOTE! Variables are just integers. No abstraction here. They should be chosen from 0..N, +// so that they can be used as array indices. + +typedef int Var; +#define var_Undef (-1) + + +struct Lit { + int x; + + Lit() : x(2*var_Undef) { } // (lit_Undef) + explicit Lit(Var var, bool sign = false) : x((var+var) + (int)sign) { } +}; + +// Don't use these for constructing/deconstructing literals. Use the normal constructors instead. +inline int toInt (Lit p) { return p.x; } // A "toInt" method that guarantees small, positive integers suitable for array indexing. +inline Lit toLit (int i) { Lit p; p.x = i; return p; } // Inverse of 'toInt()' + +inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; } +inline bool sign (Lit p) { return p.x & 1; } +inline int var (Lit p) { return p.x >> 1; } +inline Lit unsign (Lit p) { Lit q; q.x = p.x & ~1; return q; } +inline Lit id (Lit p, bool sgn) { Lit q; q.x = p.x ^ (int)sgn; return q; } + +inline bool operator == (Lit p, Lit q) { return toInt(p) == toInt(q); } +inline bool operator != (Lit p, Lit q) { return toInt(p) != toInt(q); } +inline bool operator < (Lit p, Lit q) { return toInt(p) < toInt(q); } // '<' guarantees that p, ~p are adjacent in the ordering. + + +const Lit lit_Undef(var_Undef, false); // }- Useful special constants. +const Lit lit_Error(var_Undef, true ); // } + + +//================================================================================================= +// Clause -- a simple class for representing a clause: + +class Clause { + uint size_etc; + union { float act; uint abst; } apa; + Lit data[0]; +public: + // NOTE: This constructor cannot be used directly (doesn't allocate enough memory). + template<class V> + Clause(const V& ps, bool learnt) { + size_etc = (ps.size() << 3) | (uint)learnt; + for (int i = 0; i < ps.size(); i++) data[i] = ps[i]; + if (learnt) apa.act = 0; else apa.abst = 0; } + + // -- use this function instead: + template<class V> + friend Clause* Clause_new(const V& ps, bool learnt = false) { + assert(sizeof(Lit) == sizeof(uint)); + assert(sizeof(float) == sizeof(uint)); + void* mem = xmalloc<char>(sizeof(Clause) + sizeof(uint)*(ps.size())); + return new (mem) Clause(ps, learnt); } + + int size () const { return size_etc >> 3; } + void shrink (int i) { assert(i <= size()); size_etc = (((size_etc >> 3) - i) << 3) | (size_etc & 7); } + void pop () { shrink(1); } + bool learnt () const { return size_etc & 1; } + uint mark () const { return (size_etc >> 1) & 3; } + void mark (uint m) { size_etc = (size_etc & ~6) | ((m & 3) << 1); } + Lit operator [] (int i) const { return data[i]; } + Lit& operator [] (int i) { return data[i]; } + + float& activity () { return apa.act; } + + uint abstraction () const { return apa.abst; } + + void calcAbstraction() { + uint abstraction = 0; + for (int i = 0; i < size(); i++) + abstraction |= 1 << (var(data[i]) & 31); + apa.abst = abstraction; } +}; + + +//================================================================================================= +// TrailPos -- Stores an index into the trail as well as an approximation of a level. This data +// is recorded for each assigment. (Replaces the old level information) + + +class TrailPos { + int tp; + public: + explicit TrailPos(int index, int level) : tp( (index << 5) + (level & 31) ) { } + + friend int abstractLevel(const TrailPos& p) { return 1 << (p.tp & 31); } + friend int position (const TrailPos& p) { return p.tp >> 5; } + + bool operator == (TrailPos other) const { return tp == other.tp; } + bool operator < (TrailPos other) const { return tp < other.tp; } +}; + +}; +#endif diff --git a/stp/sat/Sort.h b/stp/sat/Sort.h new file mode 100644 index 00000000..a7011edb --- /dev/null +++ b/stp/sat/Sort.h @@ -0,0 +1,133 @@ +/******************************************************************************************[Sort.h] +MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef Sort_h +#define Sort_h + + +namespace MINISAT { +//================================================================================================= + + +template<class T> +struct LessThan_default { + bool operator () (T x, T y) { return x < y; } +}; + + +//================================================================================================= + + +template <class T, class LessThan> +void selectionSort(T* array, int size, LessThan lt) +{ + int i, j, best_i; + T tmp; + + for (i = 0; i < size-1; i++){ + best_i = i; + for (j = i+1; j < size; j++){ + if (lt(array[j], array[best_i])) + best_i = j; + } + tmp = array[i]; array[i] = array[best_i]; array[best_i] = tmp; + } +} +template <class T> static inline void selectionSort(T* array, int size) { + selectionSort(array, size, LessThan_default<T>()); } + + +template <class T, class LessThan> +void sort(T* array, int size, LessThan lt, double& seed) +{ + if (size <= 15) + selectionSort(array, size, lt); + + else{ + T pivot = array[irand(seed, size)]; + T tmp; + int i = -1; + int j = size; + + for(;;){ + do i++; while(lt(array[i], pivot)); + do j--; while(lt(pivot, array[j])); + + if (i >= j) break; + + tmp = array[i]; array[i] = array[j]; array[j] = tmp; + } + + sort(array , i , lt, seed); + sort(&array[i], size-i, lt, seed); + } +} +template <class T, class LessThan> void sort(T* array, int size, LessThan lt) { + double seed = 91648253; sort(array, size, lt, seed); } +template <class T> static inline void sort(T* array, int size) { + sort(array, size, LessThan_default<T>()); } + + +template <class T, class LessThan> +void sortUnique(T* array, int& size, LessThan lt) +{ + int i, j; + T last; + + if (size == 0) return; + + sort(array, size, lt); + + i = 1; + last = array[0]; + for (j = 1; j < size; j++){ + if (lt(last, array[j])){ + last = array[i] = array[j]; + i++; } + } + + size = i; +} +template <class T> static inline void sortUnique(T* array, int& size) { + sortUnique(array, size, LessThan_default<T>()); } + + +//================================================================================================= +// For 'vec's: + + +template <class T, class LessThan> void sort(vec<T>& v, LessThan lt) { + sort((T*)v, v.size(), lt); } +template <class T> void sort(vec<T>& v) { + sort(v, LessThan_default<T>()); } + + +template <class T, class LessThan> void sortUnique(vec<T>& v, LessThan lt) { + int size = v.size(); + T* data = v.release(); + sortUnique(data, size, lt); + v.~vec<T>(); + new (&v) vec<T>(data, size); } +template <class T> void sortUnique(vec<T>& v) { + sortUnique(v, LessThan_default<T>()); } + + +//================================================================================================= +}; +#endif diff --git a/stp/sat/VarOrder.h b/stp/sat/VarOrder.h new file mode 100644 index 00000000..6ad1bfb1 --- /dev/null +++ b/stp/sat/VarOrder.h @@ -0,0 +1,146 @@ +/**************************************************************************************[VarOrder.h] +MiniSat -- Copyright (c) 2003-2005, Niklas Een, Niklas Sorensson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT +OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +**************************************************************************************************/ + +#ifndef VarOrder_h +#define VarOrder_h + +#include "SolverTypes.h" +#include "Solver.h" +#include "Heap.h" +#include "../AST/ASTUtil.h" + +namespace MINISAT { + //================================================================================================= + + struct VarOrder_lt { + const vec<double>& activity; + bool operator () (Var x, Var y) { return activity[x] > activity[y]; } + VarOrder_lt(const vec<double>& act) : activity(act) { } + }; + + + enum { p_decisionvar = 0, p_polarity = 1, p_frozen = 2, p_dontcare = 3 }; + + + class VarOrder { + const vec<char>& assigns; // var->val. Pointer to external assignment table. + const vec<double>& activity; // var->act. Pointer to external activity table. + vec<char> properties; + //Heap<VarOrder_lt> heap; + //double random_seed; // For the internal random number generator + + friend class VarFilter; + public: + //FIXME: Vijay: delete after experiments + Heap<VarOrder_lt> heap; + double random_seed; // For the internal random number generator + //FIXME ENDS HERE + + VarOrder(const vec<char>& ass, const vec<double>& act) : + assigns(ass), activity(act), heap(VarOrder_lt(act)), random_seed(2007) + //assigns(ass), activity(act), heap(VarOrder_lt(act)) + { } + + int size () { return heap.size(); } + void setVarProp (Var v, uint prop, bool b) { properties[v] = (properties[v] & ~(1 << prop)) | (b << prop); } + bool hasVarProp (Var v, uint prop) const { return properties[v] & (1 << prop); } + inline void cleanup (); + + inline void newVar(bool polarity, bool dvar); + inline void update(Var x); // Called when variable increased in activity. + inline void undo(Var x); // Called when variable is unassigned and may be selected again. + //Selects a new, unassigned variable (or 'var_Undef' if none exists). + inline Lit select(double random_freq =.0, int decision_level = 0); + }; + + + struct VarFilter { + const VarOrder& o; + VarFilter(const VarOrder& _o) : o(_o) {} + bool operator()(Var v) const { return toLbool(o.assigns[v]) == l_Undef && o.hasVarProp(v, p_decisionvar); } + //bool operator()(Var v) const { return toLbool(o.assigns[v]) == l_Undef; } + }; + + void VarOrder::cleanup() + { + VarFilter f(*this); + heap.filter(f); + } + + void VarOrder::newVar(bool polarity, bool dvar) + { + Var v = assigns.size()-1; + heap.setBounds(v+1); + properties.push(0); + setVarProp(v, p_decisionvar, dvar); + setVarProp(v, p_polarity, polarity); + undo(v); + } + + + void VarOrder::update(Var x) + { + if (heap.inHeap(x)) + heap.increase(x); + } + + + void VarOrder::undo(Var x) + { + if (!heap.inHeap(x) && hasVarProp(x, p_decisionvar)) + heap.insert(x); + } + + + Lit VarOrder::select(double random_var_freq, int decision_level) + { + Var next = var_Undef; + + if (drand(random_seed) < random_var_freq && !heap.empty()) + next = irand(random_seed,assigns.size()); + + // Activity based decision: + while (next == var_Undef || toLbool(assigns[next]) != l_Undef || !hasVarProp(next, p_decisionvar)) + if (heap.empty()){ + next = var_Undef; + break; + }else + next = heap.getmin(); + + //printing + if(BEEV::print_sat_varorder) { + if (next != var_Undef) { + BEEV::Convert_MINISATVar_To_ASTNode_Print(next, + decision_level, + hasVarProp(next, p_polarity)); + // fprintf(stderr,"var = %d, prop = %d, decision = %d, polarity = %d, frozen = %d\n", + // next+1, properties[next], hasVarProp(next, p_decisionvar), + // hasVarProp(next, p_polarity), hasVarProp(next, p_frozen)); + } + else + fprintf(stderr, "var = undef\n"); + } + + return next == var_Undef ? lit_Undef : Lit(next, hasVarProp(next, p_polarity)); + } + + + //================================================================================================= +}; +#endif diff --git a/stp/simplifier/Makefile b/stp/simplifier/Makefile new file mode 100644 index 00000000..aba07e1b --- /dev/null +++ b/stp/simplifier/Makefile @@ -0,0 +1,11 @@ +include ../Makefile.common + +SRCS = simplifier.cpp bvsolver.cpp +OBJS = $(SRCS:.cpp=.o) + +libsimplifier.a: $(OBJS) + $(AR) rc $@ $^ + $(RANLIB) $@ + +clean: + rm -rf *.o *~ *.a .#* diff --git a/stp/simplifier/bvsolver.cpp b/stp/simplifier/bvsolver.cpp new file mode 100644 index 00000000..1c08f30b --- /dev/null +++ b/stp/simplifier/bvsolver.cpp @@ -0,0 +1,714 @@ +/******************************************************************** + * 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/AST.h" +#include "../AST/ASTUtil.h" +#include "bvsolver.h" + + //This file contains the implementation of member functions of + //bvsolver class, which represents the bitvector arithmetic linear + //solver. Please also refer the STP's CAV 2007 paper for the + //complete description of the linear solver algorithm + // + //The bitvector solver is a partial solver, i.e. it does not solve + //for all variables in the system of equations. it is + //best-effort. it relies on the SAT solver to be complete. + // + //The BVSolver assumes that the input equations are normalized, and + //have liketerms combined etc. + // + //0. Traverse top-down over the input DAG, looking for a conjunction + //0. of equations. if you find one, then for each equation in the + //0. conjunction, do the following steps. + // + //1. check for Linearity of the input equation + // + //2. Solve for a "chosen" variable. The variable should occur + //2. exactly once and must have an odd coeff. Refer STP's CAV 2007 + //2. paper for actual solving procedure + // + //4. Outside the solver, Substitute and Re-normalize the input DAG +namespace BEEV { + //check the solver map for 'key'. If key is present, then return the + //value by reference in the argument 'output' + bool BVSolver::CheckAlreadySolvedMap(const ASTNode& key, ASTNode& output) { + ASTNodeMap::iterator it; + if((it = FormulasAlreadySolvedMap.find(key)) != FormulasAlreadySolvedMap.end()) { + output = it->second; + return true; + } + return false; + } //CheckAlreadySolvedMap() + + void BVSolver::UpdateAlreadySolvedMap(const ASTNode& key, const ASTNode& value) { + FormulasAlreadySolvedMap[key] = value; + } //end of UpdateAlreadySolvedMap() + + //FIXME This is doing way more arithmetic than it needs to. + //accepts an even number "in", and splits it into an odd number and + //a power of 2. i.e " in = b.(2^k) ". returns the odd number, and + //the power of two by reference + ASTNode BVSolver::SplitEven_into_Oddnum_PowerOf2(const ASTNode& in, + unsigned int& number_shifts) { + if(BVCONST != in.GetKind() || _bm->BVConstIsOdd(in)) { + FatalError("BVSolver:SplitNum_Odd_PowerOf2: input must be a BVCONST and even\n",in); + } + + unsigned int len = in.GetValueWidth(); + ASTNode zero = _bm->CreateZeroConst(len); + ASTNode two = _bm->CreateTwoConst(len); + ASTNode div_by_2 = in; + ASTNode mod_by_2 = + _bm->BVConstEvaluator(_bm->CreateTerm(BVMOD,len,div_by_2,two)); + while(mod_by_2 == zero) { + div_by_2 = + _bm->BVConstEvaluator(_bm->CreateTerm(BVDIV,len,div_by_2,two)); + number_shifts++; + mod_by_2 = + _bm->BVConstEvaluator(_bm->CreateTerm(BVMOD,len,div_by_2,two)); + } + return div_by_2; + } //end of SplitEven_into_Oddnum_PowerOf2() + + //Checks if there are any ARRAYREADS in the term, after the + //alreadyseenmap is cleared, i.e. traversing a new term altogether + bool BVSolver::CheckForArrayReads_TopLevel(const ASTNode& term) { + TermsAlreadySeenMap.clear(); + return CheckForArrayReads(term); + } + + //Checks if there are any ARRAYREADS in the term + bool BVSolver::CheckForArrayReads(const ASTNode& term) { + ASTNode a = term; + ASTNodeMap::iterator it; + if((it = TermsAlreadySeenMap.find(term)) != TermsAlreadySeenMap.end()) { + //if the term has been seen, then simply return true, else + //return false + if(ASTTrue == (it->second)) { + return true; + } + else { + return false; + } + } + + switch(term.GetKind()) { + case READ: + //an array read has been seen. Make an entry in the map and + //return true + TermsAlreadySeenMap[term] = ASTTrue; + return true; + default: { + ASTVec c = term.GetChildren(); + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + if(CheckForArrayReads(*it)) { + return true; + } + } + break; + } + } + + //If control is here, then it means that no arrayread was seen for + //the input 'term'. Make an entry in the map with the term as key + //and FALSE as value. + TermsAlreadySeenMap[term] = ASTFalse; + return false; + } //end of CheckForArrayReads() + + //check the solver map for 'key'. If key is present, then return the + //value by reference in the argument 'output' + bool BeevMgr::CheckSolverMap(const ASTNode& key, ASTNode& output) { + ASTNodeMap::iterator it; + if((it = SolverMap.find(key)) != SolverMap.end()) { + output = it->second; + return true; + } + return false; + } //end of CheckSolverMap() + + bool BeevMgr::CheckSolverMap(const ASTNode& key) { + if(SolverMap.find(key) != SolverMap.end()) + return true; + else + return false; + } //end of CheckSolverMap() + + //update solvermap with (key,value) pair + bool BeevMgr::UpdateSolverMap(const ASTNode& key, const ASTNode& value) { + ASTNode var = (BVEXTRACT == key.GetKind()) ? key[0] : key; + if(!CheckSolverMap(var) && key != value) { + SolverMap[key] = value; + return true; + } + return false; + } //end of UpdateSolverMap() + + //collects the vars in the term 'lhs' into the multiset Vars + void BVSolver::VarsInTheTerm_TopLevel(const ASTNode& lhs, ASTNodeMultiSet& Vars) { + TermsAlreadySeenMap.clear(); + VarsInTheTerm(lhs,Vars); + } + + //collects the vars in the term 'lhs' into the multiset Vars + void BVSolver::VarsInTheTerm(const ASTNode& term, ASTNodeMultiSet& Vars) { + ASTNode a = term; + ASTNodeMap::iterator it; + if((it = TermsAlreadySeenMap.find(term)) != TermsAlreadySeenMap.end()) { + //if the term has been seen, then simply return + return; + } + + switch(term.GetKind()) { + case BVCONST: + return; + case SYMBOL: + //cerr << "debugging: symbol added: " << term << endl; + Vars.insert(term); + break; + case READ: + //skip the arrayname, provided the arrayname is a SYMBOL + if(SYMBOL == term[0].GetKind()) { + VarsInTheTerm(term[1],Vars); + } + else { + VarsInTheTerm(term[0],Vars); + VarsInTheTerm(term[1],Vars); + } + break; + default: { + ASTVec c = term.GetChildren(); + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + VarsInTheTerm(*it,Vars); + } + break; + } + } + + //ensures that you don't double count. if you have seen the term + //once, then memoize + TermsAlreadySeenMap[term] = ASTTrue; + return; + } //end of VarsInTheTerm() + + bool BVSolver::DoNotSolveThis(const ASTNode& var) { + if(DoNotSolve_TheseVars.find(var) != DoNotSolve_TheseVars.end()) { + return true; + } + return false; + } + + //chooses a variable in the lhs and returns the chosen variable + ASTNode BVSolver::ChooseMonom(const ASTNode& eq, ASTNode& modifiedlhs) { + if(!(EQ == eq.GetKind() && BVPLUS == eq[0].GetKind())) { + FatalError("ChooseMonom: input must be a EQ",eq); + } + + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + ASTNode zero = _bm->CreateZeroConst(32); + + //collect all the vars in the lhs and rhs + ASTNodeMultiSet Vars; + VarsInTheTerm_TopLevel(lhs,Vars); + + //handle BVPLUS case + ASTVec c = lhs.GetChildren(); + ASTVec o; + ASTNode outmonom = _bm->CreateNode(UNDEFINED); + bool chosen_symbol = false; + bool chosen_odd = false; + + //choose variables with no coeffs + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode monom = *it; + if(SYMBOL == monom.GetKind() && + Vars.count(monom) == 1 && + !_bm->VarSeenInTerm(monom,rhs) && + !DoNotSolveThis(monom) && + !chosen_symbol) { + outmonom = monom; + chosen_symbol = true; + } + else if(BVUMINUS == monom.GetKind() && + SYMBOL == monom[0].GetKind() && + Vars.count(monom[0]) == 1 && + !DoNotSolveThis(monom[0]) && + !_bm->VarSeenInTerm(monom[0],rhs) && + !chosen_symbol) { + //cerr << "Chosen Monom: " << monom << endl; + outmonom = monom; + chosen_symbol = true; + } + else { + o.push_back(monom); + } + } + + //try to choose only odd coeffed variables first + if(!chosen_symbol) { + o.clear(); + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode monom = *it; + ASTNode var = (BVMULT == monom.GetKind()) ? monom[1] : _bm->CreateNode(UNDEFINED); + + if(BVMULT == monom.GetKind() && + BVCONST == monom[0].GetKind() && + _bm->BVConstIsOdd(monom[0]) && + ((SYMBOL == var.GetKind() && + Vars.count(var) == 1) + || + (BVEXTRACT == var.GetKind() && + SYMBOL == var[0].GetKind() && + BVCONST == var[1].GetKind() && + zero == var[2] && + !_bm->VarSeenInTerm(var[0],rhs) && + !DoNotSolveThis(var[0])) + ) && + !DoNotSolveThis(var) && + !_bm->VarSeenInTerm(var,rhs) && + !chosen_odd) { + //monom[0] is odd. + outmonom = monom; + chosen_odd = true; + } + else { + o.push_back(monom); + } + } + } + + modifiedlhs = (o.size() > 1) ? _bm->CreateTerm(BVPLUS,lhs.GetValueWidth(),o) : o[0]; + return outmonom; + } //end of choosemonom() + + //solver function which solves for variables with odd coefficient + ASTNode BVSolver::BVSolve_Odd(const ASTNode& input) { + ASTNode eq = input; + //cerr << "Input to BVSolve_Odd()" << eq << endl; + if(!(wordlevel_solve && EQ == eq.GetKind())) { + return input; + } + + ASTNode output = input; + if(CheckAlreadySolvedMap(input,output)) { + return output; + } + + //get the lhs and the rhs, and case-split on the lhs kind + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + if(BVPLUS == lhs.GetKind()) { + ASTNode chosen_monom = _bm->CreateNode(UNDEFINED); + ASTNode leftover_lhs; + + //choose monom makes sure that it gets only those vars that + //occur exactly once in lhs and rhs put together + chosen_monom = ChooseMonom(eq, leftover_lhs); + if(chosen_monom == _bm->CreateNode(UNDEFINED)) { + //no monomial was chosen + return eq; + } + + //if control is here then it means that a monom was chosen + // + //construct: rhs - (lhs without the chosen monom) + unsigned int len = lhs.GetValueWidth(); + leftover_lhs = _bm->SimplifyTerm_TopLevel(_bm->CreateTerm(BVUMINUS,len,leftover_lhs)); + ASTNode newrhs = _bm->SimplifyTerm(_bm->CreateTerm(BVPLUS,len,rhs,leftover_lhs)); + lhs = chosen_monom; + rhs = newrhs; + } //end of if(BVPLUS ...) + + if(BVUMINUS == lhs.GetKind()) { + //equation is of the form (-lhs0) = rhs + ASTNode lhs0 = lhs[0]; + rhs = _bm->SimplifyTerm(_bm->CreateTerm(BVUMINUS,rhs.GetValueWidth(),rhs)); + lhs = lhs0; + } + + switch(lhs.GetKind()) { + case SYMBOL: { + //input is of the form x = rhs first make sure that the lhs + //symbol does not occur on the rhs or that it has not been + //solved for + if(_bm->VarSeenInTerm(lhs,rhs)) { + //found the lhs in the rhs. Abort! + DoNotSolve_TheseVars.insert(lhs); + return eq; + } + + //rhs should not have arrayreads in it. it complicates matters + //during transformation + // if(CheckForArrayReads_TopLevel(rhs)) { + // return eq; + // } + + DoNotSolve_TheseVars.insert(lhs); + if(!_bm->UpdateSolverMap(lhs,rhs)) { + return eq; + } + + output = ASTTrue; + break; + } + case BVEXTRACT: { + ASTNode zero = _bm->CreateZeroConst(32); + + if(!(SYMBOL == lhs[0].GetKind() && + BVCONST == lhs[1].GetKind() && + zero == lhs[2] && + !_bm->VarSeenInTerm(lhs[0],rhs) && + !DoNotSolveThis(lhs[0]))) { + return eq; + } + + if(_bm->VarSeenInTerm(lhs[0],rhs)) { + DoNotSolve_TheseVars.insert(lhs[0]); + return eq; + } + + DoNotSolve_TheseVars.insert(lhs[0]); + if(!_bm->UpdateSolverMap(lhs,rhs)) { + return eq; + } + + //if the extract of x[i:0] = t is entered into the solvermap, + //then also add another entry for x = x1@t + ASTNode var = lhs[0]; + ASTNode newvar = NewVar(var.GetValueWidth() - lhs.GetValueWidth()); + newvar = _bm->CreateTerm(BVCONCAT,var.GetValueWidth(),newvar,rhs); + _bm->UpdateSolverMap(var,newvar); + output = ASTTrue; + break; + } + case BVMULT: { + //the input is of the form a*x = t. If 'a' is odd, then compute + //its multiplicative inverse a^-1, multiply 't' with it, and + //update the solver map + if(BVCONST != lhs[0].GetKind()) { + return eq; + } + + if(!(SYMBOL == lhs[1].GetKind() || + (BVEXTRACT == lhs[1].GetKind() && + SYMBOL == lhs[1][0].GetKind()))) { + return eq; + } + + bool ChosenVar_Is_Extract = (BVEXTRACT == lhs[1].GetKind()) ? true : false; + + //if coeff is even, then we know that all the coeffs in the eqn + //are even. Simply return the eqn + if(!_bm->BVConstIsOdd(lhs[0])) { + return eq; + } + + ASTNode a = _bm->MultiplicativeInverse(lhs[0]); + ASTNode chosenvar = (BVEXTRACT == lhs[1].GetKind()) ? lhs[1][0] : lhs[1]; + ASTNode chosenvar_value = + _bm->SimplifyTerm(_bm->CreateTerm(BVMULT,rhs.GetValueWidth(),a,rhs)); + + //if chosenvar is seen in chosenvar_value then abort + if(_bm->VarSeenInTerm(chosenvar,chosenvar_value)) { + //abort solving + DoNotSolve_TheseVars.insert(lhs); + return eq; + } + + //rhs should not have arrayreads in it. it complicates matters + //during transformation + // if(CheckForArrayReads_TopLevel(chosenvar_value)) { + // return eq; + // } + + //found a variable to solve + DoNotSolve_TheseVars.insert(chosenvar); + chosenvar = lhs[1]; + if(!_bm->UpdateSolverMap(chosenvar,chosenvar_value)) { + return eq; + } + + if(ChosenVar_Is_Extract) { + ASTNode var = lhs[1][0]; + ASTNode newvar = NewVar(var.GetValueWidth() - lhs[1].GetValueWidth()); + newvar = _bm->CreateTerm(BVCONCAT,var.GetValueWidth(),newvar,chosenvar_value); + _bm->UpdateSolverMap(var,newvar); + } + output = ASTTrue; + break; + } + default: + output = eq; + break; + } + + UpdateAlreadySolvedMap(input,output); + return output; + } //end of BVSolve_Odd() + + //Create a new variable of ValueWidth 'n' + ASTNode BVSolver::NewVar(unsigned int n) { + std:: string c("v"); + char d[32]; + sprintf(d,"%d",_symbol_count++); + std::string ccc(d); + c += "_solver_" + ccc; + + ASTNode CurrentSymbol = _bm->CreateSymbol(c.c_str()); + CurrentSymbol.SetValueWidth(n); + CurrentSymbol.SetIndexWidth(0); + return CurrentSymbol; + } //end of NewVar() + + //The toplevel bvsolver(). Checks if the formula has already been + //solved. If not, the solver() is invoked. If yes, then simply drop + //the formula + ASTNode BVSolver::TopLevelBVSolve(const ASTNode& input) { + if(!wordlevel_solve) { + return input; + } + + Kind k = input.GetKind(); + if(!(EQ == k || AND == k)) { + return input; + } + + ASTNode output = input; + if(CheckAlreadySolvedMap(input,output)) { + //output is TRUE. The formula is thus dropped + return output; + } + ASTVec o; + ASTVec c; + if(EQ == k) + c.push_back(input); + else + c = input.GetChildren(); + ASTVec eveneqns; + ASTNode solved = ASTFalse; + for(ASTVec::iterator it = c.begin(), itend = c.end();it != itend;it++) { + //_bm->ASTNodeStats("Printing before calling simplifyformula inside the solver:", *it); + ASTNode aaa = (ASTTrue == solved && EQ == it->GetKind()) ? _bm->SimplifyFormula(*it,false) : *it; + //ASTNode aaa = *it; + //_bm->ASTNodeStats("Printing after calling simplifyformula inside the solver:", aaa); + aaa = BVSolve_Odd(aaa); + //_bm->ASTNodeStats("Printing after oddsolver:", aaa); + bool even = false; + aaa = CheckEvenEqn(aaa, even); + if(even) { + eveneqns.push_back(aaa); + } + else { + if(ASTTrue != aaa) { + o.push_back(aaa); + } + } + solved = aaa; + } + + ASTNode evens; + if(eveneqns.size() > 0) { + //if there is a system of even equations then solve them + evens = (eveneqns.size() > 1) ? _bm->CreateNode(AND,eveneqns) : eveneqns[0]; + //evens = _bm->SimplifyFormula(evens,false); + evens = BVSolve_Even(evens); + _bm->ASTNodeStats("Printing after evensolver:", evens); + } + else { + evens = ASTTrue; + } + output = (o.size() > 0) ? ((o.size() > 1) ? _bm->CreateNode(AND,o) : o[0]) : ASTTrue; + output = _bm->CreateNode(AND,output,evens); + + UpdateAlreadySolvedMap(input,output); + return output; + } //end of TopLevelBVSolve() + + ASTNode BVSolver::CheckEvenEqn(const ASTNode& input, bool& evenflag) { + ASTNode eq = input; + //cerr << "Input to BVSolve_Odd()" << eq << endl; + if(!(wordlevel_solve && EQ == eq.GetKind())) { + evenflag = false; + return eq; + } + + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth()); + //lhs must be a BVPLUS, and rhs must be a BVCONST + if(!(BVPLUS == lhs.GetKind() && zero == rhs)) { + evenflag = false; + return eq; + } + + ASTVec lhs_c = lhs.GetChildren(); + ASTNode savetheconst = rhs; + for(ASTVec::iterator it=lhs_c.begin(),itend=lhs_c.end();it!=itend;it++) { + ASTNode aaa = *it; + Kind itk = aaa.GetKind(); + + if(BVCONST == itk){ + //check later if the constant is even or not + savetheconst = aaa; + continue; + } + + if(!(BVMULT == itk && + BVCONST == aaa[0].GetKind() && + SYMBOL == aaa[1].GetKind() && + !_bm->BVConstIsOdd(aaa[0]))) { + //If the monomials of the lhs are NOT of the form 'a*x' where + //'a' is even, then return the false + evenflag = false; + return eq; + } + }//end of for loop + + //if control is here then it means that all coeffs are even. the + //only remaining thing is to check if the constant is even or not + if(_bm->BVConstIsOdd(savetheconst)) { + //the constant turned out to be odd. we have UNSAT eqn + evenflag = false; + return ASTFalse; + } + + //all is clear. the eqn in even, through and through + evenflag = true; + return eq; + } //end of CheckEvenEqn + + //solve an eqn whose monomials have only even coefficients + ASTNode BVSolver::BVSolve_Even(const ASTNode& input) { + if(!wordlevel_solve) { + return input; + } + + if(!(EQ == input.GetKind() || AND == input.GetKind())) { + return input; + } + + ASTNode output; + if(CheckAlreadySolvedMap(input,output)) { + return output; + } + + ASTVec input_c; + if(EQ == input.GetKind()) { + input_c.push_back(input); + } + else { + input_c = input.GetChildren(); + } + + //power_of_2 holds the exponent of 2 in the coeff + unsigned int power_of_2 = 0; + //we need this additional variable to find the lowest power of 2 + unsigned int power_of_2_lowest = 0xffffffff; + //the monom which has the least power of 2 in the coeff + ASTNode monom_with_best_coeff; + for(ASTVec::iterator jt=input_c.begin(),jtend=input_c.end();jt!=jtend;jt++) { + ASTNode eq = *jt; + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth()); + //lhs must be a BVPLUS, and rhs must be a BVCONST + if(!(BVPLUS == lhs.GetKind() && zero == rhs)) { + return input; + } + + ASTVec lhs_c = lhs.GetChildren(); + ASTNode odd; + for(ASTVec::iterator it=lhs_c.begin(),itend=lhs_c.end();it!=itend;it++) { + ASTNode aaa = *it; + Kind itk = aaa.GetKind(); + if(!(BVCONST == itk && + !_bm->BVConstIsOdd(aaa)) && + !(BVMULT == itk && + BVCONST == aaa[0].GetKind() && + SYMBOL == aaa[1].GetKind() && + !_bm->BVConstIsOdd(aaa[0]))) { + //If the monomials of the lhs are NOT of the form 'a*x' or 'a' + //where 'a' is even, then return the eqn + return input; + } + + //we are gauranteed that if control is here then the monomial is + //of the form 'a*x' or 'a', where 'a' is even + ASTNode coeff = (BVCONST == itk) ? aaa : aaa[0]; + odd = SplitEven_into_Oddnum_PowerOf2(coeff,power_of_2); + if(power_of_2 < power_of_2_lowest) { + power_of_2_lowest = power_of_2; + monom_with_best_coeff = aaa; + } + power_of_2 = 0; + }//end of inner for loop + } //end of outer for loop + + //get the exponent + power_of_2 = power_of_2_lowest; + + //if control is here, we are gauranteed that we have chosen a + //monomial with fewest powers of 2 + ASTVec formula_out; + for(ASTVec::iterator jt=input_c.begin(),jtend=input_c.end();jt!=jtend;jt++) { + ASTNode eq = *jt; + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth()); + //lhs must be a BVPLUS, and rhs must be a BVCONST + if(!(BVPLUS == lhs.GetKind() && zero == rhs)) { + return input; + } + + unsigned len = lhs.GetValueWidth(); + ASTNode hi = _bm->CreateBVConst(32,len-1); + ASTNode low = _bm->CreateBVConst(32,len - power_of_2); + ASTNode low_minus_one = _bm->CreateBVConst(32,len - power_of_2 - 1); + ASTNode low_zero = _bm->CreateZeroConst(32); + unsigned newlen = len - power_of_2; + ASTNode two_const = _bm->CreateTwoConst(len); + + unsigned count = power_of_2; + ASTNode two = two_const; + while(--count) { + two = _bm->BVConstEvaluator(_bm->CreateTerm(BVMULT,len,two_const,two)); + } + ASTVec lhs_c = lhs.GetChildren(); + ASTVec lhs_out; + for(ASTVec::iterator it=lhs_c.begin(),itend=lhs_c.end();it!=itend;it++) { + ASTNode aaa = *it; + Kind itk = aaa.GetKind(); + if(BVCONST == itk) { + aaa = _bm->BVConstEvaluator(_bm->CreateTerm(BVDIV,len,aaa,two)); + aaa = _bm->BVConstEvaluator(_bm->CreateTerm(BVEXTRACT,newlen,aaa,low_minus_one,low_zero)); + } + else { + //it must be of the form a*x + ASTNode coeff = _bm->BVConstEvaluator(_bm->CreateTerm(BVDIV,len,aaa[0],two)); + coeff = _bm->BVConstEvaluator(_bm->CreateTerm(BVEXTRACT,newlen,coeff,low_minus_one,low_zero)); + ASTNode upper_x, lower_x; + //upper_x = _bm->SimplifyTerm(_bm->CreateTerm(BVEXTRACT, power_of_2, aaa[1], hi, low)); + lower_x = _bm->SimplifyTerm(_bm->CreateTerm(BVEXTRACT, newlen,aaa[1],low_minus_one,low_zero)); + aaa = _bm->CreateTerm(BVMULT,newlen,coeff,lower_x); + } + lhs_out.push_back(aaa); + }//end of inner forloop() + rhs = _bm->CreateZeroConst(newlen); + lhs = _bm->CreateTerm(BVPLUS,newlen,lhs_out); + formula_out.push_back(_bm->CreateSimplifiedEQ(lhs,rhs)); + } //end of outer forloop() + + output = + (formula_out.size() > 0) ? (formula_out.size() > 1) ? _bm->CreateNode(AND,formula_out) : formula_out[0] : ASTTrue; + + UpdateAlreadySolvedMap(input,output); + return output; + } //end of BVSolve_Even() +};//end of namespace BEEV diff --git a/stp/simplifier/bvsolver.h b/stp/simplifier/bvsolver.h new file mode 100644 index 00000000..a8981b12 --- /dev/null +++ b/stp/simplifier/bvsolver.h @@ -0,0 +1,134 @@ +/******************************************************************** + * 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/AST.h" +#include "../AST/ASTUtil.h" +namespace BEEV { + + //This class represents the bitvector arithmetic linear solver. + // + //The bitvector solver is a partial solver, i.e. it does not solve + //for all variables in the system of equations. it is + //best-effort. it relies on the SAT solver to be complete. + // + //The BVSolver assumes that the input equations are normalized, and + //have liketerms combined etc. + // + //0. Traverse top-down over the input DAG, looking for a conjunction + //0. of equations. if you find one, then for each equation in the + //0. conjunction, do the following steps. + // + //1. check for Linearity of the input equation + // + //2. Solve for a "chosen" variable. The variable should occur + //2. exactly once and must have an odd coeff. Refer STP's CAV 2007 + //2. paper for actual solving procedure + // + //4. Outside the solver, Substitute and Re-normalize the input DAG + class BVSolver { + //Ptr to toplevel manager that manages bit-vector expressions + //(i.e. construct various kinds of expressions), and also has + //member functions that simplify bit-vector expressions + BeevMgr * _bm; + ASTNode ASTTrue, ASTFalse; + + //Those formulas which have already been solved. If the same + //formula occurs twice then do not solve the second occurence, and + //instead drop it + ASTNodeMap FormulasAlreadySolvedMap; + + //this map is useful while traversing terms and uniquely + //identifying variables in the those terms. Prevents double + //counting. + ASTNodeMap TermsAlreadySeenMap; + ASTNodeMap TermsAlreadySeenMap_ForArrays; + + //count is used in the creation of new variables + unsigned int _symbol_count; + + //solved variables list: If a variable has been solved for then do + //not solve for it again + ASTNodeSet DoNotSolve_TheseVars; + + //checks if var has been solved for or not. if yes, then return + //true else return false + bool DoNotSolveThis(const ASTNode& var); + + //traverses a term, and creates a multiset of all variables in the + //term. Does memoization to avoid double counting. + void VarsInTheTerm(const ASTNode& lhs, ASTNodeMultiSet& v); + void VarsInTheTerm_TopLevel(const ASTNode& lhs, ASTNodeMultiSet& v); + + //choose a suitable var from the term + ASTNode ChooseMonom(const ASTNode& eq, ASTNode& modifiedterm); + //accepts an equation and solves for a variable or a monom in it + ASTNode BVSolve_Odd(const ASTNode& eq); + + //solves equations of the form a*x=t where 'a' is even. Has a + //return value, unlike the normal BVSolve() + ASTNode BVSolve_Even(const ASTNode& eq); + ASTNode CheckEvenEqn(const ASTNode& input, bool& evenflag); + + //Checks for arrayreads in a term. if yes then returns true, else + //return false + bool CheckForArrayReads(const ASTNode& term); + bool CheckForArrayReads_TopLevel(const ASTNode& term); + + //Creates new variables used in solving + ASTNode NewVar(unsigned int n); + + //this function return true if the var occurs in term, else the + //function returns false + bool VarSeenInTerm(const ASTNode& var, const ASTNode& term); + + //takes an even number "in" as input, and returns an odd number + //(return value) and a power of 2 (as number_shifts by reference), + //such that in = (odd_number * power_of_2). + // + //Refer STP's CAV 2007 (or Clark Barrett's 1998 paper on + //bit-vector arithmetic published in DAC 1998) paper for precise + //understanding of the algorithm + ASTNode SplitEven_into_Oddnum_PowerOf2(const ASTNode& in, unsigned int& number_shifts); + + //Once a formula has been solved, then update the alreadysolvedmap + //with the formula, and the solved value. The solved value can be + //described using the following example: Suppose input to the + //solver is + // + // input key: x = 2 AND y = x + t + // + // output value: y = 2 + t + void UpdateAlreadySolvedMap(const ASTNode& key, const ASTNode& value); + + //This function checks if the key (formula) has already been + //solved for. + // + //If yes it returns TRUE and fills the "output" with the + //solved-value (call by reference argument), + // + //else returns FALSE + bool CheckAlreadySolvedMap(const ASTNode& key, ASTNode& output); + public: + //constructor + BVSolver(BeevMgr * bm) : _bm(bm), _symbol_count(0) { + ASTTrue = _bm->CreateNode(TRUE); + ASTFalse = _bm->CreateNode(FALSE); + }; + + //Destructor + ~BVSolver() { + TermsAlreadySeenMap.clear(); + DoNotSolve_TheseVars.clear(); + } + + //Top Level Solver: Goes over the input DAG, identifies the + //equation to be solved, solves them, + ASTNode TopLevelBVSolve(const ASTNode& a); + }; //end of class bvsolver +};//end of namespace BEEV diff --git a/stp/simplifier/simplifier.cpp b/stp/simplifier/simplifier.cpp new file mode 100644 index 00000000..2a627398 --- /dev/null +++ b/stp/simplifier/simplifier.cpp @@ -0,0 +1,2495 @@ +/******************************************************************** + * 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/AST.h" +#include "../AST/ASTUtil.h" +namespace BEEV { + + bool BeevMgr::CheckSimplifyMap(const ASTNode& key, + ASTNode& output, bool pushNeg) { + ASTNodeMap::iterator it, itend; + it = pushNeg ? SimplifyNegMap.find(key) : SimplifyMap.find(key); + itend = pushNeg ? SimplifyNegMap.end() : SimplifyMap.end(); + + if(it != itend) { + output = it->second; + CountersAndStats("Successful_CheckSimplifyMap"); + return true; + } + + if(pushNeg && (it = SimplifyMap.find(key)) != SimplifyMap.end()) { + output = + (ASTFalse == it->second) ? + ASTTrue : + (ASTTrue == it->second) ? ASTFalse : CreateNode(NOT, it->second); + CountersAndStats("2nd_Successful_CheckSimplifyMap"); + return true; + } + + return false; + } + + void BeevMgr::UpdateSimplifyMap(const ASTNode& key, const ASTNode& value, bool pushNeg) { + if(pushNeg) + SimplifyNegMap[key] = value; + else + SimplifyMap[key] = value; + } + + bool BeevMgr::CheckSubstitutionMap(const ASTNode& key, ASTNode& output) { + ASTNodeMap::iterator it; + if((it = SolverMap.find(key)) != SolverMap.end()) { + output = it->second; + return true; + } + return false; + } + + bool BeevMgr::CheckSubstitutionMap(const ASTNode& key) { + if(SolverMap.find(key) != SolverMap.end()) + return true; + else + return false; + } + + bool BeevMgr::UpdateSubstitutionMap(const ASTNode& e0, const ASTNode& e1) { + int i = TermOrder(e0,e1); + if(0 == i) + return false; + + //e0 is of the form READ(Arr,const), and e1 is const, or + //e0 is of the form var, and e1 is const + if(1 == i && !CheckSubstitutionMap(e0)) { + SolverMap[e0] = e1; + return true; + } + + //e1 is of the form READ(Arr,const), and e0 is const, or + //e1 is of the form var, and e0 is const + if (-1 == i && !CheckSubstitutionMap(e1)) { + SolverMap[e1] = e0; + return true; + } + + return false; + } + + bool BeevMgr::CheckMultInverseMap(const ASTNode& key, ASTNode& output) { + ASTNodeMap::iterator it; + if((it = MultInverseMap.find(key)) != MultInverseMap.end()) { + output = it->second; + return true; + } + return false; + } + + void BeevMgr::UpdateMultInverseMap(const ASTNode& key, const ASTNode& value) { + MultInverseMap[key] = value; + } + + + bool BeevMgr::CheckAlwaysTrueFormMap(const ASTNode& key) { + ASTNodeSet::iterator it = AlwaysTrueFormMap.find(key); + ASTNodeSet::iterator itend = AlwaysTrueFormMap.end(); + + if(it != itend) { + //cerr << "found:" << *it << endl; + CountersAndStats("Successful_CheckAlwaysTrueFormMap"); + return true; + } + + return false; + } + + void BeevMgr::UpdateAlwaysTrueFormMap(const ASTNode& key) { + AlwaysTrueFormMap.insert(key); + } + + //if a is READ(Arr,const) or SYMBOL, and b is BVCONST then return 1 + //if b is READ(Arr,const) or SYMBOL, and a is BVCONST then return -1 + // + //else return 0 by default + int BeevMgr::TermOrder(const ASTNode& a, const ASTNode& b) { + Kind k1 = a.GetKind(); + Kind k2 = b.GetKind(); + + //a is of the form READ(Arr,const), and b is const, or + //a is of the form var, and b is const + if((k1 == READ + && + a[0].GetKind() == SYMBOL && + a[1].GetKind() == BVCONST + ) + && + (k2 == BVCONST) + ) + return 1; + + if(k1 == SYMBOL) + return 1; + + //b is of the form READ(Arr,const), and a is const, or + //b is of the form var, and a is const + if((k1 == BVCONST) + && + ((k2 == READ + && + b[0].GetKind() == SYMBOL && + b[1].GetKind() == BVCONST + ) + || + k2 == SYMBOL + )) + return -1; + return 0; + } + + //This function records all the const-indices seen so far for each + //array. It populates the map '_arrayname_readindices' whose key is + //the arrayname, and vlaue is a vector of read-indices. + // + //fill the arrayname_readindices vector if e0 is a READ(Arr,index) + //and index is a BVCONST. + // + //Since these arrayreads are being nuked and recorded in the + //substitutionmap, we have to also record the fact that each + //arrayread (e0 is of the form READ(Arr,const) here is represented + //by a BVCONST (e1). This is necessary for later Leibnitz Axiom + //generation + void BeevMgr::FillUp_ArrReadIndex_Vec(const ASTNode& e0, const ASTNode& e1) { + int i = TermOrder(e0,e1); + if(0 == i) return; + + if(1 == i && e0.GetKind() != SYMBOL && !CheckSubstitutionMap(e0)) { + _arrayname_readindices[e0[0]].push_back(e0[1]); + //e0 is the array read : READ(A,i) and e1 is a bvconst + _arrayread_symbol[e0] = e1; + return; + } + if(-1 == i && e1.GetKind() != SYMBOL && !CheckSubstitutionMap(e1)) { + _arrayname_readindices[e1[0]].push_back(e1[1]); + //e0 is the array read : READ(A,i) and e1 is a bvconst + _arrayread_symbol[e1] = e0; + return; + } + } + + ASTNode BeevMgr::SimplifyFormula_NoRemoveWrites(const ASTNode& b, bool pushNeg) { + Begin_RemoveWrites = false; + ASTNode out = SimplifyFormula(b,pushNeg); + return out; + } + + ASTNode BeevMgr::SimplifyFormula_TopLevel(const ASTNode& b, bool pushNeg) { + SimplifyMap.clear(); + SimplifyNegMap.clear(); + ASTNode out = SimplifyFormula(b,pushNeg); + SimplifyMap.clear(); + SimplifyNegMap.clear(); + return out; + } + + ASTNode BeevMgr::SimplifyFormula(const ASTNode& b, bool pushNeg){ + if(!optimize) + return b; + + Kind kind = b.GetKind(); + if(BOOLEAN_TYPE != b.GetType()) { + FatalError(" SimplifyFormula: You have input a nonformula kind: ",ASTUndefined,kind); + } + + ASTNode a = b; + ASTVec ca = a.GetChildren(); + if(!(IMPLIES == kind || + ITE == kind || + isAtomic(kind))) { + SortByExprNum(ca); + a = CreateNode(kind,ca); + } + + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + switch(kind){ + case AND: + case OR: + output = SimplifyAndOrFormula(a,pushNeg); + break; + case NOT: + output = SimplifyNotFormula(a,pushNeg); + break; + case XOR: + output = SimplifyXorFormula(a,pushNeg); + break; + case NAND: + output = SimplifyNandFormula(a,pushNeg); + break; + case NOR: + output = SimplifyNorFormula(a,pushNeg); + break; + case IFF: + output = SimplifyIffFormula(a,pushNeg); + break; + case IMPLIES: + output = SimplifyImpliesFormula(a,pushNeg); + break; + case ITE: + output = SimplifyIteFormula(a,pushNeg); + break; + default: + //kind can be EQ,NEQ,BVLT,BVLE,... or a propositional variable + output = SimplifyAtomicFormula(a,pushNeg); + //output = pushNeg ? CreateNode(NOT,a) : a; + break; + } + + //memoize + UpdateSimplifyMap(a,output, pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyAtomicFormula(const ASTNode& a, bool pushNeg) { + if(!optimize) { + return a; + } + + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) { + return output; + } + + ASTNode left,right; + if(a.Degree() == 2) { + //cerr << "Input to simplifyterm: left: " << a[0] << endl; + left = SimplifyTerm(a[0]); + //cerr << "Output of simplifyterm:left: " << left << endl; + //cerr << "Input to simplifyterm: right: " << a[1] << endl; + right = SimplifyTerm(a[1]); + //cerr << "Output of simplifyterm:left: " << right << endl; + } + + Kind kind = a.GetKind(); + switch(kind) { + case TRUE: + output = pushNeg ? ASTFalse : ASTTrue; + break; + case FALSE: + output = pushNeg ? ASTTrue : ASTFalse; + break; + case SYMBOL: + if(!CheckSolverMap(a,output)) { + output = a; + } + output = pushNeg ? CreateNode(NOT,output) : output; + break; + case BVGETBIT: { + ASTNode term = SimplifyTerm(a[0]); + ASTNode thebit = a[1]; + ASTNode zero = CreateZeroConst(1); + ASTNode one = CreateOneConst(1); + ASTNode getthebit = SimplifyTerm(CreateTerm(BVEXTRACT,1,term,thebit,thebit)); + if(getthebit == zero) + output = pushNeg ? ASTTrue : ASTFalse; + else if(getthebit == one) + output = pushNeg ? ASTFalse : ASTTrue; + else { + output = CreateNode(BVGETBIT,term,thebit); + output = pushNeg ? CreateNode(NOT,output) : output; + } + break; + } + case EQ:{ + output = CreateSimplifiedEQ(left,right); + output = LhsMinusRhs(output); + output = ITEOpt_InEqs(output); + if(output == ASTTrue) + output = pushNeg ? ASTFalse : ASTTrue; + else if (output == ASTFalse) + output = pushNeg ? ASTTrue : ASTFalse; + else + output = pushNeg ? CreateNode(NOT,output) : output; + break; + } + case NEQ: { + output = CreateSimplifiedEQ(left,right); + output = LhsMinusRhs(output); + if(output == ASTTrue) + output = pushNeg ? ASTTrue : ASTFalse; + else if (output == ASTFalse) + output = pushNeg ? ASTFalse : ASTTrue; + else + output = pushNeg ? output : CreateNode(NOT,output); + break; + } + case BVLT: + case BVLE: + case BVGT: + case BVGE: + case BVSLT: + case BVSLE: + case BVSGT: + case BVSGE: { + //output = CreateNode(kind,left,right); + //output = pushNeg ? CreateNode(NOT,output) : output; + output = CreateSimplifiedINEQ(kind,left,right,pushNeg); + break; + } + default: + FatalError("SimplifyAtomicFormula: NO atomic formula of the kind: ",ASTUndefined,kind); + break; + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } //end of SimplifyAtomicFormula() + + ASTNode BeevMgr::CreateSimplifiedINEQ(Kind k, + const ASTNode& left, + const ASTNode& right, + bool pushNeg) { + ASTNode output; + if(BVCONST == left.GetKind() && BVCONST == right.GetKind()) { + output = BVConstEvaluator(CreateNode(k,left,right)); + output = pushNeg ? (ASTFalse == output) ? ASTTrue : ASTFalse : output; + return output; + } + + unsigned len = left.GetValueWidth(); + ASTNode zero = CreateZeroConst(len); + ASTNode one = CreateOneConst(len); + ASTNode max = CreateMaxConst(len); + switch(k){ + case BVLT: + if(right == zero) { + output = pushNeg ? ASTTrue : ASTFalse; + } + else if(left == right) { + output = pushNeg ? ASTTrue : ASTFalse; + } + else if(one == right) { + output = CreateSimplifiedEQ(left,zero); + output = pushNeg ? CreateNode(NOT,output) : output; + } + else { + output = pushNeg ? CreateNode(BVLE,right,left) : CreateNode(BVLT,left,right); + } + break; + case BVLE: + if(left == zero) { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if(left == right) { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if(max == right) { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if(zero == right) { + output = CreateSimplifiedEQ(left,zero); + output = pushNeg ? CreateNode(NOT,output) : output; + } + else { + output = pushNeg ? CreateNode(BVLT,right,left) : CreateNode(BVLE,left,right); + } + break; + case BVGT: + if(left == zero) { + output = pushNeg ? ASTTrue : ASTFalse; + } + else if(left == right) { + output = pushNeg ? ASTTrue : ASTFalse; + } + else { + output = pushNeg ? CreateNode(BVLE,left,right) : CreateNode(BVLT,right,left); + } + break; + case BVGE: + if(right == zero) { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if(left == right) { + output = pushNeg ? ASTFalse : ASTTrue; + } + else { + output = pushNeg ? CreateNode(BVLT,left,right) : CreateNode(BVLE,right,left); + } + break; + case BVSLT: + case BVSLE: + case BVSGE: + case BVSGT: { + output = CreateNode(k,left,right); + output = pushNeg ? CreateNode(NOT,output) : output; + } + break; + default: + FatalError("Wrong Kind"); + break; + } + + return output; + } + + //takes care of some simple ITE Optimizations in the context of equations + ASTNode BeevMgr::ITEOpt_InEqs(const ASTNode& in) { + CountersAndStats("ITEOpts_InEqs"); + + if(!(EQ == in.GetKind() && optimize)) { + return in; + } + + ASTNode output; + if(CheckSimplifyMap(in,output,false)) { + return output; + } + + ASTNode in1 = in[0]; + ASTNode in2 = in[1]; + Kind k1 = in1.GetKind(); + Kind k2 = in2.GetKind(); + if(in1 == in2) { + //terms are syntactically the same + output = ASTTrue; + } + else if(BVCONST == k1 && BVCONST == k2) { + //here the terms are definitely not syntactically equal but may + //be semantically equal. + output = ASTFalse; + } + else if(ITE == k1 && + BVCONST == in1[1].GetKind() && + BVCONST == in1[2].GetKind() && BVCONST == k2) { + //if one side is a BVCONST and the other side is an ITE over + //BVCONST then we can do the following optimization: + // + // c = ITE(cond,c,d) <=> cond + // + // similarly ITE(cond,c,d) = c <=> cond + // + // c = ITE(cond,d,c) <=> NOT(cond) + // + //similarly ITE(cond,d,c) = d <=> NOT(cond) + ASTNode cond = in1[0]; + if(in1[1] == in2) { + //ITE(cond, c, d) = c <=> cond + output = cond; + } + else if(in1[2] == in2) { + cond = SimplifyFormula(cond,true); + output = cond; + } + else { + //last resort is to CreateNode + output = CreateNode(EQ,in1,in2); + } + } + else if(ITE == k2 && + BVCONST == in2[1].GetKind() && + BVCONST == in2[2].GetKind() && BVCONST == k1) { + ASTNode cond = in2[0]; + if(in2[1] == in1) { + //ITE(cond, c, d) = c <=> cond + output = cond; + } + else if(in2[2] == in1) { + cond = SimplifyFormula(cond,true); + output = cond; + } + else { + //last resort is to CreateNode + output = CreateNode(EQ,in1,in2); + } + } + else { + //last resort is to CreateNode + output = CreateNode(EQ,in1,in2); + } + + UpdateSimplifyMap(in,output,false); + return output; + } //End of ITEOpts_InEqs() + + //Tries to simplify the input to TRUE/FALSE. if it fails, then + //return the constructed equality + ASTNode BeevMgr::CreateSimplifiedEQ(const ASTNode& in1, const ASTNode& in2) { + CountersAndStats("CreateSimplifiedEQ"); + Kind k1 = in1.GetKind(); + Kind k2 = in2.GetKind(); + + if(!optimize) { + return CreateNode(EQ,in1,in2); + } + + if(in1 == in2) + //terms are syntactically the same + return ASTTrue; + + //here the terms are definitely not syntactically equal but may be + //semantically equal. + if(BVCONST == k1 && BVCONST == k2) + return ASTFalse; + + //last resort is to CreateNode + return CreateNode(EQ,in1,in2); + } + + //accepts cond == t1, then part is t2, and else part is t3 + ASTNode BeevMgr::CreateSimplifiedTermITE(const ASTNode& in0, + const ASTNode& in1, const ASTNode& in2) { + ASTNode t0 = in0; + ASTNode t1 = in1; + ASTNode t2 = in2; + CountersAndStats("CreateSimplifiedITE"); + if(!optimize) { + if(t1.GetValueWidth() != t2.GetValueWidth()) { + cerr << "t2 is : = " << t2; + FatalError("CreateSimplifiedTermITE: the lengths of then and else branches don't match",t1); + } + if(t1.GetIndexWidth() != t2.GetIndexWidth()) { + cerr << "t2 is : = " << t2; + FatalError("CreateSimplifiedTermITE: the lengths of then and else branches don't match",t1); + } + return CreateTerm(ITE,t1.GetValueWidth(),t0,t1,t2); + } + + if(t0 == ASTTrue) + return t1; + if (t0 == ASTFalse) + return t2; + if(t1 == t2) + return t1; + if(CheckAlwaysTrueFormMap(t0)) { + return t1; + } + if(CheckAlwaysTrueFormMap(CreateNode(NOT,t0)) || + (NOT == t0.GetKind() && CheckAlwaysTrueFormMap(t0[0]))) { + return t2; + } + + return CreateTerm(ITE,t1.GetValueWidth(),t0,t1,t2); + } + + ASTNode BeevMgr::SimplifyAndOrFormula(const ASTNode& a, bool pushNeg) { + ASTNode output; + //cerr << "input:\n" << a << endl; + + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + ASTVec c, outvec; + c = a.GetChildren(); + ASTNode flat = FlattenOneLevel(a); + c = flat.GetChildren(); + SortByExprNum(c); + + Kind k = a.GetKind(); + bool isAnd = (k == AND) ? true : false; + + ASTNode annihilator = isAnd ? + (pushNeg ? ASTTrue : ASTFalse): + (pushNeg ? ASTFalse : ASTTrue); + + ASTNode identity = isAnd ? + (pushNeg ? ASTFalse : ASTTrue): + (pushNeg ? ASTTrue : ASTFalse); + + //do the work + ASTVec::const_iterator next_it; + for(ASTVec::const_iterator i=c.begin(),iend=c.end();i!=iend;i++) { + ASTNode aaa = *i; + next_it = i+1; + bool nextexists = (next_it < iend); + + aaa = SimplifyFormula(aaa,pushNeg); + if(annihilator == aaa) { + //memoize + UpdateSimplifyMap(*i,annihilator,pushNeg); + UpdateSimplifyMap(a, annihilator,pushNeg); + //cerr << "annihilator1: output:\n" << annihilator << endl; + return annihilator; + } + ASTNode bbb = ASTFalse; + if(nextexists) { + bbb = SimplifyFormula(*next_it,pushNeg); + } + if(nextexists && bbb == aaa) { + //skip the duplicate aaa. *next_it will be included + } + else if(nextexists && + ((bbb.GetKind() == NOT && bbb[0] == aaa))) { + //memoize + UpdateSimplifyMap(a, annihilator,pushNeg); + //cerr << "annihilator2: output:\n" << annihilator << endl; + return annihilator; + } + else if(identity == aaa) { + // //drop identites + } + else if((!isAnd && !pushNeg) || + (isAnd && pushNeg)) { + outvec.push_back(aaa); + } + else if((isAnd && !pushNeg) || + (!isAnd && pushNeg)) { + outvec.push_back(aaa); + } + else { + outvec.push_back(aaa); + } + } + + switch(outvec.size()) { + case 0: { + //only identities were dropped + output = identity; + break; + } + case 1: { + output = SimplifyFormula(outvec[0],false); + break; + } + default: { + output = (isAnd) ? + (pushNeg ? CreateNode(OR,outvec) : CreateNode(AND,outvec)): + (pushNeg ? CreateNode(AND,outvec) : CreateNode(OR,outvec)); + //output = FlattenOneLevel(output); + break; + } + } + //memoize + UpdateSimplifyMap(a,output,pushNeg); + //cerr << "output:\n" << output << endl; + return output; + } //end of SimplifyAndOrFormula + + + ASTNode BeevMgr::SimplifyNotFormula(const ASTNode& a, bool pushNeg) { + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + if(!(a.Degree() == 1 && NOT == a.GetKind())) + FatalError("SimplifyNotFormula: input vector with more than 1 node",ASTUndefined); + + //if pushNeg is set then there is NOT on top + unsigned int NotCount = pushNeg ? 1 : 0; + ASTNode o = a; + //count the number of NOTs in 'a' + while(NOT == o.GetKind()) { + o = o[0]; + NotCount++; + } + + //pushnegation if there are odd number of NOTs + bool pn = (NotCount % 2 == 0) ? false : true; + + if(CheckAlwaysTrueFormMap(o)) { + output = pn ? ASTFalse : ASTTrue; + return output; + } + + if(CheckSimplifyMap(o,output,pn)) { + return output; + } + + if (ASTTrue == o) { + output = pn ? ASTFalse : ASTTrue; + } + else if (ASTFalse == o) { + output = pn ? ASTTrue : ASTFalse; + } + else { + output = SimplifyFormula(o,pn); + } + //memoize + UpdateSimplifyMap(o,output,pn); + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyXorFormula(const ASTNode& a, bool pushNeg) { + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + if (a.GetChildren().size() > 2) { + FatalError("Simplify got an XOR with more than two children."); + } + + ASTNode a0 = SimplifyFormula(a[0],false); + ASTNode a1 = SimplifyFormula(a[1],false); + output = pushNeg ? CreateNode(IFF,a0,a1) : CreateNode(XOR,a0,a1); + + if(XOR == output.GetKind()) { + a0 = output[0]; + a1 = output[1]; + if(a0 == a1) + output = ASTFalse; + else if((a0 == ASTTrue && a1 == ASTFalse) || + (a0 == ASTFalse && a1 == ASTTrue)) + output = ASTTrue; + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyNandFormula(const ASTNode& a, bool pushNeg) { + ASTNode output,a0,a1; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + //the two NOTs cancel out + if(pushNeg) { + a0 = SimplifyFormula(a[0],false); + a1 = SimplifyFormula(a[1],false); + output = CreateNode(AND,a0,a1); + } + else { + //push the NOT implicit in the NAND + a0 = SimplifyFormula(a[0],true); + a1 = SimplifyFormula(a[1],true); + output = CreateNode(OR,a0,a1); + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyNorFormula(const ASTNode& a, bool pushNeg) { + ASTNode output,a0,a1; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + //the two NOTs cancel out + if(pushNeg) { + a0 = SimplifyFormula(a[0],false); + a1 = SimplifyFormula(a[1],false); + output = CreateNode(OR,a0,a1); + } + else { + //push the NOT implicit in the NAND + a0 = SimplifyFormula(a[0],true); + a1 = SimplifyFormula(a[1],true); + output = CreateNode(AND,a0,a1); + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyImpliesFormula(const ASTNode& a, bool pushNeg) { + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + if(!(a.Degree()==2 && IMPLIES==a.GetKind())) + FatalError("SimplifyImpliesFormula: vector with wrong num of nodes",ASTUndefined); + + ASTNode c0,c1; + if(pushNeg) { + c0 = SimplifyFormula(a[0],false); + c1 = SimplifyFormula(a[1],true); + output = CreateNode(AND,c0,c1); + } + else { + c0 = SimplifyFormula(a[0],false); + c1 = SimplifyFormula(a[1],false); + if(ASTFalse == c0) { + output = ASTTrue; + } + else if (ASTTrue == c0) { + output = c1; + } + else if (c0 == c1) { + output = ASTTrue; + } + else if(CheckAlwaysTrueFormMap(c0)) { + // c0 AND (~c0 OR c1) <==> c1 + // + //applying modus ponens + output = c1; + } + else if(CheckAlwaysTrueFormMap(c1) || + CheckAlwaysTrueFormMap(CreateNode(NOT,c0)) || + (NOT == c0.GetKind() && CheckAlwaysTrueFormMap(c0[0]))) { + //(~c0 AND (~c0 OR c1)) <==> TRUE + // + //(c0 AND ~c0->c1) <==> TRUE + output = ASTTrue; + } + else if (CheckAlwaysTrueFormMap(CreateNode(NOT,c1)) || + (NOT == c1.GetKind() && CheckAlwaysTrueFormMap(c1[0]))) { + //(~c1 AND c0->c1) <==> (~c1 AND ~c1->~c0) <==> ~c0 + //(c1 AND c0->~c1) <==> (c1 AND c1->~c0) <==> ~c0 + output = CreateNode(NOT,c0); + } + else { + if(NOT == c0.GetKind()) { + output = CreateNode(OR,c0[0],c1); + } + else { + output = CreateNode(OR,CreateNode(NOT,c0),c1); + } + } + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyIffFormula(const ASTNode& a, bool pushNeg) { + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + if(!(a.Degree()==2 && IFF==a.GetKind())) + FatalError("SimplifyIffFormula: vector with wrong num of nodes",ASTUndefined); + + ASTNode c0 = a[0]; + ASTNode c1 = SimplifyFormula(a[1],false); + + if(pushNeg) + c0 = SimplifyFormula(c0,true); + else + c0 = SimplifyFormula(c0,false); + + if(ASTTrue == c0) { + output = c1; + } + else if (ASTFalse == c0) { + output = SimplifyFormula(c1,true); + } + else if (ASTTrue == c1) { + output = c0; + } + else if (ASTFalse == c1) { + output = SimplifyFormula(c0,true); + } + else if (c0 == c1) { + output = ASTTrue; + } + else if((NOT == c0.GetKind() && c0[0] == c1) || + (NOT == c1.GetKind() && c0 == c1[0])) { + output = ASTFalse; + } + else if(CheckAlwaysTrueFormMap(c0)) { + output = c1; + } + else if(CheckAlwaysTrueFormMap(c1)) { + output = c0; + } + else if(CheckAlwaysTrueFormMap(CreateNode(NOT,c0))) { + output = CreateNode(NOT,c1); + } + else if(CheckAlwaysTrueFormMap(CreateNode(NOT,c1))) { + output = CreateNode(NOT,c0); + } + else { + output = CreateNode(IFF,c0,c1); + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyIteFormula(const ASTNode& b, bool pushNeg) { + if(!optimize) + return b; + + ASTNode output; + if(CheckSimplifyMap(b,output,pushNeg)) + return output; + + if(!(b.Degree() == 3 && ITE == b.GetKind())) + FatalError("SimplifyIteFormula: vector with wrong num of nodes",ASTUndefined); + + ASTNode a = b; + ASTNode t0 = SimplifyFormula(a[0],false); + ASTNode t1,t2; + if(pushNeg) { + t1 = SimplifyFormula(a[1],true); + t2 = SimplifyFormula(a[2],true); + } + else { + t1 = SimplifyFormula(a[1],false); + t2 = SimplifyFormula(a[2],false); + } + + if(ASTTrue == t0) { + output = t1; + } + else if (ASTFalse == t0) { + output = t2; + } + else if (t1 == t2) { + output = t1; + } + else if(ASTTrue == t1 && ASTFalse == t2) { + output = t0; + } + else if(ASTFalse == t1 && ASTTrue == t2) { + output = SimplifyFormula(t0,true); + } + else if(ASTTrue == t1) { + output = CreateNode(OR,t0,t2); + } + else if(ASTFalse == t1) { + output = CreateNode(AND,CreateNode(NOT,t0),t2); + } + else if(ASTTrue == t2) { + output = CreateNode(OR,CreateNode(NOT,t0),t1); + } + else if(ASTFalse == t2) { + output = CreateNode(AND,t0,t1); + } + else if(CheckAlwaysTrueFormMap(t0)) { + output = t1; + } + else if(CheckAlwaysTrueFormMap(CreateNode(NOT,t0)) || + (NOT == t0.GetKind() && CheckAlwaysTrueFormMap(t0[0]))) { + output = t2; + } + else { + output = CreateNode(ITE,t0,t1,t2); + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + //one level deep flattening + ASTNode BeevMgr::FlattenOneLevel(const ASTNode& a) { + Kind k = a.GetKind(); + if(!(BVPLUS == k || + AND == k || OR == k + //|| BVAND == k + //|| BVOR == k + ) + ) { + return a; + } + + ASTNode output; + // if(CheckSimplifyMap(a,output,false)) { + // //check memo table + // //cerr << "output of SimplifyTerm Cache: " << output << endl; + // return output; + // } + + ASTVec c = a.GetChildren(); + ASTVec o; + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode aaa = *it; + if(k == aaa.GetKind()) { + ASTVec ac = aaa.GetChildren(); + o.insert(o.end(),ac.begin(),ac.end()); + } + else + o.push_back(aaa); + } + + if(is_Form_kind(k)) + output = CreateNode(k,o); + else + output = CreateTerm(k,a.GetValueWidth(),o); + + //UpdateSimplifyMap(a,output,false); + return output; + //memoize + } //end of flattenonelevel() + + ASTNode BeevMgr::SimplifyTerm_TopLevel(const ASTNode& b) { + SimplifyMap.clear(); + SimplifyNegMap.clear(); + ASTNode out = SimplifyTerm(b); + SimplifyNegMap.clear(); + SimplifyMap.clear(); + return out; + } + + //This function simplifies terms based on their kind + ASTNode BeevMgr::SimplifyTerm(const ASTNode& inputterm) { + //cout << "SimplifyTerm: input: " << a << endl; + if(!optimize) { + return inputterm; + } + + BVTypeCheck(inputterm); + ASTNode output; + if(wordlevel_solve && CheckSolverMap(inputterm,output)) { + //cout << "SimplifyTerm: output: " << output << endl; + return SimplifyTerm(output); + } + + if(CheckSimplifyMap(inputterm,output,false)) { + //cerr << "output of SimplifyTerm Cache: " << output << endl; + return output; + } + + Kind k = inputterm.GetKind(); + if(!is_Term_kind(k)) { + FatalError("SimplifyTerm: You have input a Non-term",ASTUndefined); + } + + unsigned int inputValueWidth = inputterm.GetValueWidth(); + switch(k) { + case BVCONST: + output = inputterm; + break; + case SYMBOL: + if(CheckSolverMap(inputterm,output)) { + return SimplifyTerm(output); + } + output = inputterm; + break; + case BVMULT: + case BVPLUS:{ + if(BVMULT == k && 2 != inputterm.Degree()) { + FatalError("SimplifyTerm: We assume that BVMULT is binary",inputterm); + } + + ASTVec c = FlattenOneLevel(inputterm).GetChildren(); + SortByExprNum(c); + ASTVec constkids, nonconstkids; + + //go through the childnodes, and separate constant and + //nonconstant nodes. combine the constant nodes using the + //constevaluator. if the resultant constant is zero and k == + //BVPLUS, then ignore it (similarily for 1 and BVMULT). else, + //add the computed constant to the nonconst vector, flatten, + //sort, and create BVPLUS/BVMULT and return + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode aaa = SimplifyTerm(*it); + if(BVCONST == aaa.GetKind()) { + constkids.push_back(aaa); + } + else { + nonconstkids.push_back(aaa); + } + } + + ASTNode one = CreateOneConst(inputValueWidth); + ASTNode max = CreateMaxConst(inputValueWidth); + ASTNode zero = CreateZeroConst(inputValueWidth); + + //initialize constoutput to zero, in case there are no elements + //in constkids + ASTNode constoutput = (k == BVPLUS) ? zero : one; + + if(1 == constkids.size()) { + //only one element in constkids + constoutput = constkids[0]; + } + else if (1 < constkids.size()) { + //many elements in constkids. simplify it + constoutput = CreateTerm(k,inputterm.GetValueWidth(),constkids); + constoutput = BVConstEvaluator(constoutput); + } + + if(BVMULT == k && zero == constoutput) { + output = zero; + } + else if(BVMULT == k && + 1 == nonconstkids.size() && + constoutput == max) { + //useful special case opt: when input is BVMULT(max_const,t), + //then output = BVUMINUS(t). this is easier on the bitblaster + output = CreateTerm(BVUMINUS,inputValueWidth,nonconstkids); + } + else { + if(0 < nonconstkids.size()) { + //nonconstkids is not empty. First, combine const and + //nonconstkids + if(BVPLUS == k && constoutput != zero) { + nonconstkids.push_back(constoutput); + } + else if(BVMULT == k && constoutput != one) { + nonconstkids.push_back(constoutput); + } + + if(1 == nonconstkids.size()) { + //exactly one element in nonconstkids. output is exactly + //nonconstkids[0] + output = nonconstkids[0]; + } + else { + //more than 1 element in nonconstkids. create BVPLUS term + SortByExprNum(nonconstkids); + output = CreateTerm(k,inputValueWidth,nonconstkids); + output = FlattenOneLevel(output); + output = DistributeMultOverPlus(output,true); + output = CombineLikeTerms(output); + } + } + else { + //nonconstkids was empty, all childnodes were constant, hence + //constoutput is the output. + output = constoutput; + } + } + if(BVMULT == output.GetKind() + || BVPLUS == output.GetKind() + ) { + ASTVec d = output.GetChildren(); + SortByExprNum(d); + output = CreateTerm(output.GetKind(),output.GetValueWidth(),d); + } + break; + } + case BVSUB: { + ASTVec c = inputterm.GetChildren(); + ASTNode a0 = SimplifyTerm(inputterm[0]); + ASTNode a1 = SimplifyTerm(inputterm[1]); + unsigned int l = inputValueWidth; + if(a0 == a1) + output = CreateZeroConst(l); + else { + //covert x-y into x+(-y) and simplify. this transformation + //triggers more simplifications + a1 = SimplifyTerm(CreateTerm(BVUMINUS,l,a1)); + output = SimplifyTerm(CreateTerm(BVPLUS,l,a0,a1)); + } + break; + } + case BVUMINUS: { + //important to treat BVUMINUS as a special case, because it + //helps in arithmetic transformations. e.g. x + BVUMINUS(x) is + //actually 0. One way to reveal this fact is to strip bvuminus + //out, and replace with something else so that combineliketerms + //can catch this fact. + ASTNode a0 = SimplifyTerm(inputterm[0]); + Kind k1 = a0.GetKind(); + unsigned int l = a0.GetValueWidth(); + ASTNode one = CreateOneConst(l); + switch(k1) { + case BVUMINUS: + output = a0[0]; + break; + case BVCONST: { + output = BVConstEvaluator(CreateTerm(BVUMINUS,l,a0)); + break; + } + case BVNEG: { + output = SimplifyTerm(CreateTerm(BVPLUS,l,a0[0],one)); + break; + } + case BVMULT: { + if(BVUMINUS == a0[0].GetKind()) { + output = CreateTerm(BVMULT,l,a0[0][0],a0[1]); + } + else if(BVUMINUS == a0[1].GetKind()) { + output = CreateTerm(BVMULT,l,a0[0],a0[1][0]); + } + else { + ASTNode a00 = SimplifyTerm(CreateTerm(BVUMINUS,l,a0[0])); + output = CreateTerm(BVMULT,l,a00,a0[1]); + } + break; + } + case BVPLUS: { + //push BVUMINUS over all the monomials of BVPLUS. Simplify + //along the way + // + //BVUMINUS(a1x1 + a2x2 + ...) <=> BVPLUS(BVUMINUS(a1x1) + + //BVUMINUS(a2x2) + ... + ASTVec c = a0.GetChildren(); + ASTVec o; + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + //Simplify(BVUMINUS(a1x1)) + ASTNode aaa = SimplifyTerm(CreateTerm(BVUMINUS,l,*it)); + o.push_back(aaa); + } + //simplify the bvplus + output = SimplifyTerm(CreateTerm(BVPLUS,l,o)); + break; + } + case BVSUB: { + //BVUMINUS(BVSUB(x,y)) <=> BVSUB(y,x) + output = SimplifyTerm(CreateTerm(BVSUB,l,a0[1],a0[0])); + break; + } + case ITE: { + //BVUMINUS(ITE(c,t1,t2)) <==> ITE(c,BVUMINUS(t1),BVUMINUS(t2)) + ASTNode c = a0[0]; + ASTNode t1 = SimplifyTerm(CreateTerm(BVUMINUS,l,a0[1])); + ASTNode t2 = SimplifyTerm(CreateTerm(BVUMINUS,l,a0[2])); + output = CreateSimplifiedTermITE(c,t1,t2); + break; + } + default: { + output = CreateTerm(BVUMINUS,l,a0); + break; + } + } + break; + } + case BVEXTRACT:{ + //it is important to take care of wordlevel transformation in + //BVEXTRACT. it exposes oppurtunities for later simplification + //and solving (variable elimination) + ASTNode a0 = SimplifyTerm(inputterm[0]); + Kind k1 = a0.GetKind(); + unsigned int a_len = inputValueWidth; + + //indices for BVEXTRACT + ASTNode i = inputterm[1]; + ASTNode j = inputterm[2]; + ASTNode zero = CreateBVConst(32,0); + //recall that the indices of BVEXTRACT are always 32 bits + //long. therefore doing a GetBVUnsigned is ok. + unsigned int i_val = GetUnsignedConst(i); + unsigned int j_val = GetUnsignedConst(j); + + // a0[i:0] and len(a0)=i+1, then return a0 + if(0 == j_val && a_len == a0.GetValueWidth()) + return a0; + + switch(k1) { + case BVCONST: { + //extract the constant + output = BVConstEvaluator(CreateTerm(BVEXTRACT,a_len,a0,i,j)); + break; + } + case BVCONCAT:{ + //assumes concatenation is binary + // + //input is of the form a0[i:j] + // + //a0 is the conatentation t@u, and a0[0] is t, and a0[1] is u + ASTNode t = a0[0]; + ASTNode u = a0[1]; + unsigned int len_a0 = a0.GetValueWidth(); + unsigned int len_u = u.GetValueWidth(); + + if(len_u > i_val) { + //Apply the following rule: + // (t@u)[i:j] <==> u[i:j], if len(u) > i + // + output = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,u,i,j)); + } + else if(len_a0 > i_val && j_val >= len_u) { + //Apply the rule: + // (t@u)[i:j] <==> t[i-len_u:j-len_u], if len(t@u) > i >= j >= len(u) + i = CreateBVConst(32, i_val - len_u); + j = CreateBVConst(32, j_val - len_u); + output = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,t,i,j)); + } + else { + //Apply the rule: + // (t@u)[i:j] <==> t[i-len_u:0] @ u[len_u-1:j] + i = CreateBVConst(32,i_val-len_u); + ASTNode m = CreateBVConst(32, len_u-1); + t = SimplifyTerm(CreateTerm(BVEXTRACT,i_val-len_u+1,t,i,zero)); + u = SimplifyTerm(CreateTerm(BVEXTRACT,len_u-j_val,u,m,j)); + output = CreateTerm(BVCONCAT,a_len,t,u); + } + break; + } + case BVPLUS: + case BVMULT: { + // (BVMULT(n,t,u))[i:j] <==> BVMULT(i+1,t[i:0],u[i:0])[i:j] + //similar rule for BVPLUS + ASTVec c = a0.GetChildren(); + ASTVec o; + for(ASTVec::iterator jt=c.begin(),jtend=c.end();jt!=jtend;jt++) { + ASTNode aaa = *jt; + aaa = SimplifyTerm(CreateTerm(BVEXTRACT,i_val+1,aaa,i,zero)); + o.push_back(aaa); + } + output = CreateTerm(a0.GetKind(),i_val+1,o); + if(j_val != 0) { + //add extraction only if j is not zero + output = CreateTerm(BVEXTRACT,a_len,output,i,j); + } + break; + } + case BVAND: + case BVOR: + case BVXOR: { + //assumes these operators are binary + // + // (t op u)[i:j] <==> t[i:j] op u[i:j] + ASTNode t = a0[0]; + ASTNode u = a0[1]; + t = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,t,i,j)); + u = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,u,i,j)); + BVTypeCheck(t); + BVTypeCheck(u); + output = CreateTerm(k1,a_len,t,u); + break; + } + case BVNEG:{ + // (~t)[i:j] <==> ~(t[i:j]) + ASTNode t = a0[0]; + t = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,t,i,j)); + output = CreateTerm(BVNEG,a_len,t); + break; + } + // case BVSX:{ +// //(BVSX(t,n)[i:j] <==> BVSX(t,i+1), if n >= i+1 and j=0 +// ASTNode t = a0[0]; +// unsigned int bvsx_len = a0.GetValueWidth(); +// if(bvsx_len < a_len) { +// FatalError("SimplifyTerm: BVEXTRACT over BVSX:" +// "the length of BVSX term must be greater than extract-len",inputterm); +// } +// if(j != zero) { +// output = CreateTerm(BVEXTRACT,a_len,a0,i,j); +// } +// else { +// output = CreateTerm(BVSX,a_len,t,CreateBVConst(32,a_len)); +// } +// break; +// } + case ITE: { + ASTNode t0 = a0[0]; + ASTNode t1 = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,a0[1],i,j)); + ASTNode t2 = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,a0[2],i,j)); + output = CreateSimplifiedTermITE(t0,t1,t2); + break; + } + default: { + output = CreateTerm(BVEXTRACT,a_len,a0,i,j); + break; + } + } + break; + } + case BVNEG: { + ASTNode a0 = SimplifyTerm(inputterm[0]); + unsigned len = inputValueWidth; + switch(a0.GetKind()) { + case BVCONST: + output = BVConstEvaluator(CreateTerm(BVNEG,len,a0)); + break; + case BVNEG: + output = a0[0]; + break; + // case ITE: { +// ASTNode cond = a0[0]; +// ASTNode thenpart = SimplifyTerm(CreateTerm(BVNEG,len,a0[1])); +// ASTNode elsepart = SimplifyTerm(CreateTerm(BVNEG,len,a0[2])); +// output = CreateSimplifiedTermITE(cond,thenpart,elsepart); +// break; +// } + default: + output = CreateTerm(BVNEG,len,a0); + break; + } + break; + } + case BVSX:{ + //a0 is the expr which is being sign extended + ASTNode a0 = SimplifyTerm(inputterm[0]); + //a1 represents the length of the term BVSX(a0) + ASTNode a1 = inputterm[1]; + //output length of the BVSX term + unsigned len = inputValueWidth; + + if(a0.GetValueWidth() == len) { + //nothing to signextend + return a0; + } + + switch(a0.GetKind()) { + case BVCONST: + output = BVConstEvaluator(CreateTerm(BVSX,len,a0,a1)); + break; + case BVNEG: + output = CreateTerm(a0.GetKind(),len,CreateTerm(BVSX,len,a0[0],a1)); + break; + case BVAND: + case BVOR: + //assuming BVAND and BVOR are binary + output = CreateTerm(a0.GetKind(),len, + CreateTerm(BVSX,len,a0[0],a1), + CreateTerm(BVSX,len,a0[1],a1)); + break; + case BVPLUS: { + //BVSX(m,BVPLUS(n,BVSX(t1),BVSX(t2))) <==> BVPLUS(m,BVSX(m,t1),BVSX(m,t2)) + ASTVec c = a0.GetChildren(); + bool returnflag = false; + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + if(BVSX != it->GetKind()) { + returnflag = true; + break; + } + } + if(returnflag) { + output = CreateTerm(BVSX,len,a0,a1); + } + else { + ASTVec o; + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode aaa = SimplifyTerm(CreateTerm(BVSX,len,*it,a1)); + o.push_back(aaa); + } + output = CreateTerm(a0.GetKind(),len,o); + } + break; + } + case BVSX: { + //if you have BVSX(m,BVSX(n,a)) then you can drop the inner + //BVSX provided m is greater than n. + a0 = SimplifyTerm(a0[0]); + output = CreateTerm(BVSX,len,a0,a1); + break; + } + case ITE: { + ASTNode cond = a0[0]; + ASTNode thenpart = SimplifyTerm(CreateTerm(BVSX,len,a0[1],a1)); + ASTNode elsepart = SimplifyTerm(CreateTerm(BVSX,len,a0[2],a1)); + output = CreateSimplifiedTermITE(cond,thenpart,elsepart); + break; + } + default: + output = CreateTerm(BVSX,len,a0,a1); + break; + } + break; + } + case BVAND: + case BVOR:{ + ASTNode max = CreateMaxConst(inputValueWidth); + ASTNode zero = CreateZeroConst(inputValueWidth); + + ASTNode identity = (BVAND == k) ? max : zero; + ASTNode annihilator = (BVAND == k) ? zero : max; + ASTVec c = FlattenOneLevel(inputterm).GetChildren(); + SortByExprNum(c); + ASTVec o; + bool constant = true; + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode aaa = SimplifyTerm(*it); + if(BVCONST != aaa.GetKind()) { + constant = false; + } + + if(aaa == annihilator) { + output = annihilator; + //memoize + UpdateSimplifyMap(inputterm,output,false); + //cerr << "output of SimplifyTerm: " << output << endl; + return output; + } + + if(aaa != identity) { + o.push_back(aaa); + } + } + + switch(o.size()) { + case 0: + output = identity; + break; + case 1: + output = o[0]; + break; + default: + SortByExprNum(o); + output = CreateTerm(k,inputValueWidth,o); + if(constant) { + output = BVConstEvaluator(output); + } + break; + } + break; + } + case BVCONCAT:{ + ASTNode t = SimplifyTerm(inputterm[0]); + ASTNode u = SimplifyTerm(inputterm[1]); + Kind tkind = t.GetKind(); + Kind ukind = u.GetKind(); + + + if(BVCONST == tkind && BVCONST == ukind) { + output = BVConstEvaluator(CreateTerm(BVCONCAT,inputValueWidth,t,u)); + } + else if(BVEXTRACT == tkind && + BVEXTRACT == ukind && + t[0] == u[0]) { + //to handle the case x[m:n]@x[n-1:k] <==> x[m:k] + ASTNode t_hi = t[1]; + ASTNode t_low = t[2]; + ASTNode u_hi = u[1]; + ASTNode u_low = u[2]; + ASTNode c = BVConstEvaluator(CreateTerm(BVPLUS,32,u_hi,CreateOneConst(32))); + if(t_low == c) { + output = CreateTerm(BVEXTRACT,inputValueWidth,t[0],t_hi,u_low); + } + else { + output = CreateTerm(BVCONCAT,inputValueWidth,t,u); + } + } + else { + output = CreateTerm(BVCONCAT,inputValueWidth,t,u); + } + break; + } + case BVXOR: + case BVXNOR: + case BVNAND: + case BVNOR: + case BVLEFTSHIFT: + case BVRIGHTSHIFT: + case BVVARSHIFT: + case BVSRSHIFT: + case BVDIV: + case BVMOD: { + ASTVec c = inputterm.GetChildren(); + ASTVec o; + bool constant = true; + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode aaa = SimplifyTerm(*it); + if(BVCONST != aaa.GetKind()) { + constant = false; + } + o.push_back(aaa); + } + output = CreateTerm(k,inputValueWidth,o); + if(constant) + output = BVConstEvaluator(output); + break; + } + case READ: { + ASTNode out1; + //process only if not in the substitution map. simplifymap + //has been checked already + if(!CheckSubstitutionMap(inputterm,out1)) { + if(WRITE == inputterm[0].GetKind()) { + //get rid of all writes + ASTNode nowrites = RemoveWrites_TopLevel(inputterm); + out1 = nowrites; + } + else if (ITE == inputterm[0].GetKind()){ + ASTNode cond = SimplifyFormula(inputterm[0][0],false); + ASTNode arr1 = SimplifyTerm(inputterm[0][1]); + ASTNode arr2 = SimplifyTerm(inputterm[0][2]); + + ASTNode index = SimplifyTerm(inputterm[1]); + + ASTNode read1 = CreateTerm(READ,inputValueWidth,arr1,index); + ASTNode read2 = CreateTerm(READ,inputValueWidth,arr2,index); + out1 = CreateSimplifiedTermITE(cond,read1,read2); + } + else { + //arr is a SYMBOL for sure + ASTNode arr = inputterm[0]; + ASTNode index = SimplifyTerm(inputterm[1]); + out1 = CreateTerm(READ,inputValueWidth,arr,index); + } + } + //it is possible that after all the procesing the READ term + //reduces to READ(Symbol,const) and hence we should check the + //substitutionmap once again. + if(!CheckSubstitutionMap(out1,output)) + output = out1; + break; + } + case ITE: { + ASTNode t0 = SimplifyFormula(inputterm[0],false); + ASTNode t1 = SimplifyTerm(inputterm[1]); + ASTNode t2 = SimplifyTerm(inputterm[2]); + output = CreateSimplifiedTermITE(t0,t1,t2); + break; + } + case SBVMOD: + case SBVDIV: { + ASTVec c = inputterm.GetChildren(); + ASTVec o; + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode aaa = SimplifyTerm(*it); + o.push_back(aaa); + } + output = CreateTerm(k,inputValueWidth,o); + break; + } + case WRITE: + default: + FatalError("SimplifyTerm: Control should never reach here:", inputterm, k); + return inputterm; + break; + } + + //memoize + UpdateSimplifyMap(inputterm,output,false); + //cerr << "SimplifyTerm: output" << output << endl; + return output; + } //end of SimplifyTerm() + + + //At the end of each simplification call, we want the output to be + //always smaller or equal to the input in size. + void BeevMgr::CheckSimplifyInvariant(const ASTNode& a, const ASTNode& output) { + //Don't do the check in optimized mode + if(optimize) + return; + + if(NodeSize(a,true) < NodeSize(output,true)) { + cerr << "lhs := " << a << endl; + cerr << "NodeSize of lhs is: " << NodeSize(a, true) << endl; + cerr << endl; + cerr << "rhs := " << output << endl; + cerr << "NodeSize of rhs is: " << NodeSize(output, true) << endl; + FatalError("SimplifyFormula: The nodesize shoudl decrease from lhs to rhs: ",ASTUndefined); + } + } + + //this function assumes that the input is a vector of childnodes of + //a BVPLUS term. it combines like terms and returns a bvplus + //term. e.g. 1.x + 2.x is converted to 3.x + ASTNode BeevMgr::CombineLikeTerms(const ASTNode& a) { + if(BVPLUS != a.GetKind()) + return a; + + ASTNode output; + if(CheckSimplifyMap(a,output,false)) { + //check memo table + //cerr << "output of SimplifyTerm Cache: " << output << endl; + return output; + } + + ASTVec c = a.GetChildren(); + //map from variables to vector of constants + ASTNodeToVecMap vars_to_consts; + //vector to hold constants + ASTVec constkids; + ASTVec outputvec; + + //useful constants + unsigned int len = c[0].GetValueWidth(); + ASTNode one = CreateOneConst(len); + ASTNode zero = CreateZeroConst(len); + ASTNode max = CreateMaxConst(len); + + //go over the childnodes of the input bvplus, and collect like + //terms in a map. the key of the map are the variables, and the + //values are stored in a ASTVec + for(ASTVec::const_iterator it=c.begin(),itend=c.end();it!=itend;it++){ + ASTNode aaa = *it; + if(SYMBOL == aaa.GetKind()) { + vars_to_consts[aaa].push_back(one); + } + else if(BVMULT == aaa.GetKind() && + BVUMINUS == aaa[0].GetKind() && + BVCONST == aaa[0][0].GetKind()) { + //(BVUMINUS(c))*(y) <==> compute(BVUMINUS(c))*y + ASTNode compute_const = BVConstEvaluator(aaa[0]); + vars_to_consts[aaa[1]].push_back(compute_const); + } + else if(BVMULT == aaa.GetKind() && + BVUMINUS == aaa[1].GetKind() && + BVCONST == aaa[0].GetKind()) { + //c*(BVUMINUS(y)) <==> compute(BVUMINUS(c))*y + ASTNode cccc = BVConstEvaluator(CreateTerm(BVUMINUS,len,aaa[0])); + vars_to_consts[aaa[1][0]].push_back(cccc); + } + else if(BVMULT == aaa.GetKind() && BVCONST == aaa[0].GetKind()) { + //assumes that BVMULT is binary + vars_to_consts[aaa[1]].push_back(aaa[0]); + } + else if(BVMULT == aaa.GetKind() && BVUMINUS == aaa[0].GetKind()) { + //(-1*x)*(y) <==> -1*(xy) + ASTNode cccc = CreateTerm(BVMULT,len,aaa[0][0],aaa[1]); + ASTVec cNodes = cccc.GetChildren(); + SortByExprNum(cNodes); + vars_to_consts[cccc].push_back(max); + } + else if(BVMULT == aaa.GetKind() && BVUMINUS == aaa[1].GetKind()) { + //x*(-1*y) <==> -1*(xy) + ASTNode cccc = CreateTerm(BVMULT,len,aaa[0],aaa[1][0]); + ASTVec cNodes = cccc.GetChildren(); + SortByExprNum(cNodes); + vars_to_consts[cccc].push_back(max); + } + else if(BVCONST == aaa.GetKind()) { + constkids.push_back(aaa); + } + else if(BVUMINUS == aaa.GetKind()) { + //helps to convert BVUMINUS into a BVMULT. here the max + //constant represents -1. this transformation allows us to + //conclude that x + BVUMINUS(x) is 0. + vars_to_consts[aaa[0]].push_back(max); + } + else + vars_to_consts[aaa].push_back(one); + } //end of for loop + + //go over the map from variables to vector of values. combine the + //vector of values, multiply to the variable, and put the + //resultant monomial in the output BVPLUS. + for(ASTNodeToVecMap::iterator it=vars_to_consts.begin(),itend=vars_to_consts.end(); + it!=itend;it++){ + ASTVec ccc = it->second; + + ASTNode constant; + if(1 < ccc.size()) { + constant = CreateTerm(BVPLUS,ccc[0].GetValueWidth(),ccc); + constant = BVConstEvaluator(constant); + } + else + constant = ccc[0]; + + //constant * var + ASTNode monom; + if(zero == constant) + monom = zero; + else if (one == constant) + monom = it->first; + else + monom = + SimplifyTerm(CreateTerm(BVMULT,constant.GetValueWidth(),constant,it->first)); + if(zero != monom) { + outputvec.push_back(monom); + } + } //end of for loop + + if(constkids.size() > 1) { + ASTNode output = CreateTerm(BVPLUS,constkids[0].GetValueWidth(),constkids); + output = BVConstEvaluator(output); + if(output != zero) + outputvec.push_back(output); + } + else if (constkids.size() == 1) { + if(constkids[0] != zero) + outputvec.push_back(constkids[0]); + } + + if (outputvec.size() > 1) { + output = CreateTerm(BVPLUS,len,outputvec); + } + else if(outputvec.size() == 1) { + output = outputvec[0]; + } + else { + output = zero; + } + + //memoize + //UpdateSimplifyMap(a,output,false); + return output; + } //end of CombineLikeTerms() + + //accepts lhs and rhs, and returns lhs - rhs = 0. The function + //assumes that lhs and rhs have already been simplified. although + //this assumption is not needed for correctness, it is essential for + //performance. The function also assumes that lhs is a BVPLUS + ASTNode BeevMgr::LhsMinusRhs(const ASTNode& eq) { + //if input is not an equality, simply return it + if(EQ != eq.GetKind()) + return eq; + + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + Kind k_lhs = lhs.GetKind(); + Kind k_rhs = rhs.GetKind(); + //either the lhs has to be a BVPLUS or the rhs has to be a + //BVPLUS + if(!(BVPLUS == k_lhs || + BVPLUS == k_rhs || + (BVMULT == k_lhs && + BVMULT == k_rhs) + )) { + return eq; + } + + ASTNode output; + if(CheckSimplifyMap(eq,output,false)) { + //check memo table + //cerr << "output of SimplifyTerm Cache: " << output << endl; + return output; + } + + //if the lhs is not a BVPLUS, but the rhs is a BVPLUS, then swap + //the lhs and rhs + bool swap_flag = false; + if(BVPLUS != k_lhs && BVPLUS == k_rhs) { + ASTNode swap = lhs; + lhs = rhs; + rhs = swap; + swap_flag = true; + } + + unsigned int len = lhs.GetValueWidth(); + ASTNode zero = CreateZeroConst(len); + //right is -1*(rhs): Simplify(-1*rhs) + rhs = SimplifyTerm(CreateTerm(BVUMINUS,len,rhs)); + + ASTVec lvec = lhs.GetChildren(); + ASTVec rvec = rhs.GetChildren(); + ASTNode lhsplusrhs; + if(BVPLUS != lhs.GetKind() && BVPLUS != rhs.GetKind()) { + lhsplusrhs = CreateTerm(BVPLUS,len,lhs,rhs); + } + else if(BVPLUS == lhs.GetKind() && BVPLUS == rhs.GetKind()) { + //combine the childnodes of the left and the right + lvec.insert(lvec.end(),rvec.begin(),rvec.end()); + lhsplusrhs = CreateTerm(BVPLUS,len,lvec); + } + else if(BVPLUS == lhs.GetKind() && BVPLUS != rhs.GetKind()){ + lvec.push_back(rhs); + lhsplusrhs = CreateTerm(BVPLUS,len,lvec); + } + else { + //Control should never reach here + FatalError("LhsMinusRhs: Control should never reach here\n"); + } + + //combine like terms + output = CombineLikeTerms(lhsplusrhs); + output = SimplifyTerm(output); + // + //Now make output into: lhs-rhs = 0 + output = CreateSimplifiedEQ(output,zero); + //sort if BVPLUS + if(BVPLUS == output.GetKind()) { + ASTVec outv = output.GetChildren(); + SortByExprNum(outv); + output = CreateTerm(BVPLUS,len,outv); + } + + //memoize + //UpdateSimplifyMap(eq,output,false); + return output; + } //end of LhsMinusRHS() + + //THis function accepts a BVMULT(t1,t2) and distributes the mult + //over plus if either or both t1 and t2 are BVPLUSes. + // + // x*(y1 + y2 + ...+ yn) <==> x*y1 + x*y2 + ... + x*yn + // + // (y1 + y2 + ...+ yn)*x <==> x*y1 + x*y2 + ... + x*yn + // + // The function assumes that the BVPLUSes have been flattened + ASTNode BeevMgr::DistributeMultOverPlus(const ASTNode& a, bool startdistribution) { + if(!startdistribution) + return a; + Kind k = a.GetKind(); + if(BVMULT != k) + return a; + + ASTNode left = a[0]; + ASTNode right = a[1]; + Kind left_kind = left.GetKind(); + Kind right_kind = right.GetKind(); + + ASTNode output; + if(CheckSimplifyMap(a,output,false)) { + //check memo table + //cerr << "output of SimplifyTerm Cache: " << output << endl; + return output; + } + + //special case optimization: c1*(c2*t1) <==> (c1*c2)*t1 + if(BVCONST == left_kind && + BVMULT == right_kind && + BVCONST == right[0].GetKind()) { + ASTNode c = BVConstEvaluator(CreateTerm(BVMULT,a.GetValueWidth(),left,right[0])); + c = CreateTerm(BVMULT,a.GetValueWidth(),c,right[1]); + return c; + left = c[0]; + right = c[1]; + left_kind = left.GetKind(); + right_kind = right.GetKind(); + } + + //special case optimization: c1*(t1*c2) <==> (c1*c2)*t1 + if(BVCONST == left_kind && + BVMULT == right_kind && + BVCONST == right[1].GetKind()) { + ASTNode c = BVConstEvaluator(CreateTerm(BVMULT,a.GetValueWidth(),left,right[1])); + c = CreateTerm(BVMULT,a.GetValueWidth(),c,right[0]); + return c; + left = c[0]; + right = c[1]; + left_kind = left.GetKind(); + right_kind = right.GetKind(); + } + + //atleast one of left or right have to be BVPLUS + if(!(BVPLUS == left_kind || BVPLUS == right_kind)) { + return a; + } + + //if left is BVPLUS and right is not, then swap left and right. we + //can do this since BVMULT is communtative + ASTNode swap; + if(BVPLUS == left_kind && BVPLUS != right_kind) { + swap = left; + left = right; + right = swap; + } + left_kind = left.GetKind(); + right_kind = right.GetKind(); + + //by this point we are gauranteed that right is a BVPLUS, but left + //may not be + ASTVec rightnodes = right.GetChildren(); + ASTVec outputvec; + unsigned len = a.GetValueWidth(); + ASTNode zero = CreateZeroConst(len); + ASTNode one = CreateOneConst(len); + if(BVPLUS != left_kind) { + //if the multiplier is not a BVPLUS then we have a special case + // x*(y1 + y2 + ...+ yn) <==> x*y1 + x*y2 + ... + x*yn + if(zero == left) { + outputvec.push_back(zero); + } + else if(one == left) { + outputvec.push_back(left); + } + else { + for(ASTVec::iterator j=rightnodes.begin(),jend=rightnodes.end(); + j!=jend;j++) { + ASTNode out = SimplifyTerm(CreateTerm(BVMULT,len,left,*j)); + outputvec.push_back(out); + } + } + } + else { + ASTVec leftnodes = left.GetChildren(); + // (x1 + x2 + ... + xm)*(y1 + y2 + ...+ yn) <==> x1*y1 + x1*y2 + + // ... + x2*y1 + ... + xm*yn + for(ASTVec::iterator i=leftnodes.begin(),iend=leftnodes.end(); + i!=iend;i++) { + ASTNode multiplier = *i; + for(ASTVec::iterator j=rightnodes.begin(),jend=rightnodes.end(); + j!=jend;j++) { + ASTNode out = SimplifyTerm(CreateTerm(BVMULT,len,multiplier,*j)); + outputvec.push_back(out); + } + } + } + + //compute output here + if(outputvec.size() > 1) { + output = CombineLikeTerms(CreateTerm(BVPLUS,len,outputvec)); + output = SimplifyTerm(output); + } + else + output = SimplifyTerm(outputvec[0]); + + //memoize + //UpdateSimplifyMap(a,output,false); + return output; + } //end of distributemultoverplus() + + //converts the BVSX(len, a0) operator into ITE( check top bit, + //extend a0 by 1, extend a0 by 0) + ASTNode BeevMgr::ConvertBVSXToITE(const ASTNode& a) { + if(BVSX != a.GetKind()) + return a; + + ASTNode output; + if(CheckSimplifyMap(a,output,false)) { + //check memo table + //cerr << "output of ConvertBVSXToITE Cache: " << output << endl; + return output; + } + + ASTNode a0 = a[0]; + unsigned a_len = a.GetValueWidth(); + unsigned a0_len = a0.GetValueWidth(); + + if(a0_len > a_len){ + FatalError("Trying to sign_extend a larger BV into a smaller BV"); + return ASTUndefined; //to stop the compiler from producing bogus warnings + } + + //sign extend + unsigned extensionlen = a_len-a0_len; + if(0 == extensionlen) { + UpdateSimplifyMap(a,output,false); + return a; + } + + std::string ones; + for(unsigned c=0; c < extensionlen;c++) + ones += '1'; + std::string zeros; + for(unsigned c=0; c < extensionlen;c++) + zeros += '0'; + + //string of oness of length extensionlen + BEEV::ASTNode BVOnes = CreateBVConst(ones.c_str(),2); + //string of zeros of length extensionlen + BEEV::ASTNode BVZeros = CreateBVConst(zeros.c_str(),2); + + //string of ones BVCONCAT a0 + BEEV::ASTNode concatOnes = CreateTerm(BEEV::BVCONCAT,a_len,BVOnes,a0); + //string of zeros BVCONCAT a0 + BEEV::ASTNode concatZeros = CreateTerm(BEEV::BVCONCAT,a_len,BVZeros,a0); + + //extract top bit of a0 + BEEV::ASTNode hi = CreateBVConst(32,a0_len-1); + BEEV::ASTNode low = CreateBVConst(32,a0_len-1); + BEEV::ASTNode topBit = CreateTerm(BEEV::BVEXTRACT,1,a0,hi,low); + + //compare topBit of a0 with 0bin1 + BEEV::ASTNode condition = CreateSimplifiedEQ(CreateBVConst(1,1),topBit); + + //ITE(topbit = 0bin1, 0bin1111...a0, 0bin000...a0) + output = CreateSimplifiedTermITE(condition,concatOnes,concatZeros); + UpdateSimplifyMap(a,output,false); + return output; + } //end of ConvertBVSXToITE() + + + ASTNode BeevMgr::RemoveWrites_TopLevel(const ASTNode& term) { + if(READ != term.GetKind() && WRITE != term[0].GetKind()) { + FatalError("RemovesWrites: Input must be a READ over a WRITE",term); + } + + if(!Begin_RemoveWrites && + !SimplifyWrites_InPlace_Flag && + !start_abstracting) { + return term; + } + else if(!Begin_RemoveWrites && + SimplifyWrites_InPlace_Flag && + !start_abstracting) { + //return term; + return SimplifyWrites_InPlace(term); + } + else { + return RemoveWrites(term); + } + } //end of RemoveWrites_TopLevel() + + ASTNode BeevMgr::SimplifyWrites_InPlace(const ASTNode& term) { + ASTNodeMultiSet WriteIndicesSeenSoFar; + bool SeenNonConstWriteIndex = false; + + if(READ != term.GetKind() && + WRITE != term[0].GetKind()) { + FatalError("RemovesWrites: Input must be a READ over a WRITE",term); + } + + ASTNode output; + if(CheckSimplifyMap(term,output,false)) { + return output; + } + + ASTVec writeIndices, writeValues; + unsigned int width = term.GetValueWidth(); + ASTNode write = term[0]; + unsigned indexwidth = write.GetIndexWidth(); + ASTNode readIndex = SimplifyTerm(term[1]); + + do { + ASTNode writeIndex = SimplifyTerm(write[1]); + ASTNode writeVal = SimplifyTerm(write[2]); + + //compare the readIndex and the current writeIndex and see if they + //simplify to TRUE or FALSE or UNDETERMINABLE at this stage + ASTNode compare_readwrite_indices = + SimplifyFormula(CreateSimplifiedEQ(writeIndex,readIndex),false); + + //if readIndex and writeIndex are equal + if(ASTTrue == compare_readwrite_indices && !SeenNonConstWriteIndex) { + UpdateSimplifyMap(term,writeVal,false); + return writeVal; + } + + if(!(ASTTrue == compare_readwrite_indices || + ASTFalse == compare_readwrite_indices)) { + SeenNonConstWriteIndex = true; + } + + //if (readIndex=writeIndex <=> FALSE) + if(ASTFalse == compare_readwrite_indices + || + (WriteIndicesSeenSoFar.find(writeIndex) != WriteIndicesSeenSoFar.end()) + ) { + //drop the current level write + //do nothing + } + else { + writeIndices.push_back(writeIndex); + writeValues.push_back(writeVal); + } + + //record the write indices seen so far + //if(BVCONST == writeIndex.GetKind()) { + WriteIndicesSeenSoFar.insert(writeIndex); + //} + + //Setup the write for the new iteration, one level inner write + write = write[0]; + }while (SYMBOL != write.GetKind()); + + ASTVec::reverse_iterator it_index = writeIndices.rbegin(); + ASTVec::reverse_iterator itend_index = writeIndices.rend(); + ASTVec::reverse_iterator it_values = writeValues.rbegin(); + ASTVec::reverse_iterator itend_values = writeValues.rend(); + + //"write" must be a symbol at the control point before the + //begining of the "for loop" + + for(;it_index!=itend_index;it_index++,it_values++) { + write = CreateTerm(WRITE,width,write,*it_index,*it_values); + write.SetIndexWidth(indexwidth); + } + + output = CreateTerm(READ,width,write,readIndex); + UpdateSimplifyMap(term,output,false); + return output; + } //end of SimplifyWrites_In_Place() + + //accepts a read over a write and returns a term without the write + //READ(WRITE(A i val) j) <==> ITE(i=j,val,READ(A,j)). We use a memo + //table for this function called RemoveWritesMemoMap + ASTNode BeevMgr::RemoveWrites(const ASTNode& input) { + //unsigned int width = input.GetValueWidth(); + if(READ != input.GetKind() || WRITE != input[0].GetKind()) { + FatalError("RemovesWrites: Input must be a READ over a WRITE",input); + } + + ASTNodeMap::iterator it; + ASTNode output = input; + if(CheckSimplifyMap(input,output,false)) { + return output; + } + + if(!start_abstracting && Begin_RemoveWrites) { + output= ReadOverWrite_To_ITE(input); + } + + if(start_abstracting) { + ASTNode newVar; + if(!CheckSimplifyMap(input,newVar,false)) { + newVar = NewVar(input.GetValueWidth()); + ReadOverWrite_NewName_Map[input] = newVar; + NewName_ReadOverWrite_Map[newVar] = input; + + UpdateSimplifyMap(input,newVar,false); + ASTNodeStats("New Var Name which replace Read_Over_Write: ", newVar); + } + output = newVar; + } //end of start_abstracting if condition + + //memoize + UpdateSimplifyMap(input,output,false); + return output; + } //end of RemoveWrites() + + ASTNode BeevMgr::ReadOverWrite_To_ITE(const ASTNode& term) { + unsigned int width = term.GetValueWidth(); + ASTNode input = term; + if(READ != term.GetKind() || WRITE != term[0].GetKind()) { + FatalError("RemovesWrites: Input must be a READ over a WRITE",term); + } + + ASTNodeMap::iterator it; + ASTNode output; + // if(CheckSimplifyMap(term,output,false)) { + // return output; + // } + + ASTNode partialITE = term; + ASTNode writeA = ASTTrue; + ASTNode oldRead = term; + //iteratively expand read-over-write + do { + ASTNode write = input[0]; + ASTNode readIndex = SimplifyTerm(input[1]); + //DO NOT CALL SimplifyTerm() on write[0]. You will go into an + //infinite loop + writeA = write[0]; + ASTNode writeIndex = SimplifyTerm(write[1]); + ASTNode writeVal = SimplifyTerm(write[2]); + + ASTNode cond = SimplifyFormula(CreateSimplifiedEQ(writeIndex,readIndex),false); + ASTNode newRead = CreateTerm(READ,width,writeA,readIndex); + ASTNode newRead_memoized = newRead; + if(CheckSimplifyMap(newRead, newRead_memoized,false)) { + newRead = newRead_memoized; + } + + if(ASTTrue == cond && (term == partialITE)) { + //found the write-value in the first iteration itself. return + //it + output = writeVal; + UpdateSimplifyMap(term,output,false); + return output; + } + + if(READ == partialITE.GetKind() && WRITE == partialITE[0].GetKind()) { + //first iteration or (previous cond==ASTFALSE and partialITE is a "READ over WRITE") + partialITE = CreateSimplifiedTermITE(cond, writeVal, newRead); + } + else if (ITE == partialITE.GetKind()){ + //ITE(i1 = j, v1, R(A,j)) + ASTNode ElseITE = CreateSimplifiedTermITE(cond, writeVal, newRead); + //R(W(A,i1,v1),j) <==> ITE(i1 = j, v1, R(A,j)) + UpdateSimplifyMap(oldRead,ElseITE,false); + //ITE(i2 = j, v2, R(W(A,i1,v1),j)) <==> ITE(i2 = j, v2, ITE(i1 = j, v1, R(A,j))) + partialITE = SimplifyTerm(partialITE); + } + else { + FatalError("RemoveWrites: Control should not reach here\n"); + } + + if(ASTTrue == cond) { + //no more iterations required + output = partialITE; + UpdateSimplifyMap(term,output,false); + return output; + } + + input = newRead; + oldRead = newRead; + } while(READ == input.GetKind() && WRITE == input[0].GetKind()); + + output = partialITE; + + //memoize + //UpdateSimplifyMap(term,output,false); + return output; + } //ReadOverWrite_To_ITE() + + //compute the multiplicative inverse of the input + ASTNode BeevMgr::MultiplicativeInverse(const ASTNode& d) { + ASTNode c = d; + if(BVCONST != c.GetKind()) { + FatalError("Input must be a constant", c); + } + + if(!BVConstIsOdd(c)) { + FatalError("MultiplicativeInverse: Input must be odd: ",c); + } + + //cerr << "input to multinverse function is: " << d << endl; + ASTNode inverse; + if(CheckMultInverseMap(d,inverse)) { + //cerr << "found the inverse of: " << d << "and it is: " << inverse << endl; + return inverse; + } + + inverse = c; + unsigned inputwidth = c.GetValueWidth(); + +#ifdef NATIVE_C_ARITH + ASTNode one = CreateOneConst(inputwidth); + while(c != one) { + //c = c*c + c = BVConstEvaluator(CreateTerm(BVMULT,inputwidth,c,c)); + //inverse = invsere*c + inverse = BVConstEvaluator(CreateTerm(BVMULT,inputwidth,inverse,c)); + } +#else + //Compute the multiplicative inverse of c using the extended + //euclidian algorithm + // + //create a '0' which is 1 bit long + ASTNode onebit_zero = CreateZeroConst(1); + //zero pad t0, i.e. 0 @ t0 + c = BVConstEvaluator(CreateTerm(BVCONCAT,inputwidth+1,onebit_zero,c)); + + //construct 2^(inputwidth), i.e. a bitvector of length + //'inputwidth+1', which is max(inputwidth)+1 + // + //all 1's + ASTNode max = CreateMaxConst(inputwidth); + //zero pad max + max = BVConstEvaluator(CreateTerm(BVCONCAT,inputwidth+1,onebit_zero,max)); + //Create a '1' which has leading zeros of length 'inputwidth' + ASTNode inputwidthplusone_one = CreateOneConst(inputwidth+1); + //add 1 to max + max = CreateTerm(BVPLUS,inputwidth+1,max,inputwidthplusone_one); + max = BVConstEvaluator(max); + + ASTNode zero = CreateZeroConst(inputwidth+1); + ASTNode max_bvgt_0 = CreateNode(BVGT,max,zero); + ASTNode quotient, remainder; + ASTNode x, x1, x2; + + //x1 initialized to zero + x1 = zero; + //x2 initialized to one + x2 = CreateOneConst(inputwidth+1); + while (ASTTrue == BVConstEvaluator(max_bvgt_0)) { + //quotient = (c divided by max) + quotient = BVConstEvaluator(CreateTerm(BVDIV,inputwidth+1, c, max)); + + //remainder of (c divided by max) + remainder = BVConstEvaluator(CreateTerm(BVMOD,inputwidth+1, c, max)); + + //x = x2 - q*x1 + x = CreateTerm(BVSUB,inputwidth+1,x2,CreateTerm(BVMULT,inputwidth+1,quotient,x1)); + x = BVConstEvaluator(x); + + //fix the inputs to the extended euclidian algo + c = max; + max = remainder; + max_bvgt_0 = CreateNode(BVGT,max,zero); + + x2 = x1; + x1 = x; + } + + ASTNode hi = CreateBVConst(32,inputwidth-1); + ASTNode low = CreateZeroConst(32); + inverse = CreateTerm(BVEXTRACT,inputwidth,x2,hi,low); + inverse = BVConstEvaluator(inverse); +#endif + + UpdateMultInverseMap(d,inverse); + //cerr << "output of multinverse function is: " << inverse << endl; + return inverse; + } //end of MultiplicativeInverse() + + //returns true if the input is odd + bool BeevMgr::BVConstIsOdd(const ASTNode& c) { + if(BVCONST != c.GetKind()) { + FatalError("Input must be a constant", c); + } + + ASTNode zero = CreateZeroConst(1); + ASTNode hi = CreateZeroConst(32); + ASTNode low = hi; + ASTNode lowestbit = CreateTerm(BVEXTRACT,1,c,hi,low); + lowestbit = BVConstEvaluator(lowestbit); + + if(lowestbit == zero) { + return false; + } + else { + return true; + } + } //end of BVConstIsOdd() + + //The big substitution function + ASTNode BeevMgr::CreateSubstitutionMap(const ASTNode& a){ + if(!optimize) + return a; + + ASTNode output = a; + //if the variable has been solved for, then simply return it + if(CheckSolverMap(a,output)) + return output; + + //traverse a and populate the SubstitutionMap + Kind k = a.GetKind(); + if(SYMBOL == k && BOOLEAN_TYPE == a.GetType()) { + bool updated = UpdateSubstitutionMap(a,ASTTrue); + output = updated ? ASTTrue : a; + return output; + } + if(NOT == k + && SYMBOL == a[0].GetKind()) { + bool updated = UpdateSubstitutionMap(a[0],ASTFalse); + output = updated ? ASTTrue : a; + return output; + } + + if(IFF == k) { + ASTVec c = a.GetChildren(); + SortByExprNum(c); + if(SYMBOL != c[0].GetKind() || + VarSeenInTerm(c[0],SimplifyFormula_NoRemoveWrites(c[1],false))) { + return a; + } + bool updated = UpdateSubstitutionMap(c[0],c[1]); + output = updated ? ASTTrue : a; + return output; + } + + if(EQ == k) { + //fill the arrayname readindices vector if e0 is a + //READ(Arr,index) and index is a BVCONST + ASTVec c = a.GetChildren(); + SortByExprNum(c); + FillUp_ArrReadIndex_Vec(c[0],c[1]); + + if(SYMBOL == c[0].GetKind() && + VarSeenInTerm(c[0],SimplifyTerm(c[1]))) { + return a; + } + + if(1 == TermOrder(c[0],c[1]) && + READ == c[0].GetKind() && + VarSeenInTerm(c[0][0],SimplifyTerm(c[1]))) { + return a; + } + bool updated = UpdateSubstitutionMap(c[0],c[1]); + output = updated ? ASTTrue : a; + return output; + } + + if(AND == k){ + ASTVec o; + ASTVec c = a.GetChildren(); + for(ASTVec::iterator it = c.begin(),itend=c.end();it!=itend;it++) { + UpdateAlwaysTrueFormMap(*it); + ASTNode aaa = CreateSubstitutionMap(*it); + + if(ASTTrue != aaa) { + if(ASTFalse == aaa) + return ASTFalse; + else + o.push_back(aaa); + } + } + if(o.size() == 0) + return ASTTrue; + + if(o.size() == 1) + return o[0]; + + return CreateNode(AND,o); + } + return output; + } //end of CreateSubstitutionMap() + + + bool BeevMgr::VarSeenInTerm(const ASTNode& var, const ASTNode& term) { + if(READ == term.GetKind() && + WRITE == term[0].GetKind() && !Begin_RemoveWrites) { + return false; + } + + if(READ == term.GetKind() && + WRITE == term[0].GetKind() && Begin_RemoveWrites) { + return true; + } + + ASTNodeMap::iterator it; + if((it = TermsAlreadySeenMap.find(term)) != TermsAlreadySeenMap.end()) { + if(it->second == var) { + return false; + } + } + + if(var == term) { + return true; + } + + for(ASTVec::const_iterator it=term.begin(),itend=term.end();it!=itend;it++){ + if(VarSeenInTerm(var,*it)) { + return true; + } + else { + TermsAlreadySeenMap[*it] = var; + } + } + + TermsAlreadySeenMap[term] = var; + return false; + } +};//end of namespace |