theory_arith.h

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file theory_arith.h
00004  * 
00005  * Author: Clark Barrett
00006  * 
00007  * Created: Fri Jan 17 18:34:55 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_arith_h_
00030 #define _cvcl__include__theory_arith_h_
00031 
00032 #include "theory.h"
00033 #include "cdmap.h"
00034 
00035 namespace CVCL {
00036 
00037   class VCL;
00038   class ArithProofRules;
00039 
00040   typedef enum {
00041     REAL = 3000,
00042     INT,
00043     SUBRANGE,
00044 
00045     UMINUS,
00046     PLUS,
00047     MINUS,
00048     MULT,
00049     DIVIDE,
00050     POW,
00051     INTDIV,
00052     MOD,
00053     LT,
00054     LE,
00055     GT,
00056     GE,
00057     IS_INTEGER,
00058     NEGINF,
00059     POSINF,
00060     DARK_SHADOW,
00061     GRAY_SHADOW
00062   } ArithKinds;
00063 
00064   //! Used to keep track of which subset of arith is being used
00065   typedef enum {
00066     NOT_USED = 0,
00067     TERMS_ONLY,
00068     DIFF_ONLY,
00069     LINEAR,
00070     NONLINEAR
00071   } ArithLang;
00072 
00073 /*****************************************************************************/
00074 /*!
00075  *\class TheoryArith
00076  *\ingroup Theories
00077  *\brief This theory handles basic linear arithmetic.
00078  *
00079  * Author: Clark Barrett
00080  *
00081  * Created: Sat Feb  8 14:44:32 2003
00082  */
00083 /*****************************************************************************/
00084 class TheoryArith :public Theory {
00085   Type d_realType;
00086   Type d_intType;
00087   CDList<Theorem> d_diseq;  // For concrete model generation
00088   CDO<size_t> d_diseqIdx; // Index to the next unprocessed disequality
00089   ArithProofRules* d_rules;
00090   CDO<bool> d_inModelCreation;
00091   bool d_realUsed;
00092   bool d_intUsed;
00093   bool d_intConstUsed;
00094   ArithLang d_langUsed;
00095   std::string d_convertToDiff;
00096   Expr d_zeroVar;
00097 
00098   //! Data class for the strongest free constant in separation inqualities
00099   class FreeConst {
00100   private:
00101     Rational d_r;
00102     bool d_strict;
00103   public:
00104     FreeConst() { }
00105     FreeConst(const Rational& r, bool strict): d_r(r), d_strict(strict) { }
00106     const Rational& getConst() const { return d_r; }
00107     bool strict() const { return d_strict; }
00108   };
00109   //! Printing
00110   friend std::ostream& operator<<(std::ostream& os, const FreeConst& fc);
00111   //! Private class for an inequality in the Fourier-Motzkin database
00112   class Ineq {
00113   private:
00114     Theorem d_ineq; //!< The inequality
00115     bool d_rhs; //!< Var is isolated on the RHS
00116     const FreeConst* d_const; //!< The max/min const for subsumption check
00117     //! Default constructor is disabled
00118     Ineq() { }
00119   public:
00120     //! Initial constructor.  'r' is taken from the subsumption database.
00121     Ineq(const Theorem& ineq, bool varOnRHS, const FreeConst& c):
00122       d_ineq(ineq), d_rhs(varOnRHS), d_const(&c) { }
00123     //! Get the inequality
00124     const Theorem& ineq() const { return d_ineq; }
00125     //! Get the max/min constant
00126     const FreeConst& getConst() const { return *d_const; }
00127     //! Flag whether var is isolated on the RHS
00128     bool varOnRHS() const { return d_rhs; }
00129     //! Flag whether var is isolated on the LHS
00130     bool varOnLHS() const { return !d_rhs; }
00131     //! Auto-cast to Theorem
00132     operator Theorem() const { return d_ineq; }
00133   };
00134   //! Printing
00135   friend std::ostream& operator<<(std::ostream& os, const Ineq& ineq);
00136   //! Database of inequalities with a variable isolated on the right
00137   ExprMap<CDList<Ineq> *> d_inequalitiesRightDB;
00138   //! Database of inequalities with a variable isolated on the left
00139   ExprMap<CDList<Ineq> *> d_inequalitiesLeftDB;
00140   //! Mapping of inequalities to the largest/smallest free constant
00141   /*! The Expr is the original inequality with the free constant
00142    * removed and inequality converted to non-strict (for indexing
00143    * purposes).  I.e. ax<c+t becomes ax<=t.  This inequality is mapped
00144    * to a pair<c,strict>, the smallest (largest for c+t<ax) constant
00145    * among inequalities with the same 'a', 'x', and 't', and a boolean
00146    * flag indicating whether the strongest inequality is strict.
00147    */
00148   CDMap<Expr, FreeConst> d_freeConstDB;
00149   // Input buffer to store the incoming inequalities
00150   CDList<Theorem> d_buffer; //!< Buffer of input inequalities
00151   CDO<size_t> d_bufferIdx; //!< Buffer index of the next unprocessed inequality
00152   const int* d_bufferThres; //!< Threshold when the buffer must be processed
00153   // Statistics for the variables
00154   /*! @brief Mapping of a variable to the number of inequalities where
00155     the variable would be isolated on the right */
00156   CDMap<Expr, int> d_countRight;
00157   /*! @brief Mapping of a variable to the number of inequalities where
00158     the variable would be isolated on the left */
00159   CDMap<Expr, int> d_countLeft;
00160   //! Set of shared terms (for counterexample generation)
00161   CDMap<Expr, bool> d_sharedTerms;
00162   //! Set of shared integer variables (i-leaves)
00163   CDMap<Expr, bool> d_sharedVars;
00164   //Directed Acyclic Graph representing partial variable ordering for
00165   //variable projection over inequalities.
00166   class VarOrderGraph {
00167     ExprMap<std::vector<Expr> > d_edges;
00168     ExprMap<bool> d_cache;
00169     bool dfs(const Expr& e1, const Expr& e2);
00170   public:
00171     void addEdge(const Expr& e1, const Expr& e2);
00172     //returns true if e1 < e2, false otherwise.
00173     bool lessThan(const Expr& e1, const Expr& e2);
00174     //selects those variables which are largest and incomparable among
00175     //v1 and puts it into v2
00176     void selectLargest(const std::vector<Expr>& v1, std::vector<Expr>& v2);
00177     //selects those variables which are smallest and incomparable among
00178     //v1, removes them from v1 and  puts them into v2. 
00179     void selectSmallest( std::vector<Expr>& v1, std::vector<Expr>& v2);
00180 
00181   };
00182   
00183   VarOrderGraph d_graph;
00184 
00185   // Private methods
00186   //! Check the term t for integrality.  
00187   /*! \return a theorem of IS_INTEGER(t) or Null. */
00188   Theorem isIntegerThm(const Expr& e);
00189   //! A helper method for isIntegerThm()
00190   /*! Check if IS_INTEGER(e) is easily derivable from the given 'thm' */
00191   Theorem isIntegerDerive(const Expr& isIntE, const Theorem& thm);
00192   //! Check the term t for integrality (return bool)
00193   bool isInteger(const Expr& e) { return !(isIntegerThm(e).isNull()); }
00194   //! Extract the free constant from an inequality
00195   const Rational& freeConstIneq(const Expr& ineq, bool varOnRHS);
00196   //! Update the free constant subsumption database with new inequality
00197   /*! \return a reference to the max/min constant.
00198    *
00199    * Also, sets 'subsumed' argument to true if the inequality is
00200    * subsumed by an existing inequality.
00201    */
00202   const FreeConst& updateSubsumptionDB(const Expr& ineq, bool varOnRHS,
00203                                       bool& subsumed);
00204   //! Check if the kids of e are fully simplified and canonized (for debugging)
00205   bool kidsCanonical(const Expr& e);
00206   //! Canonize the expression e, assuming all children are canonical
00207   Theorem canon(const Expr& e);
00208   //! Canonize the expression e recursively
00209   Theorem canonRec(const Expr& e);
00210   /*! @brief Composition of canon(const Expr&) by transitivity: take e0 = e1,
00211    * canonize e1 to e2, return e0 = e2. */
00212   Theorem canon(const Theorem& thm) {
00213     return transitivityRule(thm, canon(thm.getRHS()));
00214   }
00215   /*! @brief Canonize and reduce e w.r.t. union-find database; assume
00216    * all children are canonical */
00217   Theorem canonSimplify(const Expr& e);
00218   /*! @brief Composition of canonSimplify(const Expr&) by
00219    * transitivity: take e0 = e1, canonize and simplify e1 to e2,
00220    * return e0 = e2. */
00221   Theorem canonSimplify(const Theorem& thm) {
00222     return transitivityRule(thm, canonSimplify(thm.getRHS()));
00223   }
00224   //! Canonize predicate (x = y, x < y, etc.)
00225   Theorem canonPred(const Theorem& thm);
00226   //! Canonize predicate like canonPred except that the input theorem
00227   //! is an equivalent transformation.
00228   Theorem canonPredEquiv(const Theorem& thm);
00229   //! Solve an equation and return an equivalent Theorem in the solved form
00230   Theorem doSolve(const Theorem& e);
00231   //! takes in a conjunction equivalence Thm and canonizes it.
00232   Theorem canonConjunctionEquiv(const Theorem& thm);
00233   //! picks the monomial with the smallest abs(coeff) from the input
00234   //integer equation.
00235   Expr pickIntEqMonomial(const Expr& right);
00236   //! processes equalities with 1 or more vars of type REAL
00237   Theorem processRealEq(const Theorem& eqn);
00238   //! processes equalities whose vars are all of type INT
00239   Theorem processIntEq(const Theorem& eqn);
00240   //! One step of INT equality processing (aux. method for processIntEq())
00241   Theorem processSimpleIntEq(const Theorem& eqn);
00242   //! Process inequalities in the buffer
00243   void processBuffer();
00244   //! Take an inequality and isolate a variable
00245   Theorem isolateVariable(const Theorem& inputThm, bool& e1);
00246   //! Update the statistics counters for the variable with a coeff. c
00247   void updateStats(const Rational& c, const Expr& var);
00248   //! Update the statistics counters for the monomial
00249   void updateStats(const Expr& monomial);
00250   //! Add an inequality to the input buffer.  See also d_buffer
00251   void addToBuffer(const Theorem& thm);
00252   /*! @brief Given a canonized term, compute a factor to make all
00253     coefficients integer and relatively prime */
00254   Expr computeNormalFactor(const Expr& rhs);
00255   //! Normalize an equation (make all coefficients rel. prime integers)
00256   Theorem normalize(const Expr& e);
00257   //! Normalize an equation (make all coefficients rel. prime integers)
00258   /*! accepts a rewrite theorem over eqn|ineqn and normalizes it
00259    *  and returns a theorem to that effect.
00260    */
00261   Theorem normalize(const Theorem& thm);
00262   Expr pickMonomial(const Expr& right);
00263  public: // ArithTheoremProducer needs this function, so make it public
00264   //! Separate monomial e = c*p1*...*pn into c and 1*p1*...*pn
00265   void separateMonomial(const Expr& e, Expr& c, Expr& var);
00266  private:
00267   bool lessThanVar(const Expr& isolatedVar, const Expr& var2);
00268   //! Check if the term expression is "stale"
00269   bool isStale(const Expr& e);
00270   //! Check if the inequality is "stale" or subsumed
00271   bool isStale(const Ineq& ineq);
00272   void projectInequalities(const Theorem& theInequality,bool isolatedVarOnRHS);
00273   void assignVariables(std::vector<Expr>&v);
00274   void findRationalBound(const Expr& varSide, const Expr& ratSide, 
00275                          const Expr& var,
00276                          Rational &r);
00277   bool findBounds(const Expr& e, Rational& lub, Rational&  glb);
00278 
00279   Theorem normalizeProjectIneqs(const Theorem& ineqThm1,
00280                                 const Theorem& ineqThm2);
00281   //! Take a system of equations and turn it into a solved form
00282   Theorem solvedForm(const std::vector<Theorem>& solvedEqs);
00283   /*! @brief Substitute all vars in term 't' according to the
00284    * substitution 'subst' and canonize the result.
00285    */
00286   Theorem substAndCanonize(const Expr& t, ExprMap<Theorem>& subst);
00287   /*! @brief Substitute all vars in the RHS of the equation 'eq' of
00288    * the form (x = t) according to the substitution 'subst', and
00289    * canonize the result.
00290    */
00291   Theorem substAndCanonize(const Theorem& eq, ExprMap<Theorem>& subst);
00292   //! Traverse 'e' and push all the i-leaves into 'vars' vector
00293   void collectVars(const Expr& e, std::vector<Expr>& vars,
00294                    std::set<Expr>& cache);
00295   /*! @brief Check if alpha <= ax & bx <= beta is a finite interval
00296    *  for integer var 'x', and assert the corresponding constraint
00297    */
00298   void processFiniteInterval(const Theorem& alphaLEax,
00299                              const Theorem& bxLEbeta);
00300   //! For an integer var 'x', find and process all constraints A <= ax <= A+c 
00301   void processFiniteIntervals(const Expr& x);
00302   //! Recursive setup for isolated inequalities (and other new expressions)
00303   void setupRec(const Expr& e);
00304 
00305   //! Return whether e is syntactically identical to a rational constant
00306   bool isSyntacticRational(const Expr& e, Rational& r);
00307   //! Print a rational in SMT-LIB format
00308   void printRational(ExprStream& os, const Expr& parent, const Expr& e,
00309                      const Rational& r, bool checkLhs = true);
00310   //! Return whether e is syntactically identical to unary minus of a var
00311   bool isSyntacticUMinusVar(const Expr& e, Expr& var);
00312   //! Print a PLUS expression in SMT-LIB format
00313   void printPlus(ExprStream& os, const Expr& parent, const Expr& e);
00314   //! Print a MINUS expression in SMT-LIB format
00315   void printMinus(ExprStream& os, const Expr& parent, const Expr& e);
00316   //! Print left hand side of an arithmetic atom, converting to DIFF logic if possible
00317   void printLhs(ExprStream& os, const Expr& e);
00318   //! Whether any ite's appear in the arithmetic part of the term e
00319   bool isAtomicArithTerm(const Expr& e);
00320 
00321 public:
00322   TheoryArith(VCL* vcl, TheoryCore* core);
00323   ~TheoryArith();
00324 
00325   //! Return whether Reals are used
00326   bool realUsed() { return d_realUsed; }
00327   //! Return whether Ints are used
00328   bool intUsed() { return d_intUsed || (d_intConstUsed && !d_realUsed); }
00329   //! Return which subset of arithmetic is used
00330   ArithLang getLangUsed() { return d_langUsed; }
00331   //! Theory is used if any component is used
00332   bool theoryUsed()
00333     { return d_realUsed || d_intUsed || d_intConstUsed || (d_langUsed != NOT_USED); }
00334   //! Rewrite an atom to look like x - y op c if possible--for smtlib translation
00335   Expr rewriteToDiff(const Expr& e);
00336   //! Whether any ite's appear in the arithmetic part of the formula e
00337   bool isAtomicArithFormula(const Expr& e);
00338 
00339   // Trusted method that creates the proof rules class (used in constructor).
00340   // Implemented in arith_theorem_producer.cpp
00341   ArithProofRules* createProofRules();
00342 
00343   // Theory interface
00344   void addSharedTerm(const Expr& e);
00345   void assertFact(const Theorem& e);
00346   void refineCounterExample();
00347   void computeModelBasic(const std::vector<Expr>& v);
00348   void computeModel(const Expr& e, std::vector<Expr>& vars);
00349   void checkSat(bool fullEffort);
00350   Theorem rewrite(const Expr& e);
00351   void setup(const Expr& e);
00352   void update(const Theorem& e, const Expr& d);
00353   Theorem solve(const Theorem& e);
00354   void checkType(const Expr& e);
00355   void computeType(const Expr& e);
00356   Type computeBaseType(const Type& t);
00357   void computeModelTerm(const Expr& e, std::vector<Expr>& v);
00358   Expr computeTypePred(const Type& t, const Expr& e);
00359   Expr computeTCC(const Expr& e);
00360   ExprStream& print(ExprStream& os, const Expr& e);
00361   virtual Expr parseExprOp(const Expr& e);
00362 
00363   // Arith constructors
00364   Type realType() { return d_realType; }
00365   Type intType() { return d_intType;}
00366   Type subrangeType(const Expr& l, const Expr& r)
00367     { return Type(Expr(SUBRANGE, l, r)); }
00368   Expr rat(Rational r) { return getEM()->newRatExpr(r); }
00369   // Dark and Gray shadows (for internal use only)
00370   //! Construct the dark shadow expression representing lhs <= rhs
00371   Expr darkShadow(const Expr& lhs, const Expr& rhs) {
00372     return Expr(DARK_SHADOW, lhs, rhs);
00373   }
00374   //! Construct the gray shadow expression representing c1 <= v - e <= c2
00375   /*! Alternatively, v = e + i for some i s.t. c1 <= i <= c2
00376    */
00377   Expr grayShadow(const Expr& v, const Expr& e,
00378                   const Rational& c1, const Rational& c2) {
00379     return Expr(GRAY_SHADOW, v, e, rat(c1), rat(c2));
00380   }
00381 };
00382 
00383 // Arith testers
00384 inline bool isReal(Type t) { return t.getExpr().getKind() == REAL; }
00385 inline bool isInt(Type t) { return t.getExpr().getKind() == INT; }
00386 
00387 // Static arith testers
00388 inline bool isRational(const Expr& e) { return e.isRational(); }
00389 inline bool isIntegerConst(const Expr& e)
00390   { return e.isRational() && e.getRational().isInteger(); }
00391 inline bool isUMinus(const Expr& e) { return e.getKind() == UMINUS; }
00392 inline bool isPlus(const Expr& e) { return e.getKind() == PLUS; }
00393 inline bool isMinus(const Expr& e) { return e.getKind() == MINUS; }
00394 inline bool isMult(const Expr& e) { return e.getKind() == MULT; }
00395 inline bool isDivide(const Expr& e) { return e.getKind() == DIVIDE; }
00396 inline bool isLT(const Expr& e) { return e.getKind() == LT; }
00397 inline bool isLE(const Expr& e) { return e.getKind() == LE; }
00398 inline bool isGT(const Expr& e) { return e.getKind() == GT; }
00399 inline bool isGE(const Expr& e) { return e.getKind() == GE; }
00400 inline bool isDarkShadow(const Expr& e) { return e.getKind() == DARK_SHADOW;}
00401 inline bool isGrayShadow(const Expr& e) { return e.getKind() == GRAY_SHADOW;}
00402 inline bool isIneq(const Expr& e)
00403   { return isLT(e) || isLE(e) || isGT(e) || isGE(e); }
00404 inline bool isIntPred(const Expr& e) { return e.getKind() == IS_INTEGER; }
00405 
00406 // Static arith constructors
00407 inline Expr uminusExpr(const Expr& child)
00408   { return Expr(UMINUS, child); }
00409 inline Expr plusExpr(const Expr& left, const Expr& right)
00410   { return Expr(PLUS, left, right); }
00411 inline Expr plusExpr(const std::vector<Expr>& children) {
00412   DebugAssert(children.size() > 0, "plusExpr()");
00413   return Expr(PLUS, children);
00414 }
00415 inline Expr minusExpr(const Expr& left, const Expr& right)
00416   { return Expr(MINUS, left, right); }
00417 inline Expr multExpr(const Expr& left, const Expr& right)
00418   { return Expr(MULT, left, right); }
00419 // Begin Deepak: 
00420 //! a Mult expr with two or more children
00421 inline Expr multExpr(const std::vector<Expr>& children) {
00422   DebugAssert(children.size() > 0, "multExpr()");
00423   return Expr(MULT, children);
00424 }
00425 //! Power (x^n, or base^{pow}) expressions
00426 inline Expr powExpr(const Expr& pow, const Expr & base)
00427   { return Expr(POW, pow, base);}
00428 // End Deepak
00429 inline Expr divideExpr(const Expr& left, const Expr& right)
00430   { return Expr(DIVIDE, left, right); }
00431 inline Expr ltExpr(const Expr& left, const Expr& right)
00432   { return Expr(LT, left, right); }
00433 inline Expr leExpr(const Expr& left, const Expr& right)
00434   { return Expr(LE, left, right); }
00435 inline Expr gtExpr(const Expr& left, const Expr& right)
00436   { return Expr(GT, left, right); }
00437 inline Expr geExpr(const Expr& left, const Expr& right)
00438   { return Expr(GE, left, right); }
00439 
00440 inline Expr operator-(const Expr& child)
00441   { return uminusExpr(child); }
00442 inline Expr operator+(const Expr& left, const Expr& right)
00443   { return plusExpr(left, right); }
00444 inline Expr operator-(const Expr& left, const Expr& right)
00445   { return minusExpr(left, right); }
00446 inline Expr operator*(const Expr& left, const Expr& right)
00447   { return multExpr(left, right); }
00448 inline Expr operator/(const Expr& left, const Expr& right)
00449   { return divideExpr(left, right); }
00450 
00451 }
00452 
00453 #endif

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