CVC3

minisat_derivation.cpp

Go to the documentation of this file.
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 }