about summary refs log tree commit diff homepage
path: root/stp/simplifier/bvsolver.cpp
blob: 369251db6c8939886d329673ba3b1829196f3b43 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
/********************************************************************
 * AUTHORS: Vijay Ganesh, David L. Dill
 *
 * BEGIN DATE: November, 2005
 *
 * LICENSE: Please view LICENSE file in the home dir of this Program
 ********************************************************************/
// -*- c++ -*-

#include "../AST/AST.h"
#include "../AST/ASTUtil.h"
#include "bvsolver.h"

  //This file contains the implementation of member functions of
  //bvsolver class, which represents the bitvector arithmetic linear
  //solver. Please also refer the STP's CAV 2007 paper for the
  //complete description of the linear solver algorithm
  //
  //The bitvector solver is a partial solver, i.e. it does not solve
  //for all variables in the system of equations. it is
  //best-effort. it relies on the SAT solver to be complete.
  //
  //The BVSolver assumes that the input equations are normalized, and
  //have liketerms combined etc.
  //
  //0. Traverse top-down over the input DAG, looking for a conjunction
  //0. of equations. if you find one, then for each equation in the
  //0. conjunction, do the following steps.
  //
  //1. check for Linearity of the input equation
  //
  //2. Solve for a "chosen" variable. The variable should occur
  //2. exactly once and must have an odd coeff. Refer STP's CAV 2007
  //2. paper for actual solving procedure
  //
  //4. Outside the solver, Substitute and Re-normalize the input DAG 
namespace BEEV {  
  //check the solver map for 'key'. If key is present, then return the
  //value by reference in the argument 'output'
  bool BVSolver::CheckAlreadySolvedMap(const ASTNode& key, ASTNode& output) {
    ASTNodeMap::iterator it;
    if((it = FormulasAlreadySolvedMap.find(key)) != FormulasAlreadySolvedMap.end()) {
      output = it->second;
      return true;
    }
    return false;
  } //CheckAlreadySolvedMap()

  void BVSolver::UpdateAlreadySolvedMap(const ASTNode& key, const ASTNode& value) {
    FormulasAlreadySolvedMap[key] = value;
  } //end of UpdateAlreadySolvedMap()

  //FIXME This is doing way more arithmetic than it needs to.
  //accepts an even number "in", and splits it into an odd number and
  //a power of 2. i.e " in = b.(2^k) ". returns the odd number, and
  //the power of two by reference
  ASTNode BVSolver::SplitEven_into_Oddnum_PowerOf2(const ASTNode& in, 
						unsigned int& number_shifts) {
    if(BVCONST != in.GetKind() || _bm->BVConstIsOdd(in)) {
      FatalError("BVSolver:SplitNum_Odd_PowerOf2: input must be a BVCONST and even\n",in);
    }
    
    unsigned int len = in.GetValueWidth();
    ASTNode zero = _bm->CreateZeroConst(len);
    ASTNode two = _bm->CreateTwoConst(len);
    ASTNode div_by_2 = in;
    ASTNode mod_by_2 = 
      _bm->BVConstEvaluator(_bm->CreateTerm(BVMOD,len,div_by_2,two)); 
    while(mod_by_2 == zero) {
      div_by_2 = 
	_bm->BVConstEvaluator(_bm->CreateTerm(BVDIV,len,div_by_2,two));
      number_shifts++;
      mod_by_2 = 
	_bm->BVConstEvaluator(_bm->CreateTerm(BVMOD,len,div_by_2,two));
    }
    return div_by_2;
  } //end of SplitEven_into_Oddnum_PowerOf2()

  //Checks if there are any ARRAYREADS in the term, after the
  //alreadyseenmap is cleared, i.e. traversing a new term altogether
  bool BVSolver::CheckForArrayReads_TopLevel(const ASTNode& term) {
    TermsAlreadySeenMap.clear();
    return CheckForArrayReads(term);
  }
  
  //Checks if there are any ARRAYREADS in the term
  bool BVSolver::CheckForArrayReads(const ASTNode& term) {
    ASTNode a = term;
    ASTNodeMap::iterator it;    
    if((it = TermsAlreadySeenMap.find(term)) != TermsAlreadySeenMap.end()) {
      //if the term has been seen, then simply return true, else
      //return false
      if(ASTTrue == (it->second)) {
	return true;
      }
      else {
	return false;
      }
    }

    switch(term.GetKind()) {
    case READ:
      //an array read has been seen. Make an entry in the map and
      //return true
      TermsAlreadySeenMap[term] = ASTTrue;
      return true;
    default: {
      ASTVec c = term.GetChildren();
      for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) {
	if(CheckForArrayReads(*it)) {
	  return true;
	}
      }
      break;
    }
    }

    //If control is here, then it means that no arrayread was seen for
    //the input 'term'. Make an entry in the map with the term as key
    //and FALSE as value.
    TermsAlreadySeenMap[term] = ASTFalse;
    return false;
  } //end of CheckForArrayReads()
  
  //check the solver map for 'key'. If key is present, then return the
  //value by reference in the argument 'output'
  bool BeevMgr::CheckSolverMap(const ASTNode& key, ASTNode& output) {
    ASTNodeMap::iterator it;
    if((it = SolverMap.find(key)) != SolverMap.end()) {
      output = it->second;
      return true;
    }
    return false;
  } //end of CheckSolverMap()

  bool BeevMgr::CheckSolverMap(const ASTNode& key) {
    if(SolverMap.find(key) != SolverMap.end())	
      return true;
    else
      return false;
  } //end of CheckSolverMap()
  
  //update solvermap with (key,value) pair
  bool BeevMgr::UpdateSolverMap(const ASTNode& key, const ASTNode& value) {
    ASTNode var = (BVEXTRACT == key.GetKind()) ? key[0] : key;
    if(!CheckSolverMap(var) && key != value) {
      SolverMap[key] = value;
      return true;
    }  
    return false;
  } //end of UpdateSolverMap()

  //collects the vars in the term 'lhs' into the multiset Vars
  void BVSolver::VarsInTheTerm_TopLevel(const ASTNode& lhs, ASTNodeMultiSet& Vars) {
    TermsAlreadySeenMap.clear();
    VarsInTheTerm(lhs,Vars);
  }

  //collects the vars in the term 'lhs' into the multiset Vars
  void BVSolver::VarsInTheTerm(const ASTNode& term, ASTNodeMultiSet& Vars) {
    ASTNode a = term;
    ASTNodeMap::iterator it;    
    if((it = TermsAlreadySeenMap.find(term)) != TermsAlreadySeenMap.end()) {
      //if the term has been seen, then simply return
      return;
    }

    switch(term.GetKind()) {
    case BVCONST:
      return;
    case SYMBOL:
      //cerr << "debugging: symbol added: " << term << endl;
      Vars.insert(term);
      break;
    case READ:
      //skip the arrayname, provided the arrayname is a SYMBOL
      if(SYMBOL == term[0].GetKind()) {
	VarsInTheTerm(term[1],Vars);
      }
      else {
	VarsInTheTerm(term[0],Vars);
	VarsInTheTerm(term[1],Vars);
      }
      break;
    default: {
      ASTVec c = term.GetChildren();
      for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) {
	  VarsInTheTerm(*it,Vars);	  
      }
      break;
    }
    }

    //ensures that you don't double count. if you have seen the term
    //once, then memoize
    TermsAlreadySeenMap[term] = ASTTrue;
    return;
  } //end of VarsInTheTerm()  

  bool BVSolver::DoNotSolveThis(const ASTNode& var) {
    if(DoNotSolve_TheseVars.find(var) != DoNotSolve_TheseVars.end()) {
      return true;
    }
    return false;
  }

  //chooses a variable in the lhs and returns the chosen variable
  ASTNode BVSolver::ChooseMonom(const ASTNode& eq, ASTNode& modifiedlhs) {
    if(!(EQ == eq.GetKind() && BVPLUS == eq[0].GetKind())) {
      FatalError("ChooseMonom: input must be a EQ",eq);
    }

    ASTNode lhs = eq[0];
    ASTNode rhs = eq[1];
    ASTNode zero = _bm->CreateZeroConst(32);

    //collect all the vars in the lhs and rhs
    ASTNodeMultiSet Vars;
    VarsInTheTerm_TopLevel(lhs,Vars);

    //handle BVPLUS case
    ASTVec c = lhs.GetChildren();
    ASTVec o;    
    ASTNode outmonom = _bm->CreateNode(UNDEFINED);
    bool chosen_symbol = false;
    bool chosen_odd = false;

    //choose variables with no coeffs
    for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) {
      ASTNode monom = *it;
      if(SYMBOL == monom.GetKind() &&
	 Vars.count(monom) == 1    &&	 
	 !_bm->VarSeenInTerm(monom,rhs) &&
	 !DoNotSolveThis(monom)   &&
	 !chosen_symbol) {
	outmonom = monom;
	chosen_symbol = true;
      }
      else if(BVUMINUS == monom.GetKind()  &&
	      SYMBOL == monom[0].GetKind() &&
	      Vars.count(monom[0]) == 1    &&
	      !DoNotSolveThis(monom[0])   &&
	      !_bm->VarSeenInTerm(monom[0],rhs) &&
	      !chosen_symbol) {
	//cerr << "Chosen Monom: " << monom << endl;
	outmonom = monom;
	chosen_symbol = true;
      }
      else {
	o.push_back(monom);
      }
    }

    //try to choose only odd coeffed variables first
    if(!chosen_symbol) {
      o.clear();
      for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) {
	ASTNode monom = *it;
	ASTNode var = (BVMULT == monom.GetKind()) ? monom[1] : _bm->CreateNode(UNDEFINED);

	if(BVMULT == monom.GetKind()     && 
	   BVCONST == monom[0].GetKind() &&
	   _bm->BVConstIsOdd(monom[0])   &&
	   ((SYMBOL == var.GetKind()  && 
	     Vars.count(var) == 1) 
	    || 
	    (BVEXTRACT == var.GetKind()  && 
	     SYMBOL == var[0].GetKind()  && 
	     BVCONST == var[1].GetKind() && 
	     zero == var[2] && 
	     !_bm->VarSeenInTerm(var[0],rhs) &&
	     !DoNotSolveThis(var[0]))	    
	    ) &&
	   !DoNotSolveThis(var)     &&
	   !_bm->VarSeenInTerm(var,rhs)  &&
	   !chosen_odd) {
	  //monom[0] is odd.
	  outmonom = monom;
	  chosen_odd = true;
	}
	else {
	o.push_back(monom);
	}
      }
    }

    modifiedlhs = (o.size() > 1) ? _bm->CreateTerm(BVPLUS,lhs.GetValueWidth(),o) : o[0];
    return outmonom;
  } //end of choosemonom()

  //solver function which solves for variables with odd coefficient
  ASTNode BVSolver::BVSolve_Odd(const ASTNode& input) {
    ASTNode eq = input;
    //cerr << "Input to BVSolve_Odd()" << eq << endl;
    if(!(wordlevel_solve && EQ == eq.GetKind())) {
      return input;
    }

    ASTNode output = input;
    if(CheckAlreadySolvedMap(input,output)) {
      return output;
    }

    //get the lhs and the rhs, and case-split on the lhs kind
    ASTNode lhs = eq[0];
    ASTNode rhs = eq[1];
    if(BVPLUS == lhs.GetKind()) {
      ASTNode chosen_monom = _bm->CreateNode(UNDEFINED);
      ASTNode leftover_lhs;

      //choose monom makes sure that it gets only those vars that
      //occur exactly once in lhs and rhs put together
      chosen_monom = ChooseMonom(eq, leftover_lhs);
      if(chosen_monom == _bm->CreateNode(UNDEFINED)) {
	//no monomial was chosen
	return eq;
      }
      
      //if control is here then it means that a monom was chosen
      //
      //construct:  rhs - (lhs without the chosen monom)
      unsigned int len = lhs.GetValueWidth();
      leftover_lhs = _bm->SimplifyTerm_TopLevel(_bm->CreateTerm(BVUMINUS,len,leftover_lhs));      
      ASTNode newrhs = _bm->SimplifyTerm(_bm->CreateTerm(BVPLUS,len,rhs,leftover_lhs));
      lhs = chosen_monom;
      rhs = newrhs;
    } //end of if(BVPLUS ...)

    if(BVUMINUS == lhs.GetKind()) {
      //equation is of the form (-lhs0) = rhs
      ASTNode lhs0 = lhs[0];
      rhs = _bm->SimplifyTerm(_bm->CreateTerm(BVUMINUS,rhs.GetValueWidth(),rhs));
      lhs = lhs0;      
    }

    switch(lhs.GetKind()) {
    case SYMBOL: {     
      //input is of the form x = rhs first make sure that the lhs
      //symbol does not occur on the rhs or that it has not been
      //solved for
      if(_bm->VarSeenInTerm(lhs,rhs)) {
	//found the lhs in the rhs. Abort!
	DoNotSolve_TheseVars.insert(lhs);
	return eq;
      }
      
      //rhs should not have arrayreads in it. it complicates matters
      //during transformation
      // if(CheckForArrayReads_TopLevel(rhs)) {
      //       	return eq;
      //       }

      DoNotSolve_TheseVars.insert(lhs);
      if(!_bm->UpdateSolverMap(lhs,rhs)) {
	return eq;
      }

      output = ASTTrue;
      break;
    }
    case BVEXTRACT: {
      ASTNode zero = _bm->CreateZeroConst(32);
      
      if(!(SYMBOL == lhs[0].GetKind()  && 
      	   BVCONST == lhs[1].GetKind() && 
      	   zero == lhs[2] && 
      	   !_bm->VarSeenInTerm(lhs[0],rhs) &&
      	   !DoNotSolveThis(lhs[0]))) {
      	return eq;
      }
      
      if(_bm->VarSeenInTerm(lhs[0],rhs)) {
      	DoNotSolve_TheseVars.insert(lhs[0]);
      	return eq;
      }
      
      DoNotSolve_TheseVars.insert(lhs[0]);
      if(!_bm->UpdateSolverMap(lhs,rhs)) {
      	return eq;
      }

      //if the extract of x[i:0] = t is entered into the solvermap,
      //then also add another entry for x = x1@t
      ASTNode var = lhs[0];
      ASTNode newvar = NewVar(var.GetValueWidth() - lhs.GetValueWidth());
      newvar = _bm->CreateTerm(BVCONCAT,var.GetValueWidth(),newvar,rhs);
      _bm->UpdateSolverMap(var,newvar);      
      output = ASTTrue;
      break;
    }
    case BVMULT: {
      //the input is of the form a*x = t. If 'a' is odd, then compute
      //its multiplicative inverse a^-1, multiply 't' with it, and
      //update the solver map
      if(BVCONST != lhs[0].GetKind()) {
	return eq;
      }
      
      if(!(SYMBOL == lhs[1].GetKind() ||
	   (BVEXTRACT == lhs[1].GetKind() &&
	   SYMBOL == lhs[1][0].GetKind()))) {
	return eq;
      }

      bool ChosenVar_Is_Extract = (BVEXTRACT == lhs[1].GetKind()) ? true : false;

      //if coeff is even, then we know that all the coeffs in the eqn
      //are even. Simply return the eqn
      if(!_bm->BVConstIsOdd(lhs[0])) {
	return eq;
      }

      ASTNode a = _bm->MultiplicativeInverse(lhs[0]);
      ASTNode chosenvar = (BVEXTRACT == lhs[1].GetKind()) ? lhs[1][0] : lhs[1];
      ASTNode chosenvar_value = 
	_bm->SimplifyTerm(_bm->CreateTerm(BVMULT,rhs.GetValueWidth(),a,rhs));
      
      //if chosenvar is seen in chosenvar_value then abort
      if(_bm->VarSeenInTerm(chosenvar,chosenvar_value)) {
	//abort solving
	DoNotSolve_TheseVars.insert(lhs);
	return eq;
      }

      //rhs should not have arrayreads in it. it complicates matters
      //during transformation
      // if(CheckForArrayReads_TopLevel(chosenvar_value)) {
      //       	return eq;
      //       }
            
      //found a variable to solve
      DoNotSolve_TheseVars.insert(chosenvar);
      chosenvar = lhs[1];
      if(!_bm->UpdateSolverMap(chosenvar,chosenvar_value)) {
	return eq;
      }

      if(ChosenVar_Is_Extract) {
	ASTNode var = lhs[1][0];
	ASTNode newvar = NewVar(var.GetValueWidth() - lhs[1].GetValueWidth());
	newvar = _bm->CreateTerm(BVCONCAT,var.GetValueWidth(),newvar,chosenvar_value);
	_bm->UpdateSolverMap(var,newvar);
      }
      output = ASTTrue;
      break;
    }    
    default:
      output = eq;
      break;
    }
    
    UpdateAlreadySolvedMap(input,output);
    return output;
  } //end of BVSolve_Odd()

  //Create a new variable of ValueWidth 'n'
  ASTNode BVSolver::NewVar(unsigned int n) {
    std:: string c("v");
    char d[32];
    sprintf(d,"%d",_symbol_count++);
    std::string ccc(d);
    c += "_solver_" + ccc;
    
    ASTNode CurrentSymbol = _bm->CreateSymbol(c.c_str());
    CurrentSymbol.SetValueWidth(n);
    CurrentSymbol.SetIndexWidth(0);
    return CurrentSymbol;
  } //end of NewVar()

  //The toplevel bvsolver(). Checks if the formula has already been
  //solved. If not, the solver() is invoked. If yes, then simply drop
  //the formula
  ASTNode BVSolver::TopLevelBVSolve(const ASTNode& input) {
    if(!wordlevel_solve) {
      return input;
    }
    
    Kind k = input.GetKind();
    if(!(EQ == k || AND == k)) {
      return input;
    }

    ASTNode output = input;
    if(CheckAlreadySolvedMap(input,output)) {
      //output is TRUE. The formula is thus dropped
      return output;
    }
    ASTVec o;
    ASTVec c;
    if(EQ == k) 
      c.push_back(input);
    else 
      c = input.GetChildren();
    ASTVec eveneqns;
    ASTNode solved = ASTFalse;
    for(ASTVec::iterator it = c.begin(), itend = c.end();it != itend;it++) { 
      //_bm->ASTNodeStats("Printing before calling simplifyformula inside the solver:", *it);
      ASTNode aaa = (ASTTrue == solved && EQ == it->GetKind()) ? _bm->SimplifyFormula(*it,false) : *it;
      //ASTNode aaa = *it;
      //_bm->ASTNodeStats("Printing after calling simplifyformula inside the solver:", aaa);
      aaa = BVSolve_Odd(aaa);
      //_bm->ASTNodeStats("Printing after oddsolver:", aaa);
      bool even = false;
      aaa = CheckEvenEqn(aaa, even);
      if(even) {
	eveneqns.push_back(aaa);
      }
      else {
	if(ASTTrue != aaa) {
	  o.push_back(aaa);
	}
      }
      solved = aaa;
    }

    ASTNode evens;
    if(eveneqns.size() > 0) {
      //if there is a system of even equations then solve them
      evens = (eveneqns.size() > 1) ? _bm->CreateNode(AND,eveneqns) : eveneqns[0];
      //evens = _bm->SimplifyFormula(evens,false);
      evens = BVSolve_Even(evens);
      _bm->ASTNodeStats("Printing after evensolver:", evens);
    }
    else {
      evens = ASTTrue;
    }
    output = (o.size() > 0) ? ((o.size() > 1) ? _bm->CreateNode(AND,o) : o[0]) : ASTTrue;
    output = _bm->CreateNode(AND,output,evens);

    UpdateAlreadySolvedMap(input,output);
    return output;
  } //end of TopLevelBVSolve()

  ASTNode BVSolver::CheckEvenEqn(const ASTNode& input, bool& evenflag) {
    ASTNode eq = input;
    //cerr << "Input to BVSolve_Odd()" << eq << endl;
    if(!(wordlevel_solve && EQ == eq.GetKind())) {
      evenflag = false;
      return eq;
    }

    ASTNode lhs = eq[0];
    ASTNode rhs = eq[1];
    ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth());
    //lhs must be a BVPLUS, and rhs must be a BVCONST
    if(!(BVPLUS == lhs.GetKind() && zero == rhs)) {
      evenflag = false;
      return eq;
    }
    
    ASTVec lhs_c = lhs.GetChildren();
    ASTNode savetheconst = rhs;
    for(ASTVec::iterator it=lhs_c.begin(),itend=lhs_c.end();it!=itend;it++) {
      ASTNode aaa = *it;
      Kind itk = aaa.GetKind();

      if(BVCONST == itk){
	//check later if the constant is even or not
	savetheconst = aaa;
	continue;
      }
      
      if(!(BVMULT == itk &&
	   BVCONST == aaa[0].GetKind() &&
	   SYMBOL == aaa[1].GetKind() &&
	   !_bm->BVConstIsOdd(aaa[0]))) {
	//If the monomials of the lhs are NOT of the form 'a*x' where
	//'a' is even, then return the false
	evenflag = false;
	return eq;
      }  
    }//end of for loop

    //if control is here then it means that all coeffs are even. the
    //only remaining thing is to check if the constant is even or not
    if(_bm->BVConstIsOdd(savetheconst)) {
      //the constant turned out to be odd. we have UNSAT eqn
      evenflag = false;
      return ASTFalse;
    }
    
    //all is clear. the eqn in even, through and through
    evenflag = true;
    return eq;
  } //end of CheckEvenEqn

  //solve an eqn whose monomials have only even coefficients
  ASTNode BVSolver::BVSolve_Even(const ASTNode& input) {
    if(!wordlevel_solve) {
      return input;
    }

    if(!(EQ == input.GetKind() || AND == input.GetKind())) {
      return input;
    }

    ASTNode output;
    if(CheckAlreadySolvedMap(input,output)) {
      return output;
    }

    ASTVec input_c;
    if(EQ == input.GetKind()) {
      input_c.push_back(input);
    }
    else {
      input_c = input.GetChildren();
    }

    //power_of_2 holds the exponent of 2 in the coeff
    unsigned int power_of_2 = 0;
    //we need this additional variable to find the lowest power of 2
    unsigned int power_of_2_lowest = 0xffffffff;
    //the monom which has the least power of 2 in the coeff
    ASTNode monom_with_best_coeff;
    for(ASTVec::iterator jt=input_c.begin(),jtend=input_c.end();jt!=jtend;jt++) {
      ASTNode eq = *jt;
      ASTNode lhs = eq[0];
      ASTNode rhs = eq[1];
      ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth());
      //lhs must be a BVPLUS, and rhs must be a BVCONST
      if(!(BVPLUS == lhs.GetKind() && zero == rhs)) {
	return input;
      }
    
      ASTVec lhs_c = lhs.GetChildren();
      ASTNode odd;
      for(ASTVec::iterator it=lhs_c.begin(),itend=lhs_c.end();it!=itend;it++) {
	ASTNode aaa = *it;
	Kind itk = aaa.GetKind();
	if(!(BVCONST == itk &&
	     !_bm->BVConstIsOdd(aaa)) &&
	   !(BVMULT == itk &&
	     BVCONST == aaa[0].GetKind() &&
	     SYMBOL == aaa[1].GetKind() &&
	     !_bm->BVConstIsOdd(aaa[0]))) {
	  //If the monomials of the lhs are NOT of the form 'a*x' or 'a'
	  //where 'a' is even, then return the eqn
	  return input;
	}
	
	//we are gauranteed that if control is here then the monomial is
	//of the form 'a*x' or 'a', where 'a' is even
	ASTNode coeff = (BVCONST == itk) ? aaa : aaa[0];
	odd = SplitEven_into_Oddnum_PowerOf2(coeff,power_of_2);
	if(power_of_2  < power_of_2_lowest) {
	  power_of_2_lowest = power_of_2;
	  monom_with_best_coeff = aaa;
	}
	power_of_2 = 0;
      }//end of inner for loop
    } //end of outer for loop    

    //get the exponent
    power_of_2 = power_of_2_lowest;
    
    //if control is here, we are gauranteed that we have chosen a
    //monomial with fewest powers of 2
    ASTVec formula_out;
    for(ASTVec::iterator jt=input_c.begin(),jtend=input_c.end();jt!=jtend;jt++) {
      ASTNode eq = *jt;      
      ASTNode lhs = eq[0];
      ASTNode rhs = eq[1];
      ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth());
      //lhs must be a BVPLUS, and rhs must be a BVCONST
      if(!(BVPLUS == lhs.GetKind() && zero == rhs)) {
	return input;
      }
      
      unsigned len = lhs.GetValueWidth();
      ASTNode hi = _bm->CreateBVConst(32,len-1);
      ASTNode low = _bm->CreateBVConst(32,len - power_of_2);
      ASTNode low_minus_one = _bm->CreateBVConst(32,len - power_of_2 - 1);
      ASTNode low_zero = _bm->CreateZeroConst(32);
      unsigned newlen = len - power_of_2;
      ASTNode two_const = _bm->CreateTwoConst(len);

      unsigned count = power_of_2;
      ASTNode two = two_const;
      while(--count) {
	two = _bm->BVConstEvaluator(_bm->CreateTerm(BVMULT,len,two_const,two));
      }
      ASTVec lhs_c = lhs.GetChildren();
      ASTVec lhs_out;
      for(ASTVec::iterator it=lhs_c.begin(),itend=lhs_c.end();it!=itend;it++) {
	ASTNode aaa = *it;
	Kind itk = aaa.GetKind();
	if(BVCONST == itk) {
	  aaa = _bm->BVConstEvaluator(_bm->CreateTerm(BVDIV,len,aaa,two));
	  aaa = _bm->BVConstEvaluator(_bm->CreateTerm(BVEXTRACT,newlen,aaa,low_minus_one,low_zero));
	}
	else {
	  //it must be of the form a*x
	  ASTNode coeff = _bm->BVConstEvaluator(_bm->CreateTerm(BVDIV,len,aaa[0],two));
	  coeff = _bm->BVConstEvaluator(_bm->CreateTerm(BVEXTRACT,newlen,coeff,low_minus_one,low_zero));
	  ASTNode upper_x, lower_x;
	  //upper_x = _bm->SimplifyTerm(_bm->CreateTerm(BVEXTRACT, power_of_2, aaa[1], hi, low));
	  lower_x = _bm->SimplifyTerm(_bm->CreateTerm(BVEXTRACT, newlen,aaa[1],low_minus_one,low_zero));
	  aaa = _bm->CreateTerm(BVMULT,newlen,coeff,lower_x);
	}
	lhs_out.push_back(aaa);
      }//end of inner forloop()
      rhs = _bm->CreateZeroConst(newlen);
      lhs = _bm->CreateTerm(BVPLUS,newlen,lhs_out);     
      formula_out.push_back(_bm->CreateSimplifiedEQ(lhs,rhs));
    } //end of outer forloop()

    output = 
      (formula_out.size() > 0) ? (formula_out.size() > 1) ? _bm->CreateNode(AND,formula_out) : formula_out[0] : ASTTrue;

    UpdateAlreadySolvedMap(input,output);
    return output;
  } //end of BVSolve_Even()
} //end of namespace BEEV