arith_theorem_producer.cpp

Go to the documentation of this file.
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  * Copyright (C) 2003 by the Board of Trustees of Leland Stanford
00011  * Junior University and by New York University. 
00012  *
00013  * License to use, copy, modify, sell and/or distribute this software
00014  * and its documentation for any purpose is hereby granted without
00015  * royalty, subject to the terms and conditions defined in the \ref
00016  * LICENSE file provided with this distribution.  In particular:
00017  *
00018  * - The above copyright notice and this permission notice must appear
00019  * in all copies of the software and related documentation.
00020  *
00021  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00022  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00023  * 
00024  * <hr>
00025  * 
00026  */
00027 /*****************************************************************************/
00028 // CLASS: ArithProofRules
00029 //
00030 // AUTHOR: Sergey Berezin, 12/11/2002
00031 // AUTHOR: Vijay Ganesh,   05/30/2003
00032 //
00033 // Description: TRUSTED implementation of arithmetic proof rules.
00034 //
00035 ///////////////////////////////////////////////////////////////////////////////
00036 
00037 // This code is trusted
00038 #define _CVCL_TRUSTED_
00039 
00040 #include "arith_theorem_producer.h"
00041 #include "theory_core.h"
00042 
00043 using namespace std;
00044 using namespace CVCL;
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 // TheoryArith: trusted method for creating ArithTheoremProducer
00048 ////////////////////////////////////////////////////////////////////
00049 
00050 ArithProofRules* TheoryArith::createProofRules() {
00051   return new ArithTheoremProducer(theoryCore()->getTM(), this);
00052 }
00053   
00054 ////////////////////////////////////////////////////////////////////
00055 // Canonization rules
00056 ////////////////////////////////////////////////////////////////////
00057 
00058 
00059 #define CLASS_NAME "ArithTheoremProducer"
00060 
00061 
00062 // Rule for unary minus: -e == (-1) * e
00063 Theorem ArithTheoremProducer::uMinusToMult(const Expr& e) {
00064   Assumptions a; // no assumptions
00065   Proof pf;
00066   if(withProof()) pf = newPf("uminus_to_mult", e);
00067   return newRWTheorem((-e), (rat(-1) * e), a, pf);
00068 }
00069 
00070 
00071 // ==> x - y = x + (-1) * y
00072 Theorem ArithTheoremProducer::minusToPlus(const Expr& x, const Expr& y)
00073 {
00074   Assumptions a; // no assumptions
00075   Proof pf;
00076   if(withProof()) pf = newPf("minus_to_plus", x, y);
00077   return newRWTheorem((x-y), (x + (rat(-1) * y)), a, pf);  
00078 }
00079 
00080 
00081 // Rule for unary minus: -e == e/(-1)
00082 // This is to reduce the number of almost identical rules for uminus and div
00083 Theorem ArithTheoremProducer::canonUMinusToDivide(const Expr& e) {
00084   Assumptions a; // no assumptions
00085   Proof pf;
00086   if(withProof()) pf = newPf("canon_uminus", e);
00087   return newRWTheorem((-e), (e / rat(-1)), a, pf);
00088 }
00089 
00090 // Rules for division by constant
00091 
00092 // (c)/(d) ==> (c/d).  When d==0, c/0 = 0 (our total extension).
00093 Theorem ArithTheoremProducer::canonDivideConst(const Expr& c,
00094                                                const Expr& d) {
00095   // Make sure c and d are a const
00096   if(CHECK_PROOFS) {
00097     CHECK_SOUND(isRational(c),
00098                 CLASS_NAME "::canonDivideConst:\n c not a constant: "
00099                 + c.toString());
00100     CHECK_SOUND(isRational(d),
00101                 CLASS_NAME "::canonDivideConst:\n d not a constant: "
00102                 + d.toString());
00103   }
00104   Assumptions a; // no assumptions
00105   Proof pf;
00106   if(withProof())
00107     pf = newPf("canon_divide_const", c, d, d_hole);
00108   const Rational& dr = d.getRational();
00109   return newRWTheorem((c/d), (rat(dr==0? 0 : (c.getRational()/dr))), a, pf);
00110 }
00111 
00112 // (c * x)/d ==> (c/d) * x, takes (c*x) and d
00113 Theorem ArithTheoremProducer::canonDivideMult(const Expr& cx,
00114                                               const Expr& d) {
00115   // Check the format of c*x
00116   if(CHECK_PROOFS) {
00117     CHECK_SOUND(isMult(cx) && isRational(cx[0]),
00118                 CLASS_NAME "::canonDivideMult:\n  "
00119                 "Not a (c * x) expression: "
00120                 + cx.toString());
00121     CHECK_SOUND(isRational(d),
00122                 CLASS_NAME "::canonDivideMult:\n  "
00123                 "d is not a constant: " + d.toString());
00124   }
00125   const Rational& dr = d.getRational();
00126   Rational cdr(dr==0? 0 : (cx[0].getRational()/dr));
00127   Expr cd(rat(cdr));
00128   Assumptions a;
00129   Proof pf;
00130   if(withProof())
00131     pf = newPf("canon_divide_mult", cx[0], cx[1], d);
00132   // (c/d) may be == 1, so we also need to canonize 1*x to x
00133   if(cdr == 1)
00134     return newRWTheorem((cx/d), (cx[1]), a, pf);
00135   else if(cdr == 0) // c/0 == 0 case
00136     return newRWTheorem((cx/d), cd, a, pf);
00137   else
00138     return newRWTheorem((cx/d), (cd*cx[1]), a, pf);
00139 }
00140 
00141 // (+ t1 ... tn)/d ==> (+ (t1/d) ... (tn/d))
00142 Theorem ArithTheoremProducer::canonDividePlus(const Expr& sum, const Expr& d) {
00143   if(CHECK_PROOFS) {
00144     CHECK_SOUND(isPlus(sum) && sum.arity() >= 2 && isRational(sum[0]),
00145                 CLASS_NAME "::canonUMinusPlus:\n  "
00146                 "Expr is not a canonical sum: "
00147                 + sum.toString());
00148     CHECK_SOUND(isRational(d),
00149                 CLASS_NAME "::canonUMinusPlus:\n  "
00150                 "d is not a const: " + d.toString());
00151   }
00152   // First, propagate '/d' down to the args
00153   Assumptions a; // no assumptions
00154   Proof pf;
00155   if(withProof())
00156     pf = newPf("canon_divide_plus", rat(sum.arity()),
00157                sum.begin(), sum.end());
00158   vector<Expr> newKids;
00159   for(Expr::iterator i=sum.begin(), iend=sum.end(); i!=iend; ++i)
00160     newKids.push_back((*i)/d);
00161   // (+ t1 ... tn)/d == (+ (t1/d) ... (tn/d))
00162   return newRWTheorem((sum/d), (plusExpr(newKids)), a, pf);
00163 }
00164 
00165 // x/(d) ==> (1/d) * x, unless d == 1
00166 Theorem ArithTheoremProducer::canonDivideVar(const Expr& e, const Expr& d) {
00167   if(CHECK_PROOFS) {
00168     CHECK_SOUND(isRational(d),
00169                 CLASS_NAME "::canonDivideVar:\n  "
00170                 "d is not a const: " + d.toString());
00171   }
00172   Assumptions a;
00173   Proof pf;
00174 
00175   if(withProof())
00176     pf = newPf("canon_divide_var", e);
00177 
00178   const Rational& dr = d.getRational();
00179   if(dr == 1) 
00180     return newRWTheorem(e/d, e, a, pf);
00181   if(dr == 0) // e/0 == 0 (total extension of division)
00182     return newRWTheorem(e/d, d, a, pf);
00183   else
00184     return newRWTheorem(e/d, rat(1/dr) * e, a, pf);
00185 }
00186 
00187 
00188 // Multiplication
00189 // (MULT expr1 expr2 expr3 ...)
00190 // Each expr is in canonical form, i.e. it can be a
00191 // 1) Rational constant
00192 // 2) Arithmetic Leaf (var or term from another theory)
00193 // 3) (POW rational leaf)
00194 // where rational cannot be 0 or 1
00195 // 4) (MULT rational mterm'_1 ...) where each mterm' is of type (2) or (3)
00196 // If rational == 1 then there should be at least two mterms
00197 // 5) (PLUS rational sterm_1 ...) where each sterm is of 
00198 //     type (2) or (3) or (4) 
00199 //    if rational == 0 then there should be at least two sterms
00200 
00201 
00202 Expr ArithTheoremProducer::simplifiedMultExpr(std::vector<Expr> & mulKids)
00203 {
00204   DebugAssert(mulKids.size() >= 1 && mulKids[0].isRational(), "");
00205   if (mulKids.size() == 1) {
00206     return mulKids[0];
00207   }
00208   if ((mulKids[0] == rat(1)) && mulKids.size() == 2) {
00209     return mulKids[1];
00210   }
00211   else
00212     return multExpr(mulKids);
00213 }
00214 
00215 Expr ArithTheoremProducer::canonMultConstMult(const Expr & c,
00216                                               const Expr & e)
00217 {
00218   // c is a rational
00219   // e is (MULT rat mterm'_1 ....)
00220   // assume that e2 is already in canonic form
00221   DebugAssert(c.isRational() && e.getKind() == MULT, "");
00222   std::vector<Expr> mulKids;
00223   DebugAssert ((e.arity() > 1) && (e[0].isRational()),
00224                "arith_theorem_producer::canonMultConstMult: "
00225                "a canonized MULT expression must have arity "
00226                "greater than 1: and first child must be "
00227                "rational " + e.toString());
00228   Expr::iterator i = e.begin();
00229   mulKids.push_back(rat(c.getRational() * (*i).getRational()));
00230   ++i;
00231   for(; i != e.end(); ++i) {
00232     mulKids.push_back(*i);
00233   }
00234   return simplifiedMultExpr(mulKids);
00235 }
00236 
00237 Expr ArithTheoremProducer::canonMultConstPlus(const Expr & e1,
00238                                               const Expr & e2)
00239 {
00240   DebugAssert(e1.isRational() && e2.getKind() == PLUS &&
00241               e2.arity() > 0, "");
00242   // e1 is a rational
00243   // e2 is of the form (PLUS rational sterm1 sterm2 ...)
00244   // assume that e2 is already in canonic form
00245   std::vector<Theorem> thmPlusVector;
00246   Expr::iterator i = e2.begin();
00247   for(; i!= e2.end(); ++i) {
00248     thmPlusVector.push_back(canonMultMtermMterm(e1*(*i)));
00249   }
00250     
00251   Theorem thmPlus1 = 
00252     d_theoryArith->substitutivityRule(e2.getOp(), thmPlusVector);
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 
00435 ArithTheoremProducer::canonCombineLikeTerms(const std::vector<Expr> & sumExprs)
00436 {
00437   Rational constant = 0;
00438   MonomMap sumHashMap;
00439   vector<Expr> sumKids;
00440  
00441   // Add each distinct mterm (not including the rational) into 
00442   // an appropriate hash map entry 
00443   std::vector<Expr>::const_iterator i = sumExprs.begin();
00444   for (; i != sumExprs.end(); ++i) {
00445     Expr mul = *i;
00446     if (mul.isRational()) {
00447       constant = constant + mul.getRational();
00448     }
00449     else {
00450       switch (mul.getKind()) {
00451       case MULT: {
00452         std::vector<Expr> mulKids;
00453         DebugAssert(mul.arity() > 1 && mul[0].isRational(),"");
00454         mulKids.push_back(rat(1));
00455         Expr::iterator j = mul.begin();
00456         ++j;
00457         for (; j!= mul.end(); ++j) {
00458           mulKids.push_back(*j);
00459         }
00460                 
00461         // make sure that tempExpr is also in canonic form
00462         Expr tempExpr = mulKids.size() > 2 ? multExpr(mulKids): mulKids[1];
00463         MonomMap::iterator i=sumHashMap.find(tempExpr);
00464         if (i == sumHashMap.end()) {
00465           sumHashMap[tempExpr] = mul[0].getRational();
00466         }
00467         else {
00468           (*i).second += mul[0].getRational();
00469         }
00470       }
00471         break;
00472       default: {
00473         MonomMap::iterator i=sumHashMap.find(mul);
00474         // covers the case of POW, leaf
00475         if (i == sumHashMap.end()) {
00476           sumHashMap[mul] = 1;
00477         }
00478         else {
00479           (*i).second += 1;
00480         }
00481         break;
00482       }
00483       }
00484     }
00485   }
00486   // Now transfer to sumKids
00487   sumKids.push_back(rat(constant));
00488   MonomMap::iterator j = sumHashMap.begin(), jend=sumHashMap.end();
00489   for(; j != jend; ++j) {
00490     if ((*j).second != 0)
00491       sumKids.push_back
00492         (canonMultMtermMterm(rat((*j).second) * (*j).first).getRHS());
00493   }
00494     
00495   /*
00496     for (unsigned k = 0; k < sumKids.size(); ++k)
00497     {
00498     cout << "sumKids[" << k << "] = " << sumKids[k].toString() << endl;
00499     }
00500   */    
00501 
00502   // The ordering in map guarantees the correct order; no need to sort
00503 
00504   // std::sort(sumKids.begin(), sumKids.end(), greaterthan);
00505     
00506   if ((constant == 0) && (sumKids.size() == 2)) {
00507     return sumKids[1];
00508   }
00509   else if (sumKids.size() == 1) {
00510     return sumKids[0];
00511   }
00512   else
00513     return plusExpr(sumKids);
00514 }
00515 
00516 Expr ArithTheoremProducer::canonMultLeafOrPowOrMultPlus(const Expr & e1,
00517                                                         const Expr & e2)
00518 {
00519   DebugAssert(e2.getKind() == PLUS, "");
00520   // Leaf *  (PLUS rational sterm1 ...) 
00521   // or 
00522   // (POW n1 x1) * (PLUS rational sterm1 ...)
00523   // or
00524   // (MULT r1 m1 m2 ...) * (PLUS rational sterm1 ...)
00525   // assume that e1 and e2 are themselves canonized
00526   std::vector<Expr> sumExprs;
00527   // Multiply each term in turn. 
00528   Expr::iterator i = e2.begin();
00529   for (; i != e2.end(); ++i) {
00530     sumExprs.push_back(canonMultMtermMterm(e1 * (*i)).getRHS());
00531   }
00532   return canonCombineLikeTerms(sumExprs);
00533 }
00534 
00535 Expr ArithTheoremProducer::canonMultPlusPlus(const Expr & e1,
00536                                              const Expr & e2)
00537 {
00538   DebugAssert(e1.getKind() == PLUS && e2.getKind() == PLUS, "");
00539   // (PLUS r1 .... ) * (PLUS r1' ...)
00540   // assume that e1 and e2 are themselves canonized
00541 
00542   std::vector<Expr> sumExprs;
00543   // Multiply each term in turn. 
00544   Expr::iterator i = e1.begin();
00545   for (;  i != e1.end(); ++i) {
00546     Expr::iterator j = e2.begin();
00547     for (;  j != e2.end(); ++j) {
00548       sumExprs.push_back(canonMultMtermMterm((*i) * (*j)).getRHS());
00549     }
00550   }
00551   return canonCombineLikeTerms(sumExprs);
00552 }
00553 
00554 
00555 
00556 // The following produces a Theorem which is the result of multiplication
00557 // of two canonized mterms.  e = e1*e2
00558 Theorem
00559 ArithTheoremProducer::canonMultMtermMterm(const Expr& e)
00560 {
00561   if(CHECK_PROOFS) {
00562     CHECK_SOUND(isMult(e) && e.arity() == 2, 
00563                 "canonMultMtermMterm: e = "+e.toString());
00564   }
00565   Assumptions a;
00566   Proof pf;
00567   Expr rhs;
00568   const Expr& e1 = e[0];
00569   const Expr& e2 = e[1];
00570   string cmmm = "canon_mult_mterm_mterm";
00571 
00572   if (e1.isRational()) {
00573     // e1 is a Rational
00574     const Rational& c = e1.getRational();
00575     if (c == 0)
00576       return canonMultZero(e2);
00577     else if (c == 1)
00578       return canonMultOne(e2);
00579     else {
00580       switch (e2.getKind()) {
00581       case RATIONAL_EXPR :
00582         // rat * rat
00583         return canonMultConstConst(e1,e2);
00584         break;
00585         // TODO case of leaf
00586       case POW:
00587         // rat * (POW rat leaf)
00588         // nothing to simplify
00589         return d_theoryArith->reflexivityRule (e);
00590                 
00591         break;
00592       case MULT:
00593         rhs = canonMultConstMult(e1,e2);
00594         if(withProof()) pf = newPf(cmmm,e,rhs);
00595         return newRWTheorem(e, rhs, a, pf);
00596         break;
00597       case PLUS:
00598         rhs = canonMultConstPlus(e1,e2);
00599         if(withProof()) pf = newPf(cmmm,e,rhs);
00600         return newRWTheorem(e, rhs, a, pf);
00601         break;
00602       default:
00603         // TODO: I am going to assume that this is just a leaf
00604         // i.e., a variable or term from another theory
00605         return d_theoryArith->reflexivityRule(e);
00606         break;
00607       }
00608     }
00609   }
00610   else if (e1.getKind() == POW) {
00611     switch (e2.getKind()) {
00612     case RATIONAL_EXPR:
00613       // switch the order of the two arguments
00614       return canonMultMtermMterm(e2 * e1);
00615       break;
00616     case POW:
00617       rhs = canonMultPowPow(e1,e2);
00618       if(withProof()) pf = newPf(cmmm,e,rhs);
00619       return newRWTheorem(e,rhs, a, pf);
00620       break;
00621     case MULT:
00622       rhs = canonMultLeafOrPowMult(e1,e2);
00623       if(withProof()) pf = newPf(cmmm,e,rhs);
00624       return newRWTheorem(e, rhs, a, pf);
00625       break;
00626     case PLUS:
00627       rhs = canonMultLeafOrPowOrMultPlus(e1,e2);
00628       if(withProof()) pf = newPf(cmmm,e,rhs);
00629       return newRWTheorem(e, rhs, a, pf);                          
00630       break;
00631     default:
00632       rhs = canonMultPowLeaf(e1,e2);
00633       if(withProof()) pf = newPf(cmmm,e,rhs);
00634       return newRWTheorem(e,rhs, a, pf);
00635       break;
00636     }
00637   }
00638   else if (e1.getKind() == MULT) {
00639     switch (e2.getKind()) {
00640     case RATIONAL_EXPR:
00641     case POW:
00642       // switch the order of the two arguments
00643       return canonMultMtermMterm(e2 * e1);
00644       break;
00645     case MULT:
00646       {
00647         // (Mult r m1 m2 ...) (Mult r' m1' m2' ...)
00648         Expr result = e2;
00649         Expr::iterator i = e1.begin();
00650         for (; i != e1.end(); ++i) {
00651           result = canonMultMtermMterm((*i) * result).getRHS();
00652         }
00653         if(withProof()) pf = newPf(cmmm,e,result);
00654         return newRWTheorem(e, result, a, pf);
00655       }
00656       break;
00657     case PLUS:
00658       rhs = canonMultLeafOrPowOrMultPlus(e1,e2);
00659       if(withProof()) pf = newPf(cmmm,e,rhs);
00660       return newRWTheorem(e,rhs, a, pf);
00661       break;
00662     default:
00663       // leaf
00664       // switch the order of the two arguments
00665       return canonMultMtermMterm(e2 * e1);
00666       break;
00667     }
00668   }
00669   else if (e1.getKind() == PLUS) {
00670     switch (e2.getKind()) {
00671     case RATIONAL_EXPR:
00672     case POW:
00673     case MULT:
00674       // switch the order of the two arguments
00675       return canonMultMtermMterm(e2 * e1);
00676       break;
00677     case PLUS:
00678       rhs = canonMultPlusPlus(e1,e2);
00679       if(withProof()) pf = newPf(cmmm,e,rhs);
00680       return newRWTheorem(e, rhs, a, pf);
00681       break;
00682     default:
00683       // leaf
00684       // switch the order of the two arguments
00685       return canonMultMtermMterm(e2 * e1);
00686       break;
00687     }
00688   }
00689   else {
00690     // leaf
00691     switch (e2.getKind()) {
00692     case RATIONAL_EXPR:
00693       // switch the order of the two arguments
00694       return canonMultMtermMterm(e2 * e1);
00695       break;
00696     case POW:
00697       rhs = canonMultPowLeaf(e2,e1);
00698       if(withProof()) pf = newPf(cmmm,e,rhs);
00699       return newRWTheorem(e, rhs, a, pf);
00700       break;
00701     case MULT:
00702       rhs = canonMultLeafOrPowMult(e1,e2);;
00703       if(withProof()) pf = newPf(cmmm,e,rhs);
00704       return newRWTheorem(e, rhs, a, pf);
00705       break;
00706     case PLUS:
00707       rhs = canonMultLeafOrPowOrMultPlus(e1,e2);
00708       if(withProof()) pf = newPf(cmmm,e,rhs);
00709       return newRWTheorem(e, rhs, a, pf);
00710       break;
00711     default:
00712       // leaf * leaf
00713       rhs = canonMultLeafLeaf(e1,e2);
00714       if(withProof()) pf = newPf(cmmm,e,rhs);
00715       return newRWTheorem(e, rhs, a, pf);
00716       break;
00717     }
00718   }
00719   FatalAssert(false, "Unreachable");
00720   return newRWTheorem(e, rhs, a, pf);
00721 }
00722 
00723 // (PLUS expr1 expr2 ...) where each expr is itself in canonic form
00724 Theorem
00725 ArithTheoremProducer::canonPlus(const Expr& e) 
00726 {
00727   Assumptions a;
00728   Proof pf;
00729     
00730   if (withProof()) {
00731     pf = newPf("canon_plus", e);
00732   }
00733   DebugAssert(e.getKind() == PLUS, "");
00734 
00735   // First flatten the PLUS
00736 
00737   std::vector<Expr> sumKids;
00738   Expr::iterator i = e.begin();
00739   for(; i != e.end(); ++i) {
00740     if ((*i).getKind() != PLUS) {
00741       sumKids.push_back(*i);
00742     }
00743     else
00744       {
00745         Expr::iterator j = (*i).begin();
00746         for(; j != (*i).end(); ++j)
00747           sumKids.push_back(*j);
00748       }
00749   }
00750   Expr val = canonCombineLikeTerms(sumKids);
00751   if (withProof()) {
00752     pf = newPf("canon_plus", e, val);
00753   }    
00754   return newRWTheorem(e, val, a, pf);
00755 }
00756 
00757 // (MULT expr1 expr2 ...) where each expr is itself in canonic form
00758 Theorem
00759 ArithTheoremProducer::canonMult(const Expr& e) 
00760 {
00761   Assumptions a;
00762   Proof pf;
00763   DebugAssert(e.getKind() == MULT && e.arity() > 1, "");
00764   Expr::iterator i = e.begin();
00765   Expr result = *i;
00766   ++i;
00767   for (; i != e.end(); ++i) {
00768     result = canonMultMtermMterm(result * (*i)).getRHS();
00769   }
00770   if (withProof()) {
00771     pf = newPf("canon_mult", e,result);
00772   }
00773   return newRWTheorem(e, result, a, pf);
00774 }
00775 
00776 
00777 Theorem
00778 ArithTheoremProducer::canonInvertConst(const Expr& e) 
00779 {
00780   if(CHECK_PROOFS)
00781     CHECK_SOUND(isRational(e), "expecting a rational: e = "+e.toString());
00782     
00783   Assumptions a;
00784   Proof pf;
00785     
00786   if (withProof()) {
00787     pf = newPf("canon_invert_const", e);
00788   }
00789   const Rational& er = e.getRational();
00790   return newRWTheorem((rat(1)/e), rat(er==0? 0 : (1/er)), a, pf);
00791 }
00792 
00793 
00794 Theorem
00795 ArithTheoremProducer::canonInvertLeaf(const Expr& e) 
00796 {
00797   Assumptions a;
00798   Proof pf;
00799     
00800   if (withProof()) {
00801     pf = newPf("canon_invert_leaf", e);
00802   }
00803   return newRWTheorem((rat(1)/e), powExpr(rat(-1), e), a, pf);
00804 }
00805 
00806 
00807 Theorem
00808 ArithTheoremProducer::canonInvertPow(const Expr& e) 
00809 {
00810   DebugAssert(e.getKind() == POW, "expecting a rational"+e[0].toString());
00811     
00812   Assumptions a;
00813   Proof pf;
00814     
00815   if (withProof()) {
00816     pf = newPf("canon_invert_pow", e);
00817   }
00818   if (e[0].getRational() == -1)
00819     return newRWTheorem((rat(1)/e), e[1], a, pf);
00820   else
00821     return newRWTheorem((rat(1)/e), 
00822                         powExpr(rat(-e[0].getRational()), e), 
00823                         a, 
00824                         pf);
00825 }
00826 
00827 Theorem
00828 ArithTheoremProducer::canonInvertMult(const Expr& e) 
00829 {
00830   DebugAssert(e.getKind() == MULT, "expecting a rational"+e[0].toString());
00831 
00832   Assumptions a;
00833   Proof pf;
00834     
00835   if (withProof()) {
00836     pf = newPf("canon_invert_mult", e);
00837   }
00838 
00839   DebugAssert(e.arity() > 1, "MULT should have arity > 1"+e.toString());
00840   Expr result = canonInvert(e[0]).getRHS();
00841   for (int i = 1; i < e.arity(); ++i) {
00842     result = 
00843       canonMultMtermMterm(result * canonInvert(e[i]).getRHS()).getRHS();
00844   }
00845   return newRWTheorem((rat(1)/e), result, a, pf);
00846 }
00847 
00848 
00849 // Given an expression e in Canonic form generate 1/e in canonic form
00850 // This function assumes that e is not a PLUS expression
00851 Theorem
00852 ArithTheoremProducer::canonInvert(const Expr& e) 
00853 {
00854   DebugAssert(e.getKind() != PLUS, 
00855               "Cannot do inverse on a PLUS"+e.toString());
00856   switch (e.getKind()) {
00857   case RATIONAL_EXPR:
00858     return canonInvertConst(e);
00859     break;
00860   case POW:
00861     return canonInvertPow(e);
00862     break;
00863   case MULT:
00864     return canonInvertMult(e);
00865     break;
00866   default:
00867     // leaf
00868     return canonInvertLeaf(e);
00869     break;
00870   }
00871 }
00872 
00873 
00874 Theorem
00875 ArithTheoremProducer::canonDivide(const Expr& e) 
00876 {
00877   DebugAssert(e.getKind() == DIVIDE, "Expecting Divide"+e.toString());
00878   Assumptions a;
00879   Proof pf;
00880     
00881   if (withProof()) {
00882     pf = newPf("canon_invert_divide", e);
00883   }
00884 
00885   Theorem thm = newRWTheorem(e, e[0]*(canonInvert(e[1]).getRHS()), a, pf);
00886     
00887   return d_theoryArith->transitivityRule(thm, canonMult(thm.getRHS()));
00888 }
00889 
00890 
00891 // Rules for multiplication
00892 // t*c ==> c*t, takes constant c and term t
00893 Theorem 
00894 ArithTheoremProducer::canonMultTermConst(const Expr& c, const Expr& t) {
00895   Assumptions a;
00896   Proof pf;
00897   if(CHECK_PROOFS) {
00898     CHECK_SOUND(isRational(c),
00899                 CLASS_NAME "::canonMultTermConst:\n  "
00900                 "c is not a constant: " + c.toString());
00901   }
00902   if(withProof()) pf = newPf("canon_mult_term_const", c, t);
00903   return newRWTheorem((t*c), (c*t), a, pf);
00904 }
00905 
00906 // Rules for multiplication
00907 // t1*t2 ==> Error, takes t1 and t2 where both are non-constants
00908 Theorem 
00909 ArithTheoremProducer::canonMultTerm1Term2(const Expr& t1, const Expr& t2) {
00910   // Assumptions a;
00911   // Proof pf;
00912   // if(withProof()) pf = newPf("canon_mult_term1_term2", t1, t2);
00913   if(CHECK_PROOFS) {
00914     CHECK_SOUND(false, "Fatal Error: We don' support multiplication"
00915                 "of two non constant terms at this time " 
00916                 + t1.toString() + " and " + t2.toString());
00917   }
00918   return Theorem();
00919 }
00920 
00921 // Rules for multiplication
00922 // 0*x = 0, takes x
00923 Theorem ArithTheoremProducer::canonMultZero(const Expr& e) {
00924   Assumptions a;
00925   Proof pf;
00926   if(withProof()) pf = newPf("canon_mult_zero", e);
00927   return newRWTheorem((rat(0)*e), rat(0), a, pf);
00928 }
00929 
00930 // Rules for multiplication
00931 // 1*x ==> x, takes x
00932 Theorem ArithTheoremProducer::canonMultOne(const Expr& e) {
00933   Assumptions a;
00934   Proof pf;
00935   if(withProof()) pf = newPf("canon_mult_one", e);
00936   return newRWTheorem((rat(1)*e), e, a, pf);
00937 }
00938 
00939 // Rules for multiplication
00940 // c1*c2 ==> c', takes constant c1*c2 
00941 Theorem 
00942 ArithTheoremProducer::canonMultConstConst(const Expr& c1, const Expr& c2) {
00943   Assumptions a;
00944   Proof pf;
00945   if(CHECK_PROOFS) {
00946     CHECK_SOUND(isRational(c1),
00947                 CLASS_NAME "::canonMultConstConst:\n  "
00948                 "c1 is not a constant: " + c1.toString());
00949     CHECK_SOUND(isRational(c2),
00950                 CLASS_NAME "::canonMultConstConst:\n  "
00951                 "c2 is not a constant: " + c2.toString());
00952   }
00953   if(withProof()) pf = newPf("canon_mult_const_const", c1, c2);
00954   return 
00955     newRWTheorem((c1*c2), rat(c1.getRational()*c2.getRational()), a, pf);
00956 }
00957 
00958 // Rules for multiplication
00959 // c1*(c2*t) ==> c'*t, takes c1 and c2 and t
00960 Theorem 
00961 ArithTheoremProducer::canonMultConstTerm(const Expr& c1,
00962                                          const Expr& c2,const Expr& t) {
00963   Assumptions a;
00964   Proof pf;
00965   if(CHECK_PROOFS) {
00966     CHECK_SOUND(isRational(c1),
00967                 CLASS_NAME "::canonMultConstTerm:\n  "
00968                 "c1 is not a constant: " + c1.toString());
00969     CHECK_SOUND(isRational(c2),
00970                 CLASS_NAME "::canonMultConstTerm:\n  "
00971                 "c2 is not a constant: " + c2.toString());
00972   }
00973   
00974   if(withProof()) pf = newPf("canon_mult_const_term", c1, c2, t);
00975   return 
00976     newRWTheorem(c1*(c2*t), rat(c1.getRational()*c2.getRational())*t, a, pf);
00977 }
00978 
00979 // Rules for multiplication
00980 // c1*(+ c2 v1 ...) ==> (+ c1c2 c1v1 ...), takes c1 and the sum
00981 Theorem 
00982 ArithTheoremProducer::canonMultConstSum(const Expr& c1, const Expr& sum) {
00983   Assumptions a;
00984   Proof pf;
00985   std::vector<Expr> sumKids;
00986   
00987   if(CHECK_PROOFS) {
00988     CHECK_SOUND(isRational(c1),
00989                 CLASS_NAME "::canonMultConstTerm:\n  "
00990                 "c1 is not a constant: " + c1.toString());
00991     CHECK_SOUND(PLUS == sum.getKind(),
00992                 CLASS_NAME "::canonMultConstTerm:\n  "
00993                 "the kind must be a PLUS: " + sum.toString());
00994   }
00995   Expr::iterator i = sum.begin();
00996   for(; i != sum.end(); ++i)
00997     sumKids.push_back(c1*(*i));
00998   Expr ret = plusExpr(sumKids);
00999   if(withProof()) pf = newPf("canon_mult_const_sum", c1, sum, ret);
01000   return newRWTheorem((c1*sum),ret , a, pf);
01001 }
01002 
01003 
01004 // c^n = c' (compute the constant power expression)
01005 Theorem
01006 ArithTheoremProducer::canonPowConst(const Expr& e) {
01007   if(CHECK_PROOFS) {
01008     CHECK_SOUND(e.getKind() == POW && e.arity() == 2
01009                 && e[0].isRational() && e[1].isRational(),
01010                 "ArithTheoremProducer::canonPowConst("+e.toString()+")");
01011   }
01012   const Rational& p = e[0].getRational();
01013   const Rational& base = e[1].getRational();
01014   if(CHECK_PROOFS) {
01015     CHECK_SOUND(p.isInteger(),
01016                 "ArithTheoremProducer::canonPowConst("+e.toString()+")");
01017   }
01018   Assumptions a;
01019   Proof pf;
01020   if(withProof())
01021     pf = newPf("canon_pow_const", e);
01022   return newRWTheorem(e, rat(pow(p, base)), a, pf);
01023 }
01024 
01025 
01026 // Rules for addition
01027 // flattens the input. accepts a PLUS expr
01028 Theorem 
01029 ArithTheoremProducer::canonFlattenSum(const Expr& e) {
01030   Assumptions a;
01031   Proof pf;
01032   std::vector<Expr> sumKids;
01033   if(CHECK_PROOFS) {
01034     CHECK_SOUND(PLUS == e.getKind(),
01035                 CLASS_NAME "::canonFlattenSum:\n"
01036                 "input must be a PLUS:" + e.toString());
01037   }
01038 
01039   Expr::iterator i = e.begin();
01040   for(; i != e.end(); ++i){
01041     if (PLUS != (*i).getKind())
01042       sumKids.push_back(*i);
01043     else {
01044       Expr::iterator j = (*i).begin();
01045       for(; j != (*i).end(); ++j)
01046         sumKids.push_back(*j);
01047     }
01048   }
01049   Expr ret =  plusExpr(sumKids);
01050   if(withProof()) pf = newPf("canon_flatten_sum", e,ret);
01051   return newRWTheorem(e,ret, a, pf);
01052 }
01053 
01054 // Rules for addition
01055 // combine like terms. accepts a flattened PLUS expr
01056 Theorem 
01057 ArithTheoremProducer::canonComboLikeTerms(const Expr& e) {
01058   Assumptions a;
01059   Proof pf;
01060   std::vector<Expr> sumKids;
01061   ExprMap<Rational> sumHashMap;
01062   Rational constant = 0;
01063 
01064   if(CHECK_PROOFS) {
01065     Expr::iterator k = e.begin();
01066     for(; k != e.end(); ++k)
01067       CHECK_SOUND(!isPlus(*k),
01068                   CLASS_NAME "::canonComboLikeTerms:\n"
01069                   "input must be a flattened PLUS:" + k->toString());
01070   }
01071   Expr::iterator i = e.begin();
01072   for(; i != e.end(); ++i){
01073     if(i->isRational())
01074       constant = constant + i->getRational();
01075     else {
01076       if (!isMult(*i)) {
01077         if(0 == sumHashMap.count((*i)))
01078           sumHashMap[*i] = 1;
01079         else
01080           sumHashMap[*i] += 1;
01081       }
01082       else {
01083         if(0 == sumHashMap.count((*i)[1]))
01084           sumHashMap[(*i)[1]] = (*i)[0].getRational();
01085         else
01086           sumHashMap[(*i)[1]] = sumHashMap[(*i)[1]] + (*i)[0].getRational();
01087       }
01088     }
01089   }
01090 
01091   sumKids.push_back(rat(constant));
01092   ExprMap<Rational>::iterator j = sumHashMap.begin();
01093   for(; j != sumHashMap.end(); ++j) {
01094     if(0 == (*j).second)
01095       ;//do nothing
01096     else if (1 == (*j).second)
01097       sumKids.push_back((*j).first);
01098     else
01099       sumKids.push_back(rat((*j).second) * (*j).first);
01100   }
01101   
01102   //constant is same as sumKids[0].
01103   //corner cases: "0 + monomial" and "constant"(no monomials)
01104 
01105   Expr ret;
01106   if(2 == sumKids.size() && 0 == constant) ret = sumKids[1];
01107   else if (1 == sumKids.size()) ret = sumKids[0];
01108   else ret = plusExpr(sumKids);
01109 
01110   if(withProof()) pf = newPf("canon_combo_like_terms",e,ret);  
01111   return newRWTheorem(e, ret, a, pf);
01112 }
01113 
01114 
01115 
01116 
01117 
01118 // e[0] kind e[1] <==> true when e[0] kind e[1],
01119 // false when e[0] !kind e[1], for constants only
01120 Theorem ArithTheoremProducer::constPredicate(const Expr& e) {
01121   if(CHECK_PROOFS) {
01122     CHECK_SOUND(e.arity() == 2 && isRational(e[0]) && isRational(e[1]),
01123                 CLASS_NAME "::constPredicate:\n  "
01124                 "non-const parameters: " + e.toString());
01125   }
01126   Assumptions a;
01127   Proof pf;
01128   bool result(false);
01129   int kind = e.getKind();
01130   Rational r1 = e[0].getRational(), r2 = e[1].getRational();
01131   switch(kind) {
01132   case EQ:
01133     result = (r1 == r2)?true : false; 
01134     break;
01135   case LT:
01136     result = (r1 < r2)?true : false; 
01137     break;
01138   case LE:
01139     result = (r1 <= r2)?true : false; 
01140     break;
01141   case GT:
01142     result = (r1 > r2)?true : false; 
01143     break;
01144   case GE:
01145     result = (r1 >= r2)?true : false; 
01146     break;
01147   default:
01148     if(CHECK_PROOFS) {
01149       CHECK_SOUND(false,
01150                   "ArithTheoremProducer::constPredicate: wrong kind");
01151     }
01152     break;
01153   }
01154   Expr ret = (result) ? d_em->trueExpr() : d_em->falseExpr();
01155   if(withProof()) pf = newPf("const_predicate", e,ret);
01156   return newRWTheorem(e, ret, a, pf);
01157 }
01158 
01159 // e[0] kind e[1] <==> 0 kind e[1] - e[0]
01160 Theorem ArithTheoremProducer::rightMinusLeft(const Expr& e)
01161 {
01162   Assumptions a;
01163   Proof pf;
01164   int kind = e.getKind();
01165   if(CHECK_PROOFS) {
01166     CHECK_SOUND((EQ==kind) || 
01167                 (LT==kind) || 
01168                 (LE==kind) || 
01169                 (GE==kind) || 
01170                 (GT==kind),
01171                 "ArithTheoremProduder::rightMinusLeft: wrong kind");
01172   }
01173   if(withProof()) pf = newPf("right_minus_left",e);
01174   return newRWTheorem(e, Expr(e.getOp(), rat(0), e[1] - e[0]), a, pf);
01175 }
01176 
01177 
01178 // x kind y <==> x + z kind y + z
01179 Theorem ArithTheoremProducer::plusPredicate(const Expr& x, 
01180                                       const Expr& y,
01181                                       const Expr& z, int kind) {
01182   if(CHECK_PROOFS) {
01183     CHECK_SOUND((EQ==kind) || 
01184                 (LT==kind) || 
01185                 (LE==kind) || 
01186                 (GE==kind) || 
01187                 (GT==kind),
01188                 "ArithTheoremProduder::plusPredicate: wrong kind");
01189   }
01190   Assumptions a;
01191   Proof pf;
01192   Expr left = Expr(kind, x, y);
01193   Expr right = Expr(kind, x + z, y + z);
01194   if(withProof()) pf = newPf("plus_predicate",left,right);
01195   return newRWTheorem(left, right, a, pf);
01196 }
01197 
01198 // x = y <==> x * z = y * z
01199 Theorem ArithTheoremProducer::multEqn(const Expr& x, 
01200                                       const Expr& y,
01201                                       const Expr& z) {
01202   Assumptions a;
01203   Proof pf;
01204   if(CHECK_PROOFS)
01205     CHECK_SOUND(z.isRational() && z.getRational() != 0,
01206                 "ArithTheoremProducer::multEqn(): multiplying equation by 0");
01207   if(withProof()) pf = newPf("mult_eqn", x, y, z);
01208   return newRWTheorem(x.eqExpr(y), (x * z).eqExpr(y * z), a, pf);
01209 }
01210 
01211 
01212 // if z is +ve, return e[0] LT|LE|GT|GE e[1] <==> e[0]*z LT|LE|GT|GE e[1]*z
01213 // if z is -ve, return e[0] LT|LE|GT|GE e[1] <==> e[1]*z LT|LE|GT|GE e[0]*z
01214 Theorem ArithTheoremProducer::multIneqn(const Expr& e, const Expr& z)
01215 {
01216   int kind = e.getKind();
01217 
01218   if(CHECK_PROOFS) {
01219     CHECK_SOUND((LT==kind) || 
01220                 (LE==kind) || 
01221                 (GE==kind) || 
01222                 (GT==kind),
01223                 "ArithTheoremProduder::multIneqn: wrong kind");    
01224     CHECK_SOUND(z.isRational() && z.getRational() != 0,
01225                 "ArithTheoremProduder::multIneqn: "
01226                 "z must be non-zero rational: " + z.toString());
01227   }
01228   Op op(e.getOp());
01229   Assumptions a;
01230   Proof pf;
01231 
01232   Expr ret;
01233   if(0 < z.getRational())
01234     ret = Expr(op, e[0]*z, e[1]*z);
01235   else
01236     ret = Expr(op, e[1]*z, e[0]*z);
01237   if(withProof()) pf = newPf("mult_ineqn", e, ret);  
01238   return newRWTheorem(e, ret, a, pf);
01239 }
01240 
01241 
01242 // "op1 GE|GT op2" <==> op2 LE|LT op1
01243 Theorem ArithTheoremProducer::flipInequality(const Expr& e)
01244 {
01245   Assumptions a;
01246   Proof pf;
01247   if(CHECK_PROOFS) {
01248     CHECK_SOUND(isGT(e) || isGE(e),
01249                 "ArithTheoremProducer::flipInequality: wrong kind: " + 
01250                 e.toString());
01251   }
01252   
01253   int kind = isGE(e) ? LE : LT; 
01254   Expr ret =  Expr(kind, e[1], e[0]);
01255   if(withProof()) pf = newPf("flip_inequality", e,ret);
01256   return newRWTheorem(e,ret, a, pf);
01257 }
01258 
01259 
01260 // NOT (op1 LT op2)  <==> (op1 GE op2)
01261 // NOT (op1 LE op2)  <==> (op1 GT op2)
01262 // NOT (op1 GT op2)  <==> (op1 LE op2)
01263 // NOT (op1 GE op2)  <==> (op1 LT op2)
01264 Theorem ArithTheoremProducer::negatedInequality(const Expr& e)
01265 {
01266   const Expr& ineq = e[0];
01267   if(CHECK_PROOFS) {
01268     CHECK_SOUND(e.isNot(),
01269                 "ArithTheoremProducer::negatedInequality: wrong kind: " +
01270                 e.toString());
01271     CHECK_SOUND(isIneq(ineq),
01272                 "ArithTheoremProducer::negatedInequality: wrong kind: " +
01273                 (ineq).toString());
01274   }
01275   Assumptions a;
01276   Proof pf;
01277   if(withProof()) pf = newPf("negated_inequality", e);
01278 
01279   int kind;
01280   // NOT (op1 LT op2)  <==> (op1 GE op2)
01281   // NOT (op1 LE op2)  <==> (op1 GT op2)
01282   // NOT (op1 GT op2)  <==> (op1 LE op2)
01283   // NOT (op1 GE op2)  <==> (op1 LT op2)
01284   kind = 
01285     isLT(ineq) ? GE : 
01286     isLE(ineq) ? GT : 
01287     isGT(ineq) ? LE : 
01288     LT;
01289   return newRWTheorem(e, Expr(kind, ineq[0], ineq[1]), a, pf);
01290 }
01291 
01292 //takes two ineqs "|- alpha LT|LE t" and "|- t LT|LE beta"
01293 //and returns "|- alpha LT|LE beta"
01294 Theorem ArithTheoremProducer::realShadow(const Theorem& alphaLTt, 
01295                                          const Theorem& tLTbeta)
01296 {
01297   const Expr& expr1 = alphaLTt.getExpr();
01298   const Expr& expr2 = tLTbeta.getExpr();
01299   if(CHECK_PROOFS) {
01300     CHECK_SOUND((isLE(expr1) || isLT(expr1)) &&
01301                 (isLE(expr2) || isLT(expr2)),
01302                 "ArithTheoremProducer::realShadow: Wrong Kind: " + 
01303                 alphaLTt.toString() +  tLTbeta.toString());
01304     
01305     CHECK_SOUND(expr1[1] == expr2[0], 
01306                 "ArithTheoremProducer::realShadow:" 
01307                 " t must be same for both inputs: " +
01308                 expr1[1].toString() + " , " + expr2[0].toString());
01309   }
01310   Assumptions a;
01311   if(withAssumptions()) {
01312     a = merge(alphaLTt, tLTbeta);
01313   }
01314   int firstKind = expr1.getKind();
01315   int secondKind = expr2.getKind();
01316   int kind = (firstKind == secondKind) ? firstKind : LT;
01317   Proof pf; 
01318   if(withProof()) {
01319     vector<Proof> pfs;
01320     pfs.push_back(alphaLTt.getProof());
01321     pfs.push_back(tLTbeta.getProof());
01322     pf = newPf("real_shadow",expr1, expr2, pfs);
01323   }
01324   return newTheorem(Expr(kind, expr1[0], expr2[1]), a, pf); 
01325 }
01326 
01327 //! alpha <= t <= alpha ==> t = alpha
01328 
01329 /*! takes two ineqs "|- alpha LE t" and "|- t LE alpha"
01330   and returns "|- t = alpha"
01331 */
01332 Theorem ArithTheoremProducer::realShadowEq(const Theorem& alphaLEt, 
01333                                            const Theorem& tLEalpha)
01334 {
01335   const Expr& expr1 = alphaLEt.getExpr();
01336   const Expr& expr2 = tLEalpha.getExpr();
01337   if(CHECK_PROOFS) {
01338     CHECK_SOUND(isLE(expr1) && isLE(expr2),
01339                 "ArithTheoremProducer::realShadowLTLE: Wrong Kind: " + 
01340                 alphaLEt.toString() +  tLEalpha.toString());
01341     
01342     CHECK_SOUND(expr1[1] == expr2[0], 
01343                 "ArithTheoremProducer::realShadowLTLE:" 
01344                 " t must be same for both inputs: " +
01345                 alphaLEt.toString() + " , " + tLEalpha.toString());
01346 
01347     CHECK_SOUND(expr1[0] == expr2[1], 
01348                 "ArithTheoremProducer::realShadowLTLE:" 
01349                 " alpha must be same for both inputs: " +
01350                 alphaLEt.toString() + " , " + tLEalpha.toString());
01351   }
01352   Assumptions a;
01353   if(withAssumptions()) {
01354     a = merge(alphaLEt, tLEalpha);
01355   }
01356   Proof pf;
01357   if(withProof()) {
01358     vector<Proof> pfs;
01359     pfs.push_back(alphaLEt.getProof());
01360     pfs.push_back(tLEalpha.getProof());
01361     pf = newPf("real_shadow_eq", alphaLEt.getExpr(), tLEalpha.getExpr(), pfs);
01362   }
01363   return newRWTheorem(expr1[0], expr1[1], a, pf);
01364 }
01365 
01366 Theorem 
01367 ArithTheoremProducer::finiteInterval(const Theorem& aLEt,
01368                                      const Theorem& tLEac,
01369                                      const Theorem& isInta,
01370                                      const Theorem& isIntt) {
01371   const Expr& e1 = aLEt.getExpr();
01372   const Expr& e2 = tLEac.getExpr();
01373   if(CHECK_PROOFS) {
01374     CHECK_SOUND(isLE(e1) && isLE(e2),
01375                 "ArithTheoremProducer::finiteInterval:\n e1 = "
01376                 +e1.toString()+"\n e2 = "+e2.toString());
01377     // term 't' is the same in both inequalities
01378     CHECK_SOUND(e1[1] == e2[0],
01379                 "ArithTheoremProducer::finiteInterval:\n e1 = "
01380                 +e1.toString()+"\n e2 = "+e2.toString());
01381     // RHS in e2 is (a+c)
01382     CHECK_SOUND(isPlus(e2[1]) && e2[1].arity() == 2,
01383                 "ArithTheoremProducer::finiteInterval:\n e1 = "
01384                 +e1.toString()+"\n e2 = "+e2.toString());
01385     // term 'a' in LHS of e1 and RHS of e2 is the same
01386     CHECK_SOUND(e1[0] == e2[1][0],
01387                 "ArithTheoremProducer::finiteInterval:\n e1 = "
01388                 +e1.toString()+"\n e2 = "+e2.toString());
01389     // 'c' in the RHS of e2 is a positive integer constant
01390     CHECK_SOUND(e2[1][1].isRational() && e2[1][1].getRational().isInteger()
01391                 && e2[1][1].getRational() >= 1,
01392                 "ArithTheoremProducer::finiteInterval:\n e1 = "
01393                 +e1.toString()+"\n e2 = "+e2.toString());
01394     // Integrality constraints
01395     const Expr& isIntaExpr = isInta.getExpr();
01396     const Expr& isInttExpr = isIntt.getExpr();
01397     CHECK_SOUND(isIntPred(isIntaExpr) && isIntaExpr[0] == e1[0],
01398                 "Wrong integrality constraint:\n e1 = "
01399                 +e1.toString()+"\n isInta = "+isIntaExpr.toString());
01400     CHECK_SOUND(isIntPred(isInttExpr) && isInttExpr[0] == e1[1],
01401                 "Wrong integrality constraint:\n e1 = "
01402                 +e1.toString()+"\n isIntt = "+isInttExpr.toString());
01403   }
01404   Assumptions a;
01405   Proof pf;
01406   if(withAssumptions()) {
01407     vector<Theorem> thms;
01408     thms.push_back(aLEt);
01409     thms.push_back(tLEac);
01410     thms.push_back(isInta);
01411     thms.push_back(isIntt);
01412     a = merge(thms);
01413   }
01414   if(withProof()) {
01415     vector<Expr> es;
01416     vector<Proof> pfs;
01417     es.push_back(e1);
01418     es.push_back(e2);
01419     es.push_back(isInta.getExpr());
01420     es.push_back(isIntt.getExpr());
01421     pfs.push_back(aLEt.getProof());
01422     pfs.push_back(tLEac.getProof());
01423     pfs.push_back(isInta.getProof());
01424     pfs.push_back(isIntt.getProof());
01425     pf = newPf("finite_interval", es, pfs);
01426   }
01427   // Construct GRAY_SHADOW(t, a, 0, c)
01428   Expr g(grayShadow(e1[1], e1[0], 0, e2[1][1].getRational()));
01429   return newTheorem(g, a, pf);
01430 }
01431 
01432 
01433 // Dark & Gray shadows when a <= b
01434 Theorem ArithTheoremProducer::darkGrayShadow2ab(const Theorem& betaLEbx, 
01435                                                 const Theorem& axLEalpha,
01436                                                 const Theorem& isIntAlpha,
01437                                                 const Theorem& isIntBeta,
01438                                                 const Theorem& isIntx) {
01439   const Expr& expr1 = betaLEbx.getExpr();
01440   const Expr& expr2 = axLEalpha.getExpr();
01441   const Expr& isIntAlphaExpr = isIntAlpha.getExpr();
01442   const Expr& isIntBetaExpr = isIntBeta.getExpr();
01443   const Expr& isIntxExpr = isIntx.getExpr();
01444 
01445   if(CHECK_PROOFS) {
01446     CHECK_SOUND(isLE(expr1) && isLE(expr2),
01447                 "ArithTheoremProducer::darkGrayShadow2ab: Wrong Kind: " + 
01448                 betaLEbx.toString() +  axLEalpha.toString());
01449   }
01450 
01451   const Expr& beta = expr1[0];
01452   const Expr& bx = expr1[1];
01453   const Expr& ax = expr2[0];
01454   const Expr& alpha = expr2[1];
01455   Rational a = isMult(ax)? ax[0].getRational() : 1;
01456   Rational b = isMult(bx)? bx[0].getRational() : 1;
01457   const Expr& x = isMult(ax)? ax[1] : ax;
01458 
01459   if(CHECK_PROOFS) {
01460     // Integrality constraints
01461     CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha,
01462                 "ArithTheoremProducer::darkGrayShadow2ab:\n "
01463                 "wrong integrality constraint:\n alpha = "
01464                 +alpha.toString()+"\n isIntAlpha = "
01465                 +isIntAlphaExpr.toString());
01466     CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta,
01467                 "ArithTheoremProducer::darkGrayShadow2ab:\n "
01468                 "wrong integrality constraint:\n beta = "
01469                 +beta.toString()+"\n isIntBeta = "
01470                 +isIntBetaExpr.toString());
01471     CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x,
01472                 "ArithTheoremProducer::darkGrayShadow2ab:\n "
01473                 "wrong integrality constraint:\n x = "
01474                 +x.toString()+"\n isIntx = "
01475                 +isIntxExpr.toString());
01476     // Expressions ax and bx should match on x
01477     CHECK_SOUND(!isMult(ax) || ax.arity() == 2,
01478                 "ArithTheoremProducer::darkGrayShadow2ab:\n ax<=alpha: " +
01479                 axLEalpha.toString());
01480     CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x),
01481                 "ArithTheoremProducer::darkGrayShadow2ab:\n beta<=bx: "
01482                 +betaLEbx.toString()
01483                 +"\n ax<=alpha: "+ axLEalpha.toString());
01484     CHECK_SOUND(1 <= a && a <= b && 2 <= b,
01485                 "ArithTheoremProducer::darkGrayShadow2ab:\n beta<=bx: "
01486                 +betaLEbx.toString()
01487                 +"\n ax<=alpha: "+ axLEalpha.toString());
01488   }
01489   Assumptions A;
01490   if(withAssumptions()) {
01491     vector<Theorem> thms;
01492     thms.push_back(betaLEbx);
01493     thms.push_back(axLEalpha);
01494     thms.push_back(isIntAlpha);
01495     thms.push_back(isIntBeta);
01496     thms.push_back(isIntx);
01497     A = merge(thms);
01498   }
01499   Proof pf;
01500   if(withProof()) {
01501     vector<Proof> pfs;
01502     pfs.push_back(betaLEbx.getProof());
01503     pfs.push_back(axLEalpha.getProof());
01504     pfs.push_back(isIntAlpha.getProof());
01505     pfs.push_back(isIntBeta.getProof());
01506     pfs.push_back(isIntx.getProof());
01507     
01508     pf = newPf("dark_grayshadow_2ab", expr1, expr2, pfs);
01509   }
01510   
01511   Expr bAlpha = multExpr(rat(b), alpha);
01512   Expr aBeta = multExpr(rat(a), beta);
01513   Expr t = minusExpr(bAlpha, aBeta);
01514   Expr d = darkShadow(rat(a*b-1), t);
01515   Expr g = grayShadow(ax, alpha, -a+1, 0);
01516   return newTheorem((d || g) && (!d || !g), A, pf);
01517 }
01518 
01519 // Dark & Gray shadows when b <= a
01520 Theorem ArithTheoremProducer::darkGrayShadow2ba(const Theorem& betaLEbx, 
01521                                                 const Theorem& axLEalpha,
01522                                                 const Theorem& isIntAlpha,
01523                                                 const Theorem& isIntBeta,
01524                                                 const Theorem& isIntx) {
01525   const Expr& expr1 = betaLEbx.getExpr();
01526   const Expr& expr2 = axLEalpha.getExpr();
01527   const Expr& isIntAlphaExpr = isIntAlpha.getExpr();
01528   const Expr& isIntBetaExpr = isIntBeta.getExpr();
01529   const Expr& isIntxExpr = isIntx.getExpr();
01530 
01531   if(CHECK_PROOFS) {
01532     CHECK_SOUND(isLE(expr1) && isLE(expr2),
01533                 "ArithTheoremProducer::darkGrayShadow2ba: Wrong Kind: " + 
01534                 betaLEbx.toString() +  axLEalpha.toString());
01535   }
01536 
01537   const Expr& beta = expr1[0];
01538   const Expr& bx = expr1[1];
01539   const Expr& ax = expr2[0];
01540   const Expr& alpha = expr2[1];
01541   Rational a = isMult(ax)? ax[0].getRational() : 1;
01542   Rational b = isMult(bx)? bx[0].getRational() : 1;
01543   const Expr& x = isMult(ax)? ax[1] : ax;
01544 
01545   if(CHECK_PROOFS) {
01546     // Integrality constraints
01547     CHECK_SOUND(isIntPred(isIntAlphaExpr) && isIntAlphaExpr[0] == alpha,
01548                 "ArithTheoremProducer::darkGrayShadow2ab:\n "
01549                 "wrong integrality constraint:\n alpha = "
01550                 +alpha.toString()+"\n isIntAlpha = "
01551                 +isIntAlphaExpr.toString());
01552     CHECK_SOUND(isIntPred(isIntBetaExpr) && isIntBetaExpr[0] == beta,
01553                 "ArithTheoremProducer::darkGrayShadow2ab:\n "
01554                 "wrong integrality constraint:\n beta = "
01555                 +beta.toString()+"\n isIntBeta = "
01556                 +isIntBetaExpr.toString());
01557     CHECK_SOUND(isIntPred(isIntxExpr) && isIntxExpr[0] == x,
01558                 "ArithTheoremProducer::darkGrayShadow2ab:\n "
01559                 "wrong integrality constraint:\n x = "
01560                 +x.toString()+"\n isIntx = "
01561                 +isIntxExpr.toString());
01562     // Expressions ax and bx should match on x
01563     CHECK_SOUND(!isMult(ax) || ax.arity() == 2,
01564                 "ArithTheoremProducer::darkGrayShadow2ba:\n ax<=alpha: " +
01565                 axLEalpha.toString());
01566     CHECK_SOUND(!isMult(bx) || (bx.arity() == 2 && bx[1] == x),
01567                 "ArithTheoremProducer::darkGrayShadow2ba:\n beta<=bx: "
01568                 +betaLEbx.toString()
01569                 +"\n ax<=alpha: "+ axLEalpha.toString());
01570     CHECK_SOUND(1 <= b && b <= a && 2 <= a,
01571                 "ArithTheoremProducer::darkGrayShadow2ba:\n beta<=bx: "
01572                 +betaLEbx.toString()
01573                 +"\n ax<=alpha: "+ axLEalpha.toString());
01574   }
01575   Assumptions A;
01576   if(withAssumptions()) {
01577     vector<Theorem> thms;
01578     thms.push_back(betaLEbx);
01579     thms.push_back(axLEalpha);
01580     thms.push_back(isIntAlpha);
01581     thms.push_back(isIntBeta);
01582     thms.push_back(isIntx);
01583     A = merge(thms);
01584   }
01585   Proof pf;
01586   if(withProof()) {
01587     vector<Proof> pfs;
01588     pfs.push_back(betaLEbx.getProof());
01589     pfs.push_back(axLEalpha.getProof());
01590     pfs.push_back(isIntAlpha.getProof());
01591     pfs.push_back(isIntBeta.getProof());
01592     pfs.push_back(isIntx.getProof());
01593     
01594     pf = newPf("dark_grayshadow_2ba", betaLEbx.getExpr(),
01595                axLEalpha.getExpr(), pfs);
01596   }
01597   
01598   Expr bAlpha = multExpr(rat(b), alpha);
01599   Expr aBeta = multExpr(rat(a), beta);
01600   Expr t = minusExpr(bAlpha, aBeta);
01601   Expr d = darkShadow(rat(a*b-1), t);
01602   Expr g = grayShadow(bx, beta, 0, b-1);
01603   return newTheorem((d || g) && (!d || !g), A, pf);
01604 }
01605 
01606 /*! takes a dark shadow and expands it into an inequality.
01607 */
01608 Theorem ArithTheoremProducer::expandDarkShadow(const Theorem& darkShadow) {
01609   const Expr& theShadow = darkShadow.getExpr();
01610   if(CHECK_PROOFS){
01611     CHECK_SOUND(isDarkShadow(theShadow),
01612                 "ArithTheoremProducer::expandDarkShadow: not DARK_SHADOW: " +
01613                 theShadow.toString());
01614   }
01615   Assumptions a;
01616   if(withAssumptions())
01617     a = darkShadow.getAssumptionsCopy();
01618   Proof pf;
01619   if(withProof())
01620     pf = newPf("expand_dark_shadow", theShadow, darkShadow.getProof());
01621   return newTheorem(leExpr(theShadow[0], theShadow[1]), a, pf);
01622 }
01623 
01624 
01625 // takes a grayShadow (c1==c2) and expands it into an equality
01626 Theorem ArithTheoremProducer::expandGrayShadow0(const Theorem& grayShadow) {
01627   const Expr& theShadow = grayShadow.getExpr();
01628   if(CHECK_PROOFS) {
01629     CHECK_SOUND(isGrayShadow(theShadow),
01630                 "ArithTheoremProducer::expandGrayShadowConst0:"
01631                 " not GRAY_SHADOW: " +
01632                 theShadow.toString());
01633     CHECK_SOUND(theShadow[2] == theShadow[3],
01634                 "ArithTheoremProducer::expandGrayShadow0: c1!=c2: " +
01635                 theShadow.toString());
01636   }
01637   Assumptions a;
01638   Proof pf;
01639   if(withAssumptions())
01640     a = grayShadow.getAssumptionsCopy();
01641   if(withProof()) pf = newPf("expand_gray_shadowconst0", theShadow,
01642                              grayShadow.getProof());
01643   const Expr& v = theShadow[0];
01644   const Expr& e = theShadow[1];
01645   return newRWTheorem(v, e + theShadow[2], a, pf);
01646 }
01647 
01648 
01649 // G ==> (G1 or G2) and (!G1 or !G2),
01650 // where G  = G(x, e, c1, c2),
01651 //       G1 = G(x,e,c1,c)
01652 //       G2 = G(x,e,c+1,c2),
01653 // and    c = floor((c1+c2)/2)
01654 Theorem ArithTheoremProducer::splitGrayShadow(const Theorem& gThm) {
01655   const Expr& theShadow = gThm.getExpr();
01656   if(CHECK_PROOFS) {
01657     CHECK_SOUND(isGrayShadow(theShadow),
01658                 "ArithTheoremProducer::expandGrayShadowConst: not a shadow" +
01659                 theShadow.toString());
01660   }
01661 
01662   const Rational& c1 = theShadow[2].getRational();
01663   const Rational& c2 = theShadow[3].getRational();
01664 
01665   if(CHECK_PROOFS) {
01666     CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2,
01667                 "ArithTheoremProducer::expandGrayShadow: " +
01668                 theShadow.toString());
01669   }
01670 
01671   const Expr& v = theShadow[0];
01672   const Expr& e = theShadow[1];
01673 
01674   Assumptions a;
01675   Proof pf;
01676   if(withAssumptions())
01677     a = gThm.getAssumptionsCopy();
01678   if(withProof())
01679     pf = newPf("expand_gray_shadow", theShadow, gThm.getProof());
01680   Rational c(floor((c1+c2) / 2));
01681   Expr g1(grayShadow(v, e, c1, c));
01682   Expr g2(grayShadow(v, e, c+1, c2));
01683   return newTheorem((g1 || g2) && (!g1 || !g2), a, pf);
01684 }
01685 
01686 
01687 Theorem ArithTheoremProducer::expandGrayShadow(const Theorem& gThm) {
01688   const Expr& theShadow = gThm.getExpr();
01689   if(CHECK_PROOFS) {
01690     CHECK_SOUND(isGrayShadow(theShadow),
01691                 "ArithTheoremProducer::expandGrayShadowConst: not a shadow" +
01692                 theShadow.toString());
01693   }
01694 
01695   const Rational& c1 = theShadow[2].getRational();
01696   const Rational& c2 = theShadow[3].getRational();
01697 
01698   if(CHECK_PROOFS) {
01699     CHECK_SOUND(c1.isInteger() && c2.isInteger() && c1 < c2,
01700                 "ArithTheoremProducer::expandGrayShadow: " +
01701                 theShadow.toString());
01702   }
01703 
01704   const Expr& v = theShadow[0];
01705   const Expr& e = theShadow[1];
01706 
01707   Assumptions a;
01708   Proof pf;
01709   if(withAssumptions())
01710     a = gThm.getAssumptionsCopy();
01711   if(withProof())
01712     pf = newPf("expand_gray_shadow", theShadow, gThm.getProof());
01713   Expr ineq1(leExpr(e+rat(c1), v));
01714   Expr ineq2(leExpr(v, e+rat(c2)));
01715   return newTheorem(ineq1 && ineq2, a, pf);
01716 }
01717 
01718 
01719 // Expanding GRAY_SHADOW(a*x, c, b), where c is a constant
01720 Theorem
01721 ArithTheoremProducer::expandGrayShadowConst(const Theorem& gThm) {
01722   const Expr& theShadow = gThm.getExpr();
01723   const Expr& ax = theShadow[0];
01724   const Expr& cExpr = theShadow[1];
01725   const Expr& bExpr = theShadow[2];
01726 
01727   if(CHECK_PROOFS) {
01728     CHECK_SOUND(!isMult(ax) || ax[0].isRational(),
01729                 "ArithTheoremProducer::expandGrayShadowConst: "
01730                 "'a' in a*x is not a const: " +theShadow.toString());
01731   }
01732 
01733   Rational a = isMult(ax)? ax[0].getRational() : 1;
01734 
01735   if(CHECK_PROOFS) {
01736     CHECK_SOUND(isGrayShadow(theShadow),
01737                 "ArithTheoremProducer::expandGrayShadowConst: "
01738                 "not a GRAY_SHADOW: " +theShadow.toString());
01739     CHECK_SOUND(a.isInteger() && a >= 1,
01740                 "ArithTheoremProducer::expandGrayShadowConst: "
01741                 "'a' is not integer: " +theShadow.toString());
01742     CHECK_SOUND(cExpr.isRational(),
01743                 "ArithTheoremProducer::expandGrayShadowConst: "
01744                 "'c' is not rational" +theShadow.toString());
01745     CHECK_SOUND(bExpr.isRational() && bExpr.getRational().isInteger(),
01746                 "ArithTheoremProducer::expandGrayShadowConst: b not integer: "
01747                 +theShadow.toString());
01748   }
01749 
01750   const Rational& b = bExpr.getRational();
01751   const Rational& c = cExpr.getRational();
01752   Rational j = constRHSGrayShadow(c,b,a);
01753   // Compute sign(b)*j(c,b,a)
01754   Rational signB = (b>0)? 1 : -1;
01755   // |b| (absolute value of b)
01756   Rational bAbs = abs(b);
01757 
01758   Assumptions assump;
01759   Proof pf;
01760   Theorem conc;  // Conclusion of the rule
01761 
01762   if(withAssumptions())
01763     assump = gThm.getAssumptionsCopy();
01764 
01765   if(bAbs < j) {
01766     if(withProof())
01767       pf = newPf("expand_gray_shadow_const_0", theShadow,
01768                  gThm.getProof());
01769     conc = newTheorem(d_em->falseExpr(), assump, pf);
01770   } else if(bAbs < a+j) {
01771     if(withProof())
01772       pf = newPf("expand_gray_shadow_const_1", theShadow,
01773                  gThm.getProof());
01774     conc = newRWTheorem(ax, rat(c+b-signB*j), assump, pf);
01775   } else {
01776     if(withProof())
01777       pf = newPf("expand_gray_shadow_const", theShadow,
01778                  gThm.getProof());
01779     Expr newGrayShadow(Expr(GRAY_SHADOW, ax, cExpr, rat(b-signB*(a+j))));
01780     conc = newTheorem(ax.eqExpr(rat(c+b-signB*j)).orExpr(newGrayShadow),
01781                       assump, pf);
01782   }
01783 
01784   return conc;
01785 }
01786 
01787 
01788 Theorem
01789 ArithTheoremProducer::grayShadowConst(const Theorem& gThm) {
01790   const Expr& g = gThm.getExpr();
01791   bool checkProofs(CHECK_PROOFS);
01792   if(checkProofs) {
01793     CHECK_SOUND(isGrayShadow(g), "ArithTheoremProducer::grayShadowConst("
01794                 +g.toString()+")");
01795   }
01796 
01797   const Expr& ax = g[0];
01798   const Expr& e = g[1];
01799   const Rational& c1 = g[2].getRational();
01800   const Rational& c2 = g[3].getRational();
01801   Expr aExpr, x;
01802   d_theoryArith->separateMonomial(ax, aExpr, x);
01803 
01804   if(checkProofs) {
01805     CHECK_SOUND(e.isRational() && e.getRational().isInteger(),
01806                 "ArithTheoremProducer::grayShadowConst("+g.toString()+")");
01807     CHECK_SOUND(aExpr.isRational(),
01808                 "ArithTheoremProducer::grayShadowConst("+g.toString()+")");
01809   }
01810 
01811   const Rational& a = aExpr.getRational();
01812   const Rational& c = e.getRational();
01813 
01814   if(checkProofs) {
01815     CHECK_SOUND(a.isInteger() && a >= 2,
01816                 "ArithTheoremProducer::grayShadowConst("+g.toString()+")");
01817   }
01818 
01819   Rational newC1 = ceil((c1+c)/a), newC2 = floor((c2+c)/a);
01820   Expr newG((newC1 > newC2)? d_em->falseExpr()
01821             : grayShadow(x, rat(0), newC1, newC2));
01822   Assumptions assump;
01823   Proof pf;
01824   if(withAssumptions()) assump = gThm.getAssumptionsCopy();
01825   if(withProof())
01826     pf = newPf("gray_shadow_const", g, gThm.getProof());
01827   return newTheorem(newG, assump, pf);
01828 }
01829 
01830 
01831 Rational ArithTheoremProducer::constRHSGrayShadow(const Rational& c,
01832                                                   const Rational& b,
01833                                                   const Rational& a) {
01834   DebugAssert(c.isInteger() &&
01835               b.isInteger() &&
01836               a.isInteger() &&
01837               b != 0,
01838               "ArithTheoremProducer::constRHSGrayShadow: a, b, c must be ints");
01839   if (b > 0)
01840     return mod(c+b, a);
01841   else
01842     return mod(a-(c+b), a);
01843 }
01844 
01845 /*! Takes a Theorem(\\alpha < \\beta) and returns 
01846  *  Theorem(\\alpha < \\beta <==> \\alpha <= \\beta -1)
01847  * where \\alpha and \\beta are integer expressions
01848  */
01849 Theorem ArithTheoremProducer::lessThanToLE(const Theorem& less,
01850                                            const Theorem& isIntLHS,
01851                                            const Theorem& isIntRHS,
01852                                            bool changeRight) {
01853   const Expr& ineq = less.getExpr();
01854   const Expr& isIntLHSexpr = isIntLHS.getExpr();
01855   const Expr& isIntRHSexpr = isIntRHS.getExpr();
01856   
01857   if(CHECK_PROOFS) {
01858     CHECK_SOUND(isLT(ineq),
01859                 "ArithTheoremProducer::LTtoLE: ineq must be <");
01860     // Integrality check
01861     CHECK_SOUND(isIntPred(isIntLHSexpr) && isIntLHSexpr[0] == ineq[0],
01862                 "ArithTheoremProducer::lessThanToLE: bad integrality check:\n"
01863                 " ineq = "+ineq.toString()+"\n isIntLHS = "
01864                 +isIntLHSexpr.toString());
01865     CHECK_SOUND(isIntPred(isIntRHSexpr) && isIntRHSexpr[0] == ineq[1],
01866                 "ArithTheoremProducer::lessThanToLE: bad integrality check:\n"
01867                 " ineq = "+ineq.toString()+"\n isIntRHS = "
01868                 +isIntRHSexpr.toString());
01869   }
01870   Assumptions a;
01871   Proof pf;
01872   if(withAssumptions()) {
01873     vector<Theorem> thms;
01874     thms.push_back(less);
01875     thms.push_back(isIntLHS);
01876     thms.push_back(isIntRHS);
01877     a = merge(thms);
01878   }
01879   if(withProof()) {
01880     vector<Proof> pfs;
01881     pfs.push_back(less.getProof());
01882     pfs.push_back(isIntLHS.getProof());
01883     pfs.push_back(isIntRHS.getProof());
01884     pf = newPf(changeRight? "lessThan_To_LE_rhs" : "lessThan_To_LE_lhs",
01885                ineq, pfs);
01886   }
01887   Expr le = changeRight?
01888     leExpr(ineq[0], ineq[1] + rat(-1))
01889     : leExpr(ineq[0] + rat(1), ineq[1]);
01890   return newRWTheorem(ineq, le, a, pf);
01891 }
01892 
01893 
01894 /*! \param eqn is an equation 0 = a.x or 0 = c + a.x
01895  *  \param isIntx is a proof of IS_INTEGER(x)
01896  *
01897  * \return the theorem 0 = c + a.x <==> x=-c/a if -c/a is int else
01898  *  return the theorem 0 = c + a.x <==> false.
01899  *
01900  * It also handles the special case of 0 = a.x <==> x = 0
01901  */
01902 Theorem 
01903 ArithTheoremProducer::intVarEqnConst(const Expr& eqn,
01904                                      const Theorem& isIntx) {
01905   const Expr& left(eqn[0]);
01906   const Expr& right(eqn[1]);
01907   const Expr& isIntxexpr(isIntx.getExpr());
01908 
01909   if(CHECK_PROOFS) {
01910     CHECK_SOUND((isMult(right) && right[0].isRational())
01911                 || (right.arity() == 2 && isPlus(right)
01912                     && right[0].isRational()
01913                     && ((!isMult(right[1]) || right[1][0].isRational()))),
01914                 "ArithTheoremProducer::intVarEqnConst: "
01915                 "rhs has a wrong format: " + right.toString());
01916     CHECK_SOUND(left.isRational() && 0 == left.getRational(),
01917                 "ArithTheoremProducer:intVarEqnConst:left is not a zero: " +
01918                 left.toString());
01919   }
01920   // Integrality constraint
01921   Expr x(right);
01922   Rational a(1), c(0);
01923   if(isMult(right)) {
01924     Expr aExpr;
01925     d_theoryArith->separateMonomial(right, aExpr, x);
01926     a = aExpr.getRational();
01927   } else { // right is a PLUS
01928     c = right[0].getRational();
01929     Expr aExpr;
01930     d_theoryArith->separateMonomial(right[1], aExpr, x);
01931     a = aExpr.getRational();
01932   }
01933   if(CHECK_PROOFS) {
01934     CHECK_SOUND(isIntPred(isIntxexpr) && isIntxexpr[0] == x,
01935                 "ArithTheoremProducer:intVarEqnConst: "
01936                 "bad integrality constraint:\n right = " +
01937                 right.toString()+"\n isIntx = "+isIntxexpr.toString());
01938     CHECK_SOUND(a!=0, "ArithTheoremProducer:intVarEqnConst: eqn = "
01939                 +eqn.toString());
01940   }
01941   Assumptions assump;
01942   if(withAssumptions())
01943     assump = isIntx.getAssumptionsCopy();
01944   Proof pf;
01945   if(withProof())
01946     pf = newPf("int_const_eq", eqn, isIntx.getProof());
01947 
01948   // Solve for x:   x = r = -c/a
01949   Rational r(-c/a);
01950 
01951   if(r.isInteger())
01952     return newRWTheorem(eqn, x.eqExpr(rat(r)), assump, pf);
01953   else
01954     return newRWTheorem(eqn, d_em->falseExpr(), assump, pf);
01955 }
01956 
01957 
01958 Expr
01959 ArithTheoremProducer::create_t(const Expr& eqn) {
01960   const Expr& lhs = eqn[0];
01961   DebugAssert(isMult(lhs),
01962               CLASS_NAME "create_t : lhs must be a MULT"
01963               + lhs.toString());
01964   const Expr& x = lhs[1];
01965   Rational m = lhs[0].getRational()+1;
01966   DebugAssert(m > 0, "ArithTheoremProducer::create_t: m = "+m.toString());
01967   vector<Expr> kids;
01968   if(isPlus(eqn[1]))
01969     sumModM(kids, eqn[1], m, m);
01970   else
01971     kids.push_back(monomialModM(eqn[1], m, m));
01972   
01973   kids.push_back(multExpr(rat(1/m), x));
01974   return plusExpr(kids);
01975 }
01976 
01977 Expr
01978 ArithTheoremProducer::create_t2(const Expr& lhs, const Expr& rhs,
01979                                 const Expr& sigma) {
01980   Rational m = lhs[0].getRational()+1;
01981   DebugAssert(m > 0, "ArithTheoremProducer::create_t2: m = "+m.toString());
01982   vector<Expr> kids;
01983   if(isPlus(rhs))
01984     sumModM(kids, rhs, m, -1);
01985   else {
01986     kids.push_back(rat(0)); // For canonical form
01987     Expr monom = monomialModM(rhs, m, -1);
01988     if(!monom.isRational())
01989       kids.push_back(monom);
01990     else 
01991       DebugAssert(monom.getRational() == 0, "");
01992   }
01993   kids.push_back(rat(m)*sigma);
01994   return plusExpr(kids);
01995 }
01996 
01997 Expr
01998 ArithTheoremProducer::create_t3(const Expr& lhs, const Expr& rhs,
01999                                 const Expr& sigma) {
02000   const Rational& a = lhs[0].getRational();
02001   Rational m = a+1;
02002   DebugAssert(m > 0, "ArithTheoremProducer::create_t3: m = "+m.toString());
02003   vector<Expr> kids;
02004   if(isPlus(rhs))
02005     sumMulF(kids, rhs, m, 1);
02006   else {
02007     kids.push_back(rat(0)); // For canonical form
02008     Expr monom = monomialMulF(rhs, m, 1);
02009     if(!monom.isRational())
02010       kids.push_back(monom);
02011     else
02012       DebugAssert(monom.getRational() == 0, "");
02013   }
02014   kids.push_back(rat(-a)*sigma);
02015   return plusExpr(kids);
02016 }
02017 
02018 Rational
02019 ArithTheoremProducer::modEq(const Rational& i, const Rational& m) {
02020   DebugAssert(m > 0, "ArithTheoremProducer::modEq: m = "+m.toString());
02021   Rational half(1,2);
02022   Rational res((i - m*(floor((i/m) + half))));
02023   TRACE("arith eq", "modEq("+i.toString()+", "+m.toString()+") = ", res, "");
02024   return res;
02025 }
02026 
02027 Rational
02028 ArithTheoremProducer::f(const Rational& i, const Rational& m) {
02029   DebugAssert(m > 0, "ArithTheoremProducer::f: m = "+m.toString());
02030   Rational half(1,2);
02031   return (floor(i/m + half)+modEq(i,m));
02032 }
02033 
02034 void
02035 ArithTheoremProducer::sumModM(vector<Expr>& summands, const Expr& sum,
02036                               const Rational& m, const Rational& divisor) {
02037   DebugAssert(divisor != 0, "ArithTheoremProducer::sumModM: divisor = "
02038               +divisor.toString());
02039   Expr::iterator i = sum.begin();
02040   DebugAssert(i != sum.end(), CLASS_NAME "::sumModM");
02041   Rational C = i->getRational();
02042   C = modEq(C,m)/divisor;
02043   summands.push_back(rat(C));
02044   i++;
02045   for(Expr::iterator iend=sum.end(); i!=iend; ++i) {
02046     Expr monom = monomialModM(*i, m, divisor);
02047     if(!monom.isRational())
02048       summands.push_back(monom);
02049     else
02050       DebugAssert(monom.getRational() == 0, "");
02051   }
02052 }
02053 
02054 Expr
02055 ArithTheoremProducer::monomialModM(const Expr& i,
02056                                    const Rational& m, const Rational& divisor)
02057 {
02058   DebugAssert(divisor != 0, "ArithTheoremProducer::monomialModM: divisor = "
02059               +divisor.toString());
02060   Expr res;
02061   if(isMult(i)) {
02062     Rational ai = i[0].getRational();
02063     ai = modEq(ai,m)/divisor;
02064     if(0 == ai) res = rat(0);
02065     else if(1 == ai && i.arity() == 2) res = i[1];
02066     else {
02067       vector<Expr> kids = i.getKids();
02068       kids[0] = rat(ai);
02069       res = multExpr(kids);
02070     }
02071   } else { // It's a single variable
02072     Rational ai = modEq(1,m)/divisor;
02073     if(1 == ai) res = i;
02074     else res = rat(ai)*i;
02075   }
02076   DebugAssert(!res.isNull(), "ArithTheoremProducer::monomialModM()");
02077   TRACE("arith eq", "monomialModM(i="+i.toString()+", m="+m.toString()
02078         +", div="+divisor.toString()+") = ", res, "");
02079   return res;
02080 }
02081 
02082 void
02083 ArithTheoremProducer::sumMulF(vector<Expr>& summands, const Expr& sum,
02084                               const Rational& m, const Rational& divisor) {
02085   DebugAssert(divisor != 0, "ArithTheoremProducer::sumMulF: divisor = "
02086               +divisor.toString());
02087   Expr::iterator i = sum.begin();
02088   DebugAssert(i != sum.end(), CLASS_NAME "::sumModM");
02089   Rational C = i->getRational();
02090   C = f(C,m)/divisor;
02091   summands.push_back(rat(C));
02092   i++;
02093   for(Expr::iterator iend=sum.end(); i!=iend; ++i) {
02094     Expr monom = monomialMulF(*i, m, divisor);
02095     if(!monom.isRational())
02096       summands.push_back(monom);
02097     else
02098       DebugAssert(monom.getRational() == 0, "");
02099   }
02100 }
02101 
02102 Expr
02103 ArithTheoremProducer::monomialMulF(const Expr& i,
02104                                    const Rational& m, const Rational& divisor)
02105 {
02106   DebugAssert(divisor != 0, "ArithTheoremProducer::monomialMulF: divisor = "
02107               +divisor.toString());
02108   Rational ai = isMult(i) ? (i)[0].getRational() : 1;
02109   Expr xi = isMult(i) ? (i)[1] : (i);
02110   ai = f(ai,m)/divisor;
02111   if(0 == ai) return rat(0);
02112   if(1 == ai) return xi;
02113   return multExpr(rat(ai), xi);
02114 }
02115 
02116 // This recursive function accepts a term, t, and a 'map' of
02117 // substitutions [x1/t1, x2/t2,...,xn/tn].  it returns a t' which is
02118 // basically t[x1/t1,x2/t2...xn/tn]
02119 Expr
02120 ArithTheoremProducer::substitute(const Expr& term, ExprMap<Expr>& eMap)
02121 {
02122   ExprMap<Expr>::iterator i, iend = eMap.end();
02123 
02124   i = eMap.find(term);
02125   if(iend != i)
02126     return (*i).second;
02127 
02128   if (isMult(term)) {
02129     //in this case term is of the form c.x
02130     i = eMap.find(term[1]);
02131     if(iend != i)
02132       return term[0]*(*i).second;
02133     else
02134       return term;
02135   }
02136 
02137   if(isPlus(term)) {
02138     vector<Expr> output;
02139     for(Expr::iterator j = term.begin(), jend = term.end(); j != jend; ++j)
02140       output.push_back(substitute(*j, eMap));
02141     return plusExpr(output);
02142   }
02143   return term;    
02144 }
02145 
02146 bool ArithTheoremProducer::greaterthan(const Expr & l, const Expr & r)
02147 {
02148   //    DebugAssert(l != r, "");
02149   if (l==r) return false;
02150     
02151   switch(l.getKind()) {
02152   case RATIONAL_EXPR:
02153     DebugAssert(!r.isRational(), "");
02154     return true;
02155     break;
02156   case POW:
02157     switch (r.getKind()) {
02158     case RATIONAL_EXPR:
02159       // TODO:
02160       // alternately I could return (not greaterthan(r,l))
02161       return false;
02162       break;
02163     case POW:
02164       // x^n > y^n if x > y
02165       // x^n1 > x^n2 if n1 > n2
02166       return 
02167         ((r[1] < l[1]) || 
02168          ((r[1]==l[1]) && (r[0].getRational() < l[0].getRational())));
02169       break;
02170             
02171     case MULT:
02172       DebugAssert(r.arity() > 1, "");
02173       DebugAssert((r.arity() > 2) || (r[1] != l), "");
02174       if (r[1] == l) return false;
02175       return greaterthan(l, r[1]);
02176       break;
02177     case PLUS:
02178       DebugAssert(false, "");
02179       return true;
02180       break;
02181     default:
02182       // leaf
02183       return ((r < l[1]) || ((r == l[1]) && l[0].getRational() > 1));
02184       break;
02185     }
02186     break;
02187   case MULT:
02188     DebugAssert(l.arity() > 1, "");
02189     switch (r.getKind()) {
02190     case RATIONAL_EXPR:
02191       return false;
02192       break;
02193     case POW:
02194       DebugAssert(l.arity() > 1, "");
02195       DebugAssert((l.arity() > 2) || (l[1] != r), "");
02196       // TODO:
02197       // alternately return (not greaterthan(r,l)
02198       return ((l[1] == r) || greaterthan(l[1], r));
02199       break;
02200     case MULT:
02201       {
02202             
02203         DebugAssert(r.arity() > 1, "");
02204         Expr::iterator i = l.begin();
02205         Expr::iterator j = r.begin();
02206         ++i;
02207         ++j;
02208         for (; i != l.end() && j != r.end(); ++i, ++j) {
02209           if (*i == *j)
02210             continue;
02211           return greaterthan(*i,*j);
02212         }
02213         DebugAssert(i != l.end() || j != r.end(), "");
02214         if (i == l.end()) {
02215           // r is bigger
02216           return false;
02217         }
02218         else
02219           {
02220             // l is bigger
02221             return true;
02222           }
02223       }
02224       break;
02225     case PLUS:
02226       DebugAssert(false, "");
02227       return true;
02228       break;
02229     default:
02230       // leaf
02231       DebugAssert((l.arity() > 2) || (l[1] != r), "");
02232       return ((l[1] == r) || greaterthan(l[1], r));
02233       break;
02234     }
02235     break;
02236   case PLUS:
02237     DebugAssert(false, "");
02238     return true;
02239     break;
02240   default:
02241     // leaf
02242     switch (r.getKind()) {
02243     case RATIONAL_EXPR:
02244       return false;
02245       break;
02246     case POW:
02247       return ((r[1] < l) || ((r[1] == l) && (r[0].getRational() < 1)));
02248       break;
02249     case MULT:
02250       DebugAssert(r.arity() > 1, "");
02251       DebugAssert((r.arity() > 2) || (r[1] != l), "");
02252       if (l == r[1]) return false;
02253       return greaterthan(l,r[1]);
02254       break;
02255     case PLUS:
02256       DebugAssert(false, "");
02257       return true;
02258       break;
02259     default:
02260       // leaf
02261       return (r < l);
02262       break;
02263     }
02264     break;
02265   }
02266 }
02267 
02268 
02269 Theorem
02270 ArithTheoremProducer::eqElimIntRule(const Theorem& eqn, const Theorem& isIntx,
02271                                     const vector<Theorem>& isIntVars) {
02272   TRACE("arith eq", "eqElimIntRule(", eqn.getExpr(), ") {");
02273   Assumptions assump;
02274   Proof pf;
02275 
02276   if(CHECK_PROOFS)
02277     CHECK_SOUND(eqn.isRewrite(),
02278                 "ArithTheoremProducer::eqElimInt: input must be an equation" +
02279                 eqn.toString());
02280 
02281   const Expr& lhs = eqn.getLHS();
02282   const Expr& rhs = eqn.getRHS();
02283   Expr a, x;
02284   d_theoryArith->separateMonomial(lhs, a, x);
02285 
02286   if(CHECK_PROOFS) {
02287     // Checking LHS
02288     const Expr& isIntxe = isIntx.getExpr();
02289     CHECK_SOUND(isIntPred(isIntxe) && isIntxe[0] == x,
02290                 "ArithTheoremProducer::eqElimInt\n eqn = "
02291                 +eqn.getExpr().toString()
02292                 +"\n isIntx = "+isIntxe.toString());
02293     CHECK_SOUND(isRational(a) && a.getRational().isInteger()
02294                 && a.getRational() >= 2,
02295                 "ArithTheoremProducer::eqElimInt:\n lhs = "+lhs.toString());
02296     // Checking RHS
02297     // It cannot be a division (we don't handle it)
02298     CHECK_SOUND(!isDivide(rhs),
02299                 "ArithTheoremProducer::eqElimInt:\n rhs = "+rhs.toString());
02300     // If it's a single monomial, then it's the only "variable"
02301     if(!isPlus(rhs)) {
02302       Expr c, v;
02303       d_theoryArith->separateMonomial(rhs, c, v);
02304       CHECK_SOUND(isIntVars.size() == 1
02305                   && isIntPred(isIntVars[0].getExpr())
02306                   && isIntVars[0].getExpr()[0] == v
02307                   && isRational(c) && c.getRational().isInteger(),
02308                   "ArithTheoremProducer::eqElimInt:\n rhs = "+rhs.toString()
02309                   +"isIntVars.size = "+int2string(isIntVars.size()));
02310     } else { // RHS is a plus
02311       CHECK_SOUND(isIntVars.size() + 1 == (size_t)rhs.arity(),
02312                   "ArithTheoremProducer::eqElimInt: rhs = "+rhs.toString());
02313       // Check the free constant
02314       CHECK_SOUND(isRational(rhs[0]) && rhs[0].getRational().isInteger(),
02315                   "ArithTheoremProducer::eqElimInt: rhs = "+rhs.toString());
02316       // Check the vars
02317       for(size_t i=0, iend=isIntVars.size(); i<iend; ++i) {
02318         Expr c, v;
02319         d_theoryArith->separateMonomial(rhs[i+1], c, v);
02320         const Expr& isInt(isIntVars[i].getExpr());
02321         CHECK_SOUND(isIntPred(isInt) && isInt[0] == v
02322                     && isRational(c) && c.getRational().isInteger(),
02323                     "ArithTheoremProducer::eqElimInt:\n rhs["+int2string(i+1)
02324                     +"] = "+rhs[i+1].toString()
02325                     +"\n isInt = "+isInt.toString());
02326       }
02327     }
02328   }
02329 
02330   // Creating a fresh bound variable
02331   static int varCount(0);
02332   Expr newVar = d_em->newBoundVarExpr("_int_var", int2string(varCount++));
02333   newVar.setType(intType());
02334   Expr t2 = create_t2(lhs, rhs, newVar);
02335   Expr t3 = create_t3(lhs, rhs, newVar);
02336   vector<Expr> vars;
02337   vars.push_back(newVar);
02338   Expr res = d_em->newClosureExpr(EXISTS, vars,
02339                                   x.eqExpr(t2) && rat(0).eqExpr(t3));
02340   
02341   if(withAssumptions()) {
02342     vector<Theorem> thms(isIntVars);
02343     thms.push_back(isIntx);
02344     thms.push_back(eqn);
02345     assump = merge(thms);
02346   }
02347 
02348   if(withProof()) {
02349     vector<Proof> pfs;
02350     pfs.push_back(eqn.getProof());
02351     pfs.push_back(isIntx.getProof());
02352     vector<Theorem>::const_iterator i=isIntVars.begin(), iend=isIntVars.end();
02353     for(; i!=iend; ++i) 
02354       pfs.push_back(i->getProof());
02355     pf = newPf("eq_elim_int", eqn.getExpr(), pfs);
02356   }
02357 
02358   Theorem thm(newTheorem(res, assump, pf));
02359   TRACE("arith eq", "eqElimIntRule => ", thm.getExpr(), " }");
02360   return thm;
02361 }
02362 
02363 
02364 Theorem
02365 ArithTheoremProducer::isIntConst(const Expr& e) {
02366   Assumptions a;
02367   Proof pf;
02368 
02369   if(CHECK_PROOFS) {
02370     CHECK_SOUND(isIntPred(e) && e[0].isRational(),
02371                 "ArithTheoremProducer::isIntConst(e = "
02372                 +e.toString()+")");
02373   }
02374   if(withProof())
02375     pf = newPf("is_int_const", e);
02376   bool isInt = e[0].getRational().isInteger();
02377   return newRWTheorem(e, isInt? d_em->trueExpr() : d_em->falseExpr(), a, pf);
02378 }
02379 
02380 
02381 Theorem
02382 ArithTheoremProducer::equalLeaves1(const Theorem& thm)
02383 {
02384   Assumptions a;
02385   Proof pf;
02386   const Expr& e = thm.getRHS();
02387 
02388   if (CHECK_PROOFS) {
02389     CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR &&
02390                 e[1].getRational() == Rational(0) &&
02391                 e[0].getKind() == PLUS &&
02392                 e[0].arity() == 3 &&
02393                 e[0][0].getKind() == RATIONAL_EXPR &&
02394                 e[0][0].getRational() == Rational(0) &&
02395                 e[0][1].getKind() == MULT &&
02396                 e[0][1].arity() == 2 &&
02397                 e[0][1][0].getKind() == RATIONAL_EXPR &&
02398                 e[0][1][0].getRational() == Rational(-1),
02399                 "equalLeaves1");
02400   }
02401   if (withAssumptions())
02402     a = thm.getAssumptions();
02403   if (withProof())
02404   {
02405     vector<Proof> pfs;
02406     pfs.push_back(thm.getProof());
02407     pf = newPf("equalLeaves1", e, pfs);
02408   }
02409   return newRWTheorem(e, e[0][1][1].eqExpr(e[0][2]), a, pf);
02410 }
02411 
02412 
02413 Theorem
02414 ArithTheoremProducer::equalLeaves2(const Theorem& thm)
02415 {
02416   Assumptions a;
02417   Proof pf;
02418   const Expr& e = thm.getRHS();
02419 
02420   if (CHECK_PROOFS) {
02421     CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR &&
02422                 e[0].getRational() == Rational(0) &&
02423                 e[1].getKind() == PLUS &&
02424                 e[1].arity() == 3 &&
02425                 e[1][0].getKind() == RATIONAL_EXPR &&
02426                 e[1][0].getRational() == Rational(0) &&
02427                 e[1][1].getKind() == MULT &&
02428                 e[1][1].arity() == 2 &&
02429                 e[1][1][0].getKind() == RATIONAL_EXPR &&
02430                 e[1][1][0].getRational() == Rational(-1),
02431                 "equalLeaves2");
02432   }
02433   if (withAssumptions())
02434     a = thm.getAssumptions();
02435   if (withProof())
02436   {
02437     vector<Proof> pfs;
02438     pfs.push_back(thm.getProof());
02439     pf = newPf("equalLeaves2", e, pfs);
02440   }
02441   return newRWTheorem(e, e[1][1][1].eqExpr(e[1][2]), a, pf);
02442 }
02443 
02444 
02445 Theorem
02446 ArithTheoremProducer::equalLeaves3(const Theorem& thm)
02447 {
02448   Assumptions a;
02449   Proof pf;
02450   const Expr& e = thm.getRHS();
02451 
02452   if (CHECK_PROOFS) {
02453     CHECK_SOUND(e[1].getKind() == RATIONAL_EXPR &&
02454                 e[1].getRational() == Rational(0) &&
02455                 e[0].getKind() == PLUS &&
02456                 e[0].arity() == 3 &&
02457                 e[0][0].getKind() == RATIONAL_EXPR &&
02458                 e[0][0].getRational() == Rational(0) &&
02459                 e[0][2].getKind() == MULT &&
02460                 e[0][2].arity() == 2 &&
02461                 e[0][2][0].getKind() == RATIONAL_EXPR &&
02462                 e[0][2][0].getRational() == Rational(-1),
02463                 "equalLeaves3");
02464   }
02465   if (withAssumptions())
02466     a = thm.getAssumptions();
02467   if (withProof())
02468   {
02469     vector<Proof> pfs;
02470     pfs.push_back(thm.getProof());
02471     pf = newPf("equalLeaves3", e, pfs);
02472   }
02473   return newRWTheorem(e, e[0][2][1].eqExpr(e[0][1]), a, pf);
02474 }
02475 
02476 
02477 Theorem
02478 ArithTheoremProducer::equalLeaves4(const Theorem& thm)
02479 {
02480   Assumptions a;
02481   Proof pf;
02482   const Expr& e = thm.getRHS();
02483 
02484   if (CHECK_PROOFS) {
02485     CHECK_SOUND(e[0].getKind() == RATIONAL_EXPR &&
02486                 e[0].getRational() == Rational(0) &&
02487                 e[1].getKind() == PLUS &&
02488                 e[1].arity() == 3 &&
02489                 e[1][0].getKind() == RATIONAL_EXPR &&
02490                 e[1][0].getRational() == Rational(0) &&
02491                 e[1][2].getKind() == MULT &&
02492                 e[1][2].arity() == 2 &&
02493                 e[1][2][0].getKind() == RATIONAL_EXPR &&
02494                 e[1][2][0].getRational() == Rational(-1),
02495                 "equalLeaves4");
02496   }
02497   if (withAssumptions())
02498     a = thm.getAssumptions();
02499   if (withProof())
02500   {
02501     vector<Proof> pfs;
02502     pfs.push_back(thm.getProof());
02503     pf = newPf("equalLeaves4", e, pfs);
02504   }
02505   return newRWTheorem(e, e[1][2][1].eqExpr(e[1][1]), a, pf);
02506 }
02507 
02508 Theorem
02509 ArithTheoremProducer::diseqToIneq(const Theorem& diseq) {
02510   Assumptions a;
02511   Proof pf;
02512 
02513   const Expr& e = diseq.getExpr();
02514 
02515   if(CHECK_PROOFS) {
02516     CHECK_SOUND(e.isNot() && e[0].isEq(),
02517                 "ArithTheoremProducer::diseqToIneq: expected disequality:\n"
02518                 " e = "+e.toString());
02519   }
02520 
02521   const Expr& x = e[0][0];
02522   const Expr& y = e[0][1];
02523 
02524   if(withAssumptions())
02525     a = diseq.getAssumptions();
02526   if(withProof())
02527     pf = newPf(e, diseq.getProof());
02528   return newTheorem(ltExpr(x,y).orExpr(gtExpr(x,y)), a, pf);
02529 }

Generated on Thu Apr 13 16:57:28 2006 for CVC Lite by  doxygen 1.4.4