/********************************************************************
* 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