CVC3

theory_arith.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file theory_arith.cpp
00004  * 
00005  * Author: Clark Barrett, Vijay Ganesh.
00006  * 
00007  * Created: Fri Jan 17 18:39:18 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 
00022 #include "theory_arith.h"
00023 #include "theory_core.h"
00024 #include "translator.h"
00025 
00026 
00027 using namespace std;
00028 using namespace CVC3;
00029 
00030 
00031 Theorem TheoryArith::canonRec(const Expr& e)
00032 {
00033   if (isLeaf(e)) return reflexivityRule(e);
00034   int ar = e.arity();
00035   if (ar > 0) {
00036     vector<Theorem> newChildrenThm;
00037     vector<unsigned> changed;
00038     for(int k = 0; k < ar; ++k) {
00039       // Recursively canonize the kids
00040       Theorem thm = canonRec(e[k]);
00041       if (thm.getLHS() != thm.getRHS()) {
00042   newChildrenThm.push_back(thm);
00043   changed.push_back(k);
00044       }
00045     }
00046     if(changed.size() > 0) {
00047       return canonThm(substitutivityRule(e, changed, newChildrenThm));
00048     }
00049   }
00050   return canon(e);
00051 }
00052 
00053 
00054 void TheoryArith::printRational(ExprStream& os, const Rational& r,
00055                                 bool printAsReal)
00056 {
00057   // Print rational
00058   if (r.isInteger()) {
00059     if (r < 0) {
00060       if (os.lang() == SPASS_LANG) {
00061         os << "-" << (-r).toString();
00062         if (printAsReal) os << ".0";
00063       } else {
00064         os << "(" << push;
00065         if (os.lang() == SMTLIB_LANG) {
00066           os << "~";
00067         }
00068         else {
00069           os << "-";
00070         }
00071         os << space << (-r).toString();
00072         if (printAsReal) os << ".0";
00073         os << push << ")";
00074       }
00075     }
00076     else {
00077       os << r.toString();
00078       if (printAsReal) os << ".0";
00079     }
00080   }
00081   else {
00082     os << "(" << push << "/ ";
00083     Rational tmp = r.getNumerator();
00084     if (tmp < 0) {
00085       if (os.lang() == SPASS_LANG) {
00086         os << "-" << (-tmp).toString();
00087         if (printAsReal) os << ".0";
00088       } else {
00089         os << "(" << push;
00090         if (os.lang() == SMTLIB_LANG) {
00091           os << "~";
00092         }
00093         else {
00094           os << "-";
00095         }
00096         os << space << (-tmp).toString();
00097         if (printAsReal) os << ".0";
00098         os << push << ")";
00099       }
00100     }
00101     else {
00102       os << tmp.toString();
00103       if (printAsReal) os << ".0";
00104     }
00105     os << space;
00106     tmp = r.getDenominator();
00107     DebugAssert(tmp > 0 && tmp.isInteger(), "Unexpected rational denominator");
00108     os << tmp.toString();
00109     if (printAsReal) os << ".0";
00110     os << push << ")";
00111   }
00112 }
00113 
00114 
00115 bool TheoryArith::isAtomicArithTerm(const Expr& e)
00116 {
00117   switch (e.getKind()) {
00118     case RATIONAL_EXPR:
00119       return true;
00120     case ITE:
00121       return false;
00122     case UMINUS:
00123     case PLUS:
00124     case MINUS:
00125     case MULT:
00126     case DIVIDE:
00127     case POW:
00128     case INTDIV:
00129     case MOD: {
00130       int i=0, iend=e.arity();
00131       for(; i!=iend; ++i) {
00132         if (!isAtomicArithTerm(e[i])) return false;
00133       }
00134       break;
00135     }
00136     default:
00137       break;
00138   }
00139   return true;
00140 }
00141 
00142 
00143 bool TheoryArith::isAtomicArithFormula(const Expr& e)
00144 {
00145   switch (e.getKind()) {
00146     case LT:
00147     case GT:
00148     case LE:
00149     case GE:
00150     case EQ:
00151       return isAtomicArithTerm(e[0]) && isAtomicArithTerm(e[1]);
00152   }
00153   return false;
00154 }
00155 
00156 
00157 bool TheoryArith::isSyntacticRational(const Expr& e, Rational& r)
00158 {
00159   if (e.getKind() == REAL_CONST) {
00160     r = e[0].getRational();
00161     return true;
00162   }
00163   else if (e.isRational()) {
00164     r = e.getRational();
00165     return true;
00166   }
00167   else if (isUMinus(e)) {
00168     if (isSyntacticRational(e[0], r)) {
00169       r = -r;
00170       return true;
00171     }
00172   }
00173   else if (isDivide(e)) {
00174     Rational num;
00175     if (isSyntacticRational(e[0], num)) {
00176       Rational den;
00177       if (isSyntacticRational(e[1], den)) {
00178         if (den != 0) {
00179           r = num / den;
00180           return true;
00181         }
00182       }
00183     }
00184   }
00185   return false;
00186 }
00187 
00188 
00189 Expr TheoryArith::rewriteToDiff(const Expr& e)
00190 {
00191   Expr tmp = e[0] - e[1];
00192   tmp = canonRec(tmp).getRHS();
00193   switch (tmp.getKind()) {
00194     case RATIONAL_EXPR: {
00195       Rational r = tmp.getRational();
00196       switch (e.getKind()) {
00197         case LT:
00198           if (r < 0) return trueExpr();
00199           else return falseExpr();
00200         case LE:
00201           if (r <= 0) return trueExpr();
00202           else return falseExpr();
00203         case GT:
00204           if (r > 0) return trueExpr();
00205           else return falseExpr();
00206         case GE:
00207           if (r >= 0) return trueExpr();
00208           else return falseExpr();
00209         case EQ:
00210           if (r == 0) return trueExpr();
00211           else return falseExpr();
00212       }
00213     }
00214     case MULT:
00215       DebugAssert(tmp[0].isRational(), "Unexpected term structure from canon");
00216       if (tmp[0].getRational() != -1) return e;
00217       return Expr(e.getOp(), theoryCore()->getTranslator()->zeroVar() - tmp[1], rat(0));
00218     case PLUS: {
00219       DebugAssert(tmp[0].isRational(), "Unexpected term structure from canon");
00220       Rational c = tmp[0].getRational();
00221       Expr x, y;
00222       if (tmp.arity() == 2) {
00223         if (tmp[1].getKind() == MULT) {
00224           x = theoryCore()->getTranslator()->zeroVar();
00225           y = tmp[1];
00226         }
00227         else {
00228           x = tmp[1];
00229           y = rat(-1) * theoryCore()->getTranslator()->zeroVar();
00230         }
00231       }
00232       else if (tmp.arity() == 3) {
00233         if (tmp[1].getKind() == MULT) {
00234           x = tmp[2];
00235           y = tmp[1];
00236         }
00237         else if (tmp[2].getKind() == MULT) {
00238           x = tmp[1];
00239           y = tmp[2];
00240         }
00241         else return e;
00242       }
00243       else return e;
00244       if (x.getKind() == MULT) return e;
00245       DebugAssert(y[0].isRational(), "Unexpected term structure from canon");
00246       if (y[0].getRational() != -1) return e;
00247       return Expr(e.getOp(), x - y[1], getEM()->newRatExpr(-c));
00248     }
00249     default:
00250       return Expr(e.getOp(), tmp - theoryCore()->getTranslator()->zeroVar(), rat(0));
00251       break;
00252   }
00253   return e;
00254 }
00255 
00256 
00257 Theorem TheoryArith::canonSimp(const Expr& e)
00258 {
00259   DebugAssert(canonRec(e).getRHS() == e, "canonSimp expects input to be canonized");
00260   int ar = e.arity();
00261   if (isLeaf(e)) return find(e);
00262   if (ar > 0) {
00263     vector<Theorem> newChildrenThm;
00264     vector<unsigned> changed;
00265     Theorem thm;
00266     for (int k = 0; k < ar; ++k) {
00267       thm = canonSimp(e[k]);
00268       if (thm.getLHS() != thm.getRHS()) {
00269         newChildrenThm.push_back(thm);
00270         changed.push_back(k);
00271       }
00272     }
00273     if(changed.size() > 0) {
00274       thm = canonThm(substitutivityRule(e, changed, newChildrenThm));
00275       return transitivityRule(thm, find(thm.getRHS()));
00276     }
00277     else return find(e);
00278   }
00279   return find(e);
00280 }
00281 
00282 
00283 bool TheoryArith::recursiveCanonSimpCheck(const Expr& e)
00284 {
00285   if (e.hasFind()) return true;
00286   if (e != canonSimp(e).getRHS()) return false;
00287   Expr::iterator i = e.begin(), iend = e.end();
00288   for (; i != iend; ++i)
00289     if (!recursiveCanonSimpCheck(*i)) return false;
00290   return true;
00291 }
00292 
00293 
00294 bool TheoryArith::leavesAreNumConst(const Expr& e)
00295 {
00296   DebugAssert(e.isTerm() ||
00297               (e.isPropAtom() && theoryOf(e) == this),
00298               "Expected term or arith prop atom");
00299 
00300   if (e.validTerminalsConstFlag()) {
00301     return e.getTerminalsConstFlag();
00302   }
00303 
00304   if (e.isRational()) {
00305     e.setTerminalsConstFlag(true);
00306     return true;
00307   }
00308 
00309   if (e.isAtomic() && isLeaf(e)) {
00310     e.setTerminalsConstFlag(false);
00311     return false;
00312   }
00313 
00314   DebugAssert(e.arity() > 0, "Expected non-zero arity");
00315   int k = 0;
00316 
00317   if (e.isITE()) {
00318     k = 1;
00319   }
00320 
00321   for (; k < e.arity(); ++k) {
00322     if (!leavesAreNumConst(e[k])) {
00323       e.setTerminalsConstFlag(false);
00324       return false;
00325     }
00326   }
00327   e.setTerminalsConstFlag(true);
00328   return true;
00329 }
00330 
00331