00001 /*****************************************************************************/ 00002 /*! 00003 *\file minisat_derivation.h 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 #ifndef _cvc3__sat__minisat_derivation_h_ 00022 #define _cvc3__sat__minisat_derivation_h_ 00023 00024 00025 #include "minisat_types.h" 00026 #include <hash_map.h> 00027 #include <hash_set.h> 00028 #include <set> 00029 #include <vector> 00030 #include <deque> 00031 #include <algorithm> 00032 #include <string> 00033 00034 namespace SAT { 00035 class SatProof; 00036 } 00037 00038 namespace MiniSat { 00039 // a resolution inference as a sequence of binary resolution steps 00040 class Inference { 00041 public: 00042 typedef std::vector<std::pair<Lit, int> > TSteps; 00043 00044 private: 00045 // id of first clause 00046 int d_start; 00047 00048 // binary resolution step: 00049 // result of previous step (or d_start) 00050 // on literal with next clause (given by id) 00051 TSteps d_steps; 00052 00053 public: 00054 Inference(int clauseID) : d_start(clauseID) { 00055 // std::cout << "Start inference: " << clauseID << std::endl; 00056 }; 00057 00058 void add(Lit lit, int clauseID) { 00059 d_steps.push_back(std::make_pair(lit, clauseID)); 00060 }; 00061 00062 void add(Lit lit, Clause* clause) { 00063 add(lit, clause->id()); 00064 }; 00065 00066 int getStart() const { 00067 return d_start; 00068 } 00069 00070 const TSteps& getSteps() const { 00071 return d_steps; 00072 } 00073 00074 // returns steps as a lits: clauseId0 literal0.toString clauseID1 ... 00075 std::string toString() const; 00076 }; 00077 00078 00079 class Solver; 00080 00081 // Heavily based on the proof logging version of MiniSat (1.14p) 00082 // 00083 // Note: this implementation keeps the whole derivation in memory - 00084 // for many problems this is not feasible. 00085 // should provide an alternative implementation that logs the derivation 00086 // to a file and constructs the proof from it. 00087 class Derivation { 00088 public: 00089 typedef Hash::hash_map<int, Clause*> TClauses; 00090 typedef Hash::hash_set<int> TInputClauses; 00091 typedef Hash::hash_map<int, Inference*> TInferences; 00092 00093 private: 00094 // mapping from id to clause 00095 TClauses d_clauses; 00096 00097 // as an additional check, explicitely mark which clauses are input clauses 00098 // by adding their id to this set. 00099 // 00100 // as an invariant an id should be either in d_inferences or d_inputClauses, 00101 // as a clause does exactly have no inference attached if it is an input clause. 00102 TInputClauses d_inputClauses; 00103 00104 // unit clauses derived with computeRootReason 00105 // mapping from index of literal to clause 00106 TClauses d_unitClauses; 00107 00108 // mapping from clause id to the inference it was derived by 00109 TInferences d_inferences; 00110 00111 // clauses removed from the solver 00112 std::deque<Clause*> d_removedClauses; 00113 00114 // empty clause of derivation, if derived 00115 Clause* d_emptyClause; 00116 00117 public: 00118 Derivation() : d_emptyClause(NULL) {}; 00119 ~Derivation(); 00120 00121 // note: allow for duplicate insertion of clauses registerClause and registerInputClause, 00122 // as this can happen in the current implementation 00123 // for theory clauses which are inconsistent on insertion. 00124 00125 // register a new clause 00126 void registerClause(Clause* clause) { 00127 // std::cout << "register clause : " << clause->id() << " : " << clause->toString() << std::endl; 00128 00129 //IF_DEBUG ( 00130 if (d_clauses.contains(clause->id())) { 00131 // if clause with id does already exist, 00132 // then it must be a simplification of the original clause 00133 Clause* old = d_clauses[clause->id()]; 00134 FatalAssert(old->size() == clause->size(), 00135 "MiniSat::Derivation::registerClause: new clause of different size than old clause of same id"); 00136 00137 std::set<Lit> oldS; 00138 for (int i = 0; i < old->size(); ++i) { 00139 oldS.insert((*old)[i]); 00140 } 00141 00142 for (int i = 0; i < clause->size(); ++i) { 00143 FatalAssert(oldS.find((*clause)[i]) != oldS.end(), 00144 "MiniSat::Derivation::registerClause: new clause not subset of old clause of same id"); 00145 oldS.erase((*clause)[i]); 00146 } 00147 FatalAssert(oldS.empty(), 00148 "MiniSat::Derivation::registerClause: old clause not subset of new clause of same id"); 00149 } 00150 //) 00151 d_clauses[clause->id()] = clause; 00152 }; 00153 00154 // mark clause as input clause, i.e. true without premises 00155 void registerInputClause(int clauseID) { 00156 // std::cout << "registerInputClause: " << clauseID << std::endl; 00157 d_inputClauses.insert(clauseID); 00158 }; 00159 00160 // clause has been removed from the solver or created internally in Derivation, 00161 // so store it here for later garbage collection. 00162 void removedClause(Clause* clause) { 00163 FatalAssert(clause != NULL, "MiniSat::derivation:removedClause: NULL"); 00164 d_removedClauses.push_back(clause); 00165 }; 00166 00167 // register the inference of a clause; takes ownership of inference 00168 void registerInference(int clauseID, Inference* inference) { 00169 FatalAssert(!d_inferences.contains(clauseID), 00170 "MiniSat::Derivation::registerInference: inference for clauseID already registered"); 00171 // std::cout << "Register inference: " << clauseID << " : " << inference->toString() << std::endl; 00172 d_inferences[clauseID] = inference; 00173 }; 00174 00175 // implied is a literal that is implied at the root level. 00176 // return the id of the implying unit clause [literal], if it exists. 00177 // 00178 // otherwise derive it from its reasons and return the new clause id. 00179 // derived unit clauses are stored internally, independently of the Solver 00180 // 00181 // may resolve theory implications with Solver::resolveTheoryImplication 00182 int computeRootReason(Lit implied, Solver* solver); 00183 00184 00185 // register the empty clause (or a clause falsified in the root level) 00186 // showing that the clause set is unsatisfiable. 00187 // 00188 // if clause is not the empty clause, the empty clause is derived from it, 00189 // possible using computeRootReason 00190 void finish(Clause* clause, Solver* solver); 00191 00192 00193 // print the derivation of the given clause 00194 // 00195 // output is of the form: 00196 // ID D : L1 ... Ln : C1 K1 C2 K2 ... Cm 00197 // where: 00198 // ID - the id of a clause 00199 // D - 'I' for an input clause, 'D' for a clause derived from other clauses 00200 // Li - the clause literals 00201 // Ci Ki - the clause is derived from these clauses by binary resolution on the given literals 00202 // 00203 // factoring is done after each resolution step, i.e. duplicate literals are removed from the clause. 00204 // 00205 // example: 00206 // 3 D : +12 -2 -33 : 1 +10 2 00207 // says that the clause with the id 3 consists of the literals +12, -2, -33, 00208 // and was derived by resolution between the clauses with ids 1 and 2, 00209 // where the literal +10 is in clause 1 and -10 is in clause 2. 00210 // 00211 // for example, 1 may be the clause +12 +10 -2, and 2 may be -10 -2 -33, 00212 // which resolved on +10 yield the clause +12 -2 -2 -33, 00213 // which after factoring simplified to +12 -2 -33. 00214 void printDerivation(Clause* clause); 00215 00216 // print the derivation of the empty clause. 00217 void printDerivation(); 00218 00219 // for debugging only 00220 void checkDerivation(Clause* clause); 00221 00222 // creates a new proof; ownership transferred to caller 00223 SAT::SatProof* createProof(); 00224 SAT::SatProof* createProof(Clause* clause); 00225 00226 // see Solver::push - clauseID is the highest currently used clause id 00227 void push(int clauseID); 00228 00229 // see Solver::pop - clauseID corresponds to a clause id used in a push 00230 void pop(int clauseID); 00231 }; 00232 } 00233 00234 00235 #endif