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