CVC3
|
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