00001 /*****************************************************************************/ 00002 /*! 00003 * \file theory_core.h 00004 * 00005 * Author: Clark Barrett 00006 * 00007 * Created: Thu Jan 30 16:58:05 2003 00008 * 00009 * <hr> 00010 * Copyright (C) 2003 by the Board of Trustees of Leland Stanford 00011 * Junior University and by New York University. 00012 * 00013 * License to use, copy, modify, sell and/or distribute this software 00014 * and its documentation for any purpose is hereby granted without 00015 * royalty, subject to the terms and conditions defined in the \ref 00016 * LICENSE file provided with this distribution. In particular: 00017 * 00018 * - The above copyright notice and this permission notice must appear 00019 * in all copies of the software and related documentation. 00020 * 00021 * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES, 00022 * EXPRESSED OR IMPLIED. USE IT AT YOUR OWN RISK. 00023 * 00024 * <hr> 00025 * 00026 */ 00027 /*****************************************************************************/ 00028 00029 #ifndef _cvcl__include__theory_core_h_ 00030 #define _cvcl__include__theory_core_h_ 00031 00032 #include <queue> 00033 #include "theory.h" 00034 #include "cdmap.h" 00035 00036 namespace CVCL { 00037 00038 class ExprTransform; 00039 class Statistics; 00040 class CoreProofRules; 00041 00042 /*****************************************************************************/ 00043 /*! 00044 *\class TheoryCore 00045 *\ingroup Theories 00046 *\brief This theory handles the built-in logical connectives plus equality. 00047 * It also handles the registration and cooperation among all other theories. 00048 * 00049 * Author: Clark Barrett 00050 * 00051 * Created: Sat Feb 8 14:54:05 2003 00052 */ 00053 /*****************************************************************************/ 00054 class TheoryCore :public Theory { 00055 friend class Theory; 00056 00057 //! Context manager 00058 ContextManager* d_cm; 00059 00060 //! Theorem manager 00061 TheoremManager* d_tm; 00062 00063 //! Core proof rules 00064 CoreProofRules* d_rules; 00065 00066 //! Reference to command line flags 00067 const CLFlags& d_flags; 00068 00069 //! Reference to statistics 00070 Statistics& d_statistics; 00071 00072 //! PrettyPrinter (we own it) 00073 PrettyPrinter* d_printer; 00074 00075 //! Type Computer 00076 ExprManager::TypeComputer* d_typeComputer; 00077 00078 //! Expr Transformer 00079 ExprTransform* d_exprTrans; 00080 00081 //! Assertion queue 00082 std::queue<Theorem> d_queue; 00083 //! Queue of facts to be sent to the SearchEngine 00084 std::vector<Theorem> d_queueSE; 00085 00086 //! Equality queue 00087 /*! 00088 * Contains Theorems in the form of e1==e2, where e2 is i-leaf 00089 * simplified in the current context. 00090 * 00091 * \sa enqueueEquality(). 00092 */ 00093 std::vector<Theorem> d_equalityQueue; 00094 00095 //! Inconsistent flag 00096 CDO<bool> d_inconsistent; 00097 //! The set of reasons for incompleteness (empty when we are complete) 00098 CDMap<std::string, bool> d_incomplete; 00099 //! List of known disequalities (to be processed at every checkSat() call) 00100 CDList<Theorem> d_diseq; 00101 00102 //! Proof of inconsistent 00103 CDO<Theorem> d_incThm; 00104 //! List of all active terms in the system (for quantifier instantiation) 00105 CDList<Expr> d_terms; 00106 //! List of variables that were created up to this point 00107 CDList<Expr> d_vars; 00108 //! Database of declared identifiers 00109 std::map<std::string, Expr> d_globals; 00110 //! Bound variable stack: a vector of pairs <name, var> 00111 std::vector<std::pair<std::string, Expr> > d_boundVarStack; 00112 00113 //! List of all terms that are shared between theories (alien subterms) 00114 /*! Maps each shared term to its own theory. */ 00115 CDMap<Expr, Theory*> d_sharedTerms; 00116 00117 std::map<Expr, bool> d_typePredAsserted; 00118 00119 //! Array of registered theories 00120 std::vector<Theory*> d_theories; 00121 00122 //! Array mapping kinds to theories 00123 std::map<int, Theory*> d_theoryMap; 00124 00125 //! The theory which has the solver (if any) 00126 Theory* d_solver; 00127 00128 //! Mapping of compound type variables to simpler types (model generation) 00129 ExprHashMap<std::vector<Expr> > d_varModelMap; 00130 //! Mapping of intermediate variables to their valies 00131 ExprHashMap<Theorem> d_varAssignments; 00132 //! List of basic variables (temporary storage for model generation) 00133 std::vector<Expr> d_basicModelVars; 00134 //! Mapping of basic variables to simplified expressions (temp. storage) 00135 /*! There may be some vars which simplify to something else; we save 00136 * those separately, and keep only those which simplify to 00137 * themselves. Once the latter vars are assigned, we'll re-simplify 00138 * the former variables and use the results as concrete values. 00139 */ 00140 ExprHashMap<Theorem> d_simplifiedModelVars; 00141 00142 //! Command line flag whether to simplify in place 00143 const bool* d_simplifyInPlace; 00144 //! Which recursive simplifier to use 00145 Theorem (TheoryCore::*d_currentRecursiveSimplifier)(const Expr&); 00146 00147 //! Command line flag whether to convert to CNF 00148 const bool* d_cnfOption; 00149 00150 //! Resource limit (0==unlimited, 1==no more resources, >=2 - available). 00151 /*! Currently, it is the number of enqueued facts. Once the 00152 * resource is exhausted, the remaining facts will be dropped, and 00153 * an incomplete flag is set. 00154 */ 00155 unsigned d_resourceLimit; 00156 00157 //! Command line flag whether to dump debugging info on every new fact 00158 IF_DEBUG(const std::string* d_dumpTrace); 00159 IF_DEBUG(bool d_inCheckSATCore); 00160 IF_DEBUG(bool d_inAddFact); 00161 IF_DEBUG(bool d_inSimplify); 00162 IF_DEBUG(bool d_inRegisterAtom); 00163 00164 //! So we get notified every time there's a pop 00165 friend class CoreNotifyObj; 00166 class CoreNotifyObj :public ContextNotifyObj { 00167 TheoryCore* d_theoryCore; 00168 public: 00169 CoreNotifyObj(TheoryCore* tc, Context* context) 00170 : ContextNotifyObj(context), d_theoryCore(tc) {} 00171 void notify() { d_theoryCore->getEM()->invalidateSimpCache(); } 00172 }; 00173 CoreNotifyObj d_notifyObj; 00174 00175 // Equivalence checking variables 00176 00177 //! Memory Manager index for equiv. check Expr 00178 size_t d_equivCheckMMidx; 00179 00180 //! List of implied literals, based on registered atomic formulas of interest 00181 CDList<Theorem> d_impliedLiterals; 00182 00183 //! Next index in d_impliedLiterals that has not yet been fetched 00184 CDO<unsigned> d_impliedLiteralsIdx; 00185 00186 //! List of theorems from calls to update() 00187 // These are stored here until the equality lists are finished and then 00188 // processed by processUpdates() 00189 std::vector<Theorem> d_update_thms; 00190 00191 //! List of data accompanying above theorems from calls to update() 00192 std::vector<Expr> d_update_data; 00193 00194 public: 00195 /***************************************************************************/ 00196 /*! 00197 *\class TheoryCore::CoreSatAPI 00198 *\brief Interface class for callbacks to SAT from Core 00199 * 00200 * Author: Clark Barrett 00201 * 00202 * Created: Mon Dec 5 18:42:15 2005 00203 */ 00204 /***************************************************************************/ 00205 class CoreSatAPI { 00206 public: 00207 CoreSatAPI() {} 00208 virtual ~CoreSatAPI() {} 00209 //! Add a new lemma derived by theory core 00210 virtual void addLemma(const Theorem& thm) = 0; 00211 //! Get the bottom-most scope where conflict clauses are still valid 00212 virtual int getBottomScope() = 0; 00213 //! Add an assumption to the set of assumptions in the current context 00214 /*! Assumptions have the form e |- e */ 00215 virtual Theorem addAssumption(const Expr& assump) = 0; 00216 //! Suggest a splitter to the Sat engine 00217 /*! \param e is a literal. 00218 * \param priority is between -10 and 10. A priority above 0 indicates 00219 * that the splitter should be favored. A priority below 0 indicates that 00220 * the splitter should be delayed. 00221 */ 00222 virtual void addSplitter(const Expr& e, int priority) = 0; 00223 }; 00224 private: 00225 CoreSatAPI* d_coreSatAPI; 00226 00227 private: 00228 00229 IF_DEBUG( 00230 //! Print an entry to the dump-trace file: new fact (splitter, BCP...) 00231 void dumpTrace(const Expr& fact, const std::string& title); 00232 ) 00233 00234 //! Set the find pointer of an atomic formula and notify SearchEngine 00235 /*! \param thm is a Theorem(phi) or Theorem(NOT phi), where phi is 00236 * an atomic formula to get a find pointer to TRUE or FALSE, 00237 * respectively. 00238 * \param notifySAT indicates whether to notify the Search Engine of 00239 * this literal. 00240 */ 00241 void setFindLiteral(const Theorem& thm, bool notifySAT); 00242 //! Derived rule for rewriting ITE 00243 Theorem rewriteIte(const Expr& e); 00244 //! Core rewrites for literals (NOT and EQ) 00245 Theorem rewriteLitCore(const Expr& e); 00246 //! Rewrite n levels deep. WARNING: no caching here, be careful. 00247 Theorem rewriteN(const Expr& e, int n); 00248 /*! @brief An auxiliary function for assertEqualities(); return true 00249 * if inconsistency is derived. 00250 */ 00251 bool processEquality(const Theorem& thm, ExprMap<Theorem>& q); 00252 //! Private method to get a new theorem producer. 00253 /*! This method is used ONLY by the TheoryCore constructor. The 00254 only reason to have this method is to separate the trusted part of 00255 the constructor into a separate .cpp file (Alternative is to make 00256 the entire constructer trusted, which is not very safe). */ 00257 CoreProofRules* createProofRules(TheoremManager* tm); 00258 //! Enqueue a fact to be sent to the SearchEngine 00259 void enqueueSE(const Theorem& thm); 00260 //! Fetch the concrete assignment to the variable during model generation 00261 Theorem getModelValue(const Expr& e); 00262 00263 //! Create a new equiv. check Expr (private, only TheoryCore can do that) 00264 Expr newEquivCkExpr(const Expr& e0, const Expr& e1); 00265 00266 //! An auxiliary recursive function to process COND expressions into ITE 00267 Expr processCond(const Expr& e, int i); 00268 00269 //! Request a unit of resource 00270 /*! It will be subtracted from the resource limit. 00271 * 00272 * \return true if resource unit is granted, false if no more 00273 * resources available. 00274 */ 00275 bool getResource(); 00276 00277 public: 00278 //! Register a SatAPI for TheoryCore 00279 void registerCoreSatAPI(CoreSatAPI* coreSatAPI) 00280 { d_coreSatAPI = coreSatAPI; } 00281 00282 //! Check if the expr is Equiv. Check Expr 00283 bool isEquivCheckExpr(const Expr& e); 00284 //! Access LHS of the equiv. check expr 00285 const Expr& getE0(const Expr& e); 00286 //! Access RHS of the equiv. check expr 00287 const Expr& getE1(const Expr& e); 00288 00289 //! Constructor 00290 TheoryCore(ContextManager* cm, ExprManager* em, 00291 TheoremManager* tm, const CLFlags& flags, 00292 Statistics& statistics); 00293 //! Destructor 00294 ~TheoryCore(); 00295 00296 ContextManager* getCM() const { return d_cm; } 00297 TheoremManager* getTM() const { return d_tm; } 00298 const CLFlags& getFlags() const { return d_flags; } 00299 Statistics& getStatistics() const { return d_statistics; } 00300 ExprTransform* getExprTrans() const { return d_exprTrans; } 00301 CoreProofRules* getCoreRules() const { return d_rules; } 00302 00303 //! Get list of terms 00304 const CDList<Expr>& getTerms() { return d_terms; } 00305 00306 // Implementation of Theory API 00307 /*! Variables of uninterpreted types may be sent here, and they 00308 should be ignored. */ 00309 void addSharedTerm(const Expr& e) { } 00310 void assertFact(const Theorem& e); 00311 void checkSat(bool fullEffort); 00312 Theorem rewrite(const Expr& e); 00313 void setup(const Expr& e); 00314 void update(const Theorem& e, const Expr& d); 00315 Theorem solve(const Theorem& e); 00316 00317 Theorem simplifyOp(const Expr& e); 00318 void checkType(const Expr& e); 00319 void computeType(const Expr& e); 00320 Type computeBaseType(const Type& t); 00321 Expr computeTCC(const Expr& e); 00322 Expr computeTypePred(const Type& t,const Expr& e); 00323 Expr parseExprOp(const Expr& e); 00324 ExprStream& print(ExprStream& os, const Expr& e); 00325 //! Calls for other theories to add facts to refine a coutnerexample. 00326 void refineCounterExample(); 00327 void computeModelBasic(const std::vector<Expr>& v); 00328 00329 // User-level API methods 00330 00331 //! Set the resource limit (0==unlimited). 00332 void setResourceLimit(unsigned limit); 00333 00334 //! Check if the current context is inconsistent 00335 bool inconsistent() { return d_inconsistent ; } 00336 //! Get the proof of inconsistency for the current context 00337 /*! \return Theorem(FALSE) */ 00338 Theorem inconsistentThm() { return d_incThm; } 00339 00340 /*! @brief Add a new assertion to the core from the user or a SAT 00341 solver. Do NOT use it in a decision procedure; use 00342 enqueueFact(). */ 00343 /*! \sa enqueueFact */ 00344 void addFact(const Theorem& e); 00345 00346 //! Top-level simplifier 00347 Theorem simplify(const Expr& e, bool forceRebuild = true); 00348 00349 /*! @brief To be called by SearchEngine when it believes the context 00350 * is satisfiable. 00351 * 00352 * \return true if definitely consistent or inconsistent and false if 00353 * consistency is unknown. 00354 */ 00355 bool checkSATCore(); 00356 00357 //! Register an atomic formula of interest. 00358 /*! If e or its negation is later deduced, we will add the implied 00359 literal to d_impliedLiterals */ 00360 void registerAtom(const Expr& e); 00361 00362 //! Return the next implied literal (NULL Theorem if none) 00363 Theorem getImpliedLiteral(void); 00364 00365 //! Return total number of implied literals 00366 unsigned numImpliedLiterals() { return d_impliedLiterals.size(); } 00367 00368 //! Return an implied literal by index 00369 Theorem getImpliedLiteralByIndex(unsigned index); 00370 00371 //! Check if the current decision branch is marked as incomplete 00372 bool incomplete() { return d_incomplete.size() > 0 ; } 00373 //! Check if the branch is incomplete, and return the reasons (strings) 00374 bool incomplete(std::vector<std::string>& reasons); 00375 00376 //! Called by search engine 00377 Theorem rewriteLiteral(const Expr& e); 00378 00379 //! Parse the generic expression. 00380 /*! This method should be used in parseExprOp() for recursive calls 00381 * to subexpressions, and is the method called by the command 00382 * processor. 00383 */ 00384 Expr parseExpr(const Expr& e); 00385 //! Top-level call to parseExpr, clears the bound variable stack. 00386 /*! Use it in VCL instead of parseExpr(). */ 00387 Expr parseExprTop(const Expr& e) { 00388 d_boundVarStack.clear(); 00389 return parseExpr(e); 00390 } 00391 00392 //! Assign t a concrete value val. Used in model generation. 00393 void assignValue(const Expr& t, const Expr& val); 00394 //! Record a derived assignment to a variable (LHS). 00395 void assignValue(const Theorem& thm); 00396 00397 //! Adds expression to var database 00398 void addToVarDB(const Expr & e); 00399 //! Split compound vars into basic type variables 00400 /*! The results are saved in d_basicModelVars and 00401 * d_simplifiedModelVars. Also, add new basic vars as shared terms 00402 * whenever their type belongs to a different theory than the term 00403 * itself. 00404 */ 00405 void collectBasicVars(); 00406 //! Calls theory specific computeModel, results are placed in map 00407 void buildModel(ExprMap<Expr>& m); 00408 //! Recursively build a compound-type variable assignment for e 00409 void collectModelValues(const Expr& e, ExprMap<Expr>& m); 00410 00411 Theorem typePred(const Expr& e); 00412 00413 //! Compute and cache the subtyping predicates for the expression 00414 /*! 00415 * Note: e caches the conjunction of <em>all</em> predicates for its 00416 * subexpressions. So, when doing a look-up, it is sufficient to 00417 * assert just the predicate for the top-level e, without traversing 00418 * e recursively. 00419 */ 00420 Theorem subtypePredicate(const Expr& e); 00421 00422 // TODO: These should be private 00423 //! Enqueue a new fact 00424 void enqueueFact(const Theorem& e); 00425 00426 // Must provide proof of inconsistency 00427 void setInconsistent(const Theorem& e); 00428 00429 //! Setup additional terms within a theory-specific setup(). 00430 void setupTerm(const Expr& e, Theory* i); 00431 00432 private: 00433 // Methods provided for benefit of theories. Access is made available through theory.h 00434 00435 //! Enqueue a new equality 00436 void enqueueEquality(const Theorem& e); 00437 //! Assert a system of equations (1 or more). 00438 /*! e is either a single equation, or a conjunction of equations 00439 */ 00440 void assertEqualities(const Theorem& e); 00441 00442 //! Mark the branch as incomplete 00443 void setIncomplete(const std::string& reason); 00444 00445 private: 00446 // Helper functions 00447 00448 //! A helper function for addFact() 00449 void processFactQueue(); 00450 //! Process a notify list triggered as a result of new theorem e 00451 void processNotify(const Theorem& e, NotifyList* L); 00452 //! The recursive simplifier (to be used only in DP-specific simplifyOp()) 00453 Theorem simplifyRec(const Expr& e); 00454 //! The full recursive simplifier 00455 Theorem simplifyFullRec(const Expr& e); 00456 //! The recursive simplifier with the in-place rewriting optimization 00457 Theorem simplifyInPlaceRec(const Expr& e); 00458 //! Transitive composition of other rewrites with the above 00459 Theorem rewriteCore(const Theorem& e); 00460 //! Helper for registerAtom 00461 void setupSubFormulas(const Expr& s, const Expr& e); 00462 //! Process updates recorded by calls to update() 00463 void processUpdates(); 00464 /*! @brief The assumptions for e must be in H or phi. "Core" added 00465 * to avoid conflict with theory interface function name 00466 */ 00467 void assertFactCore(const Theorem& e); 00468 //! Process a newly derived formula 00469 void assertFormula(const Theorem& e); 00470 /*! @brief Returns phi |= e = rewriteCore(e). "Core" added to avoid 00471 conflict with theory interface function name */ 00472 Theorem rewriteCore(const Expr& e); 00473 00474 public: 00475 // Used by vcl.cpp: TODO: tcc stuff should be consolidated 00476 Theorem3 queryTCC(const Theorem& phi, const Theorem& D_phi); 00477 Theorem3 implIntro3(const Theorem3& phi, 00478 const std::vector<Expr>& assump, 00479 const std::vector<Theorem>& tccs); 00480 00481 00482 }; 00483 00484 //! Printing NotifyList class 00485 std::ostream& operator<<(std::ostream& os, const NotifyList& l); 00486 00487 } 00488 00489 #endif