00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "theory_arith.h"
00031 #include "arith_proof_rules.h"
00032 #include "arith_expr.h"
00033 #include "vcl.h"
00034 #include "arith_exception.h"
00035 #include "typecheck_exception.h"
00036 #include "eval_exception.h"
00037 #include "parser_exception.h"
00038 #include "smtlib_exception.h"
00039
00040 using namespace std;
00041 using namespace CVCL;
00042
00043
00044
00045
00046
00047
00048 namespace CVCL {
00049
00050 ostream& operator<<(ostream& os, const TheoryArith::FreeConst& fc) {
00051 os << "FreeConst(r=" << fc.getConst() << ", "
00052 << (fc.strict()? "strict" : "non-strict") << ")";
00053 return os;
00054 }
00055
00056
00057
00058
00059
00060 ostream& operator<<(ostream& os, const TheoryArith::Ineq& ineq) {
00061 os << "Ineq(" << ineq.ineq().getExpr() << ", isolated on "
00062 << (ineq.varOnRHS()? "RHS" : "LHS") << ", const = "
00063 << ineq.getConst() << ")";
00064 return os;
00065 }
00066 }
00067
00068
00069
00070
00071
00072
00073
00074 Theorem TheoryArith::isIntegerThm(const Expr& e) {
00075
00076 if(isReal(getType(e))) return Theorem();
00077
00078 return isIntegerDerive(newExpr(getEM(), IS_INTEGER, e), typePred(e));
00079 }
00080
00081
00082 Theorem TheoryArith::isIntegerDerive(const Expr& isIntE, const Theorem& thm) {
00083 const Expr& e = thm.getExpr();
00084
00085 if(e == isIntE) return thm;
00086
00087 Theorem res;
00088
00089 if(e.isAnd()) {
00090 int i, iend=e.arity();
00091 for(i=0; i<iend; ++i) {
00092 res = isIntegerDerive(isIntE, andElim(thm, i));
00093 if(!res.isNull()) return res;
00094 }
00095 }
00096 return res;
00097 }
00098
00099 const Rational& TheoryArith::freeConstIneq(const Expr& ineq, bool varOnRHS) {
00100 DebugAssert(isIneq(ineq), "TheoryArith::freeConstIneq("+ineq.toString()+")");
00101 const Expr& e = varOnRHS? ineq[0] : ineq[1];
00102
00103 switch(e.getKind()) {
00104 case PLUS:
00105 return e[0].getRational();
00106 case RATIONAL_EXPR:
00107 return e.getRational();
00108 default: {
00109 static Rational zero(0);
00110 return zero;
00111 }
00112 }
00113 }
00114
00115
00116 const TheoryArith::FreeConst&
00117 TheoryArith::updateSubsumptionDB(const Expr& ineq, bool varOnRHS,
00118 bool& subsumed) {
00119 TRACE("arith ineq", "TheoryArith::updateSubsumptionDB(", ineq,
00120 ", var isolated on "+string(varOnRHS? "RHS" : "LHS")+")");
00121 DebugAssert(isLT(ineq) || isLE(ineq), "TheoryArith::updateSubsumptionDB("
00122 +ineq.toString()+")");
00123
00124 Expr index;
00125 const Expr& t = varOnRHS? ineq[0] : ineq[1];
00126 bool strict(isLT(ineq));
00127 Rational c(0);
00128 if(isPlus(t)) {
00129 DebugAssert(t.arity() >= 2, "TheoryArith::updateSubsumptionDB("
00130 +ineq.toString()+")");
00131 c = t[0].getRational();
00132 Expr newT;
00133 if(t.arity() == 2) {
00134 newT = t[1];
00135 } else {
00136 vector<Expr> kids;
00137 Expr::iterator i=t.begin(), iend=t.end();
00138 for(++i; i!=iend; ++i) kids.push_back(*i);
00139 DebugAssert(kids.size() > 0, "kids.size = "+int2string(kids.size())
00140 +", ineq = "+ineq.toString());
00141 newT = plusExpr(kids);
00142 }
00143 if(varOnRHS)
00144 index = leExpr(newT, ineq[1]);
00145 else
00146 index = leExpr(ineq[0], newT);
00147 } else if(isRational(t)) {
00148 c = t.getRational();
00149 if(varOnRHS)
00150 index = leExpr(rat(0), ineq[1]);
00151 else
00152 index = leExpr(ineq[0], rat(0));
00153 } else if(isLT(ineq))
00154 index = leExpr(ineq[0], ineq[1]);
00155 else
00156 index = ineq;
00157
00158 CDMap<Expr, FreeConst>::iterator i=d_freeConstDB.find(index),
00159 iend=d_freeConstDB.end();
00160 if(i == iend) {
00161 subsumed = false;
00162
00163 CDOmap<Expr,FreeConst>& obj = d_freeConstDB[index];
00164 obj = FreeConst(c,strict);
00165 TRACE("arith ineq", "freeConstDB["+index.toString()+"] := ", obj, "");
00166 return obj.get();
00167 } else {
00168 CDOmap<Expr,FreeConst>& obj = d_freeConstDB[index];
00169 const FreeConst& fc = obj.get();
00170 if(varOnRHS) {
00171 subsumed = (c < fc.getConst() ||
00172 (c == fc.getConst() && (!strict || fc.strict())));
00173 } else {
00174 subsumed = (c > fc.getConst() ||
00175 (c == fc.getConst() && (strict || !fc.strict())));
00176 }
00177 if(!subsumed) {
00178 obj = FreeConst(c,strict);
00179 TRACE("arith ineq", "freeConstDB["+index.toString()+"] := ", obj, "");
00180 }
00181 return obj.get();
00182 }
00183 }
00184
00185
00186 bool TheoryArith::kidsCanonical(const Expr& e) {
00187 if(isLeaf(e)) return true;
00188 bool res(true);
00189 for(int i=0; res && i<e.arity(); ++i) {
00190 Expr simp(canon(e[i]).getRHS());
00191 res = (e[i] == simp);
00192 IF_DEBUG(if(!res) debugger.getOS() << "\ne[" << i << "] = " << e[i]
00193 << "\nsimplified = " << simp << endl);
00194 }
00195 return res;
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 Theorem TheoryArith::canon(const Expr& e)
00219 {
00220 TRACE("arith canon","canon(",e,") {");
00221 DebugAssert(kidsCanonical(e), "TheoryArith::canon("+e.toString()+")");
00222 Theorem result;
00223 switch (e.getKind()) {
00224 case UMINUS: {
00225 Theorem thm = d_rules->uMinusToMult(e[0]);
00226 Expr e2 = thm.getRHS();
00227 result = transitivityRule(thm, canon(e2));
00228 }
00229 break;
00230 case PLUS:
00231
00232
00233
00234
00235
00236
00237 result = d_rules->canonPlus(e);
00238 break;
00239 case MINUS: {
00240 DebugAssert(e.arity() == 2,"");
00241 Theorem minus_eq_sum = d_rules->minusToPlus(e[0], e[1]);
00242
00243 Expr sum(minus_eq_sum.getRHS());
00244 Theorem thm(canon(sum[1]));
00245 if(thm.getLHS() == thm.getRHS())
00246 result = canon(minus_eq_sum);
00247
00248 else {
00249 vector<unsigned> changed;
00250 vector<Theorem> thms;
00251 changed.push_back(1);
00252 thms.push_back(thm);
00253 Theorem sum_eq_canon = canon(substitutivityRule(sum, changed, thms));
00254 result = transitivityRule(minus_eq_sum, sum_eq_canon);
00255 }
00256 break;
00257 }
00258
00259 case MULT:
00260 result = d_rules->canonMult(e);
00261 break;
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323 case DIVIDE:{
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 if (e[1].getKind() == PLUS)
00346 throw ArithException("Divide by a PLUS expression not handled in"+e.toString());
00347 result = d_rules->canonDivide(e);
00348 break;
00349 }
00350 case POW:
00351 if(e[1].isRational())
00352 result = d_rules->canonPowConst(e);
00353 else
00354 result = reflexivityRule(e);
00355 break;
00356 default:
00357 result = reflexivityRule(e);
00358 break;
00359 }
00360 TRACE("arith canon","canon => ",result," }");
00361 return result;
00362 }
00363
00364
00365 Theorem
00366 TheoryArith::canonSimplify(const Expr& e) {
00367 TRACE("arith", "canonSimplify(", e, ") {");
00368 DebugAssert(kidsCanonical(e),
00369 "TheoryArith::canonSimplify("+e.toString()+")");
00370 Expr tmp(e);
00371 Theorem thm = canon(e);
00372 if(thm.getRHS().hasFind())
00373 thm = transitivityRule(thm, find(thm.getRHS()));
00374
00375 DebugAssert(thm.getRHS() == simplifyExpr(thm.getRHS()),
00376 "canonSimplify("+e.toString()+")\n"
00377 +"canon(e) = "+thm.getRHS().toString()
00378 +"\nsimplify(canon(e)) = "+simplifyExpr(thm.getRHS()).toString());
00379
00380
00381
00382
00383
00384
00385
00386
00387 TRACE("arith", "canonSimplify =>", thm, " }");
00388 return thm;
00389 }
00390
00391
00392
00393
00394 Theorem
00395 TheoryArith::canonPred(const Theorem& thm) {
00396 vector<Theorem> thms;
00397 DebugAssert(thm.getExpr().arity() == 2,
00398 "TheoryArith::canonPred: bad theorem: "+thm.toString());
00399 Expr e(thm.getExpr());
00400 thms.push_back(canonSimplify(e[0]));
00401 thms.push_back(canonSimplify(e[1]));
00402 return iffMP(thm, substitutivityRule(getOp(e), thms));
00403 }
00404
00405
00406
00407
00408 Theorem
00409 TheoryArith::canonPredEquiv(const Theorem& thm) {
00410 vector<Theorem> thms;
00411 DebugAssert(thm.getRHS().arity() == 2,
00412 "TheoryArith::canonPredEquiv: bad theorem: "+thm.toString());
00413 Expr e(thm.getRHS());
00414 thms.push_back(canonSimplify(e[0]));
00415 thms.push_back(canonSimplify(e[1]));
00416 return transitivityRule(thm, substitutivityRule(getOp(e), thms));
00417 }
00418
00419
00420
00421
00422
00423 Theorem
00424 TheoryArith::canonConjunctionEquiv(const Theorem& thm) {
00425 vector<Theorem> thms;
00426 return thm;
00427 }
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 Theorem TheoryArith::doSolve(const Theorem& thm)
00438 {
00439 const Expr& e = thm.getExpr();
00440 TRACE("arith eq","doSolve(",e,") {");
00441 DebugAssert(thm.isRewrite(), "thm = "+thm.toString());
00442 Theorem eqnThm;
00443 vector<Theorem> thms;
00444
00445 if(e[0].isRational() && e[0].getRational() == 0)
00446 eqnThm = thm;
00447 else {
00448 eqnThm = iffMP(thm, d_rules->rightMinusLeft(e));
00449 eqnThm = canonPred(eqnThm);
00450 }
00451
00452
00453 Expr right = eqnThm.getRHS();
00454
00455 if (right.isRational()) {
00456 Theorem result = iffMP(eqnThm, d_rules->constPredicate(eqnThm.getExpr()));
00457 TRACE("arith eq","doSolve => ",result," }");
00458 return result;
00459 }
00460
00461
00462 eqnThm = iffMP(eqnThm, normalize(eqnThm.getExpr()));
00463 right = eqnThm.getRHS();
00464
00465
00466
00467 if(!isInteger(right)) {
00468 Theorem res;
00469 try {
00470 res = processRealEq(eqnThm);
00471 } catch(ArithException& e) {
00472 res = symmetryRule(eqnThm);
00473 TRACE("arith eq", "doSolve: failed to solve an equation: ", e, "");
00474 IF_DEBUG(debugger.counter("FAILED to solve real equalities")++);
00475 setIncomplete("Non-linear arithmetic inequalities");
00476 }
00477 IF_DEBUG(debugger.counter("solved real equalities")++);
00478 TRACE("arith eq", "doSolve [real] => ", res, " }");
00479 return res;
00480 }
00481 else {
00482 Theorem res = processIntEq(eqnThm);
00483 IF_DEBUG(debugger.counter("solved int equalities")++);
00484 TRACE("arith eq", "doSolve [int] => ", res, " }");
00485 return res;
00486 }
00487 }
00488
00489
00490
00491
00492
00493 Expr
00494 TheoryArith::pickIntEqMonomial(const Expr& right)
00495 {
00496 DebugAssert(isPlus(right) && right.arity() > 2,
00497 "TheoryArith::pickIntEqMonomial right is wrong :-): " +
00498 right.toString());
00499 DebugAssert(right[0].isRational(),
00500 "TheoryArith::pickIntEqMonomial. right[0] must be const" +
00501 right.toString());
00502 DebugAssert(isInteger(right),
00503 "TheoryArith::pickIntEqMonomial: right is of type int: " +
00504 right.toString());
00505
00506
00507 Expr::iterator i = right.begin();
00508 i++;
00509 Rational min = isMult(*i) ? abs((*i)[0].getRational()) : 1;
00510 Expr pickedMon = *i;
00511 for(Expr::iterator iend = right.end(); i != iend; ++i) {
00512 Rational coeff = isMult(*i) ? abs((*i)[0].getRational()) : 1;
00513 if(min > coeff) {
00514 min = coeff;
00515 pickedMon = *i;
00516 }
00517 }
00518 return pickedMon;
00519 }
00520
00521
00522
00523
00524
00525 Theorem
00526 TheoryArith::processRealEq(const Theorem& eqn)
00527 {
00528 Expr right = eqn.getRHS();
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538 bool found = false;
00539
00540 Expr left;
00541
00542 if (isPlus(right)) {
00543 for(int i = right.arity()-1; i>=0; --i) {
00544 Expr c = right[i];
00545 if(isRational(c))
00546 continue;
00547 if(!isInteger(c)) {
00548 if (isLeaf(c) ||
00549 ((isMult(c) && c.arity() == 2 && isLeaf(c[1])))) {
00550 int numoccurs = 0;
00551 Expr leaf = isLeaf(c) ? c : c[1];
00552 for (int j = 0; j < right.arity(); ++j) {
00553 if (j!= i
00554 && isLeafIn(leaf, right[j])
00555
00556 ) {
00557 numoccurs++;
00558 break;
00559 }
00560 }
00561 if (!numoccurs) {
00562 left = c;
00563 found = true;
00564 break;
00565 }
00566 }
00567 }
00568 }
00569 }
00570 else if ((isMult(right) && right.arity() == 2 && isLeaf(right[1])) ||
00571 isLeaf(right)) {
00572 left = right;
00573 found = true;
00574 }
00575
00576 if (!found) {
00577
00578
00579 throw
00580 ArithException("Can't find a leaf for solve in "+eqn.toString());
00581 }
00582
00583 Rational r = -1;
00584 if (isMult(left)) {
00585 DebugAssert(left.arity() == 2, "only leaf should be chosen as lhs");
00586 DebugAssert(left[0].getRational() != 0, "left = "+left.toString());
00587 r = -1/left[0].getRational();
00588 left = left[1];
00589 }
00590
00591 DebugAssert(isReal(getBaseType(left)) && !isInteger(left),
00592 "TheoryArith::ProcessRealEq: left is integer:\n left = "
00593 +left.toString());
00594
00595
00596 Theorem result(iffMP(eqn,
00597 d_rules->multEqn(eqn.getLHS(), eqn.getRHS(), rat(r))));
00598 result = canonPred(result);
00599
00600
00601 result = iffMP(result, d_rules->plusPredicate(result.getLHS(),
00602 result.getRHS(), left, EQ));
00603 result = canonPred(result);
00604 TRACE("arith","processRealEq => ",result," }");
00605 return result;
00606 }
00607
00608
00609
00610
00611
00612 Theorem
00613 TheoryArith::processSimpleIntEq(const Theorem& eqn)
00614 {
00615 TRACE("arith eq", "processSimpleIntEq(", eqn.getExpr(), ") {");
00616 DebugAssert(eqn.isRewrite(),
00617 "TheoryArith::processSimpleIntEq: eqn must be equality" +
00618 eqn.getExpr().toString());
00619
00620 Expr right = eqn.getRHS();
00621
00622 DebugAssert(eqn.getLHS().isRational() && 0 == eqn.getLHS().getRational(),
00623 "TheoryArith::processSimpleIntEq: LHS must be 0:\n" +
00624 eqn.getExpr().toString());
00625
00626
00627 if(isMult(right)) {
00628
00629 Expr c,x;
00630 separateMonomial(right, c, x);
00631 Theorem isIntx(isIntegerThm(x));
00632 DebugAssert(!isIntx.isNull(), "right = "+right.toString());
00633 Theorem res(iffMP(eqn, d_rules->intVarEqnConst(eqn.getExpr(), isIntx)));
00634 TRACE("arith eq", "processSimpleIntEq[0 = a*x] => ", res, " }");
00635 return res;
00636 } else if(isPlus(right)) {
00637 if(2 == right.arity()) {
00638
00639 Expr c,x;
00640 separateMonomial(right[1], c, x);
00641 Theorem isIntx(isIntegerThm(x));
00642 DebugAssert(!isIntx.isNull(), "right = "+right.toString()
00643 +"\n x = "+x.toString());
00644 Theorem res(iffMP(eqn, d_rules->intVarEqnConst(eqn.getExpr(), isIntx)));
00645 TRACE("arith eq", "processSimpleIntEq[0 = c + a*x] => ", res, " }");
00646 return res;
00647 }
00648 DebugAssert(right.arity() > 2,
00649 "TheoryArith::processSimpleIntEq: RHS is not in correct form:"
00650 +eqn.getExpr().toString());
00651
00652 Expr isolated = pickIntEqMonomial(right);
00653 TRACE("arith eq", "processSimpleIntEq: isolated = ", isolated, "");
00654
00655
00656
00657
00658
00659 Rational r = isMult(isolated) ?
00660 ((isolated[0].getRational() > 0) ? -1 : 1) : -1;
00661 Theorem result;
00662 if (-1 == r) {
00663
00664
00665 result = iffMP(eqn, d_rules->multEqn(eqn.getLHS(), right, rat(r)));
00666 result = canonPred(result);
00667 Expr e = result.getRHS();
00668
00669
00670 result = iffMP(result,
00671 d_rules->plusPredicate(result.getLHS(),result.getRHS(),
00672 isolated, EQ));
00673 } else {
00674
00675 const Rational& minusa = isolated[0].getRational();
00676 Rational a = -1*minusa;
00677 isolated = (a == 1)? isolated[1] : rat(a) * isolated[1];
00678
00679
00680 result = iffMP(eqn, d_rules->plusPredicate(eqn.getLHS(),
00681 right,isolated,EQ));
00682 }
00683
00684 result = canonPred(result);
00685
00686
00687 if(!isMult(isolated) || isolated[0].getRational() == 1) {
00688 TRACE("arith eq", "processSimpleIntEq[x = rhs] => ", result, " }");
00689 return result;
00690 } else {
00691 DebugAssert(isMult(isolated) && isolated[0].getRational() >= 2,
00692 "TheoryArith::processSimpleIntEq: isolated must be mult "
00693 "with coeff >= 2.\n isolated = " + isolated.toString());
00694
00695
00696 const Expr& lhs = result.getLHS();
00697 const Expr& rhs = result.getRHS();
00698 Expr a, x;
00699 separateMonomial(lhs, a, x);
00700 Theorem isIntLHS = isIntegerThm(x);
00701 vector<Theorem> isIntRHS;
00702 if(!isPlus(rhs)) {
00703 Expr c, v;
00704 separateMonomial(rhs, c, v);
00705 isIntRHS.push_back(isIntegerThm(v));
00706 DebugAssert(!isIntRHS.back().isNull(), "");
00707 } else {
00708 DebugAssert(isPlus(rhs), "rhs = "+rhs.toString());
00709 DebugAssert(rhs.arity() >= 2, "rhs = "+rhs.toString());
00710 Expr::iterator i=rhs.begin(), iend=rhs.end();
00711 ++i;
00712 for(; i!=iend; ++i) {
00713 Expr c, v;
00714 separateMonomial(*i, c, v);
00715 isIntRHS.push_back(isIntegerThm(v));
00716 DebugAssert(!isIntRHS.back().isNull(), "");
00717 }
00718 }
00719
00720 result = d_rules->eqElimIntRule(result, isIntLHS, isIntRHS);
00721
00722 result = skolemize(result);
00723
00724 DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2,
00725 "processSimpleIntEq: result = "+result.getExpr().toString());
00726 Theorem thm1 = canonPred(andElim(result, 0));
00727 Theorem thm2 = canonPred(andElim(result, 1));
00728 Theorem newRes = andIntro(thm1, thm2);
00729 if(newRes.getExpr() != result.getExpr()) result = newRes;
00730
00731 TRACE("arith eq", "processSimpleIntEq => ", result, " }");
00732 return result;
00733 }
00734 } else {
00735
00736 Theorem result = symmetryRule(eqn);
00737 TRACE("arith eq", "processSimpleIntEq[x = 0] => ", result, " }");
00738 return result;
00739 }
00740 }
00741
00742
00743
00744
00745
00746
00747 Theorem
00748 TheoryArith::processIntEq(const Theorem& eqn)
00749 {
00750 TRACE("arith eq", "processIntEq(", eqn.getExpr(), ") {");
00751
00752 std::vector<Theorem> solvedAndNewEqs;
00753 Theorem newEq(eqn), result;
00754 bool done(false);
00755 do {
00756 result = processSimpleIntEq(newEq);
00757
00758 if(result.isRewrite()) {
00759 solvedAndNewEqs.push_back(result);
00760 done = true;
00761 }
00762 else if(!result.getExpr().isFalse()) {
00763 DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2,
00764 "TheoryArith::processIntEq("+eqn.getExpr().toString()
00765 +")\n result = "+result.getExpr().toString());
00766 solvedAndNewEqs.push_back(andElim(result, 0));
00767 newEq = andElim(result, 1);
00768 } else
00769 done = true;
00770 } while(!done);
00771 Theorem res;
00772 if(result.getExpr().isFalse()) res = result;
00773 else res = solvedForm(solvedAndNewEqs);
00774 TRACE("arith eq", "processIntEq => ", res.getExpr(), " }");
00775 return res;
00776 }
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786 Theorem
00787 TheoryArith::solvedForm(const vector<Theorem>& solvedEqs)
00788 {
00789 DebugAssert(solvedEqs.size() > 0, "TheoryArith::solvedForm()");
00790
00791
00792 TRACE_MSG("arith eq", "TheoryArith::solvedForm:solvedEqs(\n [");
00793 IF_DEBUG(if(debugger.trace("arith eq")) {
00794 for(vector<Theorem>::const_iterator j = solvedEqs.begin(),
00795 jend=solvedEqs.end(); j!=jend;++j)
00796 TRACE("arith eq", "", j->getExpr(), ",\n ");
00797 });
00798 TRACE_MSG("arith eq", " ]) {");
00799
00800
00801 vector<Theorem>::const_reverse_iterator
00802 i = solvedEqs.rbegin(),
00803 iend = solvedEqs.rend();
00804
00805
00806 ExprMap<Theorem> subst;
00807 for(; i!=iend; ++i) {
00808 if(i->isRewrite()) {
00809 Theorem thm = substAndCanonize(*i, subst);
00810 TRACE("arith eq", "solvedForm: subst["+i->getLHS().toString()+"] = ",
00811 thm.getExpr(), "");
00812 subst[i->getLHS()] = thm;
00813 }
00814 else {
00815
00816 DebugAssert(i->getExpr().isFalse(),
00817 "TheoryArith::solvedForm: an element of solvedEqs must "
00818 "be either EQ or FALSE: "+i->toString());
00819 return *i;
00820 }
00821 }
00822
00823
00824 vector<Theorem> thms;
00825 for(ExprMap<Theorem>::iterator i=subst.begin(), iend=subst.end();
00826 i!=iend; ++i)
00827 thms.push_back(i->second);
00828 return andIntro(thms);
00829 }
00830
00831
00832
00833
00834
00835
00836
00837
00838 Theorem
00839 TheoryArith::substAndCanonize(const Expr& t, ExprMap<Theorem>& subst)
00840 {
00841 TRACE("arith eq", "substAndCanonize(", t, ") {");
00842
00843 if(subst.empty()) {
00844 Theorem res(reflexivityRule(t));
00845 TRACE("arith eq", "substAndCanonize[subst empty] => ", res, " }");
00846 return res;
00847 }
00848
00849 ExprMap<Theorem>::iterator i = subst.find(t), iend=subst.end();
00850 if(i!=iend) {
00851 TRACE("arith eq", "substAndCanonize[subst] => ", i->second, " }");
00852 return i->second;
00853 }
00854
00855 if(isLeaf(t)) {
00856 Theorem res(reflexivityRule(t));
00857 TRACE("arith eq", "substAndCanonize[i-leaf] => ", res, " }");
00858 return res;
00859 }
00860
00861 vector<Theorem> thms;
00862 vector<unsigned> changed;
00863 for(unsigned j=0, jend=t.arity(); j!=jend; ++j) {
00864 Theorem thm = substAndCanonize(t[j], subst);
00865 if(thm.getRHS() != t[j]) {
00866 thm = canon(thm);
00867 thms.push_back(thm);
00868 changed.push_back(j);
00869 }
00870 }
00871
00872 Theorem res;
00873 if(thms.size() > 0) {
00874 res = substitutivityRule(t, changed, thms);
00875 res = canon(res);
00876 }
00877 else
00878 res = reflexivityRule(t);
00879 TRACE("arith eq", "substAndCanonize => ", res, " }");
00880 return res;
00881 }
00882
00883
00884
00885
00886
00887
00888
00889 Theorem
00890 TheoryArith::substAndCanonize(const Theorem& eq, ExprMap<Theorem>& subst)
00891 {
00892
00893 if(subst.empty()) return eq;
00894
00895 DebugAssert(eq.isRewrite(), "TheoryArith::substAndCanonize: t = "
00896 +eq.getExpr().toString());
00897 const Expr& t = eq.getRHS();
00898
00899 Theorem thm = substAndCanonize(t, subst);
00900
00901 if(thm.getRHS() == t) return eq;
00902
00903 vector<Theorem> thms;
00904 vector<unsigned> changed;
00905 thms.push_back(thm);
00906 changed.push_back(1);
00907 return iffMP(eq, substitutivityRule(eq.getExpr(), changed, thms));
00908 }
00909
00910
00911 void TheoryArith::processBuffer()
00912 {
00913
00914 bool varOnRHS;
00915 for(; !inconsistent() && d_bufferIdx < d_buffer.size();
00916 d_bufferIdx = d_bufferIdx+1) {
00917 const Theorem& ineqThm = d_buffer[d_bufferIdx];
00918
00919 if(isStale(ineqThm.getExpr())) continue;
00920 Theorem thm1 = isolateVariable(ineqThm, varOnRHS);
00921 const Expr& ineq = thm1.getExpr();
00922 if((ineq).isFalse())
00923 setInconsistent(thm1);
00924 else if(!ineq.isTrue()) {
00925
00926 DebugAssert(varOnRHS? !isPlus(ineq[1]) : !isPlus(ineq[0]),
00927 "TheoryArith::processBuffer(): bad result from "
00928 "isolateVariable:\nineq = "+ineq.toString());
00929
00930 projectInequalities(thm1, varOnRHS);
00931 }
00932 }
00933 }
00934
00935
00936 void TheoryArith::updateStats(const Rational& c, const Expr& v)
00937 {
00938 TRACE("arith ineq", "updateStats("+c.toString()+", ", v, ")");
00939 if(c > 0) {
00940 if(d_countRight.count(v) > 0) d_countRight[v] = d_countRight[v] + 1;
00941 else d_countRight[v] = 1;
00942 }
00943 else
00944 if(d_countLeft.count(v) > 0) d_countLeft[v] = d_countLeft[v] + 1;
00945 else d_countLeft[v] = 1;
00946 }
00947
00948
00949 void TheoryArith::updateStats(const Expr& monomial)
00950 {
00951 Expr c, m;
00952 separateMonomial(monomial, c, m);
00953 updateStats(c.getRational(), m);
00954 }
00955
00956
00957 void TheoryArith::addToBuffer(const Theorem& thm) {
00958
00959
00960 Theorem result(thm);
00961 const Expr& e = thm.getExpr();
00962
00963 if(!(e[0].isRational() && e[0].getRational() == 0)) {
00964 result = iffMP(result, d_rules->rightMinusLeft(e));
00965 result = canonPred(result);
00966 }
00967 TRACE("arith ineq", "addToBuffer(", result.getExpr(), ")");
00968
00969 d_buffer.push_back(thm);
00970
00971
00972 const Expr& rhs = thm.getExpr()[1];
00973 if(isPlus(rhs))
00974 for(Expr::iterator i=rhs.begin(), iend=rhs.end(); i!=iend; ++i)
00975 updateStats(*i);
00976 else
00977 updateStats(rhs);
00978 }
00979
00980
00981 Theorem TheoryArith::isolateVariable(const Theorem& inputThm,
00982 bool& isolatedVarOnRHS)
00983 {
00984 Theorem result(inputThm);
00985 const Expr& e = inputThm.getExpr();
00986 TRACE("arith","isolateVariable(",e,") {");
00987 TRACE("arith ineq", "isolateVariable(", e, ") {");
00988
00989 DebugAssert(isLT(e)||isLE(e),
00990 "TheoryArith::isolateVariable: " + e.toString() +
00991 " wrong kind");
00992 int kind = e.getKind();
00993 DebugAssert(e[0].isRational() && e[0].getRational() == 0,
00994 "TheoryArith::isolateVariable: theorem must be of "
00995 "the form 0 < rhs: " + inputThm.toString());
00996
00997 const Expr& zero = e[0];
00998 Expr right = e[1];
00999
01000 if (right.isRational()) {
01001 result = iffMP(result, d_rules->constPredicate(e));
01002 TRACE("arith ineq","isolateVariable => ",result.getExpr()," }");
01003 TRACE("arith","isolateVariable => ",result," }");
01004 return result;
01005 }
01006
01007
01008
01009
01010 Expr factor(computeNormalFactor(right));
01011 TRACE("arith", "isolateVariable: factor = ", factor, "");
01012 DebugAssert(factor.getRational() > 0,
01013 "isolateVariable: factor="+factor.toString());
01014
01015 if(factor.getRational() != 1) {
01016 result = iffMP(result, d_rules->multIneqn(e, factor));
01017
01018 result = canonPred(result);
01019 right = result.getExpr()[1];
01020 }
01021
01022
01023 Expr isolatedMonomial = right;
01024
01025 if (isPlus(right))
01026 isolatedMonomial = pickMonomial(right);
01027
01028 Rational r = -1;
01029 isolatedVarOnRHS = true;
01030 if (isMult(isolatedMonomial)) {
01031 r = ((isolatedMonomial[0].getRational()) >= 0)? -1 : 1;
01032 isolatedVarOnRHS =
01033 ((isolatedMonomial[0].getRational()) >= 0)? true : false;
01034 }
01035 isolatedMonomial = canon(rat(-1)*isolatedMonomial).getRHS();
01036
01037 result = iffMP(result, d_rules->plusPredicate(zero, right,
01038 isolatedMonomial, kind));
01039
01040 result = canonPred(result);
01041 if(1 != r) {
01042 result = iffMP(result, d_rules->multIneqn(result.getExpr(), rat(r)));
01043 result = canonPred(result);
01044 }
01045 TRACE("arith ineq","isolateVariable => ",result.getExpr()," }");
01046 TRACE("arith","isolateVariable => ",result," }");
01047 return result;
01048 }
01049
01050 Expr
01051 TheoryArith::computeNormalFactor(const Expr& right) {
01052
01053
01054 Rational factor;
01055 if(isPlus(right)) {
01056 vector<Rational> nums, denoms;
01057 for(int i=0, iend=right.arity(); i<iend; ++i) {
01058 switch(right[i].getKind()) {
01059 case RATIONAL_EXPR: {
01060 Rational c(abs(right[i].getRational()));
01061 nums.push_back(c.getNumerator());
01062 denoms.push_back(c.getDenominator());
01063 break;
01064 }
01065 case MULT: {
01066 Rational c(abs(right[i][0].getRational()));
01067 nums.push_back(c.getNumerator());
01068 denoms.push_back(c.getDenominator());
01069 break;
01070 }
01071 default:
01072 nums.push_back(1);
01073 denoms.push_back(1);
01074 break;
01075 }
01076 }
01077 Rational gcd_nums = gcd(nums);
01078
01079
01080
01081
01082 factor = (gcd_nums==0)? 0 : (lcm(denoms) / gcd_nums);
01083 } else if(isMult(right)) {
01084 const Rational& r = right[0].getRational();
01085 factor = (r==0)? 0 : (1/abs(r));
01086 }
01087 else
01088 factor = 1;
01089 return rat(factor);
01090 }
01091
01092
01093 bool TheoryArith::lessThanVar(const Expr& isolatedMonomial, const Expr& var2)
01094 {
01095 DebugAssert(!isRational(var2) && !isRational(isolatedMonomial),
01096 "TheoryArith::findMaxVar: isolatedMonomial cannot be rational" +
01097 isolatedMonomial.toString());
01098 Expr c, var0, var1;
01099 separateMonomial(isolatedMonomial, c, var0);
01100 separateMonomial(var2, c, var1);
01101 return var0 < var1;
01102 }
01103
01104
01105
01106
01107
01108
01109 bool TheoryArith::isStale(const Expr& e) {
01110 if(isTerm(e))
01111 return e != find(e).getRHS();
01112
01113
01114 bool stale=false;
01115 for(Expr::iterator i=e.begin(), iend=e.end(); !stale && i!=iend; ++i)
01116 stale = isStale(*i);
01117 return stale;
01118 }
01119
01120
01121 bool TheoryArith::isStale(const TheoryArith::Ineq& ineq) {
01122 TRACE("arith ineq", "isStale(", ineq, ") {");
01123 const Expr& ineqExpr = ineq.ineq().getExpr();
01124 const Rational& c = freeConstIneq(ineqExpr, ineq.varOnRHS());
01125 bool strict(isLT(ineqExpr));
01126 const FreeConst& fc = ineq.getConst();
01127
01128 bool subsumed;
01129
01130 if(ineq.varOnRHS()) {
01131 subsumed = (c < fc.getConst() ||
01132 (c == fc.getConst() && !strict && fc.strict()));
01133 } else {
01134 subsumed = (c > fc.getConst() ||
01135 (c == fc.getConst() && strict && !fc.strict()));
01136 }
01137
01138 bool res;
01139 if(subsumed) {
01140 res = true;
01141 TRACE("arith ineq", "isStale[subsumed] => ", res? "true" : "false", " }");
01142 }
01143 else {
01144 res = isStale(ineqExpr);
01145 TRACE("arith ineq", "isStale[updated] => ", res? "true" : "false", " }");
01146 }
01147 return res;
01148 }
01149
01150
01151 void TheoryArith::separateMonomial(const Expr& e, Expr& c, Expr& var) {
01152 TRACE("separateMonomial", "separateMonomial(", e, ")");
01153 DebugAssert(!isPlus(e),
01154 "TheoryArith::separateMonomial(e = "+e.toString()+")");
01155 if(isMult(e)) {
01156 DebugAssert(e.arity() >= 2,
01157 "TheoryArith::separateMonomial(e = "+e.toString()+")");
01158 c = e[0];
01159 if(e.arity() == 2) var = e[1];
01160 else {
01161 vector<Expr> kids = e.getKids();
01162 kids[0] = rat(1);
01163 var = multExpr(kids);
01164 }
01165 } else {
01166 c = rat(1);
01167 var = e;
01168 }
01169 DebugAssert(c.isRational(), "TheoryArith::separateMonomial(e = "
01170 +e.toString()+", c = "+c.toString()+")");
01171 DebugAssert(!isMult(var) || (var[0].isRational() && var[0].getRational()==1),
01172 "TheoryArith::separateMonomial(e = "
01173 +e.toString()+", var = "+var.toString()+")");
01174 }
01175
01176
01177 void TheoryArith::projectInequalities(const Theorem& theInequality,
01178 bool isolatedVarOnRHS)
01179 {
01180 TRACE("arith ineq", "projectInequalities(", theInequality.getExpr(),
01181 ", isolatedVarOnRHS="+string(isolatedVarOnRHS? "true" : "false")
01182 +") {");
01183 DebugAssert(isLE(theInequality.getExpr()) ||
01184 isLT(theInequality.getExpr()),
01185 "TheoryArith::projectIsolatedVar: "\
01186 "theInequality is of the wrong form: " +
01187 theInequality.toString());
01188
01189
01190 Theorem theIneqThm(theInequality);
01191 Expr theIneq = theIneqThm.getExpr();
01192
01193 Theorem isIntLHS(isIntegerThm(theIneq[0]));
01194 Theorem isIntRHS(isIntegerThm(theIneq[1]));
01195 bool isInt = (!isIntLHS.isNull() && !isIntRHS.isNull());
01196
01197 if(isLT(theIneq) && isInt) {
01198 Theorem thm = d_rules->lessThanToLE(theInequality, isIntLHS, isIntRHS,
01199 !isolatedVarOnRHS);
01200 theIneqThm = canonPred(iffMP(theIneqThm, thm));
01201 theIneq = theIneqThm.getExpr();
01202 }
01203 Expr isolatedMonomial =
01204 isolatedVarOnRHS ? theIneq[1] : theIneq[0];
01205
01206 Expr monomialVar, a;
01207 separateMonomial(isolatedMonomial, a, monomialVar);
01208
01209 bool subsumed;
01210 const FreeConst& bestConst =
01211 updateSubsumptionDB(theIneq, isolatedVarOnRHS, subsumed);
01212
01213 if(subsumed) {
01214 IF_DEBUG(debugger.counter("subsumed inequalities")++);
01215 TRACE("arith ineq", "subsumed inequality: ", theIneq, "");
01216 } else {
01217
01218
01219 if(isMult(monomialVar))
01220 setIncomplete("Non-linear arithmetic inequalities");
01221
01222
01223
01224 setupRec(theIneq[0]);
01225 setupRec(theIneq[1]);
01226
01227 ExprMap<CDList<Ineq> *>& db1 =
01228 isolatedVarOnRHS ? d_inequalitiesRightDB : d_inequalitiesLeftDB;
01229 ExprMap<CDList<Ineq> *>::iterator it1 = db1.find(monomialVar);
01230 if(it1 == db1.end()) {
01231 CDList<Ineq> * list = new CDList<Ineq>(d_vcl->getCurrentContext());
01232 list->push_back(Ineq(theIneqThm, isolatedVarOnRHS, bestConst));
01233 db1[monomialVar] = list;
01234 }
01235 else
01236 ((*it1).second)->push_back(Ineq(theIneqThm, isolatedVarOnRHS, bestConst));
01237
01238 ExprMap<CDList<Ineq> *>& db2 =
01239 isolatedVarOnRHS ? d_inequalitiesLeftDB : d_inequalitiesRightDB;
01240 ExprMap<CDList<Ineq> *>::iterator it = db2.find(monomialVar);
01241 if(it == db2.end()) {
01242 TRACE_MSG("arith ineq", "projectInequalities[not in DB] => }");
01243 return;
01244 }
01245
01246 CDList<Ineq>& listOfDBIneqs = *((*it).second);
01247 Theorem betaLTt, tLTalpha, thm;
01248 for(size_t i = 0, iend=listOfDBIneqs.size(); i!=iend; ++i) {
01249 const Ineq& ineqEntry = listOfDBIneqs[i];
01250 const Theorem& ineqThm = ineqEntry.ineq();
01251 if(!isStale(ineqEntry)) {
01252 betaLTt = isolatedVarOnRHS ? theIneqThm : ineqThm;
01253 tLTalpha = isolatedVarOnRHS ? ineqThm : theIneqThm;
01254 thm = normalizeProjectIneqs(betaLTt, tLTalpha);
01255
01256 IF_DEBUG(debugger.counter("real shadows")++);
01257
01258
01259 Expr e(thm.getExpr()); if(e.isFalse()) {
01260 setInconsistent(thm);
01261 TRACE_MSG("arith ineq", "projectInequalities[inconsistent] => }");
01262 return;
01263 }
01264 else {
01265 if(!e.isTrue() && !e.isEq())
01266 addToBuffer(thm);
01267 else if(e.isEq())
01268 enqueueFact(thm);
01269 }
01270 } else {
01271 IF_DEBUG(debugger.counter("stale inequalities")++);
01272 }
01273 }
01274 }
01275 TRACE_MSG("arith ineq", "projectInequalities => }");
01276 }
01277
01278 Theorem TheoryArith::normalizeProjectIneqs(const Theorem& ineqThm1,
01279 const Theorem& ineqThm2)
01280 {
01281
01282
01283 Theorem betaLTt = ineqThm1, tLTalpha = ineqThm2;
01284 Expr ineq1 = betaLTt.getExpr();
01285 Expr ineq2 = tLTalpha.getExpr();
01286 Expr c,x;
01287 separateMonomial(ineq2[0], c, x);
01288 Theorem isIntx(isIntegerThm(x));
01289 Theorem isIntBeta(isIntegerThm(ineq1[0]));
01290 Theorem isIntAlpha(isIntegerThm(ineq2[1]));
01291 bool isInt = !(isIntx.isNull() || isIntBeta.isNull() || isIntAlpha.isNull());
01292
01293 TRACE("arith ineq", "normalizeProjectIneqs(", ineq1,
01294 ", "+ineq2.toString()+") {");
01295 DebugAssert((isLE(ineq1) || isLT(ineq1)) &&
01296 (isLE(ineq2) || isLT(ineq2)),
01297 "TheoryArith::normalizeProjectIneqs: Wrong Kind inputs: " +
01298 ineq1.toString() + ineq2.toString());
01299 DebugAssert(!isPlus(ineq1[1]) && !isPlus(ineq2[0]),
01300 "TheoryArith::normalizeProjectIneqs: Wrong Kind inputs: " +
01301 ineq1.toString() + ineq2.toString());
01302
01303
01304
01305 Rational factor1 = 1, factor2 = 1;
01306 Rational b = isMult(ineq1[1]) ? (ineq1[1])[0].getRational() : 1;
01307 Rational a = isMult(ineq2[0]) ? (ineq2[0])[0].getRational() : 1;
01308 if(b != a) {
01309 factor1 = a;
01310 factor2 = b;
01311 }
01312
01313
01314
01315
01316
01317
01318
01319 if(isInt && (a >= 2 || b >= 2)) {
01320 Theorem intResult;
01321 if(a <= b)
01322 intResult = d_rules->darkGrayShadow2ab(betaLTt, tLTalpha,
01323 isIntAlpha, isIntBeta, isIntx);
01324 else
01325 intResult = d_rules->darkGrayShadow2ba(betaLTt, tLTalpha,
01326 isIntAlpha, isIntBeta, isIntx);
01327 enqueueFact(intResult);
01328
01329 DebugAssert(intResult.getExpr().isAnd() && intResult.getExpr().arity()==2,
01330 "intResult = "+intResult.getExpr().toString());
01331 const Expr& DorG = intResult.getExpr()[0];
01332 DebugAssert(DorG.isOr() && DorG.arity()==2, "DorG = "+DorG.toString());
01333 const Expr& D = DorG[0];
01334 const Expr& G = DorG[1];
01335 DebugAssert(D.getKind()==DARK_SHADOW, "D = "+D.toString());
01336 DebugAssert(G.getKind()==GRAY_SHADOW, "G = "+G.toString());
01337
01338 addSplitter(D, 100);
01339
01340 addSplitter(!G, 10);
01341 IF_DEBUG(debugger.counter("dark+gray shadows")++);
01342 }
01343
01344
01345 if(1 != factor1) {
01346 std::vector<Theorem> thms1;
01347 Theorem thm2 = iffMP(betaLTt, d_rules->multIneqn(ineq1, rat(factor1)));
01348 betaLTt = canonPred(thm2);
01349 ineq1 = betaLTt.getExpr();
01350 }
01351 if(1 != factor2) {
01352 std::vector<Theorem> thms1;
01353 Theorem thm2 = iffMP(tLTalpha, d_rules->multIneqn(ineq2, rat(factor2)));
01354 tLTalpha = canonPred(thm2);
01355 ineq2 = tLTalpha.getExpr();
01356 }
01357
01358
01359
01360 Expr beta(ineq1[0]);
01361 Expr alpha(ineq2[1]);
01362
01363 if(isLE(ineq1) && isLE(ineq2) && alpha == beta) {
01364 Theorem result = d_rules->realShadowEq(betaLTt, tLTalpha);
01365 TRACE("arith ineq", "normalizeProjectIneqs => ", result, " }");
01366 return result;
01367 }
01368
01369
01370 if(isInt)
01371 processFiniteInterval(betaLTt, tLTalpha);
01372
01373
01374
01375 Theorem result = d_rules->realShadow(betaLTt, tLTalpha);
01376
01377
01378
01379
01380
01381
01382 Expr e(result.getExpr());
01383
01384 if(!(e[0].isRational() && e[0].getRational() == 0)) {
01385 result = iffMP(result, d_rules->rightMinusLeft(e));
01386 result = canonPred(result);
01387 }
01388
01389
01390 Expr right = result.getExpr()[1];
01391
01392 if (right.isRational())
01393 result = iffMP(result, d_rules->constPredicate(result.getExpr()));
01394 TRACE("arith ineq", "normalizeProjectIneqs => ", result, " }");
01395 return result;
01396 }
01397
01398
01399 Expr TheoryArith::pickMonomial(const Expr& right)
01400 {
01401 DebugAssert(isPlus(right), "TheoryArith::pickMonomial: Wrong Kind: " +
01402 right.toString());
01403 if(d_vcl->getFlags()["var-order"].getBool()) {
01404 Expr::iterator i = right.begin();
01405 Expr isolatedMonomial = right[1];
01406
01407
01408
01409 for(++i; i != right.end(); ++i)
01410 if(lessThanVar(isolatedMonomial,*i))
01411 isolatedMonomial = *i;
01412 return isolatedMonomial;
01413 }
01414 ExprMap<Expr> var2monomial;
01415 vector<Expr> vars;
01416 Expr::iterator i = right.begin(), iend = right.end();
01417 for(;i != iend; ++i) {
01418 if(i->isRational())
01419 continue;
01420 Expr c, var;
01421 separateMonomial(*i, c, var);
01422 var2monomial[var] = *i;
01423 vars.push_back(var);
01424 }
01425 vector<Expr> largest;
01426 d_graph.selectLargest(vars, largest);
01427 DebugAssert(0 < largest.size(),
01428 "TheoryArith::pickMonomial: selectLargest: failed!!!!");
01429 if(1 == largest.size())
01430 return var2monomial[largest[0] ];
01431 else {
01432 size_t pickedVar = 0;
01433
01434
01435 int minProjections(-1);
01436 for(size_t k=0; k< largest.size(); ++k) {
01437 const Expr& var(largest[k]), monom(var2monomial[var]);
01438
01439 int nRight = (d_countRight.count(var) > 0)? d_countRight[var] : 0;
01440 int nLeft = (d_countLeft.count(var) > 0)? d_countLeft[var] : 0;
01441 int n(nRight*nLeft);
01442 TRACE("arith ineq", "pickMonomial: var=", var,
01443 ", nRight="+int2string(nRight)+", nLeft="+int2string(nLeft));
01444 if(minProjections < 0 || minProjections > n) {
01445 minProjections = n;
01446 pickedVar = k;
01447 }
01448 TRACE("arith ineq", "Number of projections for "+var.toString()+" = ",
01449 n, "");
01450 }
01451
01452 const Expr& largestVar = largest[pickedVar];
01453
01454
01455
01456
01457 for(size_t k = 0; k < largest.size(); ++k) {
01458 if(k != pickedVar)
01459 d_graph.addEdge(largestVar, largest[k]);
01460 }
01461 return var2monomial[largestVar];
01462 }
01463 }
01464
01465 void TheoryArith::VarOrderGraph::addEdge(const Expr& e1, const Expr& e2)
01466 {
01467 TRACE("arith var order", "addEdge("+e1.toString()+" > ", e2, ")");
01468 DebugAssert(e1 != e2, "TheoryArith::VarOrderGraph::addEdge("
01469 +e1.toString()+", "+e2.toString()+")");
01470 d_edges[e1].push_back(e2);
01471 }
01472
01473
01474
01475 bool TheoryArith::VarOrderGraph::lessThan(const Expr& e1, const Expr& e2)
01476 {
01477 d_cache.clear();
01478
01479 return dfs(e1,e2);
01480 }
01481
01482
01483 bool TheoryArith::VarOrderGraph::dfs(const Expr& e1, const Expr& e2)
01484 {
01485 if(e1 == e2)
01486 return true;
01487 if(d_cache.count(e2) > 0)
01488 return false;
01489 if(d_edges.count(e2) == 0)
01490 return false;
01491 d_cache[e2] = true;
01492 vector<Expr>& e2Edges = d_edges[e2];
01493 vector<Expr>::iterator i = e2Edges.begin();
01494 vector<Expr>::iterator iend = e2Edges.end();
01495
01496 for(; i != iend && !dfs(e1,*i); ++i);
01497 return (i != iend);
01498 }
01499
01500
01501 void TheoryArith::VarOrderGraph::selectSmallest(vector<Expr>& v1,
01502 vector<Expr>& v2)
01503 {
01504 int v1Size = v1.size();
01505 vector<bool> v3(v1Size);
01506 for(int j=0; j < v1Size; ++j)
01507 v3[j] = false;
01508
01509 for(int j=0; j < v1Size; ++j) {
01510 if(v3[j]) continue;
01511 for(int i =0; i < v1Size; ++i) {
01512 if((i == j) || v3[i])
01513 continue;
01514 if(lessThan(v1[i],v1[j])) {
01515 v3[j] = true;
01516 break;
01517 }
01518 }
01519 }
01520 vector<Expr> new_v1;
01521
01522 for(int j = 0; j < v1Size; ++j)
01523 if(!v3[j]) v2.push_back(v1[j]);
01524 else new_v1.push_back(v1[j]);
01525 v1 = new_v1;
01526 }
01527
01528
01529 void TheoryArith::VarOrderGraph::selectLargest(const vector<Expr>& v1,
01530 vector<Expr>& v2)
01531 {
01532 int v1Size = v1.size();
01533 vector<bool> v3(v1Size);
01534 for(int j=0; j < v1Size; ++j)
01535 v3[j] = false;
01536
01537 for(int j=0; j < v1Size; ++j) {
01538 if(v3[j]) continue;
01539 for(int i =0; i < v1Size; ++i) {
01540 if((i == j) || v3[i])
01541 continue;
01542 if(lessThan(v1[j],v1[i])) {
01543 v3[j] = true;
01544 break;
01545 }
01546 }
01547 }
01548
01549 for(int j = 0; j < v1Size; ++j)
01550 if(!v3[j]) v2.push_back(v1[j]);
01551 }
01552
01553
01554
01555
01556
01557
01558 TheoryArith::TheoryArith(VCL *vcl)
01559 : Theory(vcl, "Arithmetic"), d_vcl(vcl), d_diseq(vcl->getCurrentContext()),
01560 d_diseqIdx(vcl->getCurrentContext(), 0, 0),
01561 d_inModelCreation(vcl->getCurrentContext(), false, 0),
01562 d_realUsed(false), d_intUsed(false), d_intConstUsed(false),
01563 d_langUsed(NOT_USED),
01564 d_freeConstDB(vcl->getCurrentContext()),
01565 d_buffer(vcl->getCurrentContext()),
01566
01567 d_bufferIdx(vcl->getCurrentContext(), 0, 0),
01568 d_bufferThres(&(vcl->getFlags()["ineq-delay"].getInt())),
01569 d_countRight(vcl->getCurrentContext()),
01570 d_countLeft(vcl->getCurrentContext()),
01571 d_sharedTerms(vcl->getCurrentContext()),
01572 d_sharedVars(vcl->getCurrentContext())
01573 {
01574 IF_DEBUG(d_diseq.setName("CDList[TheoryArith::d_diseq]"));
01575 IF_DEBUG(d_buffer.setName("CDList[TheoryArith::d_buffer]"));
01576 IF_DEBUG(d_bufferIdx.setName("CDList[TheoryArith::d_bufferIdx]"));
01577
01578 getEM()->newKind(REAL, "REAL", true);
01579 getEM()->newKind(INT, "INT", true);
01580 getEM()->newKind(SUBRANGE, "SUBRANGE", true);
01581
01582 getEM()->newKind(UMINUS, "UMINUS");
01583 getEM()->newKind(PLUS, "PLUS");
01584 getEM()->newKind(MINUS, "MINUS");
01585 getEM()->newKind(MULT, "MULT");
01586 getEM()->newKind(DIVIDE, "DIVIDE");
01587 getEM()->newKind(POW, "POW");
01588 getEM()->newKind(INTDIV, "INTDIV");
01589 getEM()->newKind(MOD, "MOD");
01590 getEM()->newKind(LT, "LT");
01591 getEM()->newKind(LE, "LE");
01592 getEM()->newKind(GT, "GT");
01593 getEM()->newKind(GE, "GE");
01594 getEM()->newKind(IS_INTEGER, "IS_INTEGER");
01595 getEM()->newKind(NEGINF, "NEGINF");
01596 getEM()->newKind(POSINF, "POSINF");
01597 getEM()->newKind(DARK_SHADOW, "DARK_SHADOW");
01598 getEM()->newKind(GRAY_SHADOW, "GRAY_SHADOW");
01599
01600 d_grayShadowMMIndex = getEM()->registerSubclass(sizeof(ExprGrayShadow));
01601
01602 d_realType = Type(newExpr(getEM(), REAL));
01603 d_intType = Type(newExpr(getEM(), INT));
01604 d_rules = createProofRules(vcl);
01605
01606 vector<int> kinds;
01607 kinds.push_back(REAL);
01608 kinds.push_back(INT);
01609 kinds.push_back(SUBRANGE);
01610 kinds.push_back(IS_INTEGER);
01611 kinds.push_back(UMINUS);
01612 kinds.push_back(PLUS);
01613 kinds.push_back(MINUS);
01614 kinds.push_back(MULT);
01615 kinds.push_back(DIVIDE);
01616 kinds.push_back(POW);
01617 kinds.push_back(LT);
01618 kinds.push_back(LE);
01619 kinds.push_back(GT);
01620 kinds.push_back(GE);
01621 kinds.push_back(RATIONAL_EXPR);
01622 kinds.push_back(DARK_SHADOW);
01623 kinds.push_back(GRAY_SHADOW);
01624 kinds.push_back(INTDIV);
01625 kinds.push_back(MOD);
01626 kinds.push_back(NEGINF);
01627 kinds.push_back(POSINF);
01628
01629 registerTheory(this, kinds, true);
01630 }
01631
01632
01633
01634 TheoryArith::~TheoryArith() {
01635 if(d_rules != NULL) delete d_rules;
01636
01637 for(ExprMap<CDList<Ineq> *>::iterator i=d_inequalitiesRightDB.begin(),
01638 iend=d_inequalitiesRightDB.end(); i!=iend; ++i)
01639 delete (i->second);
01640 for(ExprMap<CDList<Ineq> *>::iterator i=d_inequalitiesLeftDB.begin(),
01641 iend=d_inequalitiesLeftDB.end(); i!=iend; ++i)
01642 delete (i->second);
01643 }
01644
01645 void TheoryArith::collectVars(const Expr& e, vector<Expr>& vars,
01646 set<Expr>& cache) {
01647
01648 if(cache.count(e) > 0) return;
01649
01650 cache.insert(e);
01651 if(isLeaf(e)) vars.push_back(e);
01652 else
01653 for(Expr::iterator i=e.begin(), iend=iend=e.end(); i!=iend; ++i)
01654 collectVars(*i, vars, cache);
01655 }
01656
01657 void
01658 TheoryArith::processFiniteInterval(const Theorem& alphaLEax,
01659 const Theorem& bxLEbeta) {
01660 const Expr& ineq1(alphaLEax.getExpr());
01661 const Expr& ineq2(bxLEbeta.getExpr());
01662 DebugAssert(isLE(ineq1), "TheoryArith::processFiniteInterval: ineq1 = "
01663 +ineq1.toString());
01664 DebugAssert(isLE(ineq2), "TheoryArith::processFiniteInterval: ineq2 = "
01665 +ineq2.toString());
01666
01667 if(!isInteger(ineq1[0])
01668 || !isInteger(ineq1[1])
01669 || !isInteger(ineq2[0])
01670 || !isInteger(ineq2[1]))
01671 return;
01672
01673 const Expr& ax = ineq1[1];
01674 const Expr& bx = ineq2[0];
01675 DebugAssert(!isPlus(ax) && !isRational(ax),
01676 "TheoryArith::processFiniteInterval:\n ax = "+ax.toString());
01677 DebugAssert(!isPlus(bx) && !isRational(bx),
01678 "TheoryArith::processFiniteInterval:\n bx = "+bx.toString());
01679 Expr a = isMult(ax)? ax[0] : rat(1);
01680 Expr b = isMult(bx)? bx[0] : rat(1);
01681
01682 Theorem thm1(alphaLEax), thm2(bxLEbeta);
01683
01684 if(a != b) {
01685 thm1 = canonPred(iffMP(alphaLEax, d_rules->multIneqn(ineq1, b)));
01686 thm2 = canonPred(iffMP(bxLEbeta, d_rules->multIneqn(ineq2, a)));
01687 }
01688
01689 const Expr& alphaLEt = thm1.getExpr();
01690 const Expr& alpha = alphaLEt[0];
01691 const Expr& t = alphaLEt[1];
01692 const Expr& beta = thm2.getExpr()[1];
01693 Expr c = canon(beta - alpha).getRHS();
01694
01695 if(c.isRational() && c.getRational() >= 1) {
01696
01697
01698
01699 Theorem bEQac = symmetryRule(canon(alpha + c));
01700
01701 vector<unsigned> changed;
01702 vector<Theorem> thms;
01703 changed.push_back(1);
01704 thms.push_back(bEQac);
01705 Theorem tLEac = substitutivityRule(thm2.getExpr(), changed, thms);
01706 tLEac = iffMP(thm2, tLEac);
01707
01708 Theorem isInta(isIntegerThm(alpha));
01709 Theorem isIntt(isIntegerThm(t));
01710 enqueueFact(d_rules->finiteInterval(thm1, tLEac, isInta, isIntt));
01711 }
01712 }
01713
01714
01715 void
01716 TheoryArith::processFiniteIntervals(const Expr& x) {
01717
01718 if(!isInteger(x)) return;
01719
01720 ExprMap<CDList<Ineq> *>::iterator iLeft, iRight;
01721 iLeft = d_inequalitiesLeftDB.find(x);
01722 if(iLeft == d_inequalitiesLeftDB.end()) return;
01723 iRight = d_inequalitiesRightDB.find(x);
01724 if(iRight == d_inequalitiesRightDB.end()) return;
01725
01726 CDList<Ineq>& ineqsLeft = *(iLeft->second);
01727 CDList<Ineq>& ineqsRight = *(iRight->second);
01728
01729 size_t sizeLeft = ineqsLeft.size();
01730 size_t sizeRight = ineqsRight.size();
01731
01732 for(size_t l=0; l<sizeLeft; ++l)
01733 for(size_t r=0; r<sizeRight; ++r)
01734 processFiniteInterval(ineqsRight[r], ineqsLeft[l]);
01735 }
01736
01737
01738
01739
01740
01741 void
01742 TheoryArith::setupRec(const Expr& e) {
01743 if(e.hasFind()) return;
01744
01745 for (int k = 0; k < e.arity(); ++k) {
01746 setupRec(e[k]);
01747 }
01748
01749 e.setFind(reflexivityRule(e));
01750
01751 setup(e);
01752 }
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771 void TheoryArith::addSharedTerm(const Expr& e) {
01772 d_sharedTerms[e] = true;
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785 }
01786
01787
01788 void TheoryArith::assertFact(const Theorem& e)
01789 {
01790 const Expr& expr = e.getExpr();
01791 if (expr.isNot() && expr[0].isEq()) {
01792 IF_DEBUG(debugger.counter("[arith] received disequalities")++);
01793 d_diseq.push_back(e);
01794 }
01795 else if (!expr.isEq()){
01796 if (expr.isNot()) {
01797
01798
01799
01800 }
01801 else if(isDarkShadow(expr)) {
01802 enqueueFact(d_rules->expandDarkShadow(e));
01803 IF_DEBUG(debugger.counter("received DARK_SHADOW")++);
01804 }
01805 else if(isGrayShadow(expr)) {
01806 IF_DEBUG(debugger.counter("received GRAY_SHADOW")++);
01807 const Rational& c1 = getC1(expr);
01808 const Rational& c2 = getC2(expr);
01809 const Expr& v = getV(expr);
01810 const Expr& ee = getE(expr);
01811 if(c1 == c2)
01812 enqueueFact(d_rules->expandGrayShadow0(e));
01813 else {
01814 Theorem gThm(e);
01815
01816 if(ee.isRational() && isMult(v)
01817 && v[0].isRational() && v[0].getRational() >= 2) {
01818 IF_DEBUG(debugger.counter("reduced const GRAY_SHADOW")++);
01819 gThm = d_rules->grayShadowConst(e);
01820 }
01821
01822 const Expr& g = gThm.getExpr();
01823 if(g.isFalse())
01824 setInconsistent(gThm);
01825 else if(getC1(g) == getC2(g))
01826 enqueueFact(d_rules->expandGrayShadow0(gThm));
01827 else {
01828
01829 enqueueFact(d_rules->expandGrayShadow(gThm));
01830
01831 Theorem thm2 = d_rules->splitGrayShadow(gThm);
01832 enqueueFact(thm2);
01833
01834 DebugAssert(thm2.getExpr().isAnd() && thm2.getExpr().arity()==2,
01835 "thm2 = "+thm2.getExpr().toString());
01836 const Expr& G1orG2 = thm2.getExpr()[0];
01837 DebugAssert(G1orG2.isOr() && G1orG2.arity()==2,
01838 "G1orG2 = "+G1orG2.toString());
01839 const Expr& G1 = G1orG2[0];
01840 const Expr& G2 = G1orG2[1];
01841 DebugAssert(G1.getKind()==GRAY_SHADOW, "G1 = "+G1.toString());
01842 DebugAssert(G2.getKind()==GRAY_SHADOW, "G2 = "+G2.toString());
01843
01844 addSplitter(G1, 10);
01845 addSplitter(G2, -10);
01846 }
01847 }
01848 }
01849 else {
01850 DebugAssert(isLE(expr) || isLT(expr) || isIntPred(expr),
01851 "expected LE or LT: "+expr.toString());
01852 if(isLE(expr) || isLT(expr)) {
01853 IF_DEBUG(debugger.counter("recevied inequalities")++);
01854
01855
01856 addToBuffer(e);
01857
01858 TRACE("arith ineq", "buffer.size() = ", d_buffer.size(),
01859 ", index="+int2string(d_bufferIdx)
01860 +", threshold="+int2string(*d_bufferThres));
01861
01862 if((((int)d_buffer.size()) - (int)d_bufferIdx > *d_bufferThres)
01863 && !d_inModelCreation)
01864 processBuffer();
01865 } else {
01866 IF_DEBUG(debugger.counter("arith IS_INTEGER")++);
01867 }
01868 }
01869 }
01870 else {
01871 IF_DEBUG(debugger.counter("[arith] received t1=t2")++);
01872 }
01873 }
01874
01875
01876 void TheoryArith::checkSat(bool fullEffort)
01877 {
01878
01879
01880
01881 TRACE("arith ineq", "TheoryArith::checkSat(fullEffort=",
01882 fullEffort? "true" : "false", ")");
01883 if (fullEffort) {
01884 while(!inconsistent() && d_bufferIdx < d_buffer.size())
01885 processBuffer();
01886 if(d_inModelCreation) {
01887 for(; d_diseqIdx < d_diseq.size(); d_diseqIdx = d_diseqIdx+1) {
01888 TRACE("model", "[arith] refining diseq: ",
01889 d_diseq[d_diseqIdx].getExpr() , "");
01890 enqueueFact(d_rules->diseqToIneq(d_diseq[d_diseqIdx]));
01891 }
01892 }
01893 }
01894 }
01895
01896
01897
01898 void TheoryArith::refineCounterExample()
01899 {
01900 d_inModelCreation = true;
01901 TRACE("model", "refineCounterExample[TheoryArith] ", "", "{");
01902 CDMap<Expr, bool>::iterator it = d_sharedTerms.begin(), it2,
01903 iend = d_sharedTerms.end();
01904
01905
01906
01907 for(; it!=iend; ++it) {
01908
01909 Expr e1 = (*it).first;
01910 for(it2 = it, ++it2; it2!=iend; ++it2) {
01911 Expr e2 = (*it2).first;
01912 DebugAssert(isReal(getBaseType(e1)),
01913 "TheoryArith::refineCounterExample: e1 = "+e1.toString()
01914 +"\n type(e1) = "+getType(e1).toString());
01915 if(findExpr(e1) != findExpr(e2)) {
01916 DebugAssert(isReal(getBaseType(e2)),
01917 "TheoryArith::refineCounterExample: e2 = "+e2.toString()
01918 +"\n type(e2) = "+getType(e2).toString());
01919 Expr eq = e1.eqExpr(e2);
01920 addSplitter(eq);
01921 }
01922 }
01923 }
01924 TRACE("model", "refineCounterExample[Theory::Arith] ", "", "}");
01925 }
01926
01927
01928 void
01929 TheoryArith::findRationalBound(const Expr& varSide, const Expr& ratSide,
01930 const Expr& var,
01931 Rational &r)
01932 {
01933 Expr c, x;
01934 separateMonomial(varSide, c, x);
01935
01936 DebugAssert(findExpr(c).isRational(),
01937 "seperateMonomial failed");
01938 DebugAssert(findExpr(ratSide).isRational(),
01939 "smallest variable in graph, should not have variables"
01940 " in inequalities: ");
01941 DebugAssert(x == var, "separateMonomial found different variable: "
01942 + var.toString());
01943 r = findExpr(ratSide).getRational() / findExpr(c).getRational();
01944 }
01945
01946 bool
01947 TheoryArith::findBounds(const Expr& e, Rational& lub, Rational& glb)
01948 {
01949 bool strictLB=false, strictUB=false;
01950 bool right = (d_inequalitiesRightDB.count(e) > 0
01951 && d_inequalitiesRightDB[e]->size() > 0);
01952 bool left = (d_inequalitiesLeftDB.count(e) > 0
01953 && d_inequalitiesLeftDB[e]->size() > 0);
01954 int numRight = 0, numLeft = 0;
01955 if(right) {
01956 CDList<Ineq> * ratsLTe = d_inequalitiesRightDB[e];
01957 for(unsigned int i=0; i<ratsLTe->size(); i++) {
01958 DebugAssert((*ratsLTe)[i].varOnRHS(), "variable on wrong side!");
01959 Expr ineq = (*ratsLTe)[i].ineq().getExpr();
01960 Expr leftSide = ineq[0], rightSide = ineq[1];
01961 Rational r;
01962 findRationalBound(rightSide, leftSide, e , r);
01963 if(numRight==0 || r>glb){
01964 glb = r;
01965 strictLB = isLT(ineq);
01966 }
01967 numRight++;
01968 }
01969 TRACE("model", " =>Lower bound ", glb.toString(), "");
01970 }
01971 if(left) {
01972 CDList<Ineq> * ratsGTe = d_inequalitiesLeftDB[e];
01973 for(unsigned int i=0; i<ratsGTe->size(); i++) {
01974 DebugAssert((*ratsGTe)[i].varOnLHS(), "variable on wrong side!");
01975 Expr ineq = (*ratsGTe)[i].ineq().getExpr();
01976 Expr leftSide = ineq[0], rightSide = ineq[1];
01977 Rational r;
01978 findRationalBound(leftSide, rightSide, e, r);
01979 if(numLeft==0 || r<lub) {
01980 lub = r;
01981 strictUB = isLT(ineq);
01982 }
01983 numLeft++;
01984 }
01985 TRACE("model", " =>Upper bound ", lub.toString(), "");
01986 }
01987 if(!left && !right) {
01988 lub = 0;
01989 glb = 0;
01990 }
01991 if(!left && right) {lub = glb +2;}
01992 if(!right && left) {glb = lub-2;}
01993 DebugAssert(glb <= lub, "Greatest lower bound needs to be smaller "
01994 "than least upper bound");
01995 return strictLB;
01996 }
01997
01998 void TheoryArith::assignVariables(std::vector<Expr>&v)
01999 {
02000 int count = 0;
02001 while (v.size() > 0) {
02002 std::vector<Expr> bottom;
02003 d_graph.selectSmallest(v, bottom);
02004 TRACE("model", "Finding variables to assign. Iteration # ", count, "");
02005 for(unsigned int i = 0; i<bottom.size(); i++) {
02006 Expr e = bottom[i];
02007 TRACE("model", "Found: ", e, "");
02008
02009 if(e.isRational()) continue;
02010
02011 Rational lub, glb;
02012 bool strictLB;
02013 strictLB = findBounds(e, lub, glb);
02014 Rational mid;
02015 if(isInteger(e)) {
02016 if(strictLB && glb.isInteger())
02017 mid = glb + 1;
02018 else
02019 mid = ceil(glb);
02020 }
02021 else
02022 mid = (lub + glb)/2;
02023 TRACE("model", "Assigning mid = ", mid, " {");
02024 assignValue(e, rat(mid));
02025 TRACE("model", "Assigned find(e) = ", findExpr(e), " }");
02026 if(inconsistent()) return;
02027 }
02028 count++;
02029 }
02030 }
02031
02032 void TheoryArith::computeModelBasic(const std::vector<Expr>& v)
02033 {
02034 d_inModelCreation = true;
02035 vector<Expr> reps;
02036 TRACE("model", "Arith=>computeModel ", "", "{");
02037 for(unsigned int i=0; i <v.size(); ++i) {
02038 const Expr& e = v[i];
02039 if(findExpr(e) == e) {
02040 TRACE("model", "arith variable:", e , "");
02041 reps.push_back(e);
02042 }
02043 else {
02044 TRACE("model", "arith variable:", e , "");
02045 TRACE("model", " ==> is defined by: ", findExpr(e) , "");
02046 }
02047 }
02048 assignVariables(reps);
02049 TRACE("model", "Arith=>computeModel", "", "}");
02050 d_inModelCreation = false;
02051 }
02052
02053
02054
02055 void TheoryArith::computeModel(const Expr& e, vector<Expr>& vars) {
02056 DebugAssert(findExpr(e).isRational(), "TheoryArith::computeModel("
02057 +e.toString()+")\n e is not assigned concrete value.\n"
02058 +" find(e) = "+findExpr(e).toString());
02059 assignValue(simplifyThm(e));
02060 vars.push_back(e);
02061 }
02062
02063
02064
02065
02066
02067
02068
02069 Theorem TheoryArith::normalize(const Expr& e) {
02070
02071
02072 TRACE("arith", "normalize(", e, ") {");
02073 DebugAssert(e.isEq() || isIneq(e),
02074 "normalize: input must be Eq or Ineq: " + e.toString());
02075 DebugAssert(!isIneq(e) || (0 == e[0].getRational()),
02076 "normalize: if (e is ineq) then e[0] must be 0" +
02077 e.toString());
02078 if(e.isEq()) {
02079 if(e[0].isRational()) {
02080 DebugAssert(0 == e[0].getRational(),
02081 "normalize: if e is Eq and e[0] is rat then e[0]==0");
02082 }
02083 else {
02084
02085 DebugAssert(e[1].isRational() && 0 == e[1].getRational(),
02086 "normalize: if e is Eq and e[1] is rat then e[1]==0\n"
02087 " e = "+e.toString());
02088 }
02089 }
02090
02091 Expr factor;
02092 if(e[0].isRational())
02093 factor = computeNormalFactor(e[1]);
02094 else
02095 factor = computeNormalFactor(e[0]);
02096
02097 TRACE("arith", "normalize: factor = ", factor, "");
02098 DebugAssert(factor.getRational() > 0,
02099 "normalize: factor="+ factor.toString());
02100
02101 Theorem thm(reflexivityRule(e));
02102
02103 if(factor.getRational() != 1) {
02104 int kind = e.getKind();
02105 switch(kind) {
02106 case EQ:
02107 thm = d_rules->multEqn(e[0], e[1], factor);
02108
02109 thm = canonPredEquiv(thm);
02110 break;
02111 case LE:
02112 case LT:
02113 case GE:
02114 case GT:
02115 thm = d_rules->multIneqn(e, factor);
02116
02117 thm = canonPredEquiv(thm);
02118 break;
02119 default:
02120 DebugAssert(false,
02121 "normalize: control should not reach here" + kind);
02122 break;
02123 }
02124 }
02125 TRACE("arith", "normalize => ", thm, " }");
02126 return(thm);
02127 }
02128
02129
02130 Theorem TheoryArith::normalize(const Theorem& eIffEqn) {
02131 return transitivityRule(eIffEqn, normalize(eIffEqn.getRHS()));
02132 }
02133
02134
02135 Theorem TheoryArith::rewrite(const Expr& e)
02136 {
02137 TRACE("arith", "TheoryArith::rewrite(", e, ") {");
02138 Theorem thm;
02139 if (!isTerm(e)) {
02140 if (!isLiteral(e)) {
02141 e.setRewriteNormal();
02142 thm = reflexivityRule(e);
02143 TRACE("arith", "TheoryArith::rewrite[non-literal] => ", thm, " }");
02144 return thm;
02145 }
02146 switch(e.getKind()) {
02147 case EQ:
02148 {
02149
02150
02151 if (isLeaf(e[0]) && isLeaf(e[1]))
02152 thm = reflexivityRule(e);
02153 else {
02154
02155 if((e[0].isRational() && e[0].getRational() == 0)
02156 || (e[1].isRational() && e[1].getRational() == 0))
02157
02158 thm = reflexivityRule(e);
02159 else {
02160 thm = d_rules->rightMinusLeft(e);
02161 thm = canonPredEquiv(thm);
02162 }
02163
02164 if ((thm.getRHS())[0].isRational() && (thm.getRHS())[1].isRational()) {
02165 thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS()));
02166 } else {
02167
02168 thm = normalize(thm);
02169
02170 thm = canonPredEquiv(thm);
02171
02172 }
02173 }
02174
02175
02176
02177 const Expr& eq = thm.getRHS();
02178 if(eq.isEq() && eq[0] < eq[1])
02179 thm = transitivityRule(thm, rewriteUsingSymmetry(eq));
02180 }
02181 break;
02182 case GRAY_SHADOW:
02183 case DARK_SHADOW:
02184 thm = reflexivityRule(e);
02185 break;
02186 case IS_INTEGER: {
02187 Theorem res(isIntegerDerive(e, typePred(e[0])));
02188 if(!res.isNull())
02189 thm = iffTrue(res);
02190 else
02191 thm = reflexivityRule(e);
02192 break;
02193 }
02194 case NOT:
02195 if (!isIneq(e[0]))
02196
02197 thm = reflexivityRule(e);
02198 else {
02199
02200
02201 thm = d_rules->negatedInequality(e);
02202 DebugAssert(isGE(thm.getRHS()) || isGT(thm.getRHS()),
02203 "Expected GE or GT");
02204 thm = transitivityRule(thm, d_rules->flipInequality(thm.getRHS()));
02205 thm = transitivityRule(thm, d_rules->rightMinusLeft(thm.getRHS()));
02206 thm = canonPredEquiv(thm);
02207
02208
02209 if ((thm.getRHS())[1].isRational())
02210 thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS()));
02211 else {
02212
02213 thm = normalize(thm);
02214
02215 thm = canonPredEquiv(thm);
02216 }
02217 }
02218 break;
02219 case LE:
02220 case LT:
02221 case GE:
02222 case GT:
02223 if (isGE(e) || isGT(e)) {
02224 thm = d_rules->flipInequality(e);
02225 thm = transitivityRule(thm, d_rules->rightMinusLeft(thm.getRHS()));
02226 }
02227 else
02228 thm = d_rules->rightMinusLeft(e);
02229 thm = canonPredEquiv(thm);
02230
02231
02232 if ((thm.getRHS())[1].isRational())
02233 thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS()));
02234 else {
02235 thm = normalize(thm);
02236 thm = canonPredEquiv(thm);
02237 }
02238 break;
02239 default:
02240 DebugAssert(false,
02241 "Theory_Arith::rewrite: control should not reach here");
02242 break;
02243 }
02244 }
02245 else {
02246 if (isAtomic(e))
02247 thm = canon(e);
02248
02249
02250
02251
02252
02253 else
02254 thm = reflexivityRule(e);
02255 }
02256
02257 thm.getRHS().setRewriteNormal();
02258 TRACE("arith", "TheoryArith::rewrite => ", thm, " }");
02259 return thm;
02260 }
02261
02262
02263 void TheoryArith::setup(const Expr& e)
02264 {
02265 if (!isTerm(e)) {
02266 if (e.isNot() || e.isEq() || isDarkShadow(e) || isGrayShadow(e)) return;
02267 if(e.getKind() == IS_INTEGER) {
02268 e[0].addToNotify(this, e);
02269 return;
02270 }
02271 DebugAssert((isLT(e)||isLE(e)) &&
02272 e[0].isRational() && e[0].getRational() == 0,
02273 "TheoryArith::setup: expected 0 < rhs:" + e.toString());
02274 e[1].addToNotify(this, e);
02275 return;
02276 }
02277 int k(0), ar(e.arity());
02278 for ( ; k < ar; ++k) {
02279 e[k].addToNotify(this, e);
02280 TRACE("arith setup", "e["+int2string(k)+"]: ", *(e[k].getNotify()), "");
02281 }
02282 }
02283
02284
02285 void TheoryArith::update(const Theorem& e, const Expr& d)
02286 {
02287 if (inconsistent()) return;
02288 IF_DEBUG(debugger.counter("arith update total")++);
02289 DebugAssert(d.hasFind(), "Expected d to have find:\nd = "+d.toString());
02290 if (isIneq(d)) {
02291
02292 DebugAssert(e.getLHS() == d[1], "Mismatch");
02293 Theorem thm = find(d);
02294 DebugAssert(thm.getRHS() == trueExpr(), "Expected find = true");
02295 vector<unsigned> changed;
02296 vector<Theorem> children;
02297 changed.push_back(1);
02298 children.push_back(e);
02299 enqueueFact(iffMP(iffTrueElim(thm),
02300 substitutivityRule(d, changed, children)));
02301 IF_DEBUG(debugger.counter("arith update ineq")++);
02302 }
02303 else if (find(d).getRHS() == d) {
02304
02305 Theorem thm = updateHelper(d);
02306 TRACE("arith", "TheoryArith::update(): thm = ", thm, "");
02307
02308
02309
02310 DebugAssert(rewrite(thm.getRHS()).getRHS() ==
02311 rewriteCore(thm.getRHS()).getRHS(), "rewrite error");
02312 enqueueEquality(transitivityRule(thm, rewrite(thm.getRHS())));
02313
02314
02315 IF_DEBUG(debugger.counter("arith update find(d)=d")++);
02316 } else {
02317
02318
02319
02320 Theorem thm = updateHelper(d);
02321 TRACE("arith", "TheoryArith::update()[non-rep]: thm = ", thm, "");
02322 enqueueFact(thm);
02323
02324
02325 IF_DEBUG(debugger.counter("arith update find(d)!=d")++);
02326 }
02327 }
02328
02329
02330 Theorem TheoryArith::solve(const Theorem& thm)
02331 {
02332 const Expr& e = thm.getExpr();
02333 DebugAssert(e.isEq(), "");
02334
02335
02336
02337
02338
02339
02340 if (isLeaf(e[0]) && !isLeafIn(e[0], e[1])
02341 && (!isInteger(e[0]) || isInteger(e[1]))
02342
02343 )
02344 return thm;
02345
02346
02347 if (isLeaf(e[1]) && !isLeafIn(e[1], e[0])
02348 && (isInteger(e[0]) || !isInteger(e[1]))
02349
02350 )
02351 return symmetryRule(thm);
02352
02353 return doSolve(thm);
02354 }
02355
02356
02357 void TheoryArith::computeModelTerm(const Expr& e, std::vector<Expr>& v) {
02358 switch(e.getKind()) {
02359 case RATIONAL_EXPR:
02360 break;
02361 case PLUS:
02362 case MULT:
02363 case DIVIDE:
02364 case POW:
02365 for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i)
02366
02367 v.push_back(*i);
02368 break;
02369 default: {
02370 Expr e2(findExpr(e));
02371 if(e==e2) {
02372 TRACE("model", "TheoryArith::computeModelTerm(", e, "): a variable");
02373
02374
02375 } else {
02376 TRACE("model", "TheoryArith::computeModelTerm("+e.toString()
02377 +"): has find pointer to ", e2, "");
02378 v.push_back(e2);
02379 }
02380 }
02381 }
02382 }
02383
02384
02385 Expr TheoryArith::computeTypePred(const Type& t, const Expr& e) {
02386 Expr tExpr = t.getExpr();
02387 switch(tExpr.getKind()) {
02388 case INT:
02389 return newExpr(getEM(), IS_INTEGER, e);
02390 case SUBRANGE: {
02391 std::vector<Expr> kids;
02392 kids.push_back(newExpr(getEM(), IS_INTEGER, e));
02393 kids.push_back(leExpr(tExpr[0], e));
02394 kids.push_back(leExpr(e, tExpr[1]));
02395 return andExpr(kids);
02396 }
02397 default:
02398 return e.getEM()->trueExpr();
02399 }
02400 }
02401
02402 void TheoryArith::computeType(const Expr& e)
02403 {
02404 switch (e.getKind()) {
02405 case RATIONAL_EXPR:
02406 if(e.getRational().isInteger())
02407 e.setType(d_intType);
02408 else
02409 e.setType(d_realType);
02410 break;
02411 case UMINUS:
02412 case PLUS:
02413 case MINUS:
02414 case MULT:
02415 case POW: {
02416 bool isInt = true;
02417 for(int k = 0; k < e.arity(); ++k) {
02418 if(d_realType != getBaseType(e[k]))
02419
02420 throw TypecheckException("Type Checking error: \n"+ e.toString());
02421 if(isInt && !isInteger(e[k]))
02422 isInt = false;
02423 }
02424 if(isInt)
02425 e.setType(d_intType);
02426 else
02427 e.setType(d_realType);
02428 break;
02429 }
02430 case DIVIDE: {
02431 Expr numerator = e[0];
02432 Expr denominator = e[1];
02433 if(denominator.isRational() && 1 == denominator.getRational())
02434 e.setType(getType(numerator));
02435 e.setType(d_realType);
02436 break;
02437 }
02438 case LT:
02439 case LE:
02440 case GT:
02441 case GE:
02442 case GRAY_SHADOW:
02443 e.setType(boolType());
02444 break;
02445 case DARK_SHADOW:
02446 for (int k = 0; k < e.arity(); ++k) {
02447 if (d_realType != getBaseType(e[k]))
02448
02449 throw TypecheckException("Type Checking error: \n"+ e.toString());
02450 }
02451 e.setType(boolType());
02452 break;
02453 case IS_INTEGER:
02454 if(d_realType != getBaseType(e[0]))
02455 throw TypecheckException("Expected type REAL, but got "
02456 +getBaseType(e[0]).toString()
02457 +"\n\nExpr = "+e.toString());
02458 e.setType(boolType());
02459 break;
02460 default:
02461 DebugAssert(false,"TheoryArith::computeType: unexpected expression:\n "
02462 +e.toString());
02463 break;
02464 }
02465 }
02466
02467
02468 Type TheoryArith::computeBaseType(const Type& t) {
02469 IF_DEBUG(int kind = t.getExpr().getKind());
02470 DebugAssert(kind==INT || kind==REAL || kind==SUBRANGE,
02471 "TheoryArith::computeBaseType("+t.toString()+")");
02472 return realType();
02473 }
02474
02475
02476 Expr
02477 TheoryArith::computeTCC(const Expr& e) {
02478 Expr tcc(Theory::computeTCC(e));
02479 switch(e.getKind()) {
02480 case DIVIDE:
02481 DebugAssert(e.arity() == 2, "");
02482 return tcc.andExpr(!(e[1].eqExpr(rat(0))));
02483 default:
02484 return tcc;
02485 }
02486 }
02487
02488
02489
02490
02491
02492 Expr
02493 TheoryArith::parseExprOp(const Expr& e) {
02494 TRACE("parser", "TheoryArith::parseExprOp(", e, ")");
02495
02496
02497
02498 switch(e.getKind()) {
02499 case ID: {
02500 int kind = getEM()->getKind(e[0].getString());
02501 switch(kind) {
02502 case NULL_KIND: return e;
02503 case REAL:
02504 case INT:
02505 case NEGINF:
02506 case POSINF: return newExpr(getEM(), kind);
02507 default:
02508 DebugAssert(false, "Bad use of bare keyword: "+e.toString());
02509 return e;
02510 }
02511 }
02512 case RAW_LIST: break;
02513 default:
02514 return e;
02515 }
02516
02517 DebugAssert(e.getKind() == RAW_LIST && e.arity() > 0,
02518 "TheoryArith::parseExprOp:\n e = "+e.toString());
02519
02520 const Expr& c1 = e[0][0];
02521 int kind = getEM()->getKind(c1.getString());
02522 switch(kind) {
02523 case UMINUS: {
02524 if(e.arity() != 2)
02525 throw ParserException("UMINUS requires exactly one argument: "
02526 +e.toString());
02527 return uminusExpr(parseExpr(e[1]));
02528 }
02529 case PLUS: {
02530 vector<Expr> k;
02531 Expr::iterator i = e.begin(), iend=e.end();
02532
02533
02534 ++i;
02535
02536 for(; i!=iend; ++i) k.push_back(parseExpr(*i));
02537 return plusExpr(k);
02538 }
02539 case MINUS: {
02540 if(e.arity() == 2)
02541 return uminusExpr(parseExpr(e[1]));
02542 else if(e.arity() == 3)
02543 return minusExpr(parseExpr(e[1]), parseExpr(e[2]));
02544 else
02545 throw ParserException("MINUS requires one or two arguments:"
02546 +e.toString());
02547 }
02548 case MULT: {
02549 vector<Expr> k;
02550 Expr::iterator i = e.begin(), iend=e.end();
02551
02552
02553 ++i;
02554
02555 for(; i!=iend; ++i) k.push_back(parseExpr(*i));
02556 return multExpr(k);
02557 }
02558 case POW: {
02559 return powExpr(parseExpr(e[1]), parseExpr(e[2]));
02560 }
02561 case DIVIDE:
02562 { return divideExpr(parseExpr(e[1]), parseExpr(e[2])); }
02563 case LT:
02564 { return ltExpr(parseExpr(e[1]), parseExpr(e[2])); }
02565 case LE:
02566 { return leExpr(parseExpr(e[1]), parseExpr(e[2])); }
02567 case GT:
02568 { return gtExpr(parseExpr(e[1]), parseExpr(e[2])); }
02569 case GE:
02570 { return geExpr(parseExpr(e[1]), parseExpr(e[2])); }
02571 case INTDIV:
02572 case MOD:
02573 case SUBRANGE: {
02574 vector<Expr> k;
02575 Expr::iterator i = e.begin(), iend=e.end();
02576
02577
02578 ++i;
02579
02580 for(; i!=iend; ++i)
02581 k.push_back(parseExpr(*i));
02582 return newExpr(e.getEM(), kind, k);
02583 break;
02584 }
02585 default:
02586 DebugAssert(false,
02587 "TheoryArith::parseExprOp: invalid input " + e.toString());
02588 break;
02589 }
02590 return e;
02591 }
02592
02593
02594
02595
02596
02597
02598 bool TheoryArith::isSyntacticRational(const Expr& e)
02599 {
02600 return e.isRational() ||
02601 (isUMinus(e) && !isUMinus(e[0]) && isSyntacticRational(e[0])) ||
02602 (isDivide(e) && (e[0].isRational() ||
02603 (isUMinus(e[0]) && e[0][0].isRational()))
02604 && e[1].isRational());
02605 }
02606
02607
02608 bool TheoryArith::isSyntacticUMinusVar(const Expr& e, Expr& var)
02609 {
02610 if (isUMinus(e)) {
02611 if (e[0].isVar()) {
02612 var = e[0];
02613 return true;
02614 }
02615 }
02616 else if (isMult(e)) {
02617 Expr coeff;
02618 if (e[0].isVar()) {
02619 var = e[0];
02620 coeff = e[1];
02621 }
02622 else if (e[1].isVar()) {
02623 var = e[1];
02624 coeff = e[0];
02625 }
02626 else return false;
02627 if (coeff.isRational() && coeff.getRational() == -1) {
02628 return true;
02629 }
02630 else if (isUMinus(coeff) && coeff[0].isRational() &&
02631 coeff[0].getRational() == 1) {
02632 return true;
02633 }
02634 }
02635 return false;
02636 }
02637
02638
02639 ExprStream&
02640 TheoryArith::print(ExprStream& os, const Expr& e) {
02641 switch(os.lang()) {
02642 case PRESENTATION_LANG:
02643 switch(e.getKind()) {
02644 case RATIONAL_EXPR:
02645 e.print(os);
02646 break;
02647 case SUBRANGE:
02648 if(e.arity() != 2) e.print(os);
02649 else
02650 os << "[" << push << e[0] << ".." << e[1] << push << "]";
02651 break;
02652 case IS_INTEGER:
02653 if(e.arity() == 1)
02654 os << "IS_INTEGER(" << push << e[0] << push << ")";
02655 else
02656 e.print(os);
02657 break;
02658 case PLUS: {
02659 int i=0, iend=e.arity();
02660 os << "(" << push;
02661 if(i!=iend) os << e[i];
02662 ++i;
02663 for(; i!=iend; ++i) os << space << "+ " << e[i];
02664 os << push << ")";
02665 break;
02666 }
02667 case MINUS:
02668 os << "(" << push << e[0] << space << "- " << e[1] << push << ")";
02669 break;
02670 case UMINUS:
02671 os << "-(" << push << e[0] << push << ")";
02672 break;
02673 case MULT: {
02674 int i=0, iend=e.arity();
02675 os << "(" << push;
02676 if(i!=iend) os << e[i];
02677 ++i;
02678 for(; i!=iend; ++i) os << space << "* " << e[i];
02679 os << push << ")";
02680 break;
02681 }
02682 case POW:
02683 os << "(" << push << e[1] << space << "^ " << e[0] << push << ")";
02684 break;
02685 case DIVIDE:
02686 os << "(" << push << e[0] << space << "/ " << e[1] << push << ")";
02687 break;
02688 case LT:
02689 if (isInt(getType(e[0])) || isInt(getType(e[1]))) {
02690 }
02691 os << "(" << push << e[0] << space << "< " << e[1] << push << ")";
02692 break;
02693 case LE:
02694 os << "(" << push << e[0] << space << "<= " << e[1] << push << ")";
02695 break;
02696 case GT:
02697 os << "(" << push << e[0] << space << "> " << e[1] << push << ")";
02698 break;
02699 case GE:
02700 os << "(" << push << e[0] << space << ">= " << e[1] << push << ")";
02701 break;
02702 case DARK_SHADOW:
02703 os << "DARK_SHADOW(" << push << e[0] << space << ", " << e[1] << push << ")";
02704 break;
02705 case GRAY_SHADOW:
02706 os << "GRAY_SHADOW(" << push << getV(e) << "," << space << getE(e)
02707 << "," << space << getC1(e) << "," << space << getC2(e)
02708 << push << ")";
02709 break;
02710 default:
02711
02712
02713 e.print(os);
02714
02715 break;
02716 }
02717 break;
02718 case SMTLIB_LANG: {
02719 Expr parent = os.getParent();
02720 switch(e.getKind()) {
02721 case RATIONAL_EXPR:
02722 e.print(os);
02723
02724 if ((e.getRational()).isInteger()) d_intConstUsed = true;
02725 else d_realUsed = true;
02726 if (parent.isNull() || (!parent.isEq() && !isIneq(parent))) {
02727 if (d_langUsed == NOT_USED) d_langUsed = TERMS_ONLY;
02728 break;
02729 }
02730 if (d_langUsed == NONLINEAR) break;
02731 else {
02732 Expr otherSide = parent[0];
02733 if (otherSide == e) otherSide = parent[1];
02734 if (isPlus(otherSide) || isMinus(otherSide))
02735 break;
02736 }
02737 d_langUsed = LINEAR;
02738 break;
02739 case REAL:
02740 if(d_vcl->getFlags()["real2int"].getBool()) {
02741 d_intUsed = true;
02742 os << "Int";
02743 }
02744 else {
02745 d_realUsed = true;
02746 os << "Real";
02747 }
02748 break;
02749 case INT:
02750 d_intUsed = true;
02751 os << "Int";
02752 break;
02753 case SUBRANGE:
02754 throw SmtlibException("TheoryArith::print: SMTLIB: SUBRANGE not implemented");
02755
02756
02757
02758
02759 break;
02760 case IS_INTEGER:
02761 d_intUsed = true;
02762 if(e.arity() == 1)
02763 os << "(" << push << "IsInt" << space << e[0] << push << ")";
02764 else
02765 throw SmtlibException("TheoryArith::print: SMTLIB: IS_INTEGER used unexpectedly");
02766 break;
02767 case PLUS: {
02768 int i=0, iend=e.arity();
02769 bool diff = false;
02770 Expr var;
02771
02772 if (iend == 2 && e[0].isVar() && isSyntacticUMinusVar(e[1], var)) {
02773 os << "(" << push << "-" << space << e[0]
02774 << space << var << push << ")";
02775 diff = true;
02776 }
02777 else if (iend == 2 && e[1].isVar() && isSyntacticUMinusVar(e[0], var)) {
02778 os << "(" << push << "-" << space << e[1]
02779 << space << var << push << ")";
02780 diff = true;;
02781 }
02782 else {
02783 for(; i!=iend; ++i) {
02784 if (i < iend-1) {
02785 os << "(" << push << "+";
02786 }
02787 os << space << e[i];
02788 }
02789 for (i=0; i < iend-1; ++i) os << push << ")";
02790 }
02791
02792 if (parent.isNull() || (!parent.isEq() && !isIneq(parent))) {
02793 if (d_langUsed == NOT_USED) d_langUsed = TERMS_ONLY;
02794 break;
02795 }
02796 if (d_langUsed >= LINEAR) break;
02797 else if (diff) {
02798 Expr otherSide = parent[0];
02799 if (otherSide == e) otherSide = parent[1];
02800 if (isSyntacticRational(otherSide)) {
02801 d_langUsed = DIFF_ONLY;
02802 break;
02803 }
02804 }
02805 d_langUsed = LINEAR;
02806 break;
02807 }
02808 case MINUS: {
02809 os << "(" << push << "- " << e[0] << space << e[1] << push << ")";
02810
02811 if (parent.isNull() || (!parent.isEq() && !isIneq(parent))) {
02812 if (d_langUsed == NOT_USED) d_langUsed = TERMS_ONLY;
02813 break;
02814 }
02815 if (d_langUsed >= LINEAR) break;
02816 else if (e[0].isVar() && e[1].isVar()) {
02817 Expr otherSide = parent[0];
02818 if (otherSide == e) otherSide = parent[1];
02819 if (isSyntacticRational(otherSide)) {
02820 d_langUsed = DIFF_ONLY;
02821 break;
02822 }
02823 }
02824 d_langUsed = LINEAR;
02825 break;
02826 }
02827 case UMINUS:
02828 os << "(" << push << "~" << space << e[0] << push << ")";
02829 if (parent.isNull() || (!parent.isEq() && !isIneq(parent))) {
02830 if (d_langUsed == NOT_USED) d_langUsed = TERMS_ONLY;
02831 break;
02832 }
02833 if (d_langUsed >= LINEAR) break;
02834 d_langUsed = LINEAR;
02835 break;
02836 case MULT: {
02837 int i=0, iend=e.arity();
02838 for(; i!=iend; ++i) {
02839 if (i < iend-1) {
02840 os << "(" << push << "*";
02841 }
02842 os << space << e[i];
02843 }
02844 for (i=0; i < iend-1; ++i) os << push << ")";
02845
02846 if (parent.isNull() || (!parent.isEq() && !isIneq(parent))) {
02847 if (d_langUsed == NOT_USED) d_langUsed = TERMS_ONLY;
02848 break;
02849 }
02850 if (d_langUsed == NONLINEAR) break;
02851 d_langUsed = LINEAR;
02852 bool nonconst = false;
02853 for (i=0; i!=iend; ++i) {
02854 if (isSyntacticRational(e[i])) {
02855 continue;
02856 }
02857 if (nonconst) {
02858 d_langUsed = NONLINEAR;
02859 break;
02860 }
02861 nonconst = true;
02862 }
02863 break;
02864 }
02865 case POW:
02866 throw SmtlibException("TheoryArith::print: SMTLIB: POW not supported");
02867 os << "(" << push << "^ " << e[1] << space << e[0] << push << ")";
02868 break;
02869 case DIVIDE:
02870 if (isSyntacticRational(e) && e[1].getRational() != 0) {
02871 os << "(" << push << "/ " << e[0] << space << e[1] << push << ")";
02872
02873 if (e[1].getRational() == 1) d_intConstUsed = true;
02874 else d_realUsed = true;
02875 if (parent.isNull() || (!parent.isEq() && !isIneq(parent))) {
02876 if (d_langUsed == NOT_USED) d_langUsed = TERMS_ONLY;
02877 break;
02878 }
02879 if (d_langUsed == NONLINEAR) break;
02880 else {
02881 Expr otherSide = parent[0];
02882 if (otherSide == e) otherSide = parent[1];
02883 if (isPlus(otherSide) || isMinus(otherSide))
02884 break;
02885 }
02886 d_langUsed = LINEAR;
02887 }
02888 else {
02889 throw SmtlibException("TheoryArith::print: SMTLIB: unexpected use of DIVIDE");
02890 }
02891 break;
02892 case LT:
02893 os << "(" << push << "< " << e[0] << space << e[1] << push << ")";
02894 if (d_langUsed >= DIFF_ONLY) break;
02895 d_langUsed = DIFF_ONLY;
02896 break;
02897 case LE:
02898 os << "(" << push << "<= " << e[0] << space << e[1] << push << ")";
02899 if (d_langUsed >= DIFF_ONLY) break;
02900 d_langUsed = DIFF_ONLY;
02901 break;
02902 case GT:
02903 os << "(" << push << "> " << e[1] << space << e[0] << push << ")";
02904 if (d_langUsed >= DIFF_ONLY) break;
02905 d_langUsed = DIFF_ONLY;
02906 break;
02907 case GE:
02908 os << "(" << push << ">= " << e[0] << space << e[1] << push << ")";
02909 if (d_langUsed >= DIFF_ONLY) break;
02910 d_langUsed = DIFF_ONLY;
02911 break;
02912 case DARK_SHADOW:
02913 throw SmtlibException("TheoryArith::print: SMTLIB: DARK_SHADOW not supported");
02914 os << "(" << push << "DARK_SHADOW" << space << e[0]
02915 << space << e[1] << push << ")";
02916 break;
02917 case GRAY_SHADOW:
02918 throw SmtlibException("TheoryArith::print: SMTLIB: GRAY_SHADOW not supported");
02919 os << "GRAY_SHADOW(" << push << getV(e) << "," << space << getE(e)
02920 << "," << space << getC1(e) << "," << space << getC2(e)
02921 << push << ")";
02922 break;
02923 default:
02924 throw SmtlibException("TheoryArith::print: SMTLIB: default not supported");
02925
02926
02927 e.print(os);
02928
02929 break;
02930 }
02931 break;
02932 }
02933 case LISP_LANG:
02934 switch(e.getKind()) {
02935 case RATIONAL_EXPR:
02936 e.print(os);
02937 break;
02938 case SUBRANGE:
02939 if(e.arity() != 2) e.print(os);
02940 else
02941 os << "(" << push << "SUBRANGE" << space << e[0]
02942 << space << e[1] << push << ")";
02943 break;
02944 case IS_INTEGER:
02945 if(e.arity() == 1)
02946 os << "(" << push << "IS_INTEGER" << space << e[0] << push << ")";
02947 else
02948 e.print(os);
02949 break;
02950 case PLUS: {
02951 int i=0, iend=e.arity();
02952 os << "(" << push << "+";
02953 for(; i!=iend; ++i) os << space << e[i];
02954 os << push << ")";
02955 break;
02956 }
02957 case MINUS:
02958
02959 os << "(" << push << "- " << e[0] << space << e[1] << push << ")";
02960 break;
02961 case UMINUS:
02962 os << "(" << push << "-" << space << e[0] << push << ")";
02963 break;
02964 case MULT: {
02965 int i=0, iend=e.arity();
02966 os << "(" << push << "*";
02967 for(; i!=iend; ++i) os << space << e[i];
02968 os << push << ")";
02969 break;
02970 }
02971 case POW:
02972 os << "(" << push << "^ " << e[1] << space << e[0] << push << ")";
02973 break;
02974 case DIVIDE:
02975 os << "(" << push << "/ " << e[0] << space << e[1] << push << ")";
02976 break;
02977 case LT:
02978 os << "(" << push << "< " << e[0] << space << e[1] << push << ")";
02979 break;
02980 case LE:
02981 os << "(" << push << "<= " << e[0] << space << e[1] << push << ")";
02982 break;
02983 case GT:
02984 os << "(" << push << "> " << e[1] << space << e[0] << push << ")";
02985 break;
02986 case GE:
02987 os << "(" << push << ">= " << e[0] << space << e[1] << push << ")";
02988 break;
02989 case DARK_SHADOW:
02990 os << "(" << push << "DARK_SHADOW" << space << e[0]
02991 << space << e[1] << push << ")";
02992 break;
02993 case GRAY_SHADOW:
02994 os << "(" << push << "GRAY_SHADOW" << space << getV(e) << space
02995 << getE(e) << space << getC1(e) << space << getC2(e)
02996 << push << ")";
02997 break;
02998 default:
02999
03000
03001 e.print(os);
03002
03003 break;
03004 }
03005 break;
03006 default:
03007
03008
03009 e.print(os);
03010 }
03011 return os;
03012 }
03013
03014
03015
03016 Expr TheoryArith::grayShadow(const Expr& v, const Expr& e,
03017 const Rational& c1, const Rational& c2) {
03018 ExprGrayShadow ev(getEM(), v, e, c1, c2, d_grayShadowMMIndex);
03019 return newExpr(&ev);
03020 }
03021
03022
03023
03024 const Rational& TheoryArith::getC1(const Expr& e) {
03025 DebugAssert(isGrayShadow(e),
03026 "TheoryArith::getC1("+e.toString()
03027 +"): not a gray shadow");
03028 return e.getRatValue(0);
03029 }
03030
03031
03032
03033 const Rational& TheoryArith::getC2(const Expr& e) {
03034 DebugAssert(isGrayShadow(e),
03035 "TheoryArith::getC2("+e.toString()
03036 +"): not a gray shadow");
03037 return e.getRatValue(1);
03038 }
03039
03040
03041
03042 const Expr& TheoryArith::getV(const Expr& e) {
03043 DebugAssert(isGrayShadow(e),
03044 "TheoryArith::getV("+e.toString()
03045 +"): not a gray shadow");
03046 return e.getExprValue(0);
03047 }
03048
03049
03050 const Expr& TheoryArith::getE(const Expr& e) {
03051 DebugAssert(isGrayShadow(e),
03052 "TheoryArith::getE("+e.toString()
03053 +"): not a gray shadow");
03054 return e.getExprValue(1);
03055 }
03056