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 "type.h"
00034 #include "cdlist.h"
00035 #include "cdmap.h"
00036 #include "expr_map.h"
00037 #include <set>
00038 
00039 namespace CVCL {
00040 
00041   class ArithProofRules;
00042 
00043   typedef enum {
00044     REAL = 3000,
00045     INT,
00046     SUBRANGE,
00047 
00048     UMINUS,
00049     PLUS,
00050     MINUS,
00051     MULT,
00052     DIVIDE,
00053     POW,
00054     INTDIV,
00055     MOD,
00056     LT,
00057     LE,
00058     GT,
00059     GE,
00060     IS_INTEGER,
00061     NEGINF,
00062     POSINF,
00063     DARK_SHADOW,
00064     GRAY_SHADOW
00065   } ArithKinds;
00066 
00067   //! Used to keep track of which subset of arith is being used
00068   typedef enum {
00069     NOT_USED = 0,
00070     TERMS_ONLY,
00071     DIFF_ONLY,
00072     LINEAR,
00073     NONLINEAR
00074   } ArithLang;
00075 
00076 /*****************************************************************************/
00077 /*!
00078  *\class TheoryArith
00079  *\ingroup Theories
00080  *\brief This theory handles basic linear arithmetic.
00081  *
00082  * Author: Clark Barrett
00083  *
00084  * Created: Sat Feb  8 14:44:32 2003
00085  */
00086 /*****************************************************************************/
00087 class TheoryArith :public Theory {
00088   VCL* d_vcl;
00089   size_t d_grayShadowMMIndex;
00090   Type d_realType;
00091   Type d_intType;
00092   CDList<Theorem> d_diseq;  // For concrete model generation
00093   CDO<size_t> d_diseqIdx; // Index to the next unprocessed disequality
00094   ArithProofRules* d_rules;
00095   CDO<bool> d_inModelCreation;
00096   bool d_realUsed;
00097   bool d_intUsed;
00098   bool d_intConstUsed;
00099   ArithLang d_langUsed;
00100   //! Data class for the strongest free constant in separation inqualities
00101   class FreeConst {
00102   private:
00103     Rational d_r;
00104     bool d_strict;
00105   public:
00106     FreeConst() { }
00107     FreeConst(const Rational& r, bool strict): d_r(r), d_strict(strict) { }
00108     const Rational& getConst() const { return d_r; }
00109     bool strict() const { return d_strict; }
00110   };
00111   //! Printing
00112   friend std::ostream& operator<<(std::ostream& os, const FreeConst& fc);
00113   //! Private class for an inequality in the Fourier-Motzkin database
00114   class Ineq {
00115   private:
00116     Theorem d_ineq; //!< The inequality
00117     bool d_rhs; //!< Var is isolated on the RHS
00118     const FreeConst* d_const; //!< The max/min const for subsumption check
00119     //! Default constructor is disabled
00120     Ineq() { }
00121   public:
00122     //! Initial constructor.  'r' is taken from the subsumption database.
00123     Ineq(const Theorem& ineq, bool varOnRHS, const FreeConst& c):
00124       d_ineq(ineq), d_rhs(varOnRHS), d_const(&c) { }
00125     //! Get the inequality
00126     const Theorem& ineq() const { return d_ineq; }
00127     //! Get the max/min constant
00128     const FreeConst& getConst() const { return *d_const; }
00129     //! Flag whether var is isolated on the RHS
00130     bool varOnRHS() const { return d_rhs; }
00131     //! Flag whether var is isolated on the LHS
00132     bool varOnLHS() const { return !d_rhs; }
00133     //! Auto-cast to Theorem
00134     operator Theorem() const { return d_ineq; }
00135   };
00136   //! Printing
00137   friend std::ostream& operator<<(std::ostream& os, const Ineq& ineq);
00138   //! Database of inequalities with a variable isolated on the right
00139   ExprMap<CDList<Ineq> *> d_inequalitiesRightDB;
00140   //! Database of inequalities with a variable isolated on the left
00141   ExprMap<CDList<Ineq> *> d_inequalitiesLeftDB;
00142   //! Mapping of inequalities to the largest/smallest free constant
00143   /*! The Expr is the original inequality with the free constant
00144    * removed and inequality converted to non-strict (for indexing
00145    * purposes).  I.e. ax<c+t becomes ax<=t.  This inequality is mapped
00146    * to a pair<c,strict>, the smallest (largest for c+t<ax) constant
00147    * among inequalities with the same 'a', 'x', and 't', and a boolean
00148    * flag indicating whether the strongest inequality is strict.
00149    */
00150   CDMap<Expr, FreeConst> d_freeConstDB;
00151   // Input buffer to store the incoming inequalities
00152   CDList<Theorem> d_buffer; //!< Buffer of input inequalities
00153   CDO<size_t> d_bufferIdx; //!< Buffer index of the next unprocessed inequality
00154   const int* d_bufferThres; //!< Threshold when the buffer must be processed
00155   // Statistics for the variables
00156   /*! @brief Mapping of a variable to the number of inequalities where
00157     the variable would be isolated on the right */
00158   CDMap<Expr, int> d_countRight;
00159   /*! @brief Mapping of a variable to the number of inequalities where
00160     the variable would be isolated on the left */
00161   CDMap<Expr, int> d_countLeft;
00162   //! Set of shared terms (for counterexample generation)
00163   CDMap<Expr, bool> d_sharedTerms;
00164   //! Set of shared integer variables (i-leaves)
00165   CDMap<Expr, bool> d_sharedVars;
00166   //Directed Acyclic Graph representing partial variable ordering for
00167   //variable projection over inequalities.
00168   class VarOrderGraph {
00169     ExprMap<std::vector<Expr> > d_edges;
00170     ExprMap<bool> d_cache;
00171     bool dfs(const Expr& e1, const Expr& e2);
00172   public:
00173     void addEdge(const Expr& e1, const Expr& e2);
00174     //returns true if e1 < e2, false otherwise.
00175     bool lessThan(const Expr& e1, const Expr& e2);
00176     //selects those variables which are largest and incomparable among
00177     //v1 and puts it into v2
00178     void selectLargest(const std::vector<Expr>& v1, std::vector<Expr>& v2);
00179     //selects those variables which are smallest and incomparable among
00180     //v1, removes them from v1 and  puts them into v2. 
00181     void selectSmallest( std::vector<Expr>& v1, std::vector<Expr>& v2);
00182 
00183   };
00184   
00185   VarOrderGraph d_graph;
00186 
00187   // Private methods
00188   //! Check the term t for integrality.  
00189   /*! \return a theorem of IS_INTEGER(t) or Null. */
00190   Theorem isIntegerThm(const Expr& e);
00191   //! A helper method for isIntegerThm()
00192   /*! Check if IS_INTEGER(e) is easily derivable from the given 'thm' */
00193   Theorem isIntegerDerive(const Expr& isIntE, const Theorem& thm);
00194   //! Check the term t for integrality (return bool)
00195   bool isInteger(const Expr& e) { return !(isIntegerThm(e).isNull()); }
00196   //! Extract the free constant from an inequality
00197   const Rational& freeConstIneq(const Expr& ineq, bool varOnRHS);
00198   //! Update the free constant subsumption database with new inequality
00199   /*! \return a reference to the max/min constant.
00200    *
00201    * Also, sets 'subsumed' argument to true if the inequality is
00202    * subsumed by an existing inequality.
00203    */
00204   const FreeConst& updateSubsumptionDB(const Expr& ineq, bool varOnRHS,
00205                                       bool& subsumed);
00206   //! Check if the kids of e are fully simplified and canonized (for debugging)
00207   bool kidsCanonical(const Expr& e);
00208   //! Canonize the expression e, assuming all children are canonical
00209   Theorem canon(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   //! Return whether e is syntactically identical to a rational constant
00305   bool isSyntacticRational(const Expr& e);
00306   //! Return whether e is syntactically identical to unary minus of a var
00307   bool isSyntacticUMinusVar(const Expr& e, Expr& var);
00308 public:
00309   TheoryArith(VCL* vcl);
00310   ~TheoryArith();
00311 
00312   //! Return whether Reals are used
00313   bool realUsed() { return d_realUsed; }
00314   //! Return whether Ints are used
00315   bool intUsed() { return d_intUsed || (d_intConstUsed && !d_realUsed); }
00316   //! Return which subset of arithmetic is used
00317   ArithLang getLangUsed() { return d_langUsed; }
00318   //! Theory is used if any component is used
00319   bool theoryUsed()
00320     { return d_realUsed || d_intUsed || d_intConstUsed || (d_langUsed != NOT_USED); }
00321   
00322 
00323   // Trusted method that creates the proof rules class (used in constructor).
00324   // Implemented in arith_theorem_producer.cpp
00325   ArithProofRules* createProofRules(VCL* vcl);
00326 
00327   // Theory interface
00328   void addSharedTerm(const Expr& e);
00329   void assertFact(const Theorem& e);
00330   void refineCounterExample();
00331   void computeModelBasic(const std::vector<Expr>& v);
00332   void computeModel(const Expr& e, std::vector<Expr>& vars);
00333   void checkSat(bool fullEffort);
00334   Theorem rewrite(const Expr& e);
00335   void setup(const Expr& e);
00336   void update(const Theorem& e, const Expr& d);
00337   Theorem solve(const Theorem& e);
00338   void computeType(const Expr& e);
00339   Type computeBaseType(const Type& t);
00340   void computeModelTerm(const Expr& e, std::vector<Expr>& v);
00341   Expr computeTypePred(const Type& t, const Expr& e);
00342   Expr computeTCC(const Expr& e);
00343   ExprStream& print(ExprStream& os, const Expr& e);
00344   virtual Expr parseExprOp(const Expr& e);
00345 
00346   // Arith constructors
00347   Type realType() { return d_realType; }
00348   Type intType() { return d_intType;}
00349   Type subrangeType(const Expr& l, const Expr& r)
00350     { return Type(newExpr(getEM(), SUBRANGE, l, r)); }
00351   Expr rat(Rational r) { return newRatExpr(d_realType.getExpr().getEM(), r); }
00352   // Dark and Gray shadows (for internal use only)
00353   //! Construct the dark shadow expression representing lhs <= rhs
00354   Expr darkShadow(const Expr& lhs, const Expr& rhs) {
00355     return newExpr(getEM(), DARK_SHADOW, lhs, rhs);
00356   }
00357   //! Construct the gray shadow expression representing c1 <= v - e <= c2
00358   /*! Alternatively, v = e + i for some i s.t. c1 <= i <= c2
00359    */
00360   Expr grayShadow(const Expr& v, const Expr& e,
00361                   const Rational& c1, const Rational& c2);
00362   //! Access lhs constant in gray shadow
00363   const Rational& getC1(const Expr& grayShadow);
00364   //! Access rhs constant in gray shadow
00365   const Rational& getC2(const Expr& grayShadow);
00366   //! Access the monomial in gray shadow
00367   const Expr& getV(const Expr& grayShadow);
00368   //! Access the expression in gray shadow
00369   const Expr& getE(const Expr& grayShadow);
00370   //! Check for gray shadow
00371   bool isGrayShadow(const Expr& e)
00372     { return e.getMMIndex() == d_grayShadowMMIndex; }
00373 };
00374 
00375 // Arith testers
00376 inline bool isReal(Type t) { return t.getExpr().getKind() == REAL; }
00377 inline bool isInt(Type t) { return t.getExpr().getKind() == INT; }
00378 
00379 // Static arith testers
00380 inline bool isRational(const Expr& e) { return e.isRational(); }
00381 inline bool isUMinus(const Expr& e) { return e.getKind() == UMINUS; }
00382 inline bool isPlus(const Expr& e) { return e.getKind() == PLUS; }
00383 inline bool isMinus(const Expr& e) { return e.getKind() == MINUS; }
00384 inline bool isMult(const Expr& e) { return e.getKind() == MULT; }
00385 inline bool isDivide(const Expr& e) { return e.getKind() == DIVIDE; }
00386 inline bool isLT(const Expr& e) { return e.getKind() == LT; }
00387 inline bool isLE(const Expr& e) { return e.getKind() == LE; }
00388 inline bool isGT(const Expr& e) { return e.getKind() == GT; }
00389 inline bool isGE(const Expr& e) { return e.getKind() == GE; }
00390 inline bool isDarkShadow(const Expr& e) { return e.getKind() == DARK_SHADOW;}
00391 inline bool isIneq(const Expr& e)
00392   { return isLT(e) || isLE(e) || isGT(e) || isGE(e); }
00393 inline bool isIntPred(const Expr& e) { return e.getKind() == IS_INTEGER; }
00394 
00395 // Static arith constructors
00396 inline Expr uminusExpr(const Expr& child)
00397   { return newExpr(child.getEM(), UMINUS, child); }
00398 inline Expr plusExpr(const Expr& left, const Expr& right)
00399   { return newExpr(left.getEM(), PLUS, left, right); }
00400 inline Expr plusExpr(const std::vector<Expr>& children) {
00401   DebugAssert(children.size() > 0, "plusExpr()");
00402   return newExpr(children[0].getEM(), PLUS, children);
00403 }
00404 inline Expr minusExpr(const Expr& left, const Expr& right)
00405   { return newExpr(left.getEM(), MINUS, left, right); }
00406 inline Expr multExpr(const Expr& left, const Expr& right)
00407   { return newExpr(left.getEM(), MULT, left, right); }
00408 // Begin Deepak: 
00409 //! a Mult expr with two or more children
00410 inline Expr multExpr(const std::vector<Expr>& children) {
00411   DebugAssert(children.size() > 0, "multExpr()");
00412   return newExpr(children[0].getEM(), MULT, children);
00413 }
00414 //! Power (x^n, or base^{pow}) expressions
00415 inline Expr powExpr(const Expr& pow, const Expr & base)
00416   { return newExpr(pow.getEM(), POW, pow, base);}
00417 // End Deepak
00418 inline Expr divideExpr(const Expr& left, const Expr& right)
00419   { return newExpr(left.getEM(), DIVIDE, left, right); }
00420 inline Expr ltExpr(const Expr& left, const Expr& right)
00421   { return newExpr(left.getEM(), LT, left, right); }
00422 inline Expr leExpr(const Expr& left, const Expr& right)
00423   { return newExpr(left.getEM(), LE, left, right); }
00424 inline Expr gtExpr(const Expr& left, const Expr& right)
00425   { return newExpr(left.getEM(), GT, left, right); }
00426 inline Expr geExpr(const Expr& left, const Expr& right)
00427   { return newExpr(left.getEM(), GE, left, right); }
00428 
00429 inline Expr operator-(const Expr& child)
00430   { return uminusExpr(child); }
00431 inline Expr operator+(const Expr& left, const Expr& right)
00432   { return plusExpr(left, right); }
00433 inline Expr operator-(const Expr& left, const Expr& right)
00434   { return minusExpr(left, right); }
00435 inline Expr operator*(const Expr& left, const Expr& right)
00436   { return multExpr(left, right); }
00437 inline Expr operator/(const Expr& left, const Expr& right)
00438   { return divideExpr(left, right); }
00439 
00440 }
00441 
00442 #endif

Generated on Fri May 20 13:13:57 2005 for CVC Lite by  doxygen 1.3.9.1