about summary refs log tree commit diff homepage
path: root/stp/simplifier/simplifier.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'stp/simplifier/simplifier.cpp')
-rw-r--r--stp/simplifier/simplifier.cpp2495
1 files changed, 2495 insertions, 0 deletions
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