CVC3
|
00001 /*****************************************************************************/ 00002 /*! 00003 *\file minisat_derivation.cpp 00004 *\brief MiniSat proof logging 00005 * 00006 * Author: Alexander Fuchs 00007 * 00008 * Created: Sun Dec 07 11:09:00 2007 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 "minisat_derivation.h" 00023 #include "minisat_solver.h" 00024 #include "sat_proof.h" 00025 #include <set> 00026 #include <iostream> 00027 00028 using namespace MiniSat; 00029 using namespace std; 00030 00031 std::string Inference::toString() const { 00032 ostringstream buffer; 00033 buffer << getStart(); 00034 for (Inference::TSteps::const_iterator step = d_steps.begin(); step != d_steps.end(); ++step) { 00035 buffer << " " << step->first.toString() << " " << step->second; 00036 } 00037 return buffer.str(); 00038 } 00039 00040 00041 00042 00043 00044 Derivation::~Derivation() { 00045 // deallocate generated unit clauses 00046 for (TClauses::iterator i = d_unitClauses.begin(); i != d_unitClauses.end(); ++i) { 00047 xfree(i->second); 00048 } 00049 00050 // deallocate removed clauses 00051 for (std::deque<Clause*>::iterator i = d_removedClauses.begin(); i != d_removedClauses.end(); ++i) { 00052 xfree(*i); 00053 } 00054 00055 // deallocate inferences 00056 for (TInferences::iterator i = d_inferences.begin(); i != d_inferences.end(); ++i) { 00057 delete i->second; 00058 } 00059 } 00060 00061 00062 int Derivation::computeRootReason(Lit implied, Solver* solver) { 00063 Clause* reason = solver->getReason(implied); 00064 // cout << "computeRootReason " << reason->id() << endl; 00065 FatalAssert(d_clauses.find(reason->id()) != d_clauses.end(), 00066 "MiniSat::Derivation::computeRootReason: implied reason not registered"); 00067 FatalAssert(reason == d_clauses.find(reason->id())->second, 00068 "MiniSat::Derivation::computeRootReason: implied reason not same as registered"); 00069 FatalAssert(reason != NULL, "MiniSat::Derivation::computeRootReason: implied reason is NULL"); 00070 FatalAssert(reason != Clause::Decision(), "MiniSat::Derivation::computeRootReason: implied is a decision"); 00071 FatalAssert((*reason)[0] == implied, "MiniSat::Derivation::computeRootReason: implied is not in its reason"); 00072 IF_DEBUG ( 00073 FatalAssert(solver->getValue((*reason)[0]) == l_True, 00074 "MiniSat::Derivation::computeRootReason: literal not implied (TRUE)"); 00075 for (int i = 1; i < reason->size(); ++i) { 00076 FatalAssert(solver->getValue((*reason)[i]) == l_False, 00077 "MiniSat::Derivation::computeRootReason: literal not implied (FALSE)"); 00078 } 00079 ) 00080 00081 // already a unit clause, so done 00082 if (reason->size() == 1) { 00083 return reason->id(); 00084 } 00085 00086 // already derived the unit clause internally 00087 TClauses::const_iterator iter = d_unitClauses.find(implied.index()); 00088 if (iter != d_unitClauses.end()) { 00089 return iter->second->id(); 00090 } 00091 00092 00093 // otherwise resolve the reason ... 00094 Inference* inference = new Inference(reason->id()); 00095 for (int i = 1; i < reason->size(); ++i) { 00096 Lit lit((*reason)[i]); 00097 inference->add(lit, computeRootReason(~lit, solver)); 00098 } 00099 00100 // and create the new unit clause 00101 // (after resolve, so that clause ids are chronological wrt. inference) 00102 vector<Lit> literals; 00103 literals.push_back(implied); 00104 Clause* unit = Clause_new(literals, CVC3::Theorem(), solver->nextClauseID()); 00105 00106 d_unitClauses[implied.index()] = unit; 00107 // cout << "compute root reason : " << unit->id() << endl; 00108 registerClause(unit); 00109 registerInference(unit->id(), inference); 00110 00111 return unit->id(); 00112 } 00113 00114 00115 void Derivation::finish(Clause* clause, Solver* solver) { 00116 FatalAssert(clause != NULL, "MiniSat::derivation:finish:"); 00117 00118 // already the empty clause 00119 if (clause->size() == 0) { 00120 d_emptyClause = clause; 00121 } 00122 // derive the empty clause 00123 else { 00124 Inference* inference = new Inference(clause->id()); 00125 for (int i = 0; i < clause->size(); ++i) { 00126 Lit lit((*clause)[i]); 00127 inference->add(lit, computeRootReason(~lit, solver)); 00128 } 00129 vector<Lit> literals; 00130 Clause* empty = Clause_new(literals, CVC3::Theorem(), solver->nextClauseID()); 00131 removedClause(empty); 00132 d_emptyClause = empty; 00133 registerClause(empty); 00134 registerInference(empty->id(), inference); 00135 } 00136 00137 checkDerivation(clause); 00138 IF_DEBUG (checkDerivation(clause)); 00139 00140 // cout << "PROOF_START" << endl; 00141 // printDerivation(); 00142 // cout << "PROOF_END" << endl; 00143 00144 } 00145 00146 00147 00148 void Derivation::checkDerivation(Clause* clause) { 00149 // find all relevant clauses 00150 00151 // - relevant: set clauses used in derivation 00152 // - regress: relevant clauses whose antecedents have to be checked 00153 std::set<int> relevant; 00154 std::set<int> regress; 00155 00156 regress.insert(clause->id()); 00157 while (!regress.empty()) { 00158 // pick next clause to derive - start from bottom, i.e. latest derived clause 00159 int clauseID = *(regress.rbegin()); 00160 regress.erase(clauseID); 00161 00162 // move to clauses relevant for the derivation 00163 FatalAssert(relevant.count(clauseID) == 0, "Solver::printProof: already in relevant"); 00164 relevant.insert(clauseID); 00165 00166 // process antecedents 00167 TInferences::const_iterator iter = d_inferences.find(clauseID); 00168 // input clause 00169 if (iter == d_inferences.end()) { 00170 FatalAssert(d_inputClauses.contains(clauseID), 00171 "Solver::printProof: clause without antecedents is not marked as input clause"); 00172 } 00173 00174 else { 00175 Inference* inference = iter->second; 00176 regress.insert(inference->getStart()); 00177 const Inference::TSteps& steps = inference->getSteps(); 00178 for (Inference::TSteps::const_iterator step = steps.begin(); step != steps.end(); ++step) { 00179 regress.insert(step->second); 00180 } 00181 } 00182 } 00183 00184 00185 // check derivation 00186 for (std::set<int>::iterator i = relevant.begin(); i != relevant.end(); ++i) { 00187 int clauseID = *i; 00188 FatalAssert(d_clauses.contains(clauseID), 00189 "MiniSat::Derivation::printProof: clause id in proof is not in clauses"); 00190 Clause* clause = d_clauses.find(clauseID)->second; 00191 00192 Inference* inference = NULL; 00193 TInferences::const_iterator j = d_inferences.find(clauseID); 00194 if (j != d_inferences.end()) { 00195 inference = j->second; 00196 } 00197 00198 FatalAssert(inference != NULL || d_inputClauses.contains(clauseID), 00199 "MiniSat::Derivation::printProof: derivation of input clause"); 00200 FatalAssert(inference == NULL || !d_inputClauses.contains(clauseID), 00201 "MiniSat::Derivation::printProof: no derivation for derived clause"); 00202 00203 if (inference != NULL) { 00204 // cout << "Regress: " << clause->id() << " : " << clause->toString() << endl; 00205 FatalAssert(d_clauses.find(inference->getStart()) != d_clauses.end(), 00206 "MiniSat::Derivation::printProof: first not in clauses"); 00207 00208 Clause* first = d_clauses.find(inference->getStart())->second; 00209 // cout << "Derived from : " << first->id() << " : " << first->toString() << endl; 00210 00211 set<Lit> derived; 00212 for (int i = 0; i < first->size(); ++i) { 00213 derived.insert((*first)[i]); 00214 } 00215 00216 // retrace derivation 00217 for (Inference::TSteps::const_iterator step = inference->getSteps().begin(); 00218 step != inference->getSteps().end(); ++step) { 00219 Lit lit = step->first; 00220 // cout << " over " << lit.toString() << endl; 00221 // cout << "Derived from ... : " << step->second << " : " << d_clauses.find(step->second)->second->toString() << endl; 00222 00223 FatalAssert(d_clauses.find(step->second) != d_clauses.end(), 00224 "MiniSat::Derivation::printProof: next not in clauses"); 00225 Clause* next = d_clauses.find(step->second)->second; 00226 00227 FatalAssert(derived.find(lit) != derived.end(), 00228 "MiniSat::Derivation::printProof: lit not in derived"); 00229 FatalAssert(next->contains(~lit), 00230 "MiniSat::Derivation::printProof: ~lit not in next"); 00231 00232 derived.erase(lit); 00233 for (int i = 0; i < next->size(); ++i) { 00234 if ((*next)[i] != ~lit) { 00235 derived.insert((*next)[i]); 00236 } 00237 } 00238 } 00239 00240 // check that we got the expected clause 00241 for (int i = 0; i < clause->size(); ++i) { 00242 FatalAssert(derived.find((*clause)[i]) != derived.end(), 00243 "MiniSat::Derivation::printProof: didn't derive expected clause"); 00244 derived.erase((*clause)[i]); 00245 } 00246 FatalAssert(derived.empty(), 00247 "MiniSat::Derivation::printProof: didn't derive expected clause 2"); 00248 }; 00249 } 00250 } 00251 00252 00253 SAT::SatProof* Derivation::createProof() { 00254 FatalAssert(d_emptyClause != NULL, "MiniSat::Derivation:createProof: no empty clause"); 00255 FatalAssert(d_emptyClause->size() == 0, 00256 "MiniSat::Derivation:createProof: empty clause is not empty"); 00257 return createProof(d_emptyClause); 00258 } 00259 00260 SAT::SatProof* Derivation::createProof(Clause* clause) { 00261 checkDerivation(clause); 00262 // IF_DEBUG (checkDerivation(clause)); 00263 00264 // find all relevant clauses 00265 00266 // - relevant: set clauses used in derivation 00267 // - regress: relevant clauses whose antecedents have to be checked 00268 std::set<int> relevant; 00269 std::set<int> regress; 00270 regress.insert(clause->id()); 00271 while (!regress.empty()) { 00272 // pick next clause to derive - start from bottom, i.e. latest derived clause 00273 int clauseID = *(regress.rbegin()); 00274 regress.erase(clauseID); 00275 relevant.insert(clauseID); 00276 00277 // process antecedents 00278 TInferences::const_iterator iter = d_inferences.find(clauseID); 00279 // input clause 00280 if (iter != d_inferences.end()) { 00281 Inference* inference = iter->second; 00282 regress.insert(inference->getStart()); 00283 const Inference::TSteps& steps = inference->getSteps(); 00284 for (Inference::TSteps::const_iterator step = steps.begin(); step != steps.end(); ++step) { 00285 regress.insert(step->second); 00286 } 00287 } 00288 } 00289 00290 // create proof 00291 SAT::SatProof* proof = new SAT::SatProof(); 00292 std::hash_map<int, SAT::SatProofNode*> proofNodes; 00293 00294 for (std::set<int>::iterator i = relevant.begin(); i != relevant.end(); ++i) { 00295 int clauseID = *i; 00296 Clause* clause = d_clauses.find(clauseID)->second; 00297 00298 Inference* inference = NULL; 00299 TInferences::const_iterator j = d_inferences.find(clauseID); 00300 if (j == d_inferences.end()) { 00301 /* 00302 <<<<<<< minisat_derivation.cpp 00303 FatalAssert(clause->getCvcClause() != NULL, "createProof: leaf without clause"); 00304 FatalAssert(clause->getCvcClause() != NULL, "createProof: leaf without clause"); 00305 proofNodes[clause->id()] = proof->registerLeaf(clause->getCvcClause()); 00306 // cout<<"cluase with :" << clause->id() << " ---> " ; 00307 // clause->getCvcClause()->print(); 00308 // cout << endl; 00309 ======= 00310 */ 00311 FatalAssert(!clause->getTheorem().isNull(), "createProof: leaf without clause"); 00312 proofNodes[clause->id()] = proof->registerLeaf(clause->getTheorem()); 00313 /* 00314 >>>>>>> 1.9 00315 */ 00316 } 00317 00318 else { 00319 inference = j->second; 00320 FatalAssert(proofNodes.contains(inference->getStart()), "createProof: contains inference start"); 00321 SAT::SatProofNode* left = proofNodes.find(inference->getStart())->second; 00322 const Inference::TSteps& steps = inference->getSteps(); 00323 for (Inference::TSteps::const_iterator step = steps.begin(); step != steps.end(); ++step) { 00324 FatalAssert(proofNodes.contains(step->second), "createProof: contains inference start"); 00325 SAT::SatProofNode* right = proofNodes.find(step->second)->second; 00326 left = proof->registerNode(left, right, miniSatToCVC(step->first)); 00327 } 00328 proofNodes[clause->id()] = left; 00329 } 00330 } 00331 proof->setRoot(proofNodes[clause->id()]); 00332 return proof; 00333 } 00334 00335 00336 void Derivation::printDerivation() { 00337 FatalAssert(d_emptyClause != NULL, "MiniSat::Derivation:printDerivation: no empty clause"); 00338 FatalAssert(d_emptyClause->size() == 0, 00339 "MiniSat::Derivation:printDerivation: empty clause is not empty"); 00340 printDerivation(d_emptyClause); 00341 } 00342 00343 void Derivation::printDerivation(Clause* clause) { 00344 IF_DEBUG (checkDerivation(clause)); 00345 00346 // find all relevant clauses 00347 00348 // - relevant: set clauses used in derivation 00349 // - regress: relevant clauses whose antecedents have to be checked 00350 std::set<int> relevant; 00351 std::set<int> regress; 00352 00353 regress.insert(clause->id()); 00354 while (!regress.empty()) { 00355 // pick next clause to derive - start from bottom, i.e. latest derived clause 00356 int clauseID = *(regress.rbegin()); 00357 regress.erase(clauseID); 00358 00359 // move to clauses relevant for the derivation 00360 relevant.insert(clauseID); 00361 00362 // process antecedents 00363 TInferences::const_iterator iter = d_inferences.find(clauseID); 00364 // input clause 00365 if (iter != d_inferences.end()) { 00366 Inference* inference = iter->second; 00367 regress.insert(inference->getStart()); 00368 const Inference::TSteps& steps = inference->getSteps(); 00369 for (Inference::TSteps::const_iterator step = steps.begin(); step != steps.end(); ++step) { 00370 regress.insert(step->second); 00371 } 00372 } 00373 } 00374 00375 00376 // print proof 00377 for (std::set<int>::iterator i = relevant.begin(); i != relevant.end(); ++i) { 00378 int clauseID = *i; 00379 Clause* clause = d_clauses.find(clauseID)->second; 00380 00381 Inference* inference = NULL; 00382 TInferences::const_iterator j = d_inferences.find(clauseID); 00383 if (j != d_inferences.end()) { 00384 inference = j->second; 00385 } 00386 00387 // ID D : L1 ... Ln : C1 K1 C2 K2 ... Cm 00388 cout << clauseID; 00389 // input clause or derived clause? 00390 if (d_inputClauses.contains(clauseID)) { 00391 cout << " I "; 00392 } else { 00393 cout << " D "; 00394 } 00395 cout << ": " << clause->toString() << " : "; 00396 if (inference != NULL) cout << inference->toString(); 00397 cout << endl; 00398 } 00399 } 00400 00401 00402 void Derivation::push(int clauseID) { 00403 // cout << "derivation push: " << clauseID << endl; 00404 } 00405 00406 void Derivation::pop(int clauseID) { 00407 // cout << "derivation pop: " << clauseID << endl; 00408 // remove all popped clauses 00409 TClauses::const_iterator i = d_clauses.begin(); 00410 while (i != d_clauses.end()) { 00411 Clause* clause = (*i).second; 00412 if ( 00413 // Warning: clause removal needs to be done 00414 // exactly the same way in minisat_solver!!! 00415 00416 // remove theory lemmas 00417 // :TODO: can't do that: kept lemmas might depend on them 00418 // (!clause->learnt() && clause->pushID() < 0) 00419 // || 00420 // remove clauses added after the last push 00421 clause->pushID() > clauseID) { 00422 int id = clause->id(); 00423 // cout << "derivation pop now: " << id << endl; 00424 d_inputClauses.erase(id); 00425 d_inferences.erase(id); 00426 00427 if (clause->size() == 1) { 00428 int index = (*clause)[0].index(); 00429 if (d_unitClauses.contains(index) && d_unitClauses[index] == clause) { 00430 d_unitClauses.erase(index); 00431 FatalAssert(!d_unitClauses.contains(index), "AHA"); 00432 } 00433 } 00434 00435 i = d_clauses.erase(i); 00436 } 00437 else { 00438 ++i; 00439 } 00440 } 00441 00442 // undo conflicting clause 00443 if (d_emptyClause != NULL && d_emptyClause->pushID() > clauseID) 00444 d_emptyClause = NULL; 00445 00446 // delete popped and removed clauses 00447 std::deque<Clause*>::iterator j = d_removedClauses.begin(); 00448 while (j != d_removedClauses.end()) { 00449 if ((*j)->pushID() > clauseID) { 00450 xfree(*j); 00451 j = d_removedClauses.erase(j); 00452 } else { 00453 ++j; 00454 } 00455 } 00456 }