CVC3

theory_core.h

Go to the documentation of this file.
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