CVC3
|
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 * 00011 * License to use, copy, modify, sell and/or distribute this software 00012 * and its documentation for any purpose is hereby granted without 00013 * royalty, subject to the terms and conditions defined in the \ref 00014 * LICENSE file provided with this distribution. 00015 * 00016 * <hr> 00017 * 00018 */ 00019 /*****************************************************************************/ 00020 00021 #ifndef _cvc3__include__theory_core_h_ 00022 #define _cvc3__include__theory_core_h_ 00023 00024 #include <queue> 00025 #include "theory.h" 00026 #include "cdmap.h" 00027 #include "statistics.h" 00028 #include <string> 00029 #include "notifylist.h" 00030 //#include "expr_transform.h" 00031 00032 namespace CVC3 { 00033 00034 class ExprTransform; 00035 // class Statistics; 00036 class CoreProofRules; 00037 class Translator; 00038 00039 /*****************************************************************************/ 00040 /*! 00041 *\class TheoryCore 00042 *\ingroup Theories 00043 *\brief This theory handles the built-in logical connectives plus equality. 00044 * It also handles the registration and cooperation among all other theories. 00045 * 00046 * Author: Clark Barrett 00047 * 00048 * Created: Sat Feb 8 14:54:05 2003 00049 */ 00050 /*****************************************************************************/ 00051 class TheoryCore :public Theory { 00052 friend class Theory; 00053 00054 //! Context manager 00055 ContextManager* d_cm; 00056 00057 //! Theorem manager 00058 TheoremManager* d_tm; 00059 00060 //! Core proof rules 00061 CoreProofRules* d_rules; 00062 00063 //! Reference to command line flags 00064 const CLFlags& d_flags; 00065 00066 //! Reference to statistics 00067 Statistics& d_statistics; 00068 00069 //! PrettyPrinter (we own it) 00070 PrettyPrinter* d_printer; 00071 00072 //! Type Computer 00073 ExprManager::TypeComputer* d_typeComputer; 00074 00075 //! Expr Transformer 00076 ExprTransform* d_exprTrans; 00077 00078 //! Translator 00079 Translator* d_translator; 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 //! Inconsistent flag 00087 CDO<bool> d_inconsistent; 00088 //! The set of reasons for incompleteness (empty when we are complete) 00089 CDMap<std::string, bool> d_incomplete; 00090 00091 //! Proof of inconsistent 00092 CDO<Theorem> d_incThm; 00093 //! List of all active terms in the system (for quantifier instantiation) 00094 CDList<Expr> d_terms; 00095 //! Map from active terms to theorems that introduced those terms 00096 00097 std::hash_map<Expr, Theorem> d_termTheorems; 00098 // CDMap<Expr, Theorem> d_termTheorems; 00099 00100 //! List of all active non-equality atomic formulas in the system (for quantifier instantiation) 00101 CDList<Expr> d_predicates; 00102 //! List of variables that were created up to this point 00103 std::vector<Expr> d_vars; 00104 //! Database of declared identifiers 00105 std::map<std::string, Expr> d_globals; 00106 //! Bound variable stack: a vector of pairs <name, var> 00107 std::vector<std::pair<std::string, Expr> > d_boundVarStack; 00108 //! Map for bound vars 00109 std::hash_map<std::string, Expr> d_boundVarMap; 00110 //! Top-level cache for parser 00111 // This cache is only used when there are no bound variables 00112 ExprMap<Expr> d_parseCacheTop; 00113 //! Alternative cache for parser when not at top-level 00114 // This cache used when there are bound variables - and it is cleared 00115 // every time the bound variable stack changes 00116 ExprMap<Expr> d_parseCacheOther; 00117 //! Current cache being used for parser 00118 ExprMap<Expr>* d_parseCache; 00119 //! Cache for tcc's 00120 ExprMap<Expr> d_tccCache; 00121 00122 //! Array of registered theories 00123 std::vector<Theory*> d_theories; 00124 00125 //! Array mapping kinds to theories 00126 std::hash_map<int, Theory*> d_theoryMap; 00127 00128 //! The theory which has the solver (if any) 00129 Theory* d_solver; 00130 00131 //! Mapping of compound type variables to simpler types (model generation) 00132 ExprHashMap<std::vector<Expr> > d_varModelMap; 00133 //! Mapping of intermediate variables to their valies 00134 ExprHashMap<Theorem> d_varAssignments; 00135 //! List of basic variables (temporary storage for model generation) 00136 std::vector<Expr> d_basicModelVars; 00137 //! Mapping of basic variables to simplified expressions (temp. storage) 00138 /*! There may be some vars which simplify to something else; we save 00139 * those separately, and keep only those which simplify to 00140 * themselves. Once the latter vars are assigned, we'll re-simplify 00141 * the former variables and use the results as concrete values. 00142 */ 00143 ExprHashMap<Theorem> d_simplifiedModelVars; 00144 00145 //! Command line flag whether to simplify in place 00146 const bool* d_simplifyInPlace; 00147 //! Which recursive simplifier to use 00148 Theorem (TheoryCore::*d_currentRecursiveSimplifier)(const Expr&); 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 //! Time limit (0==unlimited, >0==total available cpu time in seconds). 00158 /*! Currently, if exhausted processFactQueue will not perform any more 00159 * reasoning with FULL effor and an incomplete flag is set. 00160 */ 00161 unsigned d_timeBase; 00162 unsigned d_timeLimit; 00163 00164 bool d_inCheckSATCore; 00165 bool d_inAddFact; 00166 bool d_inRegisterAtom; 00167 bool d_inPP; 00168 00169 IF_DEBUG(ExprMap<bool> d_simpStack;) 00170 00171 00172 //! So we get notified every time there's a pop 00173 friend class CoreNotifyObj; 00174 class CoreNotifyObj :public ContextNotifyObj { 00175 TheoryCore* d_theoryCore; 00176 public: 00177 CoreNotifyObj(TheoryCore* tc, Context* context) 00178 : ContextNotifyObj(context), d_theoryCore(tc) {} 00179 void notify() { d_theoryCore->getEM()->invalidateSimpCache(); } 00180 }; 00181 CoreNotifyObj d_notifyObj; 00182 00183 //! List of implied literals, based on registered atomic formulas of interest 00184 CDList<Theorem> d_impliedLiterals; 00185 00186 //! Next index in d_impliedLiterals that has not yet been fetched 00187 CDO<unsigned> d_impliedLiteralsIdx; 00188 00189 //! List of theorems from calls to update() 00190 // These are stored here until the equality lists are finished and then 00191 // processed by processUpdates() 00192 std::vector<Theorem> d_update_thms; 00193 00194 //! List of data accompanying above theorems from calls to update() 00195 std::vector<Expr> d_update_data; 00196 00197 //! Notify list that gets processed on every equality 00198 NotifyList d_notifyEq; 00199 00200 //! Whether we are in the middle of doing updates 00201 unsigned d_inUpdate; 00202 00203 public: 00204 /***************************************************************************/ 00205 /*! 00206 *\class CoreSatAPI 00207 *\brief Interface class for callbacks to SAT from Core 00208 * 00209 * Author: Clark Barrett 00210 * 00211 * Created: Mon Dec 5 18:42:15 2005 00212 */ 00213 /***************************************************************************/ 00214 class CoreSatAPI { 00215 public: 00216 CoreSatAPI() {} 00217 virtual ~CoreSatAPI() {} 00218 //! Add a new lemma derived by theory core 00219 virtual void addLemma(const Theorem& thm, int priority = 0, 00220 bool atBottomScope = false) = 0; 00221 //! Add an assumption to the set of assumptions in the current context 00222 /*! Assumptions have the form e |- e */ 00223 virtual Theorem addAssumption(const Expr& assump) = 0; 00224 //! Suggest a splitter to the Sat engine 00225 /*! \param e is a literal. 00226 * \param priority is between -10 and 10. A priority above 0 indicates 00227 * that the splitter should be favored. A priority below 0 indicates that 00228 * the splitter should be delayed. 00229 */ 00230 virtual void addSplitter(const Expr& e, int priority) = 0; 00231 //! Check the validity of e in the current context 00232 virtual bool check(const Expr& e) = 0; 00233 }; 00234 private: 00235 CoreSatAPI* d_coreSatAPI; 00236 00237 private: 00238 //! Private method to get a new theorem producer. 00239 /*! This method is used ONLY by the TheoryCore constructor. The 00240 only reason to have this method is to separate the trusted part of 00241 the constructor into a separate .cpp file (Alternative is to make 00242 the entire constructer trusted, which is not very safe). 00243 Method is implemented in core_theorem_producer.cpp */ 00244 CoreProofRules* createProofRules(TheoremManager* tm); 00245 00246 // Helper functions 00247 00248 //! Effort level for processFactQueue 00249 /*! LOW means just process facts, don't call theory checkSat methods 00250 NORMAL means call theory checkSat methods without full effort 00251 FULL means call theory checkSat methods with full effort 00252 */ 00253 typedef enum { 00254 LOW, 00255 NORMAL, 00256 FULL 00257 } EffortLevel; 00258 00259 //! A helper function for addFact() 00260 /*! Returns true if lemmas were added to search engine, false otherwise */ 00261 bool processFactQueue(EffortLevel effort = NORMAL); 00262 //! Process a notify list triggered as a result of new theorem e 00263 void processNotify(const Theorem& e, NotifyList* L); 00264 //! Transitive composition of other rewrites with the above 00265 Theorem rewriteCore(const Theorem& e); 00266 //! Helper for registerAtom 00267 void setupSubFormulas(const Expr& s, const Expr& e, const Theorem& thm); 00268 //! Process updates recorded by calls to update() 00269 void processUpdates(); 00270 /*! @brief The assumptions for e must be in H or phi. "Core" added 00271 * to avoid conflict with theory interface function name 00272 */ 00273 void assertFactCore(const Theorem& e); 00274 //! Process a newly derived formula 00275 void assertFormula(const Theorem& e); 00276 //! Check that lhs and rhs of thm have same base type 00277 IF_DEBUG(void checkRewriteType(const Theorem& thm);) 00278 /*! @brief Returns phi |= e = rewriteCore(e). "Core" added to avoid 00279 conflict with theory interface function name */ 00280 Theorem rewriteCore(const Expr& e); 00281 00282 //! Set the find pointer of an atomic formula and notify SearchEngine 00283 /*! \param thm is a Theorem(phi) or Theorem(NOT phi), where phi is 00284 * an atomic formula to get a find pointer to TRUE or FALSE, 00285 * respectively. 00286 */ 00287 void setFindLiteral(const Theorem& thm); 00288 //! Core rewrites for literals (NOT and EQ) 00289 Theorem rewriteLitCore(const Expr& e); 00290 //! Enqueue a fact to be sent to the SearchEngine 00291 // void enqueueSE(const Theorem& thm);//yeting 00292 //! Fetch the concrete assignment to the variable during model generation 00293 Theorem getModelValue(const Expr& e); 00294 00295 //! An auxiliary recursive function to process COND expressions into ITE 00296 Expr processCond(const Expr& e, int i); 00297 00298 //! Return true if no special parsing is required for this kind 00299 bool isBasicKind(int kind); 00300 00301 //! Helper check functions for solve 00302 void checkEquation(const Theorem& thm); 00303 //! Helper check functions for solve 00304 void checkSolved(const Theorem& thm); 00305 00306 // Time limit exhausted 00307 bool timeLimitReached(); 00308 00309 //! Print an expression in the shared subset of SMT-LIB v1/v2 00310 //! Should only be called if os.lang() is SMTLIB_LANG or SMTLIB_V2_LANG. 00311 ExprStream& printSmtLibShared(ExprStream& os, const Expr& e); 00312 00313 00314 public: 00315 //! Constructor 00316 TheoryCore(ContextManager* cm, ExprManager* em, 00317 TheoremManager* tm, Translator* tr, 00318 const CLFlags& flags, 00319 Statistics& statistics); 00320 //! Destructor 00321 ~TheoryCore(); 00322 00323 //! Request a unit of resource 00324 /*! It will be subtracted from the resource limit. 00325 * 00326 * \return true if resource unit is granted, false if no more 00327 * resources available. 00328 */ 00329 void getResource() { 00330 getStatistics().counter("resource")++; 00331 if (d_resourceLimit > 1) d_resourceLimit--; 00332 } 00333 00334 //! Register a SatAPI for TheoryCore 00335 void registerCoreSatAPI(CoreSatAPI* coreSatAPI) { d_coreSatAPI = coreSatAPI; } 00336 00337 //! Register a callback for every equality 00338 void addNotifyEq(Theory* t, const Expr& e) { d_notifyEq.add(t, e); } 00339 00340 //! Call theory-specific preprocess routines 00341 Theorem callTheoryPreprocess(const Expr& e); 00342 00343 ContextManager* getCM() const { return d_cm; } 00344 TheoremManager* getTM() const { return d_tm; } 00345 const CLFlags& getFlags() const { return d_flags; } 00346 Statistics& getStatistics() const { return d_statistics; } 00347 ExprTransform* getExprTrans() const { return d_exprTrans; } 00348 CoreProofRules* getCoreRules() const { return d_rules; } 00349 Translator* getTranslator() const { return d_translator; } 00350 00351 //! Access to tcc cache (needed by theory_bitvector) 00352 ExprMap<Expr>& tccCache() { return d_tccCache; } 00353 00354 //! Get list of terms 00355 const CDList<Expr>& getTerms() { return d_terms; } 00356 00357 int getCurQuantLevel(); 00358 00359 //! Set the flag for the preprocessor 00360 void setInPP() { d_inPP = true; } 00361 void clearInPP() { d_inPP = false; } 00362 00363 //! Get theorem which was responsible for introducing this term 00364 Theorem getTheoremForTerm(const Expr& e); 00365 //! Get quantification level at which this term was introduced 00366 unsigned getQuantLevelForTerm(const Expr& e); 00367 //! Get list of predicates 00368 const CDList<Expr>& getPredicates() { return d_predicates; } 00369 //! Whether updates are being processed 00370 bool inUpdate() { return d_inUpdate > 0; } 00371 //! Whether its OK to add new facts (for use in rewrites) 00372 bool okToEnqueue() 00373 { return d_inAddFact || d_inCheckSATCore || d_inRegisterAtom || d_inPP; } 00374 00375 // Implementation of Theory API 00376 /*! Variables of uninterpreted types may be sent here, and they 00377 should be ignored. */ 00378 void addSharedTerm(const Expr& e) { } 00379 void assertFact(const Theorem& e); 00380 void checkSat(bool fullEffort) { } 00381 Theorem rewrite(const Expr& e); 00382 /*! Only Boolean constants (TRUE and FALSE) and variables of 00383 uninterpreted types should appear here (they come from records and 00384 tuples). Just ignore them. */ 00385 void setup(const Expr& e) { } 00386 void update(const Theorem& e, const Expr& d); 00387 Theorem solve(const Theorem& e); 00388 00389 Theorem simplifyOp(const Expr& e); 00390 void checkType(const Expr& e); 00391 Cardinality finiteTypeInfo(Expr& e, Unsigned& n, 00392 bool enumerate, bool computeSize); 00393 void computeType(const Expr& e); 00394 Type computeBaseType(const Type& t); 00395 Expr computeTCC(const Expr& e); 00396 Expr computeTypePred(const Type& t,const Expr& e); 00397 Expr parseExprOp(const Expr& e); 00398 ExprStream& print(ExprStream& os, const Expr& e); 00399 00400 //! Calls for other theories to add facts to refine a coutnerexample. 00401 void refineCounterExample(); 00402 bool refineCounterExample(Theorem& thm); 00403 void computeModelBasic(const std::vector<Expr>& v); 00404 00405 // User-level API methods 00406 00407 /*! @brief Add a new assertion to the core from the user or a SAT 00408 solver. Do NOT use it in a decision procedure; use 00409 enqueueFact(). */ 00410 /*! \sa enqueueFact */ 00411 void addFact(const Theorem& e); 00412 00413 //! Top-level simplifier 00414 Theorem simplify(const Expr& e); 00415 00416 //! Check if the current context is inconsistent 00417 bool inconsistent() { return d_inconsistent ; } 00418 //! Get the proof of inconsistency for the current context 00419 /*! \return Theorem(FALSE) */ 00420 Theorem inconsistentThm() { return d_incThm; } 00421 /*! @brief To be called by SearchEngine when it believes the context 00422 * is satisfiable. 00423 * 00424 * \return true if definitely consistent or inconsistent and false if 00425 * consistency is unknown. 00426 */ 00427 bool checkSATCore(); 00428 00429 //! Check if the current decision branch is marked as incomplete 00430 bool incomplete() { return d_incomplete.size() > 0 ; } 00431 //! Check if the branch is incomplete, and return the reasons (strings) 00432 bool incomplete(std::vector<std::string>& reasons); 00433 00434 //! Register an atomic formula of interest. 00435 /*! If e or its negation is later deduced, we will add the implied 00436 literal to d_impliedLiterals */ 00437 void registerAtom(const Expr& e, const Theorem& thm); 00438 00439 //! Return the next implied literal (NULL Theorem if none) 00440 Theorem getImpliedLiteral(void); 00441 00442 //! Return total number of implied literals 00443 unsigned numImpliedLiterals() { return d_impliedLiterals.size(); } 00444 00445 //! Return an implied literal by index 00446 Theorem getImpliedLiteralByIndex(unsigned index); 00447 00448 //! Parse the generic expression. 00449 /*! This method should be used in parseExprOp() for recursive calls 00450 * to subexpressions, and is the method called by the command 00451 * processor. 00452 */ 00453 Expr parseExpr(const Expr& e); 00454 //! Top-level call to parseExpr, clears the bound variable stack. 00455 /*! Use it in VCL instead of parseExpr(). */ 00456 Expr parseExprTop(const Expr& e) { 00457 d_boundVarStack.clear(); 00458 d_parseCache = &d_parseCacheTop; 00459 return parseExpr(e); 00460 } 00461 00462 //! Assign t a concrete value val. Used in model generation. 00463 void assignValue(const Expr& t, const Expr& val); 00464 //! Record a derived assignment to a variable (LHS). 00465 void assignValue(const Theorem& thm); 00466 00467 //! Adds expression to var database 00468 void addToVarDB(const Expr & e); 00469 //! Split compound vars into basic type variables 00470 /*! The results are saved in d_basicModelVars and 00471 * d_simplifiedModelVars. Also, add new basic vars as shared terms 00472 * whenever their type belongs to a different theory than the term 00473 * itself. 00474 */ 00475 void collectBasicVars(); 00476 //! Calls theory specific computeModel, results are placed in map 00477 void buildModel(ExprMap<Expr>& m); 00478 bool buildModel(Theorem& thm); 00479 //! Recursively build a compound-type variable assignment for e 00480 void collectModelValues(const Expr& e, ExprMap<Expr>& m); 00481 00482 //! Set the resource limit (0==unlimited). 00483 void setResourceLimit(unsigned limit) { d_resourceLimit = limit; } 00484 //! Get the resource limit 00485 unsigned getResourceLimit() { return d_resourceLimit; } 00486 //! Return true if resources are exhausted 00487 bool outOfResources() { return d_resourceLimit == 1; } 00488 00489 //! Initialize base time used for !setTimeLimit 00490 void initTimeLimit(); 00491 00492 //! Set the time limit in seconds (0==unlimited). 00493 void setTimeLimit(unsigned limit); 00494 00495 //! Called by search engine 00496 Theorem rewriteLiteral(const Expr& e); 00497 00498 private: 00499 // Methods provided for benefit of theories. Access is made available through theory.h 00500 00501 //! Assert a system of equations (1 or more). 00502 /*! e is either a single equation, or a conjunction of equations 00503 */ 00504 void assertEqualities(const Theorem& e); 00505 00506 //! Mark the branch as incomplete 00507 void setIncomplete(const std::string& reason); 00508 00509 //! Return a theorem for the type predicate of e 00510 /*! Note: used only by theory_arith */ 00511 Theorem typePred(const Expr& e); 00512 00513 public: 00514 // TODO: These should be private 00515 //! Enqueue a new fact 00516 /*! not private because used in search_fast.cpp */ 00517 void enqueueFact(const Theorem& e); 00518 void enqueueSE(const Theorem& thm);//yeting 00519 // Must provide proof of inconsistency 00520 /*! not private because used in search_fast.cpp */ 00521 void setInconsistent(const Theorem& e); 00522 00523 //! Setup additional terms within a theory-specific setup(). 00524 /*! not private because used in theory_bitvector.cpp */ 00525 void setupTerm(const Expr& e, Theory* i, const Theorem& thm); 00526 00527 00528 }; 00529 00530 //! Printing NotifyList class 00531 std::ostream& operator<<(std::ostream& os, const NotifyList& l); 00532 00533 } 00534 00535 #endif