CVC3

search_impl_base.h

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