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