CVC3
|
00001 /*****************************************************************************/ 00002 /*! 00003 * \file theory_arith_old.cpp 00004 * 00005 * Author: Clark Barrett, Vijay Ganesh. 00006 * 00007 * Created: Fri Jan 17 18:39:18 2003 00008 * 00009 * <hr> 00010 * 00011 * License to use, copy, modify, sell and/or distribute this software 00012 * and its documentation for any purpose is hereby granted without 00013 * royalty, subject to the terms and conditions defined in the \ref 00014 * LICENSE file provided with this distribution. 00015 * 00016 * <hr> 00017 * 00018 */ 00019 /*****************************************************************************/ 00020 00021 00022 #include "theory_arith_old.h" 00023 #include "arith_proof_rules.h" 00024 //#include "arith_expr.h" 00025 #include "arith_exception.h" 00026 #include "typecheck_exception.h" 00027 #include "eval_exception.h" 00028 #include "parser_exception.h" 00029 #include "smtlib_exception.h" 00030 #include "theory_core.h" 00031 #include "command_line_flags.h" 00032 //TODO: remove this dependency 00033 #include "../theory_core/core_proof_rules.h" 00034 00035 00036 using namespace std; 00037 using namespace CVC3; 00038 00039 00040 /////////////////////////////////////////////////////////////////////////////// 00041 // TheoryArithOld::FreeConst Methods // 00042 /////////////////////////////////////////////////////////////////////////////// 00043 00044 namespace CVC3 { 00045 00046 ostream& operator<<(ostream& os, const TheoryArithOld::FreeConst& fc) { 00047 os << "FreeConst(r=" << fc.getConst() << ", " 00048 << (fc.strict()? "strict" : "non-strict") << ")"; 00049 return os; 00050 } 00051 00052 /////////////////////////////////////////////////////////////////////////////// 00053 // TheoryArithOld::Ineq Methods // 00054 /////////////////////////////////////////////////////////////////////////////// 00055 00056 ostream& operator<<(ostream& os, const TheoryArithOld::Ineq& ineq) { 00057 os << "Ineq(" << ineq.ineq().getExpr() << ", isolated on " 00058 << (ineq.varOnRHS()? "RHS" : "LHS") << ", const = " 00059 << ineq.getConst() << ")"; 00060 return os; 00061 } 00062 } // End of namespace CVC3 00063 00064 00065 /////////////////////////////////////////////////////////////////////////////// 00066 // TheoryArithOld Private Methods // 00067 /////////////////////////////////////////////////////////////////////////////// 00068 00069 00070 Theorem TheoryArithOld::isIntegerThm(const Expr& e) { 00071 // Quick checks 00072 Type t = e.getType(); 00073 if (isReal(t)) return Theorem(); 00074 if (isInt(t)) return typePred(e); 00075 00076 // Try harder 00077 return isIntegerDerive(Expr(IS_INTEGER, e), typePred(e)); 00078 } 00079 00080 00081 Theorem TheoryArithOld::isIntegerDerive(const Expr& isIntE, const Theorem& thm) { 00082 const Expr& e = thm.getExpr(); 00083 // We found it! 00084 if(e == isIntE) return thm; 00085 00086 Theorem res; 00087 // If the theorem is an AND, look inside each child 00088 if(e.isAnd()) { 00089 int i, iend=e.arity(); 00090 for(i=0; i<iend; ++i) { 00091 res = isIntegerDerive(isIntE, getCommonRules()->andElim(thm, i)); 00092 if(!res.isNull()) return res; 00093 } 00094 } 00095 return res; 00096 } 00097 00098 const Rational& TheoryArithOld::freeConstIneq(const Expr& ineq, bool varOnRHS) { 00099 DebugAssert(isIneq(ineq), "TheoryArithOld::freeConstIneq("+ineq.toString()+")"); 00100 const Expr& e = varOnRHS? ineq[0] : ineq[1]; 00101 00102 switch(e.getKind()) { 00103 case PLUS: 00104 return e[0].getRational(); 00105 case RATIONAL_EXPR: 00106 return e.getRational(); 00107 default: { // MULT, DIV, or Variable 00108 static Rational zero(0); 00109 return zero; 00110 } 00111 } 00112 } 00113 00114 00115 const TheoryArithOld::FreeConst& 00116 TheoryArithOld::updateSubsumptionDB(const Expr& ineq, bool varOnRHS, 00117 bool& subsumed) { 00118 TRACE("arith ineq", "TheoryArithOld::updateSubsumptionDB(", ineq, 00119 ", var isolated on "+string(varOnRHS? "RHS" : "LHS")+")"); 00120 DebugAssert(isLT(ineq) || isLE(ineq), "TheoryArithOld::updateSubsumptionDB(" 00121 +ineq.toString()+")"); 00122 // Indexing expression: same as ineq only without the free const 00123 Expr index; 00124 const Expr& t = varOnRHS? ineq[0] : ineq[1]; 00125 bool strict(isLT(ineq)); 00126 Rational c(0); 00127 if(isPlus(t)) { 00128 DebugAssert(t.arity() >= 2, "TheoryArithOld::updateSubsumptionDB(" 00129 +ineq.toString()+")"); 00130 c = t[0].getRational(); // Extract the free const in ineq 00131 Expr newT; 00132 if(t.arity() == 2) { 00133 newT = t[1]; 00134 } else { 00135 vector<Expr> kids; 00136 Expr::iterator i=t.begin(), iend=t.end(); 00137 kids.push_back(rat(0)); 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(rat(0), canonSimplify(ineq[1] - newT).getRHS()); 00145 else 00146 index = leExpr(canonSimplify(ineq[0]-newT).getRHS(), rat(0)); 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 // Now update the database, check for subsumption, and extract the constant 00158 CDMap<Expr, FreeConst>::iterator i=d_freeConstDB.find(index), 00159 iend=d_freeConstDB.end(); 00160 if(i == iend) { 00161 subsumed = false; 00162 // Create a new entry 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 TheoryArithOld::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 // Function: TheoryArithOld::canon // 00202 // Author: Clark Barrett, Vijay Ganesh. // 00203 // Created: Sat Feb 8 14:46:32 2003 // 00204 // Description: Compute a canonical form for expression e and return a // 00205 // theorem that e is equal to its canonical form. // 00206 // Note that canonical form for arith expressions is one of the following: // 00207 // 1. rational constant // 00208 // 2. arithmetic leaf // 00209 // (i.e. variable or term from some other theory) // 00210 // 3. (MULT rat leaf) // 00211 // where rat is a non-zero rational constant, leaf is an arithmetic leaf // 00212 // 4. (PLUS const term_0 term_1 ... term_n) // 00213 // where each term_i is either a leaf or (MULT rat leaf) // 00214 // and each leaf in term_i must be strictly greater than the leaf in // 00215 // term_{i+1}. // 00216 // // 00217 /////////////////////////////////////////////////////////////////////////////// 00218 Theorem TheoryArithOld::canon(const Expr& e) 00219 { 00220 TRACE("arith canon","canon(",e,") {"); 00221 DebugAssert(kidsCanonical(e), "TheoryArithOld::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 Theorem plusThm, plusThm1; 00232 plusThm = d_rules->canonFlattenSum(e); 00233 plusThm1 = d_rules->canonComboLikeTerms(plusThm.getRHS()); 00234 result = transitivityRule(plusThm,plusThm1); 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 // this produces e0 + (-1)*e1; we have to canonize it in 2 steps 00243 Expr sum(minus_eq_sum.getRHS()); 00244 Theorem thm(canon(sum[1])); 00245 if(thm.getLHS() == thm.getRHS()) 00246 result = canonThm(minus_eq_sum); 00247 // The sum changed; do the work 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 = canonThm(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 case MULT: { 00264 Theorem thmMult, thmMult1; 00265 Expr exprMult; 00266 Expr e0 = e[0]; 00267 Expr e1 = e[1]; 00268 if(e0.isRational()) { 00269 if(rat(0) == e0) 00270 result = d_rules->canonMultZero(e1); 00271 else if (rat(1) == e0) 00272 result = d_rules->canonMultOne(e1); 00273 else 00274 switch(e1.getKind()) { 00275 case RATIONAL_EXPR : 00276 result = d_rules->canonMultConstConst(e0,e1); 00277 break; 00278 case MULT: 00279 DebugAssert(e1[0].isRational(), 00280 "theory_arith::canon:\n " 00281 "canon:MULT:MULT child is not canonical: " 00282 + e1[0].toString()); 00283 00284 thmMult = d_rules->canonMultConstTerm(e0,e1[0],e1[1]); 00285 result = transitivityRule(thmMult,canon(thmMult.getRHS())); 00286 break; 00287 case PLUS:{ 00288 Theorem thmPlus, thmPlus1; 00289 Expr ePlus; 00290 std::vector<Theorem> thmPlusVector; 00291 thmPlus = d_rules->canonMultConstSum(e0,e1); 00292 ePlus = thmPlus.getRHS(); 00293 Expr::iterator i = ePlus.begin(); 00294 for(;i != ePlus.end();++i) 00295 thmPlusVector.push_back(canon(*i)); 00296 thmPlus1 = substitutivityRule(PLUS, thmPlusVector); 00297 result = transitivityRule(thmPlus, thmPlus1); 00298 break; 00299 } 00300 default: 00301 result = reflexivityRule(e); 00302 break; 00303 } 00304 } 00305 else { 00306 if(e1.isRational()){ 00307 00308 // canonMultTermConst just reverses the order of the const and the 00309 // term. Then canon is called again. 00310 Theorem t1 = d_rules->canonMultTermConst(e1,e0); 00311 result = transitivityRule(t1,canon(t1.getRHS())); 00312 } 00313 else 00314 00315 // This is where the assertion for non-linear multiplication is 00316 // produced. 00317 result = d_rules->canonMultTerm1Term2(e0,e1); 00318 } 00319 break; 00320 } 00321 00322 */ 00323 case DIVIDE:{ 00324 /* 00325 case DIVIDE:{ 00326 if (e[1].isRational()) { 00327 if (e[1].getRational() == 0) 00328 throw ArithException("Divide by 0 error in "+e.toString()); 00329 Theorem thm = d_rules->canonDivideVar(e[0], e[1]); 00330 Expr e2 = thm.getRHS(); 00331 result = transitivityRule(thm, canon(e2)); 00332 } 00333 else 00334 { 00335 // TODO: to be handled 00336 throw ArithException("Divide by a non-const not handled in "+e.toString()); 00337 } 00338 break; 00339 } 00340 */ 00341 00342 // Division by 0 is OK (total extension, protected by TCCs) 00343 // if (e[1].isRational() && e[1].getRational() == 0) 00344 // throw ArithException("Divide by 0 error in "+e.toString()); 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 // x ^ 1 --> x 00355 if (e[0].isRational() && e[0].getRational() == 1) { 00356 result = d_rules->powerOfOne(e); 00357 } else 00358 result = reflexivityRule(e); 00359 } 00360 break; 00361 default: 00362 result = reflexivityRule(e); 00363 break; 00364 } 00365 TRACE("arith canon","canon => ",result," }"); 00366 return result; 00367 } 00368 00369 00370 Theorem 00371 TheoryArithOld::canonSimplify(const Expr& e) { 00372 TRACE("arith simplify", "canonSimplify(", e, ") {"); 00373 DebugAssert(kidsCanonical(e), 00374 "TheoryArithOld::canonSimplify("+e.toString()+")"); 00375 DebugAssert(leavesAreSimp(e), "Expected leaves to be simplified"); 00376 Expr tmp(e); 00377 Theorem thm = canon(e); 00378 if(thm.getRHS().hasFind()) 00379 thm = transitivityRule(thm, find(thm.getRHS())); 00380 // We shouldn't rely on simplification in this function anymore 00381 DebugAssert(thm.getRHS() == simplifyExpr(thm.getRHS()), 00382 "canonSimplify("+e.toString()+")\n" 00383 +"canon(e) = "+thm.getRHS().toString() 00384 +"\nsimplify(canon(e)) = "+simplifyExpr(thm.getRHS()).toString()); 00385 // if(tmp != thm.getRHS()) 00386 // thm = transitivityRule(thm, simplifyThm(thm.getRHS())); 00387 // while(tmp != thm.getRHS()) { 00388 // tmp = thm.getRHS(); 00389 // thm = canon(thm); 00390 // if(tmp != thm.getRHS()) 00391 // thm = transitivityRule(thm, simplifyThm(thm.getRHS())); 00392 // } 00393 TRACE("arith", "canonSimplify =>", thm, " }"); 00394 return thm; 00395 } 00396 00397 /*! accepts a theorem, canonizes it, applies iffMP and substituvity to 00398 * derive the canonized thm 00399 */ 00400 Theorem 00401 TheoryArithOld::canonPred(const Theorem& thm) { 00402 vector<Theorem> thms; 00403 DebugAssert(thm.getExpr().arity() == 2, 00404 "TheoryArithOld::canonPred: bad theorem: "+thm.toString()); 00405 Expr e(thm.getExpr()); 00406 thms.push_back(canonSimplify(e[0])); 00407 thms.push_back(canonSimplify(e[1])); 00408 Theorem result = iffMP(thm, substitutivityRule(e.getOp(), thms)); 00409 00410 return result; 00411 } 00412 00413 /*! accepts an equivalence theorem, canonizes it, applies iffMP and 00414 * substituvity to derive the canonized thm 00415 */ 00416 Theorem 00417 TheoryArithOld::canonPredEquiv(const Theorem& thm) { 00418 vector<Theorem> thms; 00419 DebugAssert(thm.getRHS().arity() == 2, 00420 "TheoryArithOld::canonPredEquiv: bad theorem: "+thm.toString()); 00421 Expr e(thm.getRHS()); 00422 thms.push_back(canonSimplify(e[0])); 00423 thms.push_back(canonSimplify(e[1])); 00424 Theorem result = transitivityRule(thm, substitutivityRule(e.getOp(), thms)); 00425 00426 return result; 00427 } 00428 00429 /*! accepts an equivalence theorem whose RHS is a conjunction, 00430 * canonizes it, applies iffMP and substituvity to derive the 00431 * canonized thm 00432 */ 00433 Theorem 00434 TheoryArithOld::canonConjunctionEquiv(const Theorem& thm) { 00435 vector<Theorem> thms; 00436 return thm; 00437 } 00438 00439 /*! Pseudo-code for doSolve. (Input is an equation) (output is a Theorem) 00440 * -# translate e to the form e' = 0 00441 * -# if (e'.isRational()) then {if e' != 0 return false else true} 00442 * -# a for loop checks if all the variables are integers. 00443 * - if not isolate a suitable real variable and call processRealEq(). 00444 * - if all variables are integers then isolate suitable variable 00445 * and call processIntEq(). 00446 */ 00447 Theorem TheoryArithOld::doSolve(const Theorem& thm) 00448 { 00449 const Expr& e = thm.getExpr(); 00450 if (e.isTrue() || e.isFalse()) return thm; 00451 TRACE("arith eq","doSolve(",e,") {"); 00452 DebugAssert(thm.isRewrite(), "thm = "+thm.toString()); 00453 Theorem eqnThm; 00454 vector<Theorem> thms; 00455 // Move LHS to the RHS, if necessary 00456 if(e[0].isRational() && e[0].getRational() == 0) 00457 eqnThm = thm; 00458 else { 00459 eqnThm = iffMP(thm, d_rules->rightMinusLeft(e)); 00460 eqnThm = canonPred(eqnThm); 00461 } 00462 // eqnThm is of the form 0 = e' 00463 // 'right' is of the form e' 00464 Expr right = eqnThm.getRHS(); 00465 // Check for trivial equation 00466 if (right.isRational()) { 00467 Theorem result = iffMP(eqnThm, d_rules->constPredicate(eqnThm.getExpr())); 00468 TRACE("arith eq","doSolve => ",result," }"); 00469 return result; 00470 } 00471 00472 //normalize 00473 eqnThm = iffMP(eqnThm, normalize(eqnThm.getExpr())); 00474 TRACE("arith eq","doSolve => ",eqnThm.getExpr()," }"); 00475 right = eqnThm.getRHS(); 00476 00477 //eqn is of the form 0 = e' and is normalized where 'right' denotes e' 00478 //FIXME: change processRealEq to accept equations as well instead of theorems 00479 00480 try { 00481 if (isMult(right)) { 00482 DebugAssert(right.arity() > 1, "Expected arity > 1"); 00483 if (right[0].isRational()) { 00484 Rational r = right[0].getRational(); 00485 if (r == 0) return getCommonRules()->trueTheorem(); 00486 else if (r == 1) { 00487 enqueueFact(iffMP(eqnThm, d_rules->multEqZero(eqnThm.getExpr()))); 00488 return getCommonRules()->trueTheorem(); 00489 } 00490 Theorem res = iffMP(eqnThm, 00491 d_rules->multEqn(eqnThm.getLHS(), 00492 right, rat(1/r))); 00493 res = canonPred(res); 00494 return doSolve(res); 00495 } 00496 else { 00497 enqueueFact(iffMP(eqnThm, d_rules->multEqZero(eqnThm.getExpr()))); 00498 return getCommonRules()->trueTheorem(); 00499 } 00500 } 00501 else if (isPow(right)) { 00502 DebugAssert(right.arity() == 2, "Expected arity 2"); 00503 if (right[0].isRational()) { 00504 return doSolve(iffMP(eqnThm, d_rules->powEqZero(eqnThm.getExpr()))); 00505 } 00506 throw ArithException("Can't solve exponential eqn: "+eqnThm.toString()); 00507 } 00508 else { 00509 if(!isInteger(right)) { 00510 return processRealEq(eqnThm); 00511 } 00512 else { 00513 return processIntEq(eqnThm); 00514 } 00515 } 00516 } catch(ArithException& e) { 00517 FatalAssert(false, "We should never get here!!! : " + e.toString()); 00518 00519 // // Nonlinear bail out 00520 // Theorem res; 00521 // if (isPlus(right)) { 00522 // // Solve for something 00523 // // Try to simulate groebner basis by picking the highest term 00524 // Expr isolated = right[1]; 00525 // int isolated_degree = termDegree(isolated); 00526 // for (int i = 2; i < right.arity(); i ++) { 00527 // int degree = termDegree(right[i]); 00528 // if (degree > isolated_degree) { 00529 // isolated = right[i]; 00530 // isolated_degree = degree; 00531 // } 00532 // } 00533 // Rational coeff; 00534 // if (isMult(isolated) && isolated[0].isRational()) { 00535 // coeff = isolated[0].getRational(); 00536 // DebugAssert(coeff != 0, "Expected nonzero coeff"); 00537 // isolated = canon(isolated / rat(coeff)).getRHS(); 00538 // } else coeff = 1; 00539 // res = iffMP(eqnThm, d_rules->multEqn(rat(0), right, rat(-1/coeff))); 00540 // res = canonPred(res); 00541 // res = iffMP(res, d_rules->plusPredicate(res.getLHS(), res.getRHS(), isolated, EQ)); 00542 // res = canonPred(res); 00543 // TRACE("arith nonlinear", "solved for: ", res.getExpr(), ""); 00544 // } else 00545 // res = symmetryRule(eqnThm); // Flip to e' = 0 00546 // TRACE("arith eq", "doSolve: failed to solve an equation: ", e, ""); 00547 // IF_DEBUG(debugger.counter("FAILED to solve equalities")++;) 00548 // setIncomplete("Non-linear arithmetic equalities"); 00549 // 00550 // // Since we are forgetting about this equation, setup for updates 00551 // TRACE("arith nonlinear", "adding setup to ", eqnThm.getExpr(), ""); 00552 // setupRec(eqnThm.getExpr()); 00553 // return getCommonRules()->trueTheorem(); 00554 } 00555 FatalAssert(false, ""); 00556 return Theorem(); 00557 } 00558 00559 /*! pick a monomial for the input equation. This function is used only 00560 * if the equation is an integer equation. Choose the monomial with 00561 * the smallest absolute value of coefficient. 00562 */ 00563 bool TheoryArithOld::pickIntEqMonomial(const Expr& right, Expr& isolated, bool& nonlin) 00564 { 00565 DebugAssert(isPlus(right) && right.arity() > 1, 00566 "TheoryArithOld::pickIntEqMonomial right is wrong :-): " + 00567 right.toString()); 00568 DebugAssert(right[0].isRational(), 00569 "TheoryArithOld::pickIntEqMonomial. right[0] must be const" + 00570 right.toString()); 00571 // DebugAssert(isInteger(right), 00572 // "TheoryArithOld::pickIntEqMonomial: right is of type int: " + 00573 // right.toString()); 00574 //right is of the form "C + a1x1 + ... + anxn". min is initialized 00575 //to a1 00576 Expr::iterator istart = right.begin(), iend = right.end(); 00577 istart++; 00578 Expr::iterator i = istart, j; 00579 bool found = false; 00580 nonlin = false; 00581 Rational min, coeff; 00582 Expr leaf; 00583 for(; i != iend; ++i) { 00584 if (isLeaf(*i)) { 00585 leaf = *i; 00586 coeff = 1; 00587 } 00588 else if (isMult(*i) && (*i).arity() == 2 && (*i)[0].isRational() && isLeaf((*i)[1])) { 00589 leaf = (*i)[1]; 00590 coeff = abs((*i)[0].getRational()); 00591 } 00592 else { 00593 nonlin = true; 00594 continue; 00595 } 00596 for (j = istart; j != iend; ++j) { 00597 if (j != i && isLeafIn(leaf, *j)) break; 00598 } 00599 if (j == iend) { 00600 if (!found || min > coeff) { 00601 min = coeff; 00602 isolated = *i; 00603 found = true; 00604 } 00605 } 00606 } 00607 return found; 00608 } 00609 00610 /*! input is 0=e' Theorem and some of the vars in e' are of 00611 * type REAL. isolate one of them and send back to framework. output 00612 * is "var = e''" Theorem. 00613 */ 00614 Theorem 00615 TheoryArithOld::processRealEq(const Theorem& eqn) 00616 { 00617 DebugAssert(eqn.getLHS().isRational() && 00618 eqn.getLHS().getRational() == 0, 00619 "processRealEq invariant violated"); 00620 Expr right = eqn.getRHS(); 00621 // Find variable to isolate and store it in left. Pick the largest 00622 // (according to the total ordering) variable. FIXME: change from 00623 // total ordering to the ordering we devised for inequalities. 00624 00625 // TODO: I have to pick a variable that appears as a variable in the 00626 // term but does not appear as a variable anywhere else. The variable 00627 // must appear as a single leaf and not in a MULT expression with some 00628 // other variables and nor in a POW expression. 00629 00630 bool found = false; 00631 Expr left; 00632 00633 if (isPlus(right)) { 00634 DebugAssert(right[0].isRational(), "Expected first term to be rational"); 00635 for(int i = 1, iend = right.arity(); i < iend; ++i) { 00636 Expr c = right[i]; 00637 DebugAssert(!isRational(c), "Expected non-rational"); 00638 if(!isInteger(c)) { 00639 if (isLeaf(c) || 00640 ((isMult(c) && c.arity() == 2 && isLeaf(c[1])))) { 00641 Expr leaf = isLeaf(c) ? c : c[1]; 00642 int j; 00643 for (j = 1; j < iend; ++j) { 00644 if (j!= i 00645 && isLeafIn(leaf, right[j]) 00646 ) { 00647 break; 00648 } 00649 } 00650 if (j == iend) { 00651 left = c; 00652 found = true; 00653 break; 00654 } 00655 } 00656 } 00657 } 00658 } 00659 else if ((isMult(right) && right.arity() == 2 && isLeaf(right[1])) || 00660 isLeaf(right)) { 00661 left = right; 00662 found = true; 00663 } 00664 00665 if (!found) { 00666 // The only way we can not get an isolated in the reals is if all of them 00667 // are non-linear. In this case we might have some integers to solve for 00668 // so we try that. The integer solver shouldn't be able to solve for the 00669 // reals, as they are not solvable and we should be safe. One of such 00670 // examples is if some constant ITE got skolemized and we have an equation 00671 // like SKOLEM = x^2 (bug79), in which case we should solve for the SKOLEM 00672 // where skolem is an INT variable. 00673 if (isNonlinearEq(eqn.getExpr())) 00674 return processIntEq(eqn); 00675 else throw 00676 ArithException("Can't find a leaf for solve in "+eqn.toString()); 00677 } 00678 00679 Rational r = -1; 00680 if (isMult(left)) { 00681 DebugAssert(left.arity() == 2, "only leaf should be chosen as lhs"); 00682 DebugAssert(left[0].getRational() != 0, "left = "+left.toString()); 00683 r = -1/left[0].getRational(); 00684 left = left[1]; 00685 } 00686 00687 DebugAssert(isReal(getBaseType(left)) && !isInteger(left), 00688 "TheoryArithOld::ProcessRealEq: left is integer:\n left = " 00689 +left.toString()); 00690 // Normalize equation so that coefficient of the monomial 00691 // corresponding to "left" in eqn[1] is -1 00692 Theorem result(iffMP(eqn, 00693 d_rules->multEqn(eqn.getLHS(), eqn.getRHS(), rat(r)))); 00694 result = canonPred(result); 00695 00696 // Isolate left 00697 result = iffMP(result, d_rules->plusPredicate(result.getLHS(), 00698 result.getRHS(), left, EQ)); 00699 result = canonPred(result); 00700 TRACE("arith","processRealEq => ",result," }"); 00701 return result; 00702 } 00703 00704 00705 void TheoryArithOld::getFactors(const Expr& e, set<Expr>& factors) 00706 { 00707 switch (e.getKind()) { 00708 case RATIONAL_EXPR: break; 00709 case MULT: { 00710 Expr::iterator i = e.begin(), iend = e.end(); 00711 for (; i != iend; ++i) { 00712 getFactors(*i, factors); 00713 } 00714 break; 00715 } 00716 case POW: { 00717 DebugAssert(e.arity() == 2, "invariant violated"); 00718 if (!isIntegerConst(e[0]) || e[0].getRational() <= 0) { 00719 throw ArithException("not positive integer exponent in "+e.toString()); 00720 } 00721 if (isLeaf(e[1])) factors.insert(e[1]); 00722 break; 00723 } 00724 default: { 00725 DebugAssert(isLeaf(e), "expected leaf"); 00726 DebugAssert(factors.find(e) == factors.end(), "expected new entry"); 00727 factors.insert(e); 00728 break; 00729 } 00730 } 00731 } 00732 00733 00734 /*! 00735 * \param eqn is a single equation 0 = e 00736 * \return an equivalent Theorem (x = t AND 0 = e'), or just x = t 00737 */ 00738 Theorem 00739 TheoryArithOld::processSimpleIntEq(const Theorem& eqn) 00740 { 00741 TRACE("arith eq", "processSimpleIntEq(", eqn.getExpr(), ") {"); 00742 DebugAssert(eqn.isRewrite(), 00743 "TheoryArithOld::processSimpleIntEq: eqn must be equality" + 00744 eqn.getExpr().toString()); 00745 00746 Expr right = eqn.getRHS(); 00747 00748 DebugAssert(eqn.getLHS().isRational() && 0 == eqn.getLHS().getRational(), 00749 "TheoryArithOld::processSimpleIntEq: LHS must be 0:\n" + 00750 eqn.getExpr().toString()); 00751 00752 DebugAssert(!isMult(right) && !isPow(right), "should have been handled above"); 00753 if (isPlus(right)) { 00754 if (2 == right.arity() && 00755 (isLeaf(right[1]) || 00756 (isMult(right[1]) && right[1].arity() == 2 && right[1][0].isRational() && isLeaf(right[1][1])))) { 00757 //we take care of special cases like 0 = c + a.x, 0 = c + x, 00758 Expr c,x; 00759 separateMonomial(right[1], c, x); 00760 Theorem isIntx(isIntegerThm(x)); 00761 DebugAssert(!isIntx.isNull(), "right = "+right.toString() 00762 +"\n x = "+x.toString()); 00763 Theorem res(iffMP(eqn, d_rules->intVarEqnConst(eqn.getExpr(), isIntx))); 00764 TRACE("arith eq", "processSimpleIntEq[0 = c + a*x] => ", res, " }"); 00765 return res; 00766 } 00767 // Pick a suitable monomial. isolated can be of the form x, a.x, -a.x 00768 Expr isolated; 00769 bool nonlin; 00770 if (pickIntEqMonomial(right, isolated, nonlin)) { 00771 TRACE("arith eq", "processSimpleIntEq: isolated = ", isolated, ""); 00772 00773 // First, we compute the 'sign factor' with which to multiply the 00774 // eqn. if the coeff of isolated is positive (i.e. 'isolated' is 00775 // of the form x or a.x where a>0 ) then r must be -1 and if coeff 00776 // of 'isolated' is negative, r=1. 00777 Rational r = isMult(isolated) ? 00778 ((isolated[0].getRational() > 0) ? -1 : 1) : -1; 00779 Theorem result; 00780 if (-1 == r) { 00781 // r=-1 and hence 'isolated' is 'x' or 'a.x' where a is 00782 // positive. modify eqn (0=e') to the equation (0=canon(-1*e')) 00783 result = iffMP(eqn, d_rules->multEqn(eqn.getLHS(), right, rat(r))); 00784 result = canonPred(result); 00785 Expr e = result.getRHS(); 00786 00787 // Isolate the 'isolated' 00788 result = iffMP(result, 00789 d_rules->plusPredicate(result.getLHS(),result.getRHS(), 00790 isolated, EQ)); 00791 } else { 00792 //r is 1 and hence isolated is -a.x. Make 'isolated' positive. 00793 const Rational& minusa = isolated[0].getRational(); 00794 Rational a = -1*minusa; 00795 isolated = (a == 1)? isolated[1] : rat(a) * isolated[1]; 00796 00797 // Isolate the 'isolated' 00798 result = iffMP(eqn, d_rules->plusPredicate(eqn.getLHS(), 00799 right,isolated,EQ)); 00800 } 00801 // Canonize the result 00802 result = canonPred(result); 00803 00804 //if isolated is 'x' or 1*x, then return result else continue processing. 00805 if(!isMult(isolated) || isolated[0].getRational() == 1) { 00806 TRACE("arith eq", "processSimpleIntEq[x = rhs] => ", result, " }"); 00807 return result; 00808 } else if (!nonlin) { 00809 DebugAssert(isMult(isolated) && isolated[0].getRational() >= 2, 00810 "TheoryArithOld::processSimpleIntEq: isolated must be mult " 00811 "with coeff >= 2.\n isolated = " + isolated.toString()); 00812 00813 // Compute IS_INTEGER() for lhs and rhs 00814 Expr lhs = result.getLHS(); 00815 Expr rhs = result.getRHS(); 00816 Expr a, x; 00817 separateMonomial(lhs, a, x); 00818 Theorem isIntLHS = isIntegerThm(x); 00819 vector<Theorem> isIntRHS; 00820 if(!isPlus(rhs)) { // rhs is a MULT 00821 Expr c, v; 00822 separateMonomial(rhs, c, v); 00823 isIntRHS.push_back(isIntegerThm(v)); 00824 DebugAssert(!isIntRHS.back().isNull(), ""); 00825 } else { // rhs is a PLUS 00826 DebugAssert(isPlus(rhs), "rhs = "+rhs.toString()); 00827 DebugAssert(rhs.arity() >= 2, "rhs = "+rhs.toString()); 00828 Expr::iterator i=rhs.begin(), iend=rhs.end(); 00829 ++i; // Skip the free constant 00830 for(; i!=iend; ++i) { 00831 Expr c, v; 00832 separateMonomial(*i, c, v); 00833 isIntRHS.push_back(isIntegerThm(v)); 00834 DebugAssert(!isIntRHS.back().isNull(), ""); 00835 } 00836 } 00837 // Derive (EXISTS (x:INT): x = t2 AND 0 = t3) 00838 result = d_rules->eqElimIntRule(result, isIntLHS, isIntRHS); 00839 // Skolemize the quantifier 00840 result = getCommonRules()->skolemize(result); 00841 // Canonize t2 and t3 generated by this rule 00842 DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2, 00843 "processSimpleIntEq: result = "+result.getExpr().toString()); 00844 Theorem thm1 = canonPred(getCommonRules()->andElim(result, 0)); 00845 Theorem thm2 = canonPred(getCommonRules()->andElim(result, 1)); 00846 Theorem newRes = getCommonRules()->andIntro(thm1, thm2); 00847 if(newRes.getExpr() != result.getExpr()) result = newRes; 00848 00849 TRACE("arith eq", "processSimpleIntEq => ", result, " }"); 00850 return result; 00851 } 00852 } 00853 throw 00854 ArithException("Can't find a leaf for solve in "+eqn.toString()); 00855 } else { 00856 // eqn is 0 = x. Flip it and return 00857 Theorem result = symmetryRule(eqn); 00858 TRACE("arith eq", "processSimpleIntEq[x = 0] => ", result, " }"); 00859 return result; 00860 } 00861 } 00862 00863 /*! input is 0=e' Theorem and all of the vars in e' are of 00864 * type INT. isolate one of them and send back to framework. output 00865 * is "var = e''" Theorem and some associated equations in 00866 * solved form. 00867 */ 00868 Theorem 00869 TheoryArithOld::processIntEq(const Theorem& eqn) 00870 { 00871 TRACE("arith eq", "processIntEq(", eqn.getExpr(), ") {"); 00872 // Equations in the solved form. 00873 std::vector<Theorem> solvedAndNewEqs; 00874 Theorem newEq(eqn), result; 00875 bool done(false); 00876 do { 00877 result = processSimpleIntEq(newEq); 00878 // 'result' is of the from (x1=t1) AND 0=t' 00879 if(result.isRewrite()) { 00880 solvedAndNewEqs.push_back(result); 00881 done = true; 00882 } 00883 else if (result.getExpr().isBoolConst()) { 00884 done = true; 00885 } 00886 else { 00887 DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2, 00888 "TheoryArithOld::processIntEq("+eqn.getExpr().toString() 00889 +")\n result = "+result.getExpr().toString()); 00890 solvedAndNewEqs.push_back(getCommonRules()->andElim(result, 0)); 00891 newEq = getCommonRules()->andElim(result, 1); 00892 } 00893 } while(!done); 00894 Theorem res; 00895 if (result.getExpr().isFalse()) res = result; 00896 else if (solvedAndNewEqs.size() > 0) 00897 res = solvedForm(solvedAndNewEqs); 00898 else res = result; 00899 TRACE("arith eq", "processIntEq => ", res.getExpr(), " }"); 00900 return res; 00901 } 00902 00903 /*! 00904 * Takes a vector of equations and for every equation x_i=t_i 00905 * substitutes t_j for x_j in t_i for all j>i. This turns the system 00906 * of equations into a solved form. 00907 * 00908 * Assumption: variables x_j may appear in the RHS terms t_i ONLY for 00909 * i<j, but not for i>=j. 00910 */ 00911 Theorem 00912 TheoryArithOld::solvedForm(const vector<Theorem>& solvedEqs) 00913 { 00914 DebugAssert(solvedEqs.size() > 0, "TheoryArithOld::solvedForm()"); 00915 00916 // Trace code 00917 TRACE_MSG("arith eq", "TheoryArithOld::solvedForm:solvedEqs(\n ["); 00918 IF_DEBUG(if(debugger.trace("arith eq")) { 00919 for(vector<Theorem>::const_iterator j = solvedEqs.begin(), 00920 jend=solvedEqs.end(); j!=jend;++j) 00921 TRACE("arith eq", "", j->getExpr(), ",\n "); 00922 }) 00923 TRACE_MSG("arith eq", " ]) {"); 00924 // End of Trace code 00925 00926 vector<Theorem>::const_reverse_iterator 00927 i = solvedEqs.rbegin(), 00928 iend = solvedEqs.rend(); 00929 // Substitution map: a variable 'x' is mapped to a Theorem x=t. 00930 // This map accumulates the resulting solved form. 00931 ExprMap<Theorem> subst; 00932 for(; i!=iend; ++i) { 00933 if(i->isRewrite()) { 00934 Theorem thm = substAndCanonize(*i, subst); 00935 TRACE("arith eq", "solvedForm: subst["+i->getLHS().toString()+"] = ", 00936 thm.getExpr(), ""); 00937 subst[i->getLHS()] = thm; 00938 } 00939 else { 00940 // This is the FALSE case: just return the contradiction 00941 DebugAssert(i->getExpr().isFalse(), 00942 "TheoryArithOld::solvedForm: an element of solvedEqs must " 00943 "be either EQ or FALSE: "+i->toString()); 00944 return *i; 00945 } 00946 } 00947 // Now we've collected the solved form in 'subst'. Wrap it up into 00948 // a conjunction and return. 00949 vector<Theorem> thms; 00950 for(ExprMap<Theorem>::iterator i=subst.begin(), iend=subst.end(); 00951 i!=iend; ++i) 00952 thms.push_back(i->second); 00953 00954 if (thms.size() > 1) return getCommonRules()->andIntro(thms); 00955 else return thms.back(); 00956 } 00957 00958 00959 /*! 00960 * ASSUMPTION: 't' is a fully canonized arithmetic term, and every 00961 * element of subst is a fully canonized equation of the form x=e, 00962 * indexed by the LHS variable. 00963 */ 00964 00965 Theorem 00966 TheoryArithOld::substAndCanonize(const Expr& t, ExprMap<Theorem>& subst) 00967 { 00968 TRACE("arith eq", "substAndCanonize(", t, ") {"); 00969 // Quick and dirty check: return immediately if subst is empty 00970 if(subst.empty()) { 00971 Theorem res(reflexivityRule(t)); 00972 TRACE("arith eq", "substAndCanonize[subst empty] => ", res, " }"); 00973 return res; 00974 } 00975 // Check if we can substitute 't' directly 00976 ExprMap<Theorem>::iterator i = subst.find(t), iend=subst.end(); 00977 if(i!=iend) { 00978 TRACE("arith eq", "substAndCanonize[subst] => ", i->second, " }"); 00979 return i->second; 00980 } 00981 // The base case: t is an i-leaf 00982 if(isLeaf(t)) { 00983 Theorem res(reflexivityRule(t)); 00984 TRACE("arith eq", "substAndCanonize[i-leaf] => ", res, " }"); 00985 return res; 00986 } 00987 // 't' is an arithmetic term; recurse into the children 00988 vector<Theorem> thms; 00989 vector<unsigned> changed; 00990 for(unsigned j=0, jend=t.arity(); j!=jend; ++j) { 00991 Theorem thm = substAndCanonize(t[j], subst); 00992 if(thm.getRHS() != t[j]) { 00993 thm = canonThm(thm); 00994 thms.push_back(thm); 00995 changed.push_back(j); 00996 } 00997 } 00998 // Do the actual substitution and canonize the result 00999 Theorem res; 01000 if(thms.size() > 0) { 01001 res = substitutivityRule(t, changed, thms); 01002 res = canonThm(res); 01003 } 01004 else 01005 res = reflexivityRule(t); 01006 TRACE("arith eq", "substAndCanonize => ", res, " }"); 01007 return res; 01008 } 01009 01010 01011 /*! 01012 * ASSUMPTION: 't' is a fully canonized equation of the form x = t, 01013 * and so is every element of subst, indexed by the LHS variable. 01014 */ 01015 01016 Theorem 01017 TheoryArithOld::substAndCanonize(const Theorem& eq, ExprMap<Theorem>& subst) 01018 { 01019 // Quick and dirty check: return immediately if subst is empty 01020 if(subst.empty()) return eq; 01021 01022 DebugAssert(eq.isRewrite(), "TheoryArithOld::substAndCanonize: t = " 01023 +eq.getExpr().toString()); 01024 const Expr& t = eq.getRHS(); 01025 // Do the actual substitution in the term t 01026 Theorem thm = substAndCanonize(t, subst); 01027 // Substitution had no result: return the original equation 01028 if(thm.getRHS() == t) return eq; 01029 // Otherwise substitute the result into the equation 01030 vector<Theorem> thms; 01031 vector<unsigned> changed; 01032 thms.push_back(thm); 01033 changed.push_back(1); 01034 return iffMP(eq, substitutivityRule(eq.getExpr(), changed, thms)); 01035 } 01036 01037 void TheoryArithOld::processBuffer() 01038 { 01039 // Process the inequalities in the buffer 01040 bool varOnRHS; 01041 01042 // If we are in difference logic only, just return 01043 if (diffLogicOnly) return; 01044 01045 while (!inconsistent() && (d_bufferIdx_0 < d_buffer_0.size() || d_bufferIdx_1 < d_buffer_1.size() || d_bufferIdx_2 < d_buffer_2.size() || d_bufferIdx_3 < d_buffer_3.size())) { 01046 01047 // Get the unprojected inequality 01048 Theorem ineqThm; 01049 if (d_bufferIdx_0 < d_buffer_0.size()) { 01050 ineqThm = d_buffer_0[d_bufferIdx_0]; 01051 d_bufferIdx_0 = d_bufferIdx_0 + 1; 01052 } else if (d_bufferIdx_1 < d_buffer_1.size()) { 01053 ineqThm = d_buffer_1[d_bufferIdx_1]; 01054 d_bufferIdx_1 = d_bufferIdx_1 + 1; 01055 } else if (d_bufferIdx_2 < d_buffer_2.size()) { 01056 ineqThm = d_buffer_2[d_bufferIdx_2]; 01057 d_bufferIdx_2 = d_bufferIdx_2 + 1; 01058 } else { 01059 ineqThm = d_buffer_3[d_bufferIdx_3]; 01060 d_bufferIdx_3 = d_bufferIdx_3 + 1; 01061 } 01062 01063 // // Skip this inequality if it is stale 01064 // if(isStale(ineqThm.getExpr())) { 01065 // TRACE("arith buffer", "processBuffer(", ineqThm.getExpr(), ")... skipping stale"); 01066 // continue; 01067 // } 01068 // Dejan: project the finds, not the originals (if not projected already) 01069 const Expr& inequality = ineqThm.getExpr(); 01070 Theorem inequalityFindThm = inequalityToFind(ineqThm, true); 01071 Expr inequalityFind = inequalityFindThm.getExpr(); 01072 // if (inequality != inequalityFind) 01073 // enqueueFact(inequalityFindThm); 01074 01075 TRACE("arith buffer", "processing: ", inequality, ""); 01076 TRACE("arith buffer", "with find : ", inequalityFind, ""); 01077 01078 if (!isIneq(inequalityFind)) { 01079 TRACE("arith buffer", "find not an inequality... ", "", "skipping"); 01080 continue; 01081 } 01082 01083 if (alreadyProjected.find(inequalityFind) != alreadyProjected.end()) { 01084 TRACE("arith buffer", "already projected ... ", "", "skipping"); 01085 continue; 01086 } 01087 01088 01089 // We put the dummy for now, isolate variable will set it properly (or the find's one) 01090 // This one is just if the find is different. If the find is different 01091 // We will not check it again in update, so we're fine 01092 Expr dummy; 01093 alreadyProjected[inequality] = dummy; 01094 if (inequality != inequalityFind) { 01095 01096 alreadyProjected[inequalityFind] = dummy; 01097 01098 Expr rhs = inequalityFind[1]; 01099 01100 // Collect the statistics about variables 01101 if(isPlus(rhs)) { 01102 for(Expr::iterator i=rhs.begin(), iend=rhs.end(); i!=iend; ++i) { 01103 Expr monomial = *i; 01104 updateStats(monomial); 01105 } 01106 } else // It's a monomial 01107 updateStats(rhs); 01108 } 01109 01110 // See if this one is subsumed by a stronger inequality 01111 // c1 <= t1, t2 <= c2 01112 Rational c1, c2; 01113 Expr t1, t2; 01114 // Every term in the buffer has to have a lower bound set!!! 01115 // Except for the ones that changed the find 01116 extractTermsFromInequality(inequalityFind, c1, t1, c2, t2); 01117 if (termLowerBound.find(t1) != termLowerBound.end() && c1 != termLowerBound[t1]) { 01118 TRACE("arith ineq", "skipping because stronger bounds asserted ", inequalityFind.toString(), ":" + t1.toString()); 01119 DebugAssert(termLowerBoundThm.find(t1) != termLowerBoundThm.end(), "No lower bound on asserted atom!!! " + t1.toString()); 01120 Theorem strongerBound = termLowerBoundThm[t1]; 01121 //enqueueFact(d_rules->implyWeakerInequality(strongerBound.getExpr(), inequalityFindThm.getExpr())); 01122 continue; 01123 } 01124 01125 Theorem thm1 = isolateVariable(inequalityFindThm, varOnRHS); 01126 const Expr& ineq = thm1.getExpr(); 01127 if (ineq.isFalse()) 01128 setInconsistent(thm1); 01129 else 01130 if(!ineq.isTrue()) { 01131 01132 // Check that the variable is indeed isolated correctly 01133 DebugAssert(varOnRHS? !isPlus(ineq[1]) : !isPlus(ineq[0]), "TheoryArithOld::processBuffer(): bad result from isolateVariable:\nineq = "+ineq.toString()); 01134 // and project the inequality 01135 projectInequalities(thm1, varOnRHS); 01136 } 01137 } 01138 } 01139 01140 01141 void TheoryArithOld::updateStats(const Rational& c, const Expr& v) 01142 { 01143 TRACE("arith stats", "updateStats("+c.toString()+", ", v, ")"); 01144 01145 // we can get numbers as checking for variables is not possible (nonlinear stuff) 01146 if (v.isRational()) return; 01147 01148 if (v.getType() != d_realType) { 01149 // Dejan: update the max coefficient of the variable 01150 if (c < 0) { 01151 // Goes to the left side 01152 ExprMap<Rational>::iterator maxFind = maxCoefficientLeft.find(v); 01153 if (maxFind == maxCoefficientLeft.end()) { 01154 maxCoefficientLeft[v] = - c; 01155 TRACE("arith stats", "max left", "", ""); 01156 } 01157 else 01158 if ((*maxFind).second < -c) { 01159 TRACE("arith stats", "max left", "", ""); 01160 maxCoefficientLeft[v] = -c; 01161 } 01162 } else { 01163 // Stays on the right side 01164 ExprMap<Rational>::iterator maxFind = maxCoefficientRight.find(v); 01165 if (maxFind == maxCoefficientRight.end()) { 01166 maxCoefficientRight[v] = c; 01167 TRACE("arith stats", "max right", "", ""); 01168 } 01169 else 01170 if((*maxFind).second < c) { 01171 TRACE("arith stats", "max right", "", ""); 01172 maxCoefficientRight[v] = c; 01173 } 01174 } 01175 } 01176 01177 if(c > 0) { 01178 if(d_countRight.count(v) > 0) d_countRight[v] = d_countRight[v] + 1; 01179 else d_countRight[v] = 1; 01180 } 01181 else 01182 if(d_countLeft.count(v) > 0) d_countLeft[v] = d_countLeft[v] + 1; 01183 else d_countLeft[v] = 1; 01184 } 01185 01186 01187 void TheoryArithOld::updateStats(const Expr& monomial) 01188 { 01189 Expr c, m; 01190 separateMonomial(monomial, c, m); 01191 updateStats(c.getRational(), m); 01192 } 01193 01194 int TheoryArithOld::extractTermsFromInequality(const Expr& inequality, 01195 Rational& c1, Expr& t1, 01196 Rational& c2, Expr& t2) { 01197 01198 TRACE("arith extract", "extract(", inequality.toString(), ")"); 01199 01200 DebugAssert(isIneq(inequality), "extractTermsFromInequality: expexting an inequality got: " + inequality.getString() + ")"); 01201 01202 Expr rhs = inequality[1]; 01203 01204 c1 = 0; 01205 01206 // Extract the non-constant term (both sides) 01207 vector<Expr> positive_children, negative_children; 01208 if (isPlus(rhs)) { 01209 int start_i = 0; 01210 if (rhs[0].isRational()) { 01211 start_i = 1; 01212 c1 = -rhs[0].getRational(); 01213 } 01214 int end_i = rhs.arity(); 01215 for(int i = start_i; i < end_i; i ++) { 01216 const Expr& term = rhs[i]; 01217 positive_children.push_back(term); 01218 negative_children.push_back(canon(multExpr(rat(-1),term)).getRHS()); 01219 } 01220 } else { 01221 positive_children.push_back(rhs); 01222 negative_children.push_back(canon(multExpr(rat(-1), rhs)).getRHS()); 01223 } 01224 01225 int num_vars = positive_children.size(); 01226 01227 // c1 <= t1 01228 t1 = (num_vars > 1 ? canon(plusExpr(positive_children)).getRHS() : positive_children[0]); 01229 01230 // c2 is the upper bound on t2 : t2 <= c2 01231 c2 = -c1; 01232 t2 = (num_vars > 1 ? canon(plusExpr(negative_children)).getRHS() : negative_children[0]); 01233 01234 TRACE("arith extract", "extract: ", c1.toString() + " <= ", t1.toString()); 01235 01236 return num_vars; 01237 } 01238 01239 bool TheoryArithOld::addToBuffer(const Theorem& thm, bool priority) { 01240 01241 TRACE("arith buffer", "addToBuffer(", thm.getExpr().toString(), ")"); 01242 01243 Expr ineq = thm.getExpr(); 01244 const Expr& rhs = thm.getExpr()[1]; 01245 01246 bool nonLinear = false; 01247 Rational nonLinearConstant = 0; 01248 Expr compactNonLinear; 01249 Theorem compactNonLinearThm; 01250 01251 // Collect the statistics about variables and check for non-linearity 01252 if(isPlus(rhs)) { 01253 for(Expr::iterator i=rhs.begin(), iend=rhs.end(); i!=iend; ++i) { 01254 Expr monomial = *i; 01255 updateStats(monomial); 01256 // check for non-linear 01257 if (isMult(monomial)) { 01258 if ((monomial[0].isRational() && monomial.arity() >= 3) || 01259 (!monomial[0].isRational() && monomial.arity() >= 2) || 01260 (monomial.arity() == 2 && isPow(monomial[1]))) 01261 nonLinear = true; 01262 } 01263 } 01264 if (nonLinear) { 01265 compactNonLinearThm = d_rules->compactNonLinearTerm(rhs); 01266 compactNonLinear = compactNonLinearThm.getRHS(); 01267 } 01268 } 01269 else // It's a monomial 01270 { 01271 updateStats(rhs); 01272 if (isMult(rhs)) 01273 if ((rhs[0].isRational() && rhs.arity() >= 3) 01274 || (!rhs[0].isRational() && rhs.arity() >= 2) 01275 || (rhs.arity() == 2 && isPow(rhs[1]))) { 01276 nonLinear = true; 01277 compactNonLinear = rhs; 01278 compactNonLinearThm = reflexivityRule(compactNonLinear); 01279 } 01280 } 01281 01282 if (bufferedInequalities.find(ineq) != bufferedInequalities.end()) { 01283 TRACE("arith buffer", "addToBuffer()", "", "... already in db"); 01284 if (formulaAtoms.find(ineq) != formulaAtoms.end()) { 01285 TRACE("arith buffer", "it's a formula atom, enqueuing.", "", ""); 01286 enqueueFact(thm); 01287 } 01288 return false; 01289 } 01290 01291 if (nonLinear && (isMult(rhs) || compactNonLinear != rhs)) { 01292 TRACE("arith nonlinear", "compact version of ", rhs, " is " + compactNonLinear.toString()); 01293 // Replace the rhs with the compacted nonlinear term 01294 Theorem thm1 = (compactNonLinear != rhs ? 01295 iffMP(thm, substitutivityRule(ineq, 1, compactNonLinearThm)) : thm); 01296 // Now, try to deduce the signednes of multipliers 01297 Rational c = (isMult(rhs) ? 0 : compactNonLinear[0].getRational()); 01298 // We can deduct the signs if the constant is not bigger than 0 01299 if (c <= 0) { 01300 thm1 = d_rules->nonLinearIneqSignSplit(thm1); 01301 TRACE("arith nonlinear", "spliting on signs : ", thm1.getExpr(), ""); 01302 enqueueFact(thm1); 01303 } 01304 } 01305 01306 // Get c1, c2, t1, t2 such that c1 <= t1 and t2 <= c2 01307 Expr t1, t2; 01308 Rational c1, c2; 01309 int num_vars = extractTermsFromInequality(ineq, c1, t1, c2, t2); 01310 01311 // If 2 variable, do add to difference logic (allways, just in case) 01312 bool factIsDiffLogic = false; 01313 if (num_vars <= 2) { 01314 01315 TRACE("arith diff", t2, " < ", c2); 01316 // c1 <= t1, check if difference logic 01317 // t1 of the form 0 + ax + by 01318 Expr ax = (num_vars == 2 ? t2[1] : t2); 01319 Expr a_expr, x; 01320 separateMonomial(ax, a_expr, x); 01321 Rational a = a_expr.getRational(); 01322 Expr by = (num_vars == 2 ? t2[2] : (a < 0 ? zero : rat(-1)*zero)); 01323 Expr b_expr, y; 01324 separateMonomial(by, b_expr, y); 01325 Rational b = b_expr.getRational(); 01326 01327 // Check for non-linear 01328 if (!isLeaf(x) || !isLeaf(y)) 01329 setIncomplete("Non-linear arithmetic inequalities"); 01330 01331 if (a == 1 && b == -1) { 01332 diffLogicGraph.addEdge(x, y, c2, thm); 01333 factIsDiffLogic = true; 01334 } 01335 else if (a == -1 && b == 1) { 01336 diffLogicGraph.addEdge(y, x, c2, thm); 01337 factIsDiffLogic = true; 01338 } 01339 // Not difference logic, put it in the 3 or more vars buffer 01340 else { 01341 diffLogicOnly = false; 01342 TRACE("arith diff", "not diff logic", thm.getExpr().toString(), ""); 01343 } 01344 01345 if (diffLogicGraph.isUnsat()) { 01346 TRACE("diff unsat", "UNSAT", " : ", diffLogicGraph.getUnsatTheorem()); 01347 setInconsistent(diffLogicGraph.getUnsatTheorem()); 01348 return false; 01349 } 01350 } else { 01351 diffLogicOnly = false; 01352 TRACE("arith diff", "not diff logic", thm.getExpr().toString(), ""); 01353 } 01354 01355 // For now we treat all the bound as LE, weaker 01356 CDMap<Expr, Rational>::iterator find_lower = termLowerBound.find(t1); 01357 if (find_lower != termLowerBound.end()) { 01358 // found bound c <= t1 01359 Rational found_c = (*find_lower).second; 01360 // If found c is bigger than the new one, we are done 01361 if (c1 <= found_c && !(found_c == c1 && ineq.getKind() == LT)) { 01362 TRACE("arith buffer", "addToBuffer()", "", "... lower_bound subsumed"); 01363 // Removed assert. Can happen that an atom is not asserted yet, and get's implied as 01364 // a formula atom and then asserted here. it's fine 01365 //DebugAssert(!thm.isAssump(), "Should have been propagated: " + ineq.toString() + ""); 01366 return false; 01367 } else { 01368 Theorem oldLowerBound = termLowerBoundThm[t1]; 01369 Expr oldIneq = oldLowerBound.getExpr(); 01370 if (formulaAtoms.find(oldIneq) != formulaAtoms.end()) 01371 enqueueFact(getCommonRules()->implMP(thm, d_rules->implyWeakerInequality(ineq, oldIneq))); 01372 termLowerBound[t1] = c1; 01373 termLowerBoundThm[t1] = thm; 01374 } 01375 } else { 01376 termLowerBound[t1] = c1; 01377 termLowerBoundThm[t1] = thm; 01378 } 01379 01380 CDMap<Expr, Rational>::iterator find_upper = termUpperBound.find(t2); 01381 if (find_upper != termUpperBound.end()) { 01382 // found bound t2 <= c 01383 Rational found_c = (*find_upper).second; 01384 // If found c is smaller than the new one, we are done 01385 if (found_c <= c2 && !(found_c == c2 && ineq.getKind() == LT)) { 01386 TRACE("arith buffer", "addToBuffer()", "", "... upper_bound subsumed"); 01387 //DebugAssert(!thm.isAssump(), "Should have been propagated: " + ineq.toString() + ""); 01388 return false; 01389 } else { 01390 termUpperBound[t2] = c2; 01391 termUpperBoundThm[t2] = thm; 01392 } 01393 } else { 01394 termUpperBound[t2] = c2; 01395 termUpperBoundThm[t2] = thm; 01396 } 01397 01398 // See if the bounds on the term can infer conflict or equality 01399 if (termUpperBound.find(t1) != termUpperBound.end() && 01400 termLowerBound.find(t1) != termLowerBound.end() && 01401 termUpperBound[t1] <= termLowerBound[t1]) { 01402 Theorem thm1 = termUpperBoundThm[t1]; 01403 Theorem thm2 = termLowerBoundThm[t1]; 01404 TRACE("arith propagate", "adding inequalities: ", thm1.getExpr().toString(), " with " + thm2.getExpr().toString()); 01405 enqueueFact(d_rules->addInequalities(thm1, thm2)); 01406 } else 01407 if (termUpperBound.find(t2) != termUpperBound.end() && 01408 termLowerBound.find(t2) != termLowerBound.end() && 01409 termUpperBound[t2] <= termLowerBound[t2]) { 01410 Theorem thm1 = termUpperBoundThm[t2]; 01411 Theorem thm2 = termLowerBoundThm[t2]; 01412 TRACE("arith propagate", "adding inequalities: ", thm1.getExpr().toString(), " with " + thm2.getExpr().toString()); 01413 enqueueFact(d_rules->addInequalities(thm1, thm2)); 01414 } 01415 01416 if (true) { 01417 // See if we can propagate anything to the formula atoms 01418 // c1 <= t1 ===> c <= t1 for c < c1 01419 AtomsMap::iterator find = formulaAtomLowerBound.find(t1); 01420 AtomsMap::iterator find_end = formulaAtomLowerBound.end(); 01421 if (find != find_end) { 01422 set< pair<Rational, Expr> >::iterator bounds = (*find).second.begin(); 01423 set< pair<Rational, Expr> >::iterator bounds_end = (*find).second.end(); 01424 while (bounds != bounds_end) { 01425 TRACE("arith atoms", "trying propagation", ineq, (*bounds).second); 01426 const Expr& implied = (*bounds).second; 01427 // Try to do some theory propagation 01428 if ((*bounds).first < c1 || (!(ineq.getKind() == LE && implied.getKind() == LT) && (*bounds).first == c1)) { 01429 // c1 <= t1 => c <= t1 (for c <= c1) 01430 // c1 < t1 => c <= t1 (for c <= c1) 01431 // c1 <= t1 => c < t1 (for c < c1) 01432 Theorem impliedThm = getCommonRules()->implMP(thm, d_rules->implyWeakerInequality(ineq, implied)); 01433 enqueueFact(impliedThm); 01434 } 01435 bounds ++; 01436 } 01437 } 01438 01439 // 01440 // c1 <= t1 ==> !(t1 <= c) for c < c1 01441 // ==> !(-c <= t2) 01442 // i.e. all coefficient in in the implied are opposite of t1 01443 find = formulaAtomUpperBound.find(t1); 01444 find_end = formulaAtomUpperBound.end(); 01445 if (find != find_end) { 01446 set< pair<Rational, Expr> >::iterator bounds = (*find).second.begin(); 01447 set< pair<Rational, Expr> >::iterator bounds_end = (*find).second.end(); 01448 while (bounds != bounds_end) { 01449 TRACE("arith atoms", "trying propagation", ineq, (*bounds).second); 01450 const Expr& implied = (*bounds).second; 01451 // Try to do some theory propagation 01452 if ((*bounds).first < c1) { 01453 Theorem impliedThm = getCommonRules()->implMP(thm, d_rules->implyNegatedInequality(ineq, implied)); 01454 enqueueFact(impliedThm); 01455 } 01456 bounds ++; 01457 } 01458 } 01459 } 01460 01461 // Register this as a resource 01462 theoryCore()->getResource(); 01463 01464 // If out of resources, bail out 01465 if (theoryCore()->outOfResources()) return false; 01466 01467 // Checking because we could have projected it as a find of some other 01468 // equation 01469 if (alreadyProjected.find(ineq) == alreadyProjected.end()) { 01470 // We buffer it if it's not marked for not buffering 01471 if (dontBuffer.find(ineq) == dontBuffer.end()) { 01472 // We give priority to the one that can produce a conflict 01473 if (priority) 01474 d_buffer_0.push_back(thm); 01475 else { 01476 // Push it into the buffer (one var) 01477 if (num_vars == 1) d_buffer_1.push_back(thm); 01478 else if (num_vars == 2) d_buffer_2.push_back(thm); 01479 else d_buffer_3.push_back(thm); 01480 } 01481 01482 if (factIsDiffLogic) diff_logic_size = diff_logic_size + 1; 01483 } 01484 } 01485 01486 // Remember that it's in the buffer 01487 bufferedInequalities[ineq] = thm; 01488 01489 // Since we care about this atom, lets set it up 01490 if (!ineq.hasFind()) 01491 theoryCore()->setupTerm(ineq, this, thm); 01492 01493 return true; 01494 } 01495 01496 01497 Theorem TheoryArithOld::isolateVariable(const Theorem& inputThm, 01498 bool& isolatedVarOnRHS) 01499 { 01500 Theorem result(inputThm); 01501 const Expr& e = inputThm.getExpr(); 01502 TRACE("arith","isolateVariable(",e,") {"); 01503 TRACE("arith ineq", "isolateVariable(", e, ") {"); 01504 //we assume all the children of e are canonized 01505 DebugAssert(isLT(e)||isLE(e), 01506 "TheoryArithOld::isolateVariable: " + e.toString() + 01507 " wrong kind"); 01508 int kind = e.getKind(); 01509 DebugAssert(e[0].isRational() && e[0].getRational() == 0, 01510 "TheoryArithOld::isolateVariable: theorem must be of " 01511 "the form 0 < rhs: " + inputThm.toString()); 01512 01513 const Expr& zero = e[0]; 01514 Expr right = e[1]; 01515 // Check for trivial in-equation. 01516 if (right.isRational()) { 01517 result = iffMP(result, d_rules->constPredicate(e)); 01518 TRACE("arith ineq","isolateVariable => ",result.getExpr()," }"); 01519 TRACE("arith","isolateVariable => ",result," }"); 01520 return result; 01521 } 01522 01523 // Normalization of inequality to make coefficients integer and 01524 // relatively prime. 01525 01526 Expr factor(computeNormalFactor(right, false)); 01527 TRACE("arith", "isolateVariable: factor = ", factor, ""); 01528 DebugAssert(factor.getRational() > 0, 01529 "isolateVariable: factor="+factor.toString()); 01530 // Now multiply the inequality by the factor, unless it is 1 01531 if(factor.getRational() != 1) { 01532 result = iffMP(result, d_rules->multIneqn(e, factor)); 01533 // And canonize the result 01534 result = canonPred(result); 01535 result = rafineInequalityToInteger(result); 01536 right = result.getExpr()[1]; 01537 } 01538 01539 // Find monomial to isolate and store it in isolatedMonomial 01540 Expr isolatedMonomial = right; 01541 01542 if (isPlus(right)) 01543 isolatedMonomial = pickMonomial(right); 01544 01545 TRACE("arith ineq", "isolatedMonomial => ",isolatedMonomial,""); 01546 01547 // Set the correct isolated monomial 01548 // Now, if something gets updated, but this monomial is not changed, we don't 01549 // Have to rebuffer it as the projection will still be accurate when updated 01550 alreadyProjected[e] = isolatedMonomial; 01551 01552 Rational r = -1; 01553 isolatedVarOnRHS = true; 01554 if (isMult(isolatedMonomial)) { 01555 r = ((isolatedMonomial[0].getRational()) >= 0)? -1 : 1; 01556 isolatedVarOnRHS = 01557 ((isolatedMonomial[0].getRational()) >= 0)? true : false; 01558 } 01559 isolatedMonomial = canon(rat(-1)*isolatedMonomial).getRHS(); 01560 TRACE("arith ineq", "-(isolatedMonomial) => ",isolatedMonomial,""); 01561 // Isolate isolatedMonomial on to the LHS 01562 result = iffMP(result, d_rules->plusPredicate(zero, right, 01563 isolatedMonomial, kind)); 01564 // Canonize the resulting inequality 01565 TRACE("arith ineq", "resutl => ",result,""); 01566 result = canonPred(result); 01567 if(1 != r) { 01568 result = iffMP(result, d_rules->multIneqn(result.getExpr(), rat(r))); 01569 result = canonPred(result); 01570 } 01571 TRACE("arith ineq","isolateVariable => ",result.getExpr()," }"); 01572 TRACE("arith","isolateVariable => ",result," }"); 01573 return result; 01574 } 01575 01576 Expr 01577 TheoryArithOld::computeNormalFactor(const Expr& right, bool normalizeConstants) { 01578 // Strategy: compute f = lcm(d1...dn)/gcd(c1...cn), where the RHS is 01579 // of the form c1/d1*x1 + ... + cn/dn*xn 01580 Rational factor; 01581 if(isPlus(right)) { 01582 vector<Rational> nums, denoms; 01583 for(int i=0, iend=right.arity(); i<iend; ++i) { 01584 switch(right[i].getKind()) { 01585 case RATIONAL_EXPR: 01586 if (normalizeConstants) { 01587 Rational c(abs(right[i].getRational())); 01588 nums.push_back(c.getNumerator()); 01589 denoms.push_back(c.getDenominator()); 01590 break; 01591 } 01592 break; 01593 case MULT: { 01594 Rational c(abs(right[i][0].getRational())); 01595 nums.push_back(c.getNumerator()); 01596 denoms.push_back(c.getDenominator()); 01597 break; 01598 } 01599 default: // it's a variable 01600 nums.push_back(1); 01601 denoms.push_back(1); 01602 break; 01603 } 01604 } 01605 Rational gcd_nums = gcd(nums); 01606 // x/0 == 0 in our model, as a total extension of arithmetic. The 01607 // particular value of x/0 is irrelevant, since the DP is guarded 01608 // by the top-level TCCs, and it is safe to return any value in 01609 // cases when terms are undefined. 01610 factor = (gcd_nums==0)? 0 : (lcm(denoms) / gcd_nums); 01611 } else if(isMult(right)) { 01612 const Rational& r = right[0].getRational(); 01613 factor = (r==0)? 0 : (1/abs(r)); 01614 } 01615 else 01616 factor = 1; 01617 return rat(factor); 01618 } 01619 01620 01621 bool TheoryArithOld::lessThanVar(const Expr& isolatedMonomial, const Expr& var2) 01622 { 01623 DebugAssert(!isRational(var2) && !isRational(isolatedMonomial), 01624 "TheoryArithOld::findMaxVar: isolatedMonomial cannot be rational" + 01625 isolatedMonomial.toString()); 01626 Expr c, var0, var1; 01627 separateMonomial(isolatedMonomial, c, var0); 01628 separateMonomial(var2, c, var1); 01629 return var0 < var1; 01630 } 01631 01632 /*! "Stale" means it contains non-simplified subexpressions. For 01633 * terms, it checks the expression's find pointer; for formulas it 01634 * checks the children recursively (no caching!). So, apply it with 01635 * caution, and only to simple atomic formulas (like inequality). 01636 */ 01637 bool TheoryArithOld::isStale(const Expr& e) { 01638 if(e.isTerm()) 01639 return e != find(e).getRHS(); 01640 // It's better be a simple predicate (like inequality); we check the 01641 // kids recursively 01642 bool stale=false; 01643 for(Expr::iterator i=e.begin(), iend=e.end(); !stale && i!=iend; ++i) 01644 stale = isStale(*i); 01645 return stale; 01646 } 01647 01648 01649 bool TheoryArithOld::isStale(const TheoryArithOld::Ineq& ineq) { 01650 TRACE("arith stale", "isStale(", ineq, ") {"); 01651 const Expr& ineqExpr = ineq.ineq().getExpr(); 01652 const Rational& c = freeConstIneq(ineqExpr, ineq.varOnRHS()); 01653 bool strict(isLT(ineqExpr)); 01654 const FreeConst& fc = ineq.getConst(); 01655 01656 bool subsumed; 01657 01658 if (ineqExpr.hasFind() && find(ineqExpr[1]).getRHS() != ineqExpr[1]) 01659 return true; 01660 01661 if(ineq.varOnRHS()) { 01662 subsumed = (c < fc.getConst() || 01663 (c == fc.getConst() && !strict && fc.strict())); 01664 } else { 01665 subsumed = (c > fc.getConst() || 01666 (c == fc.getConst() && strict && !fc.strict())); 01667 } 01668 01669 bool res; 01670 if(subsumed) { 01671 res = true; 01672 TRACE("arith ineq", "isStale[subsumed] => ", res? "true" : "false", " }"); 01673 } 01674 else { 01675 res = isStale(ineqExpr); 01676 TRACE("arith ineq", "isStale[updated] => ", res? "true" : "false", " }"); 01677 } 01678 return res; 01679 } 01680 01681 01682 void TheoryArithOld::separateMonomial(const Expr& e, Expr& c, Expr& var) { 01683 TRACE("separateMonomial", "separateMonomial(", e, ")"); 01684 DebugAssert(!isPlus(e), 01685 "TheoryArithOld::separateMonomial(e = "+e.toString()+")"); 01686 if(isMult(e)) { 01687 DebugAssert(e.arity() >= 2, 01688 "TheoryArithOld::separateMonomial(e = "+e.toString()+")"); 01689 c = e[0]; 01690 if(e.arity() == 2) var = e[1]; 01691 else { 01692 vector<Expr> kids = e.getKids(); 01693 kids[0] = rat(1); 01694 var = multExpr(kids); 01695 } 01696 } else { 01697 c = rat(1); 01698 var = e; 01699 } 01700 DebugAssert(c.isRational(), "TheoryArithOld::separateMonomial(e = " 01701 +e.toString()+", c = "+c.toString()+")"); 01702 DebugAssert(!isMult(var) || (var[0].isRational() && var[0].getRational()==1), 01703 "TheoryArithOld::separateMonomial(e = " 01704 +e.toString()+", var = "+var.toString()+")"); 01705 } 01706 01707 01708 void TheoryArithOld::projectInequalities(const Theorem& theInequality, 01709 bool isolatedVarOnRHS) 01710 { 01711 01712 TRACE("arith project", "projectInequalities(", theInequality.getExpr(), 01713 ", isolatedVarOnRHS="+string(isolatedVarOnRHS? "true" : "false") 01714 +") {"); 01715 DebugAssert(isLE(theInequality.getExpr()) || 01716 isLT(theInequality.getExpr()), 01717 "TheoryArithOld::projectIsolatedVar: "\ 01718 "theInequality is of the wrong form: " + 01719 theInequality.toString()); 01720 01721 //TODO: DebugAssert to check if the isolatedMonomial is of the right 01722 //form and the whether we are indeed getting inequalities. 01723 Theorem theIneqThm(theInequality); 01724 Expr theIneq = theIneqThm.getExpr(); 01725 01726 // If the inequality is strict and integer, change it to non-strict 01727 if(isLT(theIneq)) { 01728 Theorem isIntLHS(isIntegerThm(theIneq[0])); 01729 Theorem isIntRHS(isIntegerThm(theIneq[1])); 01730 if ((!isIntLHS.isNull() && !isIntRHS.isNull())) { 01731 Theorem thm = d_rules->lessThanToLE(theInequality, isIntLHS, isIntRHS, !isolatedVarOnRHS); 01732 theIneqThm = canonPred(iffMP(theIneqThm, thm)); 01733 theIneq = theIneqThm.getExpr(); 01734 } 01735 } 01736 01737 Expr isolatedMonomial = isolatedVarOnRHS ? theIneq[1] : theIneq[0]; 01738 01739 Expr monomialVar, a; 01740 separateMonomial(isolatedMonomial, a, monomialVar); 01741 01742 bool subsumed; 01743 const FreeConst& bestConst = updateSubsumptionDB(theIneq, isolatedVarOnRHS, subsumed); 01744 01745 if(subsumed) { 01746 IF_DEBUG(debugger.counter("subsumed inequalities")++;) 01747 TRACE("arith ineq", "subsumed inequality: ", theIneq, ""); 01748 } else { 01749 // If the isolated variable is actually a non-linear term, we are 01750 // incomplete 01751 if(isMult(monomialVar) || isPow(monomialVar)) 01752 setIncomplete("Non-linear arithmetic inequalities"); 01753 01754 // First, we need to make sure the isolated inequality is 01755 // setup properly. 01756 // setupRec(theIneq[0]); 01757 // setupRec(theIneq[1]); 01758 theoryCore()->setupTerm(theIneq[0], this, theIneqThm); 01759 theoryCore()->setupTerm(theIneq[1], this, theIneqThm); 01760 // Add the inequality into the appropriate DB. 01761 ExprMap<CDList<Ineq> *>& db1 = isolatedVarOnRHS ? d_inequalitiesRightDB : d_inequalitiesLeftDB; 01762 ExprMap<CDList<Ineq> *>::iterator it1 = db1.find(monomialVar); 01763 if(it1 == db1.end()) { 01764 CDList<Ineq> * list = new(true) CDList<Ineq>(theoryCore()->getCM()->getCurrentContext()); 01765 list->push_back(Ineq(theIneqThm, isolatedVarOnRHS, bestConst)); 01766 db1[monomialVar] = list; 01767 } 01768 else 01769 ((*it1).second)->push_back(Ineq(theIneqThm, isolatedVarOnRHS, bestConst)); 01770 01771 ExprMap<CDList<Ineq> *>& db2 = isolatedVarOnRHS ? d_inequalitiesLeftDB : d_inequalitiesRightDB; 01772 ExprMap<CDList<Ineq> *>::iterator it = db2.find(monomialVar); 01773 if(it == db2.end()) { 01774 TRACE_MSG("arith ineq", "projectInequalities[not in DB] => }"); 01775 return; 01776 } 01777 01778 CDList<Ineq>& listOfDBIneqs = *((*it).second); 01779 Theorem betaLTt, tLTalpha, thm; 01780 for(int i = listOfDBIneqs.size() - 1; !inconsistent() && i >= 0; --i) { 01781 const Ineq& ineqEntry = listOfDBIneqs[i]; 01782 const Theorem& ineqThm = ineqEntry.ineq(); //inequalityToFind(ineqEntry.ineq(), isolatedVarOnRHS); 01783 01784 // ineqExntry might be stale 01785 01786 if(!isStale(ineqEntry)) { 01787 betaLTt = isolatedVarOnRHS ? theIneqThm : ineqThm; 01788 tLTalpha = isolatedVarOnRHS ? ineqThm : theIneqThm; 01789 01790 thm = normalizeProjectIneqs(betaLTt, tLTalpha); 01791 if (thm.isNull()) continue; 01792 01793 IF_DEBUG(debugger.counter("real shadows")++;) 01794 01795 // Check for TRUE and FALSE theorems 01796 Expr e(thm.getExpr()); 01797 01798 if(e.isFalse()) { 01799 setInconsistent(thm); 01800 TRACE_MSG("arith ineq", "projectInequalities[inconsistent] => }"); 01801 return; 01802 } 01803 else { 01804 if(!e.isTrue() && !e.isEq()) { 01805 // setup the term so that it comes out in updates 01806 addToBuffer(thm, false); 01807 } 01808 else if(e.isEq()) 01809 enqueueFact(thm); 01810 } 01811 } else { 01812 IF_DEBUG(debugger.counter("stale inequalities")++;) 01813 } 01814 } 01815 } 01816 01817 TRACE_MSG("arith ineq", "projectInequalities => }"); 01818 } 01819 01820 Theorem TheoryArithOld::normalizeProjectIneqs(const Theorem& ineqThm1, 01821 const Theorem& ineqThm2) 01822 { 01823 //ineq1 is of the form beta < b.x or beta < x [ or with <= ] 01824 //ineq2 is of the form a.x < alpha or x < alpha. 01825 Theorem betaLTt = ineqThm1, tLTalpha = ineqThm2; 01826 Expr ineq1 = betaLTt.getExpr(); 01827 Expr ineq2 = tLTalpha.getExpr(); 01828 Expr c,x; 01829 separateMonomial(ineq2[0], c, x); 01830 Theorem isIntx(isIntegerThm(x)); 01831 Theorem isIntBeta(isIntegerThm(ineq1[0])); 01832 Theorem isIntAlpha(isIntegerThm(ineq2[1])); 01833 bool isInt = !(isIntx.isNull() || isIntBeta.isNull() || isIntAlpha.isNull()); 01834 01835 TRACE("arith ineq", "normalizeProjectIneqs(", ineq1, 01836 ", "+ineq2.toString()+") {"); 01837 DebugAssert((isLE(ineq1) || isLT(ineq1)) && 01838 (isLE(ineq2) || isLT(ineq2)), 01839 "TheoryArithOld::normalizeProjectIneqs: Wrong Kind inputs: " + 01840 ineq1.toString() + ineq2.toString()); 01841 DebugAssert(!isPlus(ineq1[1]) && !isPlus(ineq2[0]), 01842 "TheoryArithOld::normalizeProjectIneqs: Wrong Kind inputs: " + 01843 ineq1.toString() + ineq2.toString()); 01844 01845 //compute the factors to multiply the two inequalities with 01846 //so that they get the form beta < t and t < alpha. 01847 Rational factor1 = 1, factor2 = 1; 01848 Rational b = isMult(ineq1[1]) ? (ineq1[1])[0].getRational() : 1; 01849 Rational a = isMult(ineq2[0]) ? (ineq2[0])[0].getRational() : 1; 01850 if(b != a) { 01851 factor1 = a; 01852 factor2 = b; 01853 } 01854 01855 //if the ineqs are of type int then apply one of the gray 01856 //dark shadow rules. 01857 // FIXME: intResult should also be checked for immediate 01858 // optimizations, as those below for 'result'. Also, if intResult 01859 // is a single inequality, we may want to handle it similarly to the 01860 // 'result' rather than enqueuing directly. 01861 if(isInt && (a >= 2 || b >= 2)) { 01862 Theorem intResult; 01863 if(a <= b) 01864 intResult = d_rules->darkGrayShadow2ab(betaLTt, tLTalpha, 01865 isIntAlpha, isIntBeta, isIntx); 01866 else 01867 intResult = d_rules->darkGrayShadow2ba(betaLTt, tLTalpha, 01868 isIntAlpha, isIntBeta, isIntx); 01869 enqueueFact(intResult); 01870 // Fetch dark and gray shadows 01871 const Expr& DorG = intResult.getExpr(); 01872 DebugAssert(DorG.isOr() && DorG.arity()==2, "DorG = "+DorG.toString()); 01873 const Expr& G = DorG[1]; 01874 DebugAssert(G.getKind()==GRAY_SHADOW, "G = "+G.toString()); 01875 // Set the higher splitter priority for dark shadow 01876 // Expr tmp = simplifyExpr(D); 01877 // if (!tmp.isBoolConst()) 01878 // addSplitter(tmp, 5); 01879 // Also set a higher priority to the NEGATION of GRAY_SHADOW 01880 Expr tmp = simplifyExpr(!G); 01881 if (!tmp.isBoolConst()) 01882 addSplitter(tmp, 1); 01883 IF_DEBUG(debugger.counter("dark+gray shadows")++;) 01884 01885 // Dejan: Let's forget about the real shadow, we are doing integers 01886 // /return intResult; 01887 } 01888 01889 //actually normalize the inequalities 01890 if(1 != factor1) { 01891 Theorem thm2 = iffMP(betaLTt, d_rules->multIneqn(ineq1, rat(factor1))); 01892 betaLTt = canonPred(thm2); 01893 ineq1 = betaLTt.getExpr(); 01894 } 01895 if(1 != factor2) { 01896 Theorem thm2 = iffMP(tLTalpha, d_rules->multIneqn(ineq2, rat(factor2))); 01897 tLTalpha = canonPred(thm2); 01898 ineq2 = tLTalpha.getExpr(); 01899 } 01900 01901 //IF_DEBUG(debugger.counter("real shadows")++;) 01902 01903 Expr beta(ineq1[0]); 01904 Expr alpha(ineq2[1]); 01905 // In case of alpha <= t <= alpha, we generate t = alpha 01906 if(isLE(ineq1) && isLE(ineq2) && alpha == beta) { 01907 Theorem result = d_rules->realShadowEq(betaLTt, tLTalpha); 01908 TRACE("arith ineq", "normalizeProjectIneqs => ", result, " }"); 01909 return result; 01910 } 01911 01912 // Check if this inequality is a finite interval 01913 // if(isInt) 01914 // processFiniteInterval(betaLTt, tLTalpha); 01915 01916 // // Only do the real shadow if a and b = 1 01917 // if (isInt && a > 1 && b > 1) 01918 // return Theorem(); 01919 01920 //project the normalized inequalities. 01921 01922 Theorem result = d_rules->realShadow(betaLTt, tLTalpha); 01923 01924 // FIXME: Clark's changes. Is 'rewrite' more or less efficient? 01925 // result = iffMP(result, rewrite(result.getExpr())); 01926 // TRACE("arith ineq", "normalizeProjectIneqs => ", result, " }"); 01927 01928 // Now, transform the result into 0 < rhs and see if rhs is a const 01929 Expr e(result.getExpr()); 01930 // int kind = e.getKind(); 01931 if(!(e[0].isRational() && e[0].getRational() == 0)) 01932 result = iffMP(result, d_rules->rightMinusLeft(e)); 01933 result = canonPred(result); 01934 01935 //result is "0 kind e'". where e' is equal to canon(e[1]-e[0]) 01936 Expr right = result.getExpr()[1]; 01937 // Check for trivial inequality 01938 if (right.isRational()) 01939 result = iffMP(result, d_rules->constPredicate(result.getExpr())); 01940 else 01941 result = normalize(result); 01942 TRACE("arith ineq", "normalizeProjectIneqs => ", result, " }"); 01943 return result; 01944 } 01945 01946 Rational TheoryArithOld::currentMaxCoefficient(Expr var) 01947 { 01948 // We prefer real variables 01949 if (var.getType() == d_realType) return -100; 01950 01951 // Find the biggest left side coefficient 01952 ExprMap<Rational>::iterator findMaxLeft = maxCoefficientLeft.find(var); 01953 Rational leftMax = -1; 01954 if (findMaxLeft != maxCoefficientLeft.end()) 01955 leftMax = (*findMaxLeft).second; 01956 01957 // 01958 ExprMap<Rational>::iterator findMaxRight = maxCoefficientRight.find(var); 01959 Rational rightMax = -1; 01960 if (findMaxRight != maxCoefficientRight.end()) 01961 rightMax = (*findMaxRight).second; 01962 01963 // What is the max coefficient 01964 // If one is undefined, dont take it. My first thought was to project away unbounded 01965 // ones, but it happens that you get another constraint on it later and the hell breaks 01966 // loose if they have big coefficients. 01967 Rational returnValue; 01968 if (leftMax == -1) returnValue = rightMax; 01969 else if (rightMax == -1) returnValue = leftMax; 01970 else if (leftMax < rightMax) returnValue = rightMax; 01971 else returnValue = leftMax; 01972 01973 TRACE("arith stats", "max coeff of ", var.toString(), ": " + returnValue.toString() + "(left=" + leftMax.toString() + ",right=" + rightMax.toString()); 01974 01975 return returnValue; 01976 } 01977 01978 void TheoryArithOld::fixCurrentMaxCoefficient(Expr var, Rational max) { 01979 fixedMaxCoefficient[var] = max; 01980 } 01981 01982 void TheoryArithOld::selectSmallestByCoefficient(const vector<Expr>& input, vector<Expr>& output) { 01983 01984 // Clear the output vector 01985 output.clear(); 01986 01987 // Get the first variable, and set it as best 01988 Expr best_variable = input[0]; 01989 Rational best_coefficient = currentMaxCoefficient(best_variable); 01990 output.push_back(best_variable); 01991 01992 for(unsigned int i = 1; i < input.size(); i ++) { 01993 01994 // Get the current variable 01995 Expr current_variable = input[i]; 01996 // Get the current variable's max coefficient 01997 Rational current_coefficient = currentMaxCoefficient(current_variable); 01998 01999 // If strictly better than the current best, remember it 02000 if ((current_coefficient < best_coefficient)) { 02001 best_variable = current_variable; 02002 best_coefficient = current_coefficient; 02003 output.clear(); 02004 } 02005 02006 // If equal to the current best, push it to the stack (in 10% range) 02007 if (current_coefficient == best_coefficient) 02008 output.push_back(current_variable); 02009 } 02010 02011 // Fix the selected best coefficient 02012 //fixCurrentMaxCoefficient(best_variable, best_coefficient); 02013 } 02014 02015 Expr TheoryArithOld::pickMonomial(const Expr& right) 02016 { 02017 DebugAssert(isPlus(right), "TheoryArithOld::pickMonomial: Wrong Kind: " + 02018 right.toString()); 02019 if(theoryCore()->getFlags()["var-order"].getBool()) { 02020 Expr::iterator i = right.begin(); 02021 Expr isolatedMonomial = right[1]; 02022 //PLUS always has at least two elements and the first element is 02023 //always a constant. hence ++i in the initialization of the for 02024 //loop. 02025 for(++i; i != right.end(); ++i) 02026 if(lessThanVar(isolatedMonomial,*i)) 02027 isolatedMonomial = *i; 02028 return isolatedMonomial; 02029 } 02030 02031 ExprMap<Expr> var2monomial; 02032 vector<Expr> vars; 02033 Expr::iterator i = right.begin(), iend = right.end(); 02034 for(;i != iend; ++i) { 02035 if(i->isRational()) 02036 continue; 02037 Expr c, var; 02038 separateMonomial(*i, c, var); 02039 var2monomial[var] = *i; 02040 vars.push_back(var); 02041 } 02042 02043 vector<Expr> largest; 02044 d_graph.selectLargest(vars, largest); 02045 DebugAssert(0 < largest.size(), 02046 "TheoryArithOld::pickMonomial: selectLargest: failed!!!!"); 02047 02048 // DEJAN: Rafine the largest by coefficient values 02049 vector<Expr> largest_small_coeff; 02050 selectSmallestByCoefficient(largest, largest_small_coeff); 02051 DebugAssert(0 < largest_small_coeff.size(), "TheoryArithOld::pickMonomial: selectLargestByCOefficient: failed!!!!"); 02052 02053 size_t pickedVar = 0; 02054 // Pick the variable which will generate the fewest number of 02055 // projections 02056 02057 size_t size = largest_small_coeff.size(); 02058 int minProjections = -1; 02059 if (size > 1) 02060 for(size_t k=0; k< size; ++k) { 02061 const Expr& var(largest_small_coeff[k]), monom(var2monomial[var]); 02062 // Grab the counters for the variable 02063 int nRight = (d_countRight.count(var) > 0)? d_countRight[var] : 0; 02064 int nLeft = (d_countLeft.count(var) > 0)? d_countLeft[var] : 0; 02065 int n(nRight*nLeft); 02066 TRACE("arith ineq", "pickMonomial: var=", var, 02067 ", nRight="+int2string(nRight)+", nLeft="+int2string(nLeft)); 02068 if(minProjections < 0 || minProjections > n) { 02069 minProjections = n; 02070 pickedVar = k; 02071 } 02072 TRACE("arith ineq", "Number of projections for "+var.toString()+" = ", n, ""); 02073 } 02074 02075 02076 const Expr& largestVar = largest_small_coeff[pickedVar]; 02077 // FIXME: TODO: update the counters (subtract counts for the vars 02078 // other than largestVar 02079 02080 // Update the graph (all edges to the largest in the graph, not just the small coefficients). 02081 for(size_t k = 0; k < vars.size(); ++k) { 02082 if(vars[k] != largestVar) 02083 d_graph.addEdge(largestVar, vars[k]); 02084 } 02085 02086 TRACE("arith buffer", "picked var : ", var2monomial[largestVar].toString(), ""); 02087 02088 return var2monomial[largestVar]; 02089 } 02090 02091 void TheoryArithOld::VarOrderGraph::addEdge(const Expr& e1, const Expr& e2) 02092 { 02093 TRACE("arith var order", "addEdge("+e1.toString()+" > ", e2, ")"); 02094 DebugAssert(e1 != e2, "TheoryArithOld::VarOrderGraph::addEdge(" 02095 +e1.toString()+", "+e2.toString()+")"); 02096 d_edges[e1].push_back(e2); 02097 } 02098 02099 //returns true if e1 < e2, else false(i.e e2 < e1 or e1,e2 are not 02100 //comparable) 02101 bool TheoryArithOld::VarOrderGraph::lessThan(const Expr& e1, const Expr& e2) 02102 { 02103 d_cache.clear(); 02104 //returns true if e1 is in the subtree rooted at e2 implying e1 < e2 02105 return dfs(e1,e2); 02106 } 02107 02108 //returns true if e1 is in the subtree rooted at e2 implying e1 < e2 02109 bool TheoryArithOld::VarOrderGraph::dfs(const Expr& e1, const Expr& e2) 02110 { 02111 if(e1 == e2) 02112 return true; 02113 if(d_cache.count(e2) > 0) 02114 return false; 02115 if(d_edges.count(e2) == 0) 02116 return false; 02117 d_cache[e2] = true; 02118 vector<Expr>& e2Edges = d_edges[e2]; 02119 vector<Expr>::iterator i = e2Edges.begin(); 02120 vector<Expr>::iterator iend = e2Edges.end(); 02121 //if dfs finds e1 then i != iend else i is equal to iend 02122 for(; i != iend && !dfs(e1,*i); ++i); 02123 return (i != iend); 02124 } 02125 02126 void TheoryArithOld::VarOrderGraph::dfs(const Expr& v, vector<Expr>& output_list) 02127 { 02128 TRACE("arith shared", "dfs(", v.toString(), ")"); 02129 02130 // If visited already we are done 02131 if (d_cache.count(v) > 0) return; 02132 02133 // Dfs further 02134 if(d_edges.count(v) != 0) { 02135 // We have edges, so lets dfs it further 02136 vector<Expr>& vEdges = d_edges[v]; 02137 vector<Expr>::iterator e = vEdges.begin(); 02138 vector<Expr>::iterator e_end = vEdges.end(); 02139 while (e != e_end) { 02140 dfs(*e, output_list); 02141 e ++; 02142 } 02143 } 02144 02145 // Mark as visited and add to the output list 02146 d_cache[v] = true; 02147 output_list.push_back(v); 02148 } 02149 02150 void TheoryArithOld::VarOrderGraph::getVerticesTopological(vector<Expr>& output_list) 02151 { 02152 // Clear the cache 02153 d_cache.clear(); 02154 output_list.clear(); 02155 02156 // Go through all the vertices and run a dfs from them 02157 ExprMap< vector<Expr> >::iterator v_it = d_edges.begin(); 02158 ExprMap< vector<Expr> >::iterator v_it_end = d_edges.end(); 02159 while (v_it != v_it_end) 02160 { 02161 // Run dfs from this vertex 02162 dfs(v_it->first, output_list); 02163 // Go to the next one 02164 v_it ++; 02165 } 02166 } 02167 02168 void TheoryArithOld::VarOrderGraph::selectSmallest(vector<Expr>& v1, 02169 vector<Expr>& v2) 02170 { 02171 int v1Size = v1.size(); 02172 vector<bool> v3(v1Size); 02173 for(int j=0; j < v1Size; ++j) 02174 v3[j] = false; 02175 02176 for(int j=0; j < v1Size; ++j) { 02177 if(v3[j]) continue; 02178 for(int i =0; i < v1Size; ++i) { 02179 if((i == j) || v3[i]) 02180 continue; 02181 if(lessThan(v1[i],v1[j])) { 02182 v3[j] = true; 02183 break; 02184 } 02185 } 02186 } 02187 vector<Expr> new_v1; 02188 02189 for(int j = 0; j < v1Size; ++j) 02190 if(!v3[j]) v2.push_back(v1[j]); 02191 else new_v1.push_back(v1[j]); 02192 v1 = new_v1; 02193 } 02194 02195 02196 void TheoryArithOld::VarOrderGraph::selectLargest(const vector<Expr>& v1, 02197 vector<Expr>& v2) 02198 { 02199 int v1Size = v1.size(); 02200 vector<bool> v3(v1Size); 02201 for(int j=0; j < v1Size; ++j) 02202 v3[j] = false; 02203 02204 for(int j=0; j < v1Size; ++j) { 02205 if(v3[j]) continue; 02206 for(int i =0; i < v1Size; ++i) { 02207 if((i == j) || v3[i]) 02208 continue; 02209 if(lessThan(v1[j],v1[i])) { 02210 v3[j] = true; 02211 break; 02212 } 02213 } 02214 } 02215 02216 for(int j = 0; j < v1Size; ++j) 02217 if(!v3[j]) v2.push_back(v1[j]); 02218 } 02219 02220 /////////////////////////////////////////////////////////////////////////////// 02221 // TheoryArithOld Public Methods // 02222 /////////////////////////////////////////////////////////////////////////////// 02223 02224 02225 TheoryArithOld::TheoryArithOld(TheoryCore* core) 02226 : TheoryArith(core, "ArithmeticOld"), 02227 d_diseq(core->getCM()->getCurrentContext()), 02228 d_diseqIdx(core->getCM()->getCurrentContext(), 0, 0), 02229 diseqSplitAlready(core->getCM()->getCurrentContext()), 02230 d_inModelCreation(core->getCM()->getCurrentContext(), false, 0), 02231 d_freeConstDB(core->getCM()->getCurrentContext()), 02232 d_buffer_0(core->getCM()->getCurrentContext()), 02233 d_buffer_1(core->getCM()->getCurrentContext()), 02234 d_buffer_2(core->getCM()->getCurrentContext()), 02235 d_buffer_3(core->getCM()->getCurrentContext()), 02236 // Initialize index to 0 at scope 0 02237 d_bufferIdx_0(core->getCM()->getCurrentContext(), 0, 0), 02238 d_bufferIdx_1(core->getCM()->getCurrentContext(), 0, 0), 02239 d_bufferIdx_2(core->getCM()->getCurrentContext(), 0, 0), 02240 d_bufferIdx_3(core->getCM()->getCurrentContext(), 0, 0), 02241 diff_logic_size(core->getCM()->getCurrentContext(), 0, 0), 02242 d_bufferThres(&(core->getFlags()["ineq-delay"].getInt())), 02243 d_splitSign(&(core->getFlags()["nonlinear-sign-split"].getBool())), 02244 d_grayShadowThres(&(core->getFlags()["grayshadow-threshold"].getInt())), 02245 d_countRight(core->getCM()->getCurrentContext()), 02246 d_countLeft(core->getCM()->getCurrentContext()), 02247 d_sharedTerms(core->getCM()->getCurrentContext()), 02248 d_sharedTermsList(core->getCM()->getCurrentContext()), 02249 d_sharedVars(core->getCM()->getCurrentContext()), 02250 bufferedInequalities(core->getCM()->getCurrentContext()), 02251 termLowerBound(core->getCM()->getCurrentContext()), 02252 termLowerBoundThm(core->getCM()->getCurrentContext()), 02253 termUpperBound(core->getCM()->getCurrentContext()), 02254 termUpperBoundThm(core->getCM()->getCurrentContext()), 02255 alreadyProjected(core->getCM()->getCurrentContext()), 02256 dontBuffer(core->getCM()->getCurrentContext()), 02257 diffLogicOnly(core->getCM()->getCurrentContext(), true, 0), 02258 diffLogicGraph(0, core, 0, core->getCM()->getCurrentContext()), 02259 shared_index_1(core->getCM()->getCurrentContext(), 0, 0), 02260 shared_index_2(core->getCM()->getCurrentContext(), 0, 0), 02261 termUpperBounded(core->getCM()->getCurrentContext()), 02262 termLowerBounded(core->getCM()->getCurrentContext()), 02263 termConstrainedBelow(core->getCM()->getCurrentContext()), 02264 termConstrainedAbove(core->getCM()->getCurrentContext()) 02265 { 02266 IF_DEBUG(d_diseq.setName("CDList[TheoryArithOld::d_diseq]");) 02267 IF_DEBUG(d_buffer_0.setName("CDList[TheoryArithOld::d_buffer_0]");) 02268 IF_DEBUG(d_buffer_1.setName("CDList[TheoryArithOld::d_buffer_1]");) 02269 IF_DEBUG(d_buffer_2.setName("CDList[TheoryArithOld::d_buffer_2]");) 02270 IF_DEBUG(d_buffer_3.setName("CDList[TheoryArithOld::d_buffer_3]");) 02271 IF_DEBUG(d_bufferIdx_1.setName("CDList[TheoryArithOld::d_bufferIdx_0]");) 02272 IF_DEBUG(d_bufferIdx_1.setName("CDList[TheoryArithOld::d_bufferIdx_1]");) 02273 IF_DEBUG(d_bufferIdx_2.setName("CDList[TheoryArithOld::d_bufferIdx_2]");) 02274 IF_DEBUG(d_bufferIdx_3.setName("CDList[TheoryArithOld::d_bufferIdx_3]");) 02275 02276 getEM()->newKind(REAL, "_REAL", true); 02277 getEM()->newKind(INT, "_INT", true); 02278 getEM()->newKind(SUBRANGE, "_SUBRANGE", true); 02279 02280 getEM()->newKind(UMINUS, "_UMINUS"); 02281 getEM()->newKind(PLUS, "_PLUS"); 02282 getEM()->newKind(MINUS, "_MINUS"); 02283 getEM()->newKind(MULT, "_MULT"); 02284 getEM()->newKind(DIVIDE, "_DIVIDE"); 02285 getEM()->newKind(POW, "_POW"); 02286 getEM()->newKind(INTDIV, "_INTDIV"); 02287 getEM()->newKind(MOD, "_MOD"); 02288 getEM()->newKind(LT, "_LT"); 02289 getEM()->newKind(LE, "_LE"); 02290 getEM()->newKind(GT, "_GT"); 02291 getEM()->newKind(GE, "_GE"); 02292 getEM()->newKind(IS_INTEGER, "_IS_INTEGER"); 02293 getEM()->newKind(NEGINF, "_NEGINF"); 02294 getEM()->newKind(POSINF, "_POSINF"); 02295 getEM()->newKind(DARK_SHADOW, "_DARK_SHADOW"); 02296 getEM()->newKind(GRAY_SHADOW, "_GRAY_SHADOW"); 02297 02298 getEM()->newKind(REAL_CONST, "_REAL_CONST"); 02299 02300 d_kinds.push_back(REAL); 02301 d_kinds.push_back(INT); 02302 d_kinds.push_back(SUBRANGE); 02303 d_kinds.push_back(IS_INTEGER); 02304 d_kinds.push_back(UMINUS); 02305 d_kinds.push_back(PLUS); 02306 d_kinds.push_back(MINUS); 02307 d_kinds.push_back(MULT); 02308 d_kinds.push_back(DIVIDE); 02309 d_kinds.push_back(POW); 02310 d_kinds.push_back(INTDIV); 02311 d_kinds.push_back(MOD); 02312 d_kinds.push_back(LT); 02313 d_kinds.push_back(LE); 02314 d_kinds.push_back(GT); 02315 d_kinds.push_back(GE); 02316 d_kinds.push_back(RATIONAL_EXPR); 02317 d_kinds.push_back(NEGINF); 02318 d_kinds.push_back(POSINF); 02319 d_kinds.push_back(DARK_SHADOW); 02320 d_kinds.push_back(GRAY_SHADOW); 02321 d_kinds.push_back(REAL_CONST); 02322 02323 registerTheory(this, d_kinds, true); 02324 02325 d_rules = createProofRulesOld(); 02326 diffLogicGraph.setRules(d_rules); 02327 diffLogicGraph.setArith(this); 02328 02329 d_realType = Type(getEM()->newLeafExpr(REAL)); 02330 d_intType = Type(getEM()->newLeafExpr(INT)); 02331 02332 // Make the zero variable 02333 Theorem thm_exists_zero = getCommonRules()->varIntroSkolem(rat(0)); 02334 zero = thm_exists_zero.getExpr()[1]; 02335 } 02336 02337 02338 // Destructor: delete the proof rules class if it's present 02339 TheoryArithOld::~TheoryArithOld() { 02340 if(d_rules != NULL) delete d_rules; 02341 // Clear the inequality databases 02342 for(ExprMap<CDList<Ineq> *>::iterator i=d_inequalitiesRightDB.begin(), 02343 iend=d_inequalitiesRightDB.end(); i!=iend; ++i) { 02344 delete (i->second); 02345 free(i->second); 02346 } 02347 for(ExprMap<CDList<Ineq> *>::iterator i=d_inequalitiesLeftDB.begin(), 02348 iend=d_inequalitiesLeftDB.end(); i!=iend; ++i) { 02349 delete (i->second); 02350 free (i->second); 02351 } 02352 unregisterTheory(this, d_kinds, true); 02353 } 02354 02355 void TheoryArithOld::collectVars(const Expr& e, vector<Expr>& vars, 02356 set<Expr>& cache) { 02357 // Check the cache first 02358 if(cache.count(e) > 0) return; 02359 // Not processed yet. Cache the expression and proceed 02360 cache.insert(e); 02361 if(isLeaf(e)) vars.push_back(e); 02362 else 02363 for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) 02364 collectVars(*i, vars, cache); 02365 } 02366 02367 void 02368 TheoryArithOld::processFiniteInterval 02369 (const Theorem& alphaLEax, 02370 const Theorem& bxLEbeta) { 02371 const Expr& ineq1(alphaLEax.getExpr()); 02372 const Expr& ineq2(bxLEbeta.getExpr()); 02373 DebugAssert(isLE(ineq1), "TheoryArithOld::processFiniteInterval: ineq1 = " 02374 +ineq1.toString()); 02375 DebugAssert(isLE(ineq2), "TheoryArithOld::processFiniteInterval: ineq2 = " 02376 +ineq2.toString()); 02377 // If the inequalities are not integer, just return (nothing to do) 02378 if(!isInteger(ineq1[0]) 02379 || !isInteger(ineq1[1]) 02380 || !isInteger(ineq2[0]) 02381 || !isInteger(ineq2[1])) 02382 return; 02383 02384 const Expr& ax = ineq1[1]; 02385 const Expr& bx = ineq2[0]; 02386 DebugAssert(!isPlus(ax) && !isRational(ax), 02387 "TheoryArithOld::processFiniteInterval:\n ax = "+ax.toString()); 02388 DebugAssert(!isPlus(bx) && !isRational(bx), 02389 "TheoryArithOld::processFiniteInterval:\n bx = "+bx.toString()); 02390 Expr a = isMult(ax)? ax[0] : rat(1); 02391 Expr b = isMult(bx)? bx[0] : rat(1); 02392 02393 Theorem thm1(alphaLEax), thm2(bxLEbeta); 02394 // Multiply the inequalities by 'b' and 'a', and canonize them, if necessary 02395 if(a != b) { 02396 thm1 = canonPred(iffMP(alphaLEax, d_rules->multIneqn(ineq1, b))); 02397 thm2 = canonPred(iffMP(bxLEbeta, d_rules->multIneqn(ineq2, a))); 02398 } 02399 // Check that a*beta - b*alpha == c > 0 02400 const Expr& alphaLEt = thm1.getExpr(); 02401 const Expr& alpha = alphaLEt[0]; 02402 const Expr& t = alphaLEt[1]; 02403 const Expr& beta = thm2.getExpr()[1]; 02404 Expr c = canon(beta - alpha).getRHS(); 02405 02406 if(c.isRational() && c.getRational() >= 1) { 02407 // This is a finite interval. First, derive t <= alpha + c: 02408 // canon(alpha+c) => (alpha+c == beta) ==> [symmetry] beta == alpha+c 02409 // Then substitute that in thm2 02410 Theorem bEQac = symmetryRule(canon(alpha + c)); 02411 // Substitute beta == alpha+c for the second child of thm2 02412 vector<unsigned> changed; 02413 vector<Theorem> thms; 02414 changed.push_back(1); 02415 thms.push_back(bEQac); 02416 Theorem tLEac = substitutivityRule(thm2.getExpr(), changed, thms); 02417 tLEac = iffMP(thm2, tLEac); 02418 // Derive and enqueue the finite interval constraint 02419 Theorem isInta(isIntegerThm(alpha)); 02420 Theorem isIntt(isIntegerThm(t)); 02421 if (d_sharedTerms.find(thm1.getExpr()[1]) != d_sharedTerms.end()) 02422 enqueueFact(d_rules->finiteInterval(thm1, tLEac, isInta, isIntt)); 02423 } 02424 } 02425 02426 02427 void 02428 TheoryArithOld::processFiniteIntervals(const Expr& x) { 02429 // If x is not integer, do not bother 02430 if(!isInteger(x)) return; 02431 // Process every pair of the opposing inequalities for 'x' 02432 ExprMap<CDList<Ineq> *>::iterator iLeft, iRight; 02433 iLeft = d_inequalitiesLeftDB.find(x); 02434 if(iLeft == d_inequalitiesLeftDB.end()) return; 02435 iRight = d_inequalitiesRightDB.find(x); 02436 if(iRight == d_inequalitiesRightDB.end()) return; 02437 // There are some opposing inequalities; get the lists 02438 CDList<Ineq>& ineqsLeft = *(iLeft->second); 02439 CDList<Ineq>& ineqsRight = *(iRight->second); 02440 // Get the sizes of the lists 02441 size_t sizeLeft = ineqsLeft.size(); 02442 size_t sizeRight = ineqsRight.size(); 02443 // Process all the pairs of the opposing inequalities 02444 for(size_t l=0; l<sizeLeft; ++l) 02445 for(size_t r=0; r<sizeRight; ++r) 02446 processFiniteInterval(ineqsRight[r], ineqsLeft[l]); 02447 } 02448 02449 /*! This function recursively decends expression tree <strong>without 02450 * caching</strong> until it hits a node that is already setup. Be 02451 * careful on what expressions you are calling it. 02452 */ 02453 void 02454 TheoryArithOld::setupRec(const Expr& e) { 02455 if(e.hasFind()) return; 02456 // First, set up the kids recursively 02457 for (int k = 0; k < e.arity(); ++k) { 02458 setupRec(e[k]); 02459 } 02460 // Create a find pointer for e 02461 e.setFind(reflexivityRule(e)); 02462 e.setEqNext(reflexivityRule(e)); 02463 // And call our own setup() 02464 setup(e); 02465 } 02466 02467 02468 void TheoryArithOld::addSharedTerm(const Expr& e) { 02469 return; 02470 if (d_sharedTerms.find(e) == d_sharedTerms.end()) { 02471 d_sharedTerms[e] = true; 02472 d_sharedTermsList.push_back(e); 02473 } 02474 } 02475 02476 02477 void TheoryArithOld::assertFact(const Theorem& e) 02478 { 02479 TRACE("arith assert", "assertFact(", e.getExpr().toString(), ")"); 02480 02481 // Pick up any multiplicative case splits and enqueue them 02482 for (unsigned i = 0; i < multiplicativeSignSplits.size(); i ++) 02483 enqueueFact(multiplicativeSignSplits[i]); 02484 multiplicativeSignSplits.clear(); 02485 02486 const Expr& expr = e.getExpr(); 02487 if (expr.isNot() && expr[0].isEq()) { 02488 IF_DEBUG(debugger.counter("[arith] received disequalities")++;) 02489 02490 // Expr eq = expr[0]; 02491 // 02492 // // We want to expand on difference logic disequalities as soon as possible 02493 // bool diff_logic = false; 02494 // if (eq[1].isRational() && eq[1].getRational() == 0) { 02495 // if (!isPlus(eq[0])) { 02496 // if (isLeaf(eq[0])) diff_logic = true; 02497 // } 02498 // else { 02499 // int arity = eq[0].arity(); 02500 // if (arity <= 2) { 02501 // if (eq[0][0].isRational()) 02502 // diff_logic = true; 02503 // else { 02504 // Expr ax = eq[0][0], a, x; 02505 // Expr by = eq[0][1], b, y; 02506 // separateMonomial(ax, a, x); 02507 // separateMonomial(by, b, y); 02508 // if (isLeaf(x) && isLeaf(y)) 02509 // if ((a.getRational() == 1 && b.getRational() == -1) || 02510 // (a.getRational() == -1 && b.getRational() == 1)) 02511 // diff_logic = true; 02512 // } 02513 // } 02514 // if (arity == 3 && eq[0][0].isRational()) { 02515 // Expr ax = eq[0][1], a, x; 02516 // Expr by = eq[0][2], b, y; 02517 // separateMonomial(ax, a, x); 02518 // separateMonomial(by, b, y); 02519 // if (isLeaf(x) && isLeaf(y)) 02520 // if ((a.getRational() == 1 && b.getRational() == -1) || 02521 // (a.getRational() == -1 && b.getRational() == 1)) 02522 // diff_logic = true; 02523 // } 02524 // } 02525 // } 02526 // 02527 // if (diff_logic) 02528 // enqueueFact(d_rules->diseqToIneq(e)); 02529 // else 02530 d_diseq.push_back(e); 02531 } 02532 else if (!expr.isEq()){ 02533 if (expr.isNot()) { 02534 // If expr[0] is asserted to *not* be an integer, we track it 02535 // so we will detect if it ever becomes equal to an integer. 02536 if (expr[0].getKind() == IS_INTEGER) { 02537 expr[0][0].addToNotify(this, expr[0]); 02538 } 02539 // This can only be negation of dark or gray shadows, or 02540 // disequalities, which we ignore. Negations of inequalities 02541 // are handled in rewrite, we don't even receive them here. 02542 02543 // if (isGrayShadow(expr[0])) { 02544 // TRACE("arith gray", "expanding ", expr.toString(), ""); 02545 // Theorem expand = d_rules->expandGrayShadowRewrite(expr[0]); 02546 // enqueueFact(iffMP(e, substitutivityRule(expr, 0, expand))); 02547 // } 02548 02549 } 02550 else if(isDarkShadow(expr)) { 02551 enqueueFact(d_rules->expandDarkShadow(e)); 02552 IF_DEBUG(debugger.counter("received DARK_SHADOW")++;) 02553 } 02554 else if(isGrayShadow(expr)) { 02555 IF_DEBUG(debugger.counter("received GRAY_SHADOW")++;) 02556 const Rational& c1 = expr[2].getRational(); 02557 const Rational& c2 = expr[3].getRational(); 02558 02559 // If gray shadow bigger than the treshold, we are done 02560 if (*d_grayShadowThres > -1 && (c2 - c1 > *d_grayShadowThres)) { 02561 setIncomplete("Some gray shadows ignored due to threshold"); 02562 return; 02563 } 02564 02565 const Expr& v = expr[0]; 02566 const Expr& ee = expr[1]; 02567 if(c1 == c2) 02568 enqueueFact(d_rules->expandGrayShadow0(e)); 02569 else { 02570 Theorem gThm(e); 02571 // Check if we can reduce the number of cases in G(ax,c,c1,c2) 02572 if(ee.isRational() && isMult(v) 02573 && v[0].isRational() && v[0].getRational() >= 2) { 02574 IF_DEBUG(debugger.counter("reduced const GRAY_SHADOW")++;) 02575 gThm = d_rules->grayShadowConst(e); 02576 } 02577 // (Possibly) new gray shadow 02578 const Expr& g = gThm.getExpr(); 02579 if(g.isFalse()) 02580 setInconsistent(gThm); 02581 else if(g[2].getRational() == g[3].getRational()) 02582 enqueueFact(d_rules->expandGrayShadow0(gThm)); 02583 else if(g[3].getRational() - g[2].getRational() <= 5) { 02584 // Assert c1+e <= v <= c2+e 02585 enqueueFact(d_rules->expandGrayShadow(gThm)); 02586 // Split G into 2 cases x = l_bound and the other 02587 Theorem thm2 = d_rules->splitGrayShadowSmall(gThm); 02588 enqueueFact(thm2); 02589 } 02590 else { 02591 // Assert c1+e <= v <= c2+e 02592 enqueueFact(d_rules->expandGrayShadow(gThm)); 02593 // Split G into 2 cases (binary search b/w c1 and c2) 02594 Theorem thm2 = d_rules->splitGrayShadow(gThm); 02595 enqueueFact(thm2); 02596 // Fetch the two gray shadows 02597 // DebugAssert(thm2.getExpr().isAnd() && thm2.getExpr().arity()==2, 02598 // "thm2 = "+thm2.getExpr().toString()); 02599 // const Expr& G1orG2 = thm2.getExpr()[0]; 02600 // DebugAssert(G1orG2.isOr() && G1orG2.arity()==2, 02601 // "G1orG2 = "+G1orG2.toString()); 02602 // const Expr& G1 = G1orG2[0]; 02603 // const Expr& G2 = G1orG2[1]; 02604 // DebugAssert(G1.getKind()==GRAY_SHADOW, "G1 = "+G1.toString()); 02605 // DebugAssert(G2.getKind()==GRAY_SHADOW, "G2 = "+G2.toString()); 02606 // // Split on the left disjunct first (keep the priority low) 02607 // Expr tmp = simplifyExpr(G1); 02608 // if (!tmp.isBoolConst()) 02609 // addSplitter(tmp, 1); 02610 // tmp = simplifyExpr(G2); 02611 // if (!tmp.isBoolConst()) 02612 // addSplitter(tmp, -1); 02613 } 02614 } 02615 } 02616 else { 02617 DebugAssert(isLE(expr) || isLT(expr) || isIntPred(expr), 02618 "expected LE or LT: "+expr.toString()); 02619 if(isLE(expr) || isLT(expr)) { 02620 IF_DEBUG(debugger.counter("recevied inequalities")++;) 02621 02622 // // Assert the equivalent negated inequality 02623 // Theorem thm; 02624 // if (isLE(expr)) thm = d_rules->negatedInequality(!gtExpr(expr[0],expr[1])); 02625 // else thm = d_rules->negatedInequality(!geExpr(expr[0],expr[1])); 02626 // thm = symmetryRule(thm); 02627 // Theorem thm2 = simplify(thm.getRHS()[0]); 02628 // DebugAssert(thm2.getLHS() != thm2.getRHS(), "Expected rewrite"); 02629 // thm2 = getCommonRules()->substitutivityRule(thm.getRHS(), thm2); 02630 // thm = transitivityRule(thm, thm2); 02631 // enqueueFact(iffMP(e, thm)); 02632 02633 // Buffer the inequality 02634 addToBuffer(e); 02635 02636 unsigned total_buf_size = d_buffer_0.size() + d_buffer_1.size() + d_buffer_2.size() + d_buffer_3.size(); 02637 unsigned processed = d_bufferIdx_0 + d_bufferIdx_1 + d_bufferIdx_2 + d_bufferIdx_3; 02638 TRACE("arith ineq", "buffer.size() = ", total_buf_size, 02639 ", index="+int2string(processed) 02640 +", threshold="+int2string(*d_bufferThres)); 02641 02642 if(!diffLogicOnly && *d_bufferThres >= 0 && (total_buf_size > *d_bufferThres + processed) && !d_inModelCreation) { 02643 processBuffer(); 02644 } 02645 } else { 02646 IF_DEBUG(debugger.counter("arith IS_INTEGER")++;) 02647 if (!isInteger(expr[0])) { 02648 enqueueFact(d_rules->IsIntegerElim(e)); 02649 } 02650 } 02651 } 02652 } 02653 else { 02654 IF_DEBUG(debugger.counter("[arith] received t1=t2")++;) 02655 02656 // const Expr lhs = e.getExpr()[0]; 02657 // const Expr rhs = e.getExpr()[1]; 02658 // 02659 // CDMap<Expr, Rational>::iterator l_bound_find = termLowerBound[lhs]; 02660 // if (l_bound_find != termLowerBound.end()) { 02661 // Rational lhs_bound = (*l_bound_find).second; 02662 // CDMap<Expr, Rational>::iterator l_bound_find_rhs = termLowerBound[rhs]; 02663 // if (l_bound_find_rhs != termLowerBound.end()) { 02664 // 02665 // } else { 02666 // // Add the new bound for the rhs 02667 // termLowerBound[rhs] = lhs_bound; 02668 // termLowerBoundThm = 02669 // } 02670 // 02671 // } 02672 02673 02674 } 02675 } 02676 02677 02678 void TheoryArithOld::checkSat(bool fullEffort) 02679 { 02680 // vector<Expr>::const_iterator e; 02681 // vector<Expr>::const_iterator eEnd; 02682 // TODO: convert back to use iterators 02683 TRACE("arith checksat", "checksat(fullEffort = ", fullEffort? "true, modelCreation = " : "false, modelCreation = ", (d_inModelCreation ? "true)" : "false)")); 02684 TRACE("arith ineq", "TheoryArithOld::checkSat(fullEffort=", 02685 fullEffort? "true" : "false", ")"); 02686 if (fullEffort) { 02687 02688 // Process the buffer if necessary 02689 if (!inconsistent()) 02690 processBuffer(); 02691 02692 // Expand the needded inequalitites 02693 int total_buffer_size = d_buffer_0.size() + d_buffer_1.size() + d_buffer_2.size() + d_buffer_3.size(); 02694 02695 int constrained_vars = 0; 02696 if (!inconsistent() && total_buffer_size > 0) 02697 constrained_vars = computeTermBounds(); 02698 02699 bool something_enqueued = false; 02700 02701 if (d_inModelCreation || (!inconsistent() && total_buffer_size > 0 && constrained_vars > 0)) { 02702 // If in model creation we might have to reconsider some of the dis-equalities 02703 if (d_inModelCreation) d_diseqIdx = 0; 02704 02705 // Now go and try to split 02706 for(; d_diseqIdx < d_diseq.size(); d_diseqIdx = d_diseqIdx+1) { 02707 TRACE("model", "[arith] refining diseq: ", d_diseq[d_diseqIdx].getExpr() , ""); 02708 02709 // Get the disequality theorem and the expression 02710 Theorem diseqThm = d_diseq[d_diseqIdx]; 02711 Expr diseq = diseqThm.getExpr(); 02712 02713 // If we split on this one already 02714 if (diseqSplitAlready.find(diseq) != diseqSplitAlready.end()) continue; 02715 02716 // Get the equality 02717 Expr eq = diseq[0]; 02718 02719 // Get the left-hand-side and the right-hands side 02720 Expr lhs = eq[0]; 02721 Expr rhs = eq[1]; 02722 DebugAssert(lhs.hasFind() && rhs.hasFind(), "Part of dis-equality has no find!"); 02723 lhs = find(lhs).getRHS(); 02724 rhs = find(rhs).getRHS(); 02725 02726 // If the value of the equality is already determined by instantiation, we just skip it 02727 // This can happen a lot as we infer equalities in difference logic 02728 if (lhs.isRational() && rhs.isRational()) { 02729 TRACE("arith diseq", "disequality already evaluated : ", diseq.toString(), ""); 02730 continue; 02731 } 02732 02733 // We can allow ourselfs not to care about specific values if we are 02734 // not in model creation 02735 if (!d_inModelCreation) { 02736 // If the left or the right hand side is unbounded, we don't care right now 02737 if (!isConstrained(lhs) || !isConstrained(rhs)) continue; 02738 if (getUpperBound(lhs) < getLowerBound(rhs)) continue; 02739 if (getUpperBound(rhs) < getLowerBound(lhs)) continue; 02740 } 02741 02742 TRACE("arith ineq", "[arith] refining diseq: ", d_diseq[d_diseqIdx].getExpr() , ""); 02743 02744 // We don't know the value of the disequlaity, split on it (for now) 02745 enqueueFact(d_rules->diseqToIneq(diseqThm)); 02746 something_enqueued = true; 02747 02748 // Mark it as split already 02749 diseqSplitAlready[diseq] = true; 02750 } 02751 } 02752 02753 IF_DEBUG( 02754 { 02755 bool dejans_printouts = false; 02756 if (dejans_printouts) { 02757 cerr << "Disequalities after CheckSat" << endl; 02758 for (unsigned i = 0; i < d_diseq.size(); i ++) { 02759 Expr diseq = d_diseq[i].getExpr(); 02760 Expr d_find = find(diseq[0]).getRHS(); 02761 cerr << diseq.toString() << ":" << d_find.toString() << endl; 02762 } 02763 cerr << "Arith Buffer after CheckSat (0)" << endl; 02764 for (unsigned i = 0; i < d_buffer_0.size(); i ++) { 02765 Expr ineq = d_buffer_0[i].getExpr(); 02766 Expr rhs = find(ineq[1]).getRHS(); 02767 cerr << ineq.toString() << ":" << rhs.toString() << endl; 02768 } 02769 cerr << "Arith Buffer after CheckSat (1)" << endl; 02770 for (unsigned i = 0; i < d_buffer_1.size(); i ++) { 02771 Expr ineq = d_buffer_1[i].getExpr(); 02772 Expr rhs = find(ineq[1]).getRHS(); 02773 cerr << ineq.toString() << ":" << rhs.toString() << endl; 02774 } 02775 cerr << "Arith Buffer after CheckSat (2)" << endl; 02776 for (unsigned i = 0; i < d_buffer_2.size(); i ++) { 02777 Expr ineq = d_buffer_2[i].getExpr(); 02778 Expr rhs = find(ineq[1]).getRHS(); 02779 cerr << ineq.toString() << ":" << rhs.toString() << endl; 02780 } 02781 cerr << "Arith Buffer after CheckSat (3)" << endl; 02782 for (unsigned i = 0; i < d_buffer_3.size(); i ++) { 02783 Expr ineq = d_buffer_3[i].getExpr(); 02784 Expr rhs = find(ineq[1]).getRHS(); 02785 cerr << ineq.toString() << ":" << rhs.toString() << endl; 02786 } 02787 } 02788 } 02789 ) 02790 } 02791 } 02792 02793 02794 02795 void TheoryArithOld::refineCounterExample() 02796 { 02797 d_inModelCreation = true; 02798 TRACE("model", "refineCounterExample[TheoryArithOld] ", "", "{"); 02799 CDMap<Expr, bool>::iterator it = d_sharedTerms.begin(), it2, 02800 iend = d_sharedTerms.end(); 02801 // Add equalities over all pairs of shared terms as suggested 02802 // splitters. Notice, that we want to split on equality 02803 // (positively) first, to reduce the size of the model. 02804 for(; it!=iend; ++it) { 02805 // Copy by value: the elements in the pair from *it are NOT refs in CDMap 02806 Expr e1 = (*it).first; 02807 for(it2 = it, ++it2; it2!=iend; ++it2) { 02808 Expr e2 = (*it2).first; 02809 DebugAssert(isReal(getBaseType(e1)), 02810 "TheoryArithOld::refineCounterExample: e1 = "+e1.toString() 02811 +"\n type(e1) = "+e1.getType().toString()); 02812 if(findExpr(e1) != findExpr(e2)) { 02813 DebugAssert(isReal(getBaseType(e2)), 02814 "TheoryArithOld::refineCounterExample: e2 = "+e2.toString() 02815 +"\n type(e2) = "+e2.getType().toString()); 02816 Expr eq = simplifyExpr(e1.eqExpr(e2)); 02817 if (!eq.isBoolConst()) { 02818 addSplitter(eq); 02819 } 02820 } 02821 } 02822 } 02823 TRACE("model", "refineCounterExample[Theory::Arith] ", "", "}"); 02824 } 02825 02826 02827 void 02828 TheoryArithOld::findRationalBound(const Expr& varSide, const Expr& ratSide, 02829 const Expr& var, 02830 Rational &r) 02831 { 02832 Expr c, x; 02833 separateMonomial(varSide, c, x); 02834 02835 if (!findExpr(ratSide).isRational() && isNonlinearEq(ratSide.eqExpr(rat(0)))) 02836 throw ArithException("Could not generate the model due to non-linear arithmetic"); 02837 02838 DebugAssert(findExpr(c).isRational(), 02839 "seperateMonomial failed"); 02840 DebugAssert(findExpr(ratSide).isRational(), 02841 "smallest variable in graph, should not have variables" 02842 " in inequalities: "); 02843 DebugAssert(x == var, "separateMonomial found different variable: " 02844 + var.toString()); 02845 r = findExpr(ratSide).getRational() / findExpr(c).getRational(); 02846 } 02847 02848 bool 02849 TheoryArithOld::findBounds(const Expr& e, Rational& lub, Rational& glb) 02850 { 02851 bool strictLB=false, strictUB=false; 02852 bool right = (d_inequalitiesRightDB.count(e) > 0 02853 && d_inequalitiesRightDB[e]->size() > 0); 02854 bool left = (d_inequalitiesLeftDB.count(e) > 0 02855 && d_inequalitiesLeftDB[e]->size() > 0); 02856 int numRight = 0, numLeft = 0; 02857 if(right) { //rationals less than e 02858 CDList<Ineq> * ratsLTe = d_inequalitiesRightDB[e]; 02859 for(unsigned int i=0; i<ratsLTe->size(); i++) { 02860 DebugAssert((*ratsLTe)[i].varOnRHS(), "variable on wrong side!"); 02861 Expr ineq = (*ratsLTe)[i].ineq().getExpr(); 02862 Expr leftSide = ineq[0], rightSide = ineq[1]; 02863 Rational r; 02864 findRationalBound(rightSide, leftSide, e , r); 02865 if(numRight==0 || r>glb){ 02866 glb = r; 02867 strictLB = isLT(ineq); 02868 } 02869 numRight++; 02870 } 02871 TRACE("model", " =>Lower bound ", glb.toString(), ""); 02872 } 02873 if(left) { //rationals greater than e 02874 CDList<Ineq> * ratsGTe = d_inequalitiesLeftDB[e]; 02875 for(unsigned int i=0; i<ratsGTe->size(); i++) { 02876 DebugAssert((*ratsGTe)[i].varOnLHS(), "variable on wrong side!"); 02877 Expr ineq = (*ratsGTe)[i].ineq().getExpr(); 02878 Expr leftSide = ineq[0], rightSide = ineq[1]; 02879 Rational r; 02880 findRationalBound(leftSide, rightSide, e, r); 02881 if(numLeft==0 || r<lub) { 02882 lub = r; 02883 strictUB = isLT(ineq); 02884 } 02885 numLeft++; 02886 } 02887 TRACE("model", " =>Upper bound ", lub.toString(), ""); 02888 } 02889 if(!left && !right) { 02890 lub = 0; 02891 glb = 0; 02892 } 02893 if(!left && right) {lub = glb +2;} 02894 if(!right && left) {glb = lub-2;} 02895 DebugAssert(glb <= lub, "Greatest lower bound needs to be smaller " 02896 "than least upper bound"); 02897 return strictLB; 02898 } 02899 02900 void TheoryArithOld::assignVariables(std::vector<Expr>&v) 02901 { 02902 int count = 0; 02903 02904 if (diffLogicOnly) 02905 { 02906 // Compute the model 02907 diffLogicGraph.computeModel(); 02908 // Get values for the variables 02909 for (unsigned i = 0; i < v.size(); i ++) { 02910 Expr x = v[i]; 02911 assignValue(x, rat(diffLogicGraph.getValuation(x))); 02912 } 02913 // Done 02914 return; 02915 } 02916 02917 while (v.size() > 0) 02918 { 02919 std::vector<Expr> bottom; 02920 d_graph.selectSmallest(v, bottom); 02921 TRACE("model", "Finding variables to assign. Iteration # ", count, ""); 02922 for(unsigned int i = 0; i<bottom.size(); i++) 02923 { 02924 Expr e = bottom[i]; 02925 TRACE("model", "Found: ", e, ""); 02926 // Check if it is already a concrete constant 02927 if(e.isRational()) continue; 02928 02929 Rational lub, glb; 02930 bool strictLB; 02931 strictLB = findBounds(e, lub, glb); 02932 Rational mid; 02933 if(isInteger(e)) { 02934 if(strictLB && glb.isInteger()) 02935 mid = glb + 1; 02936 else 02937 mid = ceil(glb); 02938 } 02939 else 02940 mid = (lub + glb)/2; 02941 02942 TRACE("model", "Assigning mid = ", mid, " {"); 02943 assignValue(e, rat(mid)); 02944 TRACE("model", "Assigned find(e) = ", findExpr(e), " }"); 02945 if(inconsistent()) return; // Punt immediately if failed 02946 } 02947 count++; 02948 } 02949 } 02950 02951 void TheoryArithOld::computeModelBasic(const std::vector<Expr>& v) 02952 { 02953 d_inModelCreation = true; 02954 vector<Expr> reps; 02955 TRACE("model", "Arith=>computeModel ", "", "{"); 02956 for(unsigned int i=0; i <v.size(); ++i) { 02957 const Expr& e = v[i]; 02958 if(findExpr(e) == e) { 02959 TRACE("model", "arith variable:", e , ""); 02960 reps.push_back(e); 02961 } 02962 else { 02963 TRACE("model", "arith variable:", e , ""); 02964 TRACE("model", " ==> is defined by: ", findExpr(e) , ""); 02965 } 02966 } 02967 assignVariables(reps); 02968 TRACE("model", "Arith=>computeModel", "", "}"); 02969 d_inModelCreation = false; 02970 } 02971 02972 // For any arith expression 'e', if the subexpressions are assigned 02973 // concrete values, then find(e) must already be a concrete value. 02974 void TheoryArithOld::computeModel(const Expr& e, vector<Expr>& vars) { 02975 DebugAssert(findExpr(e).isRational(), "TheoryArithOld::computeModel(" 02976 +e.toString()+")\n e is not assigned concrete value.\n" 02977 +" find(e) = "+findExpr(e).toString()); 02978 assignValue(simplify(e)); 02979 vars.push_back(e); 02980 } 02981 02982 Theorem TheoryArithOld::checkIntegerEquality(const Theorem& thm) { 02983 02984 // Check if this is a rewrite theorem 02985 bool rewrite = thm.isRewrite(); 02986 02987 // If it's an integer theorem, then rafine it to integer domain 02988 Expr eq = (rewrite ? thm.getRHS() : thm.getExpr()); 02989 02990 TRACE("arith rafine", "TheoryArithOld::checkIntegerEquality(", eq, ")"); 02991 DebugAssert(eq.getKind() == EQ, "checkIntegerEquality: must be an equality"); 02992 02993 // Trivial equalities, we don't care 02994 if (!isPlus(eq[1]) && !isPlus(eq[0])) return thm; 02995 Expr old_sum = (isPlus(eq[1]) ? eq[1] : eq[0]); 02996 02997 // Get the sum part 02998 vector<Expr> children; 02999 bool const_is_integer = true; // Assuming only one constant is present (canon called before this) 03000 for (int i = 0; i < old_sum.arity(); i ++) 03001 if (!old_sum[i].isRational()) 03002 children.push_back(old_sum[i]); 03003 else 03004 const_is_integer = old_sum[i].getRational().isInteger(); 03005 03006 // If the constants are integers, we don't care 03007 if (const_is_integer) return thm; 03008 03009 Expr sum = (children.size() > 1 ? plusExpr(children) : children[0]); 03010 // Check for integer of the remainder of the sum 03011 Theorem isIntegerEquality = isIntegerThm(sum); 03012 // If it is an integer, it's unsat 03013 if (!isIntegerEquality.isNull()) { 03014 Theorem false_thm = d_rules->intEqualityRationalConstant(isIntegerEquality, eq); 03015 if (rewrite) return transitivityRule(thm, false_thm); 03016 else return iffMP(thm, false_thm); 03017 } 03018 else return thm; 03019 } 03020 03021 03022 Theorem TheoryArithOld::rafineInequalityToInteger(const Theorem& thm) { 03023 03024 // Check if this is a rewrite theorem 03025 bool rewrite = thm.isRewrite(); 03026 03027 // If it's an integer theorem, then rafine it to integer domain 03028 Expr ineq = (rewrite ? thm.getRHS() : thm.getExpr()); 03029 03030 TRACE("arith rafine", "TheoryArithOld::rafineInequalityToInteger(", ineq, ")"); 03031 DebugAssert(isIneq(ineq), "rafineInequalityToInteger: must be an inequality"); 03032 03033 // Trivial inequalities are rafined 03034 // if (!isPlus(ineq[1])) return thm; 03035 03036 // Get the sum part 03037 vector<Expr> children; 03038 if (isPlus(ineq[1])) { 03039 for (int i = 0; i < ineq[1].arity(); i ++) 03040 if (!ineq[1][i].isRational()) 03041 children.push_back(ineq[1][i]); 03042 } else children.push_back(ineq[1]); 03043 03044 Expr sum = (children.size() > 1 ? plusExpr(children) : children[0]); 03045 // Check for integer of the remainder of the sum 03046 Theorem isIntegerInequality = isIntegerThm(sum); 03047 // If it is an integer, do rafine it 03048 if (!isIntegerInequality.isNull()) { 03049 Theorem rafine = d_rules->rafineStrictInteger(isIntegerInequality, ineq); 03050 TRACE("arith rafine", "TheoryArithOld::rafineInequalityToInteger()", "=>", rafine.getRHS()); 03051 if (rewrite) return canonPredEquiv(transitivityRule(thm, rafine)); 03052 else return canonPred(iffMP(thm, rafine)); 03053 } 03054 else return thm; 03055 } 03056 03057 03058 03059 /*! accepts a rewrite theorem over eqn|ineqn and normalizes it 03060 * and returns a theorem to that effect. assumes e is non-trivial 03061 * i.e. e is not '0=const' or 'const=0' or '0 <= const' etc. 03062 */ 03063 Theorem TheoryArithOld::normalize(const Expr& e) { 03064 //e is an eqn or ineqn. e is not a trivial eqn or ineqn 03065 //trivial means 0 = const or 0 <= const. 03066 TRACE("arith normalize", "normalize(", e, ") {"); 03067 DebugAssert(e.isEq() || isIneq(e), 03068 "normalize: input must be Eq or Ineq: " + e.toString()); 03069 DebugAssert(!isIneq(e) || (0 == e[0].getRational()), 03070 "normalize: if (e is ineq) then e[0] must be 0" + 03071 e.toString()); 03072 if(e.isEq()) { 03073 if(e[0].isRational()) { 03074 DebugAssert(0 == e[0].getRational(), 03075 "normalize: if e is Eq and e[0] is rat then e[0]==0"); 03076 } 03077 else { 03078 //if e[0] is not rational then e[1] must be rational. 03079 DebugAssert(e[1].isRational() && 0 == e[1].getRational(), 03080 "normalize: if e is Eq and e[1] is rat then e[1]==0\n" 03081 " e = "+e.toString()); 03082 } 03083 } 03084 03085 Expr factor; 03086 if(e[0].isRational()) 03087 factor = computeNormalFactor(e[1], false); 03088 else 03089 factor = computeNormalFactor(e[0], false); 03090 03091 TRACE("arith normalize", "normalize: factor = ", factor, ""); 03092 DebugAssert(factor.getRational() > 0, 03093 "normalize: factor="+ factor.toString()); 03094 03095 Theorem thm(reflexivityRule(e)); 03096 // Now multiply the equality by the factor, unless it is 1 03097 if(factor.getRational() != 1) { 03098 int kind = e.getKind(); 03099 switch(kind) { 03100 case EQ: 03101 //TODO: DEJAN FIX 03102 thm = d_rules->multEqn(e[0], e[1], factor); 03103 // And canonize the result 03104 thm = canonPredEquiv(thm); 03105 03106 // If this is an equation of the form 0 = c + sum, c is not integer, but sum is 03107 // then equation has no solutions 03108 thm = checkIntegerEquality(thm); 03109 03110 break; 03111 case LE: 03112 case LT: 03113 case GE: 03114 case GT: { 03115 thm = d_rules->multIneqn(e, factor); 03116 // And canonize the result 03117 thm = canonPredEquiv(thm); 03118 // Try to rafine to integer domain 03119 thm = rafineInequalityToInteger(thm); 03120 break; 03121 } 03122 03123 default: 03124 // MS .net doesn't accept "..." + int 03125 ostringstream ss; 03126 ss << "normalize: control should not reach here " << kind; 03127 DebugAssert(false, ss.str()); 03128 break; 03129 } 03130 } else 03131 if (e.getKind() == EQ) 03132 thm = checkIntegerEquality(thm); 03133 03134 TRACE("arith normalize", "normalize => ", thm, " }"); 03135 return(thm); 03136 } 03137 03138 03139 Theorem TheoryArithOld::normalize(const Theorem& eIffEqn) { 03140 if (eIffEqn.isRewrite()) return transitivityRule(eIffEqn, normalize(eIffEqn.getRHS())); 03141 else return iffMP(eIffEqn, normalize(eIffEqn.getExpr())); 03142 } 03143 03144 03145 Theorem TheoryArithOld::rewrite(const Expr& e) 03146 { 03147 DebugAssert(leavesAreSimp(e), "Expected leaves to be simplified"); 03148 TRACE("arith", "TheoryArithOld::rewrite(", e, ") {"); 03149 Theorem thm; 03150 if (!e.isTerm()) { 03151 if (!e.isAbsLiteral()) { 03152 if (e.isPropAtom() && leavesAreNumConst(e)) { 03153 if (e.getSize() < 200) { 03154 Expr eNew = e; 03155 thm = reflexivityRule(eNew); 03156 while (eNew.containsTermITE()) { 03157 thm = transitivityRule(thm, getCommonRules()->liftOneITE(eNew)); 03158 DebugAssert(!thm.isRefl(), "Expected non-reflexive"); 03159 thm = transitivityRule(thm, theoryCore()->getCoreRules()->rewriteIteCond(thm.getRHS())); 03160 thm = transitivityRule(thm, simplify(thm.getRHS())); 03161 eNew = thm.getRHS(); 03162 } 03163 } 03164 else { 03165 thm = d_rules->rewriteLeavesConst(e); 03166 if (thm.isRefl()) { 03167 e.setRewriteNormal(); 03168 } 03169 else { 03170 thm = transitivityRule(thm, simplify(thm.getRHS())); 03171 } 03172 } 03173 // if (!thm.getRHS().isBoolConst()) { 03174 // e.setRewriteNormal(); 03175 // thm = reflexivityRule(e); 03176 // } 03177 } 03178 else { 03179 e.setRewriteNormal(); 03180 thm = reflexivityRule(e); 03181 } 03182 TRACE("arith", "TheoryArithOld::rewrite[non-literal] => ", thm, " }"); 03183 return thm; 03184 } 03185 switch(e.getKind()) { 03186 case EQ: 03187 { 03188 // canonical form for an equality of two leaves 03189 // is just l == r instead of 0 + (-1 * l) + r = 0. 03190 if (isLeaf(e[0]) && isLeaf(e[1])) 03191 thm = reflexivityRule(e); 03192 else { // Otherwise, it is "lhs = 0" 03193 //first convert e to the form 0=e' 03194 if((e[0].isRational() && e[0].getRational() == 0) 03195 || (e[1].isRational() && e[1].getRational() == 0)) 03196 //already in 0=e' or e'=0 form 03197 thm = reflexivityRule(e); 03198 else { 03199 thm = d_rules->rightMinusLeft(e); 03200 thm = canonPredEquiv(thm); 03201 } 03202 // Check for trivial equation 03203 if ((thm.getRHS())[0].isRational() && (thm.getRHS())[1].isRational()) { 03204 thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); 03205 } else { 03206 //else equation is non-trivial 03207 thm = normalize(thm); 03208 // Normalization may yield non-simplified terms 03209 if (!thm.getRHS().isBoolConst()) 03210 thm = canonPredEquiv(thm); 03211 } 03212 } 03213 03214 // Equations must be oriented such that lhs >= rhs as Exprs; 03215 // this ordering is given by operator<(Expr,Expr). 03216 const Expr& eq = thm.getRHS(); 03217 if(eq.isEq() && eq[0] < eq[1]) 03218 thm = transitivityRule(thm, getCommonRules()->rewriteUsingSymmetry(eq)); 03219 03220 // Check if the equation is nonlinear 03221 Expr nonlinearEq = thm.getRHS(); 03222 if (nonlinearEq.isEq() && isNonlinearEq(nonlinearEq)) { 03223 03224 TRACE("arith nonlinear", "nonlinear eq rewrite: ", nonlinearEq, ""); 03225 03226 Expr left = nonlinearEq[0]; 03227 Expr right = nonlinearEq[1]; 03228 03229 // Check for multiplicative equations, i.e. x*y = 0 03230 if (isNonlinearSumTerm(left) && right.isRational() && right.getRational() == 0) { 03231 Theorem eq_thm = d_rules->multEqZero(nonlinearEq); 03232 thm = transitivityRule(thm, eq_thm); 03233 thm = transitivityRule(thm, theoryCore()->simplify(thm.getRHS())); 03234 break; 03235 } 03236 03237 // Heuristics for a sum 03238 if (isPlus(left)) { 03239 03240 // Search for common factor 03241 if (left[0].getRational() == 0) { 03242 Expr::iterator i = left.begin(), iend = left.end(); 03243 ++ i; 03244 set<Expr> factors; 03245 set<Expr>::iterator is, isend; 03246 getFactors(*i, factors); 03247 for (++i; i != iend; ++i) { 03248 set<Expr> factors2; 03249 getFactors(*i, factors2); 03250 for (is = factors.begin(), isend = factors.end(); is != isend;) { 03251 if (factors2.find(*is) == factors2.end()) { 03252 factors.erase(is ++); 03253 } else 03254 ++ is; 03255 } 03256 if (factors.empty()) break; 03257 } 03258 if (!factors.empty()) { 03259 thm = transitivityRule(thm, d_rules->divideEqnNonConst(left, rat(0), *(factors.begin()))); 03260 // got (factor != 0) OR (left / factor = right / factor), need to simplify 03261 thm = transitivityRule(thm, simplify(thm.getRHS())); 03262 TRACE("arith nonlinear", "nonlinear eq rewrite (factoring): ", thm.getRHS(), ""); 03263 break; 03264 } 03265 } 03266 03267 // Look for equal powers (eq in the form of c + pow1 - pow2 = 0) 03268 Rational constant; 03269 Expr power1; 03270 Expr power2; 03271 if (isPowersEquality(nonlinearEq, power1, power2)) { 03272 // Eliminate the powers 03273 thm = transitivityRule(thm, d_rules->elimPower(nonlinearEq)); 03274 thm = transitivityRule(thm, simplify(thm.getRHS())); 03275 TRACE("arith nonlinear", "nonlinear eq rewrite (equal powers): ", thm.getRHS(), ""); 03276 break; 03277 } else 03278 // Look for one power equality (c - pow = 0); 03279 if (isPowerEquality(nonlinearEq, constant, power1)) { 03280 Rational pow1 = power1[0].getRational(); 03281 if (pow1 % 2 == 0 && constant < 0) { 03282 thm = transitivityRule(thm, d_rules->evenPowerEqNegConst(nonlinearEq)); 03283 TRACE("arith nonlinear", "nonlinear eq rewrite (even power = negative): ", thm.getRHS(), ""); 03284 break; 03285 } 03286 DebugAssert(constant != 0, "Expected nonzero const"); 03287 Rational root = ratRoot(constant, pow1.getUnsigned()); 03288 if (root != 0) { 03289 thm = transitivityRule(thm, d_rules->elimPowerConst(nonlinearEq, root)); 03290 thm = transitivityRule(thm, simplify(thm.getRHS())); 03291 TRACE("arith nonlinear", "nonlinear eq rewrite (rational root): ", thm.getRHS(), ""); 03292 break; 03293 } else { 03294 Theorem isIntPower(isIntegerThm(left)); 03295 if (!isIntPower.isNull()) { 03296 thm = transitivityRule(thm, d_rules->intEqIrrational(nonlinearEq, isIntPower)); 03297 TRACE("arith nonlinear", "nonlinear eq rewrite (irational root): ", thm.getRHS(), ""); 03298 break; 03299 } 03300 } 03301 } 03302 } 03303 03304 // Non-solvable nonlinear equations are rewritten as conjunction of inequalities 03305 if ( (nonlinearEq[0].arity() > 1 && !canPickEqMonomial(nonlinearEq[0])) || 03306 (nonlinearEq[1].arity() > 1 && !canPickEqMonomial(nonlinearEq[1])) ) { 03307 thm = transitivityRule(thm, d_rules->eqToIneq(nonlinearEq)); 03308 thm = transitivityRule(thm, simplify(thm.getRHS())); 03309 TRACE("arith nonlinear", "nonlinear eq rewrite (not solvable): ", thm.getRHS(), ""); 03310 break; 03311 } 03312 } 03313 } 03314 break; 03315 case GRAY_SHADOW: 03316 case DARK_SHADOW: 03317 thm = reflexivityRule(e); 03318 break; 03319 case IS_INTEGER: { 03320 Theorem res(isIntegerDerive(e, typePred(e[0]))); 03321 if(!res.isNull()) 03322 thm = getCommonRules()->iffTrue(res); 03323 else 03324 thm = reflexivityRule(e); 03325 break; 03326 } 03327 case NOT: 03328 if (!isIneq(e[0])) 03329 //in this case we have "NOT of DARK or GRAY_SHADOW." 03330 thm = reflexivityRule(e); 03331 else { 03332 //In this case we have the "NOT of ineq". get rid of NOT 03333 //and then treat like an ineq 03334 thm = d_rules->negatedInequality(e); 03335 DebugAssert(isGE(thm.getRHS()) || isGT(thm.getRHS()), 03336 "Expected GE or GT"); 03337 thm = transitivityRule(thm, d_rules->flipInequality(thm.getRHS())); 03338 thm = transitivityRule(thm, d_rules->rightMinusLeft(thm.getRHS())); 03339 thm = canonPredEquiv(thm); 03340 03341 // If the inequality is strict and integer, change it to non-strict 03342 Expr theIneq = thm.getRHS(); 03343 if(isLT(theIneq)) { 03344 // Check if integer 03345 Theorem isIntLHS(isIntegerThm(theIneq[0])); 03346 Theorem isIntRHS(isIntegerThm(theIneq[1])); 03347 bool isInt = (!isIntLHS.isNull() && !isIntRHS.isNull()); 03348 if (isInt) { 03349 thm = canonPredEquiv( 03350 transitivityRule(thm, d_rules->lessThanToLERewrite(theIneq, isIntLHS, isIntRHS, true))); 03351 } 03352 } 03353 03354 // Check for trivial inequation 03355 if ((thm.getRHS())[1].isRational()) 03356 thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); 03357 else { 03358 //else ineq is non-trivial 03359 thm = normalize(thm); 03360 // Normalization may yield non-simplified terms 03361 thm = canonPredEquiv(thm); 03362 } 03363 } 03364 break; 03365 case LT: 03366 case GT: 03367 case LE: 03368 case GE: { 03369 03370 if (isGE(e) || isGT(e)) { 03371 thm = d_rules->flipInequality(e); 03372 thm = transitivityRule(thm, d_rules->rightMinusLeft(thm.getRHS())); 03373 } 03374 else 03375 thm = d_rules->rightMinusLeft(e); 03376 03377 thm = canonPredEquiv(thm); 03378 03379 // If the inequality is strict and integer, change it to non-strict 03380 Expr theIneq = thm.getRHS(); 03381 if(isLT(theIneq)) { 03382 // Check if integer 03383 Theorem isIntLHS(isIntegerThm(theIneq[0])); 03384 Theorem isIntRHS(isIntegerThm(theIneq[1])); 03385 bool isInt = (!isIntLHS.isNull() && !isIntRHS.isNull()); 03386 if (isInt) { 03387 thm = canonPredEquiv( 03388 transitivityRule(thm, d_rules->lessThanToLERewrite(theIneq, isIntLHS, isIntRHS, true))); 03389 } 03390 } 03391 03392 // Check for trivial inequation 03393 if ((thm.getRHS())[1].isRational()) 03394 thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); 03395 else { // ineq is non-trivial 03396 thm = normalize(thm); 03397 thm = canonPredEquiv(thm); 03398 if (thm.getRHS()[1].isRational()) 03399 thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); 03400 } 03401 break; 03402 } 03403 default: 03404 DebugAssert(false, 03405 "Theory_Arith::rewrite: control should not reach here"); 03406 break; 03407 } 03408 } 03409 else { 03410 if (e.isAtomic()) 03411 thm = canon(e); 03412 else 03413 thm = reflexivityRule(e); 03414 } 03415 // TODO: this needs to be reviewed, esp for non-linear case 03416 // Arith canonization is idempotent 03417 if (theoryOf(thm.getRHS()) == this) 03418 thm.getRHS().setRewriteNormal(); 03419 TRACE("arith", "TheoryArithOld::rewrite => ", thm, " }"); 03420 return thm; 03421 } 03422 03423 03424 void TheoryArithOld::setup(const Expr& e) 03425 { 03426 if (!e.isTerm()) { 03427 if (e.isNot()) return; 03428 // if(e.getKind() == IS_INTEGER) { 03429 // e[0].addToNotify(this, e); 03430 // return; 03431 // } 03432 if (isIneq(e)) { 03433 DebugAssert((isLT(e)||isLE(e)) && 03434 e[0].isRational() && e[0].getRational() == 0, 03435 "TheoryArithOld::setup: expected 0 < rhs:" + e.toString()); 03436 e[1].addToNotify(this, e); 03437 } else { 03438 // if (e.isEq()) { 03439 // // Nonlinear solved equations 03440 // if (isNonlinearEq(e) && e[0].isRational() && e[0].getRational() == 0) 03441 // e[0].addToNotify(this, e); 03442 // } 03443 // 03444 // DebugAssert(isGrayShadow(e), "TheoryArithOld::setup: expected grayshadow" + e.toString()); 03445 // 03446 // // Do not add the variable, just the subterm e[0].addToNotify(this, e); 03447 // e[1].addToNotify(this, e); 03448 } 03449 return; 03450 } 03451 int k(0), ar(e.arity()); 03452 for ( ; k < ar; ++k) { 03453 e[k].addToNotify(this, e); 03454 TRACE("arith setup", "e["+int2string(k)+"]: ", *(e[k].getNotify()), ""); 03455 } 03456 } 03457 03458 03459 void TheoryArithOld::update(const Theorem& e, const Expr& d) 03460 { 03461 TRACE("arith update", "update on " + d.toString() + " with ", e.getRHS().toString(), "."); 03462 03463 if (inconsistent()) return; 03464 03465 // We accept atoms without find, but only inequalities (they come from the buffer) 03466 DebugAssert(d.hasFind() || isIneq(d), "update on a non-inequality term/atom"); 03467 03468 IF_DEBUG(debugger.counter("arith update total")++;) 03469 // if (isGrayShadow(d)) { 03470 // TRACE("shadow update", "updating index of " + d.toString() + " with ", e.getRHS().toString(), "."); 03471 // 03472 // // Substitute e[1] for e[0] in d and enqueue new shadow 03473 // DebugAssert(e.getLHS() == d[1], "Mismatch"); 03474 // Theorem thm = find(d); 03475 // 03476 // // DebugAssert(thm.getRHS() == trueExpr(), "Expected find = true"); 03477 // vector<unsigned> changed; 03478 // vector<Theorem> children; 03479 // changed.push_back(1); 03480 // children.push_back(e); 03481 // Theorem thm2 = substitutivityRule(d, changed, children); 03482 // if (thm.getRHS() == trueExpr()) { 03483 // enqueueFact(iffMP(getCommonRules()->iffTrueElim(thm), thm2)); 03484 // } 03485 // else { 03486 // enqueueFact(getCommonRules()->iffFalseElim( 03487 // transitivityRule(symmetryRule(thm2), thm))); 03488 // } 03489 // IF_DEBUG(debugger.counter("arith update ineq")++;) 03490 // } 03491 // else 03492 if (isIneq(d)) { 03493 03494 // Substitute e[1] for e[0] in d and enqueue new inequality 03495 DebugAssert(e.getLHS() == d[1], "Mismatch"); 03496 Theorem thm; 03497 if (d.hasFind()) thm = find(d); 03498 03499 // bool diff_logic = false; 03500 // Expr new_rhs = e.getRHS(); 03501 // if (!isPlus(new_rhs)) { 03502 // if (isLeaf(new_rhs)) diff_logic = true; 03503 // } 03504 // else { 03505 // int arity = new_rhs.arity(); 03506 // if (arity == 2) { 03507 // if (new_rhs[0].isRational()) diff_logic = true; 03508 // else { 03509 // Expr ax = new_rhs[0], a, x; 03510 // Expr by = new_rhs[1], b, y; 03511 // separateMonomial(ax, a, x); 03512 // separateMonomial(by, b, y); 03513 // if ((a.getRational() == 1 && b.getRational() == -1) || 03514 // (a.getRational() == -1 && b.getRational() == 1)) 03515 // diff_logic = true; 03516 // } 03517 // } else { 03518 // if (arity == 3 && new_rhs[0].isRational()) { 03519 // Expr ax = new_rhs[1], a, x; 03520 // Expr by = new_rhs[2], b, y; 03521 // separateMonomial(ax, a, x); 03522 // separateMonomial(by, b, y); 03523 // if ((a.getRational() == 1 && b.getRational() == -1) || 03524 // (a.getRational() == -1 && b.getRational() == 1)) 03525 // diff_logic = true; 03526 // } 03527 // } 03528 // } 03529 03530 // DebugAssert(thm.getRHS() == trueExpr(), "Expected find = true"); 03531 vector<unsigned> changed; 03532 vector<Theorem> children; 03533 changed.push_back(1); 03534 children.push_back(e); 03535 Theorem thm2 = substitutivityRule(d, changed, children); 03536 Expr newIneq = thm2.getRHS(); 03537 03538 // If this inequality is bufferred but not yet projected, just wait for it 03539 // but don't add the find to the buffer as it will be projected as a find 03540 // We DO want it to pass through all the buffer stuff but NOT get into the buffer 03541 // NOTE: this means that the difference logic WILL get processed 03542 if ((thm.isNull() || thm.getRHS() != falseExpr()) && 03543 bufferedInequalities.find(d) != bufferedInequalities.end() && 03544 alreadyProjected.find(d) == alreadyProjected.end()) { 03545 TRACE("arith update", "simplified but not projected : ", thm2.getRHS(), ""); 03546 dontBuffer[thm2.getRHS()] = true; 03547 } 03548 03549 if (thm.isNull()) { 03550 // This hy is in the buffer, not in the core 03551 // if it has been projected, than it's parent has been projected and will get reprojected 03552 // accuratlz. If it has not been projected, we don't care it's still there 03553 TRACE("arith update", "in udpate, but no find", "", ""); 03554 if (bufferedInequalities.find(d) != bufferedInequalities.end()) { 03555 if (thm2.getRHS()[1].isRational()) enqueueFact(iffMP(bufferedInequalities[d], thm2)); 03556 else if (alreadyProjected.find(d) != alreadyProjected.end()) { 03557 // the parent will get reprojected 03558 alreadyProjected[d] = d; 03559 } 03560 } 03561 } 03562 else if (thm.getRHS() == trueExpr()) { 03563 if (!newIneq[1].isRational() || newIneq[1].getRational() <= 0) 03564 enqueueFact(iffMP(getCommonRules()->iffTrueElim(thm), thm2)); 03565 } 03566 else { 03567 enqueueFact(getCommonRules()->iffFalseElim( 03568 transitivityRule(symmetryRule(thm2), thm))); 03569 } 03570 IF_DEBUG(debugger.counter("arith update ineq")++;) 03571 } 03572 else if (d.isEq()) { 03573 TRACE("arith nonlinear", "TheoryArithOld::update() on equality ", d, ""); 03574 // We get equalitites from the non-solve nonlinear equations 03575 // only the right hand sides get updated 03576 vector<unsigned> changed; 03577 vector<Theorem> children; 03578 changed.push_back(0); 03579 children.push_back(e); 03580 Theorem thm = substitutivityRule(d, changed, children); 03581 Expr newEq = thm.getRHS(); 03582 03583 Theorem d_find = find(d); 03584 if (d_find.getRHS() == trueExpr()) enqueueFact(iffMP(getCommonRules()->iffTrueElim(d_find), thm)); 03585 else enqueueFact(getCommonRules()->iffFalseElim(transitivityRule(symmetryRule(thm), d_find))); 03586 } 03587 else if (d.getKind() == IS_INTEGER) { 03588 // This should only happen if !d has been asserted 03589 DebugAssert(e.getRHS() == findExpr(d[0]), "Unexpected"); 03590 if (isInteger(e.getRHS())) { 03591 Theorem thm = substitutivityRule(d, find(d[0])); 03592 thm = transitivityRule(symmetryRule(find(d)), thm); 03593 thm = iffMP(thm, simplify(thm.getExpr())); 03594 setInconsistent(thm); 03595 } 03596 else { 03597 e.getRHS().addToNotify(this, d); 03598 } 03599 } 03600 else if (find(d).getRHS() == d) { 03601 // Theorem thm = canonSimp(d); 03602 // TRACE("arith", "TheoryArithOld::update(): thm = ", thm, ""); 03603 // DebugAssert(leavesAreSimp(thm.getRHS()), "updateHelper error: " 03604 // +thm.getExpr().toString()); 03605 // assertEqualities(transitivityRule(thm, rewrite(thm.getRHS()))); 03606 // IF_DEBUG(debugger.counter("arith update find(d)=d")++;) 03607 Theorem thm = simplify(d); 03608 // If the original is was a shared term, add this one as as a shared term also 03609 if (d_sharedTerms.find(d) != d_sharedTerms.end()) addSharedTerm(thm.getRHS()); 03610 DebugAssert(thm.getRHS().isAtomic(), "Expected atomic"); 03611 assertEqualities(thm); 03612 } 03613 } 03614 03615 03616 Theorem TheoryArithOld::solve(const Theorem& thm) 03617 { 03618 DebugAssert(thm.isRewrite() && thm.getLHS().isTerm(), ""); 03619 const Expr& lhs = thm.getLHS(); 03620 const Expr& rhs = thm.getRHS(); 03621 03622 // Check for already solved equalities. 03623 03624 // Have to be careful about the types: integer variable cannot be 03625 // assigned a real term. Also, watch for e[0] being a subexpression 03626 // of e[1]: this would create an unsimplifiable expression. 03627 if (isLeaf(lhs) && !isLeafIn(lhs, rhs) 03628 && (!isInteger(lhs) || isInteger(rhs)) 03629 // && !e[0].subExprOf(e[1]) 03630 ) 03631 return thm; 03632 03633 // Symmetric version is already solved 03634 if (isLeaf(rhs) && !isLeafIn(rhs, lhs) 03635 && (!isInteger(rhs) || isInteger(lhs)) 03636 // && !e[1].subExprOf(e[0]) 03637 ) 03638 return symmetryRule(thm); 03639 03640 return doSolve(thm); 03641 } 03642 03643 03644 void TheoryArithOld::computeModelTerm(const Expr& e, std::vector<Expr>& v) { 03645 switch(e.getKind()) { 03646 case RATIONAL_EXPR: // Skip the constants 03647 break; 03648 case PLUS: 03649 case MULT: 03650 case DIVIDE: 03651 case POW: // This is not a variable; extract the variables from children 03652 for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) 03653 // getModelTerm(*i, v); 03654 v.push_back(*i); 03655 break; 03656 default: { // Otherwise it's a variable. Check if it has a find pointer 03657 Expr e2(findExpr(e)); 03658 if(e==e2) { 03659 TRACE("model", "TheoryArithOld::computeModelTerm(", e, "): a variable"); 03660 // Leave it alone (it has no descendants) 03661 // v.push_back(e); 03662 } else { 03663 TRACE("model", "TheoryArithOld::computeModelTerm("+e.toString() 03664 +"): has find pointer to ", e2, ""); 03665 v.push_back(e2); 03666 } 03667 } 03668 } 03669 } 03670 03671 03672 Expr TheoryArithOld::computeTypePred(const Type& t, const Expr& e) { 03673 Expr tExpr = t.getExpr(); 03674 switch(tExpr.getKind()) { 03675 case INT: 03676 return Expr(IS_INTEGER, e); 03677 case SUBRANGE: { 03678 std::vector<Expr> kids; 03679 kids.push_back(Expr(IS_INTEGER, e)); 03680 kids.push_back(leExpr(tExpr[0], e)); 03681 kids.push_back(leExpr(e, tExpr[1])); 03682 return andExpr(kids); 03683 } 03684 default: 03685 return e.getEM()->trueExpr(); 03686 } 03687 } 03688 03689 03690 void TheoryArithOld::checkAssertEqInvariant(const Theorem& e) 03691 { 03692 if (e.isRewrite()) { 03693 DebugAssert(e.getLHS().isTerm(), "Expected equation"); 03694 if (isLeaf(e.getLHS())) { 03695 // should be in solved form 03696 DebugAssert(!isLeafIn(e.getLHS(),e.getRHS()), 03697 "Not in solved form: lhs appears in rhs"); 03698 } 03699 else { 03700 DebugAssert(e.getLHS().hasFind(), "Expected lhs to have find"); 03701 DebugAssert(!leavesAreSimp(e.getLHS()), 03702 "Expected at least one unsimplified leaf on lhs"); 03703 } 03704 DebugAssert(canonSimp(e.getRHS()).getRHS() == e.getRHS(), 03705 "Expected canonSimp(rhs) = canonSimp(rhs)"); 03706 } 03707 else { 03708 Expr expr = e.getExpr(); 03709 if (expr.isFalse()) return; 03710 03711 vector<Theorem> eqs; 03712 Theorem thm; 03713 int index, index2; 03714 03715 for (index = 0; index < expr.arity(); ++index) { 03716 thm = getCommonRules()->andElim(e, index); 03717 eqs.push_back(thm); 03718 if (thm.getExpr().isFalse()) return; 03719 DebugAssert(eqs[index].isRewrite() && 03720 eqs[index].getLHS().isTerm(), "Expected equation"); 03721 } 03722 03723 // Check for solved form 03724 for (index = 0; index < expr.arity(); ++index) { 03725 DebugAssert(isLeaf(eqs[index].getLHS()), "expected leaf on lhs"); 03726 DebugAssert(canonSimp(eqs[index].getRHS()).getRHS() == eqs[index].getRHS(), 03727 "Expected canonSimp(rhs) = canonSimp(rhs)"); 03728 DebugAssert(recursiveCanonSimpCheck(eqs[index].getRHS()), 03729 "Failed recursive canonSimp check"); 03730 for (index2 = 0; index2 < expr.arity(); ++index2) { 03731 DebugAssert(index == index2 || 03732 eqs[index].getLHS() != eqs[index2].getLHS(), 03733 "Not in solved form: repeated lhs"); 03734 DebugAssert(!isLeafIn(eqs[index].getLHS(),eqs[index2].getRHS()), 03735 "Not in solved form: lhs appears in rhs"); 03736 } 03737 } 03738 } 03739 } 03740 03741 03742 void TheoryArithOld::checkType(const Expr& e) 03743 { 03744 switch (e.getKind()) { 03745 case INT: 03746 case REAL: 03747 if (e.arity() > 0) { 03748 throw Exception("Ill-formed arithmetic type: "+e.toString()); 03749 } 03750 break; 03751 case SUBRANGE: 03752 if (e.arity() != 2 || 03753 !isIntegerConst(e[0]) || 03754 !isIntegerConst(e[1]) || 03755 e[0].getRational() > e[1].getRational()) { 03756 throw Exception("bad SUBRANGE type expression"+e.toString()); 03757 } 03758 break; 03759 default: 03760 DebugAssert(false, "Unexpected kind in TheoryArithOld::checkType" 03761 +getEM()->getKindName(e.getKind())); 03762 } 03763 } 03764 03765 03766 Cardinality TheoryArithOld::finiteTypeInfo(Expr& e, Unsigned& n, 03767 bool enumerate, bool computeSize) 03768 { 03769 Cardinality card = CARD_INFINITE; 03770 switch (e.getKind()) { 03771 case SUBRANGE: { 03772 card = CARD_FINITE; 03773 Expr typeExpr = e; 03774 if (enumerate) { 03775 Rational r = typeExpr[0].getRational() + n; 03776 if (r <= typeExpr[1].getRational()) { 03777 e = rat(r); 03778 } 03779 else e = Expr(); 03780 } 03781 if (computeSize) { 03782 Rational r = typeExpr[1].getRational() - typeExpr[0].getRational() + 1; 03783 n = r.getUnsigned(); 03784 } 03785 break; 03786 } 03787 default: 03788 break; 03789 } 03790 return card; 03791 } 03792 03793 03794 void TheoryArithOld::computeType(const Expr& e) 03795 { 03796 switch (e.getKind()) { 03797 case REAL_CONST: 03798 e.setType(d_realType); 03799 break; 03800 case RATIONAL_EXPR: 03801 if(e.getRational().isInteger()) 03802 e.setType(d_intType); 03803 else 03804 e.setType(d_realType); 03805 break; 03806 case UMINUS: 03807 case PLUS: 03808 case MINUS: 03809 case MULT: 03810 case POW: { 03811 bool isInt = true; 03812 for(int k = 0; k < e.arity(); ++k) { 03813 if(d_realType != getBaseType(e[k])) 03814 throw TypecheckException("Expecting type REAL with `" + 03815 getEM()->getKindName(e.getKind()) + "',\n"+ 03816 "but got a " + getBaseType(e[k]).toString()+ 03817 " for:\n" + e.toString()); 03818 if(isInt && !isInteger(e[k])) 03819 isInt = false; 03820 } 03821 if(isInt) 03822 e.setType(d_intType); 03823 else 03824 e.setType(d_realType); 03825 break; 03826 } 03827 case DIVIDE: { 03828 Expr numerator = e[0]; 03829 Expr denominator = e[1]; 03830 if (getBaseType(numerator) != d_realType || 03831 getBaseType(denominator) != d_realType) { 03832 throw TypecheckException("Expecting only REAL types with `DIVIDE',\n" 03833 "but got " + getBaseType(numerator).toString()+ 03834 " and " + getBaseType(denominator).toString() + 03835 " for:\n" + e.toString()); 03836 } 03837 if(denominator.isRational() && 1 == denominator.getRational()) 03838 e.setType(numerator.getType()); 03839 else 03840 e.setType(d_realType); 03841 break; 03842 } 03843 case LT: 03844 case LE: 03845 case GT: 03846 case GE: 03847 case GRAY_SHADOW: 03848 // Need to know types for all exprs -Clark 03849 // e.setType(boolType()); 03850 // break; 03851 case DARK_SHADOW: 03852 for (int k = 0; k < e.arity(); ++k) { 03853 if (d_realType != getBaseType(e[k])) 03854 throw TypecheckException("Expecting type REAL with `" + 03855 getEM()->getKindName(e.getKind()) + "',\n"+ 03856 "but got a " + getBaseType(e[k]).toString()+ 03857 " for:\n" + e.toString()); 03858 } 03859 03860 e.setType(boolType()); 03861 break; 03862 case IS_INTEGER: 03863 if(d_realType != getBaseType(e[0])) 03864 throw TypecheckException("Expected type REAL, but got " 03865 +getBaseType(e[0]).toString() 03866 +"\n\nExpr = "+e.toString()); 03867 e.setType(boolType()); 03868 break; 03869 default: 03870 DebugAssert(false,"TheoryArithOld::computeType: unexpected expression:\n " 03871 +e.toString()); 03872 break; 03873 } 03874 } 03875 03876 03877 Type TheoryArithOld::computeBaseType(const Type& t) { 03878 IF_DEBUG(int kind = t.getExpr().getKind();) 03879 DebugAssert(kind==INT || kind==REAL || kind==SUBRANGE, 03880 "TheoryArithOld::computeBaseType("+t.toString()+")"); 03881 return realType(); 03882 } 03883 03884 03885 Expr 03886 TheoryArithOld::computeTCC(const Expr& e) { 03887 Expr tcc(Theory::computeTCC(e)); 03888 switch(e.getKind()) { 03889 case DIVIDE: 03890 DebugAssert(e.arity() == 2, ""); 03891 return tcc.andExpr(!(e[1].eqExpr(rat(0)))); 03892 default: 03893 return tcc; 03894 } 03895 } 03896 03897 /////////////////////////////////////////////////////////////////////////////// 03898 //parseExprOp: 03899 //translating special Exprs to regular EXPR?? 03900 /////////////////////////////////////////////////////////////////////////////// 03901 Expr 03902 TheoryArithOld::parseExprOp(const Expr& e) { 03903 //TRACE("parser", "TheoryArithOld::parseExprOp(", e, ")"); 03904 //std::cout << "Were here"; 03905 // If the expression is not a list, it must have been already 03906 // parsed, so just return it as is. 03907 switch(e.getKind()) { 03908 case ID: { 03909 int kind = getEM()->getKind(e[0].getString()); 03910 switch(kind) { 03911 case NULL_KIND: return e; // nothing to do 03912 case REAL: 03913 case INT: 03914 case NEGINF: 03915 case POSINF: return getEM()->newLeafExpr(kind); 03916 default: 03917 DebugAssert(false, "Bad use of bare keyword: "+e.toString()); 03918 return e; 03919 } 03920 } 03921 case RAW_LIST: break; // break out of switch, do the hard work 03922 default: 03923 return e; 03924 } 03925 03926 DebugAssert(e.getKind() == RAW_LIST && e.arity() > 0, 03927 "TheoryArithOld::parseExprOp:\n e = "+e.toString()); 03928 03929 const Expr& c1 = e[0][0]; 03930 int kind = getEM()->getKind(c1.getString()); 03931 switch(kind) { 03932 case UMINUS: { 03933 if(e.arity() != 2) 03934 throw ParserException("UMINUS requires exactly one argument: " 03935 +e.toString()); 03936 return uminusExpr(parseExpr(e[1])); 03937 } 03938 case PLUS: { 03939 vector<Expr> k; 03940 Expr::iterator i = e.begin(), iend=e.end(); 03941 // Skip first element of the vector of kids in 'e'. 03942 // The first element is the operator. 03943 ++i; 03944 // Parse the kids of e and push them into the vector 'k' 03945 for(; i!=iend; ++i) k.push_back(parseExpr(*i)); 03946 return plusExpr(k); 03947 } 03948 case MINUS: { 03949 if(e.arity() == 2) { 03950 if (false && (getEM()->getInputLang() == SMTLIB_LANG 03951 || getEM()->getInputLang() == SMTLIB_V2_LANG)) { 03952 throw ParserException("Unary Minus should use '~' instead of '-' in SMT-LIB expr:" 03953 +e.toString()); 03954 } 03955 else { 03956 return uminusExpr(parseExpr(e[1])); 03957 } 03958 } 03959 else if(e.arity() == 3) 03960 return minusExpr(parseExpr(e[1]), parseExpr(e[2])); 03961 else 03962 throw ParserException("MINUS requires one or two arguments:" 03963 +e.toString()); 03964 } 03965 case MULT: { 03966 vector<Expr> k; 03967 Expr::iterator i = e.begin(), iend=e.end(); 03968 // Skip first element of the vector of kids in 'e'. 03969 // The first element is the operator. 03970 ++i; 03971 // Parse the kids of e and push them into the vector 'k' 03972 for(; i!=iend; ++i) k.push_back(parseExpr(*i)); 03973 return multExpr(k); 03974 } 03975 case POW: { 03976 return powExpr(parseExpr(e[1]), parseExpr(e[2])); 03977 } 03978 case DIVIDE: 03979 { return divideExpr(parseExpr(e[1]), parseExpr(e[2])); } 03980 case LT: 03981 { return ltExpr(parseExpr(e[1]), parseExpr(e[2])); } 03982 case LE: 03983 { return leExpr(parseExpr(e[1]), parseExpr(e[2])); } 03984 case GT: 03985 { return gtExpr(parseExpr(e[1]), parseExpr(e[2])); } 03986 case GE: 03987 { return geExpr(parseExpr(e[1]), parseExpr(e[2])); } 03988 case INTDIV: 03989 case MOD: 03990 case SUBRANGE: { 03991 vector<Expr> k; 03992 Expr::iterator i = e.begin(), iend=e.end(); 03993 // Skip first element of the vector of kids in 'e'. 03994 // The first element is the operator. 03995 ++i; 03996 // Parse the kids of e and push them into the vector 'k' 03997 for(; i!=iend; ++i) 03998 k.push_back(parseExpr(*i)); 03999 return Expr(kind, k, e.getEM()); 04000 } 04001 case IS_INTEGER: { 04002 if(e.arity() != 2) 04003 throw ParserException("IS_INTEGER requires exactly one argument: " 04004 +e.toString()); 04005 return Expr(IS_INTEGER, parseExpr(e[1])); 04006 } 04007 default: 04008 DebugAssert(false, 04009 "TheoryArithOld::parseExprOp: invalid input " + e.toString()); 04010 break; 04011 } 04012 return e; 04013 } 04014 04015 /////////////////////////////////////////////////////////////////////////////// 04016 // Pretty-printing // 04017 /////////////////////////////////////////////////////////////////////////////// 04018 04019 04020 ExprStream& 04021 TheoryArithOld::print(ExprStream& os, const Expr& e) { 04022 switch(os.lang()) { 04023 case SIMPLIFY_LANG: 04024 switch(e.getKind()) { 04025 case RATIONAL_EXPR: 04026 e.print(os); 04027 break; 04028 case SUBRANGE: 04029 os <<"ERROR:SUBRANGE:not supported in Simplify\n"; 04030 break; 04031 case IS_INTEGER: 04032 os <<"ERROR:IS_INTEGER:not supported in Simplify\n"; 04033 break; 04034 case PLUS: { 04035 int i=0, iend=e.arity(); 04036 os << "(+ "; 04037 if(i!=iend) os << e[i]; 04038 ++i; 04039 for(; i!=iend; ++i) os << " " << e[i]; 04040 os << ")"; 04041 break; 04042 } 04043 case MINUS: 04044 os << "(- " << e[0] << " " << e[1]<< ")"; 04045 break; 04046 case UMINUS: 04047 os << "-" << e[0] ; 04048 break; 04049 case MULT: { 04050 int i=0, iend=e.arity(); 04051 os << "(* " ; 04052 if(i!=iend) os << e[i]; 04053 ++i; 04054 for(; i!=iend; ++i) os << " " << e[i]; 04055 os << ")"; 04056 break; 04057 } 04058 case POW: 04059 os << "(" << push << e[1] << space << "^ " << e[0] << push << ")"; 04060 break; 04061 case DIVIDE: 04062 os << "(" << push << e[0] << space << "/ " << e[1] << push << ")"; 04063 break; 04064 case LT: 04065 if (isInt(e[0].getType()) || isInt(e[1].getType())) { 04066 } 04067 os << "(< " << e[0] << " " << e[1] <<")"; 04068 break; 04069 case LE: 04070 os << "(<= " << e[0] << " " << e[1] << ")"; 04071 break; 04072 case GT: 04073 os << "(> " << e[0] << " " << e[1] << ")"; 04074 break; 04075 case GE: 04076 os << "(>= " << e[0] << " " << e[1] << ")"; 04077 break; 04078 case DARK_SHADOW: 04079 case GRAY_SHADOW: 04080 os <<"ERROR:SHADOW:not supported in Simplify\n"; 04081 break; 04082 default: 04083 // Print the top node in the default LISP format, continue with 04084 // pretty-printing for children. 04085 e.print(os); 04086 04087 break; 04088 } 04089 break; // end of case SIMPLIFY_LANG 04090 04091 case TPTP_LANG: 04092 switch(e.getKind()) { 04093 case RATIONAL_EXPR: 04094 e.print(os); 04095 break; 04096 case SUBRANGE: 04097 os <<"ERROR:SUBRANGE:not supported in TPTP\n"; 04098 break; 04099 case IS_INTEGER: 04100 os <<"ERROR:IS_INTEGER:not supported in TPTP\n"; 04101 break; 04102 case PLUS: { 04103 if(!isInteger(e[0])){ 04104 os<<"ERRPR:plus only supports inteters now in TPTP\n"; 04105 break; 04106 } 04107 04108 int i=0, iend=e.arity(); 04109 if(iend <=1){ 04110 os<<"ERROR,plus must have more than two numbers in TPTP\n"; 04111 break; 04112 } 04113 04114 for(i=0; i <= iend-2; ++i){ 04115 os << "$plus_int("; 04116 os << e[i] << ","; 04117 } 04118 04119 os<< e[iend-1]; 04120 04121 for(i=0 ; i <= iend-2; ++i){ 04122 os << ")"; 04123 } 04124 04125 break; 04126 } 04127 case MINUS: 04128 if(!isInteger(e[0])){ 04129 os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; 04130 break; 04131 } 04132 04133 os << "$minus_int(" << e[0] << "," << e[1]<< ")"; 04134 break; 04135 case UMINUS: 04136 if(!isInteger(e[0])){ 04137 os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; 04138 break; 04139 } 04140 04141 os << "$uminus_int(" << e[0] <<")" ; 04142 break; 04143 case MULT: { 04144 if(!isInteger(e[0])){ 04145 os<<"ERRPR:times only supports inteters now in TPTP\n"; 04146 break; 04147 } 04148 04149 int i=0, iend=e.arity(); 04150 if(iend <=1){ 04151 os<<"ERROR:times must have more than two numbers in TPTP\n"; 04152 break; 04153 } 04154 04155 for(i=0; i <= iend-2; ++i){ 04156 os << "$times_int("; 04157 os << e[i] << ","; 04158 } 04159 04160 os<< e[iend-1]; 04161 04162 for(i=0 ; i <= iend-2; ++i){ 04163 os << ")"; 04164 } 04165 04166 break; 04167 } 04168 case POW: 04169 04170 if(!isInteger(e[0])){ 04171 os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; 04172 break; 04173 } 04174 04175 os << "$power_int(" << push << e[1] << space << "^ " << e[0] << push << ")"; 04176 break; 04177 04178 case DIVIDE: 04179 if(!isInteger(e[0])){ 04180 os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; 04181 break; 04182 } 04183 04184 os << "divide_int(" <<e[0] << "," << e[1] << ")"; 04185 break; 04186 04187 case LT: 04188 if(!isInteger(e[0])){ 04189 os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; 04190 break; 04191 } 04192 os << "$less_int(" << e[0] << "," << e[1] <<")"; 04193 break; 04194 04195 case LE: 04196 if(!isInteger(e[0])){ 04197 os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; 04198 break; 04199 } 04200 04201 os << "$lesseq_int(" << e[0] << "," << e[1] << ")"; 04202 break; 04203 04204 case GT: 04205 if(!isInteger(e[0])){ 04206 os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; 04207 break; 04208 } 04209 04210 os << "$greater_int(" << e[0] << "," << e[1] << ")"; 04211 break; 04212 04213 case GE: 04214 if(!isInteger(e[0])){ 04215 os<<"ERRPR:arithmetic operations only support inteters now in TPTP\n"; 04216 break; 04217 } 04218 04219 os << "$greatereq_int(" << e[0] << "," << e[1] << ")"; 04220 break; 04221 case DARK_SHADOW: 04222 case GRAY_SHADOW: 04223 os <<"ERROR:SHADOW:not supported in TPTP\n"; 04224 break; 04225 04226 case INT: 04227 os <<"$int"; 04228 break; 04229 case REAL: 04230 os <<"ERROR:REAL not supported in TPTP\n"; 04231 default: 04232 // Print the top node in the default LISP format, continue with 04233 // pretty-printing for children. 04234 e.print(os); 04235 04236 break; 04237 } 04238 break; // end of case TPTP_LANG 04239 04240 case PRESENTATION_LANG: 04241 switch(e.getKind()) { 04242 case REAL: 04243 os << "REAL"; 04244 break; 04245 case INT: 04246 os << "INT"; 04247 break; 04248 case RATIONAL_EXPR: 04249 e.print(os); 04250 break; 04251 case NEGINF: 04252 os << "NEGINF"; 04253 break; 04254 case POSINF: 04255 os << "POSINF"; 04256 break; 04257 case SUBRANGE: 04258 if(e.arity() != 2) e.printAST(os); 04259 else 04260 os << "[" << push << e[0] << ".." << e[1] << push << "]"; 04261 break; 04262 case IS_INTEGER: 04263 if(e.arity() == 1) 04264 os << "IS_INTEGER(" << push << e[0] << push << ")"; 04265 else 04266 e.printAST(os); 04267 break; 04268 case PLUS: { 04269 int i=0, iend=e.arity(); 04270 os << "(" << push; 04271 if(i!=iend) os << e[i]; 04272 ++i; 04273 for(; i!=iend; ++i) os << space << "+ " << e[i]; 04274 os << push << ")"; 04275 break; 04276 } 04277 case MINUS: 04278 os << "(" << push << e[0] << space << "- " << e[1] << push << ")"; 04279 break; 04280 case UMINUS: 04281 os << "-(" << push << e[0] << push << ")"; 04282 break; 04283 case MULT: { 04284 int i=0, iend=e.arity(); 04285 os << "(" << push; 04286 if(i!=iend) os << e[i]; 04287 ++i; 04288 for(; i!=iend; ++i) os << space << "* " << e[i]; 04289 os << push << ")"; 04290 break; 04291 } 04292 case POW: 04293 os << "(" << push << e[1] << space << "^ " << e[0] << push << ")"; 04294 break; 04295 case DIVIDE: 04296 os << "(" << push << e[0] << space << "/ " << e[1] << push << ")"; 04297 break; 04298 case LT: 04299 if (isInt(e[0].getType()) || isInt(e[1].getType())) { 04300 } 04301 os << "(" << push << e[0] << space << "< " << e[1] << push << ")"; 04302 break; 04303 case LE: 04304 os << "(" << push << e[0] << space << "<= " << e[1] << push << ")"; 04305 break; 04306 case GT: 04307 os << "(" << push << e[0] << space << "> " << e[1] << push << ")"; 04308 break; 04309 case GE: 04310 os << "(" << push << e[0] << space << ">= " << e[1] << push << ")"; 04311 break; 04312 case DARK_SHADOW: 04313 os << "DARK_SHADOW(" << push << e[0] << ", " << space << e[1] << push << ")"; 04314 break; 04315 case GRAY_SHADOW: 04316 os << "GRAY_SHADOW(" << push << e[0] << "," << space << e[1] 04317 << "," << space << e[2] << "," << space << e[3] << push << ")"; 04318 break; 04319 default: 04320 // Print the top node in the default LISP format, continue with 04321 // pretty-printing for children. 04322 e.printAST(os); 04323 04324 break; 04325 } 04326 break; // end of case PRESENTATION_LANG 04327 case SPASS_LANG: { 04328 switch(e.getKind()) { 04329 case REAL_CONST: 04330 printRational(os, e[0].getRational(), true); 04331 break; 04332 case RATIONAL_EXPR: 04333 printRational(os, e.getRational()); 04334 break; 04335 case REAL: 04336 throw SmtlibException("TheoryArithOld::print: SPASS: REAL not implemented"); 04337 break; 04338 case INT: 04339 throw SmtlibException("TheoryArithOld::print: SPASS: INT not implemented"); 04340 break; 04341 case SUBRANGE: 04342 throw SmtlibException("TheoryArithOld::print: SPASS: SUBRANGE not implemented"); 04343 break; 04344 case IS_INTEGER: 04345 throw SmtlibException("TheoryArithOld::print: SPASS: IS_INTEGER not implemented"); 04346 case PLUS: { 04347 int arity = e.arity(); 04348 if(2 == arity) { 04349 os << push << "plus(" 04350 << e[0] << "," << space << e[1] 04351 << push << ")"; 04352 } 04353 else if(2 < arity) { 04354 for (int i = 0 ; i < arity - 2; i++){ 04355 os << push << "plus("; 04356 os << e[i] << "," << space; 04357 } 04358 os << push << "plus(" 04359 << e[arity - 2] << "," << space << e[arity - 1] 04360 << push << ")"; 04361 for (int i = 0 ; i < arity - 2; i++){ 04362 os << push << ")"; 04363 } 04364 } 04365 else { 04366 throw SmtlibException("TheoryArithOld::print: SPASS: Less than two arguments for plus"); 04367 } 04368 break; 04369 } 04370 case MINUS: { 04371 os << push << "plus(" << e[0] 04372 << "," << space << push << "mult(-1," 04373 << space << e[1] << push << ")" << push << ")"; 04374 break; 04375 } 04376 case UMINUS: { 04377 os << push << "plus(0," 04378 << space << push << "mult(-1," 04379 << space << e[0] << push << ")" << push << ")"; 04380 break; 04381 } 04382 case MULT: { 04383 int arity = e.arity(); 04384 if (2 == arity){ 04385 os << push << "mult(" 04386 << e[0] << "," << space << e[1] 04387 << push << ")"; 04388 } 04389 else if (2 < arity){ 04390 for (int i = 0 ; i < arity - 2; i++){ 04391 os << push << "mult("; 04392 os << e[i] << "," << space; 04393 } 04394 os << push << "mult(" 04395 << e[arity - 2] << "," << space << e[arity - 1] 04396 << push << ")"; 04397 for (int i = 0 ; i < arity - 2; i++){ 04398 os << push << ")"; 04399 } 04400 } 04401 else{ 04402 throw SmtlibException("TheoryArithOld::print: SPASS: Less than two arguments for mult"); 04403 } 04404 break; 04405 } 04406 case POW: 04407 if (e[0].isRational() && e[0].getRational().isInteger()) { 04408 int i=0, iend=e[0].getRational().getInt(); 04409 for(; i!=iend; ++i) { 04410 if (i < iend-2) { 04411 os << push << "mult("; 04412 } 04413 os << e[1] << "," << space; 04414 } 04415 os << push << "mult(" 04416 << e[1] << "," << space << e[1]; 04417 for (i=0; i < iend-1; ++i) { 04418 os << push << ")"; 04419 } 04420 } 04421 else { 04422 throw SmtlibException("TheoryArithOld::print: SPASS: POW not supported: " + e.toString(PRESENTATION_LANG)); 04423 } 04424 break; 04425 case DIVIDE: { 04426 os << "ERROR "<< endl;break; 04427 throw SmtlibException("TheoryArithOld::print: SPASS: unexpected use of DIVIDE"); 04428 break; 04429 } 04430 case LT: { 04431 Rational r; 04432 os << push << "ls(" << space; 04433 os << e[0] << "," << space << e[1] << push << ")"; 04434 break; 04435 } 04436 case LE: { 04437 Rational r; 04438 os << push << "le(" << space; 04439 os << e[0] << "," << space << e[1] << push << ")"; 04440 break; 04441 } 04442 case GT: { 04443 Rational r; 04444 os << push << "gs(" << space; 04445 os << e[0] << "," << space << e[1] << push << ")"; 04446 break; 04447 } 04448 case GE: { 04449 Rational r; 04450 os << push << "ge(" << space; 04451 os << e[0] << "," << space << e[1] << push << ")"; 04452 break; 04453 } 04454 04455 default: 04456 throw SmtlibException("TheoryArithOld::print: SPASS: default not supported"); 04457 } 04458 break; // end of case SPASS_LANG 04459 } 04460 case SMTLIB_LANG: 04461 case SMTLIB_V2_LANG: { 04462 switch(e.getKind()) { 04463 case REAL_CONST: 04464 printRational(os, e[0].getRational(), true); 04465 break; 04466 case RATIONAL_EXPR: 04467 printRational(os, e.getRational()); 04468 break; 04469 case REAL: 04470 os << "Real"; 04471 break; 04472 case INT: 04473 os << "Int"; 04474 break; 04475 case SUBRANGE: 04476 throw SmtlibException("TheoryArithOld::print: SMTLIB: SUBRANGE not implemented"); 04477 // if(e.arity() != 2) e.print(os); 04478 // else 04479 // os << "(" << push << "SUBRANGE" << space << e[0] 04480 // << space << e[1] << push << ")"; 04481 break; 04482 case IS_INTEGER: 04483 if(e.arity() == 1) { 04484 if (os.lang() == SMTLIB_LANG) { 04485 os << "(" << push << "IsInt" << space << e[0] << push << ")"; 04486 } 04487 else { 04488 os << "(" << push << "is_int" << space << e[0] << push << ")"; 04489 } 04490 } 04491 else 04492 throw SmtlibException("TheoryArithOld::print: SMTLIB: IS_INTEGER used unexpectedly"); 04493 break; 04494 case PLUS: { 04495 if(e.arity() == 1 && os.lang() == SMTLIB_V2_LANG) { 04496 os << e[0]; 04497 } else { 04498 os << "(" << push << "+"; 04499 Expr::iterator i = e.begin(), iend = e.end(); 04500 for(; i!=iend; ++i) { 04501 os << space << (*i); 04502 } 04503 os << push << ")"; 04504 } 04505 break; 04506 } 04507 case MINUS: { 04508 os << "(" << push << "- " << e[0] << space << e[1] << push << ")"; 04509 break; 04510 } 04511 case UMINUS: { 04512 if (os.lang() == SMTLIB_LANG) { 04513 os << "(" << push << "~" << space << e[0] << push << ")"; 04514 } 04515 else { 04516 os << "(" << push << "-" << space << e[0] << push << ")"; 04517 } 04518 break; 04519 } 04520 case MULT: { 04521 int i=0, iend=e.arity(); 04522 if(iend == 1 && os.lang() == SMTLIB_V2_LANG) { 04523 os << e[0]; 04524 } else { 04525 for(; i!=iend; ++i) { 04526 if (i < iend-1) { 04527 os << "(" << push << "*"; 04528 } 04529 os << space << e[i]; 04530 } 04531 for (i=0; i < iend-1; ++i) os << push << ")"; 04532 } 04533 break; 04534 } 04535 case POW: 04536 if (e[0].isRational() && e[0].getRational().isInteger()) { 04537 int i=0, iend=e[0].getRational().getInt(); 04538 for(; i!=iend; ++i) { 04539 if (i < iend-1) { 04540 os << "(" << push << "*"; 04541 } 04542 os << space << e[1]; 04543 } 04544 for (i=0; i < iend-1; ++i) os << push << ")"; 04545 } 04546 else 04547 throw SmtlibException("TheoryArithOld::print: SMTLIB: POW not supported: " + e.toString(PRESENTATION_LANG)); 04548 // os << "(" << push << "^ " << e[1] << space << e[0] << push << ")"; 04549 break; 04550 case DIVIDE: { 04551 throw SmtlibException("TheoryArithOld::print: SMTLIB: unexpected use of DIVIDE"); 04552 break; 04553 } 04554 case LT: { 04555 Rational r; 04556 os << "(" << push << "<" << space; 04557 os << e[0] << space << e[1] << push << ")"; 04558 break; 04559 } 04560 case LE: { 04561 Rational r; 04562 os << "(" << push << "<=" << space; 04563 os << e[0] << space << e[1] << push << ")"; 04564 break; 04565 } 04566 case GT: { 04567 Rational r; 04568 os << "(" << push << ">" << space; 04569 os << e[0] << space << e[1] << push << ")"; 04570 break; 04571 } 04572 case GE: { 04573 Rational r; 04574 os << "(" << push << ">=" << space; 04575 os << e[0] << space << e[1] << push << ")"; 04576 break; 04577 } 04578 case DARK_SHADOW: 04579 throw SmtlibException("TheoryArithOld::print: SMTLIB: DARK_SHADOW not supported"); 04580 os << "(" << push << "DARK_SHADOW" << space << e[0] 04581 << space << e[1] << push << ")"; 04582 break; 04583 case GRAY_SHADOW: 04584 throw SmtlibException("TheoryArithOld::print: SMTLIB: GRAY_SHADOW not supported"); 04585 os << "GRAY_SHADOW(" << push << e[0] << "," << space << e[1] 04586 << "," << space << e[2] << "," << space << e[3] << push << ")"; 04587 break; 04588 default: 04589 throw SmtlibException("TheoryArithOld::print: SMTLIB: default not supported"); 04590 // Print the top node in the default LISP format, continue with 04591 // pretty-printing for children. 04592 e.printAST(os); 04593 04594 break; 04595 } 04596 break; // end of case SMTLIB_LANG 04597 } 04598 case LISP_LANG: 04599 switch(e.getKind()) { 04600 case REAL: 04601 case INT: 04602 case RATIONAL_EXPR: 04603 case NEGINF: 04604 case POSINF: 04605 e.print(os); 04606 break; 04607 case SUBRANGE: 04608 if(e.arity() != 2) e.printAST(os); 04609 else 04610 os << "(" << push << "SUBRANGE" << space << e[0] 04611 << space << e[1] << push << ")"; 04612 break; 04613 case IS_INTEGER: 04614 if(e.arity() == 1) 04615 os << "(" << push << "IS_INTEGER" << space << e[0] << push << ")"; 04616 else 04617 e.printAST(os); 04618 break; 04619 case PLUS: { 04620 int i=0, iend=e.arity(); 04621 os << "(" << push << "+"; 04622 for(; i!=iend; ++i) os << space << e[i]; 04623 os << push << ")"; 04624 break; 04625 } 04626 case MINUS: 04627 //os << "(" << push << e[0] << space << "- " << e[1] << push << ")"; 04628 os << "(" << push << "- " << e[0] << space << e[1] << push << ")"; 04629 break; 04630 case UMINUS: 04631 os << "(" << push << "-" << space << e[0] << push << ")"; 04632 break; 04633 case MULT: { 04634 int i=0, iend=e.arity(); 04635 os << "(" << push << "*"; 04636 for(; i!=iend; ++i) os << space << e[i]; 04637 os << push << ")"; 04638 break; 04639 } 04640 case POW: 04641 os << "(" << push << "^ " << e[1] << space << e[0] << push << ")"; 04642 break; 04643 case DIVIDE: 04644 os << "(" << push << "/ " << e[0] << space << e[1] << push << ")"; 04645 break; 04646 case LT: 04647 os << "(" << push << "< " << e[0] << space << e[1] << push << ")"; 04648 break; 04649 case LE: 04650 os << "(" << push << "<= " << e[0] << space << e[1] << push << ")"; 04651 break; 04652 case GT: 04653 os << "(" << push << "> " << e[1] << space << e[0] << push << ")"; 04654 break; 04655 case GE: 04656 os << "(" << push << ">= " << e[0] << space << e[1] << push << ")"; 04657 break; 04658 case DARK_SHADOW: 04659 os << "(" << push << "DARK_SHADOW" << space << e[0] 04660 << space << e[1] << push << ")"; 04661 break; 04662 case GRAY_SHADOW: 04663 os << "(" << push << "GRAY_SHADOW" << space << e[0] << space 04664 << e[1] << space << e[2] << space << e[3] << push << ")"; 04665 break; 04666 default: 04667 // Print the top node in the default LISP format, continue with 04668 // pretty-printing for children. 04669 e.printAST(os); 04670 04671 break; 04672 } 04673 break; // end of case LISP_LANG 04674 default: 04675 // Print the top node in the default LISP format, continue with 04676 // pretty-printing for children. 04677 e.printAST(os); 04678 } 04679 return os; 04680 } 04681 04682 Theorem TheoryArithOld::inequalityToFind(const Theorem& inequalityThm, bool normalizeRHS) { 04683 04684 // Which side of the inequality 04685 int index = (normalizeRHS ? 1 : 0); 04686 04687 TRACE("arith find", "inequalityToFind(", int2string(index) + ", " + inequalityThm.getExpr().toString(), ")"); 04688 04689 // Get the inequality expression 04690 const Expr& inequality = inequalityThm.getExpr(); 04691 04692 // The theorem we will return 04693 Theorem inequalityFindThm; 04694 04695 // If the inequality side has a find 04696 if (inequality[index].hasFind()) { 04697 // Get the find of the rhs (lhs) 04698 Theorem rhsFindThm = inequality[index].getFind(); 04699 // Get the theorem simplifys the find (in case the updates haven't updated all the finds yet 04700 // Fixed with d_theroyCore.inUpdate() 04701 rhsFindThm = transitivityRule(rhsFindThm, simplify(rhsFindThm.getRHS())); 04702 // If not the same as the original 04703 Expr rhsFind = rhsFindThm.getRHS(); 04704 if (rhsFind != inequality[index]) { 04705 // Substitute in the inequality 04706 vector<unsigned> changed; 04707 vector<Theorem> children; 04708 changed.push_back(index); 04709 children.push_back(rhsFindThm); 04710 rhsFindThm = iffMP(inequalityThm, substitutivityRule(inequality, changed, children)); 04711 // If on the left-hand side, we are done 04712 if (index == 0) 04713 inequalityFindThm = rhsFindThm; 04714 else 04715 // If on the right-hand side and left-hand side is 0, normalize it 04716 if (inequality[0].isRational() && inequality[0].getRational() == 0) 04717 inequalityFindThm = normalize(rhsFindThm); 04718 else 04719 inequalityFindThm = rhsFindThm; 04720 } else 04721 inequalityFindThm = inequalityThm; 04722 } else 04723 inequalityFindThm = inequalityThm; 04724 04725 04726 TRACE("arith find", "inequalityToFind ==>", inequalityFindThm.getExpr(), ""); 04727 04728 return inequalityFindThm; 04729 } 04730 04731 void TheoryArithOld::registerAtom(const Expr& e) { 04732 // Trace it 04733 TRACE("arith atoms", "registerAtom(", e.toString(), ")"); 04734 04735 // Mark it 04736 formulaAtoms[e] = true; 04737 04738 // If it is a atomic formula, add it to the map 04739 if (e.isAbsAtomicFormula() && isIneq(e)) { 04740 Expr rightSide = e[1]; 04741 Rational leftSide = e[0].getRational(); 04742 04743 //Get the terms for : c1 op t1 and t2 -op c2 04744 Expr t1, t2; 04745 Rational c1, c2; 04746 extractTermsFromInequality(e, c1, t1, c2, t2); 04747 04748 if (true) { 04749 TRACE("arith atoms", "registering lower bound for ", t1.toString(), " = " + c1.toString() + ")"); 04750 formulaAtomLowerBound[t1].insert(pair<Rational, Expr>(c1, e)); 04751 04752 // See if the bounds on the registered term can infered from already asserted facts 04753 CDMap<Expr, Rational>::iterator lowerBoundFind = termLowerBound.find(t1); 04754 if (lowerBoundFind != termLowerBound.end()) { 04755 Rational boundValue = (*lowerBoundFind).second; 04756 Theorem boundThm = termLowerBoundThm[t1]; 04757 Expr boundIneq = boundThm.getExpr(); 04758 if (boundValue > c1 || (boundValue == c1 && !(boundIneq.getKind() == LE && e.getKind() == LT))) { 04759 enqueueFact(getCommonRules()->implMP(boundThm, d_rules->implyWeakerInequality(boundIneq, e))); 04760 } 04761 } 04762 04763 // See if the bounds on the registered term can falsified from already asserted facts 04764 CDMap<Expr, Rational>::iterator upperBoundFind = termUpperBound.find(t1); 04765 if (upperBoundFind != termUpperBound.end()) { 04766 Rational boundValue = (*upperBoundFind).second; 04767 Theorem boundThm = termUpperBoundThm[t1]; 04768 Expr boundIneq = boundThm.getExpr(); 04769 if (boundValue < c1 || (boundValue == c1 && boundIneq.getKind() == LT && e.getKind() == LT)) { 04770 enqueueFact(getCommonRules()->implMP(boundThm, d_rules->implyNegatedInequality(boundIneq, e))); 04771 } 04772 } 04773 04774 TRACE("arith atoms", "registering upper bound for ", t2.toString(), " = " + c2.toString() + ")"); 04775 formulaAtomUpperBound[t2].insert(pair<Rational, Expr>(c2, e)); 04776 } 04777 } 04778 } 04779 04780 TheoryArithOld::DifferenceLogicGraph::DifferenceLogicGraph(TheoryArithOld* arith, TheoryCore* core, ArithProofRules* rules, Context* context) 04781 : d_pathLenghtThres(&(core->getFlags()["pathlength-threshold"].getInt())), 04782 arith(arith), 04783 core(core), 04784 rules(rules), 04785 unsat_theorem(context), 04786 biggestEpsilon(context, 0, 0), 04787 smallestPathDifference(context, 1, 0), 04788 leGraph(context), 04789 varInCycle(context) 04790 { 04791 } 04792 04793 Theorem TheoryArithOld::DifferenceLogicGraph::getUnsatTheorem() { 04794 return unsat_theorem; 04795 } 04796 04797 bool TheoryArithOld::DifferenceLogicGraph::isUnsat() { 04798 return !getUnsatTheorem().isNull(); 04799 } 04800 04801 bool TheoryArithOld::DifferenceLogicGraph::existsEdge(const Expr& x, const Expr& y) { 04802 Expr index = x - y; 04803 04804 Graph::iterator find_le = leGraph.find(index); 04805 if (find_le != leGraph.end()) { 04806 EdgeInfo edge_info = (*find_le).second; 04807 if (edge_info.isDefined()) return true; 04808 } 04809 04810 return false; 04811 } 04812 04813 bool TheoryArithOld::DifferenceLogicGraph::inCycle(const Expr& x) { 04814 return (varInCycle.find(x) != varInCycle.end()); 04815 } 04816 04817 TheoryArithOld::DifferenceLogicGraph::Graph::ElementReference TheoryArithOld::DifferenceLogicGraph::getEdge(const Expr& x, const Expr& y) { 04818 Expr index = x - y; 04819 Graph::ElementReference edge_info = leGraph[index]; 04820 04821 // If a new edge and x != y, then add vertices to the apropriate lists 04822 if (x != y && !edge_info.get().isDefined()) { 04823 04824 // Adding a new edge, take a resource 04825 core->getResource(); 04826 04827 EdgesList::iterator y_it = incomingEdges.find(y); 04828 if (y_it == incomingEdges.end() || (*y_it).second == 0) { 04829 CDList<Expr>* list = new(true) CDList<Expr>(core->getCM()->getCurrentContext()); 04830 list->push_back(x); 04831 incomingEdges[y] = list; 04832 } else 04833 ((*y_it).second)->push_back(x); 04834 04835 EdgesList::iterator x_it = outgoingEdges.find(x); 04836 if (x_it == outgoingEdges.end() || (*x_it).second == 0) { 04837 CDList<Expr>* list = new(true) CDList<Expr>(core->getCM()->getCurrentContext()); 04838 list->push_back(y); 04839 outgoingEdges[x] = list; 04840 } else 04841 ((*x_it).second)->push_back(y); 04842 } 04843 04844 return edge_info; 04845 } 04846 04847 TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::DifferenceLogicGraph::getEdgeWeight(const Expr& x, const Expr& y) { 04848 if (!existsEdge(x, y)) 04849 return EpsRational::PlusInfinity; 04850 else { 04851 EdgeInfo edgeInfo = getEdge(x, y).get(); 04852 return edgeInfo.length; 04853 } 04854 } 04855 04856 04857 void TheoryArithOld::DifferenceLogicGraph::addEdge(const Expr& x, const Expr& y, const Rational& bound, const Theorem& edge_thm) { 04858 04859 TRACE("arith diff", x, " --> ", y); 04860 DebugAssert(x != y, "addEdge, given two equal expressions!"); 04861 04862 if (isUnsat()) return; 04863 04864 // If out of resources, bail out 04865 if (core->outOfResources()) return; 04866 04867 // Get the kind of the inequality (NOTE isNull -- for model computation we add a vertex with no theorem) 04868 // FIXME: Later, add a debug assert for the theorem that checks that this variable is cvc3diffLogicSource 04869 int kind = (edge_thm.isNull() ? LE : edge_thm.getExpr().getKind()); 04870 DebugAssert(kind == LT || kind == LE, "addEdge, not an <= or <!"); 04871 04872 // Get the EpsRational bound 04873 Rational k = (kind == LE ? 0 : -1); 04874 EpsRational c(bound, k); 04875 04876 // Get the current (or a fresh new edge info) 04877 Graph::ElementReference edgeInfoRef = getEdge(x, y); 04878 // If uninitialized, or smaller length (we prefer shorter paths, so one edge is better) 04879 EdgeInfo edgeInfo = edgeInfoRef.get(); 04880 // If the edge changed to the better, do the work 04881 if (!edgeInfo.isDefined() || c <= edgeInfo.length) { 04882 04883 // Update model generation data 04884 if (edgeInfo.isDefined()) { 04885 EpsRational difference = edgeInfo.length - c; 04886 Rational rationalDifference = difference.getRational(); 04887 if (rationalDifference > 0 && rationalDifference < smallestPathDifference) { 04888 smallestPathDifference = rationalDifference; 04889 TRACE("diff model", "smallest path difference : ", smallestPathDifference, ""); 04890 } 04891 } 04892 Rational newEpsilon = - c.getEpsilon(); 04893 if (newEpsilon > biggestEpsilon) { 04894 biggestEpsilon = newEpsilon; 04895 TRACE("diff model", "biggest epsilon : ", biggestEpsilon, ""); 04896 } 04897 04898 // Set the edge info 04899 edgeInfo.length = c; 04900 edgeInfo.explanation = edge_thm; 04901 edgeInfo.path_length_in_edges = 1; 04902 edgeInfoRef = edgeInfo; 04903 04904 04905 // Try simple cycle x --> y --> x, to keep invariants (no cycles or one negative) 04906 if (existsEdge(y, x)) { 04907 varInCycle[x] = true; 04908 varInCycle[y] = true; 04909 tryUpdate(x, y, x); 04910 if (isUnsat()) 04911 return; 04912 } 04913 04914 // For all edges coming into x, z ---> x, update z ---> y and add updated ones to the updated_in_y vector 04915 CDList<Expr>* in_x = incomingEdges[x]; 04916 vector<Expr> updated_in_y; 04917 updated_in_y.push_back(x); 04918 04919 // If there 04920 if (in_x) { 04921 IF_DEBUG(int total = 0; int updated = 0;); 04922 for (unsigned it = 0; it < in_x->size() && !isUnsat(); it ++) { 04923 const Expr& z = (*in_x)[it]; 04924 if (z != arith->zero && z.hasFind() && core->find(z).getRHS() != z) continue; 04925 if (z != y && z != x && x != y) { 04926 IF_DEBUG(total ++;); 04927 TRACE("diff update", "trying with ", z.toString() + " --> ", x.toString()); 04928 if (tryUpdate(z, x, y)) { 04929 updated_in_y.push_back(z); 04930 IF_DEBUG(updated++;); 04931 } 04932 } 04933 } 04934 TRACE("diff updates", "Updates : ", int2string(updated), " of " + int2string(total)); 04935 } 04936 04937 // For all edges coming into y, z_1 ---> y, and all edges going out of y, y ---> z_2, update z1 --> z_2 04938 CDList<Expr>* out_y = outgoingEdges[y]; 04939 if (out_y) 04940 for (unsigned it_z1 = 0; it_z1 < updated_in_y.size() && !isUnsat(); it_z1 ++) { 04941 for (unsigned it_z2 = 0; it_z2 < out_y->size() && !isUnsat(); it_z2 ++) { 04942 const Expr& z1 = updated_in_y[it_z1]; 04943 const Expr& z2 = (*out_y)[it_z2]; 04944 if (z2 != arith->zero && z2.hasFind() && core->find(z2).getRHS() != z2) continue; 04945 if (z1 != z2 && z1 != y && z2 != y) 04946 tryUpdate(z1, y, z2); 04947 } 04948 } 04949 04950 } else { 04951 TRACE("arith propagate", "could have propagated ", edge_thm.getExpr(), edge_thm.isAssump() ? " ASSUMPTION " : "not assumption"); 04952 04953 } 04954 04955 } 04956 04957 void TheoryArithOld::DifferenceLogicGraph::getEdgeTheorems(const Expr& x, const Expr& z, const EdgeInfo& edgeInfo, std::vector<Theorem>& outputTheorems) { 04958 TRACE("arith diff", "Getting theorems from ", x, " to " + z.toString() + " length = " + edgeInfo.length.toString() + ", edge_length = " + int2string(edgeInfo.path_length_in_edges)); 04959 04960 if (edgeInfo.path_length_in_edges == 1) { 04961 DebugAssert(x == sourceVertex || z == sourceVertex || !edgeInfo.explanation.isNull(), "Edge from " + x.toString() + " to " + z.toString() + " has no theorem!"); 04962 if (x != sourceVertex && z != sourceVertex) 04963 outputTheorems.push_back(edgeInfo.explanation); 04964 } 04965 else { 04966 const Expr& y = edgeInfo.in_path_vertex; 04967 EdgeInfo x_y = getEdge(x, y); 04968 DebugAssert(x_y.isDefined(), "getEdgeTheorems: the cycle edge is not defined!"); 04969 EdgeInfo y_z = getEdge(y, z); 04970 DebugAssert(y_z.isDefined(), "getEdgeTheorems: the cycle edge is not defined!"); 04971 getEdgeTheorems(x, y, x_y, outputTheorems); 04972 getEdgeTheorems(y, z, y_z, outputTheorems); 04973 } 04974 } 04975 04976 void TheoryArithOld::DifferenceLogicGraph::analyseConflict(const Expr& x, int kind) { 04977 04978 // Get the cycle info 04979 Graph::ElementReference x_x_cycle_ref = getEdge(x, x); 04980 EdgeInfo x_x_cycle = x_x_cycle_ref.get(); 04981 04982 DebugAssert(x_x_cycle.isDefined(), "analyseConflict: the cycle edge is not defined!"); 04983 04984 // Vector to keep the theorems in 04985 vector<Theorem> inequalities; 04986 04987 // Get the theorems::analyse 04988 getEdgeTheorems(x, x, x_x_cycle, inequalities); 04989 04990 // Set the unsat theorem 04991 unsat_theorem = rules->cycleConflict(inequalities); 04992 04993 TRACE("diff unsat", "negative cycle : ", int2string(inequalities.size()), " vertices."); 04994 } 04995 04996 bool TheoryArithOld::DifferenceLogicGraph::tryUpdate(const Expr& x, const Expr& y, const Expr& z) { 04997 04998 // x -> y -> z, if z -> x they are all in a cycle 04999 if (existsEdge(z, x)) { 05000 varInCycle[x] = true; 05001 varInCycle[y] = true; 05002 varInCycle[z] = true; 05003 } 05004 05005 //Get all the edges 05006 Graph::ElementReference x_y_le_ref = getEdge(x, y); 05007 EdgeInfo x_y_le = x_y_le_ref; 05008 if (*d_pathLenghtThres >= 0 && x_y_le.path_length_in_edges > *d_pathLenghtThres) return false; 05009 05010 Graph::ElementReference y_z_le_ref = getEdge(y, z); 05011 EdgeInfo y_z_le = y_z_le_ref; 05012 if (*d_pathLenghtThres >= 0 && y_z_le.path_length_in_edges > *d_pathLenghtThres) return false; 05013 05014 Graph::ElementReference x_z_le_ref = getEdge(x, z); 05015 EdgeInfo x_z_le = x_z_le_ref; 05016 05017 bool cycle = (x == z); 05018 bool updated = false; 05019 05020 // Try <= + <= --> <= 05021 if (!isUnsat() && x_y_le.isDefined() && y_z_le.isDefined()) { 05022 EpsRational combined_length = x_y_le.length + y_z_le.length; 05023 int combined_edge_length = x_y_le.path_length_in_edges + y_z_le.path_length_in_edges; 05024 05025 if (!x_z_le.isDefined() || combined_length < x_z_le.length || 05026 (combined_length == x_z_le.length && (combined_edge_length < x_z_le.path_length_in_edges))) { 05027 05028 if (!cycle || combined_length <= EpsRational::Zero) { 05029 05030 if (!cycle || combined_length < EpsRational::Zero) { 05031 05032 // Remember the path differences 05033 if (!cycle) { 05034 EpsRational difference = x_z_le.length - combined_length; 05035 Rational rationalDifference = difference.getRational(); 05036 Rational newEpsilon = - x_z_le.length.getEpsilon(); 05037 if (rationalDifference > 0 && rationalDifference < smallestPathDifference) { 05038 smallestPathDifference = rationalDifference; 05039 TRACE("diff model", "smallest path difference : ", smallestPathDifference, ""); 05040 } 05041 if (newEpsilon > biggestEpsilon) { 05042 biggestEpsilon = newEpsilon; 05043 TRACE("diff model", "biggest epsilon : ", biggestEpsilon, ""); 05044 } 05045 } 05046 05047 // If we have a constraint among two integers variables strenghten it 05048 bool addAndEnqueue = false; 05049 if (core->okToEnqueue() && !combined_length.isInteger()) 05050 if (x.getType() == arith->intType() && z.getType() == arith->intType()) 05051 addAndEnqueue = true; 05052 05053 x_z_le.length = combined_length; 05054 x_z_le.path_length_in_edges = combined_edge_length; 05055 x_z_le.in_path_vertex = y; 05056 x_z_le_ref = x_z_le; 05057 05058 if (addAndEnqueue) { 05059 vector<Theorem> pathTheorems; 05060 getEdgeTheorems(x, z, x_z_le, pathTheorems); 05061 core->enqueueFact(rules->addInequalities(pathTheorems)); 05062 } 05063 05064 TRACE("arith diff", x.toString() + " -- > " + z.toString(), " : ", combined_length.toString()); 05065 updated = true; 05066 } else 05067 if (core->okToEnqueue()) { 05068 // 0 length cycle 05069 vector<Theorem> antecedentThms; 05070 getEdgeTheorems(x, y, x_y_le, antecedentThms); 05071 getEdgeTheorems(y, z, y_z_le, antecedentThms); 05072 core->enqueueFact(rules->implyEqualities(antecedentThms)); 05073 } 05074 05075 // Try to propagate somthing in the original formula 05076 if (updated && !cycle && x != sourceVertex && z != sourceVertex && core->okToEnqueue()) 05077 arith->tryPropagate(x, z, x_z_le, LE); 05078 05079 } 05080 05081 if (cycle && combined_length < EpsRational::Zero) 05082 analyseConflict(x, LE); 05083 } 05084 } 05085 05086 return updated; 05087 } 05088 05089 void TheoryArithOld::DifferenceLogicGraph::expandSharedTerm(const Expr& x) { 05090 05091 } 05092 05093 TheoryArithOld::DifferenceLogicGraph::~DifferenceLogicGraph() { 05094 for (EdgesList::iterator it = incomingEdges.begin(), it_end = incomingEdges.end(); it != it_end; it ++) { 05095 if ((*it).second) { 05096 delete (*it).second; 05097 free ((*it).second); 05098 } 05099 } 05100 for (EdgesList::iterator it = outgoingEdges.begin(), it_end = outgoingEdges.end(); it != it_end; it ++) { 05101 if ((*it).second) { 05102 delete (*it).second; 05103 free ((*it).second); 05104 } 05105 } 05106 } 05107 05108 void TheoryArithOld::tryPropagate(const Expr& x, const Expr& y, const DifferenceLogicGraph::EdgeInfo& x_y_edge, int kind) { 05109 05110 TRACE("diff atoms", "trying propagation", " x = " + x.toString(), " y = " + y.toString()); 05111 05112 // bail on non representative terms (we don't pass non-representative terms) 05113 // if (x.hasFind() && find(x).getRHS() != x) return; 05114 // if (y.hasFind() && find(y).getRHS() != y) return; 05115 05116 // given edge x - z (kind) lenth 05117 05118 // Make the index (c1 <= y - x) 05119 vector<Expr> t1_summands; 05120 t1_summands.push_back(rat(0)); 05121 if (y != zero) t1_summands.push_back(y); 05122 // We have to canonize in case it is nonlinear 05123 // nonlinear terms are canonized with a constants --> 1*x*y, hence (-1)*1*x*y will not be canonical 05124 if (x != zero) t1_summands.push_back(canon(rat(-1)*x).getRHS()); 05125 Expr t1 = canon(plusExpr(t1_summands)).getRHS(); 05126 05127 TRACE("diff atoms", "trying propagation", " t1 = " + t1.toString(), ""); 05128 05129 // The constant c1 <= y - x 05130 Rational c1 = - x_y_edge.length.getRational(); 05131 05132 // See if we can propagate anything to the formula atoms 05133 // c1 <= t1 ===> c <= t1 for c < c1 05134 AtomsMap::iterator find = formulaAtomLowerBound.find(t1); 05135 AtomsMap::iterator find_end = formulaAtomLowerBound.end(); 05136 if (find != find_end) { 05137 set< pair<Rational, Expr> >::iterator bounds = (*find).second.begin(); 05138 set< pair<Rational, Expr> >::iterator bounds_end = (*find).second.end(); 05139 while (bounds != bounds_end) { 05140 const Expr& implied = (*bounds).second; 05141 // Try to do some theory propagation 05142 if ((*bounds).first < c1 || (implied.getKind() == LE && (*bounds).first == c1)) { 05143 TRACE("diff atoms", "found propagation", "", ""); 05144 // c1 <= t1 => c <= t1 (for c <= c1) 05145 // c1 < t1 => c <= t1 (for c <= c1) 05146 // c1 <= t1 => c < t1 (for c < c1) 05147 vector<Theorem> antecedentThms; 05148 diffLogicGraph.getEdgeTheorems(x, y, x_y_edge, antecedentThms); 05149 Theorem impliedThm = d_rules->implyWeakerInequalityDiffLogic(antecedentThms, implied); 05150 enqueueFact(impliedThm); 05151 } 05152 bounds ++; 05153 } 05154 } 05155 05156 // 05157 // c1 <= t1 ==> !(t1 <= c) for c < c1 05158 // ==> !(-c <= t2) 05159 // i.e. all coefficient in in the implied are opposite of t1 05160 find = formulaAtomUpperBound.find(t1); 05161 find_end = formulaAtomUpperBound.end(); 05162 if (find != find_end) { 05163 set< pair<Rational, Expr> >::iterator bounds = (*find).second.begin(); 05164 set< pair<Rational, Expr> >::iterator bounds_end = (*find).second.end(); 05165 while (bounds != bounds_end) { 05166 const Expr& implied = (*bounds).second; 05167 // Try to do some theory propagation 05168 if ((*bounds).first < c1) { 05169 TRACE("diff atoms", "found negated propagation", "", ""); 05170 vector<Theorem> antecedentThms; 05171 diffLogicGraph.getEdgeTheorems(x, y, x_y_edge, antecedentThms); 05172 Theorem impliedThm = d_rules->implyNegatedInequalityDiffLogic(antecedentThms, implied); 05173 enqueueFact(impliedThm); 05174 } 05175 bounds ++; 05176 } 05177 } 05178 } 05179 05180 void TheoryArithOld::DifferenceLogicGraph::computeModel() { 05181 05182 // If source vertex is null, create it 05183 if (sourceVertex.isNull()) { 05184 Theorem thm_exists_zero = arith->getCommonRules()->varIntroSkolem(arith->zero); 05185 sourceVertex = thm_exists_zero.getExpr()[1]; 05186 } 05187 05188 // The empty theorem to pass around 05189 Theorem thm; 05190 05191 // Add an edge to all the vertices 05192 EdgesList::iterator vertexIt = incomingEdges.begin(); 05193 EdgesList::iterator vertexItEnd = incomingEdges.end(); 05194 for (; vertexIt != vertexItEnd; vertexIt ++) { 05195 Expr vertex = (*vertexIt).first; 05196 if (core->find(vertex).getRHS() != vertex) continue; 05197 if (vertex != sourceVertex && !existsEdge(sourceVertex, vertex)) 05198 addEdge(sourceVertex, vertex, 0, thm); 05199 } 05200 vertexIt = outgoingEdges.begin(); 05201 vertexItEnd = outgoingEdges.end(); 05202 for (; vertexIt != vertexItEnd; vertexIt ++) { 05203 Expr vertex = (*vertexIt).first; 05204 if (core->find(vertex).getRHS() != vertex) continue; 05205 if (vertex != sourceVertex && !existsEdge(sourceVertex, vertex)) 05206 addEdge(sourceVertex, vertex, 0, thm); 05207 } 05208 05209 // Also add an edge to cvcZero 05210 if (!existsEdge(sourceVertex, arith->zero)) 05211 addEdge(sourceVertex, arith->zero, 0, thm); 05212 05213 // For the < edges we will have a small enough epsilon to add 05214 // So, we will upper-bound the number of vertices and then divide 05215 // the smallest edge with that number so as to not be able to bypass 05216 05217 } 05218 05219 Rational TheoryArithOld::DifferenceLogicGraph::getValuation(const Expr& x) { 05220 05221 // For numbers, return it's value 05222 if (x.isRational()) return x.getRational(); 05223 05224 // For the source vertex, we don't care 05225 if (x == sourceVertex) return 0; 05226 05227 // The path from source to targer vertex 05228 Graph::ElementReference x_le_c_ref = getEdge(sourceVertex, x); 05229 EdgeInfo x_le_c = x_le_c_ref; 05230 05231 // The path from source to zero (adjusment) 05232 Graph::ElementReference zero_le_c_ref = getEdge(sourceVertex, arith->zero); 05233 EdgeInfo zero_le_c = zero_le_c_ref; 05234 05235 TRACE("diff model", "zero adjustment: ", zero_le_c.length.getRational(), ""); 05236 TRACE("diff model", "zero adjustment (eps): ", zero_le_c.length.getEpsilon(), ""); 05237 05238 // Value adjusted with the epsilon 05239 Rational epsAdjustment = (biggestEpsilon > 0 ? (x_le_c.length.getEpsilon() - zero_le_c.length.getEpsilon()) * smallestPathDifference / (2 * (biggestEpsilon + 1)) : 0); 05240 Rational value = x_le_c.length.getRational() + epsAdjustment; 05241 05242 TRACE("diff model" , "biggest epsilon: ", biggestEpsilon, ""); 05243 TRACE("diff model" , "smallestPathDifference: ", smallestPathDifference, ""); 05244 TRACE("diff model" , "x_le_c.getEpsilon: ", x_le_c.length.getEpsilon(), ""); 05245 TRACE("diff model" , "x_le_c.length: ", x_le_c.length.getRational(), ""); 05246 05247 // Value adjusted with the shift for zero 05248 value = zero_le_c.length.getRational() - value; 05249 05250 TRACE("diff model", "Value of ", x, " : " + value.toString()); 05251 05252 // Return it 05253 return value; 05254 } 05255 05256 // The infinity constant 05257 const TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::DifferenceLogicGraph::EpsRational::PlusInfinity(PLUS_INFINITY); 05258 // The negative infinity constant 05259 const TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::DifferenceLogicGraph::EpsRational::MinusInfinity(MINUS_INFINITY); 05260 // The negative infinity constant 05261 const TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::DifferenceLogicGraph::EpsRational::Zero; 05262 05263 void TheoryArithOld::addMultiplicativeSignSplit(const Theorem& case_split_thm) { 05264 multiplicativeSignSplits.push_back(case_split_thm); 05265 } 05266 05267 bool TheoryArithOld::addPairToArithOrder(const Expr& smaller, const Expr& bigger) { 05268 TRACE("arith var order", "addPairToArithOrder(" + smaller.toString(), ", ", bigger.toString() + ")"); 05269 // We only accept arithmetic terms 05270 if (!isReal(smaller.getType()) && !isInt(smaller.getType())) return false; 05271 if (!isReal(bigger.getType()) && !isInt(bigger.getType())) return false; 05272 // We don't want to introduce loops 05273 FatalAssert(!d_graph.lessThan(smaller, bigger), "The pair (" + bigger.toString() + "," + smaller.toString() + ") is already in the order"); 05274 // Update the graph 05275 d_graph.addEdge(smaller, bigger); 05276 return true; 05277 } 05278 05279 bool TheoryArithOld::isNonlinearSumTerm(const Expr& term) { 05280 if (isPow(term)) return true; 05281 if (!isMult(term)) return false; 05282 int vars = 0; 05283 for (int j = 0; j < term.arity(); j ++) 05284 if (isPow(term[j])) return true; 05285 else if (isLeaf(term[j])) { 05286 vars ++; 05287 if (vars > 1) return true; 05288 } 05289 return false; 05290 } 05291 05292 bool TheoryArithOld::isNonlinearEq(const Expr& e) { 05293 05294 DebugAssert(e.isEq(), "TheoryArithOld::isNonlinear: expecting an equation" + e.toString()); 05295 05296 const Expr& lhs = e[0]; 05297 const Expr& rhs = e[1]; 05298 05299 if (isNonlinearSumTerm(lhs) || isNonlinearSumTerm(rhs)) return true; 05300 05301 // Check the right-hand side 05302 for (int i = 0; i < lhs.arity(); i ++) 05303 if (isNonlinearSumTerm(lhs[i])) return true; 05304 05305 // Check the left hand side 05306 for (int i = 0; i < rhs.arity(); i ++) 05307 if (isNonlinearSumTerm(rhs[i])) return true; 05308 05309 return false; 05310 } 05311 05312 05313 bool TheoryArithOld::isPowersEquality(const Expr& eq, Expr& power1, Expr& power2) { 05314 // equality should be in the form 0 + x1^n - x2^n = 0 05315 DebugAssert(eq.isEq(), "TheoryArithOld::isPowersEquality, expecting an equality got " + eq.toString()); 05316 05317 if (!isPlus(eq[0])) return false; 05318 if (eq[0].arity() != 3) return false; 05319 if (!(eq[0][0].isRational()) || !(eq[0][0].getRational() == 0)) return false; 05320 05321 // Process the first term 05322 Expr term1 = eq[0][1]; 05323 Rational term1_c; 05324 if (isPow(term1)) { 05325 term1_c = 1; 05326 power1 = term1; 05327 } else 05328 if (isMult(term1) && term1.arity() == 2) { 05329 if (term1[0].isRational()) { 05330 term1_c = term1[0].getRational(); 05331 if (isPow(term1[1])) { 05332 if (term1_c == 1) power1 = term1[1]; 05333 else if (term1_c == -1) power2 = term1[1]; 05334 else return false; 05335 } else return false; 05336 } else return false; 05337 } else return false; 05338 05339 // Process the second term 05340 Expr term2 = eq[0][2]; 05341 Rational term2_c; 05342 if (isPow(term2)) { 05343 term2_c = 1; 05344 power1 = term2; 05345 } else 05346 if (isMult(term2) && term2.arity() == 2) { 05347 if (term2[0].isRational()) { 05348 term2_c = term2[0].getRational(); 05349 if (isPow(term2[1])) { 05350 if (term2_c == 1) power1 = term2[1]; 05351 else if (term2_c == -1) power2 = term2[1]; 05352 else return false; 05353 } else return false; 05354 } else return false; 05355 } else return false; 05356 05357 // Check that they are of opposite signs 05358 if (term1_c == term2_c) return false; 05359 05360 // Check that the powers are equal numbers 05361 if (!power1[0].isRational()) return false; 05362 if (!power2[0].isRational()) return false; 05363 if (power1[0].getRational() != power2[0].getRational()) return false; 05364 05365 // Everything is fine 05366 return true; 05367 } 05368 05369 bool TheoryArithOld::isPowerEquality(const Expr& eq, Rational& constant, Expr& power1) { 05370 DebugAssert(eq.isEq(), "TheoryArithOld::isPowerEquality, expecting an equality got " + eq.toString()); 05371 05372 if (!isPlus(eq[0])) return false; 05373 if (eq[0].arity() != 2) return false; 05374 if (!eq[0][0].isRational()) return false; 05375 05376 constant = eq[0][0].getRational(); 05377 05378 Expr term = eq[0][1]; 05379 if (isPow(term)) { 05380 power1 = term; 05381 constant = -constant; 05382 } else 05383 if (isMult(term) && term.arity() == 2) { 05384 if (term[0].isRational() && isPow(term[1])) { 05385 Rational term2_c = term[0].getRational(); 05386 if (term2_c == 1) { 05387 power1 = term[1]; 05388 constant = -constant; 05389 } else if (term2_c == -1) { 05390 power1 = term[1]; 05391 return true; 05392 } else return false; 05393 } else return false; 05394 } else return false; 05395 05396 // Check that the power is an integer 05397 if (!power1[0].isRational()) return false; 05398 if (!power1[0].getRational().isInteger()) return false; 05399 05400 return true; 05401 } 05402 05403 int TheoryArithOld::termDegree(const Expr& e) { 05404 if (isLeaf(e)) return 1; 05405 if (isPow(e)) return termDegree(e[1]) * e[0].getRational().getInt(); 05406 if (isMult(e)) { 05407 int degree = 0; 05408 for (int i = 0; i < e.arity(); i ++) degree += termDegree(e[i]); 05409 return degree; 05410 } 05411 return 0; 05412 } 05413 05414 bool TheoryArithOld::canPickEqMonomial(const Expr& right) 05415 { 05416 DebugAssert(right.arity() > 1, "TheoryArithOld::canPickEqMonomial, expecting > 1 child, got " + right.arity()); 05417 05418 Expr::iterator istart = right.begin(); 05419 Expr::iterator iend = right.end(); 05420 05421 // Skip the first one 05422 istart++; 05423 for(Expr::iterator i = istart; i != iend; ++i) { 05424 05425 Expr leaf; 05426 Rational coeff; 05427 05428 // Check if linear term 05429 if (isLeaf(*i)) { 05430 leaf = *i; 05431 coeff = 1; 05432 } else if (isMult(*i) && (*i).arity() == 2 && (*i)[0].isRational() && isLeaf((*i)[1])) { 05433 leaf = (*i)[1]; 05434 coeff = abs((*i)[0].getRational()); 05435 } else 05436 continue; 05437 05438 // If integer, must be coeff 1/-1 05439 if (!isIntegerThm(leaf).isNull()) 05440 if (coeff != 1 && coeff != -1) 05441 continue; 05442 05443 // Check if a leaf in other ones 05444 Expr::iterator j; 05445 for (j = istart; j != iend; ++j) 05446 if (j != i && isLeafIn(leaf, *j)) 05447 break; 05448 if (j == iend) 05449 return true; 05450 } 05451 05452 return false; 05453 } 05454 05455 bool TheoryArithOld::isBounded(const Expr& t, BoundsQueryType queryType) { 05456 TRACE("arith shared", "isBounded(", t.toString(), ")"); 05457 return hasUpperBound(t, queryType) && hasLowerBound(t, queryType); 05458 } 05459 05460 TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::getUpperBound(const Expr& t, BoundsQueryType queryType) 05461 { 05462 TRACE("arith shared", "getUpperBound(", t.toString(), ")"); 05463 05464 // If t is a constant it's bounded 05465 if (t.isRational()) { 05466 TRACE("arith shared", "getUpperBound(", t.toString(), ") ==> " + t.getRational().toString()); 05467 return t.getRational(); 05468 } 05469 05470 // If buffered, just return it 05471 CDMap<Expr, DifferenceLogicGraph::EpsRational>::iterator find_t = termUpperBounded.find(t); 05472 if (find_t != termUpperBounded.end()) { 05473 TRACE("arith shared", "getUpperBound(", t.toString(), ") ==> " + (*find_t).second.toString()); 05474 return (*find_t).second; 05475 } else if (queryType == QueryWithCacheAll) { 05476 // Asked for cache query, so no bound is found 05477 TRACE("arith shared", "getUpperBound(", t.toString(), ") ==> +inf"); 05478 return DifferenceLogicGraph::EpsRational::PlusInfinity; 05479 } 05480 05481 // Assume it's not bounded 05482 DifferenceLogicGraph::EpsRational upperBound = DifferenceLogicGraph::EpsRational::PlusInfinity; 05483 05484 // We always buffer the leaves, so all that's left are the terms 05485 if (!isLeaf(t)) { 05486 if (isMult(t)) { 05487 // We only handle linear terms 05488 if (!isNonlinearSumTerm(t)) { 05489 // Separate the multiplication 05490 Expr c, v; 05491 separateMonomial(t, c, v); 05492 // Get the upper-bound for the variable 05493 if (c.getRational() > 0) upperBound = getUpperBound(v); 05494 else upperBound = getLowerBound(v); 05495 if (upperBound.isFinite()) upperBound = upperBound * c.getRational(); 05496 else upperBound = DifferenceLogicGraph::EpsRational::PlusInfinity; 05497 } 05498 } else if (isPlus(t)) { 05499 // If one of them is unconstrained then the term itself is unconstrained 05500 upperBound = DifferenceLogicGraph::EpsRational::Zero; 05501 for (int i = 0; i < t.arity(); i ++) { 05502 Expr t_i = t[i]; 05503 DifferenceLogicGraph::EpsRational t_i_upperBound = getUpperBound(t_i, queryType); 05504 if (t_i_upperBound.isFinite()) upperBound = upperBound + t_i_upperBound; 05505 else { 05506 upperBound = DifferenceLogicGraph::EpsRational::PlusInfinity; 05507 // Not-bounded, check for constrained 05508 if (queryType == QueryWithCacheLeavesAndConstrainedComputation) { 05509 for(; i < t.arity() && isConstrainedAbove(t[i], QueryWithCacheLeaves); i ++); 05510 if (i == t.arity()) { 05511 TRACE("arith shared", "getUpperBound(", t.toString(), ") ==> constrained"); 05512 termConstrainedAbove[t] = true; 05513 } 05514 break; 05515 } else break; 05516 } 05517 } 05518 } 05519 } 05520 05521 // Buffer it 05522 if (upperBound.isFinite()) { 05523 termUpperBounded[t] = upperBound; 05524 termConstrainedAbove[t] = true; 05525 } 05526 05527 // Return if bounded or not 05528 TRACE("arith shared", "getUpperBound(", t.toString(), ") ==> " + upperBound.toString()); 05529 return upperBound; 05530 } 05531 05532 TheoryArithOld::DifferenceLogicGraph::EpsRational TheoryArithOld::getLowerBound(const Expr& t, BoundsQueryType queryType) 05533 { 05534 TRACE("arith shared", "getLowerBound(", t.toString(), ")"); 05535 05536 // If t is a constant it's bounded 05537 if (t.isRational()) { 05538 TRACE("arith shared", "getLowerBound(", t.toString(), ") ==> " + t.getRational().toString()); 05539 return t.getRational(); 05540 } 05541 05542 // If buffered, just return it 05543 CDMap<Expr, DifferenceLogicGraph::EpsRational>::iterator t_find = termLowerBounded.find(t); 05544 if (t_find != termLowerBounded.end()) { 05545 TRACE("arith shared", "getLowerBound(", t.toString(), ") ==> " + (*t_find).second.toString()); 05546 return (*t_find).second; 05547 } else if (queryType == QueryWithCacheAll) { 05548 // Asked for cache query, so no bound is found 05549 TRACE("arith shared", "getLowerBound(", t.toString(), ") ==> -inf"); 05550 return DifferenceLogicGraph::EpsRational::MinusInfinity; 05551 } 05552 05553 // Assume it's not bounded 05554 DifferenceLogicGraph::EpsRational lowerBound = DifferenceLogicGraph::EpsRational::MinusInfinity; 05555 05556 // Leaves are always buffered 05557 if (!isLeaf(t)) { 05558 if (isMult(t)) { 05559 // We only handle linear terms 05560 if (!isNonlinearSumTerm(t)) { 05561 // Separate the multiplication 05562 Expr c, v; 05563 separateMonomial(t, c, v); 05564 // Get the upper-bound for the variable 05565 if (c.getRational() > 0) lowerBound = getLowerBound(v); 05566 else lowerBound = getUpperBound(v); 05567 if (lowerBound.isFinite()) lowerBound = lowerBound * c.getRational(); 05568 else lowerBound = DifferenceLogicGraph::EpsRational::MinusInfinity; 05569 } 05570 } else if (isPlus(t)) { 05571 // If one of them is unconstrained then the term itself is unconstrained 05572 lowerBound = DifferenceLogicGraph::EpsRational::Zero; 05573 for (int i = 0; i < t.arity(); i ++) { 05574 Expr t_i = t[i]; 05575 DifferenceLogicGraph::EpsRational t_i_lowerBound = getLowerBound(t_i, queryType); 05576 if (t_i_lowerBound.isFinite()) lowerBound = lowerBound + t_i_lowerBound; 05577 else { 05578 lowerBound = DifferenceLogicGraph::EpsRational::MinusInfinity; 05579 // Not-bounded, check for constrained 05580 if (queryType == QueryWithCacheLeavesAndConstrainedComputation) { 05581 for(; i < t.arity() && isConstrainedBelow(t[i], QueryWithCacheLeaves); i ++); 05582 if (i == t.arity()) { 05583 TRACE("arith shared", "getLowerBound(", t.toString(), ") ==> constrained"); 05584 termConstrainedBelow[t] = true; 05585 } 05586 break; 05587 } else break; 05588 } 05589 } 05590 } 05591 } 05592 05593 // Buffer it 05594 if (lowerBound.isFinite()) { 05595 termLowerBounded[t] = lowerBound; 05596 termConstrainedBelow[t] = true; 05597 } 05598 05599 // Return if bounded or not 05600 TRACE("arith shared", "getLowerBound(", t.toString(), ") ==> " + lowerBound.toString()); 05601 return lowerBound; 05602 } 05603 05604 int TheoryArithOld::computeTermBounds() 05605 { 05606 int computeTermBoundsConstrainedCount = 0; 05607 05608 vector<Expr> sorted_vars; 05609 // Get the variables in the topological order 05610 if (!diffLogicOnly) d_graph.getVerticesTopological(sorted_vars); 05611 // Or if difference logic only, just get them 05612 else { 05613 diffLogicGraph.getVariables(sorted_vars); 05614 IF_DEBUG( 05615 diffLogicGraph.writeGraph(cerr); 05616 ) 05617 } 05618 05619 // Go in the reverse topological order and try to see if the vats are constrained/bounded 05620 for (int i = sorted_vars.size() - 1; i >= 0; i --) 05621 { 05622 // Get the variable 05623 Expr v = sorted_vars[i]; 05624 05625 // If the find is not identity, skip it 05626 if (v.hasFind() && find(v).getRHS() != v) continue; 05627 05628 TRACE("arith shared", "processing: ", v.toString(), ""); 05629 05630 // If the variable is not an integer, it's unconstrained, unless we are in model generation 05631 if (isIntegerThm(v).isNull() && !d_inModelCreation) continue; 05632 05633 // We only do the computation if the variable is not already constrained 05634 if (!isConstrained(v, QueryWithCacheAll)) { 05635 05636 // Recall if we already computed the constraint 05637 bool constrainedAbove = isConstrained(v, QueryWithCacheAll); 05638 05639 // See if it's bounded from above in the difference graph 05640 DifferenceLogicGraph::EpsRational upperBound = diffLogicGraph.getEdgeWeight(v, zero); 05641 if (!constrainedAbove) constrainedAbove = upperBound.isFinite(); 05642 05643 // Try to refine the bound by checking projected inequalities 05644 if (!diffLogicOnly) { 05645 ExprMap<CDList<Ineq> *>::iterator v_left_find = d_inequalitiesLeftDB.find(v); 05646 // If not constraint from one side, it's unconstrained 05647 if (v_left_find != d_inequalitiesLeftDB.end()) { 05648 // Check right hand side for an unconstrained variable 05649 CDList<Ineq>*& left_list = (*v_left_find).second; 05650 if (left_list && left_list->size() > 0) { 05651 for (unsigned ineq_i = 0; ineq_i < left_list->size(); ineq_i ++) { 05652 // Get the inequality 05653 Ineq ineq = (*left_list)[ineq_i]; 05654 // Get the right-hand side (v <= rhs) 05655 Expr rhs = ineq.ineq().getExpr()[1]; 05656 // If rhs changed, skip it 05657 if (rhs.hasFind() && find(rhs).getRHS() != rhs) continue; 05658 // Compute the upper bound while 05659 DifferenceLogicGraph::EpsRational currentUpperBound = getUpperBound(rhs, (constrainedAbove ? QueryWithCacheLeaves : QueryWithCacheLeavesAndConstrainedComputation)); 05660 if (currentUpperBound.isFinite() && (!upperBound.isFinite() || currentUpperBound < upperBound)) { 05661 upperBound = currentUpperBound; 05662 constrainedAbove = true; 05663 } 05664 // If not constrained, check if right-hand-side is constrained 05665 if (!constrainedAbove) constrainedAbove = isConstrainedAbove(rhs, QueryWithCacheAll); 05666 } 05667 } 05668 } 05669 } 05670 // Difference logic case (no projections) 05671 else if (!constrainedAbove) { 05672 // If there is no incoming edges, then the variable is not constrained 05673 if (!diffLogicGraph.hasIncoming(v)) constrainedAbove = false; 05674 // If there is a cycle from t to t, all the variables 05675 // in the graph are constrained by each-other (we could 05676 // choose one, but it's too complicated) 05677 else if (diffLogicGraph.inCycle(v)) constrainedAbove = true; 05678 // Otherwise, since there is no bounds, and the cycles 05679 // can be shifted (since one of them can be taken as 05680 // unconstrained), we can assume that the variables is 05681 // not constrained. Conundrum here is that when in model-generation 05682 // we actually should take it as constrained so that it's 05683 // split on and we are on the safe side 05684 else constrainedAbove = d_inModelCreation; 05685 } 05686 05687 // Cache the upper bound and upper constrained computation 05688 if (constrainedAbove) termConstrainedAbove[v] = true; 05689 if (upperBound.isFinite()) termUpperBounded[v] = upperBound; 05690 05691 // Recall the below computation if it's there 05692 bool constrainedBelow = isConstrainedBelow(v, QueryWithCacheAll); 05693 05694 // See if it's bounded from below in the difference graph 05695 DifferenceLogicGraph::EpsRational lowerBound = diffLogicGraph.getEdgeWeight(zero, v); 05696 if (lowerBound.isFinite()) lowerBound = -lowerBound; 05697 else lowerBound = DifferenceLogicGraph::EpsRational::MinusInfinity; 05698 if (!constrainedBelow) constrainedBelow = lowerBound.isFinite(); 05699 05700 // Try to refine the bound by checking projected inequalities 05701 if (!diffLogicOnly) { 05702 ExprMap<CDList<Ineq> *>::iterator v_right_find = d_inequalitiesRightDB.find(v); 05703 // If not constraint from one side, it's unconstrained 05704 if (v_right_find != d_inequalitiesRightDB.end()) { 05705 // Check right hand side for an unconstrained variable 05706 CDList<Ineq>*& right_list = (*v_right_find).second; 05707 if (right_list && right_list->size() > 0) { 05708 for (unsigned ineq_i = 0; ineq_i < right_list->size(); ineq_i ++) { 05709 // Get the inequality 05710 Ineq ineq = (*right_list)[ineq_i]; 05711 // Get the right-hand side (lhs <= 0) 05712 Expr lhs = ineq.ineq().getExpr()[0]; 05713 // If lhs has changed, skip it 05714 if (lhs.hasFind() && find(lhs).getRHS() != lhs) continue; 05715 // Compute the lower bound 05716 DifferenceLogicGraph::EpsRational currentLowerBound = getLowerBound(lhs, (constrainedBelow ? QueryWithCacheLeaves : QueryWithCacheLeavesAndConstrainedComputation)); 05717 if (currentLowerBound.isFinite() && (!lowerBound.isFinite() || currentLowerBound > lowerBound)) { 05718 lowerBound = currentLowerBound; 05719 constrainedBelow = true; 05720 } 05721 // If not constrained, check if right-hand-side is constrained 05722 if (!constrainedBelow) constrainedBelow = isConstrainedBelow(lhs, QueryWithCacheAll); 05723 } 05724 } 05725 } 05726 } 05727 // Difference logic case (no projections) 05728 else if (!constrainedBelow) { 05729 // If there is no incoming edges, then the variable is not constrained 05730 if (!diffLogicGraph.hasOutgoing(v)) constrainedBelow = false; 05731 // If there is a cycle from t to t, all the variables 05732 // in the graph are constrained by each-other (we could 05733 // choose one, but it's too complicated) 05734 else if (diffLogicGraph.inCycle(v)) constrainedBelow = true; 05735 // Otherwise, since there is no bounds, and the cycles 05736 // can be shifted (since one of them can be taken as 05737 // unconstrained), we can assume that the variables is 05738 // not constrained. Conundrum here is that when in model-generation 05739 // we actually should take it as constrained so that it's 05740 // split on and we are on the safe side 05741 else constrainedBelow = d_inModelCreation; 05742 } 05743 05744 // Cache the lower bound and lower constrained computation 05745 if (constrainedBelow) termConstrainedBelow[v] = true; 05746 if (lowerBound.isFinite()) termLowerBounded[v] = lowerBound; 05747 05748 // Is this variable constrained 05749 if (constrainedAbove && constrainedBelow) computeTermBoundsConstrainedCount ++; 05750 05751 TRACE("arith shared", (constrainedAbove && constrainedBelow ? "constrained " : "unconstrained "), "", ""); 05752 } else 05753 computeTermBoundsConstrainedCount ++; 05754 } 05755 05756 TRACE("arith shared", "number of constrained variables : ", int2string(computeTermBoundsConstrainedCount), " of " + int2string(sorted_vars.size())); 05757 05758 return computeTermBoundsConstrainedCount; 05759 } 05760 05761 bool TheoryArithOld::isConstrainedAbove(const Expr& t, BoundsQueryType queryType) 05762 { 05763 TRACE("arith shared", "isConstrainedAbove(", t.toString(), ")"); 05764 05765 // Rational numbers are constrained 05766 if (t.isRational()) { 05767 TRACE("arith shared", "isConstrainedAbove() ==> true", "", ""); 05768 return true; 05769 } 05770 05771 // Look it up in the cache 05772 CDMap<Expr, bool>::iterator t_find = termConstrainedAbove.find(t); 05773 if (t_find != termConstrainedAbove.end()) { 05774 TRACE("arith shared", "isConstrainedAbove() ==> true", "", ""); 05775 return true; 05776 } 05777 else if (queryType == QueryWithCacheAll) { 05778 TRACE("arith shared", "isConstrainedAbove() ==> false", "", ""); 05779 return false; 05780 } 05781 05782 bool constrainedAbove = true; 05783 05784 if (isLeaf(t)) { 05785 // Leaves are always cached 05786 constrainedAbove = false; 05787 } else { 05788 if (isMult(t)) { 05789 // Non-linear terms are constrained by default 05790 // we only deal with the linear stuff 05791 if (!isNonlinearSumTerm(t)) { 05792 // Separate the multiplication 05793 Expr c, v; 05794 separateMonomial(t, c, v); 05795 // Check if the variable is constrained 05796 if (c.getRational() > 0) constrainedAbove = isConstrainedAbove(v, queryType); 05797 else constrainedAbove = isConstrainedBelow(v, queryType); 05798 } 05799 } else if (isPlus(t)) { 05800 // If one of them is unconstrained then the term itself is unconstrained 05801 for (int i = 0; i < t.arity() && constrainedAbove; i ++) 05802 if (!isConstrainedAbove(t[i])) constrainedAbove = false; 05803 } 05804 } 05805 05806 // Remember it 05807 if (constrainedAbove) termConstrainedAbove[t] = true; 05808 05809 TRACE("arith shared", "isConstrainedAbove() ==> ", constrainedAbove ? "true" : "false", ""); 05810 05811 // Return in 05812 return constrainedAbove; 05813 } 05814 05815 bool TheoryArithOld::isConstrainedBelow(const Expr& t, BoundsQueryType queryType) 05816 { 05817 TRACE("arith shared", "isConstrainedBelow(", t.toString(), ")"); 05818 05819 // Rational numbers are constrained 05820 if (t.isRational()) return true; 05821 05822 // Look it up in the cache 05823 CDMap<Expr, bool>::iterator t_find = termConstrainedBelow.find(t); 05824 if (t_find != termConstrainedBelow.end()) { 05825 TRACE("arith shared", "isConstrainedBelow() ==> true", "", ""); 05826 return true; 05827 } 05828 else if (queryType == QueryWithCacheAll) { 05829 TRACE("arith shared", "isConstrainedBelow() ==> false", "", ""); 05830 return false; 05831 } 05832 05833 bool constrainedBelow = true; 05834 05835 if (isLeaf(t)) { 05836 // Leaves are always cached 05837 constrainedBelow = false; 05838 } else { 05839 if (isMult(t)) { 05840 // Non-linear terms are constrained by default 05841 // we only deal with the linear stuff 05842 if (!isNonlinearSumTerm(t)) { 05843 // Separate the multiplication 05844 Expr c, v; 05845 separateMonomial(t, c, v); 05846 // Check if the variable is constrained 05847 if (c.getRational() > 0) constrainedBelow = isConstrainedBelow(v, queryType); 05848 else constrainedBelow = isConstrainedAbove(v, queryType); 05849 } 05850 } else if (isPlus(t)) { 05851 // If one of them is unconstrained then the term itself is unconstrained 05852 constrainedBelow = true; 05853 for (int i = 0; i < t.arity() && constrainedBelow; i ++) 05854 if (!isConstrainedBelow(t[i])) 05855 constrainedBelow = false; 05856 } 05857 } 05858 05859 // Cache it 05860 if (constrainedBelow) termConstrainedBelow[t] = true; 05861 05862 TRACE("arith shared", "isConstrainedBelow() ==> ", constrainedBelow ? "true" : "false", ""); 05863 05864 // Return it 05865 return constrainedBelow; 05866 } 05867 05868 bool TheoryArithOld::isConstrained(const Expr& t, bool intOnly, BoundsQueryType queryType) 05869 { 05870 TRACE("arith shared", "isConstrained(", t.toString(), ")"); 05871 // For the reals we consider them unconstrained if not asked for full check 05872 if (intOnly && isIntegerThm(t).isNull()) return false; 05873 bool result = (isConstrainedAbove(t, queryType) && isConstrainedBelow(t, queryType)); 05874 TRACE("arith shared", "isConstrained(", t.toString(), (result ? ") ==> true " : ") ==> false ") ); 05875 return result; 05876 } 05877 05878 bool TheoryArithOld::DifferenceLogicGraph::hasIncoming(const Expr& x) 05879 { 05880 EdgesList::iterator find_x = incomingEdges.find(x); 05881 05882 // No edges at all meaning no incoming 05883 if (find_x == incomingEdges.end()) return false; 05884 05885 // The pointer being null, also no incoming 05886 CDList<Expr>*& list = (*find_x).second; 05887 if (!list) return false; 05888 05889 // If in model creation, source vertex goes to all vertices 05890 if (sourceVertex.isNull()) 05891 return list->size() > 0; 05892 else 05893 return list->size() > 1; 05894 } 05895 05896 bool TheoryArithOld::DifferenceLogicGraph::hasOutgoing(const Expr& x) 05897 { 05898 EdgesList::iterator find_x = outgoingEdges.find(x); 05899 05900 // No edges at all meaning no incoming 05901 if (find_x == outgoingEdges.end()) return false; 05902 05903 // The pointer being null, also no incoming 05904 CDList<Expr>*& list = (*find_x).second; 05905 if (!list) return false; 05906 05907 // If the list is not empty we have outgoing edges 05908 return list->size() > 0; 05909 } 05910 05911 void TheoryArithOld::DifferenceLogicGraph::getVariables(vector<Expr>& variables) 05912 { 05913 set<Expr> vars_set; 05914 05915 EdgesList::iterator incoming_it = incomingEdges.begin(); 05916 EdgesList::iterator incoming_it_end = incomingEdges.end(); 05917 while (incoming_it != incoming_it_end) { 05918 Expr var = (*incoming_it).first; 05919 if (var != sourceVertex) 05920 vars_set.insert(var); 05921 incoming_it ++; 05922 } 05923 05924 EdgesList::iterator outgoing_it = outgoingEdges.begin(); 05925 EdgesList::iterator outgoing_it_end = outgoingEdges.end(); 05926 while (outgoing_it != outgoing_it_end) { 05927 Expr var = (*outgoing_it).first; 05928 if (var != sourceVertex) 05929 vars_set.insert(var); 05930 outgoing_it ++; 05931 } 05932 05933 set<Expr>::iterator set_it = vars_set.begin(); 05934 set<Expr>::iterator set_it_end = vars_set.end(); 05935 while (set_it != set_it_end) { 05936 variables.push_back(*set_it); 05937 set_it ++; 05938 } 05939 } 05940 05941 void TheoryArithOld::DifferenceLogicGraph::writeGraph(ostream& out) { 05942 return; 05943 out << "digraph G {" << endl; 05944 05945 EdgesList::iterator incoming_it = incomingEdges.begin(); 05946 EdgesList::iterator incoming_it_end = incomingEdges.end(); 05947 while (incoming_it != incoming_it_end) { 05948 05949 Expr var_u = (*incoming_it).first; 05950 05951 CDList<Expr>* edges = (*incoming_it).second; 05952 if (edges) 05953 for (unsigned edge_i = 0; edge_i < edges->size(); edge_i ++) { 05954 Expr var_v = (*edges)[edge_i]; 05955 out << var_u.toString() << " -> " << var_v.toString() << endl; 05956 } 05957 05958 incoming_it ++; 05959 } 05960 05961 out << "}" << endl; 05962 }