common_theorem_producer.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  *\file common_theorem_producer.cpp
00004  *\brief Implementation of common proof rules
00005  *
00006  * Author: Clark Barrett
00007  *
00008  * Created: Wed Jan 11 16:10:15 2006
00009  *
00010  * <hr>
00011  * Copyright (C) 2006 by the Board of Trustees of Leland Stanford
00012  * Junior University and by New York University. 
00013  *
00014  * License to use, copy, modify, sell and/or distribute this software
00015  * and its documentation for any purpose is hereby granted without
00016  * royalty, subject to the terms and conditions defined in the \ref
00017  * LICENSE file provided with this distribution.  In particular:
00018  *
00019  * - The above copyright notice and this permission notice must appear
00020  * in all copies of the software and related documentation.
00021  *
00022  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00023  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00024  * 
00025  * <hr>
00026  *
00027  */
00028 /*****************************************************************************/
00029 
00030 
00031 // This code is trusted
00032 #define _CVCL_TRUSTED_
00033 
00034 
00035 #include "common_theorem_producer.h"
00036 
00037 
00038 using namespace CVCL;
00039 using namespace std;
00040 
00041 
00042 // The trusted method of TheoremManager which creates this theorem producer
00043 CommonProofRules* TheoremManager::createProofRules() {
00044   return new CommonTheoremProducer(this);
00045 }
00046 
00047 
00048 CommonTheoremProducer::CommonTheoremProducer(TheoremManager* tm)
00049   : TheoremProducer(tm),
00050     d_skolemized_thms(tm->getCM()->getCurrentContext()),
00051     d_skolemVars(tm->getCM()->getCurrentContext())
00052 {}
00053 
00054 
00055 Theorem CommonTheoremProducer::assumpRule(const Expr& e, int scope) {
00056   TRACE("assump", "assumpRule(", e, ")");
00057   Proof pf;
00058   if(withProof()) pf = newLabel(e);
00059   return newAssumption(e, pf, scope);
00060 }
00061 
00062 
00063 Theorem CommonTheoremProducer::reflexivityRule(const Expr& a) {
00064   Proof pf;
00065   if(withProof()) {
00066     Type t = a.getType();
00067     if(CHECK_PROOFS)
00068       CHECK_SOUND(!t.isNull(),
00069                   "reflexivityRule: 'a' has no type: " + a.toString());
00070     bool useIff = (t.isBool());
00071     pf = newPf(useIff? "iff_refl" : "eq_refl", t.getExpr(), a);
00072   }
00073   return newReflTheorem(a, pf);
00074 }
00075 
00076 
00077 // ==> (a == a) IFF TRUE
00078 Theorem CommonTheoremProducer::rewriteReflexivity(const Expr& t) {
00079   if(CHECK_PROOFS)
00080     CHECK_SOUND((t.isEq() || t.isIff()) && t[0] == t[1],
00081                 "rewriteReflexivity: wrong expression: "
00082                 + t.toString());
00083   Assumptions a;
00084   Proof pf;
00085   if(withProof()) {
00086     if(t.isEq()) {
00087       DebugAssert(!t[0].getType().isNull(),
00088                   "rewriteReflexivity: t[0] has no type: "
00089                   + t[0].toString());
00090       pf = newPf("rewrite_eq_refl", t[0].getType().getExpr(), t[0]);
00091     } else
00092       pf = newPf("rewrite_iff_refl", t[0]);
00093   }
00094   return newRWTheorem(t, d_em->trueExpr(), a, pf);
00095 }
00096 
00097 
00098 Theorem CommonTheoremProducer::symmetryRule(const Theorem& a1_eq_a2) {
00099   if(CHECK_PROOFS)
00100     CHECK_SOUND(a1_eq_a2.isRewrite(),
00101                 ("CVCL::CommonTheoremProducer: "
00102                  "theorem is not an equality or iff:\n  "
00103                  + a1_eq_a2.getExpr().toString()).c_str());
00104   const Expr& a1 = a1_eq_a2.getLHS();
00105   const Expr& a2 = a1_eq_a2.getRHS();
00106 
00107   Proof pf;
00108   Assumptions a;
00109   /////////////////////////////////////////////////////////////////////////
00110   //// Proof compaction
00111   /////////////////////////////////////////////////////////////////////////
00112   // If a1 == a2, use reflexivity
00113   if(a1 == a2) return reflexivityRule(a1);
00114   // Otherwise, do the work
00115   if (withAssumptions()) a = a1_eq_a2.getAssumptionsCopy();
00116   if(withProof()) {
00117     Type t = a1.getType();
00118     // Check the types
00119     IF_DEBUG(a1_eq_a2.getExpr().getType());
00120     bool isEquality = !t.isBool();
00121     if(isEquality) {
00122       vector<Expr> args;
00123       args.push_back(t.getExpr());
00124       args.push_back(a1);
00125       args.push_back(a2);
00126       pf = newPf("eq_symm", args, a1_eq_a2.getProof());
00127     } else
00128       pf = newPf("iff_symm", a1, a2, a1_eq_a2.getProof());
00129   }
00130   return newRWTheorem(a2, a1, a, pf);
00131 }
00132 
00133 
00134 Theorem CommonTheoremProducer::rewriteUsingSymmetry(const Expr& a1_eq_a2) {
00135   bool isIff = a1_eq_a2.isIff();
00136   if(CHECK_PROOFS)
00137     CHECK_SOUND(a1_eq_a2.isEq() || isIff, "rewriteUsingSymmetry precondition violated");
00138   const Expr& a1 = a1_eq_a2[0];
00139   const Expr& a2 = a1_eq_a2[1];
00140   // Proof compaction: if a1 == a2, use reflexivity
00141   if(a1 == a2) return reflexivityRule(a1_eq_a2);
00142   // Otherwise, do the work
00143   Assumptions assump; // No assumptions, leave it Null
00144   Proof pf;
00145   if(withProof()) {
00146     Type t = a1.getType();
00147     DebugAssert(!t.isNull(),
00148                 "rewriteUsingSymmetry: a1 has no type: " + a1.toString());
00149     if(isIff)
00150       pf = newPf("rewrite_iff_symm", a1, a2);
00151     else {
00152       pf = newPf("rewrite_eq_symm", t.getExpr(), a1, a2);
00153     }
00154   }
00155   return newRWTheorem(a1_eq_a2, isIff ? a2.iffExpr(a1) : a2.eqExpr(a1), assump, pf);
00156 }
00157 
00158 
00159 Theorem CommonTheoremProducer::transitivityRule(const Theorem& a1_eq_a2,
00160                                           const Theorem& a2_eq_a3) {
00161   DebugAssert(!a1_eq_a2.isNull(), "transitivityRule()");
00162   DebugAssert(!a2_eq_a3.isNull(), "transitivityRule()");
00163   if(CHECK_PROOFS) {
00164     CHECK_SOUND(a1_eq_a2.isRewrite() && a2_eq_a3.isRewrite(),  
00165                 "CVCL::CommonTheoremProducer::transitivityRule:\n  "
00166                 "Wrong premises: first = "
00167                 + a1_eq_a2.getExpr().toString() + ", second = "
00168                 + a2_eq_a3.getExpr().toString());
00169     CHECK_SOUND(a1_eq_a2.getRHS() == a2_eq_a3.getLHS(),
00170                 "CVCL::CommonTheoremProducer::transitivityRule:\n  "
00171                 "Wrong premises: first = "
00172                 + a1_eq_a2.getExpr().toString() + ", second = "
00173                 + a2_eq_a3.getExpr().toString());
00174   }
00175   const Expr& a1 = a1_eq_a2.getLHS();
00176   const Expr& a2 = a1_eq_a2.getRHS();
00177   const Expr& a3 = a2_eq_a3.getRHS();
00178 
00179   /////////////////////////////////////////////////////////////////////////
00180   //// Proof compaction
00181   /////////////////////////////////////////////////////////////////////////
00182   // if a1 == a3, use reflexivity (and lose all assumptions)
00183   if(a1 == a3) return reflexivityRule(a1);
00184   // if a1 == a2, or if a2 == a3, use only the non-trivial part
00185   if(a1 == a2) return a2_eq_a3;
00186   if(a2 == a3) return a1_eq_a2;
00187 
00188   ////////////////////////////////////////////////////////////////////////
00189   //// No shortcuts.  Do the work.
00190   ////////////////////////////////////////////////////////////////////////
00191 
00192   Assumptions a;
00193   Proof pf;
00194   // Merge the assumptions
00195   if(withAssumptions())
00196     a = merge(a1_eq_a2, a2_eq_a3);
00197   // Build the proof
00198   if(withProof()) {
00199     Type t = a1.getType();
00200     bool isEquality = (!t.isBool());
00201     string name((isEquality)? "eq_trans" : "iff_trans");
00202     vector<Expr> args;
00203     vector<Proof> pfs;
00204     DebugAssert(!t.isNull(), "transitivityRule: "
00205                 "Type is not computed for a1: " + a1.toString());
00206     // Type argument is needed only for equality
00207     if(isEquality) args.push_back(t.getExpr());
00208     args.push_back(a1);
00209     args.push_back(a2);
00210     args.push_back(a3);
00211     pfs.push_back(a1_eq_a2.getProof());
00212     pfs.push_back(a2_eq_a3.getProof());
00213     pf = newPf(name, args, pfs);
00214   }
00215   return newRWTheorem(a1, a3, a, pf);
00216 }
00217 
00218 
00219 Theorem CommonTheoremProducer::substitutivityRule(const Op& op,
00220                                                   const vector<Theorem>& thms) {
00221   IF_DEBUG
00222     (static DebugTimer
00223        accum0(debugger.timer("substitutivityRule time"));
00224      static DebugTimer tmpTimer(debugger.newTimer());
00225      static DebugCounter count(debugger.counter("substitutivityRule calls"));
00226      debugger.setCurrentTime(tmpTimer);
00227      count++);
00228   // Check for trivial case: no theorems, return (op == op)
00229   unsigned size(thms.size());
00230   if(size == 0)
00231     return reflexivityRule(d_tm->getEM()->newLeafExpr(op));
00232   // Check that theorems are of the form c_i == d_i and collect
00233   // vectors of c_i's and d_i's and the vector of proofs
00234   vector<Expr> c, d;
00235   vector<Proof> pfs;
00236   // Reserve memory for argument vectors.  Do not reserve memory for
00237   // pfs, they are rarely used and slow anyway.
00238   c.reserve(size); d.reserve(size);
00239   for(vector<Theorem>::const_iterator i = thms.begin(), iend = thms.end();
00240       i != iend; ++i) {
00241     // Check that t is c == d or c IFF d
00242     if(CHECK_PROOFS)
00243       CHECK_SOUND(i->isRewrite(),
00244                   "CVCL::CommonTheoremProducer::substitutivityRule:\n  "
00245                   "premis is not an equality or IFF: "
00246                   + i->getExpr().toString()
00247                   + "\n  op = " + op.toString());
00248     // Collect the pieces
00249     c.push_back(i->getLHS());
00250     d.push_back(i->getRHS());
00251     if(withProof()) pfs.push_back(i->getProof());
00252   }
00253   Expr e1(op, c), e2(op, d);
00254   // Proof compaction: if e1 == e2, use reflexivity
00255   if(e1 == e2) return reflexivityRule(e1);
00256   // Otherwise, do the work
00257   Assumptions a;
00258   Proof pf;
00259   if(withAssumptions()) a = merge(thms);
00260   if(withProof())
00261     // FIXME: this rule is not directly expressible in flea
00262     pf = newPf("basic_subst_op",e1,e2,pfs);
00263   Theorem res = newRWTheorem(e1, e2, a, pf);
00264   IF_DEBUG(debugger.setElapsed(tmpTimer);
00265            accum0 += tmpTimer);
00266   return res;
00267 }
00268 
00269 
00270 Theorem CommonTheoremProducer::substitutivityRule(const Expr& e,
00271                                                   const vector<unsigned>& changed,
00272                                                   const vector<Theorem>& thms) {
00273   IF_DEBUG
00274     (static DebugTimer
00275        accum0(debugger.timer("substitutivityRule2 time"));
00276      static DebugTimer tmpTimer(debugger.newTimer());
00277      static DebugCounter count(debugger.counter("substitutivityRule2 calls"));
00278      debugger.setCurrentTime(tmpTimer);
00279      count++);
00280   unsigned csize = changed.size();
00281   DebugAssert(csize > 0, "substitutivityRule2 should not be called");
00282   DebugAssert(csize == thms.size(), "substitutivityRule2: wrong args");
00283 
00284   // Check that theorems are of the form c_i == d_i and collect
00285   // vectors of c_i's and d_i's and the vector of proofs
00286   unsigned size = e.arity();
00287   DebugAssert(size >= csize, "Bad call to substitutivityRule2");
00288   vector<Expr> c;
00289   bool checkProofs(CHECK_PROOFS);
00290   for(unsigned j = 0, k = 0; k < size; ++k) {
00291     if (j == csize || changed[j] != k) {
00292       c.push_back(e[k]);
00293       continue;
00294     }
00295     // Check that t is c == d or c IFF d
00296     if(checkProofs)
00297       CHECK_SOUND(thms[j].isRewrite() && thms[j].getLHS() == e[k],
00298                   "CVCL::CommonTheoremProducer::substitutivityRule:\n  "
00299                   "premis is not an equality or IFF: "
00300                   + thms[j].getExpr().toString()
00301                   + "\n  e = " + e.toString());
00302     // Collect the pieces
00303     c.push_back(thms[j].getRHS());
00304     ++j;
00305   }
00306   Expr e2(e.getOp(), c);
00307   IF_DEBUG(if(e == e2) {
00308     ostream& os = debugger.getOS();
00309     os << "substitutivityRule2: e = " << e << "\n e2 = " << e2
00310        << "\n changed kids: [\n";
00311     for(unsigned j=0; j<changed.size(); j++)
00312       os << "  (" << changed[j] << ") " << thms[j] << "\n";
00313     os << "]\n";
00314   });
00315   DebugAssert(e != e2,
00316               "substitutivityRule2 should not be called in this case:\n"
00317               "e = "+e.toString());
00318 
00319   Assumptions a;
00320   Proof pf;
00321   if(withAssumptions()) a = merge(thms);
00322   vector<Proof> pfs;
00323   if(withProof())
00324     for(vector<Theorem>::const_iterator i = thms.begin(), iend = thms.end();
00325         i != iend; ++i) {
00326       // Check that t is c == d or c IFF d
00327       if(CHECK_PROOFS)
00328         CHECK_SOUND(i->isRewrite(),
00329                     "CVCL::CommonTheoremProducer::substitutivityRule:\n  "
00330                     "premis is not an equality or IFF: "
00331                     + i->getExpr().toString());
00332                     // + "\n  op = " + ((Op) e.getOp).toString());
00333       pfs.push_back(i->getProof());
00334       pf = newPf("optimized_subst_op",e,e2,pfs);
00335   }
00336   Theorem res = newRWTheorem(e, e2, a, pf);
00337   IF_DEBUG(debugger.setElapsed(tmpTimer);
00338            accum0 += tmpTimer);
00339   return res;
00340 }
00341 
00342 
00343 // |- e,  |- !e ==> |- FALSE
00344 Theorem CommonTheoremProducer::contradictionRule(const Theorem& e,
00345                                                  const Theorem& not_e) {
00346   Assumptions a;
00347   Proof pf;
00348   if(CHECK_PROOFS)
00349     CHECK_SOUND(!e.getExpr() == not_e.getExpr(),
00350                 "CommonTheoremProducer::contraditionRule: "
00351                 "theorems don't match:\n e = "+e.toString()
00352                 +"\n not_e = "+not_e.toString());
00353   if(withAssumptions()) a = merge(e, not_e);
00354   if(withProof()) {
00355     vector<Proof> pfs;
00356     pfs.push_back(e.getProof());
00357     pfs.push_back(not_e.getProof());
00358     pf = newPf("contradition", e.getExpr(), pfs);
00359   }
00360   return newTheorem(d_em->falseExpr(), a, pf);
00361 }
00362 
00363 
00364 // e ==> e IFF TRUE
00365 Theorem CommonTheoremProducer::iffTrue(const Theorem& e)
00366 {
00367   Assumptions a;
00368   Proof pf;
00369   if (withAssumptions()) a = e.getAssumptions().copy();
00370   if(withProof()) {
00371     pf = newPf("iff_true", e.getExpr(), e.getProof());
00372   }
00373   return newRWTheorem(e.getExpr(), d_em->trueExpr(), a, pf);
00374 }
00375 
00376 
00377 // e ==> !e IFF FALSE
00378 Theorem CommonTheoremProducer::iffNotFalse(const Theorem& e) {
00379   Assumptions a;
00380   Proof pf;
00381   if (withAssumptions()) a = e.getAssumptions().copy();
00382   if(withProof()) {
00383     pf = newPf("iff_not_false", e.getExpr(), e.getProof());
00384   }
00385   return newRWTheorem(!e.getExpr(), d_em->falseExpr(), a, pf);
00386 }
00387 
00388 
00389 // e IFF TRUE ==> e
00390 Theorem CommonTheoremProducer::iffTrueElim(const Theorem& e) {
00391   if(CHECK_PROOFS)
00392     CHECK_SOUND(e.isRewrite() && e.getRHS().isTrue(),
00393                 "CommonTheoremProducer::iffTrueElim: "
00394                 "theorem is not e<=>TRUE: "+ e.toString());
00395   Assumptions a;
00396   Proof pf;
00397   if (withAssumptions()) a = e.getAssumptions().copy();
00398   if(withProof()) {
00399     pf = newPf("iff_true_elim", e.getLHS(), e.getProof());
00400   }
00401   return newTheorem(e.getLHS(), a, pf);
00402 }
00403 
00404 
00405 // e IFF FALSE ==> !e
00406 Theorem CommonTheoremProducer::iffFalseElim(const Theorem& e) {
00407   if(CHECK_PROOFS)
00408     CHECK_SOUND(e.isRewrite() && e.getRHS().isFalse(),
00409                 "CommonTheoremProducer::iffFalseElim: "
00410                 "theorem is not e<=>FALSE: "+ e.toString());
00411   const Expr& lhs = e.getLHS();
00412   Assumptions a;
00413   Proof pf;
00414   if (withAssumptions()) a = e.getAssumptions().copy();
00415   if(withProof()) {
00416     pf = newPf("iff_false_elim", lhs, e.getProof());
00417   }
00418   return newTheorem(!lhs, a, pf);
00419 }
00420 
00421 
00422 // e1 <=> e2  ==>  ~e1 <=> ~e2
00423 Theorem CommonTheoremProducer::iffContrapositive(const Theorem& e) {
00424   if(CHECK_PROOFS)
00425     CHECK_SOUND(e.isRewrite() && e.getRHS().getType().isBool(),
00426                 "CommonTheoremProducer::iffContrapositive: "
00427                 "theorem is not e1<=>e2: "+ e.toString());
00428   Assumptions a;
00429   Proof pf;
00430   if (withAssumptions()) a = e.getAssumptions().copy();
00431   if(withProof()) {
00432     pf = newPf("iff_contrapositive", e.getExpr(), e.getProof());
00433   }
00434   return newRWTheorem(e.getLHS().negate(),e.getRHS().negate(), a, pf);
00435 }
00436 
00437 
00438 // !!e ==> e
00439 Theorem CommonTheoremProducer::notNotElim(const Theorem& not_not_e) {
00440   if(CHECK_PROOFS)
00441     CHECK_SOUND(not_not_e.getExpr().isNot() && not_not_e.getExpr()[0].isNot(),
00442                 "CommonTheoremProducer::notNotElim: bad theorem: !!e = "
00443                 + not_not_e.toString());
00444   Assumptions a;
00445   Proof pf;
00446   if(withAssumptions()) a = not_not_e.getAssumptionsCopy();
00447   if(withProof())
00448     pf = newPf("not_not_elim", not_not_e.getExpr(), not_not_e.getProof());
00449   return newTheorem(not_not_e.getExpr()[0][0], a, pf);
00450 }
00451 
00452 
00453 Theorem CommonTheoremProducer::iffMP(const Theorem& e1, const Theorem& e1_iff_e2)
00454 {
00455   if(CHECK_PROOFS) {
00456     CHECK_SOUND(e1_iff_e2.isRewrite(),
00457                 "iffMP: not IFF: "+e1_iff_e2.toString());
00458     CHECK_SOUND(e1.getExpr() == (e1_iff_e2.getLHS()),
00459                 "iffMP: theorems don't match:\n  e1 = " + e1.toString()
00460                 + ", e1_iff_e2 = " + e1_iff_e2.toString());
00461   }
00462   const Expr& e2(e1_iff_e2.getRHS());
00463   // Avoid e1.getExpr(), it may cause unneeded Expr creation
00464   if (e1_iff_e2.getLHS() == e2) return e1;
00465   Assumptions a;
00466   Proof pf;
00467   if(withAssumptions()) a = merge(e1, e1_iff_e2);
00468   if(withProof()) {
00469     vector<Proof> pfs;
00470     pfs.push_back(e1.getProof());
00471     pfs.push_back(e1_iff_e2.getProof());
00472     pf = newPf("iff_mp", e1.getExpr(), e2, pfs);
00473   }
00474   return newTheorem(e2, a, pf);
00475 }
00476 
00477 
00478 // e1 AND (e1 IMPLIES e2) ==> e2
00479 Theorem CommonTheoremProducer::implMP(const Theorem& e1,
00480                                       const Theorem& e1_impl_e2) {
00481   const Expr& impl = e1_impl_e2.getExpr();
00482   if(CHECK_PROOFS) {
00483     CHECK_SOUND(impl.isImpl() && impl.arity()==2,
00484                 "implMP: not IMPLIES: "+impl.toString());
00485     CHECK_SOUND(e1.getExpr() == impl[0],
00486                 "implMP: theorems don't match:\n  e1 = " + e1.toString()
00487                 + ", e1_impl_e2 = " + impl.toString());
00488   }
00489   const Expr& e2 = impl[1];
00490   // Avoid e1.getExpr(), it may cause unneeded Expr creation
00491   if (impl[0] == e2) return e1;
00492   Assumptions a;
00493   Proof pf;
00494   if(withAssumptions()) a = merge(e1, e1_impl_e2);
00495   if(withProof()) {
00496     vector<Proof> pfs;
00497     pfs.push_back(e1.getProof());
00498     pfs.push_back(e1_impl_e2.getProof());
00499     pf = newPf("impl_mp", e1.getExpr(), e2, pfs);
00500   }
00501   return newTheorem(e2, a, pf);
00502 }
00503 
00504 
00505 // AND(e_0,...e_{n-1}) ==> e_i
00506 Theorem CommonTheoremProducer::andElim(const Theorem& e, int i) {
00507   if(CHECK_PROOFS) {
00508     CHECK_SOUND(e.getExpr().isAnd(), "andElim: not an AND: " + e.toString());
00509     CHECK_SOUND(i < e.getExpr().arity(), "andElim: i = " + int2string(i)
00510                 + " >= arity = " + int2string(e.getExpr().arity())
00511                 + " in " + e.toString());
00512   }
00513   Assumptions a;
00514   Proof pf;
00515   if(withAssumptions())
00516     a = e.getAssumptions().copy();
00517   if(withProof())
00518     pf = newPf("andE", d_em->newRatExpr(i), e.getExpr(), e.getProof());
00519   return newTheorem(e.getExpr()[i], a, pf);
00520 }
00521 
00522 
00523 //! e1, e2 ==> AND(e1, e2)
00524 Theorem CommonTheoremProducer::andIntro(const Theorem& e1, const Theorem& e2) {
00525   vector<Theorem> thms;
00526   thms.push_back(e1);
00527   thms.push_back(e2);
00528   return andIntro(thms);
00529 }
00530 
00531 
00532 Theorem CommonTheoremProducer::andIntro(const vector<Theorem>& es) {
00533   Assumptions a;
00534   Proof pf;
00535   if(CHECK_PROOFS)
00536     CHECK_SOUND(es.size() > 0,
00537                 "andIntro(vector<Theorem>): vector must be non-empty");
00538   if(withAssumptions()) {
00539     a = merge(es);
00540   }
00541   if(withProof()) {
00542     vector<Proof> pfs;
00543     for(vector<Theorem>::const_iterator i=es.begin(), iend=es.end();
00544         i!=iend; ++i)
00545       pfs.push_back(i->getProof());
00546     pf = newPf("andI", pfs);
00547   }
00548   vector<Expr> kids;
00549   for(vector<Theorem>::const_iterator i=es.begin(), iend=es.end();
00550       i!=iend; ++i)
00551     kids.push_back(i->getExpr());
00552   return newTheorem(andExpr(kids), a, pf);
00553 }
00554 
00555 
00556 //  G,a1,...,an |- phi
00557 // -------------------------------------------------
00558 //  G |- (a1 & ... & an) -> phi
00559 Theorem CommonTheoremProducer::implIntro(const Theorem& phi,
00560                                          const std::vector<Expr>& assump) {
00561   bool checkProofs(CHECK_PROOFS);
00562   // This rule only makes sense when runnnig with assumptions
00563   if(checkProofs) {
00564     CHECK_SOUND(withAssumptions(),
00565                 "implIntro: called while running without assumptions");
00566   }
00567 
00568   const Assumptions& phiAssump = phi.getAssumptionsRef();
00569 
00570   if(checkProofs) {
00571     for(size_t i=0; i<assump.size(); i++) {
00572       const Theorem& thm = phiAssump[assump[i]];
00573       CHECK_SOUND(!thm.isNull() && thm.isAssump(),
00574                   "implIntro: this is not an assumption of phi:\n\n"
00575                   "  a["+int2string(i)+"] = "+assump[i].toString()
00576                   +"\n\n  phi = "+phi.getExpr().toString());
00577     }
00578   }
00579 
00580   // Proof compaction: trivial derivation
00581   if(assump.size() == 0) return phi;
00582 
00583   Assumptions a(phiAssump - assump);
00584   Proof pf;
00585   if(withProof()) {
00586     vector<Proof> u; // Proof labels for assumptions
00587     for(vector<Expr>::const_iterator i=assump.begin(), iend=assump.end();
00588         i!=iend; ++i) {
00589       const Theorem& t = phiAssump[*i];
00590       u.push_back(t.getProof());
00591     }
00592     // Arguments to the proof rule:
00593     // impl_intro_3(phi, a1,...,an,tcc1,...tccn,pf_tcc1,...pf_tccn,
00594     //              [lambda(a1,...,an): pf_phi])
00595     vector<Expr> args;
00596     vector<Proof> pfs;
00597     args.push_back(phi.getExpr());
00598     args.insert(args.end(), assump.begin(), assump.end());
00599     // Lambda-abstraction of pf_phi
00600     pfs.push_back(newPf(u, assump, phi.getProof()));
00601     pf = newPf("impl_intro", args, pfs);
00602   }
00603   Expr conj(andExpr(assump));
00604   return newTheorem(conj.impExpr(phi.getExpr()), a, pf);
00605 }
00606 
00607 
00608 // e1 => e2  ==>  ~e2 => ~e1
00609 Theorem CommonTheoremProducer::implContrapositive(const Theorem& thm) {
00610   const Expr& impl = thm.getExpr();
00611   if(CHECK_PROOFS) {
00612     CHECK_SOUND(impl.isImpl() && impl.arity()==2,
00613                 "CommonTheoremProducer::implContrapositive: thm="
00614                 +impl.toString());
00615   }
00616   Assumptions a;
00617   Proof pf;
00618   if(withAssumptions()) a = thm.getAssumptionsCopy();
00619   if(withProof())
00620     pf = newPf("impl_contrapositive", impl, thm.getProof());
00621   return newTheorem(impl[1].negate().impExpr(impl[0].negate()), a, pf);
00622 }
00623 
00624 
00625 // NOT e ==> e IFF FALSE
00626 Theorem CommonTheoremProducer::notToIff(const Theorem& not_e)
00627 {
00628   if(CHECK_PROOFS)
00629     CHECK_SOUND(not_e.getExpr().isNot(),
00630                 "notToIff: not NOT: "+not_e.toString());
00631 
00632   // Make it an atomic rule (more efficient)
00633   Expr e(not_e.getExpr()[0]);
00634   Assumptions a;
00635   Proof pf;
00636   if(withAssumptions()) a = not_e.getAssumptions().copy();
00637   if(withProof())
00638     pf=newPf("not_to_iff", e, not_e.getProof());
00639   return newRWTheorem(e, d_em->falseExpr(), a, pf);
00640 }
00641 
00642 
00643 // ==> IFF(e1,e2) IFF <simplified expr>
00644 Theorem CommonTheoremProducer::rewriteIff(const Expr& e) {
00645   Assumptions a;
00646   Proof pf;
00647   if(CHECK_PROOFS)
00648     CHECK_SOUND(e.isIff(), "rewriteIff precondition violated");
00649   if(withProof()) {
00650     pf = newPf("rewrite_iff", e[0], e[1]);
00651   }
00652 
00653   if(e[0] == e[1]) return rewriteReflexivity(e);
00654 
00655   switch(e[0].getKind()) {
00656   case TRUE:
00657     return newRWTheorem(e, e[1], a, pf);
00658   case FALSE:
00659     return newRWTheorem(e, !e[1], a ,pf);
00660   case NOT:
00661     if(e[0][0]==e[1]) 
00662       return newRWTheorem(e, d_em->falseExpr(), a, pf);
00663     break;
00664   default: break;
00665   }
00666   
00667   switch(e[1].getKind()) {
00668   case TRUE:
00669     return newRWTheorem(e, e[0], a, pf);
00670   case FALSE:
00671     return newRWTheorem(e, !e[0], a, pf);
00672   case NOT:
00673     if(e[0]==e[1][0]) 
00674       return newRWTheorem(e, d_em->falseExpr(), a, pf);
00675     break;
00676   default:
00677     break;
00678   }
00679 
00680   if(e[0] < e[1])
00681     return rewriteUsingSymmetry(e);
00682   else
00683     return reflexivityRule(e);
00684 }
00685 
00686 
00687 // ==> AND(e_1,...,e_n) IFF <simplified expr>
00688 // 1) if e_i = FALSE then return FALSE
00689 // 2) if e_i = TRUE, remove it from children
00690 // 3) if e_i = AND(f_1,...,f_m) then AND(e_1,...,e_{i-1},f_1,...,f_m,e_{i+1},...,e_n)
00691 // 4) if n=0 return TRUE
00692 // 5) if n=1 return e_1
00693 Theorem CommonTheoremProducer::rewriteAnd(const Expr& e) {
00694   if(CHECK_PROOFS)
00695     CHECK_SOUND(e.isAnd(), "rewriteAnd: bad Expr: " + e.toString());
00696   Assumptions a;
00697   Proof pf;
00698   ExprMap<bool> newKids;
00699   bool isFalse (false);
00700   for (Expr::iterator k=e.begin(), kend=e.end(); !isFalse && k != kend; ++k) {
00701     const Expr& ek = *k;
00702     if (ek.isFalse()) { isFalse=true; break; }
00703     if (ek.isAnd()) {
00704       for(Expr::iterator j=ek.begin(), jend=ek.end(); j!=jend; ++j) {
00705         if(newKids.count(j->negate()) > 0) { isFalse=true; break; }
00706         newKids[*j]=true;
00707       }
00708     } else if(!ek.isTrue()) {
00709       if(newKids.count(ek.negate()) > 0) { isFalse=true; break; }
00710       newKids[ek]=true;
00711     }
00712   }
00713   Expr res;
00714   if (isFalse) res = d_em->falseExpr();
00715   else if (newKids.size() == 0) res = d_em->trueExpr(); // All newKids were TRUE
00716   else if (newKids.size() == 1)
00717     res = newKids.begin()->first; // The only child
00718   else {
00719     vector<Expr> v;
00720     for(ExprMap<bool>::iterator i=newKids.begin(), iend=newKids.end();
00721         i!=iend; ++i)
00722       v.push_back(i->first);
00723     res = andExpr(v);
00724   }
00725   if(withProof()) {
00726     pf = newPf("rewrite_and", e,res);
00727   }
00728   return newRWTheorem(e, res, a, pf);
00729 }
00730 
00731 
00732 // ==> OR(e1,e2) IFF <simplified expr>
00733 Theorem CommonTheoremProducer::rewriteOr(const Expr& e) {
00734   if(CHECK_PROOFS)
00735     CHECK_SOUND(e.isOr(), "rewriteOr: bad Expr: " + e.toString());
00736   Assumptions a;
00737   Proof pf;
00738   ExprMap<bool> newKids;
00739   bool isTrue (false);
00740   for (Expr::iterator k=e.begin(), kend=e.end(); !isTrue && k != kend; ++k) {
00741     const Expr& ek = *k;
00742     if (ek.isTrue()) { isTrue=true; break; }
00743     else if (ek.isOr()) {
00744       for(Expr::iterator j=ek.begin(), jend=ek.end(); j!=jend; ++j) {
00745         if(newKids.count(j->negate()) > 0) { isTrue=true; break; }
00746         newKids[*j]=true;
00747       }
00748     } else if(!ek.isFalse()) {
00749       if(newKids.count(ek.negate()) > 0) { isTrue=true; break; }
00750       newKids[ek]=true;
00751     }
00752   }
00753   Expr res;
00754   if (isTrue) res = d_em->trueExpr();
00755   else if (newKids.size() == 0) res = d_em->falseExpr(); // All kids were FALSE
00756   else if (newKids.size() == 1) res = newKids.begin()->first; // The only child
00757   else {
00758     vector<Expr> v;
00759     for(ExprMap<bool>::iterator i=newKids.begin(), iend=newKids.end();
00760         i!=iend; ++i)
00761       v.push_back(i->first);
00762     res = orExpr(v);
00763   }
00764   if(withProof()) {
00765     pf = newPf("rewrite_or", e, res);
00766   }
00767   return newRWTheorem(e, res, a, pf);
00768 }
00769 
00770 
00771 // ==> NOT TRUE IFF FALSE
00772 Theorem CommonTheoremProducer::rewriteNotTrue(const Expr& e) {
00773   Assumptions a;
00774   Proof pf;
00775   if(CHECK_PROOFS)
00776     CHECK_SOUND(e.isNot() && e[0].isTrue(),
00777                 "rewriteNotTrue precondition violated");
00778   if(withProof())
00779     pf = newPf("rewrite_not_true");
00780   return newRWTheorem(e, d_em->falseExpr(), a, pf);
00781 }
00782 
00783 
00784 // ==> NOT FALSE IFF TRUE
00785 Theorem CommonTheoremProducer::rewriteNotFalse(const Expr& e) {
00786   Assumptions a;
00787   Proof pf;
00788   if(CHECK_PROOFS)
00789     CHECK_SOUND(e.isNot() && e[0].isFalse(),
00790                 "rewriteNotFalse precondition violated");
00791   if(withProof())
00792     pf = newPf("rewrite_not_false");
00793   return newRWTheorem(e, d_em->trueExpr(), a, pf);
00794 }
00795 
00796 
00797 // ==> (NOT NOT e) IFF e, takes !!e
00798 Theorem CommonTheoremProducer::rewriteNotNot(const Expr& e) {
00799   Assumptions a;
00800   Proof pf;
00801   if(CHECK_PROOFS)
00802     CHECK_SOUND(e.isNot() && e[0].isNot(),
00803                 "rewriteNotNot precondition violated");
00804   if(withProof())
00805     pf = newPf("rewrite_not_not", e[0][0]);
00806   return newRWTheorem(e, e[0][0], a, pf);
00807 }
00808 
00809 
00810 //! ==> NOT FORALL (vars): e  IFF EXISTS (vars) NOT e
00811 Theorem CommonTheoremProducer::rewriteNotForall(const Expr& e) {
00812   if(CHECK_PROOFS) {
00813     CHECK_SOUND(e.isNot() && e[0].isForall(),
00814                 "rewriteNotForall: expr must be NOT FORALL:\n"
00815                 +e.toString());
00816   }
00817   Assumptions a;
00818   Proof pf;
00819   if(withProof())
00820     pf = newPf("rewrite_not_forall", e);
00821   return newRWTheorem(e, d_em->newClosureExpr(EXISTS, e[0].getVars(),
00822                                               !e[0].getBody()), a, pf);
00823 }
00824 
00825 
00826 //! ==> NOT EXISTS (vars): e  IFF FORALL (vars) NOT e
00827 Theorem CommonTheoremProducer::rewriteNotExists(const Expr& e) {
00828   if(CHECK_PROOFS) {
00829     CHECK_SOUND(e.isNot() && e[0].isExists(),
00830                 "rewriteNotExists: expr must be NOT FORALL:\n"
00831                 +e.toString());
00832   }
00833   Assumptions a;
00834   Proof pf;
00835   if(withProof())
00836     pf = newPf("rewrite_not_exists", e);
00837   return newRWTheorem(e, d_em->newClosureExpr(FORALL, e[0].getVars(),
00838                                               !e[0].getBody()), a, pf);
00839 }
00840 
00841 
00842 Expr CommonTheoremProducer::skolemize(const Expr& e)
00843 {
00844   vector<Expr> vars;
00845   const vector<Expr>& boundVars = e.getVars(); 
00846   for(unsigned int i=0; i<boundVars.size(); i++) {
00847     Expr skolV(e.skolemExpr(i));
00848     Type tp(e.getVars()[i].getType());
00849     skolV.setType(tp);
00850     vars.push_back(skolV);
00851   }
00852   return(e.getBody().substExpr(boundVars, vars));
00853 }
00854 
00855 
00856 Theorem CommonTheoremProducer::skolemizeRewrite(const Expr& e)
00857 {
00858   Assumptions a;
00859   Proof pf;
00860   if(CHECK_PROOFS) {
00861     CHECK_SOUND(e.isExists(), "skolemize rewrite called on non-existential: "
00862                 + e.toString());
00863   }
00864   Expr skol = skolemize(e);
00865   if(withProof()) {
00866     Expr rw(e.iffExpr(skol));
00867     pf = newLabel(rw);
00868   }
00869   return newRWTheorem(e, skol, a, pf);
00870 
00871 }
00872 
00873 
00874 Theorem CommonTheoremProducer::skolemizeRewriteVar(const Expr& e)
00875 {
00876   Assumptions a;
00877   Proof pf;
00878   if(CHECK_PROOFS) {
00879     CHECK_SOUND(e.isExists(), "skolemizeRewriteVar("
00880                 +e.toString()+")");
00881   }
00882 
00883   const vector<Expr>& boundVars = e.getVars();
00884   const Expr& body = e.getBody();
00885 
00886   if(CHECK_PROOFS) {
00887     CHECK_SOUND(boundVars.size()==1, "skolemizeRewriteVar("
00888                 +e.toString()+")");
00889     CHECK_SOUND(body.isEq() || body.isIff(), "skolemizeRewriteVar("
00890                 +e.toString()+")");
00891     const Expr& v = boundVars[0];
00892     CHECK_SOUND(body[1] == v, "skolemizeRewriteVar("
00893                 +e.toString()+")");
00894     CHECK_SOUND(!(v.subExprOf(body[0])), "skolemizeRewriteVar("
00895                 +e.toString()+")");
00896   }
00897   // Create the Skolem constant appropriately
00898   Expr skolV(e.skolemExpr(0));
00899   Type tp(e.getVars()[0].getType());
00900   skolV.setType(tp);
00901   // Skolemized expression
00902   Expr skol = Expr(body.getOp(), body[0], skolV);
00903 
00904   if(withProof()) {
00905     Expr rw(e.iffExpr(skol));
00906     pf = newLabel(rw);
00907   }
00908   return newRWTheorem(e, skol, a, pf);
00909 }
00910 
00911 
00912 Theorem CommonTheoremProducer::varIntroRule(const Expr& phi) {
00913   // This rule is sound for all expressions phi
00914   Assumptions a; Proof pf;
00915   const Expr boundVar = d_em->newBoundVarExpr(phi.getType());
00916 
00917   Expr body;  
00918   if(phi.getType().isBool())
00919     body = phi.iffExpr(boundVar);
00920   else
00921     body = phi.eqExpr(boundVar);
00922 
00923   std::vector<Expr> v; 
00924   v.push_back(boundVar);
00925   const Expr result = d_em->newClosureExpr(EXISTS, v, body);
00926   
00927   if(withProof()) 
00928     pf = newPf("var_intro", phi, boundVar);
00929   return newTheorem(result, a, pf);
00930 }
00931 
00932 
00933 Theorem CommonTheoremProducer::skolemize(const Theorem& thm) { 
00934   const Expr& e = thm.getExpr();
00935   if(e.isExists()) {
00936     TRACE("skolem", "Skolemizing existential:", "", "{");
00937     CDMap<Expr, Theorem>::iterator i=d_skolemized_thms.find(e),
00938       iend=d_skolemized_thms.end();
00939     if(i!=iend) {
00940       TRACE("skolem", "Skolemized theorem found in map: ", (*i).second, "}");
00941       return iffMP(thm, (*i).second);
00942     }
00943     Theorem skol = skolemizeRewrite(e);
00944     for(unsigned int i=0; i<e.getVars().size(); i++) {
00945       Expr skolV(e.skolemExpr(i));
00946       Type tp(e.getVars()[i].getType());
00947       skolV.setType(tp);
00948     }
00949     d_skolem_axioms.push_back(skol);
00950     d_skolemized_thms.insert(e, skol, 0);//d_coreSatAPI->getBottomScope());
00951     skol = iffMP(thm, skol);
00952     TRACE("skolem", "skolemized new theorem: ", skol, "}");
00953     return skol;
00954   }
00955   return thm;
00956 }
00957 
00958 
00959 Theorem CommonTheoremProducer::varIntroSkolem(const Expr& e) {
00960   // First, look up the cache
00961   CDMap<Expr, Theorem>::iterator i=d_skolemVars.find(e),
00962     iend=d_skolemVars.end();
00963   if(i!=iend) return (*i).second;
00964   // Not in cache; create a new one
00965   Theorem thm = varIntroRule(e);
00966   const Expr& e2 = thm.getExpr();
00967   DebugAssert(e2.isExists() && e2.getVars().size()==1, "varIntroSkolem: e2 = "
00968               +e2.toString());
00969   Theorem skolThm;
00970   // Check if we have a corresponding skolemized version already
00971   CDMap<Expr, Theorem>::iterator j=d_skolemized_thms.find(e2),
00972     jend=d_skolemized_thms.end();
00973   if(j!=jend) {
00974     skolThm = (*i).second;
00975   } else {
00976     skolThm = skolemizeRewriteVar(e2);
00977     d_skolem_axioms.push_back(skolThm);
00978     d_skolemized_thms.insert(e2, skolThm, 0); //d_coreSatAPI->getBottomScope());
00979   }
00980   thm = iffMP(thm, skolThm);
00981   d_skolemVars.insert(e, thm, 0); //d_coreSatAPI->getBottomScope());
00982   return thm;
00983 }
00984 
00985 
00986 // Derived Rules
00987 
00988 
00989 Theorem CommonTheoremProducer::trueTheorem()
00990 {
00991   return iffTrueElim(reflexivityRule(d_em->trueExpr()));
00992 }
00993 
00994 
00995 Theorem CommonTheoremProducer::rewriteAnd(const Theorem& e)
00996 {
00997   return iffMP(e, rewriteAnd(e.getExpr()));
00998 }
00999 
01000 
01001 Theorem CommonTheoremProducer::rewriteOr(const Theorem& e)
01002 {
01003   return iffMP(e, rewriteOr(e.getExpr()));
01004 }

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