00001 /*****************************************************************************/ 00002 /*! 00003 * \file search_impl_base.h 00004 * \brief Abstract API to the proof search engine 00005 * 00006 * Author: Clark Barrett, Vijay Ganesh (Clausal Normal Form Converter) 00007 * 00008 * Created: Fri Jan 17 13:35:03 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 #ifndef _cvc3__include__search_impl_base_h_ 00023 #define _cvc3__include__search_impl_base_h_ 00024 00025 #include "search.h" 00026 #include "theory_core.h" 00027 #include "variable.h" 00028 #include "formula_value.h" 00029 00030 namespace CVC3 { 00031 00032 class SearchEngineRules; 00033 class VariableManager; 00034 00035 //! API to to a generic proof search engine (a.k.a. SAT solver) 00036 /*! \ingroup SE */ 00037 class SearchImplBase :public SearchEngine { 00038 friend class DecisionEngine; 00039 protected: 00040 /*! \addtogroup SE 00041 * @{ 00042 */ 00043 //! Variable manager for classes Variable and Literal 00044 VariableManager* d_vm; 00045 00046 /*! @brief The bottom-most scope for the current call to checkSAT (where conflict 00047 clauses are still valid). 00048 */ 00049 CDO<int> d_bottomScope; 00050 00051 TheoryCore::CoreSatAPI* d_coreSatAPI_implBase; 00052 00053 //! Representation of a DP-suggested splitter 00054 class Splitter { 00055 Literal d_lit; 00056 public: 00057 // int priority; 00058 //! Constructor 00059 Splitter(const Literal& lit); 00060 //! Copy constructor 00061 Splitter(const Splitter& s); 00062 //! Assignment 00063 Splitter& operator=(const Splitter& s); 00064 //! Descructor 00065 ~Splitter(); 00066 operator Literal() { return d_lit; } 00067 //! The order is descending by priority ("reversed", highest first) 00068 // friend bool operator<(const Splitter& s1, const Splitter& s2) { 00069 // return (s1.priority > s2.priority 00070 // || (s1.priority == s2.priority && s1.expr > s2.expr)); 00071 // } 00072 }; 00073 //! Backtracking ordered set of DP-suggested splitters 00074 CDList<Splitter> d_dpSplitters; 00075 00076 /*! @brief Theorem from the last successful checkValid call. It is 00077 used by getProof and getAssumptions. */ 00078 Theorem d_lastValid; 00079 /*! @brief Assumptions from the last unsuccessful checkValid call. 00080 These are used by getCounterExample. */ 00081 ExprHashMap<bool> d_lastCounterExample; 00082 /*! @brief Maintain the list of current assumptions (user asserts and 00083 splitters) for getAssumptions(). */ 00084 CDMap<Expr,Theorem> d_assumptions; 00085 00086 //! Backtracking cache for the CNF generator 00087 CDMap<Expr, Theorem> d_cnfCache; 00088 //! Backtracking set of new variables generated by CNF translator 00089 /*! Specific search engines do not have to split on these variables */ 00090 CDMap<Expr, bool> d_cnfVars; 00091 //! Command line flag whether to convert to CNF 00092 const bool* d_cnfOption; 00093 //! Flag: whether to convert term ITEs into CNF 00094 const bool* d_ifLiftOption; 00095 //! Flag: ignore auxiliary CNF variables when searching for a splitter 00096 const bool* d_ignoreCnfVarsOption; 00097 //! Flag: Preserve the original formula with +cnf (for splitter heuristics) 00098 const bool* d_origFormulaOption; 00099 00100 /*! 00101 * \name CNF Caches 00102 * 00103 * These caches are for subexpressions of the translated formula 00104 * phi, to avoid expanding phi into a tree. We cannot use 00105 * d_cnfCache for that, since it is effectively non-backtracking, 00106 * and we do not know if a subexpression of phi was translated at 00107 * the current level, or at some other (inactive) branch of the 00108 * decision tree. 00109 * @{ 00110 */ 00111 //! Cache for enqueueCNF() 00112 CDMap<Expr,bool> d_enqueueCNFCache; 00113 //! Cache for applyCNFRules() 00114 CDMap<Expr,bool> d_applyCNFRulesCache; 00115 //! Cache for replaceITE() 00116 CDMap<Expr,Theorem> d_replaceITECache; 00117 /*@}*/ // End of CNF Caches 00118 00119 //! Construct a Literal out of an Expr or return an existing one 00120 Literal newLiteral(const Expr& e) { return Literal(d_vm, e); } 00121 00122 /*! @brief Our version of simplifier: take Theorem(e), apply 00123 simplifier to get Theorem(e==e'), return Theorem(e') */ 00124 Theorem simplify(const Theorem& e) 00125 { return d_core->iffMP(e, d_core->simplify(e.getExpr())); } 00126 00127 //! Notify the search engine about a new literal fact. 00128 /*! It should be called by SearchEngine::addFact() only. 00129 * Must be implemented by the subclasses of SearchEngine. 00130 * 00131 * IMPORTANT: do not call addFact() from this function; use 00132 * enqueueFact() or setInconsistent() instead. 00133 */ 00134 virtual void addLiteralFact(const Theorem& thm) = 0; 00135 //! Notify the search engine about a new non-literal fact. 00136 /*! It should be called by SearchEngine::addFact() only. 00137 * Must be implemented by the subclasses of SearchEngine. 00138 * 00139 * IMPORTANT: do not call addFact() from this function; use 00140 * enqueueFact() or setInconsistent() instead. 00141 */ 00142 virtual void addNonLiteralFact(const Theorem& thm) = 0; 00143 //! Add a new fact to the search engine bypassing CNF converter 00144 /*! Calls either addLiteralFact() or addNonLiteralFact() 00145 * appropriately, and converts to CNF when d_cnfOption is set. If 00146 * fromCore==true, this fact already comes from the core, and 00147 * doesn't need to be reported back to the core. 00148 */ 00149 void addCNFFact(const Theorem& thm, bool fromCore=false); 00150 00151 public: 00152 00153 int getBottomScope() { return d_bottomScope; } 00154 00155 //! Check if e is a clause (a literal, or a disjunction of literals) 00156 bool isClause(const Expr& e); 00157 00158 //! Check if e is a propositional clause 00159 /*! \sa isPropAtom() */ 00160 bool isPropClause(const Expr& e); 00161 //! Check whether e is a fresh variable introduced by the CNF converter 00162 /*! Search engines do not need to split on those variables in order 00163 * to be complete 00164 */ 00165 bool isCNFVar(const Expr& e) { return (d_cnfVars.count(e) > 0); } 00166 //! Check if a splitter is required for completeness 00167 /*! Currently, it checks that 'e' is not an auxiliary CNF variable */ 00168 bool isGoodSplitter(const Expr& e); 00169 00170 private: 00171 00172 //! Translate theta to CNF and enqueue the new clauses 00173 void enqueueCNF(const Theorem& theta); 00174 //! Recursive version of enqueueCNF() 00175 void enqueueCNFrec(const Theorem& theta); 00176 //! FIXME: write a comment 00177 void applyCNFRules(const Theorem& e); 00178 00179 //! Cache a theorem phi <=> v by phi, where v is a literal. 00180 void addToCNFCache(const Theorem& thm); 00181 00182 //! Find a theorem phi <=> v by phi, where v is a literal. 00183 /*! \return Null Theorem if not found. */ 00184 Theorem findInCNFCache(const Expr& e); 00185 00186 //! Replaces ITE subexpressions in e with variables 00187 Theorem replaceITE(const Expr& e); 00188 00189 protected: 00190 00191 //! Return the current scope level (for convenience) 00192 int scopeLevel() { return d_core->getCM()->scopeLevel(); } 00193 00194 public: 00195 //! Constructor 00196 SearchImplBase(TheoryCore* core); 00197 //! Destructor 00198 virtual ~SearchImplBase(); 00199 00200 virtual void registerAtom(const Expr& e) 00201 { d_core->theoryOf(e)->registerAtom(e, Theorem()); } 00202 virtual Theorem getImpliedLiteral() { return d_core->getImpliedLiteral(); } 00203 virtual void push() { d_core->getCM()->push(); } 00204 virtual void pop() { d_core->getCM()->pop(); } 00205 00206 /////////////////////////////////////////////////////////////////////////// 00207 // checkValid() is the method that subclasses must implement. 00208 /////////////////////////////////////////////////////////////////////////// 00209 00210 //! Checks the validity of a formula in the current context 00211 /*! The method that actually calls the SAT solver (implemented in a 00212 subclass). It should maintain d_assumptions (add all asserted 00213 splitters to it), and set d_lastValid and d_lastCounterExample 00214 appropriately before exiting. */ 00215 virtual QueryResult checkValidInternal(const Expr& e) = 0; 00216 //! Similar to checkValidInternal(), only returns Theorem(e) or Null 00217 virtual QueryResult checkValid(const Expr& e, Theorem& result); 00218 //! Reruns last check with e as an additional assumption 00219 virtual QueryResult restartInternal(const Expr& e) = 0; 00220 //! Reruns last check with e as an additional assumption 00221 virtual QueryResult restart(const Expr& e, Theorem& result); 00222 void returnFromCheck() 00223 { Theorem thm; restart(d_core->falseExpr(), thm); } 00224 virtual Theorem lastThm() { return d_lastValid; } 00225 00226 /////////////////////////////////////////////////////////////////////////// 00227 // The following methods are provided by the base class, and in most 00228 // cases should be sufficient. However, they are virtual so that 00229 // subclasses can add functionality to them if needed. 00230 /////////////////////////////////////////////////////////////////////////// 00231 00232 /*! @brief Generate and add a new assertion to the set of assertions 00233 in the current context. This should only be used by class VCL in 00234 assertFormula(). */ 00235 Theorem newUserAssumption(const Expr& e); 00236 //! Add a new internal asserion 00237 virtual Theorem newIntAssumption(const Expr& e); 00238 //! Helper for above function 00239 void newIntAssumption(const Theorem& thm); 00240 //! Get all assumptions made in this and all previous contexts. 00241 /*! \param assumptions should be an empty vector which will be filled \ 00242 with the assumptions */ 00243 void getUserAssumptions(std::vector<Expr>& assumptions); 00244 void getInternalAssumptions(std::vector<Expr>& assumptions); 00245 virtual void getAssumptions(std::vector<Expr>& assumptions); 00246 //! Check if the formula has been assumed 00247 virtual bool isAssumption(const Expr& e); 00248 00249 //! Add a new fact to the search engine from the core 00250 /*! It should be called by TheoryCore::assertFactCore(). */ 00251 void addFact(const Theorem& thm); 00252 00253 //! Suggest a splitter to the SearchEngine 00254 /*! The higher is the priority, the sooner the SAT solver will split 00255 * on it. It can be positive or negative (default is 0). 00256 * 00257 * The set of suggested splitters is backtracking; that is, a 00258 * splitter is "forgotten" once the scope is backtracked. 00259 * 00260 * This method can be used either to change the priority 00261 * of existing splitters, or to introduce new splitters that DPs 00262 * consider relevant, even though they do not appear in existing 00263 * formulas. 00264 */ 00265 virtual void addSplitter(const Expr& e, int priority); 00266 00267 virtual void getCounterExample(std::vector<Expr>& assertions, bool inOrder = true); 00268 00269 // The following two methods should be called only after a checkValid 00270 // which returns true. In any other case, they return Null values. 00271 00272 //! Returns the proof term for the last proven query 00273 /*! It should be called only after a checkValid which returns true. 00274 In any other case, it returns Null. */ 00275 virtual Proof getProof(); 00276 /*! @brief Returns the set of assumptions used in the proof. It 00277 should be a subset of getAssumptions(). */ 00278 /*! It should be called only after a checkValid which returns true. 00279 In any other case, it returns Null. */ 00280 virtual const Assumptions& getAssumptionsUsed(); 00281 00282 //! Process result of checkValid 00283 void processResult(const Theorem& res, const Expr& e); 00284 00285 //:ALEX: 00286 inline virtual FormulaValue getValue(const CVC3::Expr& e) { 00287 FatalAssert(false, "not implemented"); 00288 return UNKNOWN_VAL; 00289 } 00290 00291 /* @} */ // end of group SE 00292 00293 }; 00294 00295 00296 } 00297 00298 #endif