search_theorem_producer.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file search_theorem_producer.cpp
00004  * \brief Implementation of the proof rules for the simple search engine
00005  * 
00006  * Author: Sergey Berezin
00007  * 
00008  * Created: Mon Feb 24 14:51:51 2003
00009  *
00010  * <hr>
00011  * Copyright (C) 2003 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 #include "search.h"
00031 #include "assumptions_value.h"
00032 #include "theory_core.h"
00033 #include "theorem_manager.h"
00034 #include "common_proof_rules.h"
00035 
00036 
00037 #define _CVCL_TRUSTED_
00038 #include "search_theorem_producer.h"
00039 
00040 
00041 using namespace std;
00042 using namespace CVCL;
00043 
00044 
00045 /////////////////////////////////////////////////////////////////////////////
00046 // class SearchEngine trusted methods
00047 /////////////////////////////////////////////////////////////////////////////
00048 
00049 SearchEngineRules*
00050 SearchEngine::createRules() {
00051   return new SearchEngineTheoremProducer(d_core->getTM());
00052 }
00053 
00054 
00055 SearchEngineTheoremProducer::SearchEngineTheoremProducer(TheoremManager* tm)
00056   : TheoremProducer(tm), d_commonRules(tm->getRules())
00057 { }
00058 
00059 
00060 /////////////////////////////////////////////////////////////////////////////
00061 // Proof rules
00062 /////////////////////////////////////////////////////////////////////////////
00063 
00064 // Proof by contradiction: !A |- FALSE ==> |- A.  "!A" doesn't
00065 // have to be present in the assumptions.
00066 Theorem
00067 SearchEngineTheoremProducer::proofByContradiction(const Expr& a,
00068                                                   const Theorem& pfFalse) {
00069   if(CHECK_PROOFS)
00070     CHECK_SOUND(pfFalse.getExpr().isFalse(),
00071                 "proofByContradiction: pfFalse = : " + pfFalse.toString());
00072   Expr not_a(!a);
00073   Assumptions assump;
00074   Proof pf;
00075   if(withAssumptions()) {
00076     // Make a clean copy, so we can erase !a safely
00077     assump = pfFalse.getAssumptions() - not_a;
00078   }
00079   if(withProof()) {
00080     // TODO: optimize with 1 traversal?
00081     Theorem thm(pfFalse.getAssumptions()[not_a]);
00082     Proof u; // proof label for !a
00083     if(!thm.isNull()) u = thm.getProof();
00084     // Proof compaction: if u is Null, use "FALSE => A" rule
00085     if(u.isNull())
00086       pf = newPf("false_implies_anything", a, pfFalse.getProof());
00087     else
00088       pf = newPf("pf_by_contradiction", a,
00089                  // LAMBDA-abstraction (LAMBDA (u: !a): pfFalse)
00090                  newPf(u, not_a, pfFalse.getProof()));
00091   }
00092   return newTheorem(a, assump, pf);
00093 }
00094     
00095 // Similar rule, only negation introduction:
00096 // A |- FALSE ==> !A
00097 Theorem
00098 SearchEngineTheoremProducer::negIntro(const Expr& not_a,
00099                                       const Theorem& pfFalse) {
00100   if(CHECK_PROOFS) {
00101     CHECK_SOUND(pfFalse.getExpr().isFalse(),
00102                 "negIntro: pfFalse = : " + pfFalse.toString());
00103     CHECK_SOUND(not_a.isNot(), "negIntro: not_a = "+not_a.toString());
00104   }
00105 
00106   Expr a(not_a[0]);
00107   Assumptions assump;
00108   Proof pf;
00109   if(withAssumptions()) {
00110     // Make a clean copy, so we can erase 'a' safely
00111     assump = pfFalse.getAssumptions() - a;
00112   }
00113   if(withProof()) {
00114     Theorem thm(pfFalse.getAssumptions()[a]);
00115     Proof u; // proof label for 'a'
00116     if(!thm.isNull()) u = thm.getProof();
00117     // Proof compaction: if u is Null, use "FALSE => !A" rule
00118     if(u.isNull())
00119       pf = newPf("false_implies_anything", not_a, pfFalse.getProof());
00120     else
00121       pf = newPf("neg_intro", not_a,
00122                  // LAMBDA-abstraction (LAMBDA (u: a): pfFalse)
00123                  newPf(u, a, pfFalse.getProof()));
00124   }
00125   return newTheorem(not_a, assump, pf);
00126 }
00127     
00128 
00129 // Case split: u1:A |- C, u2:!A |- C  ==>  |- C
00130 Theorem
00131 SearchEngineTheoremProducer::caseSplit(const Expr& a,
00132                                        const Theorem& a_proves_c,
00133                                        const Theorem& not_a_proves_c) {
00134   Expr c(a_proves_c.getExpr());
00135 
00136   if(CHECK_PROOFS) {
00137     CHECK_SOUND(c == not_a_proves_c.getExpr(), 
00138                 "caseSplit: conclusions differ:\n  positive case C = "
00139                 + c.toString() + "\n  negative case C = "
00140                 + not_a_proves_c.getExpr().toString());
00141     // The opposite assumption should not appear in the theorems
00142     // Actually, this doesn't violate soundness, no reason to check
00143 //     CHECK_SOUND(a_proves_c.getAssumptions()[!a].isNull(), 
00144 //              "caseSplit: wrong assumption: " + (!a).toString()
00145 //              +"\n in "+a_proves_c.toString());
00146 //     CHECK_SOUND(not_a_proves_c.getAssumptions()[a].isNull(), 
00147 //              "caseSplit: wrong assumption: " + a.toString()
00148 //              +"\n in "+not_a_proves_c.toString());
00149   }
00150 
00151   Assumptions a1;
00152   Assumptions a2;
00153 
00154   // Proof compaction: if either theorem proves C without a or !a,
00155   // then just use that theorem.  This only works if assumptions are
00156   // active.
00157   if(withAssumptions()) {
00158     a1 = a_proves_c.getAssumptions() - a;
00159     a2 = not_a_proves_c.getAssumptions() - !a;
00160 
00161     if (a1 == a_proves_c.getAssumptions()) return a_proves_c;
00162     if (a2 == not_a_proves_c.getAssumptions()) return not_a_proves_c;
00163   }
00164   // No easy way out.  Do the work.
00165   Assumptions assump;
00166   Proof pf;
00167   if(withAssumptions()) {
00168     assump = a1;
00169     a1.add(a2);
00170   }
00171   if(withProof()) {
00172     // Create lambda-abstractions
00173     vector<Proof> pfs;
00174     pfs.push_back(newPf(a_proves_c.getAssumptions()[a].getProof(), 
00175                         a, a_proves_c.getProof()));
00176     pfs.push_back(newPf(not_a_proves_c.getAssumptions()[!a].getProof(), 
00177                         !a, not_a_proves_c.getProof()));
00178     pf = newPf("case_split", a, c, pfs);
00179   }
00180   return newTheorem(c, assump, pf);
00181 }
00182 
00183 // Conflict clause rule: 
00184 // Gamma, A_1,...,A_n |- B ==> Gamma |- (OR B A_1 ... A_n)
00185 // The assumptions A_i are given by the vector 'lits'.
00186 // If B==FALSE, it is omitted from the result.
00187 
00188 // NOTE: here "!A_i" means an inverse of A_i, not just a negation.
00189 // That is, if A_i is NOT C, then !A_i is C.
00190 
00191 // verification function used by conflictClause
00192 void SearchEngineTheoremProducer::verifyConflict(const Theorem& thm, 
00193                                                  TheoremMap& m) {
00194   const Assumptions::iterator iend = thm.getAssumptions().end();
00195   for (Assumptions::iterator i = thm.getAssumptions().begin(); 
00196        i != iend; ++i) {
00197     CHECK_SOUND(!i->isNull(),
00198                 "SearchEngineTheoremProducer::conflictClause: "
00199                 "Found null theorem");
00200     if (!i->isFlagged()) {
00201       i->setFlag();
00202       if (m.count(*i) == 0) {
00203         CHECK_SOUND(!i->isAssump(), 
00204                     "SearchEngineTheoremProducer::conflictClause: "
00205                     "literal and gamma sets do not form a complete "
00206                     "cut of Theorem assumptions. Stray theorem: \n"
00207                     +i->toString());
00208         verifyConflict(*i, m);
00209       }
00210       else {
00211         m[*i] = true;
00212       }
00213     }
00214   }
00215 }
00216 
00217 
00218 Theorem
00219 SearchEngineTheoremProducer::
00220 conflictClause(const Theorem& thm, const vector<Theorem>& lits, 
00221                const vector<Theorem>& gamma) {
00222   TRACE("search proofs", "conflictClause(", thm.getExpr(), ") {");
00223   IF_DEBUG(if(debugger.trace("search proofs")) {
00224     ostream& os = debugger.getOS();
00225     os << "lits = [";
00226     for(vector<Theorem>::const_iterator i=lits.begin(), iend=lits.end();
00227         i!=iend; ++i)
00228       os << i->getExpr() << ",\n";
00229     os << "]\n\ngamma = [";
00230     for(vector<Theorem>::const_iterator i=gamma.begin(), iend=gamma.end();
00231         i!=iend; ++i)
00232       os << i->getExpr() << ",\n";
00233     os << "]" << endl;
00234   });
00235   bool checkProofs(CHECK_PROOFS);
00236   // This rule only makes sense when runnnig with assumptions
00237   if(checkProofs) {
00238     CHECK_SOUND(withAssumptions(),
00239                 "conflictClause: called while running without assumptions");
00240   }
00241 
00242   // Assumptions aOrig(thm.getAssumptions());
00243 
00244   vector<Expr> literals;
00245   vector<Proof> u; // Vector of proof labels
00246   literals.reserve(lits.size() + 1);
00247   u.reserve(lits.size());
00248   const vector<Theorem>::const_iterator iend = lits.end();
00249   for(vector<Theorem>::const_iterator i=lits.begin(); i!=iend; ++i) {
00250     Expr neg(i->getExpr().negate());
00251 
00252     literals.push_back(neg);
00253     if(withProof()) u.push_back(i->getProof());
00254   }
00255 
00256   if(checkProofs) {
00257     TheoremMap m;
00258     TRACE_MSG("search proofs", "adding gamma to m: {");
00259     for(vector<Theorem>::const_iterator i = gamma.begin();
00260         i != gamma.end(); ++i) {
00261       TRACE("search proofs", "m[", *i, "]");
00262       m[*i] = false;
00263     }
00264     TRACE_MSG("search proofs", "}");
00265 
00266     for(vector<Theorem>::const_iterator i = lits.begin(); i!=iend; ++i) {
00267       TRACE("search proofs", "check lit: ", *i, "");
00268       CHECK_SOUND(m.count(*i) == 0, 
00269                   "SearchEngineTheoremProducer::conflictClause: "
00270                   "literal and gamma sets are not disjoint: lit = "
00271                   +i->toString());
00272       m[*i] = false;
00273     }
00274     thm.clearAllFlags();
00275     verifyConflict(thm, m);
00276     TheoremMap::iterator t = m.begin(), tend = m.end();
00277     for (; t != tend; ++t) {
00278       CHECK_SOUND(t->second == true,
00279                   "SearchEngineTheoremProducer::conflictClause: "
00280                   "literal or gamma set contains extra element : "
00281                   + t->first.toString());
00282     }
00283   }
00284  
00285   Assumptions a(gamma);
00286 
00287   if(!thm.getExpr().isFalse())
00288     literals.push_back(thm.getExpr());
00289 
00290   Proof pf;
00291   if(withProof()) {
00292     if(lits.size()>0) {
00293       vector<Expr> assump;
00294       // If assumptions are not leaves, we need to create new
00295       // variables for them and substitute them for their proofs in
00296       // the proof term
00297       ExprHashMap<Expr> subst;
00298       DebugAssert(u.size() == lits.size(), "");
00299       for(size_t i=0, iend=lits.size(); i<iend; ++i) {
00300         const Expr& e(lits[i].getExpr());
00301         assump.push_back(e);
00302         Proof& v = u[i];
00303         if(!v.getExpr().isVar()) {
00304           Proof label = newLabel(e);
00305           subst[v.getExpr()] = label.getExpr();
00306           v = label;
00307         }
00308       }
00309       Proof body(thm.getProof());
00310       if(!subst.empty())
00311         body = Proof(body.getExpr().substExpr(subst));
00312       pf = newPf("conflict_clause", newPf(u, assump, body));
00313     }
00314     else
00315       pf = newPf("false_to_empty_or", thm.getProof());
00316   }
00317   Theorem res(newTheorem(Expr(OR, literals, d_em), a, pf));
00318   TRACE("search proofs", "conflictClause => ", res.getExpr(), " }");
00319   return res;
00320 }
00321 
00322 
00323 // Theorem
00324 // SearchEngineTheoremProducer::
00325 // conflictClause(const Theorem& thm, const vector<Expr>& lits) {
00326 //   bool checkProofs(CHECK_PROOFS);
00327 //   // This rule only makes sense when runnnig with assumptions
00328 //   if(checkProofs) {
00329 //     CHECK_SOUND(withAssumptions(),
00330 //              "conflictClause: called while running without assumptions");
00331 //   }
00332 
00333 //   Assumptions aOrig(thm.getAssumptions());
00334 
00335 //   vector<Expr> literals;
00336 //   vector<Expr> negations;
00337 //   vector<Proof> u; // Vector of proof labels
00338 //   literals.reserve(lits.size() + 1);
00339 //   negations.reserve(lits.size());
00340 //   u.reserve(lits.size());
00341 //   for(vector<Expr>::const_iterator i=lits.begin(), iend=lits.end();
00342 //       i!=iend; ++i) {
00343 //     Expr neg(i->isNot()? (*i)[0] : !(*i));
00344 //     if(checkProofs)
00345 //       CHECK_SOUND(!aOrig[neg].isNull(), 
00346 //                "SearchEngineTheoremProducer::conflictClause: "
00347 //                "literal is not in the set of assumptions: neg = "
00348 //                +neg.toString() + "\n Theorem = " + thm.toString());
00349 //     literals.push_back(*i);
00350 //     negations.push_back(neg);
00351 //     if(withProof()) u.push_back(aOrig[neg].getProof());
00352 //   }
00353 
00354 //   Assumptions a = aOrig - negations;
00355 
00356 //   if(!thm.getExpr().isFalse())
00357 //     literals.push_back(thm.getExpr());
00358 
00359 //   Proof pf;
00360 //   if(withProof()) {
00361 //     if(lits.size()>0)
00362 //       pf = newPf("conflict_clause", newPf(u, literals, thm.getProof()));
00363 //     else
00364 //       pf = newPf("false_to_empty_or", thm.getProof());
00365 //   }
00366 //  // Use ExprManager in newExpr, since literals may be empty
00367 //   return newTheorem(Expr(d_em, OR, literals), a, pf);
00368 // }
00369 
00370 
00371 // "Cut" rule: { G_i |- A_i };  G', { A_i } |- B ==> union(G_i)+G' |- B.
00372 Theorem
00373 SearchEngineTheoremProducer::
00374 cutRule(const vector<Theorem>& thmsA,
00375         const Theorem& as_prove_b) {
00376   if(CHECK_PROOFS)
00377     CHECK_SOUND(withAssumptions(),
00378                 "cutRule called without assumptions activated");
00379   // Optimization: use only those theorems that occur in B's assumptions.
00380   // *** No, take it back, it's a mis-optimization.  Most of the time,
00381   // cutRule is applied when we *know* thmsA are present in the
00382   // assumptions of 'as_proof_b'.
00383 
00384   Proof pf;
00385   vector<Expr> exprs;
00386   exprs.reserve(thmsA.size() + 1);
00387   const vector<Theorem>::const_iterator iend = thmsA.end();
00388   for(vector<Theorem>::const_iterator i=thmsA.begin(); i!=iend; ++i) {
00389     exprs.push_back(i->getExpr());
00390   }
00391 
00392   Assumptions a(thmsA); // add the As
00393   a.add(as_prove_b.getAssumptions() - exprs); // Add G'
00394   
00395   if(withProof()) {
00396     vector<Proof> pfs;
00397     pfs.reserve(thmsA.size() + 1);
00398     for(vector<Theorem>::const_iterator i = thmsA.begin(); i != iend; ++i) {
00399       pfs.push_back(i->getProof());
00400     }
00401     exprs.push_back(as_prove_b.getExpr());
00402     pfs.push_back(as_prove_b.getProof());
00403     pf = newPf("cut_rule",exprs,pfs);
00404   }
00405   return newTheorem(as_prove_b.getExpr(), a, pf);
00406 }
00407 
00408 
00409 void 
00410 SearchEngineTheoremProducer::checkSoundNoSkolems(const Expr& e, 
00411                                                  ExprMap<bool>& visited, 
00412                                                  const ExprMap<bool>& skolems)
00413 {
00414   if(visited.count(e)>0)
00415     return;
00416   else
00417     visited[e] = true;
00418   CHECK_SOUND(skolems.count(e) == 0, 
00419               "skolem constant found in axioms of false theorem: "
00420               + e.toString());
00421   for(Expr::iterator it = e.begin(), end = e.end(); it!= end; ++it)
00422     checkSoundNoSkolems(*it, visited, skolems);
00423   if(e.getKind() == FORALL || e.getKind() == EXISTS)
00424     checkSoundNoSkolems(e.getBody(), visited, skolems);       
00425 }
00426 
00427 void 
00428 SearchEngineTheoremProducer::checkSoundNoSkolems(const Theorem& t, 
00429                                                  ExprMap<bool>& visited, 
00430                                                  const ExprMap<bool>& skolems)
00431 {
00432   if(t.isFlagged())
00433     return;
00434   t.setFlag();
00435   if(t.isAssump())
00436     checkSoundNoSkolems(t.getExpr(), visited, skolems);
00437   else
00438   {
00439       Assumptions a = t.getAssumptions();
00440       Assumptions::iterator it = a.begin(), end = a.end();
00441       for(; it!=end; ++it)
00442         checkSoundNoSkolems(*it, visited, skolems);
00443    }
00444 }
00445 
00446 /*! Eliminate skolem axioms: 
00447  * Gamma, Delta |- false => Gamma|- false 
00448  * where Delta is a set of skolem axioms {|-Exists(x) phi (x) => phi(c)}
00449  * and gamma does not contain any of the skolem constants c.
00450  */
00451 
00452 Theorem 
00453 SearchEngineTheoremProducer::eliminateSkolemAxioms(const Theorem& tFalse, 
00454                                             const std::vector<Theorem>& delta)
00455 {
00456   TRACE("skolem", "=>eliminateSkolemAxioms ", delta.size(), "{");
00457   if(delta.empty())
00458   {
00459     TRACE("skolem",  "eliminateSkolemAxioms","" , "}");
00460     return tFalse;
00461   }
00462   const Expr& falseExpr = tFalse.getExpr();
00463   if(CHECK_PROOFS) {
00464     CHECK_SOUND(falseExpr.isFalse(),
00465                 "eliminateSkolemAxiom called on non-false theorem");
00466     ExprMap<bool> visited;
00467     ExprMap<bool> skolems;
00468     vector<Theorem>::const_iterator it = delta.begin(), end = delta.end();
00469     for(; it!=end; ++it) {
00470       CHECK_SOUND(it->isRewrite(),
00471                   "eliminateSkolemAxioms(): Skolem axiom is not "
00472                   "an IFF: "+it->toString());
00473       const Expr& ex = it->getLHS();
00474       CHECK_SOUND(ex.isExists(), 
00475                   "Did not receive skolem axioms in Delta"
00476                   " of eliminateSkolemAxioms" + it->toString());
00477       // Collect the Skolem constants for further soundness checks
00478       for(unsigned int j=0; j<ex.getVars().size(); j++) {
00479         Expr sk_var(ex.skolemExpr(j));
00480         if(sk_var.getType().isBool()) {
00481           sk_var = d_em->newLeafExpr(sk_var.mkOp());
00482         }
00483         skolems[sk_var] = true;
00484         TRACE("skolem", ">> Eliminating variable: ", sk_var, "<<");
00485       }
00486     }
00487     tFalse.clearAllFlags();
00488     checkSoundNoSkolems(tFalse, visited, skolems);
00489   }
00490   Assumptions a;
00491   if(withAssumptions())
00492     a = tFalse.getAssumptionsCopy();
00493   Proof pf;
00494   if(!withProof()) return tFalse;
00495   else 
00496     {
00497       Proof origFalse = tFalse.getProof();
00498       std::vector<Proof>skolemizeLabels;
00499       std::vector<Expr> exprs;
00500       for(unsigned int i=0; i<delta.size(); i++)
00501         {
00502           exprs.push_back(delta[i].getExpr());
00503           skolemizeLabels.push_back(delta[i].getProof());
00504         }
00505       pf = newPf(skolemizeLabels, exprs, origFalse);
00506     }
00507   TRACE("skolem",  "eliminateSkolemAxioms","" , "}");
00508   return newTheorem(tFalse.getExpr(), a, pf);
00509 }
00510 
00511 
00512 Theorem
00513 SearchEngineTheoremProducer::unitProp(const std::vector<Theorem>& thms,
00514                                       const Theorem& clause,
00515                                       unsigned i) {
00516   Expr e(clause.getExpr());
00517   if(CHECK_PROOFS) {
00518     // Soundness check: first, check the form of the 'clause' theorem
00519     CHECK_SOUND(e.isOr() && e.arity() > (int)i,
00520                 "SearchEngineTheoremProducer::unitProp: bad theorem or i="
00521                 +int2string(i)+" > arity="+int2string(e.arity())
00522                 +" in clause = " + clause.toString());
00523     // Now, check correspondence of thms to the disjunction
00524     CHECK_SOUND(((int)thms.size()) == e.arity() - 1,
00525                 "SearchEngineTheoremProducer::unitProp: "
00526                 "wrong number of theorems"
00527                 "\n  thms.size = " + int2string(thms.size())
00528                 +"\n  clause.arity = " + int2string(e.arity()));
00529 
00530     for(unsigned j=0,k=0; j<thms.size(); j++) {
00531       if(j!=i) {
00532         Expr ej(e[j]), ek(thms[k].getExpr());
00533         CHECK_SOUND((ej.isNot() && ej[0] == ek) || (ek.isNot() && ej == ek[0]),
00534                     "SearchEngineTheoremProducer::unitProp: "
00535                     "wrong theorem["+int2string(k)+"]"
00536                     "\n  thm = " + thms[k].toString() +
00537                     "\n  literal = " + e[j].toString() +
00538                     "\n  clause = " + clause.toString());
00539         k++;
00540       }
00541     }
00542   }
00543 
00544   Assumptions a;
00545   Proof pf;
00546   if(withAssumptions()) {
00547     a = Assumptions(thms);
00548     a.add(clause);
00549   }
00550 
00551   if(withProof()) {
00552     vector<Proof> pfs;
00553     vector<Expr> exprs;
00554     exprs.reserve(thms.size() + 1);
00555     pfs.reserve(thms.size()+1);
00556     const vector<Theorem>::const_iterator iend = thms.end();
00557     for(vector<Theorem>::const_iterator i=thms.begin(); i!=iend; ++i) {
00558       exprs.push_back(i->getExpr());
00559       pfs.push_back(i->getProof());
00560     }
00561     exprs.push_back(clause.getExpr());
00562     pfs.push_back(clause.getProof());
00563     pf = newPf("unit_prop", exprs, pfs);
00564   }
00565   return newTheorem(e[i], a, pf);
00566 }
00567 
00568 Theorem
00569 SearchEngineTheoremProducer::propAndrAF(const Theorem& andr_th,
00570                                         bool left,
00571                                         const Theorem& b_th) {
00572   const Expr& andr_e(andr_th.getExpr());
00573   if(CHECK_PROOFS) {
00574     CHECK_SOUND(andr_e.getKind() == AND_R &&
00575                 ((left && b_th.refutes(andr_e[1])) ||
00576                  (!left && b_th.refutes(andr_e[2]))),
00577                 "SearchEngineTheoremProducer::propAndrAF");
00578   }
00579 
00580   Assumptions a;
00581   Proof pf;
00582   if(withAssumptions()) {
00583     a.add(andr_th);
00584     a.add(b_th);
00585   }
00586 
00587   if(withProof()) {
00588     vector<Proof> pfs;
00589     vector<Expr> exprs;
00590     exprs.push_back(andr_th.getExpr());
00591     exprs.push_back(b_th.getExpr());
00592     pfs.push_back(andr_th.getProof());
00593     pfs.push_back(b_th.getProof());
00594     // can we note which branch to take?
00595     pf = newPf("prop_andr_af", exprs, pfs);
00596   }
00597 
00598   return newTheorem(andr_e[0].negate(), a, pf);
00599 }
00600 
00601 Theorem
00602 SearchEngineTheoremProducer::propAndrAT(const Theorem& andr_th,
00603                                         const Theorem& l_th,
00604                                         const Theorem& r_th) {
00605   const Expr& andr_e(andr_th.getExpr());
00606   if(CHECK_PROOFS) {
00607     CHECK_SOUND(andr_e.getKind() == AND_R &&
00608                 l_th.proves(andr_e[1]) && r_th.proves(andr_e[2]),
00609                 "SearchEngineTheoremProducer::propAndrAT");
00610   }
00611 
00612   Assumptions a;
00613   Proof pf;
00614   if(withAssumptions()) {
00615     a.add(andr_th);
00616     a.add(l_th);
00617     a.add(r_th);
00618   }
00619 
00620   if(withProof()) {
00621     vector<Proof> pfs;
00622     vector<Expr> exprs;
00623     exprs.push_back(andr_th.getExpr());
00624     exprs.push_back(l_th.getExpr());
00625     exprs.push_back(r_th.getExpr());
00626     pfs.push_back(andr_th.getProof());
00627     pfs.push_back(l_th.getProof());
00628     pfs.push_back(r_th.getProof());
00629     pf = newPf("prop_andr_at", exprs, pfs);
00630   }
00631 
00632   return newTheorem(andr_e[0], a, pf);
00633 }
00634 
00635 void
00636 SearchEngineTheoremProducer::propAndrLRT(const Theorem& andr_th,
00637                                          const Theorem& a_th,
00638                                          Theorem* l_th,
00639                                          Theorem* r_th) {
00640   const Expr& andr_e(andr_th.getExpr());
00641   if(CHECK_PROOFS) {
00642     CHECK_SOUND(andr_e.getKind() == AND_R && a_th.proves(andr_e[0]),
00643                 "SearchEngineTheoremProducer::propAndrLRT");
00644   }
00645 
00646   Assumptions a;
00647   Proof pf;
00648   if(withAssumptions()) {
00649     a.add(andr_th);
00650     a.add(a_th);
00651   }
00652 
00653   if(withProof()) {
00654     vector<Proof> pfs;
00655     vector<Expr> exprs;
00656     exprs.push_back(andr_th.getExpr());
00657     exprs.push_back(a_th.getExpr());
00658     pfs.push_back(andr_th.getProof());
00659     pfs.push_back(a_th.getProof());
00660     pf = newPf("prop_andr_lrt", exprs, pfs);
00661   }
00662 
00663   if (l_th) *l_th = newTheorem(andr_e[1], a, pf);
00664   if (r_th) *r_th = newTheorem(andr_e[2], a, pf);
00665 }
00666 
00667 Theorem
00668 SearchEngineTheoremProducer::propAndrLF(const Theorem& andr_th,
00669                                         const Theorem& a_th,
00670                                         const Theorem& r_th) {
00671   const Expr& andr_e(andr_th.getExpr());
00672   if(CHECK_PROOFS) {
00673     CHECK_SOUND(andr_e.getKind() == AND_R &&
00674                 a_th.refutes(andr_e[0]) && r_th.proves(andr_e[2]),
00675                 "SearchEngineTheoremProducer::propAndrLF");
00676   }
00677 
00678   Assumptions a;
00679   Proof pf;
00680   if(withAssumptions()) {
00681     a.add(andr_th);
00682     a.add(a_th);
00683     a.add(r_th);
00684   }
00685 
00686   if(withProof()) {
00687     vector<Proof> pfs;
00688     vector<Expr> exprs;
00689     exprs.push_back(andr_th.getExpr());
00690     exprs.push_back(a_th.getExpr());
00691     exprs.push_back(r_th.getExpr());
00692     pfs.push_back(andr_th.getProof());
00693     pfs.push_back(a_th.getProof());
00694     pfs.push_back(r_th.getProof());
00695     pf = newPf("prop_andr_lf", exprs, pfs);
00696   }
00697 
00698   return newTheorem(andr_e[1].negate(), a, pf);
00699 }
00700 
00701 Theorem
00702 SearchEngineTheoremProducer::propAndrRF(const Theorem& andr_th,
00703                                         const Theorem& a_th,
00704                                         const Theorem& l_th) {
00705   const Expr& andr_e(andr_th.getExpr());
00706   if(CHECK_PROOFS) {
00707     CHECK_SOUND(andr_e.getKind() == AND_R &&
00708                 a_th.refutes(andr_e[0]) && l_th.proves(andr_e[1]),
00709                 "SearchEngineTheoremProducer::propAndrRF");
00710   }
00711 
00712   Assumptions a;
00713   Proof pf;
00714   if(withAssumptions()) {
00715     a.add(andr_th);
00716     a.add(a_th);
00717     a.add(l_th);
00718   }
00719 
00720   if(withProof()) {
00721     vector<Proof> pfs;
00722     vector<Expr> exprs;
00723     exprs.push_back(andr_th.getExpr());
00724     exprs.push_back(a_th.getExpr());
00725     exprs.push_back(l_th.getExpr());
00726     pfs.push_back(andr_th.getProof());
00727     pfs.push_back(a_th.getProof());
00728     pfs.push_back(l_th.getProof());
00729     pf = newPf("prop_andr_rf", exprs, pfs);
00730   }
00731 
00732   return newTheorem(andr_e[2].negate(), a, pf);
00733 }
00734 
00735 Theorem
00736 SearchEngineTheoremProducer::confAndrAT(const Theorem& andr_th,
00737                                         const Theorem& a_th,
00738                                         bool left,
00739                                         const Theorem& b_th) {
00740   const Expr& andr_e(andr_th.getExpr());
00741   if(CHECK_PROOFS) {
00742     CHECK_SOUND(andr_e.getKind() == AND_R && a_th.proves(andr_e[0]) &&
00743                 ((left && b_th.refutes(andr_e[1])) ||
00744                  (!left && b_th.refutes(andr_e[2]))),
00745                 "SearchEngineTheoremProducer::confAndrAT");
00746   }
00747 
00748   Assumptions a;
00749   Proof pf;
00750   if(withAssumptions()) {
00751     a.add(andr_th);
00752     a.add(a_th);
00753     a.add(b_th);
00754   }
00755 
00756   if(withProof()) {
00757     vector<Proof> pfs;
00758     vector<Expr> exprs;
00759     exprs.push_back(andr_th.getExpr());
00760     exprs.push_back(a_th.getExpr());
00761     exprs.push_back(b_th.getExpr());
00762     pfs.push_back(andr_th.getProof());
00763     pfs.push_back(a_th.getProof());
00764     pfs.push_back(b_th.getProof());
00765     // can we note which branch to take?
00766     pf = newPf("conf_andr_at", exprs, pfs);
00767   }
00768 
00769   return newTheorem(d_em->falseExpr(), a, pf);
00770 }
00771 
00772 Theorem
00773 SearchEngineTheoremProducer::confAndrAF(const Theorem& andr_th,
00774                                         const Theorem& a_th,
00775                                         const Theorem& l_th,
00776                                         const Theorem& r_th) {
00777   const Expr& andr_e(andr_th.getExpr());
00778   if(CHECK_PROOFS) {
00779     CHECK_SOUND(andr_e.getKind() == AND_R && a_th.refutes(andr_e[0]) &&
00780                 l_th.proves(andr_e[1]) && r_th.proves(andr_e[2]),
00781                 "SearchEngineTheoremProducer::confAndrAF");
00782   }
00783 
00784   Assumptions a;
00785   Proof pf;
00786   if(withAssumptions()) {
00787     a.add(andr_th);
00788     a.add(a_th);
00789     a.add(l_th);
00790     a.add(r_th);
00791   }
00792 
00793   if(withProof()) {
00794     vector<Proof> pfs;
00795     vector<Expr> exprs;
00796     exprs.push_back(andr_th.getExpr());
00797     exprs.push_back(a_th.getExpr());
00798     exprs.push_back(l_th.getExpr());
00799     exprs.push_back(r_th.getExpr());
00800     pfs.push_back(andr_th.getProof());
00801     pfs.push_back(a_th.getProof());
00802     pfs.push_back(l_th.getProof());
00803     pfs.push_back(r_th.getProof());
00804     pf = newPf("conf_andr_af", exprs, pfs);
00805   }
00806 
00807   return newTheorem(d_em->falseExpr(), a, pf);
00808 }
00809 
00810 Theorem
00811 SearchEngineTheoremProducer::propIffr(const Theorem& iffr_th,
00812                                       int p,
00813                                       const Theorem& a_th,
00814                                       const Theorem& b_th)
00815 {
00816   int a(-1), b(-1);
00817   if(CHECK_PROOFS)
00818     CHECK_SOUND(p == 0 || p == 1 || p == 2,
00819                 "SearchEngineTheoremProducer::propIffr: p="
00820                 +int2string(p));
00821   switch (p) {
00822   case 0: a = 1; b = 2; break;
00823   case 1: a = 0; b = 2; break;
00824   case 2: a = 0; b = 1; break;
00825   }
00826 
00827   const Expr& iffr_e(iffr_th.getExpr());
00828 
00829   bool v0 = a_th.proves(iffr_e[a]);
00830   bool v1 = b_th.proves(iffr_e[b]);
00831 
00832   if (CHECK_PROOFS) {
00833     CHECK_SOUND(iffr_e.getKind() == IFF_R &&
00834                 (v0 || a_th.refutes(iffr_e[a])) &&
00835                 (v1 || b_th.refutes(iffr_e[b])),
00836                 "SearchEngineTheoremProducer::propIffr");
00837   }
00838 
00839   Assumptions aa;
00840   Proof pf;
00841   if (withAssumptions()) {
00842     aa.add(iffr_th);
00843     aa.add(a_th);
00844     aa.add(b_th);
00845   }
00846 
00847   if (withProof()) {
00848     vector<Proof> pfs;
00849     vector<Expr> exprs;
00850     exprs.push_back(iffr_th.getExpr());
00851     exprs.push_back(a_th.getExpr());
00852     exprs.push_back(b_th.getExpr());
00853     pfs.push_back(iffr_th.getProof());
00854     pfs.push_back(a_th.getProof());
00855     pfs.push_back(b_th.getProof());
00856     pf = newPf("prop_iffr", exprs, pfs);
00857   }
00858 
00859   return newTheorem(v0 == v1 ? iffr_e[p] : iffr_e[p].negate(), aa, pf);
00860 }
00861 
00862 Theorem
00863 SearchEngineTheoremProducer::confIffr(const Theorem& iffr_th,
00864                                       const Theorem& i_th,
00865                                       const Theorem& l_th,
00866                                       const Theorem& r_th)
00867 {
00868   const Expr& iffr_e(iffr_th.getExpr());
00869 
00870   bool v0 = i_th.proves(iffr_e[0]);
00871   bool v1 = l_th.proves(iffr_e[1]);
00872   bool v2 = r_th.proves(iffr_e[2]);
00873 
00874   if (CHECK_PROOFS) {
00875     CHECK_SOUND(iffr_e.getKind() == IFF_R &&
00876                 (v0 || i_th.refutes(iffr_e[0])) &&
00877                 (v1 || l_th.refutes(iffr_e[1])) &&
00878                 (v2 || r_th.refutes(iffr_e[2])) &&
00879                 ((v0 && v1 != v2) || (!v0 && v1 == v2)),
00880                 "SearchEngineTheoremProducer::confIffr");
00881   }
00882 
00883   Assumptions a;
00884   Proof pf;
00885   if (withAssumptions()) {
00886     a.add(iffr_th);
00887     a.add(i_th);
00888     a.add(l_th);
00889     a.add(r_th);
00890   }
00891 
00892   if (withProof()) {
00893     vector<Proof> pfs;
00894     vector<Expr> exprs;
00895     exprs.push_back(iffr_th.getExpr());
00896     exprs.push_back(i_th.getExpr());
00897     exprs.push_back(l_th.getExpr());
00898     exprs.push_back(r_th.getExpr());
00899     pfs.push_back(iffr_th.getProof());
00900     pfs.push_back(i_th.getProof());
00901     pfs.push_back(l_th.getProof());
00902     pfs.push_back(r_th.getProof());
00903     pf = newPf("conf_iffr", exprs, pfs);
00904   }
00905 
00906   return newTheorem(d_em->falseExpr(), a, pf);
00907 }
00908 
00909 Theorem
00910 SearchEngineTheoremProducer::propIterIte(const Theorem& iter_th,
00911                                          bool left,
00912                                          const Theorem& if_th,
00913                                          const Theorem& then_th)
00914 {
00915   const Expr& iter_e(iter_th.getExpr());
00916 
00917   bool v0 = if_th.proves(iter_e[1]);
00918   bool v1 = then_th.proves(iter_e[left ? 2 : 3]);
00919 
00920   if (CHECK_PROOFS) {
00921     CHECK_SOUND(iter_e.getKind() == ITE_R &&
00922                 (v0 || if_th.refutes(iter_e[1])) &&
00923                 (v1 || then_th.refutes(iter_e[left ? 2 : 3])) &&
00924                 v0 == left,
00925                 "SearchEngineTheoremProducer::propIterIte");
00926   }
00927 
00928   Assumptions a;
00929   Proof pf;
00930   if (withAssumptions()) {
00931     a.add(iter_th);
00932     a.add(if_th);
00933     a.add(then_th);
00934   }
00935 
00936   if (withProof()) {
00937     vector<Proof> pfs;
00938     vector<Expr> exprs;
00939     exprs.push_back(iter_th.getExpr());
00940     exprs.push_back(if_th.getExpr());
00941     exprs.push_back(then_th.getExpr());
00942     pfs.push_back(iter_th.getProof());
00943     pfs.push_back(if_th.getProof());
00944     pfs.push_back(then_th.getProof());
00945     pf = newPf("prop_iter_ite", exprs, pfs);
00946   }
00947 
00948   return newTheorem(v1 ? iter_e[0] : iter_e[0].negate(), a, pf);
00949 }
00950 
00951 void
00952 SearchEngineTheoremProducer::propIterIfThen(const Theorem& iter_th,
00953                                             bool left,
00954                                             const Theorem& ite_th,
00955                                             const Theorem& then_th,
00956                                             Theorem* if_th,
00957                                             Theorem* else_th)
00958 {
00959   const Expr& iter_e(iter_th.getExpr());
00960 
00961   bool v0 = ite_th.proves(iter_e[0]);
00962   bool v1 = then_th.proves(iter_e[left ? 2 : 3]);
00963 
00964   if (CHECK_PROOFS) {
00965     CHECK_SOUND(iter_e.getKind() == ITE_R &&
00966                 (v0 || ite_th.refutes(iter_e[0])) &&
00967                 (v1 || then_th.refutes(iter_e[left ? 2 : 3])) &&
00968                 v0 != v1,
00969                 "SearchEngineTheoremProducer::propIterIfThen");
00970   }
00971 
00972   Assumptions a;
00973   Proof pf;
00974   if (withAssumptions()) {
00975     a.add(iter_th);
00976     a.add(ite_th);
00977     a.add(then_th);
00978   }
00979 
00980   if (withProof()) {
00981     vector<Proof> pfs;
00982     vector<Expr> exprs;
00983     exprs.push_back(iter_th.getExpr());
00984     exprs.push_back(ite_th.getExpr());
00985     exprs.push_back(then_th.getExpr());
00986     pfs.push_back(iter_th.getProof());
00987     pfs.push_back(ite_th.getProof());
00988     pfs.push_back(then_th.getExpr());
00989     pf = newPf("prop_iter_if_then", exprs, pfs);
00990   }
00991 
00992   if (if_th)
00993     *if_th = newTheorem(left ? iter_e[1].negate() : iter_e[1], a, pf);
00994   if (else_th)
00995     *else_th = newTheorem(v0 ? iter_e[left ? 3 : 2] : iter_e[left ? 3 : 2].negate(), a, pf);
00996 }
00997 
00998 Theorem
00999 SearchEngineTheoremProducer::propIterThen(const Theorem& iter_th,
01000                                           const Theorem& ite_th,
01001                                           const Theorem& if_th)
01002 {
01003   const Expr& iter_e(iter_th.getExpr());
01004 
01005   bool v0 = ite_th.proves(iter_e[0]);
01006   bool v1 = if_th.proves(iter_e[1]);
01007 
01008   if (CHECK_PROOFS) {
01009     CHECK_SOUND(iter_e.getKind() == ITE_R &&
01010                 (v0 || ite_th.refutes(iter_e[0])) &&
01011                 (v1 || if_th.refutes(iter_e[1])),
01012                 "SearchEngineTheoremProducer::propIterThen");
01013   }
01014 
01015   Assumptions a;
01016   Proof pf;
01017   if (withAssumptions()) {
01018     a.add(iter_th);
01019     a.add(ite_th);
01020     a.add(if_th);
01021   }
01022 
01023   if (withProof()) {
01024     vector<Proof> pfs;
01025     vector<Expr> exprs;
01026     exprs.push_back(iter_th.getExpr());
01027     exprs.push_back(ite_th.getExpr());
01028     exprs.push_back(if_th.getExpr());
01029     pfs.push_back(iter_th.getProof());
01030     pfs.push_back(ite_th.getProof());
01031     pfs.push_back(if_th.getExpr());
01032     pf = newPf("prop_iter_then", exprs, pfs);
01033   }
01034 
01035   return newTheorem(v1 ?
01036                     (v0 ? iter_e[2] : iter_e[2].negate()) :
01037                     (v0 ? iter_e[3] : iter_e[3].negate()), a, pf);
01038 }
01039 
01040 Theorem
01041 SearchEngineTheoremProducer::confIterThenElse(const Theorem& iter_th,
01042                                               const Theorem& ite_th,
01043                                               const Theorem& then_th,
01044                                               const Theorem& else_th)
01045 {
01046   const Expr& iter_e(iter_th.getExpr());
01047 
01048   bool v0 = ite_th.proves(iter_e[0]);
01049   bool v1 = then_th.proves(iter_e[2]);
01050   bool v2 = else_th.proves(iter_e[3]);
01051 
01052   if (CHECK_PROOFS) {
01053     CHECK_SOUND(iter_e.getKind() == ITE_R &&
01054                 (v0 || ite_th.refutes(iter_e[0])) &&
01055                 (v1 || then_th.refutes(iter_e[2])) &&
01056                 (v2 || else_th.refutes(iter_e[3])) &&
01057                 ((v0 && !v1 && !v2) || (!v0 && v1 && v2)),
01058                 "SearchEngineTheoremProducer::confIterThenElse");
01059   }
01060 
01061   Assumptions a;
01062   Proof pf;
01063   if (withAssumptions()) {
01064     a.add(iter_th);
01065     a.add(ite_th);
01066     a.add(then_th);
01067     a.add(else_th);
01068   }
01069 
01070   if (withProof()) {
01071     vector<Proof> pfs;
01072     vector<Expr> exprs;
01073     exprs.push_back(iter_th.getExpr());
01074     exprs.push_back(ite_th.getExpr());
01075     exprs.push_back(then_th.getExpr());
01076     exprs.push_back(else_th.getExpr());
01077     pfs.push_back(iter_th.getProof());
01078     pfs.push_back(ite_th.getProof());
01079     pfs.push_back(then_th.getExpr());
01080     pfs.push_back(else_th.getExpr());
01081     pf = newPf("conf_iter_then_else", exprs, pfs);
01082   }
01083 
01084   return newTheorem(d_em->falseExpr(), a, pf);
01085 }
01086 
01087 Theorem
01088 SearchEngineTheoremProducer::confIterIfThen(const Theorem& iter_th,
01089                                             bool left,
01090                                             const Theorem& ite_th,
01091                                             const Theorem& if_th,
01092                                             const Theorem& then_th)
01093 {
01094   const Expr& iter_e(iter_th.getExpr());
01095 
01096   bool v0 = ite_th.proves(iter_e[0]);
01097   bool v1 = if_th.proves(iter_e[1]);
01098   bool v2 = then_th.proves(iter_e[left ? 2 : 3]);
01099 
01100   if (CHECK_PROOFS) {
01101     CHECK_SOUND(iter_e.getKind() == ITE_R &&
01102                 (v0 || ite_th.refutes(iter_e[0])) &&
01103                 (v1 || if_th.refutes(iter_e[1])) &&
01104                 (v2 || then_th.refutes(iter_e[left ? 2 : 3])) &&
01105                 v1 == left && v0 != v2,
01106                 "SearchEngineTheoremProducer::confIterThenElse");
01107   }
01108 
01109   Assumptions a;
01110   Proof pf;
01111   if (withAssumptions()) {
01112     a.add(iter_th);
01113     a.add(ite_th);
01114     a.add(if_th);
01115     a.add(then_th);
01116   }
01117 
01118   if (withProof()) {
01119     vector<Proof> pfs;
01120     vector<Expr> exprs;
01121     exprs.push_back(iter_th.getExpr());
01122     exprs.push_back(ite_th.getExpr());
01123     exprs.push_back(if_th.getExpr());
01124     exprs.push_back(then_th.getExpr());
01125     pfs.push_back(iter_th.getProof());
01126     pfs.push_back(ite_th.getProof());
01127     pfs.push_back(if_th.getExpr());
01128     pfs.push_back(then_th.getExpr());
01129     pf = newPf("conf_iter_then_else", exprs, pfs);
01130   }
01131 
01132   return newTheorem(d_em->falseExpr(), a, pf);
01133 }
01134 
01135 // "Conflict" rule (all literals in a clause become FALSE)
01136 // { G_j |- !l_j, j in [1..n] } , G |- (OR l_1 ... l_n) ==> FALSE
01137 Theorem
01138 SearchEngineTheoremProducer::conflictRule(const std::vector<Theorem>& thms,
01139                                           const Theorem& clause) {
01140   Expr e(clause.getExpr());
01141   if(CHECK_PROOFS) {
01142     // Soundness check: first, check the form of the 'clause' theorem
01143     CHECK_SOUND(e.isOr(),
01144                 "SearchEngineTheoremProducer::unitProp: "
01145                 "bad theorem in clause = "+clause.toString());
01146     // Now, check correspondence of thms to the disjunction
01147     CHECK_SOUND(((int)thms.size()) == e.arity(),
01148                 "SearchEngineTheoremProducer::conflictRule: "
01149                 "wrong number of theorems"
01150                 "\n  thms.size = " + int2string(thms.size())
01151                 +"\n  clause.arity = " + int2string(e.arity()));
01152 
01153     for(unsigned j=0; j<thms.size(); j++) {
01154       Expr ej(e[j]), ek(thms[j].getExpr());
01155       CHECK_SOUND((ej.isNot() && ej[0] == ek) || (ek.isNot() && ej == ek[0]),
01156                   "SearchEngineTheoremProducer::conflictRule: "
01157                   "wrong theorem["+int2string(j)+"]"
01158                   "\n  thm = " + thms[j].toString() +
01159                   "\n  literal = " + e[j].toString() +
01160                   "\n  clause = " + clause.toString());
01161     }
01162   }
01163 
01164   Assumptions a;
01165   Proof pf;
01166   if(withAssumptions()) {
01167     a = Assumptions(thms);
01168     a.add(clause);
01169   }
01170   if(withProof()) {
01171     vector<Proof> pfs;
01172     vector<Expr> exprs;
01173     exprs.reserve(thms.size() + 1);
01174     pfs.reserve(thms.size()+1);
01175     const vector<Theorem>::const_iterator iend = thms.end();
01176     for(vector<Theorem>::const_iterator i=thms.begin(); i!=iend; ++i) {
01177       exprs.push_back(i->getExpr());
01178       pfs.push_back(i->getProof());
01179     }
01180     exprs.push_back(clause.getExpr());
01181     pfs.push_back(clause.getProof());
01182     pf = newPf("conflict", exprs, pfs);
01183   }
01184   return newTheorem(d_em->falseExpr(), a, pf);
01185 }
01186 
01187 
01188 ///////////////////////////////////////////////////////////////////////
01189 //// Conjunctive Normal Form (CNF) proof rules
01190 ///////////////////////////////////////////////////////////////////////
01191 Theorem
01192 SearchEngineTheoremProducer::andCNFRule(const Theorem& thm) {
01193   return opCNFRule(thm, AND, "and_cnf_rule");
01194 }
01195 
01196 Theorem
01197 SearchEngineTheoremProducer::orCNFRule(const Theorem& thm) {
01198   return opCNFRule(thm, OR, "or_cnf_rule");
01199 }
01200 
01201 Theorem
01202 SearchEngineTheoremProducer::impCNFRule(const Theorem& thm) {
01203   return opCNFRule(thm, IMPLIES, "implies_cnf_rule");
01204 }
01205 
01206 Theorem
01207 SearchEngineTheoremProducer::iffCNFRule(const Theorem& thm) {
01208   return opCNFRule(thm, IFF, "iff_cnf_rule");
01209 }
01210 
01211 Theorem
01212 SearchEngineTheoremProducer::iteCNFRule(const Theorem& thm) {
01213   return opCNFRule(thm, ITE, "ite_cnf_rule");
01214 }
01215 
01216 
01217 Theorem
01218 SearchEngineTheoremProducer::iteToClauses(const Theorem& ite) {
01219   const Expr& iteExpr = ite.getExpr();
01220 
01221   if(CHECK_PROOFS) {
01222     CHECK_SOUND(iteExpr.isITE() && iteExpr.getType().isBool(),
01223                 "SearchEngineTheoremProducer::iteToClauses("+iteExpr.toString()
01224                 +")\n Argument must be a Boolean ITE");
01225   }
01226   const Expr& cond = iteExpr[0];
01227   const Expr& t1 = iteExpr[1];
01228   const Expr& t2 = iteExpr[2];
01229 
01230   Assumptions a;
01231   Proof pf;
01232   if(withAssumptions()) a = ite.getAssumptionsCopy();
01233   if(withProof())
01234     pf = newPf("ite_to_clauses", iteExpr, ite.getProof());
01235   return newTheorem((cond.negate() || t1) && (cond || t2), a, pf);
01236 }
01237 
01238 
01239 Theorem
01240 SearchEngineTheoremProducer::iffToClauses(const Theorem& iff) {
01241   if(CHECK_PROOFS) {
01242     CHECK_SOUND(iff.isRewrite() && iff.getLHS().getType().isBool(),
01243                 "SearchEngineTheoremProducer::iffToClauses("+iff.getExpr().toString()
01244                 +")\n Argument must be a Boolean IFF");
01245   }
01246   const Expr& t1 = iff.getLHS();
01247   const Expr& t2 = iff.getRHS();
01248 
01249   Assumptions a;
01250   Proof pf;
01251   if(withAssumptions()) a = iff.getAssumptionsCopy();
01252   if(withProof())
01253     pf = newPf("iff_to_clauses", iff.getExpr(), iff.getProof());
01254   return newTheorem((t1.negate() || t2) && (t1 || t2.negate()), a, pf);
01255 }
01256 
01257 
01258 /////////////////////////////////////////////////////////////////////////
01259 //// helper functions for CNF (Conjunctive Normal Form) conversion
01260 /////////////////////////////////////////////////////////////////////////
01261 Theorem
01262 SearchEngineTheoremProducer::opCNFRule(const Theorem& thm, 
01263                                        int kind,
01264                                        const string& ruleName) {
01265   TRACE("mycnf", "opCNFRule["+d_em->getKindName(kind)+"](",
01266         thm.getExpr(), ") {");
01267   ExprMap<Expr> localCache;
01268   if(CHECK_PROOFS) {
01269     Expr phiIffVar = thm.getExpr();
01270     CHECK_SOUND(phiIffVar.isIff(),
01271                 "SearchEngineTheoremProducer::opCNFRule("
01272                 +d_em->getKindName(kind)+"): "
01273                 "input must be an IFF: thm = " + phiIffVar.toString());
01274     CHECK_SOUND(phiIffVar[0].getKind() == kind,
01275                 "SearchEngineTheoremProducer::opCNFRule("
01276                 +d_em->getKindName(kind)+"): "
01277                 "input phi has wrong kind: thm = " + phiIffVar.toString());
01278     CHECK_SOUND(phiIffVar[0] != phiIffVar[1],
01279                 "SearchEngineTheoremProducer::opCNFRule("
01280                 +d_em->getKindName(kind)+"): "
01281                 "wrong input thm = " + phiIffVar.toString());   
01282     for(Expr::iterator it=phiIffVar[0].begin(), itend=phiIffVar[0].end();
01283         it!=itend;++it){
01284       CHECK_SOUND(phiIffVar[1] != *it,
01285                   "SearchEngineTheoremProducer::opCNFRule("
01286                   +d_em->getKindName(kind)+"): "
01287                   "wrong input thm = " + phiIffVar.toString());
01288     }
01289   }
01290   const Expr& phi = thm.getExpr()[0];
01291   const Expr& phiVar = thm.getExpr()[1];
01292 
01293   std::vector<Expr> boundVars;
01294   std::vector<Expr> boundVarsAndLiterals;
01295   std::vector<Expr> equivs;
01296   for(Expr::iterator i=phi.begin(), iend=phi.end(); i != iend; i++) {
01297     // First, strip the negation and check if the formula is atomic
01298     Expr tmp(*i);
01299     while(tmp.isNot())
01300       tmp = tmp[0];
01301 
01302     if(tmp.isPropAtom())
01303       boundVarsAndLiterals.push_back(*i); 
01304     else
01305       boundVarsAndLiterals.push_back(findInLocalCache(*i, localCache,
01306                                                       boundVars));
01307   }
01308   
01309   for(ExprMap<Expr>::iterator it=localCache.begin(), itend=localCache.end(); 
01310       it != itend; it++) {
01311     DebugAssert((*it).second.isIff(),
01312                 "SearchEngineTheoremProducer::opCNFRule: " +
01313                 (*it).second.toString());
01314     DebugAssert(!(*it).second[0].isPropLiteral() && 
01315                 (*it).second[1].isAbsLiteral(),
01316                 "SearchEngineTheoremProducer::opCNFRule: " +
01317                 (*it).second.toString());
01318     equivs.push_back((*it).second);
01319   }
01320   
01321   DebugAssert(boundVarsAndLiterals.size() == (unsigned)phi.arity(),
01322               "SearchEngineTheoremProducer::opCNFRule: "
01323               "wrong size of boundvars: phi = " + phi.toString());
01324   
01325   DebugAssert(boundVars.size() == equivs.size(),
01326               "SearchEngineTheoremProducer::opCNFRule: "
01327               "wrong size of boundvars: phi = " + phi.toString());
01328               
01329   Expr cnfInput = phi.arity() > 0 ? Expr(phi.getOp(), boundVarsAndLiterals) : phi;
01330   Expr  result = convertToCNF(phiVar, cnfInput);
01331   if(boundVars.size() > 0)
01332     result =
01333       d_em->newClosureExpr(EXISTS, boundVars, result.andExpr(andExpr(equivs)));
01334   
01335   Assumptions a;
01336   Proof pf;
01337   if(withAssumptions()) a = thm.getAssumptionsCopy();
01338   if(withProof())
01339     pf = newPf(ruleName, thm.getExpr(), thm.getProof());
01340   Theorem res(newTheorem(result, a, pf));
01341   TRACE("mycnf", "opCNFRule["+d_em->getKindName(kind)+"] => ", res.getExpr(),
01342         " }");
01343   return res;
01344 }
01345 
01346 //! produces the CNF for the formula  v <==> phi 
01347 Expr SearchEngineTheoremProducer::convertToCNF(const Expr& v, const Expr & phi) {
01348   //we assume that v \iff phi. v is the newVar corresponding to phi
01349   
01350   Expr::iterator i = phi.begin(), iend = phi.end();
01351   std::vector<Expr> clauses;
01352   std::vector<Expr> lastClause;
01353   switch(phi.getKind()) {
01354   case AND: {
01355     const Expr& negV = v.negate();
01356     lastClause.push_back(v);
01357     for(;i!=iend; ++i) {
01358       clauses.push_back(negV.orExpr(*i));
01359       lastClause.push_back(i->negate());
01360     }
01361     clauses.push_back(orExpr(lastClause));
01362   }
01363     break;
01364   case OR:{
01365     lastClause.push_back(v.negate());
01366     for(;i!=iend; ++i) {
01367       clauses.push_back(v.orExpr(i->negate()));
01368       lastClause.push_back(*i);
01369     }
01370     clauses.push_back(orExpr(lastClause));
01371   }
01372     break;
01373   case IFF: {
01374     const Expr& v1 = phi[0];
01375     const Expr& v2 = phi[1];
01376     Expr negV = v.negate();    
01377     Expr negv1 = v1.negate();
01378     Expr negv2 = v2.negate();
01379     clauses.push_back(Expr(OR, negV, negv1, v2));
01380     clauses.push_back(Expr(OR, negV, v1, negv2));
01381     clauses.push_back(Expr(OR, v, v1, v2));
01382     clauses.push_back(Expr(OR, v, negv1, negv2));
01383   } break;
01384   case IMPLIES:{
01385     const Expr& v1 = phi[0];
01386     const Expr& v2 = phi[1];
01387     Expr negV = v.negate();    
01388     Expr negv1 = v1.negate();
01389     Expr negv2 = v2.negate();
01390     clauses.push_back(Expr(OR, negV, negv1, v2));
01391     clauses.push_back(v.orExpr(v1));
01392     clauses.push_back(v.orExpr(negv2));
01393   }
01394     break;
01395   case ITE: {
01396     const Expr& v1 = phi[0];
01397     const Expr& v2 = phi[1];
01398     const Expr& v3 = phi[2];
01399     const Expr& negV = v.negate();
01400     const Expr& negv1 = v1.negate();
01401     const Expr& negv2 = v2.negate();
01402     const Expr& negv3 = v3.negate();
01403     clauses.push_back(Expr(OR, negV, negv1, v2));
01404     clauses.push_back(Expr(OR, negV, v1, v3));
01405     clauses.push_back(Expr(OR, v, negv1, negv2));
01406     clauses.push_back(Expr(OR, v, v1, negv3));
01407   }
01408     break;
01409   default:
01410     DebugAssert(false, "SearchEngineTheoremProducer::convertToCNF: "
01411                 "bad operator in phi = "+phi.toString());
01412     break;
01413   }
01414   return andExpr(clauses);
01415 }
01416 
01417 ///////////////////////////////////////////////////////////////////////
01418 // helper functions for CNF converters
01419 ///////////////////////////////////////////////////////////////////////
01420 
01421 Expr SearchEngineTheoremProducer::findInLocalCache(const Expr& i, 
01422                                                    ExprMap<Expr>& localCache,
01423                                                    vector<Expr>& boundVars) {
01424   TRACE("mycnf", "findInLocalCache(", i.toString(), ") { ");
01425   Expr boundVar;
01426   unsigned int negationDepth = 0;
01427   ExprMap<Expr>::iterator it;
01428  
01429   Expr phi = i;
01430   while(phi.isNot()) {
01431     phi = phi[0];
01432     negationDepth++;
01433   }
01434   
01435   it = localCache.find(phi);
01436   Expr v;
01437   if(it != localCache.end()) {
01438     v = ((*it).second)[1];
01439     IF_DEBUG(debugger.counter("CNF Local Cache Hits")++);
01440   }
01441   else {
01442     v = d_em->newBoundVarExpr(i.getType());
01443     boundVars.push_back(v);
01444     localCache[phi] = phi.iffExpr(v);
01445   }
01446   if(negationDepth % 2 != 0)
01447     v = !v;
01448   TRACE("mycnf", "findInLocalCache => ", v, " }");
01449   return v;
01450 }

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