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