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