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

Generated on Fri May 20 13:13:48 2005 for CVC Lite by  doxygen 1.3.9.1