expr_transform.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file expr_transform.cpp
00004  * 
00005  * Author: Ying Hu, Clark Barrett
00006  * 
00007  * Created: Jun 05 2003
00008  *
00009  * <hr>
00010  * Copyright (C) 2003 by the Board of Trustees of Leland Stanford
00011  * Junior University and by New York University. 
00012  *
00013  * License to use, copy, modify, sell and/or distribute this software
00014  * and its documentation for any purpose is hereby granted without
00015  * royalty, subject to the terms and conditions defined in the \ref
00016  * LICENSE file provided with this distribution.  In particular:
00017  *
00018  * - The above copyright notice and this permission notice must appear
00019  * in all copies of the software and related documentation.
00020  *
00021  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00022  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00023  * 
00024  * <hr>
00025  * 
00026  */
00027 /*****************************************************************************/
00028 
00029 
00030 #include "expr_transform.h"
00031 #include "theory_core.h"
00032 #include "dictionary.h"
00033 #include "hash.h"
00034 #include "command_line_flags.h"
00035 #include "core_proof_rules.h"
00036 
00037 
00038 using namespace std;
00039 using namespace CVCL;
00040 
00041 
00042 ExprTransform::ExprTransform(TheoryCore* core) : d_core(core)
00043 {
00044   d_commonRules = d_core->getCommonRules();  
00045   d_rules = d_core->getCoreRules();
00046 }
00047 
00048 
00049 Theorem ExprTransform::preprocess(const Expr& e)
00050 {
00051   Theorem thm1;
00052   if (d_core->getFlags()["pp-pushneg"].getBool())
00053     thm1 = pushNegation(e);
00054   else
00055     thm1 = d_commonRules->reflexivityRule(e);
00056   thm1 = d_commonRules->transitivityRule(thm1, d_core->simplify(thm1.getRHS()));
00057   if (d_core->getFlags()["ite-ify"].getBool())
00058     thm1 = d_commonRules->transitivityRule(thm1,ite_convert(thm1.getRHS()));
00059   if (d_core->getFlags()["pp-ite"].getBool())
00060     return d_commonRules->transitivityRule(thm1,ite_simplify(thm1.getRHS()));
00061   return thm1;
00062 }
00063 
00064 
00065 Theorem ExprTransform::preprocess(const Theorem& thm)
00066 {
00067   return d_commonRules->iffMP(thm, preprocess(thm.getExpr()));
00068 }
00069 
00070 
00071 // We assume that the cache is initially empty
00072 Theorem ExprTransform::pushNegation(const Expr& e) {
00073   if(e.isTerm()) return d_commonRules->reflexivityRule(e);
00074   Theorem res(pushNegationRec(e, false));
00075   d_pushNegCache.clear();
00076   return res;
00077 }
00078 
00079 
00080 // Recursively descend into the expression e, keeping track of whether
00081 // we are under even or odd number of negations ('neg' == true means
00082 // odd, the context is "negative").
00083 
00084 // Produce a proof of e <==> e' or !e <==> e', depending on whether
00085 // neg is false or true, respectively.
00086 Theorem ExprTransform::pushNegationRec(const Expr& e, bool neg) {
00087   TRACE("pushNegation", "pushNegationRec(", e,
00088         ", neg=" + string(neg? "true":"false") + ") {");
00089   DebugAssert(!e.isTerm(), "pushNegationRec: not boolean e = "+e.toString());
00090   ExprMap<Theorem>::iterator i = d_pushNegCache.find(neg? !e : e);
00091   if(i != d_pushNegCache.end()) { // Found cached result
00092     TRACE("pushNegation", "pushNegationRec [cached] => ", (*i).second, "}");
00093     return (*i).second;
00094   }
00095   // By default, do not rewrite
00096   Theorem res(d_core->reflexivityRule((neg)? !e : e));
00097   if(neg) {
00098     switch(e.getKind()) {
00099       case TRUE: res = d_commonRules->rewriteNotTrue(!e); break;
00100       case FALSE: res = d_commonRules->rewriteNotFalse(!e); break;
00101       case NOT: 
00102         res = pushNegationRec(d_commonRules->rewriteNotNot(!e), false);
00103         break;
00104       case AND:
00105         res = pushNegationRec(d_rules->rewriteNotAnd(!e), false);
00106         break;
00107       case OR: 
00108         res = pushNegationRec(d_rules->rewriteNotOr(!e), false);
00109         break;
00110       case IMPLIES: {
00111         vector<Theorem> thms;
00112         thms.push_back(d_rules->rewriteImplies(e));
00113         res = pushNegationRec
00114           (d_commonRules->substitutivityRule(NOT, thms), true);
00115         break;
00116       }
00117 //       case IFF:
00118 //      // Preserve equivalences to explore structural similarities
00119 //      if(e[0].getKind() == e[1].getKind())
00120 //        res = d_commonRules->reflexivityRule(!e);
00121 //      else
00122 //        res = pushNegationRec(d_commonRules->rewriteNotIff(!e), false);
00123 //         break;
00124       case ITE:
00125         res = pushNegationRec(d_rules->rewriteNotIte(!e), false);
00126         break;
00127 
00128       // Replace LETDECL and CONSTDEF with their definitions.  The
00129       // typechecker makes sure it's type-safe to do so.
00130       case LETDECL: {
00131         vector<Theorem> thms;
00132         thms.push_back(d_rules->rewriteLetDecl(e));
00133         res = pushNegationRec
00134           (d_commonRules->substitutivityRule(NOT, thms), true);
00135         break;
00136       }
00137       case CONSTDEF:
00138       {
00139         vector<Theorem> thms;
00140         thms.push_back(d_rules->rewriteConstDef(e));
00141         res = pushNegationRec
00142           (d_commonRules->substitutivityRule(NOT, thms), true);
00143         break;
00144       }
00145       default:
00146         res = d_commonRules->reflexivityRule(!e);
00147     } // end of switch(e.getKind())
00148   } else { // if(!neg)
00149     switch(e.getKind()) {
00150       case NOT: res = pushNegationRec(e[0], true); break;
00151       case AND:
00152       case OR:
00153       case IFF:
00154       case ITE: {
00155         Op op = e.getOp();
00156         vector<Theorem> thms;
00157         for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i)
00158           thms.push_back(pushNegationRec(*i, false));
00159         res = d_commonRules->substitutivityRule(op, thms);
00160         break;
00161       }
00162       case IMPLIES:
00163         res = pushNegationRec(d_rules->rewriteImplies(e), false);
00164         break;
00165       case LETDECL:
00166         res = pushNegationRec(d_rules->rewriteLetDecl(e), false);
00167         break;
00168       case CONSTDEF:
00169         res = pushNegationRec(d_rules->rewriteConstDef(e), false);
00170         break;
00171       default:
00172         res = d_commonRules->reflexivityRule(e);
00173     } // end of switch(e.getKind())
00174   }
00175   TRACE("pushNegation", "pushNegationRec => ", res, "}");
00176   d_pushNegCache[neg? !e : e] = res;
00177   return res;
00178 }
00179 
00180 
00181 Theorem ExprTransform::pushNegationRec(const Theorem& thm, bool neg) {
00182   DebugAssert(thm.isRewrite(), "pushNegationRec(Theorem): bad theorem: "
00183               + thm.toString());
00184   Expr e(thm.getRHS());
00185   if(neg) {
00186     DebugAssert(e.isNot(), 
00187                 "pushNegationRec(Theorem, neg = true): bad Theorem: "
00188                 + thm.toString());
00189     e = e[0];
00190   }
00191   return d_commonRules->transitivityRule(thm, pushNegationRec(e, neg));
00192 }
00193 
00194 
00195 Theorem ExprTransform::pushNegation1(const Expr& e) {
00196   TRACE("pushNegation1", "pushNegation1(", e, ") {");
00197   DebugAssert(e.isNot(), "pushNegation1("+e.toString()+")");
00198   Theorem res;
00199   switch(e[0].getKind()) {
00200     case TRUE: res = d_commonRules->rewriteNotTrue(e); break;
00201     case FALSE: res = d_commonRules->rewriteNotFalse(e); break;
00202     case NOT: 
00203       res = d_commonRules->rewriteNotNot(e);
00204       break;
00205     case AND:
00206       res = d_rules->rewriteNotAnd(e);
00207       break;
00208     case OR: 
00209       res = d_rules->rewriteNotOr(e);
00210       break;
00211     case IMPLIES: {
00212       vector<Theorem> thms;
00213       thms.push_back(d_rules->rewriteImplies(e[0]));
00214       res = d_commonRules->substitutivityRule(e.getOp(), thms);
00215       res = d_commonRules->transitivityRule(res, d_rules->rewriteNotOr(res.getRHS()));
00216       break;
00217     }
00218     case ITE:
00219       res = d_rules->rewriteNotIte(e);
00220       break;
00221       // Replace LETDECL and CONSTDEF with their definitions.  The
00222       // typechecker makes sure it's type-safe to do so.
00223     case LETDECL: {
00224       vector<Theorem> thms;
00225       thms.push_back(d_rules->rewriteLetDecl(e[0]));
00226       res = d_commonRules->substitutivityRule(e.getOp(), thms);
00227       res = d_commonRules->transitivityRule(res, pushNegation1(res.getRHS()));
00228       break;
00229     }
00230     case CONSTDEF: {
00231       vector<Theorem> thms;
00232       thms.push_back(d_rules->rewriteConstDef(e[0]));
00233       res = d_commonRules->substitutivityRule(e.getOp(), thms);
00234       res = d_commonRules->transitivityRule(res, pushNegation1(res.getRHS()));
00235       break;
00236     }
00237     default:
00238       res = d_commonRules->reflexivityRule(e);
00239   }
00240   TRACE("pushNegation1", "pushNegation1 => ", res.getExpr(), " }");
00241   return res;
00242 }
00243 
00244 
00245 typedef Hash_Table<Expr, Expr> CareSet;
00246 typedef Hash_Ptr<Expr, Expr> CareSetPtr;
00247 typedef Dict<Expr, CareSet*> Queue;
00248 typedef Dict_Ptr<Expr, CareSet*> QueuePtr;
00249 
00250 typedef ExprMap<Theorem> Table;
00251 
00252 static int cf(Expr x, Expr y) { 
00253         return (x.getIndex() < y.getIndex()) ? -1 : (x.getIndex() == y.getIndex()) ? 0 : 1; }  // compare
00254 static size_t hf(const Expr x) { 
00255         return x.getEM()->hash(x);; }                             // hash
00256 static size_t mf(const Expr x, const Expr y) { return x==y; }             // match
00257 
00258 static void update_queue(Queue *q, Expr e, CareSet *cs_prime){
00259   CareSet **cs=q->Fetch(e);
00260 
00261   // if there is already an entry for this expr,
00262   // AND the new careset with the old careset
00263 
00264   if (cs) {
00265     CareSetPtr p(*cs);
00266     while (p!=NULL) {
00267       if (!cs_prime->Fetch(p->Key()) ||
00268           (*cs_prime)[p->Key()]!=p->Data()) {
00269         Expr key=p->Key();
00270         ++p;
00271         (*cs)->Delete(key);
00272       }
00273       else
00274         ++p;
00275     }
00276   }
00277   else
00278     q->Insert(e, new CareSet(*cs_prime));
00279 }
00280 
00281 Theorem ExprTransform::substitute(Expr e, Table *init_st) {
00282   static Table *memoize;
00283   static Table *st;
00284   
00285   // initialize
00286   if (init_st) {
00287     if (memoize) delete memoize;
00288     memoize = new Table();
00289     st = init_st;
00290   }
00291   
00292   // atomic expressions don't change
00293   if(e.isNull() || e.isBoolConst()
00294      || e.isString() || e.isRational())
00295     return d_commonRules->reflexivityRule(e);
00296   
00297   // has the result been memoized
00298   ExprMap<Theorem>::iterator i = memoize->find(e);
00299   if(i != memoize->end()) { // Found cached result
00300     return (*i).second;
00301   }
00302   
00303   // do substitution
00304   i = st->find(e);
00305   if (i != st->end()) {
00306     return d_commonRules->transitivityRule((*i).second, substitute((*i).second.getRHS())); //get the theorem stored by simplifying, and do substitute recursively
00307   }
00308   
00309   // build new expr with all sub-exprs substituted
00310   Theorem thm;
00311   if(e.getKind() != ITE)
00312     thm = d_commonRules->reflexivityRule(e);
00313   else{
00314     vector<Theorem> thms;
00315     vector<unsigned> changed;
00316     Expr tmp;
00317     thm = substitute(e[0]);
00318     if(thm.getRHS() == e[0]){
00319       thm = d_commonRules->reflexivityRule(e);
00320       tmp = e;
00321     }
00322     else{
00323       thms.push_back(thm);
00324       changed.push_back(0);       
00325       thm = d_commonRules->substitutivityRule(e, changed, thms);
00326       tmp = thm.getRHS();
00327     }    
00328     Theorem thm1 = d_rules->rewriteIteThen(tmp, substitute(tmp[1]));
00329     //DebugAssert(thm.getRHS()==thm1.getLHS(), "preprocess: transitivity rule1: " + tmp.toString());
00330     thm = d_commonRules->transitivityRule(thm, thm1);
00331     tmp = thm.getRHS();
00332     thm1 = d_rules->rewriteIteElse(tmp, substitute(tmp[2]));
00333     //DebugAssert(thm.getRHS()==thm1.getLHS(), "preprocess: transitivity rule2: " + tmp.toString());
00334     thm = d_commonRules->transitivityRule(thm, thm1);    
00335   }
00336 
00337   (*memoize)[e] = thm;
00338   return thm;
00339 }
00340 
00341 Theorem ExprTransform::ite_simplify(Expr e){
00342   
00343   Queue q(cf);
00344   Table st;
00345   
00346   // go through all the exprs in reverse topological order
00347   // and build up the substitution table
00348   q.Insert(e, new CareSet(hf, mf));
00349   for (QueuePtr p(&q); p!=NULL; ++p) {
00350     
00351     Expr e = Expr(p->Key());
00352     
00353     if(e.isNull() || e.isBoolConst() || e.isVar() 
00354        || e.isString() || e.isRational() || e.isApply())
00355       continue;
00356 
00357     CareSet cs(*p->Data());
00358     
00359     // free up memory so that we don't run out of the stuff
00360     delete p->Data();
00361     p->Data() = NULL;
00362     
00363     // simplify an ite if its ifpart belongs to the care set
00364     if (e.getKind()==ITE) {
00365       const Expr e1 = Expr(e);
00366       Expr *v = cs.Fetch(e1[0]);
00367       if (v) {
00368         vector<Theorem> thms;
00369         vector<unsigned> changed;
00370         if((*v).isTrue()){
00371           // e1[0] |- e1[0] ==> e1[0] IFF TRUE
00372           Theorem thm0 = d_commonRules->iffTrue(d_commonRules->assumpRule(e1[0]));
00373           thms.push_back(thm0);
00374           changed.push_back(0);   
00375           thm0 = d_commonRules->substitutivityRule(e1, changed, thms);
00376           Theorem thm1 = d_rules->rewriteIteTrue(thm0.getRHS());
00377           thm0 = d_commonRules->transitivityRule(thm0, thm1);
00378           st[e1] = thm0;
00379           if(e1[1].getKind() != TRUE && e1[1].getKind() != FALSE)
00380             update_queue(&q, e1[1], &cs);
00381           continue;
00382         }
00383         else { //v==FALSE
00384           // e1[0] IFF FALSE |- e1[0] IFF FALSE
00385           Theorem thm0 = d_commonRules->assumpRule(e1[0].iffExpr(d_core->falseExpr()));
00386           thms.push_back(thm0);
00387           changed.push_back(0);   
00388           thm0 = d_commonRules->substitutivityRule(e1, changed, thms);
00389           Theorem thm1 = d_rules->rewriteIteFalse(thm0.getRHS());
00390           thm0 = d_commonRules->transitivityRule(thm0, thm1);
00391           st[e1] = thm0;
00392           if(e1[2].getKind() != TRUE && e1[2].getKind() != FALSE)
00393             update_queue(&q, e1[2], &cs);
00394           continue;
00395         }
00396       }
00397     }
00398     // add children to the queue, updating their caresets
00399     // in the case of an ite-expr
00400     if (e.getKind()==ITE) {
00401       CareSet cs_prime(cs);
00402       const Expr ite = Expr(e);
00403       if(ite[0].getKind() != TRUE && ite[0].getKind() != FALSE)
00404         update_queue(&q, ite[0], &cs);
00405       // add if-part==TRUE to the care-set for the then-part
00406       cs_prime.Insert(ite[0], d_core->trueExpr());
00407       if(ite[1].getKind() != TRUE && ite[1].getKind() != FALSE)
00408         update_queue(&q, ite[1], &cs_prime);
00409       // add if-part==FALSE to the care-set for the else-part
00410       cs_prime[ite[0]]=d_core->falseExpr();
00411       if(ite[2].getKind() != TRUE && ite[2].getKind() != FALSE)
00412         update_queue(&q, ite[2], &cs_prime);
00413     }
00414   }
00415   
00416   // perform all the substituations
00417   return substitute(e, &st);
00418 }
00419 
00420 Theorem ExprTransform::ite_convert(const Expr& e){
00421   switch(e.getKind()){
00422   case TRUE:
00423   case FALSE:
00424     return d_commonRules->reflexivityRule(e); break;
00425   case ITE:
00426     {
00427       Theorem thm0 = ite_convert(e[0]);
00428       Theorem thm1 = ite_convert(e[1]);
00429       Theorem thm2 = ite_convert(e[2]);
00430       vector<Theorem> thms;
00431       thms.push_back(thm0);
00432       thms.push_back(thm1);
00433       thms.push_back(thm2);
00434       
00435       return d_commonRules->substitutivityRule(e.getOp(), thms);
00436     }
00437     break;
00438   case NOT:
00439     {
00440       Theorem thm = ite_convert(e[0]);
00441       vector<Theorem> thms;
00442       thms.push_back(thm);
00443       thm = d_commonRules->substitutivityRule(e.getOp(), thms);
00444       return d_commonRules->transitivityRule(thm, d_rules->NotToIte(thm.getRHS()));
00445     }
00446     break;
00447   case AND:
00448     {
00449       DebugAssert(e.arity() > 0, "Expected non-empty AND");
00450       const vector<Expr>& kids = e.getKids();
00451       unsigned i(0), ar(kids.size());
00452       vector<Theorem> thms;
00453       for(; i < ar; i++){
00454         thms.push_back(ite_convert(kids[i]));
00455       }
00456       Theorem thm = d_commonRules->substitutivityRule(e.getOp(), thms);
00457       thm = d_commonRules->transitivityRule(thm, d_rules->AndToIte(thm.getRHS()));
00458       return thm;
00459     }
00460     break;
00461   case OR:
00462     {
00463       DebugAssert(e.arity() > 0, "Expected non-empty OR");
00464       const vector<Expr>& kids = e.getKids();
00465       unsigned i(0), ar(kids.size());
00466       vector<Theorem> thms;
00467       for(; i < ar; i++){
00468         thms.push_back(ite_convert(kids[i]));
00469       }
00470       Theorem thm = d_commonRules->substitutivityRule(e.getOp(), thms);
00471       return d_commonRules->transitivityRule(thm, d_rules->OrToIte(thm.getRHS()));
00472     }
00473     break;
00474   case IMPLIES:
00475     {
00476       vector<Theorem> thms;
00477       thms.push_back(ite_convert(e[0]));
00478       thms.push_back(ite_convert(e[1]));
00479       Theorem thm = d_commonRules->substitutivityRule(e.getOp(), thms);
00480       return d_commonRules->transitivityRule(thm, d_rules->ImpToIte(thm.getRHS()));
00481     }
00482     break;
00483   case IFF:
00484           {
00485             vector<Theorem> thms;
00486             thms.push_back(ite_convert(e[0]));
00487             thms.push_back(ite_convert(e[1]));
00488             Theorem thm = d_commonRules->substitutivityRule(e.getOp(), thms);
00489             return d_commonRules->transitivityRule(thm, d_rules->IffToIte(thm.getRHS()));
00490           }
00491           break;
00492   default:
00493     return d_commonRules->reflexivityRule(e);
00494   }
00495 }
00496 
00497 Expr ExprTransform::ite_reorder(const Expr& e){
00498   switch(e.getKind()){
00499   case TRUE:
00500   case FALSE:
00501     return e; break;
00502   case ITE:
00503     {
00504       int x = random(); // 2 ^ 30 = 1073741824
00505       if(x < 1073741824)
00506         return ite_reorder(e[0]).iteExpr(ite_reorder(e[1]), ite_reorder(e[2]));
00507       if(e[0].isTrue()){
00508         return ite_reorder(e[1]);
00509       }
00510       else if(e[0].isFalse()){
00511         return ite_reorder(e[2]);
00512       }
00513       else if(e[1].isTrue())
00514         return ite_reorder(e[2]).iteExpr(e[1], ite_reorder(e[0]));
00515       else if(e[1].isFalse() && e[2].isTrue())
00516         return ite_reorder(e[0]).iteExpr(e[1], e[2]);
00517       else if(e[1].isFalse()){
00518         Expr e0 = ite_reorder(e[2]);
00519         if(e0.isTrue())
00520           return getNeg(ite_reorder(e[0]));
00521         else if(e0.isFalse())
00522           return e[1];
00523         else
00524           return getNeg(e0).iteExpr(e[1], getNeg(ite_reorder(e[0])));
00525       }
00526       else if(e[2].isTrue()){
00527         Expr e0 = ite_reorder(e[1]);
00528         if(e0.isTrue())
00529           return e[2];
00530         else if(e0.isFalse())
00531           return getNeg(ite_reorder(e[0])) ;
00532         else
00533           return getNeg(e0).iteExpr(getNeg(ite_reorder(e[0])), e[2]);
00534       }
00535       else if(e[2].isFalse()){
00536         Expr e0 = ite_reorder(e[1]);
00537         if(e0.isTrue())
00538           return ite_reorder(e[0]);
00539         else if(e0.isFalse())
00540           return e[2];
00541         else
00542           return e0.iteExpr(ite_reorder(e[0]), e[2]);
00543       }
00544       else{
00545         Expr e0 = getNeg(ite_reorder(e[0]));
00546         if(e0.isTrue())
00547           return ite_reorder(e[2]);
00548         else if(e0.isFalse())
00549           return ite_reorder(e[1]);
00550         else
00551           return e0.iteExpr(ite_reorder(e[2]), ite_reorder(e[1]));
00552       }
00553     }
00554     break;
00555   default:
00556     return e;
00557   } 
00558 }
00559 
00560 Expr ExprTransform::getNeg(const Expr& e){
00561   switch(e.getKind()){
00562   case TRUE:
00563     return d_core->falseExpr(); break;
00564   case FALSE:
00565     return d_core->trueExpr(); break;
00566   case ITE:
00567     {
00568       if(e[1].isFalse() && e[2].isTrue())
00569         return e[0];
00570       else
00571         return e.iteExpr(d_core->falseExpr(), d_core->trueExpr());
00572     }
00573     break;
00574   default:
00575     return e.iteExpr(d_core->falseExpr(), d_core->trueExpr());
00576   }
00577 }
00578 
00579 

Generated on Thu Apr 13 16:57:31 2006 for CVC Lite by  doxygen 1.4.4