CVC3
|
00001 /*****************************************************************************/ 00002 /*! 00003 * \file arith_theorem_producer.cpp 00004 * 00005 * Author: Vijay Ganesh, Sergey Berezin 00006 * 00007 * Created: Dec 13 02:09:04 GMT 2002 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 // CLASS: ArithProofRules 00021 // 00022 // AUTHOR: Sergey Berezin, 12/11/2002 00023 // AUTHOR: Vijay Ganesh, 05/30/2003 00024 // 00025 // Description: TRUSTED implementation of arithmetic proof rules. 00026 // 00027 /////////////////////////////////////////////////////////////////////////////// 00028 00029 // This code is trusted 00030 #define _CVC3_TRUSTED_ 00031 00032 #include "arith_theorem_producer3.h" 00033 #include "theory_core.h" 00034 #include "theory_arith3.h" 00035 00036 using namespace std; 00037 using namespace CVC3; 00038 00039 //////////////////////////////////////////////////////////////////// 00040 // TheoryArith: trusted method for creating ArithTheoremProducer3 00041 //////////////////////////////////////////////////////////////////// 00042 00043 ArithProofRules* TheoryArith3::createProofRules3() { 00044 return new ArithTheoremProducer3(theoryCore()->getTM(), this); 00045 } 00046 00047 //////////////////////////////////////////////////////////////////// 00048 // Canonization rules 00049 //////////////////////////////////////////////////////////////////// 00050 00051 00052 #define CLASS_NAME "ArithTheoremProducer3" 00053 00054 00055 // Rule for variables: e == 1 * e 00056 Theorem ArithTheoremProducer3::varToMult(const Expr& e) { 00057 Proof pf; 00058 if(withProof()) pf = newPf("var_to_mult", e); 00059 return newRWTheorem(e, (rat(1) * e), Assumptions::emptyAssump(), pf); 00060 } 00061 00062 00063 // Rule for unary minus: -e == (-1) * e 00064 Theorem ArithTheoremProducer3::uMinusToMult(const Expr& e) { 00065 Proof pf; 00066 if(withProof()) pf = newPf("uminus_to_mult", e); 00067 return newRWTheorem((-e), (rat(-1) * e), Assumptions::emptyAssump(), pf); 00068 } 00069 00070 00071 // ==> x - y = x + (-1) * y 00072 Theorem ArithTheoremProducer3::minusToPlus(const Expr& x, const Expr& y) 00073 { 00074 Proof pf; 00075 if(withProof()) pf = newPf("minus_to_plus", x, y); 00076 return newRWTheorem((x-y), (x + (rat(-1) * y)), Assumptions::emptyAssump(), pf); 00077 } 00078 00079 00080 // Rule for unary minus: -e == e/(-1) 00081 // This is to reduce the number of almost identical rules for uminus and div 00082 Theorem ArithTheoremProducer3::canonUMinusToDivide(const Expr& e) { 00083 Proof pf; 00084 if(withProof()) pf = newPf("canon_uminus", e); 00085 return newRWTheorem((-e), (e / rat(-1)), Assumptions::emptyAssump(), pf); 00086 } 00087 00088 // Rules for division by constant 00089 00090 // (c)/(d) ==> (c/d). When d==0, c/0 = 0 (our total extension). 00091 Theorem ArithTheoremProducer3::canonDivideConst(const Expr& c, 00092 const Expr& d) { 00093 // Make sure c and d are a const 00094 if(CHECK_PROOFS) { 00095 CHECK_SOUND(isRational(c), 00096 CLASS_NAME "::canonDivideConst:\n c not a constant: " 00097 + c.toString()); 00098 CHECK_SOUND(isRational(d), 00099 CLASS_NAME "::canonDivideConst:\n d not a constant: " 00100 + d.toString()); 00101 } 00102 Proof pf; 00103 if(withProof()) 00104 pf = newPf("canon_divide_const", c, d, d_hole); 00105 const Rational& dr = d.getRational(); 00106 return newRWTheorem((c/d), (rat(dr==0? 0 : (c.getRational()/dr))), Assumptions::emptyAssump(), pf); 00107 } 00108 00109 // (c * x)/d ==> (c/d) * x, takes (c*x) and d 00110 Theorem ArithTheoremProducer3::canonDivideMult(const Expr& cx, 00111 const Expr& d) { 00112 // Check the format of c*x 00113 if(CHECK_PROOFS) { 00114 CHECK_SOUND(isMult(cx) && isRational(cx[0]), 00115 CLASS_NAME "::canonDivideMult:\n " 00116 "Not a (c * x) expression: " 00117 + cx.toString()); 00118 CHECK_SOUND(isRational(d), 00119 CLASS_NAME "::canonDivideMult:\n " 00120 "d is not a constant: " + d.toString()); 00121 } 00122 const Rational& dr = d.getRational(); 00123 Rational cdr(dr==0? 0 : (cx[0].getRational()/dr)); 00124 Expr cd(rat(cdr)); 00125 Proof pf; 00126 if(withProof()) 00127 pf = newPf("canon_divide_mult", cx[0], cx[1], d); 00128 // (c/d) may be == 1, so we also need to canonize 1*x to x 00129 if(cdr == 1) 00130 return newRWTheorem((cx/d), (cx[1]), Assumptions::emptyAssump(), pf); 00131 else if(cdr == 0) // c/0 == 0 case 00132 return newRWTheorem((cx/d), cd, Assumptions::emptyAssump(), pf); 00133 else 00134 return newRWTheorem((cx/d), (cd*cx[1]), Assumptions::emptyAssump(), pf); 00135 } 00136 00137 // (+ t1 ... tn)/d ==> (+ (t1/d) ... (tn/d)) 00138 Theorem ArithTheoremProducer3::canonDividePlus(const Expr& sum, const Expr& d) { 00139 if(CHECK_PROOFS) { 00140 CHECK_SOUND(isPlus(sum) && sum.arity() >= 2 && isRational(sum[0]), 00141 CLASS_NAME "::canonUMinusPlus:\n " 00142 "Expr is not a canonical sum: " 00143 + sum.toString()); 00144 CHECK_SOUND(isRational(d), 00145 CLASS_NAME "::canonUMinusPlus:\n " 00146 "d is not a const: " + d.toString()); 00147 } 00148 // First, propagate '/d' down to the args 00149 Proof pf; 00150 if(withProof()) 00151 pf = newPf("canon_divide_plus", rat(sum.arity()), 00152 sum.begin(), sum.end()); 00153 vector<Expr> newKids; 00154 for(Expr::iterator i=sum.begin(), iend=sum.end(); i!=iend; ++i) 00155 newKids.push_back((*i)/d); 00156 // (+ t1 ... tn)/d == (+ (t1/d) ... (tn/d)) 00157 return newRWTheorem((sum/d), (plusExpr(newKids)), Assumptions::emptyAssump(), pf); 00158 } 00159 00160 // x/(d) ==> (1/d) * x, unless d == 1 00161 Theorem ArithTheoremProducer3::canonDivideVar(const Expr& e, const Expr& d) { 00162 if(CHECK_PROOFS) { 00163 CHECK_SOUND(isRational(d), 00164 CLASS_NAME "::canonDivideVar:\n " 00165 "d is not a const: " + d.toString()); 00166 } 00167 Proof pf; 00168 00169 if(withProof()) 00170 pf = newPf("canon_divide_var", e); 00171 00172 const Rational& dr = d.getRational(); 00173 if(dr == 1) 00174 return newRWTheorem(e/d, e, Assumptions::emptyAssump(), pf); 00175 if(dr == 0) // e/0 == 0 (total extension of division) 00176 return newRWTheorem(e/d, d, Assumptions::emptyAssump(), pf); 00177 else 00178 return newRWTheorem(e/d, rat(1/dr) * e, Assumptions::emptyAssump(), pf); 00179 } 00180 00181 00182 // Multiplication 00183 // (MULT expr1 expr2 expr3 ...) 00184 // Each expr is in canonical form, i.e. it can be a 00185 // 1) Rational constant 00186 // 2) Arithmetic Leaf (var or term from another theory) 00187 // 3) (POW rational leaf) 00188 // where rational cannot be 0 or 1 00189 // 4) (MULT rational mterm'_1 ...) where each mterm' is of type (2) or (3) 00190 // If rational == 1 then there should be at least two mterms 00191 // 5) (PLUS rational sterm_1 ...) where each sterm is of 00192 // type (2) or (3) or (4) 00193 // if rational == 0 then there should be at least two sterms 00194 00195 00196 Expr ArithTheoremProducer3::simplifiedMultExpr(std::vector<Expr> & mulKids) 00197 { 00198 DebugAssert(mulKids.size() >= 1 && mulKids[0].isRational(), ""); 00199 if (mulKids.size() == 1) { 00200 return mulKids[0]; 00201 } 00202 if ((mulKids[0] == rat(1)) && mulKids.size() == 2) { 00203 return mulKids[1]; 00204 } 00205 else 00206 return multExpr(mulKids); 00207 } 00208 00209 Expr ArithTheoremProducer3::canonMultConstMult(const Expr & c, 00210 const Expr & e) 00211 { 00212 // c is a rational 00213 // e is (MULT rat mterm'_1 ....) 00214 // assume that e2 is already in canonic form 00215 DebugAssert(c.isRational() && e.getKind() == MULT, ""); 00216 std::vector<Expr> mulKids; 00217 DebugAssert ((e.arity() > 1) && (e[0].isRational()), 00218 "ArithTheoremProducer3::canonMultConstMult: " 00219 "a canonized MULT expression must have arity " 00220 "greater than 1: and first child must be " 00221 "rational " + e.toString()); 00222 Expr::iterator i = e.begin(); 00223 mulKids.push_back(rat(c.getRational() * (*i).getRational())); 00224 ++i; 00225 for(; i != e.end(); ++i) { 00226 mulKids.push_back(*i); 00227 } 00228 return simplifiedMultExpr(mulKids); 00229 } 00230 00231 Expr ArithTheoremProducer3::canonMultConstPlus(const Expr & e1, 00232 const Expr & e2) 00233 { 00234 DebugAssert(e1.isRational() && e2.getKind() == PLUS && 00235 e2.arity() > 0, ""); 00236 // e1 is a rational 00237 // e2 is of the form (PLUS rational sterm1 sterm2 ...) 00238 // assume that e2 is already in canonic form 00239 std::vector<Theorem> thmPlusVector; 00240 Expr::iterator i = e2.begin(); 00241 for(; i!= e2.end(); ++i) { 00242 thmPlusVector.push_back(canonMultMtermMterm(e1*(*i))); 00243 } 00244 00245 Theorem thmPlus1 = 00246 d_theoryArith->substitutivityRule(e2.getOp(), thmPlusVector); 00247 return thmPlus1.getRHS(); 00248 } 00249 00250 Expr ArithTheoremProducer3::canonMultPowPow(const Expr & e1, 00251 const Expr & e2) 00252 { 00253 DebugAssert(e1.getKind() == POW && e2.getKind() == POW, ""); 00254 // (POW r1 leaf1) * (POW r2 leaf2) 00255 Expr leaf1 = e1[1]; 00256 Expr leaf2 = e2[1]; 00257 Expr can_expr; 00258 if (leaf1 == leaf2) { 00259 Rational rsum = e1[0].getRational() + e2[0].getRational(); 00260 if (rsum == 0) { 00261 return rat(1); 00262 } 00263 else if (rsum == 1) { 00264 return leaf1; 00265 } 00266 else 00267 { 00268 return powExpr(rat(rsum), leaf1); 00269 } 00270 } 00271 else 00272 { 00273 std::vector<Expr> mulKids; 00274 mulKids.push_back(rat(1)); 00275 // the leafs should be put in decreasing order 00276 if (leaf1 < leaf2) { 00277 mulKids.push_back(e2); 00278 mulKids.push_back(e1); 00279 } 00280 else 00281 { 00282 mulKids.push_back(e1); 00283 mulKids.push_back(e2); 00284 } 00285 // FIXME: don't really need to simplify, just wrap up a MULT? 00286 return simplifiedMultExpr(mulKids); 00287 } 00288 } 00289 00290 Expr ArithTheoremProducer3::canonMultPowLeaf(const Expr & e1, 00291 const Expr & e2) 00292 { 00293 DebugAssert(e1.getKind() == POW, ""); 00294 // (POW r1 leaf1) * leaf2 00295 Expr leaf1 = e1[1]; 00296 Expr leaf2 = e2; 00297 Expr can_expr; 00298 if (leaf1 == leaf2) { 00299 Rational rsum = e1[0].getRational() + 1; 00300 if (rsum == 0) { 00301 return rat(1); 00302 } 00303 else if (rsum == 1) { 00304 return leaf1; 00305 } 00306 else 00307 { 00308 return powExpr(rat(rsum), leaf1); 00309 } 00310 } 00311 else 00312 { 00313 std::vector<Expr> mulKids; 00314 mulKids.push_back(rat(1)); 00315 // the leafs should be put in decreasing order 00316 if (leaf1 < leaf2) { 00317 mulKids.push_back(e2); 00318 mulKids.push_back(e1); 00319 } 00320 else 00321 { 00322 mulKids.push_back(e1); 00323 mulKids.push_back(e2); 00324 } 00325 return simplifiedMultExpr(mulKids); 00326 } 00327 } 00328 00329 Expr ArithTheoremProducer3::canonMultLeafLeaf(const Expr & e1, 00330 const Expr & e2) 00331 { 00332 // leaf1 * leaf2 00333 Expr leaf1 = e1; 00334 Expr leaf2 = e2; 00335 Expr can_expr; 00336 if (leaf1 == leaf2) { 00337 return powExpr(rat(2), leaf1); 00338 } 00339 else 00340 { 00341 std::vector<Expr> mulKids; 00342 mulKids.push_back(rat(1)); 00343 // the leafs should be put in decreasing order 00344 if (leaf1 < leaf2) { 00345 mulKids.push_back(e2); 00346 mulKids.push_back(e1); 00347 } 00348 else 00349 { 00350 mulKids.push_back(e1); 00351 mulKids.push_back(e2); 00352 } 00353 return simplifiedMultExpr(mulKids); 00354 } 00355 } 00356 00357 Expr ArithTheoremProducer3::canonMultLeafOrPowMult(const Expr & e1, 00358 const Expr & e2) 00359 { 00360 DebugAssert(e2.getKind() == MULT, ""); 00361 // Leaf * (MULT rat1 mterm1 ...) 00362 // (POW r1 leaf1) * (MULT rat1 mterm1 ...) where 00363 // each mterm is a leaf or (POW r leaf). Furthermore the leafs 00364 // in the mterms are in descending order 00365 Expr leaf1 = e1.getKind() == POW ? e1[1] : e1; 00366 std::vector<Expr> mulKids; 00367 DebugAssert(e2.arity() > 1, "MULT expr must have arity 2 or more"); 00368 Expr::iterator i = e2.begin(); 00369 // push the rational 00370 mulKids.push_back(*i); 00371 ++i; 00372 // Now i points to the first mterm 00373 for(; i != e2.end(); ++i) { 00374 Expr leaf2 = ((*i).getKind() == POW) ? (*i)[1] : (*i); 00375 if (leaf1 == leaf2) { 00376 Rational r1 = e1.getKind() == POW ? e1[0].getRational() : 1; 00377 Rational r2 = 00378 ((*i).getKind() == POW ? (*i)[0].getRational() : 1); 00379 // if r1 + r2 == 0 then it is the case of x^n * x^{-n} 00380 // So, nothing needs to be added 00381 if (r1 + r2 != 0) { 00382 if (r1 + r2 == 1) { 00383 mulKids.push_back(leaf1); 00384 } 00385 else 00386 { 00387 mulKids.push_back(powExpr(rat(r1 + r2), leaf1)); 00388 } 00389 } 00390 break; 00391 } 00392 // This ensures that the leaves in the mterms are also arranged 00393 // in decreasing order 00394 // Note that this will need to be changed if we want the order to 00395 // be increasing order. 00396 else if (leaf2 < leaf1) { 00397 mulKids.push_back(e1); 00398 mulKids.push_back(*i); 00399 break; 00400 } 00401 else // leaf1 < leaf2 00402 mulKids.push_back(*i); 00403 } 00404 if (i == e2.end()) { 00405 mulKids.push_back(e1); 00406 } 00407 else 00408 { 00409 // e1 and *i have already been added 00410 for (++i; i != e2.end(); ++i) { 00411 mulKids.push_back(*i); 00412 } 00413 } 00414 return simplifiedMultExpr(mulKids); 00415 } 00416 00417 // Local class for ordering monomials; note, that it flips the 00418 // ordering given by greaterthan(), to sort in ascending order. 00419 class MonomialLess { 00420 public: 00421 bool operator()(const Expr& e1, const Expr& e2) const { 00422 return ArithTheoremProducer3::greaterthan(e1,e2); 00423 } 00424 }; 00425 00426 typedef map<Expr,Rational,MonomialLess> MonomMap; 00427 00428 Expr 00429 ArithTheoremProducer3::canonCombineLikeTerms(const std::vector<Expr> & sumExprs) 00430 { 00431 Rational constant = 0; 00432 MonomMap sumHashMap; 00433 vector<Expr> sumKids; 00434 00435 // Add each distinct mterm (not including the rational) into 00436 // an appropriate hash map entry 00437 std::vector<Expr>::const_iterator i = sumExprs.begin(); 00438 for (; i != sumExprs.end(); ++i) { 00439 Expr mul = *i; 00440 if (mul.isRational()) { 00441 constant = constant + mul.getRational(); 00442 } 00443 else { 00444 switch (mul.getKind()) { 00445 case MULT: { 00446 std::vector<Expr> mulKids; 00447 DebugAssert(mul.arity() > 1 && mul[0].isRational(),""); 00448 mulKids.push_back(rat(1)); 00449 Expr::iterator j = mul.begin(); 00450 ++j; 00451 for (; j!= mul.end(); ++j) { 00452 mulKids.push_back(*j); 00453 } 00454 00455 // make sure that tempExpr is also in canonic form 00456 Expr tempExpr = mulKids.size() > 2 ? multExpr(mulKids): mulKids[1]; 00457 MonomMap::iterator i=sumHashMap.find(tempExpr); 00458 if (i == sumHashMap.end()) { 00459 sumHashMap[tempExpr] = mul[0].getRational(); 00460 } 00461 else { 00462 (*i).second += mul[0].getRational(); 00463 } 00464 } 00465 break; 00466 default: { 00467 MonomMap::iterator i=sumHashMap.find(mul); 00468 // covers the case of POW, leaf 00469 if (i == sumHashMap.end()) { 00470 sumHashMap[mul] = 1; 00471 } 00472 else { 00473 (*i).second += 1; 00474 } 00475 break; 00476 } 00477 } 00478 } 00479 } 00480 // Now transfer to sumKids 00481 sumKids.push_back(rat(constant)); 00482 MonomMap::iterator j = sumHashMap.begin(), jend=sumHashMap.end(); 00483 for(; j != jend; ++j) { 00484 if ((*j).second != 0) 00485 sumKids.push_back 00486 (canonMultMtermMterm(rat((*j).second) * (*j).first).getRHS()); 00487 } 00488 00489 /* 00490 for (unsigned k = 0; k < sumKids.size(); ++k) 00491 { 00492 cout << "sumKids[" << k << "] = " << sumKids[k].toString() << endl; 00493 } 00494 */ 00495 00496 // The ordering in map guarantees the correct order; no need to sort 00497 00498 // std::sort(sumKids.begin(), sumKids.end(), greaterthan); 00499 00500 if ((constant == 0) && (sumKids.size() == 2)) { 00501 return sumKids[1]; 00502 } 00503 else if (sumKids.size() == 1) { 00504 return sumKids[0]; 00505 } 00506 else 00507 return plusExpr(sumKids); 00508 } 00509 00510 Expr ArithTheoremProducer3::canonMultLeafOrPowOrMultPlus(const Expr & e1, 00511 const Expr & e2) 00512 { 00513 DebugAssert(e2.getKind() == PLUS, ""); 00514 // Leaf * (PLUS rational sterm1 ...) 00515 // or 00516 // (POW n1 x1) * (PLUS rational sterm1 ...) 00517 // or 00518 // (MULT r1 m1 m2 ...) * (PLUS rational sterm1 ...) 00519 // assume that e1 and e2 are themselves canonized 00520 std::vector<Expr> sumExprs; 00521 // Multiply each term in turn. 00522 Expr::iterator i = e2.begin(); 00523 for (; i != e2.end(); ++i) { 00524 sumExprs.push_back(canonMultMtermMterm(e1 * (*i)).getRHS()); 00525 } 00526 return canonCombineLikeTerms(sumExprs); 00527 } 00528 00529 Expr ArithTheoremProducer3::canonMultPlusPlus(const Expr & e1, 00530 const Expr & e2) 00531 { 00532 DebugAssert(e1.getKind() == PLUS && e2.getKind() == PLUS, ""); 00533 // (PLUS r1 .... ) * (PLUS r1' ...) 00534 // assume that e1 and e2 are themselves canonized 00535 00536 std::vector<Expr> sumExprs; 00537 // Multiply each term in turn. 00538 Expr::iterator i = e1.begin(); 00539 for (; i != e1.end(); ++i) { 00540 Expr::iterator j = e2.begin(); 00541 for (; j != e2.end(); ++j) { 00542 sumExprs.push_back(canonMultMtermMterm((*i) * (*j)).getRHS()); 00543 } 00544 } 00545 return canonCombineLikeTerms(sumExprs); 00546 } 00547 00548 00549 00550 // The following produces a Theorem which is the result of multiplication 00551 // of two canonized mterms. e = e1*e2 00552 Theorem 00553 ArithTheoremProducer3::canonMultMtermMterm(const Expr& e) 00554 { 00555 if(CHECK_PROOFS) { 00556 CHECK_SOUND(isMult(e) && e.arity() == 2, 00557 "canonMultMtermMterm: e = "+e.toString()); 00558 } 00559 Proof pf; 00560 Expr rhs; 00561 const Expr& e1 = e[0]; 00562 const Expr& e2 = e[1]; 00563 string cmmm = "canon_mult_mterm_mterm"; 00564 00565 if (e1.isRational()) { 00566 // e1 is a Rational 00567 const Rational& c = e1.getRational(); 00568 if (c == 0) 00569 return canonMultZero(e2); 00570 else if (c == 1) 00571 return canonMultOne(e2); 00572 else { 00573 switch (e2.getKind()) { 00574 case RATIONAL_EXPR : 00575 // rat * rat 00576 return canonMultConstConst(e1,e2); 00577 break; 00578 // TODO case of leaf 00579 case POW: 00580 // rat * (POW rat leaf) 00581 // nothing to simplify 00582 return d_theoryArith->reflexivityRule (e); 00583 00584 break; 00585 case MULT: 00586 rhs = canonMultConstMult(e1,e2); 00587 if(withProof()) pf = newPf(cmmm,e,rhs); 00588 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); 00589 break; 00590 case PLUS: 00591 rhs = canonMultConstPlus(e1,e2); 00592 if(withProof()) pf = newPf(cmmm,e,rhs); 00593 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); 00594 break; 00595 default: 00596 // TODO: I am going to assume that this is just a leaf 00597 // i.e., a variable or term from another theory 00598 return d_theoryArith->reflexivityRule(e); 00599 break; 00600 } 00601 } 00602 } 00603 else if (e1.getKind() == POW) { 00604 switch (e2.getKind()) { 00605 case RATIONAL_EXPR: 00606 // switch the order of the two arguments 00607 return canonMultMtermMterm(e2 * e1); 00608 break; 00609 case POW: 00610 rhs = canonMultPowPow(e1,e2); 00611 if(withProof()) pf = newPf(cmmm,e,rhs); 00612 return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); 00613 break; 00614 case MULT: 00615 rhs = canonMultLeafOrPowMult(e1,e2); 00616 if(withProof()) pf = newPf(cmmm,e,rhs); 00617 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); 00618 break; 00619 case PLUS: 00620 rhs = canonMultLeafOrPowOrMultPlus(e1,e2); 00621 if(withProof()) pf = newPf(cmmm,e,rhs); 00622 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); 00623 break; 00624 default: 00625 rhs = canonMultPowLeaf(e1,e2); 00626 if(withProof()) pf = newPf(cmmm,e,rhs); 00627 return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); 00628 break; 00629 } 00630 } 00631 else if (e1.getKind() == MULT) { 00632 switch (e2.getKind()) { 00633 case RATIONAL_EXPR: 00634 case POW: 00635 // switch the order of the two arguments 00636 return canonMultMtermMterm(e2 * e1); 00637 break; 00638 case MULT: 00639 { 00640 // (Mult r m1 m2 ...) (Mult r' m1' m2' ...) 00641 Expr result = e2; 00642 Expr::iterator i = e1.begin(); 00643 for (; i != e1.end(); ++i) { 00644 result = canonMultMtermMterm((*i) * result).getRHS(); 00645 } 00646 if(withProof()) pf = newPf(cmmm,e,result); 00647 return newRWTheorem(e, result, Assumptions::emptyAssump(), pf); 00648 } 00649 break; 00650 case PLUS: 00651 rhs = canonMultLeafOrPowOrMultPlus(e1,e2); 00652 if(withProof()) pf = newPf(cmmm,e,rhs); 00653 return newRWTheorem(e,rhs, Assumptions::emptyAssump(), pf); 00654 break; 00655 default: 00656 // leaf 00657 // switch the order of the two arguments 00658 return canonMultMtermMterm(e2 * e1); 00659 break; 00660 } 00661 } 00662 else if (e1.getKind() == PLUS) { 00663 switch (e2.getKind()) { 00664 case RATIONAL_EXPR: 00665 case POW: 00666 case MULT: 00667 // switch the order of the two arguments 00668 return canonMultMtermMterm(e2 * e1); 00669 break; 00670 case PLUS: 00671 rhs = canonMultPlusPlus(e1,e2); 00672 if(withProof()) pf = newPf(cmmm,e,rhs); 00673 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); 00674 break; 00675 default: 00676 // leaf 00677 // switch the order of the two arguments 00678 return canonMultMtermMterm(e2 * e1); 00679 break; 00680 } 00681 } 00682 else { 00683 // leaf 00684 switch (e2.getKind()) { 00685 case RATIONAL_EXPR: 00686 // switch the order of the two arguments 00687 return canonMultMtermMterm(e2 * e1); 00688 break; 00689 case POW: 00690 rhs = canonMultPowLeaf(e2,e1); 00691 if(withProof()) pf = newPf(cmmm,e,rhs); 00692 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); 00693 break; 00694 case MULT: 00695 rhs = canonMultLeafOrPowMult(e1,e2);; 00696 if(withProof()) pf = newPf(cmmm,e,rhs); 00697 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); 00698 break; 00699 case PLUS: 00700 rhs = canonMultLeafOrPowOrMultPlus(e1,e2); 00701 if(withProof()) pf = newPf(cmmm,e,rhs); 00702 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); 00703 break; 00704 default: 00705 // leaf * leaf 00706 rhs = canonMultLeafLeaf(e1,e2); 00707 if(withProof()) pf = newPf(cmmm,e,rhs); 00708 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); 00709 break; 00710 } 00711 } 00712 FatalAssert(false, "Unreachable"); 00713 return newRWTheorem(e, rhs, Assumptions::emptyAssump(), pf); 00714 } 00715 00716 // (PLUS expr1 expr2 ...) where each expr is itself in canonic form 00717 Theorem 00718 ArithTheoremProducer3::canonPlus(const Expr& e) 00719 { 00720 Proof pf; 00721 00722 if (withProof()) { 00723 pf = newPf("canon_plus", e); 00724 } 00725 DebugAssert(e.getKind() == PLUS, ""); 00726 00727 // First flatten the PLUS 00728 00729 std::vector<Expr> sumKids; 00730 Expr::iterator i = e.begin(); 00731 for(; i != e.end(); ++i) { 00732 if ((*i).getKind() != PLUS) { 00733 sumKids.push_back(*i); 00734 } 00735 else 00736 { 00737 Expr::iterator j = (*i).begin(); 00738 for(; j != (*i).end(); ++j) 00739 sumKids.push_back(*j); 00740 } 00741 } 00742 Expr val = canonCombineLikeTerms(sumKids); 00743 if (withProof()) { 00744 pf = newPf("canon_plus", e, val); 00745 } 00746 return newRWTheorem(e, val, Assumptions::emptyAssump(), pf); 00747 } 00748 00749 // (MULT expr1 expr2 ...) where each expr is itself in canonic form 00750 Theorem 00751 ArithTheoremProducer3::canonMult(const Expr& e) 00752 { 00753 Proof pf; 00754 DebugAssert(e.getKind() == MULT && e.arity() > 1, ""); 00755 Expr::iterator i = e.begin(); 00756 Expr result = *i; 00757 ++i; 00758 for (; i != e.end(); ++i) { 00759 result = canonMultMtermMterm(result * (*i)).getRHS(); 00760 } 00761 if (withProof()) { 00762 pf = newPf("canon_mult", e,result); 00763 } 00764 return newRWTheorem(e, result, Assumptions::emptyAssump(), pf); 00765 } 00766 00767 00768 Theorem 00769 ArithTheoremProducer3::canonInvertConst(const Expr& e) 00770 { 00771 if(CHECK_PROOFS) 00772 CHECK_SOUND(isRational(e), "expecting a rational: e = "+e.toString()); 00773 00774 Proof pf; 00775 00776 if (withProof()) { 00777 pf = newPf("canon_invert_const", e); 00778 } 00779 const Rational& er = e.getRational(); 00780 return newRWTheorem((rat(1)/e), rat(er==0? 0 : (1/er)), Assumptions::emptyAssump(), pf); 00781 } 00782 00783 00784 Theorem 00785 ArithTheoremProducer3::canonInvertLeaf(const Expr& e) 00786 { 00787 Proof pf; 00788 00789 if (withProof()) { 00790 pf = newPf("canon_invert_leaf", e); 00791 } 00792 return newRWTheorem((rat(1)/e), powExpr(rat(-1), e), Assumptions::emptyAssump(), pf); 00793 } 00794 00795 00796 Theorem 00797 ArithTheoremProducer3::canonInvertPow(const Expr& e) 00798 { 00799 DebugAssert(e.getKind() == POW, "expecting a rational"+e[0].toString()); 00800 00801 Proof pf; 00802 00803 if (withProof()) { 00804 pf = newPf("canon_invert_pow", e); 00805 } 00806 if (e[0].getRational() == -1) 00807 return newRWTheorem((rat(1)/e), e[1], Assumptions::emptyAssump(), pf); 00808 else 00809 return newRWTheorem((rat(1)/e), 00810 powExpr(rat(-e[0].getRational()), e), 00811 Assumptions::emptyAssump(), 00812 pf); 00813 } 00814 00815 Theorem 00816 ArithTheoremProducer3::canonInvertMult(const Expr& e) 00817 { 00818 DebugAssert(e.getKind() == MULT, "expecting a rational"+e[0].toString()); 00819 00820 Proof pf; 00821 00822 if (withProof()) { 00823 pf = newPf("canon_invert_mult", e); 00824 } 00825 00826 DebugAssert(e.arity() > 1, "MULT should have arity > 1"+e.toString()); 00827 Expr result = canonInvert(e[0]).getRHS(); 00828 for (int i = 1; i < e.arity(); ++i) { 00829 result = 00830 canonMultMtermMterm(result * canonInvert(e[i]).getRHS()).getRHS(); 00831 } 00832 return newRWTheorem((rat(1)/e), result, Assumptions::emptyAssump(), pf); 00833 } 00834 00835 00836 // Given an expression e in Canonic form generate 1/e in canonic form 00837 // This function assumes that e is not a PLUS expression 00838 Theorem 00839 ArithTheoremProducer3::canonInvert(const Expr& e) 00840 { 00841 DebugAssert(e.getKind() != PLUS, 00842 "Cannot do inverse on a PLUS"+e.toString()); 00843 switch (e.getKind()) { 00844 case RATIONAL_EXPR: 00845 return canonInvertConst(e); 00846 break; 00847 case POW: 00848 return canonInvertPow(e); 00849 break; 00850 case MULT: 00851 return canonInvertMult(e); 00852 break; 00853 default: 00854 // leaf 00855 return canonInvertLeaf(e); 00856 break; 00857 } 00858 } 00859 00860 00861 Theorem ArithTheoremProducer3::moveSumConstantRight(const Expr& e) { 00862 00863 // Check soundness of the rule if necessary 00864 if (CHECK_PROOFS) { 00865 CHECK_SOUND(isIneq(e) || e.isEq(), "moveSumConstantRight: input must be Eq or Ineq: " + e.toString()); 00866 CHECK_SOUND(isRational(e[0]) || isPlus(e[0]), "moveSumConstantRight: left side must be a canonised sum: " + e.toString()); 00867 CHECK_SOUND(isRational(e[1]) && e[1].getRational() == 0, "moveSumConstantRight: right side must be 0: " + e.toString()); 00868 } 00869 00870 // The rational constant of the sum 00871 Rational r = 0; 00872 00873 // The right hand side of the expression 00874 Expr right = e[0]; 00875 00876 // The vector of sum terms 00877 vector<Expr> sumTerms; 00878 00879 // Get all the non rational children and 00880 if (!right.isRational()) 00881 for(Expr::iterator it = right.begin(); it != right.end(); it ++) { 00882 // If the term is rational then add the rational number to r 00883 if ((*it).isRational()) r = r + (*it).getRational(); 00884 // Otherwise just add the sumTerm to the sumTerms 00885 else sumTerms.push_back((*it)); 00886 } 00887 00888 // Setup the new expression 00889 Expr transformed; 00890 if (sumTerms.size() > 1) 00891 // If the number of summands is > 1 return the sum of them 00892 transformed = Expr(e.getKind(), plusExpr(sumTerms), rat(-r)); 00893 else 00894 // Otherwise return the one summand as itself 00895 transformed = Expr(e.getKind(), sumTerms[0], rat(-r)); 00896 00897 00898 // If proof is needed set it up 00899 Proof pf; 00900 if (withProof()) pf = newPf("arithm_sum_constant_right", e); 00901 00902 // Retrun the theorem explaining the transformation 00903 return newRWTheorem(e, transformed, Assumptions::emptyAssump(), pf); 00904 } 00905 00906 Theorem 00907 ArithTheoremProducer3::canonDivide(const Expr& e) 00908 { 00909 DebugAssert(e.getKind() == DIVIDE, "Expecting Divide"+e.toString()); 00910 Proof pf; 00911 00912 if (withProof()) { 00913 pf = newPf("canon_invert_divide", e); 00914 } 00915 00916 Theorem thm = newRWTheorem(e, e[0]*(canonInvert(e[1]).getRHS()), Assumptions::emptyAssump(), pf); 00917 00918 return d_theoryArith->transitivityRule(thm, canonMult(thm.getRHS())); 00919 } 00920 00921 00922 // Rules for multiplication 00923 // t*c ==> c*t, takes constant c and term t 00924 Theorem 00925 ArithTheoremProducer3::canonMultTermConst(const Expr& c, const Expr& t) { 00926 Proof pf; 00927 if(CHECK_PROOFS) { 00928 CHECK_SOUND(isRational(c), 00929 CLASS_NAME "::canonMultTermConst:\n " 00930 "c is not a constant: " + c.toString()); 00931 } 00932 if(withProof()) pf = newPf("canon_mult_term_const", c, t); 00933 return newRWTheorem((t*c), (c*t), Assumptions::emptyAssump(), pf); 00934 } 00935 00936 // Rules for multiplication 00937 // t1*t2 ==> Error, takes t1 and t2 where both are non-constants 00938 Theorem 00939 ArithTheoremProducer3::canonMultTerm1Term2(const Expr& t1, const Expr& t2) { 00940 // Proof pf; 00941 // if(withProof()) pf = newPf("canon_mult_term1_term2", t1, t2); 00942 if(CHECK_PROOFS) { 00943 CHECK_SOUND(false, "Fatal Error: We don't support multiplication" 00944 "of two non constant terms at this time " 00945 + t1.toString() + " and " + t2.toString()); 00946 } 00947 return Theorem(); 00948 } 00949 00950 // Rules for multiplication 00951 // 0*x = 0, takes x 00952 Theorem ArithTheoremProducer3::canonMultZero(const Expr& e) { 00953 Proof pf; 00954 if(withProof()) pf = newPf("canon_mult_zero", e); 00955 return newRWTheorem((rat(0)*e), rat(0), Assumptions::emptyAssump(), pf); 00956 } 00957 00958 // Rules for multiplication 00959 // 1*x ==> x, takes x 00960 Theorem ArithTheoremProducer3::canonMultOne(const Expr& e) { 00961 Proof pf; 00962 if(withProof()) pf = newPf("canon_mult_one", e); 00963 return newRWTheorem((rat(1)*e), e, Assumptions::emptyAssump(), pf); 00964 } 00965 00966 // Rules for multiplication 00967 // c1*c2 ==> c', takes constant c1*c2 00968 Theorem 00969 ArithTheoremProducer3::canonMultConstConst(const Expr& c1, const Expr& c2) { 00970 Proof pf; 00971 if(CHECK_PROOFS) { 00972 CHECK_SOUND(isRational(c1), 00973 CLASS_NAME "::canonMultConstConst:\n " 00974 "c1 is not a constant: " + c1.toString()); 00975 CHECK_SOUND(isRational(c2), 00976 CLASS_NAME "::canonMultConstConst:\n " 00977 "c2 is not a constant: " + c2.toString()); 00978 } 00979 if(withProof()) pf = newPf("canon_mult_const_const", c1, c2); 00980 return 00981 newRWTheorem((c1*c2), rat(c1.getRational()*c2.getRational()), Assumptions::emptyAssump(), pf); 00982 } 00983 00984 // Rules for multiplication 00985 // c1*(c2*t) ==> c'*t, takes c1 and c2 and t 00986 Theorem 00987 ArithTheoremProducer3::canonMultConstTerm(const Expr& c1, 00988 const Expr& c2,const Expr& t) { 00989 Proof pf; 00990 if(CHECK_PROOFS) { 00991 CHECK_SOUND(isRational(c1), 00992 CLASS_NAME "::canonMultConstTerm:\n " 00993 "c1 is not a constant: " + c1.toString()); 00994 CHECK_SOUND(isRational(c2), 00995 CLASS_NAME "::canonMultConstTerm:\n " 00996 "c2 is not a constant: " + c2.toString()); 00997 } 00998 00999 if(withProof()) pf = newPf("canon_mult_const_term", c1, c2, t); 01000 return 01001 newRWTheorem(c1*(c2*t), rat(c1.getRational()*c2.getRational())*t, Assumptions::emptyAssump(), pf); 01002 } 01003 01004 // Rules for multiplication 01005 // c1*(+ c2 v1 ...) ==> (+ c1c2 c1v1 ...), takes c1 and the sum 01006 Theorem 01007 ArithTheoremProducer3::canonMultConstSum(const Expr& c1, const Expr& sum) { 01008 Proof pf; 01009 std::vector<Expr> sumKids; 01010 01011 if(CHECK_PROOFS) { 01012 CHECK_SOUND(isRational(c1), 01013 CLASS_NAME "::canonMultConstTerm:\n " 01014 "c1 is not a constant: " + c1.toString()); 01015 CHECK_SOUND(PLUS == sum.getKind(), 01016 CLASS_NAME "::canonMultConstTerm:\n " 01017 "the kind must be a PLUS: " + sum.toString()); 01018 } 01019 Expr::iterator i = sum.begin(); 01020 for(; i != sum.end(); ++i) 01021 sumKids.push_back(c1*(*i)); 01022 Expr ret = plusExpr(sumKids); 01023 if(withProof()) pf = newPf("canon_mult_const_sum", c1, sum, ret); 01024 return newRWTheorem((c1*sum),ret , Assumptions::emptyAssump(), pf); 01025 } 01026 01027 01028 // c^n = c' (compute the constant power expression) 01029 Theorem 01030 ArithTheoremProducer3::canonPowConst(const Expr& e) { 01031 if(CHECK_PROOFS) { 01032 CHECK_SOUND(e.getKind() == POW && e.arity() == 2 01033 && e[0].isRational() && e[1].isRational(), 01034 "ArithTheoremProducer3::canonPowConst("+e.toString()+")"); 01035 } 01036 const Rational& p = e[0].getRational(); 01037 const Rational& base = e[1].getRational(); 01038 if(CHECK_PROOFS) { 01039 CHECK_SOUND(p.isInteger(), 01040 "ArithTheoremProducer3::canonPowConst("+e.toString()+")"); 01041 } 01042 Expr res; 01043 if (base == 0 && p < 0) { 01044 res = rat(0); 01045 } 01046 else res = rat(pow(p, base)); 01047 Proof pf; 01048 if(withProof()) 01049 pf = newPf("canon_pow_const", e); 01050 return newRWTheorem(e, res, Assumptions::emptyAssump(), pf); 01051 } 01052 01053 01054 // Rules for addition 01055 // flattens the input. accepts a PLUS expr 01056 Theorem 01057 ArithTheoremProducer3::canonFlattenSum(const Expr& e) { 01058 Proof pf; 01059 std::vector<Expr> sumKids; 01060 if(CHECK_PROOFS) { 01061 CHECK_SOUND(PLUS == e.getKind(), 01062 CLASS_NAME "::canonFlattenSum:\n" 01063 "input must be a PLUS:" + e.toString()); 01064 } 01065 01066 Expr::iterator i = e.begin(); 01067 for(; i != e.end(); ++i){ 01068 if (PLUS != (*i).getKind()) 01069 sumKids.push_back(*i); 01070 else { 01071 Expr::iterator j = (*i).begin(); 01072 for(; j != (*i).end(); ++j) 01073 sumKids.push_back(*j); 01074 } 01075 } 01076 Expr ret = plusExpr(sumKids); 01077 if(withProof()) pf = newPf("canon_flatten_sum", e,ret); 01078 return newRWTheorem(e,ret, Assumptions::emptyAssump(), pf); 01079 } 01080 01081 // Rules for addition 01082 // combine like terms. accepts a flattened PLUS expr 01083 Theorem 01084 ArithTheoremProducer3::canonComboLikeTerms(const Expr& e) { 01085 Proof pf; 01086 std::vector<Expr> sumKids; 01087 ExprMap<Rational> sumHashMap; 01088 Rational constant = 0; 01089 01090 if(CHECK_PROOFS) { 01091 Expr::iterator k = e.begin(); 01092 for(; k != e.end(); ++k) 01093 CHECK_SOUND(!isPlus(*k), 01094 CLASS_NAME "::canonComboLikeTerms:\n" 01095 "input must be a flattened PLUS:" + k->toString()); 01096 } 01097 Expr::iterator i = e.begin(); 01098 for(; i != e.end(); ++i){ 01099 if(i->isRational()) 01100 constant = constant + i->getRational(); 01101 else { 01102 if (!isMult(*i)) { 01103 if(0 == sumHashMap.count((*i))) 01104 sumHashMap[*i] = 1; 01105 else 01106 sumHashMap[*i] += 1; 01107 } 01108 else { 01109 if(0 == sumHashMap.count((*i)[1])) 01110 sumHashMap[(*i)[1]] = (*i)[0].getRational(); 01111 else 01112 sumHashMap[(*i)[1]] = sumHashMap[(*i)[1]] + (*i)[0].getRational(); 01113 } 01114 } 01115 } 01116 01117 sumKids.push_back(rat(constant)); 01118 ExprMap<Rational>::iterator j = sumHashMap.begin(); 01119 for(; j != sumHashMap.end(); ++j) { 01120 if(0 == (*j).second) 01121 ;//do nothing 01122 else if (1 == (*j).second) 01123 sumKids.push_back((*j).first); 01124 else 01125 sumKids.push_back(rat((*j).second) * (*j).first); 01126 } 01127 01128 //constant is same as sumKids[0]. 01129 //corner cases: "0 + monomial" and "constant"(no monomials) 01130 01131 Expr ret; 01132 if(2 == sumKids.size() && 0 == constant) ret = sumKids[1]; 01133 else if (1 == sumKids.size()) ret = sumKids[0]; 01134 else ret = plusExpr(sumKids); 01135 01136 if(withProof()) pf = newPf("canon_combo_like_terms",e,ret); 01137 return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); 01138 } 01139 01140 01141 // 0 = (* e1 e2 ...) <=> 0 = e1 OR 0 = e2 OR ... 01142 Theorem ArithTheoremProducer3::multEqZero(const Expr& expr) 01143 { 01144 if (CHECK_PROOFS) { 01145 CHECK_SOUND(expr.isEq() && expr[0].isRational() && 01146 expr[0].getRational() == 0 && 01147 isMult(expr[1]) && expr[1].arity() > 1, 01148 "multEqZero invariant violated"+expr.toString()); 01149 } 01150 Proof pf; 01151 vector<Expr> kids; 01152 Expr::iterator i = expr[1].begin(), iend = expr[1].end(); 01153 for (; i != iend; ++i) { 01154 kids.push_back(rat(0).eqExpr(*i)); 01155 } 01156 if (withProof()) { 01157 pf = newPf("multEqZero", expr); 01158 } 01159 return newRWTheorem(expr, Expr(OR, kids), Assumptions::emptyAssump(), pf); 01160 } 01161 01162 01163 // 0 = (^ c x) <=> false if c <=0 01164 // <=> 0 = x if c > 0 01165 Theorem ArithTheoremProducer3::powEqZero(const Expr& expr) 01166 { 01167 if (CHECK_PROOFS) { 01168 CHECK_SOUND(expr.isEq() && expr[0].isRational() && 01169 expr[0].getRational() == 0 && 01170 isPow(expr[1]) && expr[1].arity() == 2 && 01171 expr[1][0].isRational(), 01172 "powEqZero invariant violated"+expr.toString()); 01173 } 01174 Proof pf; 01175 if (withProof()) { 01176 pf = newPf("powEqZero", expr); 01177 } 01178 Rational r = expr[1][0].getRational(); 01179 Expr res; 01180 if (r <= 0) { 01181 res = d_em->falseExpr(); 01182 } 01183 else { 01184 res = rat(0).eqExpr(expr[1][1]); 01185 } 01186 return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); 01187 } 01188 01189 01190 // x^n = y^n <=> x = y (if n is odd) 01191 // x^n = y^n <=> x = y OR x = -y (if n is even) 01192 Theorem ArithTheoremProducer3::elimPower(const Expr& expr) 01193 { 01194 if (CHECK_PROOFS) { 01195 CHECK_SOUND(expr.isEq() && isPow(expr[0]) && 01196 isPow(expr[1]) && 01197 isIntegerConst(expr[0][0]) && 01198 expr[0][0].getRational() > 0 && 01199 expr[0][0] == expr[1][0], 01200 "elimPower invariant violated"+expr.toString()); 01201 } 01202 Proof pf; 01203 if (withProof()) { 01204 pf = newPf("elimPower", expr); 01205 } 01206 Rational r = expr[0][0].getRational(); 01207 Expr res = expr[0][1].eqExpr(expr[1][1]); 01208 if (r % 2 == 0) { 01209 res = res.orExpr(expr[0][1].eqExpr(-expr[1][1])); 01210 } 01211 return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); 01212 } 01213 01214 01215 // x^n = c <=> x = root (if n is odd and root^n = c) 01216 // x^n = c <=> x = root OR x = -root (if n is even and root^n = c) 01217 Theorem ArithTheoremProducer3::elimPowerConst(const Expr& expr, const Rational& root) 01218 { 01219 if (CHECK_PROOFS) { 01220 CHECK_SOUND(expr.isEq() && isPow(expr[0]) && 01221 isIntegerConst(expr[0][0]) && 01222 expr[0][0].getRational() > 0 && 01223 expr[1].isRational() && 01224 pow(expr[0][0].getRational(), root) == expr[1].getRational(), 01225 "elimPowerConst invariant violated"+expr.toString()); 01226 } 01227 Proof pf; 01228 if (withProof()) { 01229 pf = newPf("elimPowerConst", expr, rat(root)); 01230 } 01231 Rational r = expr[0][0].getRational(); 01232 Expr res = expr[0][1].eqExpr(rat(root)); 01233 if (r % 2 == 0) { 01234 res = res.orExpr(expr[0][1].eqExpr(rat(-root))); 01235 } 01236 return newRWTheorem(expr, res, Assumptions::emptyAssump(), pf); 01237 } 01238 01239 01240 // x^n = c <=> false (if n is even and c is negative) 01241 Theorem ArithTheoremProducer3::evenPowerEqNegConst(const Expr& expr) 01242 { 01243 if (CHECK_PROOFS) { 01244 CHECK_SOUND(expr.isEq() && isPow(expr[0]) && 01245 expr[1].isRational() && 01246 isIntegerConst(expr[0][0]) && 01247 expr[0][0].getRational() % 2 == 0 && 01248 expr[1].getRational() < 0, 01249 "evenPowerEqNegConst invariant violated"+expr.toString()); 01250 } 01251 Proof pf; 01252 if (withProof()) { 01253 pf = newPf("evenPowerEqNegConst", expr); 01254 } 01255 return newRWTheorem(expr, d_em->falseExpr(), Assumptions::emptyAssump(), pf); 01256 } 01257 01258 01259 // x^n = c <=> false (if x is an integer and c is not a perfect n power) 01260 Theorem ArithTheoremProducer3::intEqIrrational(const Expr& expr, const Theorem& isIntx) 01261 { 01262 if (CHECK_PROOFS) { 01263 CHECK_SOUND(expr.isEq() && isPow(expr[0]) && 01264 expr[1].isRational() && 01265 expr[1].getRational() != 0 && 01266 isIntegerConst(expr[0][0]) && 01267 expr[0][0].getRational() > 0 && 01268 ratRoot(expr[1].getRational(), expr[0][0].getRational().getUnsigned()) == 0, 01269 "intEqIrrational invariant violated"+expr.toString()); 01270 CHECK_SOUND(isIntPred(isIntx.getExpr()) && isIntx.getExpr()[0] == expr[0][1], 01271 "ArithTheoremProducer3::intEqIrrational:\n " 01272 "wrong integrality constraint:\n expr = " 01273 +expr.toString()+"\n isIntx = " 01274 +isIntx.getExpr().toString()); 01275 } 01276 const Assumptions& assump(isIntx.getAssumptionsRef()); 01277 Proof pf; 01278 if (withProof()) { 01279 pf = newPf("int_eq_irr", expr, isIntx.getProof()); 01280 } 01281 return newRWTheorem(expr, d_em->falseExpr(), assump, pf); 01282 } 01283 01284 01285 // e[0] kind e[1] <==> true when e[0] kind e[1], 01286 // false when e[0] !kind e[1], for constants only 01287 Theorem ArithTheoremProducer3::constPredicate(const Expr& e) { 01288 if(CHECK_PROOFS) { 01289 CHECK_SOUND(e.arity() == 2 && isRational(e[0]) && isRational(e[1]), 01290 CLASS_NAME "::constPredicate:\n " 01291 "non-const parameters: " + e.toString()); 01292 } 01293 Proof pf; 01294 bool result(false); 01295 int kind = e.getKind(); 01296 Rational r1 = e[0].getRational(), r2 = e[1].getRational(); 01297 switch(kind) { 01298 case EQ: 01299 result = (r1 == r2)?true : false; 01300 break; 01301 case LT: 01302 result = (r1 < r2)?true : false; 01303 break; 01304 case LE: 01305 result = (r1 <= r2)?true : false; 01306 break; 01307 case GT: 01308 result = (r1 > r2)?true : false; 01309 break; 01310 case GE: 01311 result = (r1 >= r2)?true : false; 01312 break; 01313 default: 01314 if(CHECK_PROOFS) { 01315 CHECK_SOUND(false, 01316 "ArithTheoremProducer3::constPredicate: wrong kind"); 01317 } 01318 break; 01319 } 01320 Expr ret = (result) ? d_em->trueExpr() : d_em->falseExpr(); 01321 if(withProof()) pf = newPf("const_predicate", e,ret); 01322 return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); 01323 } 01324 01325 // e[0] kind e[1] <==> 0 kind e[1] - e[0] 01326 Theorem ArithTheoremProducer3::rightMinusLeft(const Expr& e) 01327 { 01328 Proof pf; 01329 int kind = e.getKind(); 01330 if(CHECK_PROOFS) { 01331 CHECK_SOUND((EQ==kind) || 01332 (LT==kind) || 01333 (LE==kind) || 01334 (GE==kind) || 01335 (GT==kind), 01336 "ArithTheoremProducer3::rightMinusLeft: wrong kind"); 01337 } 01338 if(withProof()) pf = newPf("right_minus_left",e); 01339 return newRWTheorem(e, Expr(e.getOp(), rat(0), e[1] - e[0]), Assumptions::emptyAssump(), pf); 01340 } 01341 01342 01343 // e[0] kind e[1] <==> 0 kind e[1] - e[0] 01344 Theorem ArithTheoremProducer3::leftMinusRight(const Expr& e) 01345 { 01346 Proof pf; 01347 int kind = e.getKind(); 01348 if(CHECK_PROOFS) { 01349 CHECK_SOUND((EQ==kind) || 01350 (LT==kind) || 01351 (LE==kind) || 01352 (GE==kind) || 01353 (GT==kind), 01354 "ArithTheoremProducer3::rightMinusLeft: wrong kind"); 01355 } 01356 if(withProof()) pf = newPf("left_minus_right",e); 01357 return newRWTheorem(e, Expr(e.getOp(), e[0] - e[1], rat(0)), Assumptions::emptyAssump(), pf); 01358 } 01359 01360 01361 // x kind y <==> x + z kind y + z 01362 Theorem ArithTheoremProducer3::plusPredicate(const Expr& x, 01363 const Expr& y, 01364 const Expr& z, int kind) { 01365 if(CHECK_PROOFS) { 01366 CHECK_SOUND((EQ==kind) || 01367 (LT==kind) || 01368 (LE==kind) || 01369 (GE==kind) || 01370 (GT==kind), 01371 "ArithTheoremProducer3::plusPredicate: wrong kind"); 01372 } 01373 Proof pf; 01374 Expr left = Expr(kind, x, y); 01375 Expr right = Expr(kind, x + z, y + z); 01376 if(withProof()) pf = newPf("plus_predicate",left,right); 01377 return newRWTheorem(left, right, Assumptions::emptyAssump(), pf); 01378 } 01379 01380 // x = y <==> x * z = y * z 01381 Theorem ArithTheoremProducer3::multEqn(const Expr& x, 01382 const Expr& y, 01383 const Expr& z) { 01384 Proof pf; 01385 if(CHECK_PROOFS) 01386 CHECK_SOUND(z.isRational() && z.getRational() != 0, 01387 "ArithTheoremProducer3::multEqn(): multiplying equation by 0"); 01388 if(withProof()) pf = newPf("mult_eqn", x, y, z); 01389 return newRWTheorem(x.eqExpr(y), (x * z).eqExpr(y * z), Assumptions::emptyAssump(), pf); 01390 } 01391 01392 01393 // x = y <==> z=0 OR x * 1/z = y * 1/z 01394 Theorem ArithTheoremProducer3::divideEqnNonConst(const Expr& x, 01395 const Expr& y, 01396 const Expr& z) { 01397 Proof pf; 01398 if(withProof()) pf = newPf("mult_eqn_nonconst", x, y, z); 01399 return newRWTheorem(x.eqExpr(y), (z.eqExpr(rat(0))).orExpr((x / z).eqExpr(y / z)), 01400 Assumptions::emptyAssump(), pf); 01401 } 01402 01403 01404 // if z is +ve, return e[0] LT|LE|GT|GE e[1] <==> e[0]*z LT|LE|GT|GE e[1]*z 01405 // if z is -ve, return e[0] LT|LE|GT|GE e[1] <==> e[1]*z LT|LE|GT|GE e[0]*z 01406 Theorem ArithTheoremProducer3::multIneqn(const Expr& e, const Expr& z) 01407 { 01408 int kind = e.getKind(); 01409 01410 if(CHECK_PROOFS) { 01411 CHECK_SOUND((LT==kind) || 01412 (LE==kind) || 01413 (GE==kind) || 01414 (GT==kind), 01415 "ArithTheoremProducer3::multIneqn: wrong kind"); 01416 CHECK_SOUND(z.isRational() && z.getRational() != 0, 01417 "ArithTheoremProducer3::multIneqn: " 01418 "z must be non-zero rational: " + z.toString()); 01419 } 01420 Op op(e.getOp()); 01421 Proof pf; 01422 01423 Expr ret; 01424 if(0 < z.getRational()) 01425 ret = Expr(op, e[0]*z, e[1]*z); 01426 else 01427 ret = Expr(op, e[1]*z, e[0]*z); 01428 if(withProof()) pf = newPf("mult_ineqn", e, ret); 01429 return newRWTheorem(e, ret, Assumptions::emptyAssump(), pf); 01430 } 01431 01432 01433 Theorem ArithTheoremProducer3::eqToIneq(const Expr& e) { 01434 01435 // Check soundness of the rule if necessary 01436 if (CHECK_PROOFS) 01437 CHECK_SOUND(e.isEq(), "eqToIneq: input must be an equality: " + e.toString()); 01438 01439 // The proof object we will use 01440 Proof pf; 01441 01442 // The parts of the equality x = y 01443 const Expr& x = e[0]; 01444 const Expr& y = e[1]; 01445 01446 // Setup the proof if needed 01447 if (withProof()) 01448 pf = newPf("eqToIneq", e); 01449 01450 // Retrun the theorem explaining the transformation 01451 return newRWTheorem(e, leExpr(x,y).andExpr(geExpr(x,y)), Assumptions::emptyAssump(), pf); 01452 } 01453 01454 // "op1 GE|GT op2" <==> op2 LE|LT op1 01455 Theorem ArithTheoremProducer3::flipInequality(const Expr& e) 01456 { 01457 Proof pf; 01458 if(CHECK_PROOFS) { 01459 CHECK_SOUND(isGT(e) || isGE(e), 01460 "ArithTheoremProducer3::flipInequality: wrong kind: " + 01461 e.toString()); 01462 } 01463 01464 int kind = isGE(e) ? LE : LT; 01465 Expr ret = Expr(kind, e[1], e[0]); 01466 if(withProof()) pf = newPf("flip_inequality", e,ret); 01467 return newRWTheorem(e,ret, Assumptions::emptyAssump(), pf); 01468 } 01469 01470 01471 // NOT (op1 LT op2) <==> (op1 GE op2) 01472 // NOT (op1 LE op2) <==> (op1 GT op2) 01473 // NOT (op1 GT op2) <==> (op1 LE op2) 01474 // NOT (op1 GE op2) <==> (op1 LT op2) 01475 Theorem ArithTheoremProducer3::negatedInequality(const Expr& e) 01476 { 01477 const Expr& ineq = e[0]; 01478 if(CHECK_PROOFS) { 01479 CHECK_SOUND(e.isNot(), 01480 "ArithTheoremProducer3::negatedInequality: wrong kind: " + 01481 e.toString()); 01482 CHECK_SOUND(isIneq(ineq), 01483 "ArithTheoremProducer3::negatedInequality: wrong kind: " + 01484 (ineq).toString()); 01485 } 01486 Proof pf; 01487 if(withProof()) pf = newPf("negated_inequality", e); 01488 01489 int kind; 01490 // NOT (op1 LT op2) <==> (op1 GE op2) 01491 // NOT (op1 LE op2) <==> (op1 GT op2) 01492 // NOT (op1 GT op2) <==> (op1 LE op2) 01493 // NOT (op1 GE op2) <==> (op1 LT op2) 01494 kind = 01495 isLT(ineq) ? GE : 01496 isLE(ineq) ? GT : 01497 isGT(ineq) ? LE : 01498 LT; 01499 return newRWTheorem(e, Expr(kind, ineq[0], ineq[1]), Assumptions::emptyAssump(), pf); 01500 } 01501 01502 //takes two ineqs "|- alpha LT|LE t" and "|- t LT|LE beta" 01503 //and returns "|- alpha LT|LE beta" 01504 Theorem ArithTheoremProducer3::realShadow(const Theorem& alphaLTt, 01505 const Theorem& tLTbeta) 01506 { 01507 const Expr& expr1 = alphaLTt.getExpr(); 01508 const Expr& expr2 = tLTbeta.getExpr(); 01509 if(CHECK_PROOFS) { 01510 CHECK_SOUND((isLE(expr1) || isLT(expr1)) && 01511 (isLE(expr2) || isLT(expr2)), 01512 "ArithTheoremProducer3::realShadow: Wrong Kind: " + 01513 alphaLTt.toString() + tLTbeta.toString()); 01514 01515 CHECK_SOUND(expr1[1] == expr2[0], 01516 "ArithTheoremProducer3::realShadow:" 01517 " t must be same for both inputs: " + 01518 expr1[1].toString() + " , " + expr2[0].toString()); 01519 } 01520 Assumptions a(alphaLTt, tLTbeta); 01521 int firstKind = expr1.getKind(); 01522 int secondKind = expr2.getKind(); 01523 int kind = (firstKind == secondKind) ? firstKind : LT; 01524 Proof pf; 01525 if(withProof()) { 01526 vector<Proof> pfs; 01527 pfs.push_back(alphaLTt.getProof()); 01528 pfs.push_back(tLTbeta.getProof()); 01529 pf = newPf("real_shadow",expr1, expr2, pfs); 01530 } 01531 return newTheorem(Expr(kind, expr1[0], expr2[1]), a, pf); 01532 } 01533 01534 //! alpha <= t <= alpha ==> t = alpha 01535 01536 /*! takes two ineqs "|- alpha LE t" and "|- t LE alpha" 01537 and returns "|- t = alpha" 01538 */ 01539 Theorem ArithTheoremProducer3::realShadowEq(const Theorem& alphaLEt, 01540 const Theorem& tLEalpha) 01541 { 01542 const Expr& expr1 = alphaLEt.getExpr(); 01543 const Expr& expr2 = tLEalpha.getExpr(); 01544 if(CHECK_PROOFS) { 01545 CHECK_SOUND(isLE(expr1) && isLE(expr2), 01546 "ArithTheoremProducer3::realShadowLTLE: Wrong Kind: " + 01547 alphaLEt.toString() + tLEalpha.toString()); 01548 01549 CHECK_SOUND(expr1[1] == expr2[0], 01550 "ArithTheoremProducer3::realShadowLTLE:" 01551 " t must be same for both inputs: " + 01552 alphaLEt.toString() + " , " + tLEalpha.toString()); 01553 01554 CHECK_SOUND(expr1[0] == expr2[1], 01555 "ArithTheoremProducer3::realShadowLTLE:" 01556 " alpha must be same for both inputs: " + 01557 alphaLEt.toString() + " , " + tLEalpha.toString()); 01558 } 01559 Assumptions a(alphaLEt, tLEalpha); 01560 Proof pf; 01561 if(withProof()) { 01562 vector<Proof> pfs; 01563 pfs.push_back(alphaLEt.getProof()); 01564 pfs.push_back(tLEalpha.getProof()); 01565 pf = newPf("real_shadow_eq", alphaLEt.getExpr(), tLEalpha.getExpr(), pfs); 01566 } 01567 return newRWTheorem(expr1[0], expr1[1], a, pf); 01568 } 01569 01570 Theorem 01571 ArithTheoremProducer3::finiteInterval(const Theorem& aLEt, 01572 const Theorem& tLEac, 01573 const Theorem& isInta, 01574 const Theorem& isIntt) { 01575 const Expr& e1 = aLEt.getExpr(); 01576 const Expr& e2 = tLEac.getExpr(); 01577 if(CHECK_PROOFS) { 01578 CHECK_SOUND(isLE(e1) && isLE(e2), 01579 "ArithTheoremProducer3::finiteInterval:\n e1 = " 01580 +e1.toString()+"\n e2 = "+e2.toString()); 01581 // term 't' is the same in both inequalities 01582 CHECK_SOUND(e1[1] == e2[0], 01583 "ArithTheoremProducer3::finiteInterval:\n e1 = " 01584 +e1.toString()+"\n e2 = "+e2.toString()); 01585 // RHS in e2 is (a+c) 01586 CHECK_SOUND(isPlus(e2[1]) && e2[1].arity() == 2, 01587 "ArithTheoremProducer3::finiteInterval:\n e1 = " 01588 +e1.toString()+"\n e2 = "+e2.toString()); 01589 // term 'a' in LHS of e1 and RHS of e2 is the same 01590 CHECK_SOUND(e1[0] == e2[1][0], 01591 "ArithTheoremProducer3::finiteInterval:\n e1 = " 01592 +e1.toString()+"\n e2 = "+e2.toString()); 01593 // 'c' in the RHS of e2 is a positive integer constant 01594 CHECK_SOUND(e2[1][1].isRational() && e2[1][1].getRational().isInteger() 01595 && e2[1][1].getRational() >= 1, 01596 "ArithTheoremProducer3::finiteInterval:\n e1 = " 01597 +e1.toString()+"\n e2 = "+e2.toString()); 01598 // Integrality constraints 01599 const Expr& isIntaExpr = isInta.getExpr(); 01600 const Expr& isInttExpr = isIntt.getExpr(); 01601 CHECK_SOUND(isIntPred(isIntaExpr) && isIntaExpr[0] == e1[0], 01602 "Wrong integrality constraint:\n e1 = " 01603 +e1.toString()+"\n isInta = "+isIntaExpr.toString()); 01604 CHECK_SOUND(isIntPred(isInttExpr) && isInttExpr[0] == e1[1], 01605 "Wrong integrality constraint:\n e1 = " 01606 +e1.toString()+"\n isIntt = "+isInttExpr.toString()); 01607 } 01608 vector<Theorem> thms; 01609 thms.push_back(aLEt); 01610 thms.push_back(tLEac); 01611 thms.push_back(isInta); 01612 thms.push_back(isIntt); 01613 Assumptions a(thms); 01614 Proof pf; 01615 if(withProof()) { 01616 vector<Expr> es; 01617 vector<Proof> pfs; 01618 es.push_back(e1); 01619 es.push_back(e2); 01620 es.push_back(isInta.getExpr()); 01621 es.push_back(isIntt.getExpr()); 01622 pfs.push_back(aLEt.getProof()); 01623 pfs.push_back(tLEac.getProof()); 01624 pfs.push_back(isInta.getProof()); 01625 pfs.push_back(isIntt.getProof()); 01626 pf = newPf("finite_interval", es, pfs); 01627 } 01628 // Construct GRAY_SHADOW(t, a, 0, c) 01629 Expr g(grayShadow(e1[1], e1[0], 0, e2[1][1].getRational())); 01630 return newTheorem(g, a, pf); 01631 } 01632 01633 01634 // Dark & Gray shadows when a <= b 01635 Theorem ArithTheoremProducer3::darkGrayShadow2ab(const Theorem& betaLEbx, 01636 const Theorem& axLEalpha, 01637 const Theorem& isIntAlpha, 01638 const Theorem& isIntBeta, 01639 const Theorem& isIntx) { 01640 const Expr& expr1 = betaLEbx.getExpr(); 01641 const Expr& expr2 = axLEalpha.getExpr(); 01642 const Expr& isIntAlphaExpr = isIntAlpha.getExpr(); 01643 const Expr& isIntBetaExpr = isIntBeta.getExpr(); 01644 const Expr& isIntxExpr = isIntx.getExpr(); 01645 01646 if(CHECK_PROOFS) { 01647 CHECK_SOUND(isLE(expr1) && isLE(expr2), 01648 "ArithTheoremProducer3::darkGrayShadow2ab: Wrong Kind: " + 01649 betaLEbx.toString() + axLEalpha.toString()); 01650 } 01651 01652 const Expr& beta = expr1[0]; 01653 const Expr& bx = expr1[1]; 01654 const Expr& ax = expr2[0]; 01655 const Expr& alpha = expr2[1]; 01656 Rational a = isMult(ax)? ax[0].getRational() : 1; 01657 Rational b = isMult(bx)? bx[0].getRational() : 1; 01658 const Expr& x = isMult(ax)? ax[1] : ax; 01659 01660 if(CHECK_PROOFS) { 01661 // Integrality constraints 01662 CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha, 01663 "ArithTheoremProducer3::darkGrayShadow2ab:\n " 01664 "wrong integrality constraint:\n alpha = " 01665 +alpha.toString()+"\n isIntAlpha = " 01666 +isIntAlphaExpr.toString()); 01667 CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta, 01668 "ArithTheoremProducer3::darkGrayShadow2ab:\n " 01669 "wrong integrality constraint:\n beta = " 01670 +beta.toString()+"\n isIntBeta = " 01671 +isIntBetaExpr.toString()); 01672 CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x, 01673 "ArithTheoremProducer3::darkGrayShadow2ab:\n " 01674 "wrong integrality constraint:\n x = " 01675 +x.toString()+"\n isIntx = " 01676 +isIntxExpr.toString()); 01677 // Expressions ax and bx should match on x 01678 CHECK_SOUND(!isMult(ax) || ax.arity() == 2, 01679 "ArithTheoremProducer3::darkGrayShadow2ab:\n ax<=alpha: " + 01680 axLEalpha.toString()); 01681 CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x), 01682 "ArithTheoremProducer3::darkGrayShadow2ab:\n beta<=bx: " 01683 +betaLEbx.toString() 01684 +"\n ax<=alpha: "+ axLEalpha.toString()); 01685 CHECK_SOUND(1 <= a && a <= b && 2 <= b, 01686 "ArithTheoremProducer3::darkGrayShadow2ab:\n beta<=bx: " 01687 +betaLEbx.toString() 01688 +"\n ax<=alpha: "+ axLEalpha.toString()); 01689 } 01690 vector<Theorem> thms; 01691 thms.push_back(betaLEbx); 01692 thms.push_back(axLEalpha); 01693 thms.push_back(isIntAlpha); 01694 thms.push_back(isIntBeta); 01695 thms.push_back(isIntx); 01696 Assumptions A(thms); 01697 01698 Expr bAlpha = multExpr(rat(b), alpha); 01699 Expr aBeta = multExpr(rat(a), beta); 01700 Expr t = minusExpr(bAlpha, aBeta); 01701 Expr d = darkShadow(rat(a*b-1), t); 01702 Expr g = grayShadow(ax, alpha, -a+1, 0); 01703 01704 Proof pf; 01705 if(withProof()) { 01706 vector<Expr> exprs; 01707 exprs.push_back(expr1); 01708 exprs.push_back(expr2); 01709 exprs.push_back(d); 01710 exprs.push_back(g); 01711 01712 vector<Proof> pfs; 01713 pfs.push_back(betaLEbx.getProof()); 01714 pfs.push_back(axLEalpha.getProof()); 01715 pfs.push_back(isIntAlpha.getProof()); 01716 pfs.push_back(isIntBeta.getProof()); 01717 pfs.push_back(isIntx.getProof()); 01718 01719 pf = newPf("dark_grayshadow_2ab", exprs, pfs); 01720 } 01721 01722 return newTheorem((d || g), A, pf); 01723 } 01724 01725 // Dark & Gray shadows when b <= a 01726 Theorem ArithTheoremProducer3::darkGrayShadow2ba(const Theorem& betaLEbx, 01727 const Theorem& axLEalpha, 01728 const Theorem& isIntAlpha, 01729 const Theorem& isIntBeta, 01730 const Theorem& isIntx) { 01731 const Expr& expr1 = betaLEbx.getExpr(); 01732 const Expr& expr2 = axLEalpha.getExpr(); 01733 const Expr& isIntAlphaExpr = isIntAlpha.getExpr(); 01734 const Expr& isIntBetaExpr = isIntBeta.getExpr(); 01735 const Expr& isIntxExpr = isIntx.getExpr(); 01736 01737 if(CHECK_PROOFS) { 01738 CHECK_SOUND(isLE(expr1) && isLE(expr2), 01739 "ArithTheoremProducer3::darkGrayShadow2ba: Wrong Kind: " + 01740 betaLEbx.toString() + axLEalpha.toString()); 01741 } 01742 01743 const Expr& beta = expr1[0]; 01744 const Expr& bx = expr1[1]; 01745 const Expr& ax = expr2[0]; 01746 const Expr& alpha = expr2[1]; 01747 Rational a = isMult(ax)? ax[0].getRational() : 1; 01748 Rational b = isMult(bx)? bx[0].getRational() : 1; 01749 const Expr& x = isMult(ax)? ax[1] : ax; 01750 01751 if(CHECK_PROOFS) { 01752 // Integrality constraints 01753 CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha, 01754 "ArithTheoremProducer3::darkGrayShadow2ab:\n " 01755 "wrong integrality constraint:\n alpha = " 01756 +alpha.toString()+"\n isIntAlpha = " 01757 +isIntAlphaExpr.toString()); 01758 CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta, 01759 "ArithTheoremProducer3::darkGrayShadow2ab:\n " 01760 "wrong integrality constraint:\n beta = " 01761 +beta.toString()+"\n isIntBeta = " 01762 +isIntBetaExpr.toString()); 01763 CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x, 01764 "ArithTheoremProducer3::darkGrayShadow2ab:\n " 01765 "wrong integrality constraint:\n x = " 01766 +x.toString()+"\n isIntx = " 01767 +isIntxExpr.toString()); 01768 // Expressions ax and bx should match on x 01769 CHECK_SOUND(!isMult(ax) || ax.arity() == 2, 01770 "ArithTheoremProducer3::darkGrayShadow2ba:\n ax<=alpha: " + 01771 axLEalpha.toString()); 01772 CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x), 01773 "ArithTheoremProducer3::darkGrayShadow2ba:\n beta<=bx: " 01774 +betaLEbx.toString() 01775 +"\n ax<=alpha: "+ axLEalpha.toString()); 01776 CHECK_SOUND(1 <= b && b <= a && 2 <= a, 01777 "ArithTheoremProducer3::darkGrayShadow2ba:\n beta<=bx: " 01778 +betaLEbx.toString() 01779 +"\n ax<=alpha: "+ axLEalpha.toString()); 01780 } 01781 vector<Theorem> thms; 01782 thms.push_back(betaLEbx); 01783 thms.push_back(axLEalpha); 01784 thms.push_back(isIntAlpha); 01785 thms.push_back(isIntBeta); 01786 thms.push_back(isIntx); 01787 Assumptions A(thms); 01788 Proof pf; 01789 if(withProof()) { 01790 vector<Proof> pfs; 01791 pfs.push_back(betaLEbx.getProof()); 01792 pfs.push_back(axLEalpha.getProof()); 01793 pfs.push_back(isIntAlpha.getProof()); 01794 pfs.push_back(isIntBeta.getProof()); 01795 pfs.push_back(isIntx.getProof()); 01796 01797 pf = newPf("dark_grayshadow_2ba", betaLEbx.getExpr(), 01798 axLEalpha.getExpr(), pfs); 01799 } 01800 01801 Expr bAlpha = multExpr(rat(b), alpha); 01802 Expr aBeta = multExpr(rat(a), beta); 01803 Expr t = minusExpr(bAlpha, aBeta); 01804 Expr d = darkShadow(rat(a*b-1), t); 01805 Expr g = grayShadow(bx, beta, 0, b-1); 01806 return newTheorem((d || g), A, pf); 01807 } 01808 01809 /*! takes a dark shadow and expands it into an inequality. 01810 */ 01811 Theorem ArithTheoremProducer3::expandDarkShadow(const Theorem& darkShadow) { 01812 const Expr& theShadow = darkShadow.getExpr(); 01813 if(CHECK_PROOFS){ 01814 CHECK_SOUND(isDarkShadow(theShadow), 01815 "ArithTheoremProducer3::expandDarkShadow: not DARK_SHADOW: " + 01816 theShadow.toString()); 01817 } 01818 Proof pf; 01819 if(withProof()) 01820 pf = newPf("expand_dark_shadow", theShadow, darkShadow.getProof()); 01821 return newTheorem(leExpr(theShadow[0], theShadow[1]), darkShadow.getAssumptionsRef(), pf); 01822 } 01823 01824 01825 // takes a grayShadow (c1==c2) and expands it into an equality 01826 Theorem ArithTheoremProducer3::expandGrayShadow0(const Theorem& grayShadow) { 01827 const Expr& theShadow = grayShadow.getExpr(); 01828 if(CHECK_PROOFS) { 01829 CHECK_SOUND(isGrayShadow(theShadow), 01830 "ArithTheoremProducer3::expandGrayShadowConst0:" 01831 " not GRAY_SHADOW: " + 01832 theShadow.toString()); 01833 CHECK_SOUND(theShadow[2] == theShadow[3], 01834 "ArithTheoremProducer3::expandGrayShadow0: c1!=c2: " + 01835 theShadow.toString()); 01836 } 01837 Proof pf; 01838 if(withProof()) pf = newPf("expand_gray_shadowconst0", theShadow, 01839 grayShadow.getProof()); 01840 const Expr& v = theShadow[0]; 01841 const Expr& e = theShadow[1]; 01842 return newRWTheorem(v, e + theShadow[2], grayShadow.getAssumptionsRef(), pf); 01843 } 01844 01845 01846 // G ==> (G1 or G2) and (!G1 or !G2), 01847 // where G = G(x, e, c1, c2), 01848 // G1 = G(x,e,c1,c) 01849 // G2 = G(x,e,c+1,c2), 01850 // and c = floor((c1+c2)/2) 01851 // DEJAN: TRY THE MIDDLE IMMEDIATELY, WE MIGHT GET LUCKY 01852 Theorem ArithTheoremProducer3::splitGrayShadow(const Theorem& gThm) { 01853 const Expr& theShadow = gThm.getExpr(); 01854 if(CHECK_PROOFS) { 01855 CHECK_SOUND(isGrayShadow(theShadow), 01856 "ArithTheoremProducer3::expandGrayShadowConst: not a shadow" + 01857 theShadow.toString()); 01858 } 01859 01860 const Rational& c1 = theShadow[2].getRational(); 01861 const Rational& c2 = theShadow[3].getRational(); 01862 01863 if(CHECK_PROOFS) { 01864 CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2, 01865 "ArithTheoremProducer3::expandGrayShadow: " + 01866 theShadow.toString()); 01867 } 01868 01869 const Expr& v = theShadow[0]; 01870 const Expr& e = theShadow[1]; 01871 01872 Proof pf; 01873 Rational c(floor((c1+c2) / 2)); 01874 Expr g1(grayShadow(v, e, c1, c)); 01875 Expr g2(grayShadow(v, e, c+1, c2)); 01876 01877 if(withProof()){ 01878 vector<Expr> exprs; 01879 exprs.push_back(theShadow); 01880 exprs.push_back(g1); 01881 exprs.push_back(g2); 01882 pf = newPf("split_gray_shadow", exprs, gThm.getProof()); 01883 } 01884 01885 return newTheorem((g1 || g2) && (!g1 || !g2), gThm.getAssumptionsRef(), pf); 01886 } 01887 01888 01889 Theorem ArithTheoremProducer3::expandGrayShadow(const Theorem& gThm) { 01890 const Expr& theShadow = gThm.getExpr(); 01891 if(CHECK_PROOFS) { 01892 CHECK_SOUND(isGrayShadow(theShadow), 01893 "ArithTheoremProducer3::expandGrayShadowConst: not a shadow" + 01894 theShadow.toString()); 01895 } 01896 01897 const Rational& c1 = theShadow[2].getRational(); 01898 const Rational& c2 = theShadow[3].getRational(); 01899 01900 if(CHECK_PROOFS) { 01901 CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2, 01902 "ArithTheoremProducer3::expandGrayShadow: " + 01903 theShadow.toString()); 01904 } 01905 01906 const Expr& v = theShadow[0]; 01907 const Expr& e = theShadow[1]; 01908 01909 Proof pf; 01910 if(withProof()) 01911 pf = newPf("expand_gray_shadow", theShadow, gThm.getProof()); 01912 Expr ineq1(leExpr(e+rat(c1), v)); 01913 Expr ineq2(leExpr(v, e+rat(c2))); 01914 return newTheorem(ineq1 && ineq2, gThm.getAssumptionsRef(), pf); 01915 } 01916 01917 01918 // Expanding GRAY_SHADOW(a*x, c, b), where c is a constant 01919 Theorem 01920 ArithTheoremProducer3::expandGrayShadowConst(const Theorem& gThm) { 01921 const Expr& theShadow = gThm.getExpr(); 01922 const Expr& ax = theShadow[0]; 01923 const Expr& cExpr = theShadow[1]; 01924 const Expr& bExpr = theShadow[2]; 01925 01926 if(CHECK_PROOFS) { 01927 CHECK_SOUND(!isMult(ax) || ax[0].isRational(), 01928 "ArithTheoremProducer3::expandGrayShadowConst: " 01929 "'a' in a*x is not a const: " +theShadow.toString()); 01930 } 01931 01932 Rational a = isMult(ax)? ax[0].getRational() : 1; 01933 01934 if(CHECK_PROOFS) { 01935 CHECK_SOUND(isGrayShadow(theShadow), 01936 "ArithTheoremProducer3::expandGrayShadowConst: " 01937 "not a GRAY_SHADOW: " +theShadow.toString()); 01938 CHECK_SOUND(a.isInteger() && a >= 1, 01939 "ArithTheoremProducer3::expandGrayShadowConst: " 01940 "'a' is not integer: " +theShadow.toString()); 01941 CHECK_SOUND(cExpr.isRational(), 01942 "ArithTheoremProducer3::expandGrayShadowConst: " 01943 "'c' is not rational" +theShadow.toString()); 01944 CHECK_SOUND(bExpr.isRational() && bExpr.getRational().isInteger(), 01945 "ArithTheoremProducer3::expandGrayShadowConst: b not integer: " 01946 +theShadow.toString()); 01947 } 01948 01949 const Rational& b = bExpr.getRational(); 01950 const Rational& c = cExpr.getRational(); 01951 Rational j = constRHSGrayShadow(c,b,a); 01952 // Compute sign(b)*j(c,b,a) 01953 Rational signB = (b>0)? 1 : -1; 01954 // |b| (absolute value of b) 01955 Rational bAbs = abs(b); 01956 01957 const Assumptions& assump(gThm.getAssumptionsRef()); 01958 Proof pf; 01959 Theorem conc; // Conclusion of the rule 01960 01961 if(bAbs < j) { 01962 if(withProof()) 01963 pf = newPf("expand_gray_shadow_const_0", theShadow, 01964 gThm.getProof()); 01965 conc = newTheorem(d_em->falseExpr(), assump, pf); 01966 } else if(bAbs < a+j) { 01967 if(withProof()) 01968 pf = newPf("expand_gray_shadow_const_1", theShadow, 01969 gThm.getProof()); 01970 conc = newRWTheorem(ax, rat(c+b-signB*j), assump, pf); 01971 } else { 01972 if(withProof()) 01973 pf = newPf("expand_gray_shadow_const", theShadow, 01974 gThm.getProof()); 01975 Expr newGrayShadow(Expr(GRAY_SHADOW, ax, cExpr, rat(b-signB*(a+j)))); 01976 conc = newTheorem(ax.eqExpr(rat(c+b-signB*j)).orExpr(newGrayShadow), 01977 assump, pf); 01978 } 01979 01980 return conc; 01981 } 01982 01983 01984 Theorem 01985 ArithTheoremProducer3::grayShadowConst(const Theorem& gThm) { 01986 const Expr& g = gThm.getExpr(); 01987 bool checkProofs(CHECK_PROOFS); 01988 if(checkProofs) { 01989 CHECK_SOUND(isGrayShadow(g), "ArithTheoremProducer3::grayShadowConst(" 01990 +g.toString()+")"); 01991 } 01992 01993 const Expr& ax = g[0]; 01994 const Expr& e = g[1]; 01995 const Rational& c1 = g[2].getRational(); 01996 const Rational& c2 = g[3].getRational(); 01997 Expr aExpr, x; 01998 d_theoryArith->separateMonomial(ax, aExpr, x); 01999 02000 if(checkProofs) { 02001 CHECK_SOUND(e.isRational() && e.getRational().isInteger(), 02002 "ArithTheoremProducer3::grayShadowConst("+g.toString()+")"); 02003 CHECK_SOUND(aExpr.isRational(), 02004 "ArithTheoremProducer3::grayShadowConst("+g.toString()+")"); 02005 } 02006 02007 const Rational& a = aExpr.getRational(); 02008 const Rational& c = e.getRational(); 02009 02010 if(checkProofs) { 02011 CHECK_SOUND(a.isInteger() && a >= 2, 02012 "ArithTheoremProducer3::grayShadowConst("+g.toString()+")"); 02013 } 02014 02015 Rational newC1 = ceil((c1+c)/a), newC2 = floor((c2+c)/a); 02016 Expr newG((newC1 > newC2)? d_em->falseExpr() 02017 : grayShadow(x, rat(0), newC1, newC2)); 02018 Proof pf; 02019 if(withProof()) 02020 pf = newPf("gray_shadow_const", g, newG, gThm.getProof()); 02021 return newTheorem(newG, gThm.getAssumptionsRef(), pf); 02022 } 02023 02024 02025 Rational ArithTheoremProducer3::constRHSGrayShadow(const Rational& c, 02026 const Rational& b, 02027 const Rational& a) { 02028 DebugAssert(c.isInteger() && 02029 b.isInteger() && 02030 a.isInteger() && 02031 b != 0, 02032 "ArithTheoremProducer3::constRHSGrayShadow: a, b, c must be ints"); 02033 if (b > 0) 02034 return mod(c+b, a); 02035 else 02036 return mod(a-(c+b), a); 02037 } 02038 02039 /*! Takes a Theorem(\\alpha < \\beta) and returns 02040 * Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1) 02041 * where \\alpha and \\beta are integer expressions 02042 */ 02043 Theorem ArithTheoremProducer3::lessThanToLE(const Theorem& less, 02044 const Theorem& isIntLHS, 02045 const Theorem& isIntRHS, 02046 bool changeRight) { 02047 const Expr& ineq = less.getExpr(); 02048 const Expr& isIntLHSexpr = isIntLHS.getExpr(); 02049 const Expr& isIntRHSexpr = isIntRHS.getExpr(); 02050 02051 if(CHECK_PROOFS) { 02052 CHECK_SOUND(isLT(ineq), 02053 "ArithTheoremProducer3::LTtoLE: ineq must be <"); 02054 // Integrality check 02055 CHECK_SOUND(isIntPred(isIntLHSexpr) && isIntLHSexpr[0] == ineq[0], 02056 "ArithTheoremProducer3::lessThanToLE: bad integrality check:\n" 02057 " ineq = "+ineq.toString()+"\n isIntLHS = " 02058 +isIntLHSexpr.toString()); 02059 CHECK_SOUND(isIntPred(isIntRHSexpr) && isIntRHSexpr[0] == ineq[1], 02060 "ArithTheoremProducer3::lessThanToLE: bad integrality check:\n" 02061 " ineq = "+ineq.toString()+"\n isIntRHS = " 02062 +isIntRHSexpr.toString()); 02063 } 02064 vector<Theorem> thms; 02065 thms.push_back(less); 02066 thms.push_back(isIntLHS); 02067 thms.push_back(isIntRHS); 02068 Assumptions a(thms); 02069 Proof pf; 02070 Expr le = changeRight? 02071 leExpr(ineq[0], ineq[1] + rat(-1)) 02072 : leExpr(ineq[0] + rat(1), ineq[1]); 02073 if(withProof()) { 02074 vector<Proof> pfs; 02075 pfs.push_back(less.getProof()); 02076 pfs.push_back(isIntLHS.getProof()); 02077 pfs.push_back(isIntRHS.getProof()); 02078 pf = newPf(changeRight? "lessThan_To_LE_rhs" : "lessThan_To_LE_lhs", 02079 ineq,le, pfs); 02080 } 02081 02082 return newRWTheorem(ineq, le, a, pf); 02083 } 02084 02085 02086 /*! \param eqn is an equation 0 = a.x or 0 = c + a.x 02087 * \param isIntx is a proof of IS_INTEGER(x) 02088 * 02089 * \return the theorem 0 = c + a.x <==> x=-c/a if -c/a is int else 02090 * return the theorem 0 = c + a.x <==> false. 02091 * 02092 * It also handles the special case of 0 = a.x <==> x = 0 02093 */ 02094 Theorem 02095 ArithTheoremProducer3::intVarEqnConst(const Expr& eqn, 02096 const Theorem& isIntx) { 02097 const Expr& left(eqn[0]); 02098 const Expr& right(eqn[1]); 02099 const Expr& isIntxexpr(isIntx.getExpr()); 02100 02101 if(CHECK_PROOFS) { 02102 CHECK_SOUND((isMult(right) && right[0].isRational()) 02103 || (right.arity() == 2 && isPlus(right) 02104 && right[0].isRational() 02105 && ((!isMult(right[1]) || right[1][0].isRational()))), 02106 "ArithTheoremProducer3::intVarEqnConst: " 02107 "rhs has a wrong format: " + right.toString()); 02108 CHECK_SOUND(left.isRational() && 0 == left.getRational(), 02109 "ArithTheoremProducer3:intVarEqnConst:left is not a zero: " + 02110 left.toString()); 02111 } 02112 // Integrality constraint 02113 Expr x(right); 02114 Rational a(1), c(0); 02115 if(isMult(right)) { 02116 Expr aExpr; 02117 d_theoryArith->separateMonomial(right, aExpr, x); 02118 a = aExpr.getRational(); 02119 } else { // right is a PLUS 02120 c = right[0].getRational(); 02121 Expr aExpr; 02122 d_theoryArith->separateMonomial(right[1], aExpr, x); 02123 a = aExpr.getRational(); 02124 } 02125 if(CHECK_PROOFS) { 02126 CHECK_SOUND(isIntPred(isIntxexpr) && isIntxexpr[0] == x, 02127 "ArithTheoremProducer3:intVarEqnConst: " 02128 "bad integrality constraint:\n right = " + 02129 right.toString()+"\n isIntx = "+isIntxexpr.toString()); 02130 CHECK_SOUND(a!=0, "ArithTheoremProducer3:intVarEqnConst: eqn = " 02131 +eqn.toString()); 02132 } 02133 const Assumptions& assump(isIntx.getAssumptionsRef()); 02134 02135 /* 02136 Proof pf; 02137 if(withProof()) 02138 pf = newPf("int_const_eq", eqn, isIntx.getProof()); 02139 02140 // Solve for x: x = r = -c/a 02141 Rational r(-c/a); 02142 02143 if(r.isInteger()){ 02144 return newRWTheorem(eqn, x.eqExpr(rat(r)), assump, pf); 02145 else 02146 return newRWTheorem(eqn, d_em->falseExpr(), assump, pf); 02147 */ 02148 02149 Proof pf; 02150 // Solve for x: x = r = -c/a 02151 Rational r(-c/a); 02152 02153 if(r.isInteger()){ 02154 if(withProof()) 02155 pf = newPf("int_const_eq", eqn, x.eqExpr(rat(r)),isIntx.getProof()); 02156 return newRWTheorem(eqn, x.eqExpr(rat(r)), assump, pf); 02157 } 02158 else{ 02159 if(withProof()) 02160 pf = newPf("int_const_eq", eqn, d_em->falseExpr(),isIntx.getProof()); 02161 return newRWTheorem(eqn, d_em->falseExpr(), assump, pf); 02162 } 02163 } 02164 02165 02166 Expr 02167 ArithTheoremProducer3::create_t(const Expr& eqn) { 02168 const Expr& lhs = eqn[0]; 02169 DebugAssert(isMult(lhs), 02170 CLASS_NAME "create_t : lhs must be a MULT" 02171 + lhs.toString()); 02172 const Expr& x = lhs[1]; 02173 Rational m = lhs[0].getRational()+1; 02174 DebugAssert(m > 0, "ArithTheoremProducer3::create_t: m = "+m.toString()); 02175 vector<Expr> kids; 02176 if(isPlus(eqn[1])) 02177 sumModM(kids, eqn[1], m, m); 02178 else 02179 kids.push_back(monomialModM(eqn[1], m, m)); 02180 02181 kids.push_back(multExpr(rat(1/m), x)); 02182 return plusExpr(kids); 02183 } 02184 02185 Expr 02186 ArithTheoremProducer3::create_t2(const Expr& lhs, const Expr& rhs, 02187 const Expr& sigma) { 02188 Rational m = lhs[0].getRational()+1; 02189 DebugAssert(m > 0, "ArithTheoremProducer3::create_t2: m = "+m.toString()); 02190 vector<Expr> kids; 02191 if(isPlus(rhs)) 02192 sumModM(kids, rhs, m, -1); 02193 else { 02194 kids.push_back(rat(0)); // For canonical form 02195 Expr monom = monomialModM(rhs, m, -1); 02196 if(!monom.isRational()) 02197 kids.push_back(monom); 02198 else 02199 DebugAssert(monom.getRational() == 0, ""); 02200 } 02201 kids.push_back(rat(m)*sigma); 02202 return plusExpr(kids); 02203 } 02204 02205 Expr 02206 ArithTheoremProducer3::create_t3(const Expr& lhs, const Expr& rhs, 02207 const Expr& sigma) { 02208 const Rational& a = lhs[0].getRational(); 02209 Rational m = a+1; 02210 DebugAssert(m > 0, "ArithTheoremProducer3::create_t3: m = "+m.toString()); 02211 vector<Expr> kids; 02212 if(isPlus(rhs)) 02213 sumMulF(kids, rhs, m, 1); 02214 else { 02215 kids.push_back(rat(0)); // For canonical form 02216 Expr monom = monomialMulF(rhs, m, 1); 02217 if(!monom.isRational()) 02218 kids.push_back(monom); 02219 else 02220 DebugAssert(monom.getRational() == 0, ""); 02221 } 02222 kids.push_back(rat(-a)*sigma); 02223 return plusExpr(kids); 02224 } 02225 02226 Rational 02227 ArithTheoremProducer3::modEq(const Rational& i, const Rational& m) { 02228 DebugAssert(m > 0, "ArithTheoremProducer3::modEq: m = "+m.toString()); 02229 Rational half(1,2); 02230 Rational res((i - m*(floor((i/m) + half)))); 02231 TRACE("arith eq", "modEq("+i.toString()+", "+m.toString()+") = ", res, ""); 02232 return res; 02233 } 02234 02235 Rational 02236 ArithTheoremProducer3::f(const Rational& i, const Rational& m) { 02237 DebugAssert(m > 0, "ArithTheoremProducer3::f: m = "+m.toString()); 02238 Rational half(1,2); 02239 return (floor(i/m + half)+modEq(i,m)); 02240 } 02241 02242 void 02243 ArithTheoremProducer3::sumModM(vector<Expr>& summands, const Expr& sum, 02244 const Rational& m, const Rational& divisor) { 02245 DebugAssert(divisor != 0, "ArithTheoremProducer3::sumModM: divisor = " 02246 +divisor.toString()); 02247 Expr::iterator i = sum.begin(); 02248 DebugAssert(i != sum.end(), CLASS_NAME "::sumModM"); 02249 Rational C = i->getRational(); 02250 C = modEq(C,m)/divisor; 02251 summands.push_back(rat(C)); 02252 i++; 02253 for(Expr::iterator iend=sum.end(); i!=iend; ++i) { 02254 Expr monom = monomialModM(*i, m, divisor); 02255 if(!monom.isRational()) 02256 summands.push_back(monom); 02257 else 02258 DebugAssert(monom.getRational() == 0, ""); 02259 } 02260 } 02261 02262 Expr 02263 ArithTheoremProducer3::monomialModM(const Expr& i, 02264 const Rational& m, const Rational& divisor) 02265 { 02266 DebugAssert(divisor != 0, "ArithTheoremProducer3::monomialModM: divisor = " 02267 +divisor.toString()); 02268 Expr res; 02269 if(isMult(i)) { 02270 Rational ai = i[0].getRational(); 02271 ai = modEq(ai,m)/divisor; 02272 if(0 == ai) res = rat(0); 02273 else if(1 == ai && i.arity() == 2) res = i[1]; 02274 else { 02275 vector<Expr> kids = i.getKids(); 02276 kids[0] = rat(ai); 02277 res = multExpr(kids); 02278 } 02279 } else { // It's a single variable 02280 Rational ai = modEq(1,m)/divisor; 02281 if(1 == ai) res = i; 02282 else res = rat(ai)*i; 02283 } 02284 DebugAssert(!res.isNull(), "ArithTheoremProducer3::monomialModM()"); 02285 TRACE("arith eq", "monomialModM(i="+i.toString()+", m="+m.toString() 02286 +", div="+divisor.toString()+") = ", res, ""); 02287 return res; 02288 } 02289 02290 void 02291 ArithTheoremProducer3::sumMulF(vector<Expr>& summands, const Expr& sum, 02292 const Rational& m, const Rational& divisor) { 02293 DebugAssert(divisor != 0, "ArithTheoremProducer3::sumMulF: divisor = " 02294 +divisor.toString()); 02295 Expr::iterator i = sum.begin(); 02296 DebugAssert(i != sum.end(), CLASS_NAME "::sumModM"); 02297 Rational C = i->getRational(); 02298 C = f(C,m)/divisor; 02299 summands.push_back(rat(C)); 02300 i++; 02301 for(Expr::iterator iend=sum.end(); i!=iend; ++i) { 02302 Expr monom = monomialMulF(*i, m, divisor); 02303 if(!monom.isRational()) 02304 summands.push_back(monom); 02305 else 02306 DebugAssert(monom.getRational() == 0, ""); 02307 } 02308 } 02309 02310 Expr 02311 ArithTheoremProducer3::monomialMulF(const Expr& i, 02312 const Rational& m, const Rational& divisor) 02313 { 02314 DebugAssert(divisor != 0, "ArithTheoremProducer3::monomialMulF: divisor = " 02315 +divisor.toString()); 02316 Rational ai = isMult(i) ? (i)[0].getRational() : 1; 02317 Expr xi = isMult(i) ? (i)[1] : (i); 02318 ai = f(ai,m)/divisor; 02319 if(0 == ai) return rat(0); 02320 if(1 == ai) return xi; 02321 return multExpr(rat(ai), xi); 02322 } 02323 02324 // This recursive function accepts a term, t, and a 'map' of 02325 // substitutions [x1/t1, x2/t2,...,xn/tn]. it returns a t' which is 02326 // basically t[x1/t1,x2/t2...xn/tn] 02327 Expr 02328 ArithTheoremProducer3::substitute(const Expr& term, ExprMap<Expr>& eMap) 02329 { 02330 ExprMap<Expr>::iterator i, iend = eMap.end(); 02331 02332 i = eMap.find(term); 02333 if(iend != i) 02334 return (*i).second; 02335 02336 if (isMult(term)) { 02337 //in this case term is of the form c.x 02338 i = eMap.find(term[1]); 02339 if(iend != i) 02340 return term[0]*(*i).second; 02341 else 02342 return term; 02343 } 02344 02345 if(isPlus(term)) { 02346 vector<Expr> output; 02347 for(Expr::iterator j = term.begin(), jend = term.end(); j != jend; ++j) 02348 output.push_back(substitute(*j, eMap)); 02349 return plusExpr(output); 02350 } 02351 return term; 02352 } 02353 02354 bool ArithTheoremProducer3::greaterthan(const Expr & l, const Expr & r) 02355 { 02356 // DebugAssert(l != r, ""); 02357 if (l==r) return false; 02358 02359 switch(l.getKind()) { 02360 case RATIONAL_EXPR: 02361 DebugAssert(!r.isRational(), ""); 02362 return true; 02363 break; 02364 case POW: 02365 switch (r.getKind()) { 02366 case RATIONAL_EXPR: 02367 // TODO: 02368 // alternately I could return (not greaterthan(r,l)) 02369 return false; 02370 break; 02371 case POW: 02372 // x^n > y^n if x > y 02373 // x^n1 > x^n2 if n1 > n2 02374 return 02375 ((r[1] < l[1]) || 02376 ((r[1]==l[1]) && (r[0].getRational() < l[0].getRational()))); 02377 break; 02378 02379 case MULT: 02380 DebugAssert(r.arity() > 1, ""); 02381 DebugAssert((r.arity() > 2) || (r[1] != l), ""); 02382 if (r[1] == l) return false; 02383 return greaterthan(l, r[1]); 02384 break; 02385 case PLUS: 02386 DebugAssert(false, ""); 02387 return true; 02388 break; 02389 default: 02390 // leaf 02391 return ((r < l[1]) || ((r == l[1]) && l[0].getRational() > 1)); 02392 break; 02393 } 02394 break; 02395 case MULT: 02396 DebugAssert(l.arity() > 1, ""); 02397 switch (r.getKind()) { 02398 case RATIONAL_EXPR: 02399 return false; 02400 break; 02401 case POW: 02402 DebugAssert(l.arity() > 1, ""); 02403 DebugAssert((l.arity() > 2) || (l[1] != r), ""); 02404 // TODO: 02405 // alternately return (not greaterthan(r,l) 02406 return ((l[1] == r) || greaterthan(l[1], r)); 02407 break; 02408 case MULT: 02409 { 02410 02411 DebugAssert(r.arity() > 1, ""); 02412 Expr::iterator i = l.begin(); 02413 Expr::iterator j = r.begin(); 02414 ++i; 02415 ++j; 02416 for (; i != l.end() && j != r.end(); ++i, ++j) { 02417 if (*i == *j) 02418 continue; 02419 return greaterthan(*i,*j); 02420 } 02421 DebugAssert(i != l.end() || j != r.end(), ""); 02422 if (i == l.end()) { 02423 // r is bigger 02424 return false; 02425 } 02426 else 02427 { 02428 // l is bigger 02429 return true; 02430 } 02431 } 02432 break; 02433 case PLUS: 02434 DebugAssert(false, ""); 02435 return true; 02436 break; 02437 default: 02438 // leaf 02439 DebugAssert((l.arity() > 2) || (l[1] != r), ""); 02440 return ((l[1] == r) || greaterthan(l[1], r)); 02441 break; 02442 } 02443 break; 02444 case PLUS: 02445 DebugAssert(false, ""); 02446 return true; 02447 break; 02448 default: 02449 // leaf 02450 switch (r.getKind()) { 02451 case RATIONAL_EXPR: 02452 return false; 02453 break; 02454 case POW: 02455 return ((r[1] < l) || ((r[1] == l) && (r[0].getRational() < 1))); 02456 break; 02457 case MULT: 02458 DebugAssert(r.arity() > 1, ""); 02459 DebugAssert((r.arity() > 2) || (r[1] != l), ""); 02460 if (l == r[1]) return false; 02461 return greaterthan(l,r[1]); 02462 break; 02463 case PLUS: 02464 DebugAssert(false, ""); 02465 return true; 02466 break; 02467 default: 02468 // leaf 02469 return (r < l); 02470 break; 02471 } 02472 break; 02473 } 02474 } 02475 02476 02477 /*! IS_INTEGER(x) |= EXISTS (y : INT) y = x 02478 * where x is not already known to be an integer. 02479 */ 02480 Theorem ArithTheoremProducer3::IsIntegerElim(const Theorem& isIntx) 02481 { 02482 Expr expr = isIntx.getExpr(); 02483 if (CHECK_PROOFS) { 02484 CHECK_SOUND(expr.getKind() == IS_INTEGER, 02485 "Expected IS_INTEGER predicate"); 02486 } 02487 expr = expr[0]; 02488 DebugAssert(!d_theoryArith->isInteger(expr), "Expected non-integer"); 02489 02490 Assumptions a(isIntx); 02491 Proof pf; 02492 02493 if (withProof()) 02494 { 02495 pf = newPf("isIntElim", isIntx.getProof()); 02496 } 02497 02498 Expr newVar = d_em->newBoundVarExpr(d_theoryArith->intType()); 02499 Expr res = d_em->newClosureExpr(EXISTS, newVar, newVar.eqExpr(expr)); 02500 02501 return newTheorem(res, a, pf); 02502 } 02503 02504 02505 Theorem 02506 ArithTheoremProducer3::eqElimIntRule(const Theorem& eqn, const Theorem& isIntx, 02507 const vector<Theorem>& isIntVars) { 02508 TRACE("arith eq", "eqElimIntRule(", eqn.getExpr(), ") {"); 02509 Proof pf; 02510 02511 if(CHECK_PROOFS) 02512 CHECK_SOUND(eqn.isRewrite(), 02513 "ArithTheoremProducer3::eqElimInt: input must be an equation" + 02514 eqn.toString()); 02515 02516 const Expr& lhs = eqn.getLHS(); 02517 const Expr& rhs = eqn.getRHS(); 02518 Expr a, x; 02519 d_theoryArith->separateMonomial(lhs, a, x); 02520 02521 if(CHECK_PROOFS) { 02522 // Checking LHS 02523 const Expr& isIntxe = isIntx.getExpr(); 02524 CHECK_SOUND(isIntPred(isIntxe) && isIntxe[0] == x, 02525 "ArithTheoremProducer3::eqElimInt\n eqn = " 02526 +eqn.getExpr().toString() 02527 +"\n isIntx = "+isIntxe.toString()); 02528 CHECK_SOUND(isRational(a) && a.getRational().isInteger() 02529 && a.getRational() >= 2, 02530 "ArithTheoremProducer3::eqElimInt:\n lhs = "+lhs.toString()); 02531 // Checking RHS 02532 // It cannot be a division (we don't handle it) 02533 CHECK_SOUND(!isDivide(rhs), 02534 "ArithTheoremProducer3::eqElimInt:\n rhs = "+rhs.toString()); 02535 // If it's a single monomial, then it's the only "variable" 02536 if(!isPlus(rhs)) { 02537 Expr c, v; 02538 d_theoryArith->separateMonomial(rhs, c, v); 02539 CHECK_SOUND(isIntVars.size() == 1 02540 && isIntPred(isIntVars[0].getExpr()) 02541 && isIntVars[0].getExpr()[0] == v 02542 && isRational(c) && c.getRational().isInteger(), 02543 "ArithTheoremProducer3::eqElimInt:\n rhs = "+rhs.toString() 02544 +"isIntVars.size = "+int2string(isIntVars.size())); 02545 } else { // RHS is a plus 02546 CHECK_SOUND(isIntVars.size() + 1 == (size_t)rhs.arity(), 02547 "ArithTheoremProducer3::eqElimInt: rhs = "+rhs.toString()); 02548 // Check the free constant 02549 CHECK_SOUND(isRational(rhs[0]) && rhs[0].getRational().isInteger(), 02550 "ArithTheoremProducer3::eqElimInt: rhs = "+rhs.toString()); 02551 // Check the vars 02552 for(size_t i=0, iend=isIntVars.size(); i<iend; ++i) { 02553 Expr c, v; 02554 d_theoryArith->separateMonomial(rhs[i+1], c, v); 02555 const Expr& isInt(isIntVars[i].getExpr()); 02556 CHECK_SOUND(isIntPred(isInt) && isInt[0] == v 02557 && isRational(c) && c.getRational().isInteger(), 02558 "ArithTheoremProducer3::eqElimInt:\n rhs["+int2string(i+1) 02559 +"] = "+rhs[i+1].toString() 02560 +"\n isInt = "+isInt.toString()); 02561 } 02562 } 02563 } 02564 02565 // Creating a fresh bound variable 02566 static int varCount(0); 02567 Expr newVar = d_em->newBoundVarExpr("_int_var", int2string(varCount++)); 02568 newVar.setType(intType()); 02569 Expr t2 = create_t2(lhs, rhs, newVar); 02570 Expr t3 = create_t3(lhs, rhs, newVar); 02571 vector<Expr> vars; 02572 vars.push_back(newVar); 02573 Expr res = d_em->newClosureExpr(EXISTS, vars, 02574 x.eqExpr(t2) && rat(0).eqExpr(t3)); 02575 02576 vector<Theorem> thms(isIntVars); 02577 thms.push_back(isIntx); 02578 thms.push_back(eqn); 02579 Assumptions assump(thms); 02580 02581 if(withProof()) { 02582 vector<Proof> pfs; 02583 pfs.push_back(eqn.getProof()); 02584 pfs.push_back(isIntx.getProof()); 02585 vector<Theorem>::const_iterator i=isIntVars.begin(), iend=isIntVars.end(); 02586 for(; i!=iend; ++i) 02587 pfs.push_back(i->getProof()); 02588 pf = newPf("eq_elim_int", eqn.getExpr(), res, pfs); 02589 } 02590 02591 Theorem thm(newTheorem(res, assump, pf)); 02592 TRACE("arith eq", "eqElimIntRule => ", thm.getExpr(), " }"); 02593 return thm; 02594 } 02595 02596 02597 Theorem 02598 ArithTheoremProducer3::isIntConst(const Expr& e) { 02599 Proof pf; 02600 02601 if(CHECK_PROOFS) { 02602 CHECK_SOUND(isIntPred(e) && e[0].isRational(), 02603 "ArithTheoremProducer3::isIntConst(e = " 02604 +e.toString()+")"); 02605 } 02606 if(withProof()) 02607 pf = newPf("is_int_const", e); 02608 bool isInt = e[0].getRational().isInteger(); 02609 return newRWTheorem(e, isInt? d_em->trueExpr() : d_em->falseExpr(), Assumptions::emptyAssump(), pf); 02610 } 02611 02612 02613 Theorem 02614 ArithTheoremProducer3::equalLeaves1(const Theorem& thm) 02615 { 02616 Proof pf; 02617 const Expr& e = thm.getRHS(); 02618 02619 if (CHECK_PROOFS) { 02620 CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR && 02621 e[1].getRational() == Rational(0) && 02622 e[0].getKind() == PLUS && 02623 e[0].arity() == 3 && 02624 e[0][0].getKind() == RATIONAL_EXPR && 02625 e[0][0].getRational() == Rational(0) && 02626 e[0][1].getKind() == MULT && 02627 e[0][1].arity() == 2 && 02628 e[0][1][0].getKind() == RATIONAL_EXPR && 02629 e[0][1][0].getRational() == Rational(-1), 02630 "equalLeaves1"); 02631 } 02632 if (withProof()) 02633 { 02634 vector<Proof> pfs; 02635 pfs.push_back(thm.getProof()); 02636 pf = newPf("equalLeaves1", e, pfs); 02637 } 02638 return newRWTheorem(e, e[0][1][1].eqExpr(e[0][2]), thm.getAssumptionsRef(), pf); 02639 } 02640 02641 02642 Theorem 02643 ArithTheoremProducer3::equalLeaves2(const Theorem& thm) 02644 { 02645 Proof pf; 02646 const Expr& e = thm.getRHS(); 02647 02648 if (CHECK_PROOFS) { 02649 CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR && 02650 e[0].getRational() == Rational(0) && 02651 e[1].getKind() == PLUS && 02652 e[1].arity() == 3 && 02653 e[1][0].getKind() == RATIONAL_EXPR && 02654 e[1][0].getRational() == Rational(0) && 02655 e[1][1].getKind() == MULT && 02656 e[1][1].arity() == 2 && 02657 e[1][1][0].getKind() == RATIONAL_EXPR && 02658 e[1][1][0].getRational() == Rational(-1), 02659 "equalLeaves2"); 02660 } 02661 if (withProof()) 02662 { 02663 vector<Proof> pfs; 02664 pfs.push_back(thm.getProof()); 02665 pf = newPf("equalLeaves2", e, pfs); 02666 } 02667 return newRWTheorem(e, e[1][1][1].eqExpr(e[1][2]), thm.getAssumptionsRef(), pf); 02668 } 02669 02670 02671 Theorem 02672 ArithTheoremProducer3::equalLeaves3(const Theorem& thm) 02673 { 02674 Proof pf; 02675 const Expr& e = thm.getRHS(); 02676 02677 if (CHECK_PROOFS) { 02678 CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR && 02679 e[1].getRational() == Rational(0) && 02680 e[0].getKind() == PLUS && 02681 e[0].arity() == 3 && 02682 e[0][0].getKind() == RATIONAL_EXPR && 02683 e[0][0].getRational() == Rational(0) && 02684 e[0][2].getKind() == MULT && 02685 e[0][2].arity() == 2 && 02686 e[0][2][0].getKind() == RATIONAL_EXPR && 02687 e[0][2][0].getRational() == Rational(-1), 02688 "equalLeaves3"); 02689 } 02690 if (withProof()) 02691 { 02692 vector<Proof> pfs; 02693 pfs.push_back(thm.getProof()); 02694 pf = newPf("equalLeaves3", e, pfs); 02695 } 02696 return newRWTheorem(e, e[0][2][1].eqExpr(e[0][1]), thm.getAssumptionsRef(), pf); 02697 } 02698 02699 02700 Theorem 02701 ArithTheoremProducer3::equalLeaves4(const Theorem& thm) 02702 { 02703 Proof pf; 02704 const Expr& e = thm.getRHS(); 02705 02706 if (CHECK_PROOFS) { 02707 CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR && 02708 e[0].getRational() == Rational(0) && 02709 e[1].getKind() == PLUS && 02710 e[1].arity() == 3 && 02711 e[1][0].getKind() == RATIONAL_EXPR && 02712 e[1][0].getRational() == Rational(0) && 02713 e[1][2].getKind() == MULT && 02714 e[1][2].arity() == 2 && 02715 e[1][2][0].getKind() == RATIONAL_EXPR && 02716 e[1][2][0].getRational() == Rational(-1), 02717 "equalLeaves4"); 02718 } 02719 if (withProof()) 02720 { 02721 vector<Proof> pfs; 02722 pfs.push_back(thm.getProof()); 02723 pf = newPf("equalLeaves4", e, pfs); 02724 } 02725 return newRWTheorem(e, e[1][2][1].eqExpr(e[1][1]), thm.getAssumptionsRef(), pf); 02726 } 02727 02728 Theorem 02729 ArithTheoremProducer3::diseqToIneq(const Theorem& diseq) { 02730 Proof pf; 02731 02732 const Expr& e = diseq.getExpr(); 02733 02734 if(CHECK_PROOFS) { 02735 CHECK_SOUND(e.isNot() && e[0].isEq(), 02736 "ArithTheoremProducer3::diseqToIneq: expected disequality:\n" 02737 " e = "+e.toString()); 02738 } 02739 02740 const Expr& x = e[0][0]; 02741 const Expr& y = e[0][1]; 02742 02743 if(withProof()) 02744 pf = newPf(e, diseq.getProof()); 02745 return newTheorem(ltExpr(x,y).orExpr(gtExpr(x,y)), diseq.getAssumptionsRef(), pf); 02746 } 02747 02748 Theorem ArithTheoremProducer3::dummyTheorem(const Expr& e) { 02749 Proof pf; 02750 return newRWTheorem(e, d_em->trueExpr(), Assumptions::emptyAssump(), pf); 02751 } 02752 02753 Theorem ArithTheoremProducer3::oneElimination(const Expr& e) { 02754 02755 // Check soundness 02756 if (CHECK_PROOFS) 02757 CHECK_SOUND(isMult(e) && 02758 e.arity() == 2 && 02759 e[0].isRational() && 02760 e[0].getRational() == 1, 02761 "oneElimination: input must be a multiplication by one" + e.toString()); 02762 02763 // The proof object that we will us 02764 Proof pf; 02765 02766 // Setup the proof if needed 02767 if (withProof()) 02768 pf = newPf("oneElimination", e); 02769 02770 // Return the rewrite theorem that explains the phenomenon 02771 return newRWTheorem(e, e[1], Assumptions::emptyAssump(), pf); 02772 } 02773 02774 Theorem ArithTheoremProducer3::clashingBounds(const Theorem& lowerBound, const Theorem& upperBound) { 02775 02776 // Get the expressions 02777 const Expr& lowerBoundExpr = lowerBound.getExpr(); 02778 const Expr& upperBoundExpr = upperBound.getExpr(); 02779 02780 // Check soundness 02781 if (CHECK_PROOFS) { 02782 CHECK_SOUND(isLE(lowerBoundExpr) || isLT(lowerBoundExpr), "clashingBounds: lowerBound should be >= or > " + lowerBoundExpr.toString()); 02783 CHECK_SOUND(isGE(upperBoundExpr) || isGT(upperBoundExpr), "clashingBounds: upperBound should be <= or < " + upperBoundExpr.toString()); 02784 CHECK_SOUND(lowerBoundExpr[0].isRational(), "clashingBounds: lowerBound left side should be a rational " + lowerBoundExpr.toString()); 02785 CHECK_SOUND(upperBoundExpr[0].isRational(), "clashingBounds: upperBound left side should be a rational " + upperBoundExpr.toString()); 02786 CHECK_SOUND(lowerBoundExpr[1] == upperBoundExpr[1], "clashingBounds: bounds not on the same term " + lowerBoundExpr.toString() + ", " + upperBoundExpr.toString()); 02787 02788 // Get the bounds 02789 Rational lowerBoundR = lowerBoundExpr[0].getRational(); 02790 Rational upperBoundR = upperBoundExpr[0].getRational(); 02791 02792 if (isLE(lowerBoundExpr) && isGE(upperBoundExpr)) { 02793 CHECK_SOUND(upperBoundR < lowerBoundR, "clashingBounds: bounds are satisfiable"); 02794 } else { 02795 CHECK_SOUND(upperBoundR <= lowerBoundR, "clashingBounds: bounds are satisfiable"); 02796 } 02797 } 02798 02799 // The proof object that we will use 02800 Proof pf; 02801 // Setup the proof if needed 02802 if (withProof()) 02803 pf = newPf("clashingBounds", lowerBoundExpr, upperBoundExpr); 02804 02805 // Put the bounds expressions in the assumptions 02806 Assumptions assumptions; 02807 assumptions.add(lowerBound); 02808 assumptions.add(upperBound); 02809 02810 // Return the theorem 02811 return newTheorem(d_em->falseExpr(), assumptions, pf); 02812 } 02813 02814 Theorem ArithTheoremProducer3::addInequalities(const Theorem& thm1, const Theorem& thm2) { 02815 02816 // Get the expressions of the theorem 02817 const Expr& expr1 = thm1.getExpr(); 02818 const Expr& expr2 = thm2.getExpr(); 02819 02820 // Check soundness 02821 if (CHECK_PROOFS) { 02822 02823 CHECK_SOUND(isIneq(expr1), "addInequalities: expecting an inequality for thm1, got " + expr1.toString()); 02824 CHECK_SOUND(isIneq(expr2), "addInequalities: expecting an inequality for thm2, got " + expr2.toString()); 02825 02826 if (isLE(expr1) || isLT(expr1)) 02827 CHECK_SOUND(isLE(expr2) || isLT(expr2), "addInequalities: expr2 should be <(=) also " + expr2.toString()); 02828 if (isGE(expr1) || isGT(expr1)) 02829 CHECK_SOUND(isGE(expr2) || isGT(expr2), "addInequalities: expr2 should be >(=) also" + expr2.toString()); 02830 } 02831 02832 // Create the assumptions 02833 Assumptions a(thm1, thm2); 02834 02835 // Get the kinds of the inequalitites 02836 int kind1 = expr1.getKind(); 02837 int kind2 = expr2.getKind(); 02838 02839 // Set-up the resulting inequality 02840 int kind = (kind1 == kind2) ? kind1 : ((kind1 == LT) || (kind2 == LT))? LT : GT; 02841 02842 // Create the proof object 02843 Proof pf; 02844 if(withProof()) { 02845 vector<Proof> pfs; 02846 pfs.push_back(thm1.getProof()); 02847 pfs.push_back(thm2.getProof()); 02848 pf = newPf("addInequalities", expr1, expr2, pfs); 02849 } 02850 02851 // Create the new expressions 02852 Expr leftSide = plusExpr(expr1[0], expr2[0]); 02853 Expr rightSide = plusExpr(expr1[1], expr2[1]); 02854 02855 // Return the theorem 02856 return newTheorem(Expr(kind, leftSide, rightSide), a, pf); 02857 } 02858 02859 Theorem ArithTheoremProducer3::implyWeakerInequality(const Expr& expr1, const Expr& expr2) { 02860 02861 // Check soundness 02862 if (CHECK_PROOFS) { 02863 02864 // Both must be inequalitites 02865 CHECK_SOUND(isIneq(expr1), "implyWeakerInequality: expr1 should be an inequality" + expr1.toString()); 02866 CHECK_SOUND(isIneq(expr2), "implyWeakerInequality: expr1 should be an inequality" + expr2.toString()); 02867 02868 // Should be of the same type 02869 if (isLE(expr1) || isLT(expr1)) 02870 CHECK_SOUND(isLE(expr2) || isLT(expr2), "implyWeakerInequality: expr2 should be <(=) also " + expr2.toString()); 02871 if (isGE(expr1) || isGT(expr1)) 02872 CHECK_SOUND(isGE(expr2) || isGT(expr2), "implyWeakerInequality: expr2 should be >(=) also" + expr2.toString()); 02873 02874 // Left sides must be rational numbers 02875 CHECK_SOUND(expr1[0].isRational(), "implyWeakerInequality: expr1 should have a rational on the left side" + expr1.toString()); 02876 CHECK_SOUND(expr2[0].isRational(), "implyWeakerInequality: expr2 should have a rational on the left side" + expr2.toString()); 02877 02878 // Right sides must be identical 02879 CHECK_SOUND(expr1[1] == expr2[1], "implyWeakerInequality: the expression must be the same" + expr1.toString() + " and " + expr2.toString()); 02880 02881 Rational expr1rat = expr1[0].getRational(); 02882 Rational expr2rat = expr2[0].getRational(); 02883 02884 02885 // Check the bounds 02886 if (isLE(expr1) || isLT(expr2)) { 02887 CHECK_SOUND(expr2rat < expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); 02888 } else { 02889 CHECK_SOUND(expr2rat <= expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); 02890 } 02891 if (isGE(expr1) || isGT(expr2)) { 02892 CHECK_SOUND(expr2rat > expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); 02893 } else { 02894 CHECK_SOUND(expr2rat >= expr1rat, "implyWeakerInequality: the implication doesn't apply" + expr1.toString() + " and " + expr2.toString()); 02895 } 02896 } 02897 02898 // Create the proof object 02899 Proof pf; 02900 if(withProof()) pf = newPf("implyWeakerInequality", expr1, expr2); 02901 02902 // Return the theorem 02903 return newTheorem(expr1.impExpr(expr2), Assumptions::emptyAssump(), pf); 02904 } 02905 02906 Theorem ArithTheoremProducer3::implyNegatedInequality(const Expr& expr1, const Expr& expr2) { 02907 02908 // Check soundness 02909 if (CHECK_PROOFS) { 02910 CHECK_SOUND(isIneq(expr1), "implyNegatedInequality: lowerBound should be an inequality " + expr1.toString()); 02911 CHECK_SOUND(isIneq(expr2), "implyNegatedInequality: upperBound should be be an inequality " + expr2.toString()); 02912 CHECK_SOUND(expr1[0].isRational(), "implyNegatedInequality: lowerBound left side should be a rational " + expr1.toString()); 02913 CHECK_SOUND(expr2[0].isRational(), "implyNegatedInequality: upperBound left side should be a rational " + expr2.toString()); 02914 CHECK_SOUND(expr1[1] == expr2[1], "implyNegatedInequality: bounds not on the same term " + expr1.toString() + ", " + expr2.toString()); 02915 02916 // Get the bounds 02917 Rational lowerBoundR = expr1[0].getRational(); 02918 Rational upperBoundR = expr2[0].getRational(); 02919 02920 if (isLE(expr1) && isGE(expr2)) 02921 CHECK_SOUND(upperBoundR < lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); 02922 if (isLT(expr1) || isGT(expr2)) 02923 CHECK_SOUND(upperBoundR <= lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); 02924 if (isGE(expr1) && isLE(expr2)) 02925 CHECK_SOUND(upperBoundR > lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); 02926 if (isGT(expr1) || isLT(expr2)) 02927 CHECK_SOUND(upperBoundR >= lowerBoundR, "implyNegatedInequality: cant imply negation" + expr1.toString() + ", " + expr2.toString()); 02928 } 02929 02930 // The proof object that we will use 02931 Proof pf; 02932 if (withProof()) pf = newPf("implyNegatedInequality", expr1, expr2); 02933 02934 // Return the theorem 02935 return newTheorem(expr1.impExpr(expr2.negate()), Assumptions::emptyAssump(), pf); 02936 } 02937 02938 Theorem ArithTheoremProducer3::trustedRewrite(const Expr& expr1, const Expr& expr2) { 02939 02940 // The proof object that we will us 02941 Proof pf; 02942 02943 // Setup the proof if needed 02944 if (withProof()) pf = newPf("trustedRewrite", expr1, expr2); 02945 02946 // Return the rewrite theorem that explains the phenomenon 02947 return newRWTheorem(expr1, expr2, Assumptions::emptyAssump(), pf); 02948 02949 } 02950 02951 Theorem ArithTheoremProducer3::integerSplit(const Expr& intVar, const Rational& intPoint) { 02952 02953 // Check soundness 02954 if (CHECK_PROOFS) { 02955 CHECK_SOUND(intPoint.isInteger(), "integerSplit: we can only split on integer points, given" + intPoint.toString()); 02956 } 02957 02958 // Create the expression 02959 const Expr& split = Expr(IS_INTEGER, intVar).impExpr(leExpr(intVar, rat(intPoint)).orExpr(geExpr(intVar, rat(intPoint + 1)))); 02960 02961 // The proof object that we will use 02962 Proof pf; 02963 if (withProof()) pf = newPf("integerSplit", intVar, rat(intPoint)); 02964 02965 // Return the theorem 02966 return newTheorem(split, Assumptions::emptyAssump(), pf); 02967 } 02968 02969 02970 Theorem ArithTheoremProducer3::rafineStrictInteger(const Theorem& isIntConstrThm, const Expr& constr) { 02971 02972 02973 // Check soundness 02974 if (CHECK_PROOFS) { 02975 // Right side of the constraint should correspond to the proved integer expression 02976 CHECK_SOUND(isIneq(constr), "rafineStrictInteger: expected a constraint got : " + constr.toString()); 02977 CHECK_SOUND(isIntConstrThm.getExpr()[0] == constr[1], "rafineStrictInteger: proof of intger doesn't correspond to the constarint right side"); 02978 CHECK_SOUND(constr[0].isRational(), "rafineStrictInteger: right side of the constraint muts be a rational"); 02979 } 02980 02981 // Get the contraint bound 02982 Rational bound = constr[0].getRational(); 02983 02984 // Get the kind of the constraint 02985 int kind = constr.getKind(); 02986 02987 // If the bound is strict, make it non-strict 02988 switch (kind) { 02989 case LT: 02990 kind = LE; 02991 if (bound.isInteger()) bound ++; // 3 < x --> 4 <= x 02992 else bound = ceil(bound); // 3.4 < x --> 4 <= x 02993 break; 02994 case LE: 02995 kind = LE; 02996 if (!bound.isInteger()) bound = ceil(bound); // 3.5 <= x --> 4 <= x 02997 break; 02998 case GT: 02999 kind = GE; 03000 if (bound.isInteger()) bound --; // 3 > x --> 2 >= x 03001 else bound = floor(bound); // 3.4 > x --> 3 >= x 03002 break; 03003 case GE: 03004 kind = GE; 03005 if (!bound.isInteger()) bound = floor(bound); // 3.4 >= x --> 3 >= x 03006 break; 03007 } 03008 03009 // The new constraint 03010 Expr newConstr(kind, rat(bound), constr[1]); 03011 03012 // Pick up the assumptions from the integer proof 03013 const Assumptions& assump(isIntConstrThm.getAssumptionsRef()); 03014 03015 // Construct the proof object if necessary 03016 Proof pf; 03017 if (withProof()) pf = newPf("rafineStrictInteger", constr, isIntConstrThm.getProof()); 03018 03019 // Return the rewrite theorem that explains the phenomenon 03020 return newRWTheorem(constr, newConstr, assump, pf); 03021 } 03022 03023 03024 Theorem ArithTheoremProducer3::splitGrayShadowSmall(const Theorem& gThm) { 03025 DebugAssert(false, "Not implemented!!!"); 03026 return Theorem(); 03027 } 03028 03029 Theorem ArithTheoremProducer3::implyWeakerInequalityDiffLogic(const std::vector<Theorem>& antecedentThms, const Expr& implied) { 03030 DebugAssert(false, "Not implemented!!!"); 03031 return Theorem(); 03032 } 03033 03034 Theorem ArithTheoremProducer3::implyNegatedInequalityDiffLogic(const std::vector<Theorem>& antecedentThms, const Expr& implied) { 03035 DebugAssert(false, "Not implemented!!!"); 03036 return Theorem(); 03037 } 03038 03039 Theorem ArithTheoremProducer3::expandGrayShadowRewrite(const Expr& theShadow) { 03040 DebugAssert(false, "Not implemented!!!"); 03041 return Theorem(); 03042 } 03043 03044 Theorem ArithTheoremProducer3::compactNonLinearTerm(const Expr& nonLinear) { 03045 DebugAssert(false, "Not implemented!!!"); 03046 return Theorem(); 03047 } 03048 03049 Theorem ArithTheoremProducer3::nonLinearIneqSignSplit(const Theorem& ineqThm) { 03050 DebugAssert(false, "Not implemented!!!"); 03051 return Theorem(); 03052 } 03053 03054 Theorem ArithTheoremProducer3::implyDiffLogicBothBounds(const Expr& x, 03055 std::vector<Theorem>& c1_le_x, Rational c1, 03056 std::vector<Theorem>& x_le_c2, Rational c2) { 03057 DebugAssert(false, "Not implemented!!!"); 03058 return Theorem(); 03059 } 03060 03061 Theorem ArithTheoremProducer3::addInequalities(const vector<Theorem>& thms) { 03062 DebugAssert(false, "Not implemented!!!"); 03063 return Theorem(); 03064 } 03065 03066 Theorem ArithTheoremProducer3::powerOfOne(const Expr& e) { 03067 DebugAssert(false, "Not implemented!!!"); 03068 return Theorem(); 03069 } 03070 03071 // 03072 // This one is here just to compile... the code is in old arithmetic 03073 Theorem ArithTheoremProducer3::simpleIneqInt(const Expr& ineq, const Theorem& isIntRHS) 03074 { 03075 DebugAssert(false, "Not implemented!!!"); 03076 return Theorem(); 03077 } 03078 03079 // Given: 03080 // 0 = c + t 03081 // where t is integer and c is not 03082 // deduce bot 03083 Theorem ArithTheoremProducer3::intEqualityRationalConstant(const Theorem& isIntConstrThm, const Expr& constr) { 03084 DebugAssert(false, "Not implemented!!!"); 03085 return Theorem(); 03086 } 03087 03088 Theorem ArithTheoremProducer3::cycleConflict(const vector<Theorem>& inequalitites) { 03089 DebugAssert(false, "Not implemented!!!"); 03090 return Theorem(); 03091 } 03092 03093 Theorem ArithTheoremProducer3::implyEqualities(const vector<Theorem>& inequalitites) { 03094 DebugAssert(false, "Not implemented!!!"); 03095 return Theorem(); 03096 } 03097 03098 03099 /*! Takes a Theorem(\\alpha < \\beta) and returns 03100 * Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1) 03101 * where \\alpha and \\beta are integer expressions 03102 */ 03103 Theorem ArithTheoremProducer3::lessThanToLERewrite(const Expr& ineq, 03104 const Theorem& isIntLHS, 03105 const Theorem& isIntRHS, 03106 bool changeRight) { 03107 03108 const Expr& isIntLHSexpr = isIntLHS.getExpr(); 03109 const Expr& isIntRHSexpr = isIntRHS.getExpr(); 03110 03111 if(CHECK_PROOFS) { 03112 CHECK_SOUND(isLT(ineq), "ArithTheoremProducerOld::LTtoLE: ineq must be <"); 03113 // Integrality check 03114 CHECK_SOUND(isIntPred(isIntLHSexpr) && isIntLHSexpr[0] == ineq[0], 03115 "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n" 03116 " ineq = "+ineq.toString()+"\n isIntLHS = " 03117 +isIntLHSexpr.toString()); 03118 CHECK_SOUND(isIntPred(isIntRHSexpr) && isIntRHSexpr[0] == ineq[1], 03119 "ArithTheoremProducerOld::lessThanToLE: bad integrality check:\n" 03120 " ineq = "+ineq.toString()+"\n isIntRHS = " 03121 +isIntRHSexpr.toString()); 03122 } 03123 03124 vector<Theorem> thms; 03125 thms.push_back(isIntLHS); 03126 thms.push_back(isIntRHS); 03127 Assumptions a(thms); 03128 Proof pf; 03129 Expr le = changeRight? leExpr(ineq[0], ineq[1] + rat(-1)) : leExpr(ineq[0] + rat(1), ineq[1]); 03130 if(withProof()) { 03131 vector<Proof> pfs; 03132 pfs.push_back(isIntLHS.getProof()); 03133 pfs.push_back(isIntRHS.getProof()); 03134 pf = newPf(changeRight? "lessThan_To_LE_rhs" : "lessThan_To_LE_lhs", le, pfs); 03135 } 03136 03137 return newRWTheorem(ineq, le, a, pf); 03138 }