CVC3
|
00001 /*****************************************************************************/ 00002 /*! 00003 *\file search_sat.h 00004 *\brief Search engine that uses an external SAT engine 00005 * 00006 * Author: Clark Barrett 00007 * 00008 * Created: Mon Dec 5 17:52:05 2005 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 #ifndef _cvc3__include__search_sat_h_ 00023 #define _cvc3__include__search_sat_h_ 00024 00025 #include <vector> 00026 #include <set> 00027 #include "search.h" 00028 #include "smartcdo.h" 00029 #include "cdlist.h" 00030 #include "cnf_manager.h" 00031 #include "expr.h" 00032 #include "dpllt.h" 00033 #include "theory_core.h" 00034 #include "formula_value.h" 00035 00036 namespace CVC3 { 00037 00038 //! Search engine that connects to a generic SAT reasoning module 00039 /*! \ingroup SE */ 00040 class SearchSat :public SearchEngine { 00041 00042 //! Name of search engine 00043 std::string d_name; 00044 00045 //! Bottom scope for current query 00046 CDO<int> d_bottomScope; 00047 00048 //! Last expr checked for validity 00049 CDO<Expr> d_lastCheck; 00050 00051 /*! @brief Theorem from the last successful checkValid call. It is 00052 used by getProof and getAssumptions. */ 00053 CDO<Theorem> d_lastValid; 00054 00055 //! List of all user assumptions 00056 CDList<Theorem> d_userAssumptions; 00057 00058 //! List of all internal assumptions 00059 CDList<Theorem> d_intAssumptions; 00060 00061 //! Index to where unprocessed assumptions start 00062 CDO<unsigned> d_idxUserAssump; 00063 00064 TheoryCore::CoreSatAPI* d_coreSatAPI; 00065 00066 //! Pointer to DPLLT implementation 00067 SAT::DPLLT* d_dpllt; 00068 00069 //! Implementation of TheoryAPI for DPLLT 00070 SAT::DPLLT::TheoryAPI* d_theoryAPI; 00071 00072 //! Implementation of Decider for DPLLT 00073 SAT::DPLLT::Decider* d_decider; 00074 00075 //! Store of theorems for expressions sent to DPLLT 00076 CDMap<Expr, Theorem> d_theorems; 00077 00078 //! Manages CNF formula and its relationship to original Exprs and Theorems 00079 SAT::CNF_Manager *d_cnfManager; 00080 00081 //! Callback for CNF_Manager 00082 SAT::CNF_Manager::CNFCallback *d_cnfCallback; 00083 00084 //! Cached values of variables 00085 std::vector<SAT::Var::Val> d_vars; 00086 00087 //! Whether we are currently in a call to dpllt->checkSat 00088 bool d_inCheckSat; 00089 00090 //! CNF Formula used for theory lemmas 00091 SAT::CD_CNF_Formula d_lemmas; 00092 00093 //! Lemmas waiting to be translated since last call to getNewClauses() 00094 std::vector<std::pair<Theorem, int> > d_pendingLemmas; 00095 00096 //! Scope parameter for lemmas waiting to be translated since last call to getNewClauses() 00097 std::vector<bool> d_pendingScopes; 00098 00099 //! Backtracking size of d_pendingLemmas 00100 CDO<unsigned> d_pendingLemmasSize; 00101 00102 //! Backtracking next item in d_pendingLemmas 00103 CDO<unsigned> d_pendingLemmasNext; 00104 00105 //! Current position in d_lemmas 00106 CDO<unsigned> d_lemmasNext; 00107 00108 //! List for backtracking var values 00109 std::vector<unsigned> d_varsUndoList; 00110 00111 //! Backtracking size of d_varsUndoList 00112 CDO<unsigned> d_varsUndoListSize; 00113 00114 public: 00115 //! Pair of Lit and priority of this Lit 00116 class LitPriorityPair { 00117 SAT::Lit d_lit; 00118 int d_priority; 00119 LitPriorityPair() {} 00120 public: 00121 LitPriorityPair(SAT::Lit lit, int priority) 00122 : d_lit(lit), d_priority(priority) {} 00123 SAT::Lit getLit() const { return d_lit; } 00124 int getPriority() const { return d_priority; } 00125 friend bool operator<(const LitPriorityPair& p1, 00126 const LitPriorityPair& p2); 00127 }; 00128 00129 private: 00130 //! Used to determine order to find splitters 00131 std::set<LitPriorityPair> d_prioritySet; 00132 //! Current position in prioritySet 00133 CDO<std::set<LitPriorityPair>::const_iterator> d_prioritySetStart; 00134 //! Backtracking size of priority set entries 00135 CDO<unsigned> d_prioritySetEntriesSize; 00136 //! Entries in priority set in insertion order (so set can be backtracked) 00137 std::vector<std::set<LitPriorityPair>::iterator> d_prioritySetEntries; 00138 //! Backtracking size of priority set entries at bottom scope 00139 std::vector<unsigned> d_prioritySetBottomEntriesSizeStack; 00140 //! Current size of bottom entries 00141 unsigned d_prioritySetBottomEntriesSize; 00142 //! Entries in priority set in insertion order (so set can be backtracked) 00143 std::vector<std::set<LitPriorityPair>::iterator> d_prioritySetBottomEntries; 00144 00145 //! Last Var registered with core theory 00146 CDO<unsigned> d_lastRegisteredVar; 00147 00148 //! Whether it's OK to call DPLLT solver from the current scope 00149 CDO<bool> d_dplltReady; 00150 00151 CDO<unsigned> d_nextImpliedLiteral; 00152 00153 //! Helper class for resetting DPLLT engine 00154 /*! We need to be notified when the scope goes below the scope from 00155 * which the last invalid call to checkValid originated. This helper class 00156 * ensures that this happens. 00157 */ 00158 friend class Restorer; 00159 class Restorer :public ContextNotifyObj { 00160 SearchSat* d_ss; 00161 public: 00162 Restorer(Context* context, SearchSat* ss) 00163 : ContextNotifyObj(context), d_ss(ss) {} 00164 void notifyPre() { d_ss->restorePre(); } 00165 void notify() { d_ss->restore(); } 00166 }; 00167 //! Instance of Restorer class 00168 Restorer d_restorer; 00169 00170 private: 00171 00172 //! Get rid of bottom scope entries in prioritySet 00173 void restorePre(); 00174 //! Get rid of entries in prioritySet and pendingLemmas added since last push 00175 void restore(); 00176 //! Helper for addLemma and check 00177 bool recordNewRootLit(SAT::Lit lit, int priority = 0, bool atBottomScope = false); 00178 00179 friend class SearchSatCoreSatAPI; 00180 friend class SearchSatCNFCallback; 00181 //! Core theory callback which adds a new lemma from the core theory 00182 void addLemma(const Theorem& thm, int priority = 0, bool atBotomScope = false); 00183 //! Core theory callback which asks for the bottom scope for current query 00184 int getBottomScope() { return d_bottomScope; } 00185 //! Core theory callback which suggests a splitter 00186 void addSplitter(const Expr& e, int priority); 00187 00188 friend class SearchSatTheoryAPI; 00189 //! DPLLT callback to inform theory that a literal has been assigned 00190 void assertLit(SAT::Lit l); 00191 //! DPLLT callback to ask if theory has detected inconsistency. 00192 SAT::DPLLT::ConsistentResult checkConsistent(SAT::CNF_Formula& cnf, bool fullEffort); 00193 //! DPLLT callback to get theory propagations. 00194 SAT::Lit getImplication(); 00195 //! DPLLT callback to explain a theory propagation. 00196 void getExplanation(SAT::Lit l, SAT::CNF_Formula& cnf); 00197 //! DPLLT callback to get more general theory clauses. 00198 bool getNewClauses(SAT::CNF_Formula& cnf); 00199 00200 friend class SearchSatDecider; 00201 //! DPLLT callback to decide which literal to split on next 00202 SAT::Lit makeDecision(); 00203 00204 //! Recursively traverse DAG looking for a splitter 00205 /*! Returns true if a splitter is found, false otherwise. The splitter is 00206 * returned in lit (lit should be set to true). Nodes whose current value is 00207 * fully justified are marked by calling setFlag to avoid searching them in 00208 * the future. 00209 */ 00210 bool findSplitterRec(SAT::Lit lit, SAT::Var::Val value, 00211 SAT::Lit* litDecision); 00212 00213 //! Get the value of a CNF Literal 00214 SAT::Var::Val getValue(SAT::Lit c) { 00215 DebugAssert(!c.isNull() && 00216 (!c.isVar() || unsigned(c.getVar()) < d_vars.size()), 00217 "Lit out of bounds in getValue"); 00218 return c.isPositive() ? d_vars[c.getVar()] : 00219 c.isInverted() ? SAT::Var::invertValue(d_vars[c.getVar()]) : 00220 c.isTrue() ? SAT::Var::TRUE_VAL : SAT::Var::FALSE_VAL; 00221 } 00222 00223 SAT::Var::Val getValue(SAT::Var v) { 00224 DebugAssert(v.isVar() && unsigned(v) < d_vars.size(), "Var out of bounds in getValue"); 00225 return d_vars[v]; 00226 } 00227 00228 //! Set the value of a variable 00229 void setValue(SAT::Var v, SAT::Var::Val val) { 00230 DebugAssert(!v.isNull(), "expected non-null Var"); 00231 DebugAssert(unsigned(v) < d_vars.size(), "Var out of bounds in getValue"); 00232 DebugAssert(d_vars[v] == SAT::Var::UNKNOWN, "Expected unknown"); 00233 DebugAssert(val != SAT::Var::UNKNOWN, "Expected set to non-unknown"); 00234 d_vars[v] = val; 00235 DebugAssert(d_varsUndoListSize == d_varsUndoList.size(), "Size mismatch"); 00236 d_varsUndoList.push_back(unsigned(v)); 00237 d_varsUndoListSize = d_varsUndoListSize + 1; 00238 } 00239 00240 //! Check whether this variable's value is justified 00241 bool checkJustified(SAT::Var v) 00242 { return d_cnfManager->concreteLit(SAT::Lit(v)).isJustified(); } 00243 00244 //! Mark this variable as justified 00245 void setJustified(SAT::Var v) 00246 { d_cnfManager->concreteLit(SAT::Lit(v)).setJustified(); } 00247 00248 //! Main checking procedure shared by checkValid and restart 00249 QueryResult check(const Expr& e, Theorem& result, bool isRestart = false); 00250 00251 //! Helper for newUserAssumptionInt 00252 void newUserAssumptionIntHelper(const Theorem& thm, SAT::CNF_Formula_Impl& cnf, 00253 bool atBottomScope); 00254 //! Helper for newUserAssumption 00255 Theorem newUserAssumptionInt(const Expr& e, SAT::CNF_Formula_Impl& cnf, 00256 bool atBottomScope); 00257 00258 public: 00259 00260 //! Constructor 00261 //! name is the name of the dpllt engine to use, as returned by getName() 00262 SearchSat(TheoryCore* core, const std::string& name); 00263 00264 //! Destructor 00265 virtual ~SearchSat(); 00266 00267 // Implementation of virtual SearchEngine methods 00268 virtual const std::string& getName() { return d_name; } 00269 virtual void registerAtom(const Expr& e); 00270 virtual Theorem getImpliedLiteral(); 00271 virtual void push() { d_dpllt->push(); } 00272 virtual void pop() { d_dpllt->pop(); } 00273 virtual QueryResult checkValid(const Expr& e, Theorem& result) 00274 { return check(e, result); } 00275 virtual QueryResult restart(const Expr& e, Theorem& result) 00276 { return check(e, result, true); } 00277 virtual void returnFromCheck(); 00278 virtual Theorem lastThm() { return d_lastValid; } 00279 virtual Theorem newUserAssumption(const Expr& e); 00280 virtual void getUserAssumptions(std::vector<Expr>& assumptions); 00281 virtual void getInternalAssumptions(std::vector<Expr>& assumptions); 00282 virtual void getAssumptions(std::vector<Expr>& assumptions); 00283 virtual bool isAssumption(const Expr& e); 00284 virtual void getCounterExample(std::vector<Expr>& assertions, 00285 bool inOrder = true); 00286 virtual Proof getProof(); 00287 00288 //:ALEX: 00289 virtual FormulaValue getValue(const CVC3::Expr& e) { 00290 SAT::Lit l = d_cnfManager->getCNFLit(e); 00291 00292 if (l.isNull()) { 00293 //:DEBUG: 00294 std::cout << "No lit for expr: " << e.toString() << std::endl; 00295 FatalAssert(false, "getValue"); 00296 return UNKNOWN_VAL; 00297 } else { 00298 switch (getValue(l)) { 00299 case SAT::Var::TRUE_VAL: return TRUE_VAL; 00300 case SAT::Var::FALSE_VAL: return FALSE_VAL; 00301 case SAT::Var::UNKNOWN: return UNKNOWN_VAL; 00302 default: 00303 DebugAssert(false, "unreachable"); 00304 return UNKNOWN_VAL; 00305 } 00306 } 00307 } 00308 00309 }; 00310 00311 inline bool operator<(const SearchSat::LitPriorityPair& p1, 00312 const SearchSat::LitPriorityPair& p2) 00313 { 00314 if (p1.d_priority > p2.d_priority) return true; 00315 if (p1.d_priority < p2.d_priority) return false; 00316 return abs(p1.d_lit.getID()) < abs(p2.d_lit.getID()) || 00317 (abs(p1.d_lit.getID()) == abs(p2.d_lit.getID()) && p1.d_lit.getID() > 0 && (!(p2.d_lit.getID() > 0))); 00318 } 00319 00320 } 00321 00322 #endif