theory.h

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file theory.h
00004  * \brief Generic API for Theories plus methods commonly used by theories
00005  * 
00006  * Author: Clark Barrett
00007  * 
00008  * Created: Sat Nov 30 23:30:15 2002
00009  *
00010  * <hr>
00011  * Copyright (C) 2003 by the Board of Trustees of Leland Stanford
00012  * Junior University and by New York University. 
00013  *
00014  * License to use, copy, modify, sell and/or distribute this software
00015  * and its documentation for any purpose is hereby granted without
00016  * royalty, subject to the terms and conditions defined in the \ref
00017  * LICENSE file provided with this distribution.  In particular:
00018  *
00019  * - The above copyright notice and this permission notice must appear
00020  * in all copies of the software and related documentation.
00021  *
00022  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00023  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00024  * 
00025  * <hr>
00026  * 
00027  */
00028 /*****************************************************************************/
00029 
00030 #ifndef _cvcl__include__theory_h_
00031 #define _cvcl__include__theory_h_
00032 
00033 #include "expr_stream.h"
00034 #include "common_proof_rules.h"
00035 #include "cdlist.h"
00036 
00037 namespace CVCL {
00038 
00039 class TheoryCore;
00040 class Theorem;
00041 class Type;
00042 
00043 /************************************************************************/
00044 /*!
00045  *\defgroup Theories Theories
00046  *\ingroup VC
00047  *\brief Theories
00048  *@{
00049  */
00050 /***********************************************************************/
00051 
00052 /*****************************************************************************/
00053 /*!
00054  *\anchor Theory
00055  *\class Theory
00056  *\brief Base class for theories
00057  *
00058  * Author: Clark Barrett
00059  *
00060  * Created: Thu Jan 30 16:37:56 2003
00061  *
00062  * This is an abstract class which all theories should inherit from.  In
00063  * addition to providing an abstract theory interface, it provides access
00064  * functions to core functionality.  However, in order to avoid duplicating the
00065  * data structures which implement this functionality, all the functionality is
00066  * stored in a separate class (which actually derives from this one) called
00067  * TheoryCore.  These two classes work closely together to provide the core
00068  * functionality.
00069  */
00070 /*****************************************************************************/
00071 
00072 class Theory {
00073   friend class TheoryCore;
00074 private:
00075   ExprManager* d_em;
00076   TheoryCore* d_theoryCore; //!< Provides the core functionality
00077   CommonProofRules* d_commonRules; //!< Commonly used proof rules
00078   std::string d_name; //!< Name of the theory (for debugging)
00079 
00080   //! Private default constructor.
00081   /*! Everyone besides TheoryCore has to use the public constructor
00082     which sets up all the provided functionality automatically.
00083   */
00084   Theory(void);
00085 
00086 protected:
00087   bool d_theoryUsed; //! Whether theory has been used (for smtlib translator)
00088 
00089 public:
00090   //! Exposed constructor.
00091   /*! Note that each instance of Theory must have a name (mostly for
00092     debugging purposes). */
00093   Theory(TheoryCore* theoryCore, const std::string& name);
00094   //! Destructor
00095   virtual ~Theory(void);
00096 
00097   //! Access to ExprManager
00098   ExprManager* getEM() { return d_em; }
00099 
00100   //! Get a pointer to theoryCore
00101   TheoryCore* theoryCore() { return d_theoryCore; }
00102 
00103   //! Get a pointer to common proof rules
00104   CommonProofRules* getCommonRules() { return d_commonRules; }
00105 
00106   //! Get the name of the theory (for debugging purposes)
00107   const std::string& getName() const { return d_name; }
00108 
00109   //! Get whether theory has been used (for smtlib translator)
00110   virtual bool theoryUsed() { return d_theoryUsed; }
00111 
00112   /***************************************************************************/
00113   /*!
00114    *\defgroup Theory_API Abstract Theory Interface
00115    *\anchor theory_api
00116    *\ingroup Theories
00117    *\brief Abstract Theory Interface
00118    *
00119    * These are the theory-specific methods which provide the decision procedure
00120    * functionality for a new theory.  At the very least, a theory must
00121    * implement the checkSat method.  The other methods can be used to make the
00122    * implementation more convenient.  For more information on this API, see
00123    * Clark Barrett's PhD dissertation and \ref theory_api_howto.
00124    *@{
00125    */
00126   /***************************************************************************/
00127 
00128   //! Notify theory of a new shared term
00129   /*! When a term e associated with theory i occurs as a child of an expression
00130     associated with theory j, the framework calls i->addSharedTerm(e) and
00131     j->addSharedTerm(e)
00132   */
00133   virtual void addSharedTerm(const Expr& e) {}
00134 
00135   //! Assert a new fact to the decision procedure
00136   /*! Each fact that makes it into the core framework is assigned to exactly
00137     one theory: the theory associated with that fact.  assertFact is called to
00138     inform the theory that a new fact has been assigned to the theory.
00139   */
00140   virtual void assertFact(const Theorem& e) = 0;
00141 
00142   //! Check for satisfiability in the theory
00143   /*! \param fullEffort when it is false, checkSat can do as much or
00144    as little work as it likes, though simple inferences and checks for
00145    consistency should be done to increase efficiency.  If fullEffort is true,
00146    checkSat must check whether the set of facts given by assertFact together
00147    with the arrangement of shared terms (provided by addSharedTerm) induced by
00148    the global find database equivalence relation are satisfiable.  If
00149    satisfiable, checkSat does nothing.
00150 
00151    If satisfiability can be acheived by merging some of the shared terms, a new
00152    fact must be enqueued using enqueueFact (this fact need not be a literal).
00153    If there is no way to make things satisfiable, setInconsistent must be called.
00154   */
00155   virtual void checkSat(bool fullEffort) = 0;
00156 
00157   //! Theory-specific rewrite rules.  
00158   /*! By default, rewrite just returns a reflexive theorem stating that the
00159     input expression is equivalent to itself.  However, rewrite is allowed to
00160     return any theorem which describes how the input expression is equivalent
00161     to some new expression.  rewrite should be used to perform simplifications,
00162     normalization, and any other preprocessing on theory-specific expressions
00163     that needs to be done.
00164   */
00165   virtual Theorem rewrite(const Expr& e) { return reflexivityRule(e); }
00166 
00167   //! Set up the term e for call-backs when e or its children change.
00168   /*! setup is called once for each expression associated with the theory.  It
00169     is typically used to setup theory-specific data for an expression and to
00170     add call-back information for use with update.
00171     \sa update
00172   */
00173   virtual void setup(const Expr& e) {}
00174 
00175   //! Notify a theory of a new equality
00176   /*! update is a call-back used by the notify mechanism of the core theory.
00177     It works as follows.  When an equation t1 = t2 makes it into the core
00178     framework, the two find equivalence classes for t1 and t2 are merged.  The
00179     result is that t2 is the new equivalence class representative and t1 is no
00180     longer an equivalence class representative.  When this happens, the notify
00181     list of t1 is traversed.  Notify list entries consist of a theory and an
00182     expression d.  For each entry (i,d), i->update(e, d) is called, where e is
00183     the theorem corresponding to the equality t1=t2.
00184 
00185     To add the entry (i,d) to a term t1's notify list, a call must be made to
00186     t1.addNotify(i,d).  This is typically done in setup.
00187 
00188     \sa setup
00189   */
00190   virtual void update(const Theorem& e, const Expr& d) {}
00191 
00192   //! An optional solver.
00193   /*! The solve method can be used to implement a Shostak-style solver.  Since
00194     solvers do not in general combine, the following technique is used.  One
00195     theory is designated as the primary solver (in our case, it is the theory
00196     of arithmetic).  For each equation that enters the core framework, the
00197     primary solver is called to ensure that the equation is in solved form with
00198     respect to the primary theory.
00199 
00200     After the primary solver, the solver for the theory associated with the
00201     equation is called.  This solver can do whatever it likes, as long as the
00202     result is still in solved form with respect to the primary solver.  This is
00203     a slight generalization of what is described in my (Clark)'s PhD thesis.
00204   */
00205   virtual Theorem solve(const Theorem& e) { return e; }
00206 
00207   /////////////////////////////////
00208   // Extensions to original API: //
00209   /////////////////////////////////
00210 
00211   //! Recursive simplification step
00212   /*!
00213    * INVARIANT: the result is a Theorem(e=e'), where e' is a fully
00214    * simplified version of e.  To simplify subexpressions recursively,
00215    * call simplify() function.
00216    *
00217    * This theory-specific method is called when the simplifier
00218    * descends top-down into the expression.  Normally, every kid is
00219    * simplified recursively, and the results are combined into the new
00220    * parent with the same operator (Op).  This functionality is
00221    * provided with the default implementation.
00222    *
00223    * However, in some expressions some kids may not matter in the
00224    * result, and can be skipped.  For instance, if the first kid in a
00225    * long AND simplifies to FALSE, then the entire expression
00226    * simplifies to FALSE, and the remaining kids do not need to be
00227    * simplified.
00228    *
00229    * This call is a chance for a DP to provide these types of
00230    * optimizations during the top-down phase of simplification.
00231    */
00232   virtual Theorem simplifyOp(const Expr& e);
00233 
00234   //! Check that e is a valid Type expr
00235   virtual void checkType(const Expr& e)
00236     { throw Exception("Cannot construct type from expr: "+e.toString()); }
00237 
00238   //! Compute and store the type of e
00239   /*!
00240    * \param e is the expression whose type is computed.  
00241    *
00242    * This function computes the type of the top-level operator of e,
00243    * and recurses into children using getType(), if necessary.
00244    */
00245   virtual void computeType(const Expr& e) {}
00246   //! Compute the base type of the top-level operator of an arbitrary type
00247   virtual Type computeBaseType(const Type& tp) { return tp; }
00248   /*! @brief  Theory specific computation of the subtyping predicate for 
00249    *  type t applied to the expression e.
00250    */ 
00251   /*! By default returns true. Each theory needs to compute subtype predicates
00252    *  for the types associated with it. So, for example, the theory of records
00253    *  will take a record type [# f1: T1, f2: T2 #] and an expression e
00254    *  and will return the subtyping predicate for e, namely:
00255    *  computeTypePred(T1, e.f1) AND computeTypePred(T2, e.f2)
00256    */ 
00257   virtual Expr computeTypePred(const Type& t, const Expr& e) 
00258     { return e.getEM()->trueExpr(); }
00259   //! Compute and cache the TCC of e.
00260   /*! 
00261    * \param e is an expression (term or formula).  This function
00262    * computes the TCC of e which is true iff the expression is defined.
00263    *
00264    * This function computes the TCC or predicate of the top-level
00265    * operator of e, and recurses into children using getTCC(), if
00266    * necessary.
00267    *
00268    * The default implementation is to compute TCCs recursively for all
00269    * children, and return their conjunction.
00270    */
00271   virtual Expr computeTCC(const Expr& e);
00272 
00273   //! Theory-specific parsing implemented by the DP
00274   virtual Expr parseExprOp(const Expr& e) { return e; }
00275 
00276   //! Theory-specific pretty-printing.
00277   /*! By default, print the top node in AST, and resume
00278     pretty-printing the children.  The same call e.print(os) can be
00279     used in DP-specific printers to use AST printing for the given
00280     node.  In fact, it is strongly recommended to add e.print(os) as
00281     the default for all the cases/kinds that are not handled by the
00282     particular pretty-printer.
00283   */
00284   virtual ExprStream& print(ExprStream& os, const Expr& e) {
00285     return e.printAST(os);
00286   }
00287 
00288   //! Add variables from 'e' to 'v' for constructing a concrete model
00289   /*! If e is already of primitive type, do NOT add it to v. */
00290   virtual void computeModelTerm(const Expr& e, std::vector<Expr>& v);
00291   //! Process disequalities from the arrangement for model generation
00292   virtual void refineCounterExample() {}
00293   //! Assign concrete values to basic-type variables in v
00294   virtual void computeModelBasic(const std::vector<Expr>& v) {}
00295   //! Compute the value of a compound variable from the more primitive ones
00296   /*! The more primitive variables for e are already assigned concrete
00297    * values, and are available through getModelValue().
00298    *
00299    * The new value for e must be assigned using assignValue() method.
00300    *
00301    * \param e is the compound type expression to assign a value;
00302    *
00303    * \param vars are the variables actually assigned.  Normally, 'e'
00304    * is the only element of vars.  However, e.g. in the case of
00305    * uninterpreted functions, assigning 'f' means assigning all
00306    * relevant applications of 'f' to constant values (f(0), f(5),
00307    * etc.).  Such applications might not be known before the model is
00308    * constructed (they may be of the form f(x), f(y+z), etc., where
00309    * x,y,z are still unassigned).
00310    *
00311    * Populating 'vars' is an opportunity for a DP to change the set of
00312    * top-level "variables" to assign, if needed.  In particular, it
00313    * may drop 'e' from the model entirely, if it is already a concrete
00314    * value by itself.
00315    */
00316   virtual void computeModel(const Expr& e, std::vector<Expr>& vars) {
00317     assignValue(find(e));
00318     vars.push_back(e);
00319   }
00320 
00321   //! Receives all the type predicates for the types of the given theory
00322   /*! Type predicates may be expensive to enqueue eagerly, and DPs may
00323     choose to postpone them, or transform them to something more
00324     efficient.  By default, the asserted type predicate is
00325     immediately enqueued as a new fact.
00326 
00327     Note: Used only by bitvector theory.
00328 
00329     \param e is the expression for which the type predicate is computed
00330     \param pred is the predicate theorem P(e)
00331   */
00332   virtual void assertTypePred(const Expr& e, const Theorem& pred)
00333     { enqueueFact(pred); }
00334 
00335   //! Theory-specific rewrites for atomic formulas
00336   /*! The intended use is to convert complex atomic formulas into an
00337    * equivalent Boolean combination of simpler formulas.  Such
00338    * conversion may be harmful for algebraic rewrites, and is not
00339    * always desirable to have in rewrite() method.
00340    *
00341    * Note: Used only by bitvector theory and rewriteLiteral in core.
00342    *
00343    * However, if rewrite() alone cannot solve the problem, and the SAT
00344    * solver needs to be envoked, these additional rewrites may ease
00345    * the job for the SAT solver.
00346    */
00347   virtual Theorem rewriteAtomic(const Expr& e) { return reflexivityRule(e); }
00348 
00349   //! Notification of conflict
00350   /*!
00351    * Decision procedures implement this method when they want to be
00352    * notified about a conflict.
00353    *
00354    * Note: Used only by quantifier theory
00355    *
00356    * \param thm is the theorem of FALSE given to setInconsistent()
00357    */
00358   virtual void notifyInconsistent(const Theorem& thm) { }
00359 
00360   /*@}*/ // End of Theory_API group
00361 
00362   /***************************************************************************/
00363   /*!
00364    *\name Core Framework Functionality
00365    * These methods provide convenient access to core functionality for the
00366    * benefit of decision procedures.
00367    *@{
00368    */
00369   /***************************************************************************/
00370 
00371   //! Check if the current context is inconsistent
00372   virtual bool inconsistent();
00373   //! Make the context inconsistent; The formula proved by e must FALSE.
00374   virtual void setInconsistent(const Theorem& e);
00375 
00376   //! Mark the current decision branch as possibly incomplete
00377   /*!
00378    * This should be set when a decision procedure uses an incomplete
00379    * algorithm, and cannot guarantee satisfiability after the final
00380    * checkSat() call with full effort.  An example would be
00381    * instantiation of universal quantifiers.
00382    *
00383    * A decision procedure can provide a reason for incompleteness,
00384    * which will be reported back to the user.
00385    */
00386   virtual void setIncomplete(const std::string& reason);
00387 
00388   //! Simplify a term e and return a Theorem(e==e')
00389   /*! \sa simplifyExpr() */
00390   virtual Theorem simplify(const Expr& e, bool forceRebuild = true);
00391   //! Simplify a term e w.r.t. the current context
00392   /*! \sa simplify */
00393   Expr simplifyExpr(const Expr& e, bool forceRebuild = true)
00394     { return simplify(e, forceRebuild).getRHS(); }
00395   //! Recursive call of the simplifier.  Should only be called from simplifyOp().
00396   virtual Theorem simplifyRec(const Expr& e);
00397 
00398   //! Submit a derived fact to the core from a decision procedure
00399   /*! \param e is the Theorem for the new fact 
00400    */
00401   virtual void enqueueFact(const Theorem& e);
00402   //! Enqueue a new equality e: e1==e2, where e2 is i-leaf simplified
00403   virtual void enqueueEquality(const Theorem& e);
00404 
00405   //! Handle new equalities (usually asserted through addFact)
00406   /*!
00407    * INVARIANT: the Theorem 'e' is an equality e1==e2, where e2 is
00408    * i-leaf simplified in the current context, or a conjunction of
00409    * such equalities.
00410    *
00411    * IMPORTANT: decision procedures should NOT use this function in
00412    * update(); use enqueueEquality() instead.
00413    */
00414   virtual void assertEqualities(const Theorem& e);
00415 
00416   //! Parse the generic expression.
00417   /*! This method should be used in parseExprOp() for recursive calls
00418    *  to subexpressions, and is the method called by the command
00419    *  processor.
00420    */
00421   virtual Expr parseExpr(const Expr& e);
00422 
00423   //! Assigns t a concrete value val.  Used in model generation.
00424   virtual void assignValue(const Expr& t, const Expr& val);
00425   //! Record a derived assignment to a variable (LHS).
00426   virtual void assignValue(const Theorem& thm);
00427 
00428   /*@}*/ // End of Core Framework Functionality
00429 
00430   /***************************************************************************/
00431   /*!
00432    *\name Theory Helper Methods
00433    * These methods provide basic functionality needed by all theories.
00434    *@{
00435    */
00436   /***************************************************************************/
00437 
00438   //! Register new kinds with the given theory
00439   void registerKinds(Theory* theory, std::vector<int>& kinds);
00440   //! Register a new theory
00441   void registerTheory(Theory* theory, std::vector<int>& kinds,
00442                       bool hasSolver=false);
00443 
00444   //! Return the number of registered theories
00445   int getNumTheories();
00446 
00447   //! Test whether a kind maps to any theory
00448   bool hasTheory(int kind);
00449   //! Return the theory associated with a kind
00450   Theory* theoryOf(int kind);
00451   //! Return the theory associated with an Expr
00452   Theory* theoryOf(const Expr& e);
00453 
00454   //! Return the theorem that e is equal to its find
00455   Theorem find(const Expr& e);
00456   //! Return the find of e, or e if it has no find
00457   inline const Expr& findExpr(const Expr& e)
00458     { return e.hasFind() ? find(e).getRHS() : e; }
00459 
00460   //! Compute the TCC of e, or the subtyping predicate, if e is a type
00461   Expr getTCC(const Expr& e);
00462   //! Compute (or look up in cache) the base type of e and return the result
00463   Type getBaseType(const Expr& e);
00464   //! Compute the base type from an arbitrary type
00465   Type getBaseType(const Type& tp);
00466   //! Calls the correct theory to compute a type predicate
00467   Expr getTypePred(const Type& t, const Expr& e);
00468 
00469   //! Update the children of the term e
00470   /*! When a decision procedure receives a call to update() because a
00471     child of a term 'e' has changed, this method can be called to
00472     compute the new value of 'e'.
00473     \sa update
00474   */
00475   Theorem updateHelper(const Expr& e);
00476   //! Setup a term for congruence closure (must have sig and rep attributes)
00477   void setupCC(const Expr& e);
00478   //! Update a term w.r.t. congruence closure (must be setup with setupCC())
00479   void updateCC(const Theorem& e, const Expr& d);
00480   //! Rewrite a term w.r.t. congruence closure (must be setup with setupCC())
00481   Theorem rewriteCC(const Expr& e);
00482 
00483   /*! @brief Calls the correct theory to get all of the terms that
00484     need to be assigned values in the concrete model */
00485   void getModelTerm(const Expr& e, std::vector<Expr>& v);
00486   //! Fetch the concrete assignment to the variable during model generation
00487   Theorem getModelValue(const Expr& e);
00488 
00489   //! Suggest a splitter to the SearchEngine
00490   void addSplitter(const Expr& e, int priority = 0);
00491 
00492   /*@}*/ // End of Theory Helper Methods
00493 
00494   /***************************************************************************/
00495   /*!
00496    *\name Core Testers
00497    *@{
00498    */
00499   /***************************************************************************/
00500 
00501   //! Test if e is an i-leaf term for the current theory
00502   /*! A term 'e' is an i-leaf for a theory 'i', if it is a variable,
00503     or 'e' belongs to a different theory.  This definition makes sense
00504     for a larger term which by itself belongs to the current theory
00505     'i', but (some of) its children are variables or belong to
00506     different theories. */
00507   bool isLeaf(const Expr& e) { return e.isVar() || theoryOf(e) != this; }
00508 
00509   //! Test if e1 is an i-leaf in e2
00510   /*! \sa isLeaf */
00511   bool isLeafIn(const Expr& e1, const Expr& e2);
00512 
00513   //! Test if all i-leaves of e are simplified
00514   /*! \sa isLeaf */
00515   bool leavesAreSimp(const Expr& e);
00516 
00517   /*@}*/ // End of Core Testers
00518 
00519   /***************************************************************************/
00520   /*!
00521    *\name Common Type and Expr Methods
00522    *@{
00523    */
00524   /***************************************************************************/
00525 
00526   //! Return BOOLEAN type
00527   Type boolType() { return Type::typeBool(d_em); }
00528 
00529   //! Return FALSE Expr
00530   const Expr& falseExpr() { return d_em->falseExpr(); }
00531 
00532   //! Return TRUE Expr
00533   const Expr& trueExpr() { return d_em->trueExpr(); }
00534 
00535   //! Create a new variable given its name and type
00536   /*! Add the variable to the database for resolving IDs in parseExpr
00537    */
00538   Expr newVar(const std::string& name, const Type& type);
00539   //! Create a new named expression given its name, type, and definition
00540   /*! Add the definition to the database for resolving IDs in parseExpr
00541    */
00542   Expr newVar(const std::string& name, const Type& type, const Expr& def);
00543 
00544   //! Create a new uninterpreted function
00545   /*! Add the definition to the database for resolving IDs in parseExpr
00546    */
00547   Op newFunction(const std::string& name, const Type& type,
00548                  bool computeTransClosure);
00549   //! Create a new defined function
00550   /*! Add the definition to the database for resolving IDs in parseExpr
00551    */
00552   Op newFunction(const std::string& name, const Type& type, const Expr& def);
00553 
00554   //! Create and add a new bound variable to the stack, for parseExprOp().
00555   /*!
00556    * The stack is popped automatically upon return from the
00557    * parseExprOp() which used this method.
00558    *
00559    * Bound variable names may repeat, in which case the latest
00560    * declaration takes precedence.
00561    */
00562   Expr addBoundVar(const std::string& name, const Type& type);
00563   //! Create and add a new bound named def to the stack, for parseExprOp().
00564   /*!
00565    * The stack is popped automatically upon return from the
00566    * parseExprOp() which used this method.
00567    *
00568    * Bound variable names may repeat, in which case the latest
00569    * declaration takes precedence.
00570    *
00571    * The type may be Null, but 'def' must always be a valid Expr
00572    */
00573   Expr addBoundVar(const std::string& name, const Type& type, const Expr& def);
00574 
00575   /*! @brief Lookup variable and return it and its type.  Return NULL Expr if
00576     it doesn't exist yet. */
00577   Expr lookupVar(const std::string& name, Type* type);
00578 
00579   //! Create a new uninterpreted type with the given name
00580   /*! Add the name to the global variable database d_globals
00581    */
00582   Type newTypeExpr(const std::string& name);
00583   //! Create a new type abbreviation with the given name 
00584   Type newTypeExpr(const std::string& name, const Type& def);
00585 
00586   //! Resolve an identifier, for use in parseExprOp()
00587   /*!
00588    * First, search the bound variable stack, and if the name is not
00589    * found, search the global constant and type declarations.  
00590    *
00591    * \return an expression to use in place of the identifier, or Null
00592    * if cannot resolve the name.
00593    */
00594   Expr resolveID(const std::string& name);
00595 
00596   //! Install name as a new identifier associated with Expr e
00597   void installID(const std::string& name, const Expr& e);
00598 
00599   Theorem typePred(const Expr& e);
00600 
00601   //! e: T ==> |- [all the subtype-related facts for e and its subterms]
00602   Theorem subtypePredicate(const Expr& e);
00603 
00604   /*@}*/ // End of Common Type and Expr Methods
00605 
00606   /***************************************************************************/
00607   /*!
00608    *\name Commonly Used Proof Rules
00609    *\anchor theory_api_core_proof_rules
00610    *@{
00611    */
00612   /***************************************************************************/
00613 
00614   //!  ==> a == a
00615   Theorem reflexivityRule(const Expr& a)
00616     { return d_commonRules->reflexivityRule(a); }
00617 
00618   //!  a1 == a2 ==> a2 == a1
00619   Theorem symmetryRule(const Theorem& a1_eq_a2)
00620     { return d_commonRules->symmetryRule(a1_eq_a2); }
00621 
00622   //! (a1 == a2) & (a2 == a3) ==> (a1 == a3)
00623   Theorem transitivityRule(const Theorem& a1_eq_a2,
00624                            const Theorem& a2_eq_a3)
00625     { return d_commonRules->transitivityRule(a1_eq_a2, a2_eq_a3); }
00626 
00627   //! (c_1 == d_1) & ... & (c_n == d_n) ==> op(c_1,...,c_n) == op(d_1,...,d_n)
00628   Theorem substitutivityRule(const Op& op,
00629                              const std::vector<Theorem>& thms)
00630     { return d_commonRules->substitutivityRule(op, thms); }
00631 
00632   //! Optimized: only positions which changed are included
00633   Theorem substitutivityRule(const Expr& e,
00634                              const std::vector<unsigned>& changed,
00635                              const std::vector<Theorem>& thms)
00636     { return d_commonRules->substitutivityRule(e, changed, thms); }
00637 
00638   //! e1 AND (e1 IFF e2) ==> e2
00639   Theorem iffMP(const Theorem& e1, const Theorem& e1_iff_e2) {
00640     return d_commonRules->iffMP(e1, e1_iff_e2);
00641   }
00642 
00643   //! ==> AND(e1,e2) IFF [simplified expr]
00644   Theorem rewriteAnd(const Expr& e) {
00645     return d_commonRules->rewriteAnd(e);
00646   }
00647 
00648   //! ==> OR(e1,...,en) IFF [simplified expr]
00649   Theorem rewriteOr(const Expr& e) {
00650     return d_commonRules->rewriteOr(e);
00651   }
00652   
00653   /*@}*/ // End of Commonly Used Proof Rules
00654 
00655 
00656 };
00657 
00658 /*@}*/ // End of group Theories
00659 
00660 }
00661 
00662 #endif

Generated on Thu Apr 13 16:57:34 2006 for CVC Lite by  doxygen 1.4.4