search_impl_base.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file search.cpp
00004  * 
00005  * Author: Clark Barrett, Vijay Ganesh (CNF Converter)
00006  * 
00007  * Created: Fri Jan 17 14:19:54 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 "search_impl_base.h"
00031 #include "theory.h"
00032 #include "eval_exception.h"
00033 #include "search_rules.h"
00034 #include "variable.h"
00035 #include "command_line_flags.h"
00036 #include "statistics.h"
00037 #include "theorem_manager.h"
00038 #include "expr_transform.h"
00039 
00040 
00041 using namespace std;
00042 
00043 
00044 namespace CVCL {
00045 
00046 
00047   class CoreSatAPI_implBase :public TheoryCore::CoreSatAPI {
00048     SearchImplBase* d_se;
00049   public:
00050     CoreSatAPI_implBase(SearchImplBase* se) : d_se(se) {}
00051     virtual ~CoreSatAPI_implBase() {}
00052     virtual void addLemma(const Theorem& thm) { d_se->addFact(thm); }
00053     virtual int getBottomScope() { return d_se->getBottomScope(); }
00054     virtual Theorem addAssumption(const Expr& assump)
00055       { return d_se->newIntAssumption(assump); }
00056     virtual void addSplitter(const Expr& e, int priority)
00057       { d_se->addSplitter(e, priority); }
00058   };
00059 
00060 
00061 }
00062 
00063 
00064 using namespace CVCL;
00065 
00066 
00067 // class SearchImplBase::Splitter methods
00068 
00069 // Constructor
00070 SearchImplBase::Splitter::Splitter(const Literal& lit): d_lit(lit) {
00071 d_lit.count()++;
00072   TRACE("Splitter", "Splitter(", d_lit, ")");
00073 }
00074 
00075 // Copy constructor
00076 SearchImplBase::Splitter::Splitter(const SearchImplBase::Splitter& s)
00077   : d_lit(s.d_lit) {
00078   d_lit.count()++;
00079   TRACE("Splitter", "Splitter[copy](", d_lit, ")");
00080 }
00081 
00082 // Assignment
00083 SearchImplBase::Splitter&
00084 SearchImplBase::Splitter::operator=(const SearchImplBase::Splitter& s) {
00085   if(this == &s) return *this; // Self-assignment
00086   d_lit.count()--;
00087   d_lit = s.d_lit;
00088   d_lit.count()++;
00089   TRACE("Splitter", "Splitter[assign](", d_lit, ")");
00090   return *this;
00091 }
00092 
00093 // Destructor
00094 SearchImplBase::Splitter::~Splitter() {
00095   d_lit.count()--;
00096   TRACE("Splitter", "~Splitter(", d_lit, ")");
00097 }
00098 
00099 
00100 
00101 //! Constructor
00102 SearchImplBase::SearchImplBase(TheoryCore* core)
00103   : SearchEngine(core),
00104     d_bottomScope(core->getCM()->getCurrentContext()),
00105     d_dpSplitters(core->getCM()->getCurrentContext()),
00106     d_lastValid(d_commonRules->trueTheorem()),
00107     d_assumptions(core->getCM()->getCurrentContext()),
00108     d_cnfCache(core->getCM()->getCurrentContext()),
00109     d_cnfVars(core->getCM()->getCurrentContext()),
00110     d_cnfOption(&(core->getFlags()["cnf"].getBool())),
00111     d_ifLiftOption(&(core->getFlags()["iflift"].getBool())),
00112     d_ignoreCnfVarsOption(&(core->getFlags()["ignore-cnf-vars"].getBool())),
00113     d_origFormulaOption(&(core->getFlags()["orig-formula"].getBool())),
00114     d_enqueueCNFCache(core->getCM()->getCurrentContext()),
00115     d_applyCNFRulesCache(core->getCM()->getCurrentContext()),
00116     d_replaceITECache(core->getCM()->getCurrentContext())
00117 {
00118   d_vm = new VariableManager(core->getCM(), d_rules,
00119                              core->getFlags()["mm"].getString());
00120   IF_DEBUG(d_assumptions.setName("CDList[SearchImplBase::d_assumptions]"));
00121   d_coreSatAPI_implBase = new CoreSatAPI_implBase(this);
00122   core->registerCoreSatAPI(d_coreSatAPI_implBase);
00123 }
00124 
00125 
00126 //! Destructor
00127 SearchImplBase::~SearchImplBase()
00128 {
00129   delete d_coreSatAPI_implBase;
00130   delete d_vm;
00131 }
00132 
00133 
00134 // Returns a new theorem if e has not already been asserted, otherwise returns
00135 // a NULL theorem.
00136 Theorem SearchImplBase::newUserAssumption(const Expr& e, int scope) {
00137   FatalAssert(scope == -1, "non-current scope not supported in SearchImplBase");
00138   Theorem thm;
00139   CDMap<Expr,Theorem>::iterator i(d_assumptions.find(e));
00140   IF_DEBUG(if(debugger.trace("search verbose")) {
00141     ostream& os(debugger.getOS());
00142     os << "d_assumptions = [";
00143     for(CDMap<Expr,Theorem>::iterator i=d_assumptions.begin(),
00144           iend=d_assumptions.end(); i!=iend; ++i) {
00145       debugger.getOS() << "(" << (*i).first << " => " << (*i).second << "), ";
00146     }
00147     os << "]" << endl;
00148   });
00149   if(i!=d_assumptions.end()) {
00150     TRACE("search verbose", "newUserAssumption(", e,
00151           "): assumption already exists");
00152   } else {
00153     thm = d_commonRules->assumpRule(e);
00154     d_assumptions[e] = thm;
00155     e.setUserAssumption();
00156     TRACE("search verbose", "newUserAssumption(", thm,
00157           "): created new assumption");
00158   }
00159   if (!thm.isNull()) d_core->addFact(d_core->getExprTrans()->preprocess(thm));
00160   return thm;
00161 }
00162 
00163 
00164 // Same as newUserAssertion, except it's an error to assert something that's
00165 // already been asserted.
00166 Theorem SearchImplBase::newIntAssumption(const Expr& e) {
00167   Theorem thm = d_commonRules->assumpRule(e);
00168   newIntAssumption(thm);
00169   return thm;
00170 }
00171 
00172 
00173 void SearchImplBase::newIntAssumption(const Theorem& thm) {
00174   DebugAssert(!d_assumptions.count(thm.getExpr()),
00175               "newIntAssumption: repeated assertion: "+thm.getExpr().toString());
00176     d_assumptions[thm.getExpr()] = thm;
00177     thm.getExpr().setIntAssumption();
00178     TRACE("search verbose", "newIntAssumption(", thm,
00179           "): new assumption");
00180 }
00181 
00182 
00183 void SearchImplBase::getUserAssumptions(vector<Expr>& assumptions)
00184 {
00185   for(CDMap<Expr,Theorem>::orderedIterator i=d_assumptions.orderedBegin(),
00186         iend=d_assumptions.orderedEnd(); i!=iend; ++i)
00187     if ((*i).first.isUserAssumption()) assumptions.push_back((*i).first);
00188 }
00189 
00190 
00191 void SearchImplBase::getInternalAssumptions(std::vector<Expr>& assumptions)
00192 {
00193   for(CDMap<Expr,Theorem>::orderedIterator i=d_assumptions.orderedBegin(),
00194         iend=d_assumptions.orderedEnd(); i!=iend; ++i)
00195     if ((*i).first.isIntAssumption()) assumptions.push_back((*i).first);
00196 }
00197 
00198 
00199 void SearchImplBase::getAssumptions(std::vector<Expr>& assumptions)
00200 {
00201   for(CDMap<Expr,Theorem>::orderedIterator i=d_assumptions.orderedBegin(),
00202         iend=d_assumptions.orderedEnd(); i!=iend; ++i)
00203     assumptions.push_back((*i).first);
00204 }
00205 
00206 
00207 bool SearchImplBase::isAssumption(const Expr& e) {
00208   return d_assumptions.count(e) > 0;
00209 }
00210 
00211 
00212 void SearchImplBase::addCNFFact(const Theorem& thm, bool fromCore) {
00213   TRACE("addCNFFact", "addCNFFact(", thm.getExpr(), ") {");
00214   if(thm.isAbsLiteral()) {
00215     addLiteralFact(thm);
00216     // These literals are derived, and  should also be reported to the core.  
00217     if(!fromCore) d_core->enqueueFact(thm);
00218   } else {
00219     addNonLiteralFact(thm);
00220   }
00221   TRACE_MSG("addCNFFact", "addCNFFact => }");
00222 }
00223 
00224 
00225 void SearchImplBase::addFact(const Theorem& thm) {
00226   TRACE("search addFact", "SearchImplBase::addFact(", thm.getExpr(), ") {");
00227   if(*d_cnfOption)
00228     enqueueCNF(thm);
00229   else
00230     addCNFFact(thm, true);
00231   TRACE_MSG("search addFact", "SearchImplBase::addFact => }");
00232 }
00233 
00234 
00235 void SearchImplBase::addSplitter(const Expr& e, int priority) {
00236   DebugAssert(e.isAbsLiteral(), "SearchImplBase::addSplitter("+e.toString()+")");
00237   d_dpSplitters.push_back(Splitter(newLiteral(e)));
00238 }
00239 
00240 
00241 void SearchImplBase::getCounterExample(vector<Expr>& assertions, bool inOrder)
00242 {
00243   if(!d_core->getTM()->withAssumptions())
00244     throw EvalException
00245       ("Method getCounterExample() (or command COUNTEREXAMPLE) cannot be used\n"
00246        " without assumptions activated");
00247   if(!d_lastValid.isNull())
00248     throw EvalException
00249       ("Method getCounterExample() (or command COUNTEREXAMPLE)\n"
00250        " must be called only after failed QUERY");
00251   if(!d_lastCounterExample.empty()) {
00252     if (inOrder) {
00253       for(CDMap<Expr,Theorem>::orderedIterator i=d_assumptions.orderedBegin(),
00254             iend=d_assumptions.orderedEnd(); i!=iend; ++i) {
00255         if (d_lastCounterExample.find((*i).first) != d_lastCounterExample.end()) {
00256           assertions.push_back((*i).first);
00257         }
00258       }
00259       DebugAssert(assertions.size()==d_lastCounterExample.size(),
00260                   "getCounterExample: missing assertion");
00261     }
00262     else {
00263       ExprHashMap<bool>::iterator i=d_lastCounterExample.begin(),
00264         iend = d_lastCounterExample.end();
00265       for(; i!=iend; ++i) assertions.push_back((*i).first);
00266     }
00267   }
00268 }
00269 
00270 
00271 Proof 
00272 SearchImplBase::getProof()
00273 {
00274   if(!d_core->getTM()->withProof())
00275     throw EvalException
00276       ("DUMP_PROOF cannot be used without proofs activated");
00277   if(d_lastValid.isNull())
00278     throw EvalException
00279       ("DUMP_PROOF must be called only after successful QUERY");
00280   // Double-check for optimized version
00281   if(d_lastValid.isNull()) return Proof();
00282   return d_lastValid.getProof();
00283 }
00284 
00285 
00286 const Assumptions
00287 SearchImplBase::getAssumptionsUsed()
00288 {
00289   if(!d_core->getTM()->withAssumptions())
00290     throw EvalException
00291       ("DUMP_ASSUMPTIONS cannot be used without assumptions activated");
00292   if(d_lastValid.isNull())
00293     throw EvalException
00294       ("DUMP_ASSUMPTIONS must be called only after successful QUERY");
00295   // Double-check for optimized version
00296   if(d_lastValid.isNull()) return Assumptions();
00297   return d_lastValid.getAssumptions();
00298 }
00299 
00300 /*! 
00301  * Given a proof of FALSE ('res') from an assumption 'e', derive the
00302  * proof of the inverse of e.
00303  *
00304  * \param res is a proof of FALSE
00305  * \param e is the assumption used in the above proof
00306  */
00307 bool SearchImplBase::processResult(const Theorem& res, const Expr& e)
00308 {
00309   // Result must be either Null (== SAT) or false (== unSAT)
00310   DebugAssert(res.isNull() || res.getExpr().isFalse(),
00311               "processResult: bad input"
00312               + res.toString());
00313   if(res.isNull()) {
00314     // Didn't prove valid (if CVC-lite is complete, it means invalid).
00315     // The assumptions for the counterexample must have been already
00316     // set by checkSAT().
00317     d_lastValid = Theorem(); // Reset last proof
00318     // Remove !e, keep just the counterexample
00319     d_lastCounterExample.erase(!e);
00320     if (e.isNot()) d_lastCounterExample.erase(e[0]);
00321     return false;
00322   } else {
00323     // Proved valid
00324     Theorem res2 =
00325       d_rules->eliminateSkolemAxioms(res, d_commonRules->getSkolemAxioms());
00326     if(e.isNot())
00327       d_lastValid = d_rules->negIntro(e, res2);
00328     else
00329       d_lastValid = d_rules->proofByContradiction(e, res2);
00330     d_lastCounterExample.clear(); // Reset counterexample
00331     return true;
00332   }
00333 }
00334 
00335 
00336 Theorem SearchImplBase::checkValid(const Expr& e) {
00337   d_commonRules->clearSkolemAxioms();
00338   if(checkValidInternal(e)) return d_lastValid;
00339   else return Theorem();
00340 }
00341 
00342 
00343 Theorem SearchImplBase::restart(const Expr& e) {
00344   if (restartInternal(e)) return d_lastValid;
00345   else return Theorem();
00346 }
00347 
00348 
00349 void 
00350 SearchImplBase::enqueueCNF(const Theorem& beta) {
00351   TRACE("mycnf", "enqueueCNF(", beta, ") {");
00352   if(*d_origFormulaOption)
00353     addCNFFact(beta);
00354 
00355   enqueueCNFrec(beta);
00356   TRACE_MSG("mycnf", "enqueueCNF => }");
00357 }
00358 
00359 
00360 void 
00361 SearchImplBase::enqueueCNFrec(const Theorem& beta) {
00362   Theorem theta = beta;
00363 
00364   TRACE("mycnf","enqueueCNFrec(", theta.getExpr(), ") { ");
00365   TRACE("cnf-clauses", "enqueueCNF call", theta.getExpr(), "");
00366   // The theorem scope shouldn't be higher than current
00367   DebugAssert(theta.getScope() <= scopeLevel(),
00368               "\n theta.getScope()="+int2string(theta.getScope())
00369               +"\n scopeLevel="+int2string(scopeLevel())
00370               +"\n e = "+theta.getExpr().toString());
00371 
00372   Expr thetaExpr = theta.getExpr();
00373 
00374   if(d_enqueueCNFCache.count(thetaExpr) > 0) {
00375     TRACE_MSG("mycnf", "enqueueCNFrec[cached] => }");
00376     return;
00377   }
00378 
00379   d_enqueueCNFCache[thetaExpr] = true;
00380 
00381   //   // Strip double negations first
00382   while(thetaExpr.isNot() && thetaExpr[0].isNot()) {
00383     theta = d_commonRules->notNotElim(theta);
00384     thetaExpr = theta.getExpr();
00385     // Cache all the derived theorems too
00386     d_enqueueCNFCache[thetaExpr] = true;
00387   }
00388 
00389   // Check for a propositional literal
00390   if(thetaExpr.isPropLiteral()) {
00391     theta = d_commonRules->iffMP(theta, replaceITE(thetaExpr));
00392     DebugAssert(!*d_ifLiftOption || theta.isAbsLiteral(),
00393                 "Must be a literal: theta = "
00394                 +theta.getExpr().toString());
00395     addCNFFact(theta);
00396     TRACE_MSG("mycnf", "enqueueCNFrec[literal] => }");
00397     TRACE("cnf-clauses", "literal with proofs(", theta.getExpr(), ")");
00398     return;
00399   }
00400   
00401   thetaExpr = theta.getExpr();
00402   // Obvious optimizations for AND and OR  
00403   switch(thetaExpr.getKind()) {
00404   case AND:
00405     // Split up the top-level conjunction and translate individually
00406     for(int i=0; i<thetaExpr.arity(); i++)
00407       enqueueCNFrec(d_commonRules->andElim(theta, i));
00408     TRACE_MSG("mycnf", "enqueueCNFrec[AND] => }");
00409     return;
00410   case OR: {
00411     // Check if we are already in CNF (ignoring ITEs in the terms),
00412     // and if we are, translate term ITEs on the way
00413     bool cnf(true);
00414     TRACE("bv mycnf", "enqueueCNFrec[OR] ( ", theta.getExpr().toString(), ")");
00415     for(Expr::iterator i=thetaExpr.begin(),iend=thetaExpr.end();
00416         i!=iend && cnf; i++) {
00417       if(!(*i).isPropLiteral())
00418         cnf = false;
00419     }
00420     if(cnf) {
00421       vector<Theorem> thms;
00422       vector<unsigned int> changed;
00423       unsigned int cc=0;
00424       for(Expr::iterator i=thetaExpr.begin(),iend=thetaExpr.end();
00425           i!=iend; i++,cc++) {
00426         Theorem thm = replaceITE(*i);   
00427         if(thm.getLHS() != thm.getRHS()) {
00428           thms.push_back(thm);
00429           changed.push_back(cc);
00430         }
00431       }
00432       if(changed.size() > 0) {
00433         Theorem rewrite =
00434           d_commonRules->substitutivityRule(theta.getExpr(), changed, thms);
00435         theta = d_commonRules->iffMP(theta, rewrite);
00436       }
00437       addCNFFact(theta);
00438       TRACE_MSG("mycnf", "enqueueCNFrec[cnf] => }");
00439       return;           
00440     }
00441     break;
00442   }
00443   case IFF: { // Check for "var <=> phi" and "phi <=> var"
00444     const Expr& t0 = thetaExpr[0];
00445     const Expr& t1 = thetaExpr[1];
00446     if(t1.isPropLiteral()) {
00447       if(!t1.isAbsLiteral())
00448         theta = d_commonRules->transitivityRule(theta, replaceITE(t1));
00449       applyCNFRules(theta);
00450       return;
00451     } else if(thetaExpr[0].isPropLiteral()) {
00452       theta = d_commonRules->symmetryRule(theta);
00453       if(!t0.isAbsLiteral())
00454         theta = d_commonRules->transitivityRule(theta, replaceITE(t0));
00455       applyCNFRules(theta);
00456       return;
00457     }
00458     break;
00459   }
00460   case ITE:
00461     if(thetaExpr[0].isPropLiteral() && thetaExpr[1].isPropLiteral()
00462        && thetaExpr[2].isPropLiteral()) {
00463       // Replace ITEs
00464       vector<Theorem> thms;
00465       vector<unsigned int> changed;
00466       for(int c=0, cend=thetaExpr.arity(); c<cend; ++c) {
00467         Theorem thm = replaceITE(thetaExpr[c]);
00468         if(thm.getLHS() != thm.getRHS()) {
00469           DebugAssert(!*d_ifLiftOption || thm.getRHS().isAbsLiteral(),
00470                       "thm = "+thm.getExpr().toString());
00471           thms.push_back(thm);
00472           changed.push_back(c);
00473         }
00474       }
00475       if(changed.size() > 0) {
00476         Theorem rewrite =
00477           d_commonRules->substitutivityRule(theta.getExpr(), changed, thms);
00478         theta = d_commonRules->iffMP(theta, rewrite);
00479       }
00480       // Convert to clauses
00481       Theorem thm = d_rules->iteToClauses(theta);
00482       DebugAssert(thm.getExpr().isAnd() && thm.getExpr().arity()==2,
00483                   "enqueueCNFrec [ITE over literals]\n thm = "
00484                   +thm.getExpr().toString());
00485       addCNFFact(d_commonRules->andElim(thm, 0));
00486       addCNFFact(d_commonRules->andElim(thm, 1));
00487       return;
00488     }
00489     break;
00490   default: 
00491     break;
00492   }
00493 
00494   // Now do the real work
00495   Theorem res = findInCNFCache(theta.getExpr());
00496   if(!res.isNull()) {
00497     Theorem thm = d_commonRules->iffMP(theta, res);
00498     DebugAssert(thm.isAbsLiteral(), "thm = "+thm.getExpr().toString());
00499     addCNFFact(thm);
00500     TRACE("cnf-clauses", "enqueueCNFrec call[cache hit]:(",
00501           thm.getExpr(), ")");
00502     applyCNFRules(res);
00503     TRACE_MSG("mycnf", "enqueueCNFrec[cached] => }");
00504     return;
00505   }
00506 
00507   //  std::vector<Theorem> clauses;
00508   Theorem result;
00509   // (\phi <==> v)
00510   result = d_commonRules->varIntroSkolem(theta.getExpr());
00511 
00512   TRACE("mycnf", "enqueueCNFrec: varIntroSkolem => ", result.getExpr(),
00513         " @ "+int2string(result.getScope())
00514         +" (current="+int2string(scopeLevel())+")");
00515 
00516   //result = skolemize(result, false);
00517 
00518   TRACE("mycnf", "enqueueCNFrec: skolemize => ", result.getExpr(),
00519         " @ "+int2string(result.getScope())
00520         +" (current="+int2string(scopeLevel())+")");
00521   DebugAssert(result.isRewrite(),
00522               "SearchImplBase::CNF(): result = "+result.toString());
00523   DebugAssert(!result.getLHS().isPropLiteral() && 
00524               result.getRHS().isPropLiteral(),
00525               "SearchImplBase::CNF(): result = "+result.toString());
00526   DebugAssert(result.getLHS() == theta.getExpr(),
00527               "SearchImplBase::CNF(): result = "+result.toString()
00528               +"\n theta = "+theta.toString());
00529   
00530   //enqueue v
00531   Theorem var(d_commonRules->iffMP(theta, result));
00532   // Add variable to the set of CNF vars
00533   d_cnfVars[var.getExpr()] = true;
00534   TRACE("mycnf", "enqueueCNFrec: theta = ", theta.getExpr(),
00535         " @ "+int2string(theta.getScope())
00536         +" (current="+int2string(scopeLevel())+")");
00537   TRACE("mycnf", "enqueueCNFrec: var = ", var.getExpr(),
00538         " @ "+int2string(var.getScope())
00539         +" (current="+int2string(scopeLevel())+")");
00540   DebugAssert(var.isAbsLiteral(), "var = "+var.getExpr().toString());
00541   addCNFFact(var);
00542   // phi <=> v
00543   addToCNFCache(result);
00544   applyCNFRules(result);
00545   TRACE_MSG("mycnf", "enqueueCNFrec => }");
00546 }
00547 
00548 
00549 /*!
00550  * \param thm is the input of the form phi <=> v
00551  */
00552 void
00553 SearchImplBase::applyCNFRules(const Theorem& thm) {
00554   TRACE("mycnf", "applyCNFRules(", thm.getExpr(), ") { ");
00555   
00556   Theorem result = thm;
00557   DebugAssert(result.isRewrite(),
00558               "SearchImplBase::applyCNFRules: input must be an iff: " + 
00559               result.getExpr().toString());
00560   Expr lhs = result.getLHS();
00561   Expr rhs = result.getRHS();
00562   DebugAssert(rhs.isAbsLiteral(),
00563               "SearchImplBase::applyCNFRules: rhs of input must be literal: " +
00564               result.getExpr().toString());
00565 
00566   // Eliminate negation first
00567   while(result.getLHS().isNot())
00568     result = d_commonRules->iffContrapositive(result);
00569   lhs = result.getLHS();
00570   rhs = result.getRHS();
00571   
00572   CDMap<Expr,bool>::iterator it = d_applyCNFRulesCache.find(lhs);
00573   if(it == d_applyCNFRulesCache.end())
00574     d_applyCNFRulesCache[lhs] = true;
00575   else {
00576     TRACE_MSG("mycnf","applyCNFRules[temp cache] => }");
00577     return;
00578   }
00579   
00580   // Catch the trivial case v1 <=> v2
00581   if(lhs.isPropLiteral()) {
00582     if(!lhs.isAbsLiteral()) {
00583       Theorem replaced = d_commonRules->symmetryRule(replaceITE(lhs));
00584       result = d_commonRules->transitivityRule(replaced, result);
00585       lhs = result.getLHS();
00586       DebugAssert(rhs == result.getRHS(),
00587                   "applyCNFRules [literal lhs]\n result = "
00588                   +result.getExpr().toString()
00589                   +"\n rhs = "+rhs.toString());
00590     }
00591     Theorem thm = d_rules->iffToClauses(result);
00592     DebugAssert(thm.getExpr().isAnd() && thm.getExpr().arity()==2,
00593                 "applyCNFRules [literal lhs]\n thm = "
00594                 +thm.getExpr().toString());
00595     addCNFFact(d_commonRules->andElim(thm, 0));
00596     addCNFFact(d_commonRules->andElim(thm, 1));
00597     return;
00598   }
00599   
00600   // Check the kids in e[0], replace them with cache[e[0][i]], rebuild thm
00601   vector<unsigned> changed;
00602   vector<Theorem> substitutions;
00603   int c=0;
00604   for(Expr::iterator j = lhs.begin(), jend = lhs.end(); j!=jend; ++c,++j) {
00605     const Expr& phi = *j;
00606     if(!phi.isPropLiteral()) {
00607       Theorem phiIffVar = findInCNFCache(phi);
00608       if(phiIffVar.isNull()) {
00609         // Create a new variable for this child
00610         phiIffVar = d_commonRules->varIntroSkolem(phi);
00611         addToCNFCache(phiIffVar);
00612       }
00613       DebugAssert(phiIffVar.isRewrite(),
00614                   "SearchImplBase::applyCNFRules: result = " +
00615                   result.toString());
00616       DebugAssert(phi == phiIffVar.getLHS(),
00617                   "SearchImplBase::applyCNFRules:\n phi = " + 
00618                   phi.toString()
00619                   + "\n\n phiIffVar = " + phiIffVar.toString());
00620       DebugAssert(phiIffVar.getRHS().isAbsLiteral(),
00621                   "SearchImplBase::applyCNFRules: phiIffVar = " +
00622                   phiIffVar.toString());
00623       changed.push_back(c);
00624       substitutions.push_back(phiIffVar);
00625       applyCNFRules(phiIffVar);
00626     }
00627   }
00628   if(changed.size() > 0) {
00629     Theorem subst = 
00630       d_commonRules->substitutivityRule(lhs, changed, substitutions);
00631     subst = d_commonRules->symmetryRule(subst);
00632     result = d_commonRules->transitivityRule(subst, result);
00633   }
00634 
00635   switch(result.getLHS().getKind()) {
00636   case AND:
00637     result = d_rules->andCNFRule(result);
00638     break;
00639   case OR:
00640     result = d_rules->orCNFRule(result);
00641     break;
00642   case IFF:
00643     result = d_rules->iffCNFRule(result);
00644     break;
00645   case IMPLIES:
00646     result = d_rules->impCNFRule(result);
00647     break;
00648   case ITE:
00649     result = d_rules->iteCNFRule(result);
00650     break;
00651   default:
00652     DebugAssert(false,
00653                 "SearchImplBase::applyCNFRules: "
00654                 "the input operator must be and|or|iff|imp|ite\n result = " + 
00655                 result.getLHS().toString());
00656     break;
00657   }
00658 
00659   // FIXME: eliminate this once debugged
00660   Theorem clauses(result);
00661 
00662   // Enqueue the clauses
00663   DebugAssert(!clauses.isNull(), "Oops!..");
00664   DebugAssert(clauses.getExpr().isAnd(), "clauses = "
00665               +clauses.getExpr().toString());
00666 
00667   // The clauses may containt term ITEs, and we need to translate those
00668   
00669   for(int i=0, iend=clauses.getExpr().arity(); i<iend; ++i) {
00670     Theorem clause(d_commonRules->andElim(clauses,i));
00671     addCNFFact(clause);
00672   }
00673   TRACE_MSG("mycnf","applyCNFRules => }");
00674 }
00675 
00676 
00677 bool SearchImplBase::isClause(const Expr& e) {
00678   if(e.isAbsLiteral()) return true;
00679   if(!e.isOr()) return false;
00680 
00681   bool cnf(true);
00682   for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend && cnf; ++i)
00683     cnf = (*i).isAbsLiteral();
00684   return cnf;
00685 }
00686 
00687 
00688 bool
00689 SearchImplBase::isPropClause(const Expr& e) {
00690   if(e.isPropLiteral()) return true;
00691   if(!e.isOr()) return false;
00692 
00693   bool cnf(true);
00694   for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend && cnf; ++i)
00695     cnf = (*i).isPropLiteral();
00696   return cnf;
00697 }
00698 
00699 
00700 bool
00701 SearchImplBase::isGoodSplitter(const Expr& e) {
00702   if(!*d_ignoreCnfVarsOption) return true;
00703   TRACE("isGoodSplitter", "isGoodSplitter(", e, ") {");
00704   // Check for var being an auxiliary CNF variable
00705   const Expr& var = e.isNot()? e[0] : e;
00706   bool res(!isCNFVar(var));
00707   TRACE("isGoodSplitter", "isGoodSplitter => ", res? "true" : "false", " }");
00708   return res;
00709 }
00710 
00711 
00712 void
00713 SearchImplBase::addToCNFCache(const Theorem& thm) {
00714   TRACE("mycnf", "addToCNFCache(", thm.getExpr(), ")");
00715 
00716   d_core->getStatistics().counter("CNF New Vars")++;
00717 
00718   Theorem result = thm;
00719   DebugAssert(result.isRewrite(),
00720               "SearchImplBase::addToCNFCache: input must be an iff: " + 
00721               result.getExpr().toString());
00722   // Record the CNF variable
00723   d_cnfVars[thm.getRHS()] = true;
00724 
00725   Theorem t(thm);
00726   Expr phi = thm.getLHS();
00727   while(phi.isNot()) {
00728     t = d_commonRules->iffContrapositive(thm);
00729     phi = phi[0];
00730   }
00731   DebugAssert(d_cnfCache.count(phi) == 0, 
00732               "thm = "+thm.getExpr().toString() + 
00733               "\n t = "+ t.getExpr().toString());
00734   //d_cnfCache.insert(phi, t);
00735   d_cnfCache.insert(phi, t, d_bottomScope);
00736 }
00737 
00738 
00739 Theorem 
00740 SearchImplBase::findInCNFCache(const Expr& e) { 
00741   TRACE("mycnf", "findInCNFCache(", e, ") { ");
00742   Expr phi(e);
00743 
00744   int numNegs(0);
00745   // Strip all the top-level negations from e
00746   while(phi.isNot()) {
00747     phi = phi[0]; numNegs++;
00748   }
00749   CDMap<Expr,Theorem>::iterator it = d_cnfCache.find(phi);
00750   if(it != d_cnfCache.end()) {
00751     // IF_DEBUG(debugger.counter("CNF cache hits")++);
00752     d_core->getStatistics().counter("CNF cache hits")++;
00753     Theorem thm = (*it).second;
00754     
00755     DebugAssert(thm.isRewrite() && thm.getLHS() == phi,
00756                 "SearchImplBase::findInCNFCache: thm must be an iff: " + 
00757                 thm.getExpr().toString());
00758     
00759     // Now put all the negations back.  If the number of negations is
00760     // odd, first transform phi<=>v into !phi<=>!v.  Then apply
00761     // !!phi<=>phi rewrite as many times as needed.
00762     if(numNegs % 2 != 0) {
00763       thm = d_commonRules->iffContrapositive(thm); 
00764       numNegs--;
00765     }
00766     for(; numNegs > 0; numNegs-=2) {
00767       Theorem t = d_commonRules->rewriteNotNot(!!(thm.getLHS()));
00768       thm = d_commonRules->transitivityRule(t,thm);
00769     }
00770 
00771     DebugAssert(numNegs == 0, "numNegs = "+int2string(numNegs));
00772     TRACE("mycnf", "findInCNFCache => ", thm.getExpr(), " }");
00773     return thm;
00774   }
00775   TRACE_MSG("mycnf", "findInCNFCache => null  }");
00776   return Theorem();
00777 }
00778 
00779 /*!
00780  * Strategy:
00781  *
00782  * For a given atomic formula phi(ite(c, t1, t2)) which depends on a
00783  * term ITE, generate an equisatisfiable formula:
00784  *
00785  * phi(x) & ite(c, t1=x, t2=x),
00786  *
00787  * where x is a new variable.
00788  *
00789  * The phi(x) part will be generated by the caller, and our job is to
00790  * assert the 'ite(c, t1=x, t2=x)', and return a rewrite theorem
00791  * phi(ite(c, t1, t2)) <=> phi(x).
00792  */
00793 Theorem
00794 SearchImplBase::replaceITE(const Expr& e) {
00795   TRACE("replaceITE","replaceITE(", e, ") { ");
00796   Theorem res;
00797 
00798   CDMap<Expr,Theorem>::iterator i=d_replaceITECache.find(e),
00799     iend=d_replaceITECache.end();
00800   if(i!=iend) {
00801     TRACE("replaceITE", "replaceITE[cached] => ", (*i).second, " }");
00802     return (*i).second;
00803   }
00804   
00805   if(e.isAbsLiteral())
00806     res = d_core->rewriteLiteral(e);
00807   else
00808     res = d_commonRules->reflexivityRule(e);
00809 
00810 
00811   // If 'res' is e<=>phi, and the resulting formula phi is not a
00812   // literal, introduce a new variable x, enqueue phi<=>x, and return
00813   // e<=>x.
00814   if(!res.getRHS().isPropLiteral()) {
00815     Theorem varThm(findInCNFCache(res.getRHS()));
00816     if(varThm.isNull()) {
00817       varThm = d_commonRules->varIntroSkolem(res.getRHS());
00818       Theorem var;
00819       if(res.isRewrite())
00820         var = d_commonRules->transitivityRule(res,varThm);
00821       else 
00822         var = d_commonRules->iffMP(res,varThm);
00823       //d_cnfVars[var.getExpr()] = true;
00824       //addCNFFact(var);
00825       addToCNFCache(varThm);
00826     }
00827     applyCNFRules(varThm);
00828     //enqueueCNFrec(varThm);
00829     res = d_commonRules->transitivityRule(res, varThm);
00830   }
00831   
00832   d_replaceITECache[e] = res;
00833   
00834   TRACE("replaceITE", "replaceITE => ", res, " }");
00835   return res;
00836 }

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