CVC3
|
00001 /*****************************************************************************/ 00002 /*! 00003 * \file theory_arith_new.cpp 00004 * 00005 * Author: Dejan Jovanovic 00006 * 00007 * Created: Thu Jun 14 13:42:00 2007 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_new.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 00033 00034 using namespace std; 00035 using namespace CVC3; 00036 00037 00038 /////////////////////////////////////////////////////////////////////////////// 00039 // TheoryArithNew::FreeConst Methods // 00040 /////////////////////////////////////////////////////////////////////////////// 00041 00042 namespace CVC3 { 00043 00044 ostream& operator<<(ostream& os, const TheoryArithNew::FreeConst& fc) { 00045 os << "FreeConst(r=" << fc.getConst() << ", " 00046 << (fc.strict()? "strict" : "non-strict") << ")"; 00047 return os; 00048 } 00049 00050 /////////////////////////////////////////////////////////////////////////////// 00051 // TheoryArithNew::Ineq Methods // 00052 /////////////////////////////////////////////////////////////////////////////// 00053 00054 ostream& operator<<(ostream& os, const TheoryArithNew::Ineq& ineq) { 00055 os << "Ineq(" << ineq.ineq().getExpr() << ", isolated on " 00056 << (ineq.varOnRHS()? "RHS" : "LHS") << ", const = " 00057 << ineq.getConst() << ")"; 00058 return os; 00059 } 00060 } // End of namespace CVC3 00061 00062 00063 /////////////////////////////////////////////////////////////////////////////// 00064 // TheoryArithNew Private Methods // 00065 /////////////////////////////////////////////////////////////////////////////// 00066 00067 00068 Theorem TheoryArithNew::isIntegerThm(const Expr& e) { 00069 // Quick check 00070 if(isReal(e.getType())) return Theorem(); 00071 // Try harder 00072 return isIntegerDerive(Expr(IS_INTEGER, e), typePred(e)); 00073 } 00074 00075 00076 Theorem TheoryArithNew::isIntegerDerive(const Expr& isIntE, const Theorem& thm) { 00077 const Expr& e = thm.getExpr(); 00078 // We found it! 00079 if(e == isIntE) return thm; 00080 00081 Theorem res; 00082 // If the theorem is an AND, look inside each child 00083 if(e.isAnd()) { 00084 int i, iend=e.arity(); 00085 for(i=0; i<iend; ++i) { 00086 res = isIntegerDerive(isIntE, getCommonRules()->andElim(thm, i)); 00087 if(!res.isNull()) return res; 00088 } 00089 } 00090 return res; 00091 } 00092 00093 00094 bool TheoryArithNew::kidsCanonical(const Expr& e) { 00095 if(isLeaf(e)) return true; 00096 bool res(true); 00097 for(int i=0; res && i<e.arity(); ++i) { 00098 Expr simp(canon(e[i]).getRHS()); 00099 res = (e[i] == simp); 00100 IF_DEBUG(if(!res) debugger.getOS() << "\ne[" << i << "] = " << e[i] 00101 << "\nsimplified = " << simp << endl;) 00102 } 00103 return res; 00104 } 00105 00106 00107 00108 00109 /** 00110 * Compute a canonical form for expression e and return a theorem that e is equal to its canonical form. 00111 * Note that canonical form for arith expressions is of the following form: 00112 * 00113 * b + a_1 x_1 + a_2 x_2 + ... + a_n x_n (ONE SUM EXPRESION) 00114 * 00115 * or just a rational b (RATIONAL EXPRESSION) 00116 * 00117 * where a_i and b are rationals and x_i are arithmetical leaves (i.e. variables or non arithmetic terms) 00118 * 00119 * @author Clark Barrett 00120 * @author Vijay Ganesh 00121 * @since Sat Feb 8 14:46:32 2003 00122 */ 00123 Theorem TheoryArithNew::canon(const Expr& e) 00124 { 00125 // Trace the arith canon of the expression in the debug version 00126 TRACE("arith", "canon(", e , ") {"); 00127 00128 // The invariant is that the kids of the expression should already be canonised 00129 //DebugAssert(kidsCanonical(e), "TheoryArithNew::canon("+e.toString()+")"); 00130 00131 // The resulting theorem object 00132 Theorem result; 00133 00134 switch (e.getKind()) { 00135 00136 // -E 00137 case UMINUS: { 00138 00139 // Convert the unary minus to multiplication with -1 00140 result = d_rules->uMinusToMult(e[0]); 00141 00142 // Get the resulting epression 00143 Expr e2 = result.getRHS(); 00144 00145 // Canonise the resulting expression and combine the theorems 00146 result = transitivityRule(result, canon(e2)); 00147 00148 // UMINUS case break 00149 break; 00150 } 00151 00152 // e[0] + e[1] 00153 case PLUS: 00154 00155 // Call the canonPlus procedure to canonise + 00156 result = d_rules->canonPlus(e); 00157 00158 // PLUS case break 00159 break; 00160 00161 // e[0] - e[1] 00162 case MINUS: { 00163 00164 // Arity of the minus should be exactly 2 (TODO: looks useless, maybe remove) 00165 DebugAssert(e.arity() == 2," "); 00166 00167 // This produces e[0] + (-1)*e[1], we have to canonize it in 2 steps 00168 Theorem minus_eq_sum = d_rules->minusToPlus(e[0], e[1]); 00169 00170 // The resulting sum expression 00171 Expr sum(minus_eq_sum.getRHS()); 00172 00173 // Canonise the sum[1] 00174 Theorem thm(canon(sum[1])); 00175 00176 // If the sum[1] sayed the same, canonise the sum expression 00177 if(thm.getLHS() == thm.getRHS()) 00178 result = canonThm(minus_eq_sum); 00179 // The sum changed; do the work 00180 else { 00181 00182 // Substitute and try to canonise again 00183 Theorem sum_eq_canon = canonThm(substitutivityRule(sum, 1, thm)); 00184 00185 // Combine the results, and thats it 00186 result = transitivityRule(minus_eq_sum, sum_eq_canon); 00187 } 00188 00189 // MINUS case break 00190 break; 00191 00192 } 00193 00194 // e[0] * e[1] 00195 case MULT: 00196 00197 // Canonise using the canonMult() proof rule 00198 result = d_rules->canonMult(e); 00199 00200 // MULT case break 00201 break; 00202 00203 // e[0] DIV e[1] 00204 case DIVIDE: { 00205 00206 // Division by 0 is OK (total extension, protected by TCCs) 00207 // if (e[1].isRational() && e[1].getRational() == 0) 00208 // throw ArithException("Divide by 0 error in "+e.toString()); 00209 if (e[1].getKind() == PLUS) 00210 throw ArithException("Divide by a PLUS expression not handled in" + e.toString()); 00211 00212 // Canonise the divite using canonDivide() method 00213 result = d_rules->canonDivide(e); 00214 00215 // DIVIDE case break 00216 break; 00217 } 00218 00219 // e[0]^e[1] 00220 case POW : 00221 00222 // If we are raising to a constant rational call canonPowConst() proof rule 00223 if(e[1].isRational()) result = d_rules->canonPowConst(e); 00224 // Othervise just return the same expression 00225 else result = reflexivityRule(e); 00226 00227 // POW case break 00228 break; 00229 00230 default: 00231 00232 // How did we get here (TODO: check if need to throw and exception), anyhow, just return the reflexivity rule 00233 result = reflexivityRule(e); 00234 00235 // Default break 00236 break; 00237 } 00238 00239 // Finished with the canonisation, trace the result in the debug version 00240 TRACE("arith","canon => ",result," }"); 00241 00242 // Return the resulting theorem 00243 return result; 00244 } 00245 00246 Theorem TheoryArithNew::canonSimplify(const Expr& e) { 00247 // Trace the function on the arith trace flag 00248 TRACE("arith", "canonSimplify(", e, ") {"); 00249 00250 // Assert that all the kids must be already canonical 00251 //DebugAssert(kidsCanonical(e), "TheoryArithNew::canonSimplify("+e.toString()+")"); 00252 // Assert that all the leaves must be simplified 00253 //DebugAssert(leavesAreSimp(e), "Expected leaves to be simplified"); 00254 00255 // Make a copy of the expression 00256 Expr tmp(e); 00257 00258 // Canonise the expresion 00259 Theorem thm = canon(e); 00260 00261 // If the new simplified expression has a find, use it (TODO: Check whats going on here) 00262 if(thm.getRHS().hasFind()) 00263 thm = transitivityRule(thm, find(thm.getRHS())); 00264 00265 // We shouldn't rely on simplification in this function anymore 00266 DebugAssert(thm.getRHS() == simplifyExpr(thm.getRHS()), "canonSimplify("+e.toString()+")\n"+"canon(e) = "+thm.getRHS().toString()+"\nsimplify(canon(e)) = "+simplifyExpr(thm.getRHS()).toString()); 00267 00268 // Trace the resulting theorem 00269 TRACE("arith", "canonSimplify =>", thm, " }"); 00270 00271 // Return the theorem 00272 return thm; 00273 } 00274 00275 /*! accepts a theorem, canonizes it, applies iffMP and substituvity to 00276 * derive the canonized thm 00277 */ 00278 Theorem 00279 TheoryArithNew::canonPred(const Theorem& thm) { 00280 vector<Theorem> thms; 00281 DebugAssert(thm.getExpr().arity() == 2, 00282 "TheoryArithNew::canonPred: bad theorem: "+thm.toString()); 00283 Expr e(thm.getExpr()); 00284 thms.push_back(canonSimplify(e[0])); 00285 thms.push_back(canonSimplify(e[1])); 00286 return iffMP(thm, substitutivityRule(e.getOp(), thms)); 00287 } 00288 00289 /** 00290 * Accepts an equivalence theorem, canonizes the subexpressions, applies transitivity and substituvity to derive the canonized theorem. 00291 * 00292 * @param thm equivalence theorem 00293 * @return the canonised expression theorem 00294 */ 00295 Theorem TheoryArithNew::canonPredEquiv(const Theorem& thm) { 00296 00297 vector<Theorem> thms; // Vector to hold the simplified versions of e[0] and e[1] 00298 00299 // Arity of the expression should be 2 00300 DebugAssert(thm.getRHS().arity() == 2, "TheoryArithNew::canonPredEquiv: bad theorem: " + thm.toString()); 00301 00302 // Get the expression of the theorem 00303 Expr e(thm.getRHS()); 00304 00305 // Simplify both sides of the equivalence 00306 thms.push_back(canonSimplify(e[0])); 00307 thms.push_back(canonSimplify(e[1])); 00308 00309 // Return the theorem substituting e[0] and e[1] with their simplified versions 00310 return transitivityRule(thm, substitutivityRule(e.getOp(), thms)); 00311 } 00312 00313 /*! accepts an equivalence theorem whose RHS is a conjunction, 00314 * canonizes it, applies iffMP and substituvity to derive the 00315 * canonized thm 00316 */ 00317 Theorem 00318 TheoryArithNew::canonConjunctionEquiv(const Theorem& thm) { 00319 vector<Theorem> thms; 00320 return thm; 00321 } 00322 00323 /*! Pseudo-code for doSolve. (Input is an equation) (output is a Theorem) 00324 * -# translate e to the form e' = 0 00325 * -# if (e'.isRational()) then {if e' != 0 return false else true} 00326 * -# a for loop checks if all the variables are integers. 00327 * - if not isolate a suitable real variable and call processRealEq(). 00328 * - if all variables are integers then isolate suitable variable 00329 * and call processIntEq(). 00330 */ 00331 Theorem TheoryArithNew::doSolve(const Theorem& thm) 00332 { 00333 const Expr& e = thm.getExpr(); 00334 TRACE("arith eq","doSolve(",e,") {"); 00335 DebugAssert(thm.isRewrite(), "thm = "+thm.toString()); 00336 Theorem eqnThm; 00337 vector<Theorem> thms; 00338 // Move LHS to the RHS, if necessary 00339 if(e[0].isRational() && e[0].getRational() == 0) 00340 eqnThm = thm; 00341 else { 00342 eqnThm = iffMP(thm, d_rules->rightMinusLeft(e)); 00343 eqnThm = canonPred(eqnThm); 00344 } 00345 // eqnThm is of the form 0 = e' 00346 // 'right' is of the form e' 00347 Expr right = eqnThm.getRHS(); 00348 // Check for trivial equation 00349 if (right.isRational()) { 00350 Theorem result = iffMP(eqnThm, d_rules->constPredicate(eqnThm.getExpr())); 00351 TRACE("arith eq","doSolve => ",result," }"); 00352 return result; 00353 } 00354 00355 //normalize 00356 eqnThm = iffMP(eqnThm, normalize(eqnThm.getExpr())); 00357 right = eqnThm.getRHS(); 00358 00359 //eqn is of the form 0 = e' and is normalized where 'right' denotes e' 00360 //FIXME: change processRealEq to accept equations as well instead of theorems 00361 if(!isInteger(right)) { 00362 Theorem res; 00363 try { 00364 res = processRealEq(eqnThm); 00365 } catch(ArithException& e) { 00366 res = symmetryRule(eqnThm); // Flip to e' = 0 00367 TRACE("arith eq", "doSolve: failed to solve an equation: ", e, ""); 00368 IF_DEBUG(debugger.counter("FAILED to solve real equalities")++;) 00369 setIncomplete("Non-linear arithmetic inequalities"); 00370 } 00371 IF_DEBUG(debugger.counter("solved real equalities")++;) 00372 TRACE("arith eq", "doSolve [real] => ", res, " }"); 00373 return res; 00374 } 00375 else { 00376 Theorem res = processIntEq(eqnThm); 00377 IF_DEBUG(debugger.counter("solved int equalities")++;) 00378 TRACE("arith eq", "doSolve [int] => ", res, " }"); 00379 return res; 00380 } 00381 } 00382 00383 /*! pick a monomial for the input equation. This function is used only 00384 * if the equation is an integer equation. Choose the monomial with 00385 * the smallest absolute value of coefficient. 00386 */ 00387 Expr 00388 TheoryArithNew::pickIntEqMonomial(const Expr& right) 00389 { 00390 DebugAssert(isPlus(right) && right.arity() > 2, 00391 "TheoryArithNew::pickIntEqMonomial right is wrong :-): " + 00392 right.toString()); 00393 DebugAssert(right[0].isRational(), 00394 "TheoryArithNew::pickIntEqMonomial. right[0] must be const" + 00395 right.toString()); 00396 DebugAssert(isInteger(right), 00397 "TheoryArithNew::pickIntEqMonomial: right is of type int: " + 00398 right.toString()); 00399 //right is of the form "C + a1x1 + ... + anxn". min is initialized 00400 //to a1 00401 Expr::iterator i = right.begin(); 00402 i++; //skip 'C' 00403 Rational min = isMult(*i) ? abs((*i)[0].getRational()) : 1; 00404 Expr pickedMon = *i; 00405 for(Expr::iterator iend = right.end(); i != iend; ++i) { 00406 Rational coeff = isMult(*i) ? abs((*i)[0].getRational()) : 1; 00407 if(min > coeff) { 00408 min = coeff; 00409 pickedMon = *i; 00410 } 00411 } 00412 return pickedMon; 00413 } 00414 00415 /*! input is e1=e2<==>0=e' Theorem and some of the vars in e' are of 00416 * type REAL. isolate one of them and send back to framework. output 00417 * is "e1=e2 <==> var = e''" Theorem. 00418 */ 00419 Theorem 00420 TheoryArithNew::processRealEq(const Theorem& eqn) 00421 { 00422 Expr right = eqn.getRHS(); 00423 // Find variable to isolate and store it in left. Pick the largest 00424 // (according to the total ordering) variable. FIXME: change from 00425 // total ordering to the ordering we devised for inequalities. 00426 00427 // TODO: I have to pick a variable that appears as a variable in the 00428 // term but does not appear as a variable anywhere else. The variable 00429 // must appear as a single leaf and not in a MULT expression with some 00430 // other variables and nor in a POW expression. 00431 00432 bool found = false; 00433 00434 Expr left; 00435 00436 if (isPlus(right)) { 00437 for(int i = right.arity()-1; i>=0; --i) { 00438 Expr c = right[i]; 00439 if(isRational(c)) 00440 continue; 00441 if(!isInteger(c)) { 00442 if (isLeaf(c) || 00443 ((isMult(c) && c.arity() == 2 && isLeaf(c[1])))) { 00444 int numoccurs = 0; 00445 Expr leaf = isLeaf(c) ? c : c[1]; 00446 for (int j = 0; j < right.arity(); ++j) { 00447 if (j!= i 00448 && isLeafIn(leaf, right[j]) 00449 // && leaf.subExprOf(right[j]) 00450 ) { 00451 numoccurs++; 00452 break; 00453 } 00454 } 00455 if (!numoccurs) { 00456 left = c; 00457 found = true; 00458 break; 00459 } 00460 } 00461 } 00462 } 00463 } 00464 else if ((isMult(right) && right.arity() == 2 && isLeaf(right[1])) || 00465 isLeaf(right)) { 00466 left = right; 00467 found = true; 00468 } 00469 00470 if (!found) { 00471 // TODO: 00472 // throw an arithmetic exception that this cannot be done. 00473 throw 00474 ArithException("Can't find a leaf for solve in "+eqn.toString()); 00475 } 00476 00477 Rational r = -1; 00478 if (isMult(left)) { 00479 DebugAssert(left.arity() == 2, "only leaf should be chosen as lhs"); 00480 DebugAssert(left[0].getRational() != 0, "left = "+left.toString()); 00481 r = -1/left[0].getRational(); 00482 left = left[1]; 00483 } 00484 00485 DebugAssert(isReal(getBaseType(left)) && !isInteger(left), 00486 "TheoryArithNew::ProcessRealEq: left is integer:\n left = " 00487 +left.toString()); 00488 // Normalize equation so that coefficient of the monomial 00489 // corresponding to "left" in eqn[1] is -1 00490 Theorem result(iffMP(eqn, 00491 d_rules->multEqn(eqn.getLHS(), eqn.getRHS(), rat(r)))); 00492 result = canonPred(result); 00493 00494 // Isolate left 00495 result = iffMP(result, d_rules->plusPredicate(result.getLHS(), 00496 result.getRHS(), left, EQ)); 00497 result = canonPred(result); 00498 TRACE("arith","processRealEq => ",result," }"); 00499 return result; 00500 } 00501 00502 /*! 00503 * \param eqn is a single equation 0 = e 00504 * \return an equivalent Theorem (x = t AND 0 = e'), or just x = t 00505 */ 00506 Theorem 00507 TheoryArithNew::processSimpleIntEq(const Theorem& eqn) 00508 { 00509 TRACE("arith eq", "processSimpleIntEq(", eqn.getExpr(), ") {"); 00510 DebugAssert(eqn.isRewrite(), 00511 "TheoryArithNew::processSimpleIntEq: eqn must be equality" + 00512 eqn.getExpr().toString()); 00513 00514 Expr right = eqn.getRHS(); 00515 00516 DebugAssert(eqn.getLHS().isRational() && 0 == eqn.getLHS().getRational(), 00517 "TheoryArithNew::processSimpleIntEq: LHS must be 0:\n" + 00518 eqn.getExpr().toString()); 00519 00520 //recall that 0 = c case is already handled in doSolve() function. 00521 if(isMult(right)) { 00522 //here we take care of special case 0=c.x 00523 Expr c,x; 00524 separateMonomial(right, c, x); 00525 Theorem isIntx(isIntegerThm(x)); 00526 DebugAssert(!isIntx.isNull(), "right = "+right.toString()); 00527 Theorem res(iffMP(eqn, d_rules->intVarEqnConst(eqn.getExpr(), isIntx))); 00528 TRACE("arith eq", "processSimpleIntEq[0 = a*x] => ", res, " }"); 00529 return res; 00530 } else if(isPlus(right)) { 00531 if(2 == right.arity()) { 00532 //we take care of special cases like 0 = c + a.x, 0 = c + x, 00533 Expr c,x; 00534 separateMonomial(right[1], c, x); 00535 Theorem isIntx(isIntegerThm(x)); 00536 DebugAssert(!isIntx.isNull(), "right = "+right.toString() 00537 +"\n x = "+x.toString()); 00538 Theorem res(iffMP(eqn, d_rules->intVarEqnConst(eqn.getExpr(), isIntx))); 00539 TRACE("arith eq", "processSimpleIntEq[0 = c + a*x] => ", res, " }"); 00540 return res; 00541 } 00542 DebugAssert(right.arity() > 2, 00543 "TheoryArithNew::processSimpleIntEq: RHS is not in correct form:" 00544 +eqn.getExpr().toString()); 00545 // Pick a suitable monomial. isolated can be of the form x, a.x, -a.x 00546 Expr isolated = pickIntEqMonomial(right); 00547 TRACE("arith eq", "processSimpleIntEq: isolated = ", isolated, ""); 00548 00549 // First, we compute the 'sign factor' with which to multiply the 00550 // eqn. if the coeff of isolated is positive (i.e. 'isolated' is 00551 // of the form x or a.x where a>0 ) then r must be -1 and if coeff 00552 // of 'isolated' is negative, r=1. 00553 Rational r = isMult(isolated) ? 00554 ((isolated[0].getRational() > 0) ? -1 : 1) : -1; 00555 Theorem result; 00556 if (-1 == r) { 00557 // r=-1 and hence 'isolated' is 'x' or 'a.x' where a is 00558 // positive. modify eqn (0=e') to the equation (0=canon(-1*e')) 00559 result = iffMP(eqn, d_rules->multEqn(eqn.getLHS(), right, rat(r))); 00560 result = canonPred(result); 00561 Expr e = result.getRHS(); 00562 00563 // Isolate the 'isolated' 00564 result = iffMP(result, 00565 d_rules->plusPredicate(result.getLHS(),result.getRHS(), 00566 isolated, EQ)); 00567 } else { 00568 //r is 1 and hence isolated is -a.x. Make 'isolated' positive. 00569 const Rational& minusa = isolated[0].getRational(); 00570 Rational a = -1*minusa; 00571 isolated = (a == 1)? isolated[1] : rat(a) * isolated[1]; 00572 00573 // Isolate the 'isolated' 00574 result = iffMP(eqn, d_rules->plusPredicate(eqn.getLHS(), 00575 right,isolated,EQ)); 00576 } 00577 // Canonize the result 00578 result = canonPred(result); 00579 00580 //if isolated is 'x' or 1*x, then return result else continue processing. 00581 if(!isMult(isolated) || isolated[0].getRational() == 1) { 00582 TRACE("arith eq", "processSimpleIntEq[x = rhs] => ", result, " }"); 00583 return result; 00584 } else { 00585 DebugAssert(isMult(isolated) && isolated[0].getRational() >= 2, 00586 "TheoryArithNew::processSimpleIntEq: isolated must be mult " 00587 "with coeff >= 2.\n isolated = " + isolated.toString()); 00588 00589 // Compute IS_INTEGER() for lhs and rhs 00590 Expr lhs = result.getLHS(); 00591 Expr rhs = result.getRHS(); 00592 Expr a, x; 00593 separateMonomial(lhs, a, x); 00594 Theorem isIntLHS = isIntegerThm(x); 00595 vector<Theorem> isIntRHS; 00596 if(!isPlus(rhs)) { // rhs is a MULT 00597 Expr c, v; 00598 separateMonomial(rhs, c, v); 00599 isIntRHS.push_back(isIntegerThm(v)); 00600 DebugAssert(!isIntRHS.back().isNull(), ""); 00601 } else { // rhs is a PLUS 00602 DebugAssert(isPlus(rhs), "rhs = "+rhs.toString()); 00603 DebugAssert(rhs.arity() >= 2, "rhs = "+rhs.toString()); 00604 Expr::iterator i=rhs.begin(), iend=rhs.end(); 00605 ++i; // Skip the free constant 00606 for(; i!=iend; ++i) { 00607 Expr c, v; 00608 separateMonomial(*i, c, v); 00609 isIntRHS.push_back(isIntegerThm(v)); 00610 DebugAssert(!isIntRHS.back().isNull(), ""); 00611 } 00612 } 00613 // Derive (EXISTS (x:INT): x = t2 AND 0 = t3) 00614 result = d_rules->eqElimIntRule(result, isIntLHS, isIntRHS); 00615 // Skolemize the quantifier 00616 result = getCommonRules()->skolemize(result); 00617 // Canonize t2 and t3 generated by this rule 00618 DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2, 00619 "processSimpleIntEq: result = "+result.getExpr().toString()); 00620 Theorem thm1 = canonPred(getCommonRules()->andElim(result, 0)); 00621 Theorem thm2 = canonPred(getCommonRules()->andElim(result, 1)); 00622 Theorem newRes = getCommonRules()->andIntro(thm1, thm2); 00623 if(newRes.getExpr() != result.getExpr()) result = newRes; 00624 00625 TRACE("arith eq", "processSimpleIntEq => ", result, " }"); 00626 return result; 00627 } 00628 } else { 00629 // eqn is 0 = x. Flip it and return 00630 Theorem result = symmetryRule(eqn); 00631 TRACE("arith eq", "processSimpleIntEq[x = 0] => ", result, " }"); 00632 return result; 00633 } 00634 } 00635 00636 /*! input is e1=e2<==>0=e' Theorem and all of the vars in e' are of 00637 * type INT. isolate one of them and send back to framework. output 00638 * is "e1=e2 <==> var = e''" Theorem and some associated equations in 00639 * solved form. 00640 */ 00641 Theorem 00642 TheoryArithNew::processIntEq(const Theorem& eqn) 00643 { 00644 TRACE("arith eq", "processIntEq(", eqn.getExpr(), ") {"); 00645 // Equations in the solved form. 00646 std::vector<Theorem> solvedAndNewEqs; 00647 Theorem newEq(eqn), result; 00648 bool done(false); 00649 do { 00650 result = processSimpleIntEq(newEq); 00651 // 'result' is of the from (x1=t1) AND 0=t' 00652 if(result.isRewrite()) { 00653 solvedAndNewEqs.push_back(result); 00654 done = true; 00655 } 00656 else if(!result.getExpr().isFalse()) { 00657 DebugAssert(result.getExpr().isAnd() && result.getExpr().arity() == 2, 00658 "TheoryArithNew::processIntEq("+eqn.getExpr().toString() 00659 +")\n result = "+result.getExpr().toString()); 00660 solvedAndNewEqs.push_back(getCommonRules()->andElim(result, 0)); 00661 newEq = getCommonRules()->andElim(result, 1); 00662 } else 00663 done = true; 00664 } while(!done); 00665 Theorem res; 00666 if(result.getExpr().isFalse()) res = result; 00667 else res = solvedForm(solvedAndNewEqs); 00668 TRACE("arith eq", "processIntEq => ", res.getExpr(), " }"); 00669 return res; 00670 } 00671 00672 /*! 00673 * Takes a vector of equations and for every equation x_i=t_i 00674 * substitutes t_j for x_j in t_i for all j>i. This turns the system 00675 * of equations into a solved form. 00676 * 00677 * Assumption: variables x_j may appear in the RHS terms t_i ONLY for 00678 * i<j, but not for i>=j. 00679 */ 00680 Theorem 00681 TheoryArithNew::solvedForm(const vector<Theorem>& solvedEqs) 00682 { 00683 DebugAssert(solvedEqs.size() > 0, "TheoryArithNew::solvedForm()"); 00684 00685 // Trace code 00686 TRACE_MSG("arith eq", "TheoryArithNew::solvedForm:solvedEqs(\n ["); 00687 IF_DEBUG(if(debugger.trace("arith eq")) { 00688 for(vector<Theorem>::const_iterator j = solvedEqs.begin(), 00689 jend=solvedEqs.end(); j!=jend;++j) 00690 TRACE("arith eq", "", j->getExpr(), ",\n "); 00691 }) 00692 TRACE_MSG("arith eq", " ]) {"); 00693 // End of Trace code 00694 00695 vector<Theorem>::const_reverse_iterator 00696 i = solvedEqs.rbegin(), 00697 iend = solvedEqs.rend(); 00698 // Substitution map: a variable 'x' is mapped to a Theorem x=t. 00699 // This map accumulates the resulting solved form. 00700 ExprMap<Theorem> subst; 00701 for(; i!=iend; ++i) { 00702 if(i->isRewrite()) { 00703 Theorem thm = substAndCanonize(*i, subst); 00704 TRACE("arith eq", "solvedForm: subst["+i->getLHS().toString()+"] = ", 00705 thm.getExpr(), ""); 00706 subst[i->getLHS()] = thm; 00707 } 00708 else { 00709 // This is the FALSE case: just return the contradiction 00710 DebugAssert(i->getExpr().isFalse(), 00711 "TheoryArithNew::solvedForm: an element of solvedEqs must " 00712 "be either EQ or FALSE: "+i->toString()); 00713 return *i; 00714 } 00715 } 00716 // Now we've collected the solved form in 'subst'. Wrap it up into 00717 // a conjunction and return. 00718 vector<Theorem> thms; 00719 for(ExprMap<Theorem>::iterator i=subst.begin(), iend=subst.end(); 00720 i!=iend; ++i) 00721 thms.push_back(i->second); 00722 if (thms.size() > 1) 00723 return getCommonRules()->andIntro(thms); 00724 else 00725 return thms.back(); 00726 } 00727 00728 00729 /*! 00730 * ASSUMPTION: 't' is a fully canonized arithmetic term, and every 00731 * element of subst is a fully canonized equation of the form x=e, 00732 * indexed by the LHS variable. 00733 */ 00734 00735 Theorem 00736 TheoryArithNew::substAndCanonize(const Expr& t, ExprMap<Theorem>& subst) 00737 { 00738 TRACE("arith eq", "substAndCanonize(", t, ") {"); 00739 // Quick and dirty check: return immediately if subst is empty 00740 if(subst.empty()) { 00741 Theorem res(reflexivityRule(t)); 00742 TRACE("arith eq", "substAndCanonize[subst empty] => ", res, " }"); 00743 return res; 00744 } 00745 // Check if we can substitute 't' directly 00746 ExprMap<Theorem>::iterator i = subst.find(t), iend=subst.end(); 00747 if(i!=iend) { 00748 TRACE("arith eq", "substAndCanonize[subst] => ", i->second, " }"); 00749 return i->second; 00750 } 00751 // The base case: t is an i-leaf 00752 if(isLeaf(t)) { 00753 Theorem res(reflexivityRule(t)); 00754 TRACE("arith eq", "substAndCanonize[i-leaf] => ", res, " }"); 00755 return res; 00756 } 00757 // 't' is an arithmetic term; recurse into the children 00758 vector<Theorem> thms; 00759 vector<unsigned> changed; 00760 for(unsigned j=0, jend=t.arity(); j!=jend; ++j) { 00761 Theorem thm = substAndCanonize(t[j], subst); 00762 if(thm.getRHS() != t[j]) { 00763 thm = canonThm(thm); 00764 thms.push_back(thm); 00765 changed.push_back(j); 00766 } 00767 } 00768 // Do the actual substitution and canonize the result 00769 Theorem res; 00770 if(thms.size() > 0) { 00771 res = substitutivityRule(t, changed, thms); 00772 res = canonThm(res); 00773 } 00774 else 00775 res = reflexivityRule(t); 00776 TRACE("arith eq", "substAndCanonize => ", res, " }"); 00777 return res; 00778 } 00779 00780 00781 /*! 00782 * ASSUMPTION: 't' is a fully canonized equation of the form x = t, 00783 * and so is every element of subst, indexed by the LHS variable. 00784 */ 00785 00786 Theorem 00787 TheoryArithNew::substAndCanonize(const Theorem& eq, ExprMap<Theorem>& subst) 00788 { 00789 // Quick and dirty check: return immediately if subst is empty 00790 if(subst.empty()) return eq; 00791 00792 DebugAssert(eq.isRewrite(), "TheoryArithNew::substAndCanonize: t = " 00793 +eq.getExpr().toString()); 00794 const Expr& t = eq.getRHS(); 00795 // Do the actual substitution in the term t 00796 Theorem thm = substAndCanonize(t, subst); 00797 // Substitution had no result: return the original equation 00798 if(thm.getRHS() == t) return eq; 00799 // Otherwise substitute the result into the equation 00800 vector<Theorem> thms; 00801 vector<unsigned> changed; 00802 thms.push_back(thm); 00803 changed.push_back(1); 00804 return iffMP(eq, substitutivityRule(eq.getExpr(), changed, thms)); 00805 } 00806 00807 00808 void TheoryArithNew::updateStats(const Rational& c, const Expr& v) 00809 { 00810 TRACE("arith ineq", "updateStats("+c.toString()+", ", v, ")"); 00811 if(c > 0) { 00812 if(d_countRight.count(v) > 0) d_countRight[v] = d_countRight[v] + 1; 00813 else d_countRight[v] = 1; 00814 } 00815 else 00816 if(d_countLeft.count(v) > 0) d_countLeft[v] = d_countLeft[v] + 1; 00817 else d_countLeft[v] = 1; 00818 } 00819 00820 00821 void TheoryArithNew::updateStats(const Expr& monomial) 00822 { 00823 Expr c, m; 00824 separateMonomial(monomial, c, m); 00825 updateStats(c.getRational(), m); 00826 } 00827 00828 00829 void TheoryArithNew::addToBuffer(const Theorem& thm) { 00830 // First, turn the inequality into 0 < rhs 00831 // FIXME: check if this can be optimized away 00832 Theorem result(thm); 00833 const Expr& e = thm.getExpr(); 00834 // int kind = e.getKind(); 00835 if(!(e[0].isRational() && e[0].getRational() == 0)) { 00836 result = iffMP(result, d_rules->rightMinusLeft(e)); 00837 result = canonPred(result); 00838 } 00839 TRACE("arith ineq", "addToBuffer(", result.getExpr(), ")"); 00840 // Push it into the buffer 00841 d_buffer.push_back(thm); 00842 00843 // Collect the statistics about variables 00844 const Expr& rhs = thm.getExpr()[1]; 00845 if(isPlus(rhs)) 00846 for(Expr::iterator i=rhs.begin(), iend=rhs.end(); i!=iend; ++i) 00847 updateStats(*i); 00848 else // It's a monomial 00849 updateStats(rhs); 00850 } 00851 00852 00853 Expr TheoryArithNew::computeNormalFactor(const Expr& right, NormalizationType type) { 00854 // Strategy: compute f = lcm(d1...dn)/gcd(c1...cn), where the RHS is of the form c1/d1*x1 + ... + cn/dn*xn or a rational 00855 00856 // The expression must be canonised, i.e. it is a sum or a rational 00857 DebugAssert(isRational(right) || isPlus(right),"TheoryArithNew::computeNormalFactor: " + right.toString() + "wrong kind"); 00858 00859 // The factor we will compute 00860 Rational factor; 00861 00862 // Sign of the factor 00863 int sign = 0; 00864 00865 // In case the expression is a PLUS expression find the gcd 00866 if(isPlus(right)) { 00867 00868 // Vector of numerators and denominators 00869 vector<Rational> nums, denoms; 00870 00871 // Pass throught the sum and pick up the integers 00872 for(int i = 0, iend = right.arity(); i < iend; i ++) { 00873 00874 Rational c(1); // The rational constant of the current summand 00875 00876 // If rational or multiplicatino set c to be the apropriate rational 00877 switch(right[i].getKind()) { 00878 00879 case RATIONAL_EXPR: 00880 00881 // Sum term is just a rational, so just add it 00882 c = abs(right[i].getRational()); 00883 break; 00884 00885 case MULT: 00886 00887 // Sum term is involves multiplication 00888 c = right[i][0].getRational(); 00889 00890 // If this is the first one (sign is still not set) set the sign depending on the sign of the term 00891 if (!sign) { 00892 00893 // If the normalization type is NORMALIZE_UNIT just return the invese of the first 00894 if (type == NORMALIZE_UNIT) return rat(1/c); 00895 00896 // Set the sign otherwise 00897 sign = (c > 0 ? 1 : -1); 00898 } 00899 00900 // Constant should be positive for lcd and gcd computation 00901 c = abs(c); 00902 00903 break; 00904 00905 default: // Stays 1 or everything else 00906 00907 break; 00908 } 00909 00910 // Add the demoninator and the numerator to the apropriate vectors 00911 nums.push_back(c.getNumerator()); 00912 denoms.push_back(c.getDenominator()); 00913 } 00914 00915 // Compute the gcd of all the numerators 00916 Rational gcd_nums = gcd(nums); 00917 00918 // x/0 == 0 in our model, as a total extension of arithmetic. The 00919 // particular value of x/0 is irrelevant, since the DP is guarded 00920 // by the top-level TCCs, and it is safe to return any value in 00921 // cases when terms are undefined. 00922 factor = (gcd_nums == 0)? 0 : (sign * lcm(denoms) / gcd_nums); 00923 } else 00924 // The expression is a rational, just return 1 00925 factor = 1; 00926 00927 // Return the reational expression representing the factor 00928 return rat(factor); 00929 } 00930 00931 00932 bool TheoryArithNew::lessThanVar(const Expr& isolatedMonomial, const Expr& var2) 00933 { 00934 DebugAssert(!isRational(var2) && !isRational(isolatedMonomial), 00935 "TheoryArithNew::findMaxVar: isolatedMonomial cannot be rational" + 00936 isolatedMonomial.toString()); 00937 Expr c, var0, var1; 00938 separateMonomial(isolatedMonomial, c, var0); 00939 separateMonomial(var2, c, var1); 00940 return var0 < var1; 00941 } 00942 00943 00944 void TheoryArithNew::separateMonomial(const Expr& e, Expr& c, Expr& var) { 00945 TRACE("separateMonomial", "separateMonomial(", e, ")"); 00946 DebugAssert(!isPlus(e), 00947 "TheoryArithNew::separateMonomial(e = "+e.toString()+")"); 00948 if(isMult(e)) { 00949 DebugAssert(e.arity() >= 2, 00950 "TheoryArithNew::separateMonomial(e = "+e.toString()+")"); 00951 c = e[0]; 00952 if(e.arity() == 2) var = e[1]; 00953 else { 00954 vector<Expr> kids = e.getKids(); 00955 kids[0] = rat(1); 00956 var = multExpr(kids); 00957 } 00958 } else { 00959 c = rat(1); 00960 var = e; 00961 } 00962 DebugAssert(c.isRational(), "TheoryArithNew::separateMonomial(e = " 00963 +e.toString()+", c = "+c.toString()+")"); 00964 DebugAssert(!isMult(var) || (var[0].isRational() && var[0].getRational()==1), 00965 "TheoryArithNew::separateMonomial(e = " 00966 +e.toString()+", var = "+var.toString()+")"); 00967 } 00968 00969 00970 //returns true if e1 < e2, else false(i.e e2 < e1 or e1,e2 are not 00971 //comparable) 00972 bool TheoryArithNew::VarOrderGraph::lessThan(const Expr& e1, const Expr& e2) 00973 { 00974 d_cache.clear(); 00975 //returns true if e1 is in the subtree rooted at e2 implying e1 < e2 00976 return dfs(e1,e2); 00977 } 00978 00979 //returns true if e1 is in the subtree rooted at e2 implying e1 < e2 00980 bool TheoryArithNew::VarOrderGraph::dfs(const Expr& e1, const Expr& e2) 00981 { 00982 if(e1 == e2) 00983 return true; 00984 if(d_cache.count(e2) > 0) 00985 return false; 00986 if(d_edges.count(e2) == 0) 00987 return false; 00988 d_cache[e2] = true; 00989 vector<Expr>& e2Edges = d_edges[e2]; 00990 vector<Expr>::iterator i = e2Edges.begin(); 00991 vector<Expr>::iterator iend = e2Edges.end(); 00992 //if dfs finds e1 then i != iend else i is equal to iend 00993 for(; i != iend && !dfs(e1,*i); ++i); 00994 return (i != iend); 00995 } 00996 00997 00998 void TheoryArithNew::VarOrderGraph::selectSmallest(vector<Expr>& v1, 00999 vector<Expr>& v2) 01000 { 01001 int v1Size = v1.size(); 01002 vector<bool> v3(v1Size); 01003 for(int j=0; j < v1Size; ++j) 01004 v3[j] = false; 01005 01006 for(int j=0; j < v1Size; ++j) { 01007 if(v3[j]) continue; 01008 for(int i =0; i < v1Size; ++i) { 01009 if((i == j) || v3[i]) 01010 continue; 01011 if(lessThan(v1[i],v1[j])) { 01012 v3[j] = true; 01013 break; 01014 } 01015 } 01016 } 01017 vector<Expr> new_v1; 01018 01019 for(int j = 0; j < v1Size; ++j) 01020 if(!v3[j]) v2.push_back(v1[j]); 01021 else new_v1.push_back(v1[j]); 01022 v1 = new_v1; 01023 } 01024 01025 01026 void TheoryArithNew::VarOrderGraph::selectLargest(const vector<Expr>& v1, 01027 vector<Expr>& v2) 01028 { 01029 int v1Size = v1.size(); 01030 vector<bool> v3(v1Size); 01031 for(int j=0; j < v1Size; ++j) 01032 v3[j] = false; 01033 01034 for(int j=0; j < v1Size; ++j) { 01035 if(v3[j]) continue; 01036 for(int i =0; i < v1Size; ++i) { 01037 if((i == j) || v3[i]) 01038 continue; 01039 if(lessThan(v1[j],v1[i])) { 01040 v3[j] = true; 01041 break; 01042 } 01043 } 01044 } 01045 01046 for(int j = 0; j < v1Size; ++j) 01047 if(!v3[j]) v2.push_back(v1[j]); 01048 } 01049 01050 /////////////////////////////////////////////////////////////////////////////// 01051 // TheoryArithNew Public Methods // 01052 /////////////////////////////////////////////////////////////////////////////// 01053 01054 01055 TheoryArithNew::TheoryArithNew(TheoryCore* core) 01056 : TheoryArith(core, "ArithmeticNew"), 01057 d_diseq(core->getCM()->getCurrentContext()), 01058 d_diseqIdx(core->getCM()->getCurrentContext(), 0, 0), 01059 d_inModelCreation(core->getCM()->getCurrentContext(), false, 0), 01060 d_freeConstDB(core->getCM()->getCurrentContext()), 01061 d_buffer(core->getCM()->getCurrentContext()), 01062 // Initialize index to 0 at scope 0 01063 d_bufferIdx(core->getCM()->getCurrentContext(), 0, 0), 01064 d_bufferThres(&(core->getFlags()["ineq-delay"].getInt())), 01065 d_countRight(core->getCM()->getCurrentContext()), 01066 d_countLeft(core->getCM()->getCurrentContext()), 01067 d_sharedTerms(core->getCM()->getCurrentContext()), 01068 d_sharedVars(core->getCM()->getCurrentContext()), 01069 consistent(core->getCM()->getCurrentContext()), 01070 lowerBound(core->getCM()->getCurrentContext()), 01071 upperBound(core->getCM()->getCurrentContext()), 01072 beta(core->getCM()->getCurrentContext()), 01073 assertedExprCount(core->getCM()->getCurrentContext()), 01074 integer_lemma(core->getCM()->getCurrentContext()) 01075 { 01076 IF_DEBUG(d_diseq.setName("CDList[TheoryArithNew::d_diseq]");) 01077 IF_DEBUG(d_buffer.setName("CDList[TheoryArithNew::d_buffer]");) 01078 IF_DEBUG(d_bufferIdx.setName("CDList[TheoryArithNew::d_bufferIdx]");) 01079 01080 getEM()->newKind(REAL, "_REAL", true); 01081 getEM()->newKind(INT, "_INT", true); 01082 getEM()->newKind(SUBRANGE, "_SUBRANGE", true); 01083 01084 getEM()->newKind(UMINUS, "_UMINUS"); 01085 getEM()->newKind(PLUS, "_PLUS"); 01086 getEM()->newKind(MINUS, "_MINUS"); 01087 getEM()->newKind(MULT, "_MULT"); 01088 getEM()->newKind(DIVIDE, "_DIVIDE"); 01089 getEM()->newKind(POW, "_POW"); 01090 getEM()->newKind(INTDIV, "_INTDIV"); 01091 getEM()->newKind(MOD, "_MOD"); 01092 getEM()->newKind(LT, "_LT"); 01093 getEM()->newKind(LE, "_LE"); 01094 getEM()->newKind(GT, "_GT"); 01095 getEM()->newKind(GE, "_GE"); 01096 getEM()->newKind(IS_INTEGER, "_IS_INTEGER"); 01097 getEM()->newKind(NEGINF, "_NEGINF"); 01098 getEM()->newKind(POSINF, "_POSINF"); 01099 getEM()->newKind(DARK_SHADOW, "_DARK_SHADOW"); 01100 getEM()->newKind(GRAY_SHADOW, "_GRAY_SHADOW"); 01101 01102 getEM()->newKind(REAL_CONST, "_REAL_CONST"); 01103 01104 vector<int> kinds; 01105 kinds.push_back(REAL); 01106 kinds.push_back(INT); 01107 kinds.push_back(SUBRANGE); 01108 kinds.push_back(IS_INTEGER); 01109 kinds.push_back(UMINUS); 01110 kinds.push_back(PLUS); 01111 kinds.push_back(MINUS); 01112 kinds.push_back(MULT); 01113 kinds.push_back(DIVIDE); 01114 kinds.push_back(POW); 01115 kinds.push_back(INTDIV); 01116 kinds.push_back(MOD); 01117 kinds.push_back(LT); 01118 kinds.push_back(LE); 01119 kinds.push_back(GT); 01120 kinds.push_back(GE); 01121 kinds.push_back(RATIONAL_EXPR); 01122 kinds.push_back(NEGINF); 01123 kinds.push_back(POSINF); 01124 kinds.push_back(DARK_SHADOW); 01125 kinds.push_back(GRAY_SHADOW); 01126 kinds.push_back(REAL_CONST); 01127 01128 registerTheory(this, kinds, true); 01129 01130 d_rules = createProofRules(); 01131 01132 d_realType = Type(getEM()->newLeafExpr(REAL)); 01133 d_intType = Type(getEM()->newLeafExpr(INT)); 01134 consistent = SATISFIABLE; 01135 assertedExprCount = 0; 01136 } 01137 01138 01139 // Destructor: delete the proof rules class if it's present 01140 TheoryArithNew::~TheoryArithNew() { 01141 if(d_rules != NULL) delete d_rules; 01142 // Clear the inequality databases 01143 for(ExprMap<CDList<Ineq> *>::iterator i=d_inequalitiesRightDB.begin(), 01144 iend=d_inequalitiesRightDB.end(); i!=iend; ++i) { 01145 delete (i->second); 01146 free(i->second); 01147 } 01148 for(ExprMap<CDList<Ineq> *>::iterator i=d_inequalitiesLeftDB.begin(), 01149 iend=d_inequalitiesLeftDB.end(); i!=iend; ++i) { 01150 delete (i->second); 01151 free (i->second); 01152 } 01153 } 01154 01155 void TheoryArithNew::collectVars(const Expr& e, vector<Expr>& vars, 01156 set<Expr>& cache) { 01157 // Check the cache first 01158 if(cache.count(e) > 0) return; 01159 // Not processed yet. Cache the expression and proceed 01160 cache.insert(e); 01161 if(isLeaf(e)) vars.push_back(e); 01162 else 01163 for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) 01164 collectVars(*i, vars, cache); 01165 } 01166 01167 void 01168 TheoryArithNew::processFiniteInterval(const Theorem& alphaLEax, 01169 const Theorem& bxLEbeta) { 01170 const Expr& ineq1(alphaLEax.getExpr()); 01171 const Expr& ineq2(bxLEbeta.getExpr()); 01172 DebugAssert(isLE(ineq1), "TheoryArithNew::processFiniteInterval: ineq1 = " 01173 +ineq1.toString()); 01174 DebugAssert(isLE(ineq2), "TheoryArithNew::processFiniteInterval: ineq2 = " 01175 +ineq2.toString()); 01176 // If the inequalities are not integer, just return (nothing to do) 01177 if(!isInteger(ineq1[0]) 01178 || !isInteger(ineq1[1]) 01179 || !isInteger(ineq2[0]) 01180 || !isInteger(ineq2[1])) 01181 return; 01182 01183 const Expr& ax = ineq1[1]; 01184 const Expr& bx = ineq2[0]; 01185 DebugAssert(!isPlus(ax) && !isRational(ax), 01186 "TheoryArithNew::processFiniteInterval:\n ax = "+ax.toString()); 01187 DebugAssert(!isPlus(bx) && !isRational(bx), 01188 "TheoryArithNew::processFiniteInterval:\n bx = "+bx.toString()); 01189 Expr a = isMult(ax)? ax[0] : rat(1); 01190 Expr b = isMult(bx)? bx[0] : rat(1); 01191 01192 Theorem thm1(alphaLEax), thm2(bxLEbeta); 01193 // Multiply the inequalities by 'b' and 'a', and canonize them, if necessary 01194 if(a != b) { 01195 thm1 = canonPred(iffMP(alphaLEax, d_rules->multIneqn(ineq1, b))); 01196 thm2 = canonPred(iffMP(bxLEbeta, d_rules->multIneqn(ineq2, a))); 01197 } 01198 // Check that a*beta - b*alpha == c > 0 01199 const Expr& alphaLEt = thm1.getExpr(); 01200 const Expr& alpha = alphaLEt[0]; 01201 const Expr& t = alphaLEt[1]; 01202 const Expr& beta = thm2.getExpr()[1]; 01203 Expr c = canon(beta - alpha).getRHS(); 01204 01205 if(c.isRational() && c.getRational() >= 1) { 01206 // This is a finite interval. First, derive t <= alpha + c: 01207 // canon(alpha+c) => (alpha+c == beta) ==> [symmetry] beta == alpha+c 01208 // Then substitute that in thm2 01209 Theorem bEQac = symmetryRule(canon(alpha + c)); 01210 // Substitute beta == alpha+c for the second child of thm2 01211 vector<unsigned> changed; 01212 vector<Theorem> thms; 01213 changed.push_back(1); 01214 thms.push_back(bEQac); 01215 Theorem tLEac = substitutivityRule(thm2.getExpr(), changed, thms); 01216 tLEac = iffMP(thm2, tLEac); 01217 // Derive and enqueue the finite interval constraint 01218 Theorem isInta(isIntegerThm(alpha)); 01219 Theorem isIntt(isIntegerThm(t)); 01220 enqueueFact(d_rules->finiteInterval(thm1, tLEac, isInta, isIntt)); 01221 } 01222 } 01223 01224 01225 void 01226 TheoryArithNew::processFiniteIntervals(const Expr& x) { 01227 // If x is not integer, do not bother 01228 if(!isInteger(x)) return; 01229 // Process every pair of the opposing inequalities for 'x' 01230 ExprMap<CDList<Ineq> *>::iterator iLeft, iRight; 01231 iLeft = d_inequalitiesLeftDB.find(x); 01232 if(iLeft == d_inequalitiesLeftDB.end()) return; 01233 iRight = d_inequalitiesRightDB.find(x); 01234 if(iRight == d_inequalitiesRightDB.end()) return; 01235 // There are some opposing inequalities; get the lists 01236 CDList<Ineq>& ineqsLeft = *(iLeft->second); 01237 CDList<Ineq>& ineqsRight = *(iRight->second); 01238 // Get the sizes of the lists 01239 size_t sizeLeft = ineqsLeft.size(); 01240 size_t sizeRight = ineqsRight.size(); 01241 // Process all the pairs of the opposing inequalities 01242 for(size_t l=0; l<sizeLeft; ++l) 01243 for(size_t r=0; r<sizeRight; ++r) 01244 processFiniteInterval(ineqsRight[r], ineqsLeft[l]); 01245 } 01246 01247 /*! This function recursively decends expression tree <strong>without 01248 * caching</strong> until it hits a node that is already setup. Be 01249 * careful on what expressions you are calling it. 01250 */ 01251 void 01252 TheoryArithNew::setupRec(const Expr& e) { 01253 if(e.hasFind()) return; 01254 // First, set up the kids recursively 01255 for (int k = 0; k < e.arity(); ++k) { 01256 setupRec(e[k]); 01257 } 01258 // Create a find pointer for e 01259 e.setFind(reflexivityRule(e)); 01260 e.setEqNext(reflexivityRule(e)); 01261 // And call our own setup() 01262 setup(e); 01263 } 01264 01265 01266 /*! 01267 * Keep track of all finitely bounded integer variables in shared 01268 * terms. 01269 * 01270 * When a new shared term t is reported, all of its variables x1...xn 01271 * are added to the set d_sharedVars. 01272 * 01273 * For each newly added variable x, check all of its opposing 01274 * inequalities, find out all the finite bounds and assert the 01275 * corresponding GRAY_SHADOW constraints. 01276 * 01277 * When projecting integer inequalities, the database d_sharedVars is 01278 * consulted, and if the variable is in it, check the shadows for 01279 * being a finite interval, and produce the additional GRAY_SHADOW 01280 * constraints. 01281 */ 01282 void TheoryArithNew::addSharedTerm(const Expr& e) { 01283 d_sharedTerms[e] = true; 01284 /* 01285 set<Expr> cache; // Aux. cache for collecting i-leaves 01286 vector<Expr> vars; // Vector of vars in e 01287 collectVars(e, vars, cache); 01288 for(vector<Expr>::iterator i=vars.begin(), iend=vars.end(); i!=iend; ++i) { 01289 if(d_sharedVars.count(*i) == 0) { 01290 TRACE("arith shared", "TheoryArithNew::addSharedTerm: new var = ", *i, ""); 01291 processFiniteIntervals(*i); 01292 d_sharedVars[*i]=true; 01293 } 01294 } 01295 */ 01296 } 01297 01298 void TheoryArithNew::refineCounterExample() 01299 { 01300 d_inModelCreation = true; 01301 TRACE("model", "refineCounterExample[TheoryArithNew] ", "", "{"); 01302 CDMap<Expr, bool>::iterator it = d_sharedTerms.begin(), it2, 01303 iend = d_sharedTerms.end(); 01304 // Add equalities over all pairs of shared terms as suggested 01305 // splitters. Notice, that we want to split on equality 01306 // (positively) first, to reduce the size of the model. 01307 for(; it!=iend; ++it) { 01308 // Copy by value: the elements in the pair from *it are NOT refs in CDMap 01309 Expr e1 = (*it).first; 01310 for(it2 = it, ++it2; it2!=iend; ++it2) { 01311 Expr e2 = (*it2).first; 01312 DebugAssert(isReal(getBaseType(e1)), 01313 "TheoryArithNew::refineCounterExample: e1 = "+e1.toString() 01314 +"\n type(e1) = "+e1.getType().toString()); 01315 if(findExpr(e1) != findExpr(e2)) { 01316 DebugAssert(isReal(getBaseType(e2)), 01317 "TheoryArithNew::refineCounterExample: e2 = "+e2.toString() 01318 +"\n type(e2) = "+e2.getType().toString()); 01319 Expr eq = simplifyExpr(e1.eqExpr(e2)); 01320 if (!eq.isBoolConst()) 01321 addSplitter(eq); 01322 } 01323 } 01324 } 01325 TRACE("model", "refineCounterExample[Theory::Arith] ", "", "}"); 01326 } 01327 01328 01329 void 01330 TheoryArithNew::findRationalBound(const Expr& varSide, const Expr& ratSide, 01331 const Expr& var, 01332 Rational &r) 01333 { 01334 Expr c, x; 01335 separateMonomial(varSide, c, x); 01336 01337 DebugAssert(findExpr(c).isRational(), 01338 "seperateMonomial failed"); 01339 DebugAssert(findExpr(ratSide).isRational(), 01340 "smallest variable in graph, should not have variables" 01341 " in inequalities: "); 01342 DebugAssert(x == var, "separateMonomial found different variable: " 01343 + var.toString()); 01344 r = findExpr(ratSide).getRational() / findExpr(c).getRational(); 01345 } 01346 01347 bool 01348 TheoryArithNew::findBounds(const Expr& e, Rational& lub, Rational& glb) 01349 { 01350 bool strictLB=false, strictUB=false; 01351 bool right = (d_inequalitiesRightDB.count(e) > 0 01352 && d_inequalitiesRightDB[e]->size() > 0); 01353 bool left = (d_inequalitiesLeftDB.count(e) > 0 01354 && d_inequalitiesLeftDB[e]->size() > 0); 01355 int numRight = 0, numLeft = 0; 01356 if(right) { //rationals less than e 01357 CDList<Ineq> * ratsLTe = d_inequalitiesRightDB[e]; 01358 for(unsigned int i=0; i<ratsLTe->size(); i++) { 01359 DebugAssert((*ratsLTe)[i].varOnRHS(), "variable on wrong side!"); 01360 Expr ineq = (*ratsLTe)[i].ineq().getExpr(); 01361 Expr leftSide = ineq[0], rightSide = ineq[1]; 01362 Rational r; 01363 findRationalBound(rightSide, leftSide, e , r); 01364 if(numRight==0 || r>glb){ 01365 glb = r; 01366 strictLB = isLT(ineq); 01367 } 01368 numRight++; 01369 } 01370 TRACE("model", " =>Lower bound ", glb.toString(), ""); 01371 } 01372 if(left) { //rationals greater than e 01373 CDList<Ineq> * ratsGTe = d_inequalitiesLeftDB[e]; 01374 for(unsigned int i=0; i<ratsGTe->size(); i++) { 01375 DebugAssert((*ratsGTe)[i].varOnLHS(), "variable on wrong side!"); 01376 Expr ineq = (*ratsGTe)[i].ineq().getExpr(); 01377 Expr leftSide = ineq[0], rightSide = ineq[1]; 01378 Rational r; 01379 findRationalBound(leftSide, rightSide, e, r); 01380 if(numLeft==0 || r<lub) { 01381 lub = r; 01382 strictUB = isLT(ineq); 01383 } 01384 numLeft++; 01385 } 01386 TRACE("model", " =>Upper bound ", lub.toString(), ""); 01387 } 01388 if(!left && !right) { 01389 lub = 0; 01390 glb = 0; 01391 } 01392 if(!left && right) {lub = glb +2;} 01393 if(!right && left) {glb = lub-2;} 01394 DebugAssert(glb <= lub, "Greatest lower bound needs to be smaller " 01395 "than least upper bound"); 01396 return strictLB; 01397 } 01398 01399 void TheoryArithNew::assignVariables(std::vector<Expr>&v) 01400 { 01401 int count = 0; 01402 while (v.size() > 0) { 01403 std::vector<Expr> bottom; 01404 d_graph.selectSmallest(v, bottom); 01405 TRACE("model", "Finding variables to assign. Iteration # ", count, ""); 01406 for(unsigned int i = 0; i<bottom.size(); i++) { 01407 Expr e = bottom[i]; 01408 TRACE("model", "Found: ", e, ""); 01409 // Check if it is already a concrete constant 01410 if(e.isRational()) continue; 01411 01412 Rational lub, glb; 01413 bool strictLB; 01414 strictLB = findBounds(e, lub, glb); 01415 Rational mid; 01416 if(isInteger(e)) { 01417 if(strictLB && glb.isInteger()) 01418 mid = glb + 1; 01419 else 01420 mid = ceil(glb); 01421 } 01422 else 01423 mid = (lub + glb)/2; 01424 TRACE("model", "Assigning mid = ", mid, " {"); 01425 assignValue(e, rat(mid)); 01426 TRACE("model", "Assigned find(e) = ", findExpr(e), " }"); 01427 if(inconsistent()) return; // Punt immediately if failed 01428 } 01429 count++; 01430 } 01431 } 01432 01433 void TheoryArithNew::computeModelBasic(const std::vector<Expr>& v) 01434 { 01435 d_inModelCreation = true; 01436 vector<Expr> reps; 01437 TRACE("model", "Arith=>computeModel ", "", "{"); 01438 for(unsigned int i=0; i <v.size(); ++i) { 01439 const Expr& e = v[i]; 01440 if(findExpr(e) == e) { 01441 TRACE("model", "arith variable:", e , ""); 01442 reps.push_back(e); 01443 } 01444 else { 01445 TRACE("model", "arith variable:", e , ""); 01446 TRACE("model", " ==> is defined by: ", findExpr(e) , ""); 01447 } 01448 } 01449 assignVariables(reps); 01450 TRACE("model", "Arith=>computeModel", "", "}"); 01451 d_inModelCreation = false; 01452 } 01453 01454 // For any arith expression 'e', if the subexpressions are assigned 01455 // concrete values, then find(e) must already be a concrete value. 01456 void TheoryArithNew::computeModel(const Expr& e, vector<Expr>& vars) { 01457 DebugAssert(findExpr(e).isRational(), "TheoryArithNew::computeModel(" 01458 +e.toString()+")\n e is not assigned concrete value.\n" 01459 +" find(e) = "+findExpr(e).toString()); 01460 assignValue(simplify(e)); 01461 vars.push_back(e); 01462 } 01463 01464 /*! accepts a rewrite theorem over eqn|ineqn and normalizes it 01465 * and returns a theorem to that effect. assumes e is non-trivial 01466 * i.e. e is not '0=const' or 'const=0' or '0 <= const' etc. 01467 */ 01468 Theorem TheoryArithNew::normalize(const Expr& e, NormalizationType type) { 01469 01470 //e is an eqn or ineqn. e is not a trivial eqn or ineqn 01471 //trivial means 0 = const or 0 <= const. 01472 01473 // Trace the normalization on the arithm trace flag 01474 TRACE("arith", "normalize(", e, ") {"); 01475 01476 // The constraint must be an equality or inequality 01477 DebugAssert(isIneq(e), "normalize: input must be an inequality: " + e.toString()); 01478 01479 // The right side must be a sum or a multiplication 01480 DebugAssert(isPlus(e[1]) || (isMult(e[1]) && e[1][0].isRational()), "normalize: right side must be a sum or a mult: " + e.toString()); 01481 01482 // The left side must be 0 01483 DebugAssert(e[0].isRational() && 0 == e[0].getRational(), "normalize: e[0] must be 0" + e.toString()); 01484 01485 // Compute the factor to use for normalizing the inequality 01486 Expr factor; 01487 // If a mult, just take the coefficient 01488 if (isMult(e[1])) factor = rat(1/e[1][0].getRational()); 01489 // Otherwise compute it 01490 else factor = computeNormalFactor(e[1], type); 01491 01492 // Trace the rezult on the arith flag 01493 TRACE("arith", "normalize: factor = ", factor, ""); 01494 01495 // The theorem we will be creating (reflexivity, just in case) 01496 Theorem thm; 01497 01498 // Now multiply the equality by the factor, unless it is 1 01499 if(factor.getRational() != 1) 01500 switch(e.getKind()) { 01501 01502 case LE: 01503 case LT: 01504 case GE: 01505 case GT: 01506 01507 // Multiply inequality by the factor 01508 thm = d_rules->multIneqn(e, factor); 01509 01510 // And canonize the result 01511 thm = canonPredEquiv(thm); 01512 01513 // Inequalities case break 01514 break; 01515 01516 default: 01517 01518 // How did we get here 01519 FatalAssert(false, "normalize: control should not reach here" + e.toString()); 01520 01521 // Default case break 01522 break; 01523 } 01524 else 01525 // If rational is 1 then nothing to be done 01526 thm = reflexivityRule(e); 01527 01528 01529 // Trace the resulting theorem on the arith trace flag 01530 TRACE("arith", "normalize => ", thm, " }"); 01531 01532 // Return the explaining theorem 01533 return(thm); 01534 } 01535 01536 01537 Theorem TheoryArithNew::normalize(const Theorem& eIffEqn, NormalizationType type) { 01538 return transitivityRule(eIffEqn, normalize(eIffEqn.getRHS(), type)); 01539 } 01540 01541 Theorem TheoryArithNew::rafineIntegerConstraints(const Theorem& thm) { 01542 01543 // The resulting theorem 01544 Theorem result = thm; 01545 01546 // Get the constraint 01547 const Expr& constr = result.getRHS(); 01548 01549 // Get the proof that this constraint is an integer constraint 01550 Theorem isIntConstraintThm = isIntegerThm(constr[1]); 01551 01552 // If not an integer, just return the same theorem 01553 if (isIntConstraintThm.isNull()) return result; 01554 01555 // Trace the integer 01556 TRACE("integer", "TheoryArithNew::rafineIntegerConstraints(", constr, ")"); 01557 TRACE("integer", "TheoryArithNew::rafineIntegerConstraints: int proof:", isIntConstraintThm, ""); 01558 01559 // Get the left-hand of the constraint (the rational) 01560 Rational r = constr[0].getRational(); 01561 01562 // If it is a strict inequality, make it non-strict 01563 if (constr.getKind() == LT || constr.getKind() == GT || !r.isInteger()) 01564 result = transitivityRule(result, d_rules->rafineStrictInteger(isIntConstraintThm, constr)); 01565 01566 // Return the result 01567 return result; 01568 } 01569 01570 Theorem TheoryArithNew::rewrite(const Expr& e) { 01571 01572 // Leaves are assumeed to be already simplified 01573 //DebugAssert(leavesAreSimp(e), "Expected leaves to be simplified"); 01574 01575 // Trace the rewrites on the arith flag 01576 TRACE("arith", "TheoryArithNew::rewrite(", e, ") {"); 01577 01578 // The resulting theorem object 01579 Theorem thm; 01580 01581 // Are we in the NOT expression 01582 bool isNot = false; 01583 01584 // If the expression is not a term, i.e a literal 01585 if (!e.isTerm()) { 01586 01587 // If the expression is not a literal just return the reflexivity theorem 01588 if (!e.isAbsLiteral()) { 01589 01590 // Set the expression REWRITE NORMAL FLAG 01591 e.setRewriteNormal(); 01592 01593 // Create the reflaxivity rule 01594 thm = reflexivityRule(e); 01595 01596 // Trace the non-literal rewrite 01597 TRACE("arith", "TheoryArithNew::rewrite[non-literal] => ", thm, " }"); 01598 01599 // Return the theorem 01600 return thm; 01601 } 01602 01603 // Its a literal, switch the arithmetic relations for rewrite 01604 switch(e.getKind()) { 01605 01606 // Equality 01607 case EQ: { 01608 01609 // Rewrite equality as two inequalities 01610 thm = d_rules->eqToIneq(e); 01611 Expr andExpr = thm.getRHS(); 01612 01613 // Rewrite the left inequality 01614 Expr leExpr = andExpr[0]; 01615 const Theorem& thmLeft = simplify(leExpr); 01616 01617 // Rewrite the right inequality 01618 Expr geExpr = andExpr[1]; 01619 const Theorem& thmRight = simplify(geExpr); 01620 01621 // Do the substitution 01622 thm = transitivityRule(thm, substitutivityRule(andExpr, thmLeft, thmRight)); 01623 01624 // EQ case break 01625 break; 01626 } 01627 01628 // Negation of an atomic formula 01629 case NOT: 01630 01631 // If here, the equality should have already been rewritten as two disequalitites 01632 DebugAssert(e[0].getKind() != EQ, "TheoryArithNew::rewrite, not expecting equality under negation"); 01633 01634 // Negate the inequality and continue with the normal case 01635 thm = d_rules->negatedInequality(e); 01636 01637 // IMPORTANT, LE, LT, GE, GT MUST BE UNDER THIS 01638 isNot = true; 01639 01640 case LT: 01641 case GT: 01642 case LE: 01643 case GE: 01644 01645 // Move everything to the right side 01646 if (isNot) 01647 thm = transitivityRule(thm, d_rules->rightMinusLeft(thm.getRHS())); 01648 else 01649 thm = d_rules->rightMinusLeft(e); 01650 01651 // Canonise children again 01652 thm = canonPredEquiv(thm); 01653 01654 // If a trivial inequation just return true or false 01655 if ((thm.getRHS())[1].isRational()) 01656 thm = transitivityRule(thm, d_rules->constPredicate(thm.getRHS())); 01657 else { // It's a non-trivial inequation 01658 01659 // Normalize the inequality 01660 thm = normalize(thm, NORMALIZE_UNIT); 01661 01662 // Get the left and right side 01663 const Expr& normalised = thm.getRHS(); 01664 const Expr& rightSide = normalised[1]; 01665 const Expr& leftSide = normalised[0]; 01666 01667 // If the right side is a sum, move the rational to the right side 01668 if (isPlus(rightSide)) { 01669 // Check if the fist of the sum is a rational 01670 if (rightSide[0].isRational()) { 01671 // Add the negative constant to both sides 01672 thm = transitivityRule(thm, d_rules->plusPredicate(leftSide, rightSide, rat(-rightSide[0].getRational()), thm.getRHS().getKind())); 01673 // Canonize the left side 01674 const Theorem& thmLeft = d_rules->canonPlus(thm.getRHS()[0]); 01675 // Canonize the right side 01676 const Theorem& thmRight = d_rules->canonPlus(thm.getRHS()[1]); 01677 // Sunstitute the canonised into the expression 01678 thm = transitivityRule(thm, substitutivityRule(thm.getRHS(), thmLeft, thmRight)); 01679 } 01680 } 01681 } 01682 01683 // If a strict inequality on integers, or bounded by a non-integer, rafine it to a non-strict one 01684 // thm = rafineIntegerConstraints(thm); 01685 01686 // EQ, LE, LT, GE, GT case break 01687 break; 01688 01689 case IS_INTEGER: 01690 01691 // TRACE 01692 TRACE("integer", "Got ", e.toString(), ""); 01693 TRACE("integer", "Type ", e[0].getType().toString(), ""); 01694 01695 // TODO: What with the integers 01696 thm = d_rules->dummyTheorem(e); 01697 01698 // IS_INTEGER case break 01699 break; 01700 01701 default: 01702 01703 // How did we get here 01704 FatalAssert(false, "Theory_Arith::rewrite: control should not reach here"); 01705 01706 // default break 01707 break; 01708 01709 } // End relation case 01710 01711 } else { // Expression is a term 01712 01713 // Terms that don't contain formulas are canonised via the canon() function 01714 if (e.isAtomic()) thm = canon(e); 01715 // Otherwise just return the same expression 01716 else thm = reflexivityRule(e); 01717 } 01718 01719 // Compact the theorem into one rule 01720 //thm = d_rules->trustedRewrite(e, thm.getRHS()); 01721 01722 // Arith canonization is idempotent, the theory should stay the same 01723 if (theoryOf(thm.getRHS()) == this) 01724 thm.getRHS().setRewriteNormal(); 01725 01726 // Finished, trace the end of rewrite on the arith flag 01727 TRACE("arith", "TheoryArithNew::rewrite => ", thm, " }"); 01728 01729 // Return the final theorem 01730 return thm; 01731 } 01732 01733 01734 void TheoryArithNew::setup(const Expr& e) 01735 { 01736 //If the expression is not a term but rather a predicate 01737 if (!e.isTerm()) { 01738 01739 // If not or equality, just return 01740 if (e.isNot() || e.isEq()) return; 01741 01742 // TODO: Integer::eqToIneq 01743 if (isIntPred(e)) return; 01744 01745 // Check if the expression is canonised as (SUM t1 ... tn) @ b 01746 DebugAssert(isIneq(e) && e[0].isRational(), "TheoryArithNew::setup: b @ (sum t1 ... tn) :" + e.toString()); 01747 01748 // Add the sum to the notify list of e 01749 e[1].addToNotify(this, e); 01750 01751 } else { 01752 01753 // The arity of the expression 01754 int arity(e.arity()); 01755 01756 // Go through all the children and add this expression to their notify lists 01757 for (int k = 0 ; k < arity; k ++) { 01758 01759 // Add the to the notify list of the children 01760 e[k].addToNotify(this, e); 01761 01762 // Trace this notification add 01763 TRACE("arith setup", "e["+int2string(k)+"]: ", *(e[k].getNotify()), ""); 01764 } 01765 } 01766 } 01767 01768 01769 void TheoryArithNew::update(const Theorem& e, const Expr& d) 01770 { 01771 if (inconsistent()) return; 01772 IF_DEBUG(debugger.counter("arith update total")++;) 01773 if (!d.hasFind()) return; 01774 if (isIneq(d)) { 01775 // Substitute e[1] for e[0] in d and enqueue new inequality 01776 DebugAssert(e.getLHS() == d[1], "Mismatch"); 01777 Theorem thm = find(d); 01778 // DebugAssert(thm.getRHS() == trueExpr(), "Expected find = true"); 01779 vector<unsigned> changed; 01780 vector<Theorem> children; 01781 changed.push_back(1); 01782 children.push_back(e); 01783 Theorem thm2 = substitutivityRule(d, changed, children); 01784 if (thm.getRHS() == trueExpr()) { 01785 enqueueFact(iffMP(getCommonRules()->iffTrueElim(thm), thm2)); 01786 } 01787 else { 01788 enqueueFact(getCommonRules()->iffFalseElim( 01789 transitivityRule(symmetryRule(thm2), thm))); 01790 } 01791 IF_DEBUG(debugger.counter("arith update ineq")++;) 01792 } 01793 else if (find(d).getRHS() == d) { 01794 // Substitute e[1] for e[0] in d and assert the result equal to d 01795 Theorem thm = canonSimp(d); 01796 TRACE("arith", "TheoryArithNew::update(): thm = ", thm, ""); 01797 DebugAssert(leavesAreSimp(thm.getRHS()), "updateHelper error: " 01798 +thm.getExpr().toString()); 01799 assertEqualities(transitivityRule(thm, rewrite(thm.getRHS()))); 01800 IF_DEBUG(debugger.counter("arith update find(d)=d")++;) 01801 } 01802 } 01803 01804 01805 Theorem TheoryArithNew::solve(const Theorem& thm) 01806 { 01807 DebugAssert(thm.isRewrite() && thm.getLHS().isTerm(), ""); 01808 const Expr& lhs = thm.getLHS(); 01809 const Expr& rhs = thm.getRHS(); 01810 01811 // Check for already solved equalities. 01812 01813 // Have to be careful about the types: integer variable cannot be 01814 // assigned a real term. Also, watch for e[0] being a subexpression 01815 // of e[1]: this would create an unsimplifiable expression. 01816 if (isLeaf(lhs) && !isLeafIn(lhs, rhs) 01817 && (lhs.getType() != intType() || isInteger(rhs)) 01818 // && !e[0].subExprOf(e[1]) 01819 ) 01820 return thm; 01821 01822 // Symmetric version is already solved 01823 if (isLeaf(rhs) && !isLeafIn(rhs, lhs) 01824 && (rhs.getType() != intType() || isInteger(lhs)) 01825 // && !e[1].subExprOf(e[0]) 01826 ) 01827 return symmetryRule(thm); 01828 01829 return doSolve(thm); 01830 } 01831 01832 01833 void TheoryArithNew::computeModelTerm(const Expr& e, std::vector<Expr>& v) { 01834 switch(e.getKind()) { 01835 case RATIONAL_EXPR: // Skip the constants 01836 break; 01837 case PLUS: 01838 case MULT: 01839 case DIVIDE: 01840 case POW: // This is not a variable; extract the variables from children 01841 for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) 01842 // getModelTerm(*i, v); 01843 v.push_back(*i); 01844 break; 01845 default: { // Otherwise it's a variable. Check if it has a find pointer 01846 Expr e2(findExpr(e)); 01847 if(e==e2) { 01848 TRACE("model", "TheoryArithNew::computeModelTerm(", e, "): a variable"); 01849 // Leave it alone (it has no descendants) 01850 // v.push_back(e); 01851 } else { 01852 TRACE("model", "TheoryArithNew::computeModelTerm("+e.toString() 01853 +"): has find pointer to ", e2, ""); 01854 v.push_back(e2); 01855 } 01856 } 01857 } 01858 } 01859 01860 Expr TheoryArithNew::computeTypePred(const Type& t, const Expr& e) { 01861 Expr tExpr = t.getExpr(); 01862 switch(tExpr.getKind()) { 01863 case INT: 01864 return Expr(IS_INTEGER, e); 01865 case SUBRANGE: { 01866 std::vector<Expr> kids; 01867 kids.push_back(Expr(IS_INTEGER, e)); 01868 kids.push_back(leExpr(tExpr[0], e)); 01869 kids.push_back(leExpr(e, tExpr[1])); 01870 return andExpr(kids); 01871 } 01872 default: 01873 return e.getEM()->trueExpr(); 01874 } 01875 } 01876 01877 01878 void TheoryArithNew::checkAssertEqInvariant(const Theorem& e) 01879 { 01880 return; 01881 } 01882 01883 01884 void TheoryArithNew::checkType(const Expr& e) 01885 { 01886 switch (e.getKind()) { 01887 case INT: 01888 case REAL: 01889 if (e.arity() > 0) { 01890 throw Exception("Ill-formed arithmetic type: "+e.toString()); 01891 } 01892 break; 01893 case SUBRANGE: 01894 if (e.arity() != 2 || 01895 !isIntegerConst(e[0]) || 01896 !isIntegerConst(e[1]) || 01897 e[0].getRational() > e[1].getRational()) { 01898 throw Exception("bad SUBRANGE type expression"+e.toString()); 01899 } 01900 break; 01901 default: 01902 DebugAssert(false, "Unexpected kind in TheoryArithNew::checkType" 01903 +getEM()->getKindName(e.getKind())); 01904 } 01905 } 01906 01907 01908 Cardinality TheoryArithNew::finiteTypeInfo(Expr& e, Unsigned& n, 01909 bool enumerate, bool computeSize) 01910 { 01911 Cardinality card = CARD_INFINITE; 01912 switch (e.getKind()) { 01913 case SUBRANGE: { 01914 card = CARD_FINITE; 01915 Expr typeExpr = e; 01916 if (enumerate) { 01917 Rational r = typeExpr[0].getRational() + n; 01918 if (r <= typeExpr[1].getRational()) { 01919 e = rat(r); 01920 } 01921 else e = Expr(); 01922 } 01923 if (computeSize) { 01924 Rational r = typeExpr[1].getRational() - typeExpr[0].getRational() + 1; 01925 n = r.getUnsigned(); 01926 } 01927 break; 01928 } 01929 default: 01930 break; 01931 } 01932 return card; 01933 } 01934 01935 01936 void TheoryArithNew::computeType(const Expr& e) 01937 { 01938 switch (e.getKind()) { 01939 case REAL_CONST: 01940 e.setType(d_realType); 01941 break; 01942 case RATIONAL_EXPR: 01943 if(e.getRational().isInteger()) 01944 e.setType(d_intType); 01945 else 01946 e.setType(d_realType); 01947 break; 01948 case UMINUS: 01949 case PLUS: 01950 case MINUS: 01951 case MULT: 01952 case POW: { 01953 bool isInt = true; 01954 for(int k = 0; k < e.arity(); ++k) { 01955 if(d_realType != getBaseType(e[k])) 01956 throw TypecheckException("Expecting type REAL with `" + 01957 getEM()->getKindName(e.getKind()) + "',\n"+ 01958 "but got a " + getBaseType(e[k]).toString()+ 01959 " for:\n" + e.toString()); 01960 if(isInt && !isInteger(e[k])) 01961 isInt = false; 01962 } 01963 if(isInt) 01964 e.setType(d_intType); 01965 else 01966 e.setType(d_realType); 01967 break; 01968 } 01969 case DIVIDE: { 01970 Expr numerator = e[0]; 01971 Expr denominator = e[1]; 01972 if (getBaseType(numerator) != d_realType || 01973 getBaseType(denominator) != d_realType) { 01974 throw TypecheckException("Expecting only REAL types with `DIVIDE',\n" 01975 "but got " + getBaseType(numerator).toString()+ 01976 " and " + getBaseType(denominator).toString() + 01977 " for:\n" + e.toString()); 01978 } 01979 if(denominator.isRational() && 1 == denominator.getRational()) 01980 e.setType(numerator.getType()); 01981 else 01982 e.setType(d_realType); 01983 break; 01984 } 01985 case LT: 01986 case LE: 01987 case GT: 01988 case GE: 01989 case GRAY_SHADOW: 01990 // Need to know types for all exprs -Clark 01991 // e.setType(boolType()); 01992 // break; 01993 case DARK_SHADOW: 01994 for (int k = 0; k < e.arity(); ++k) { 01995 if (d_realType != getBaseType(e[k])) 01996 throw TypecheckException("Expecting type REAL with `" + 01997 getEM()->getKindName(e.getKind()) + "',\n"+ 01998 "but got a " + getBaseType(e[k]).toString()+ 01999 " for:\n" + e.toString()); 02000 } 02001 02002 e.setType(boolType()); 02003 break; 02004 case IS_INTEGER: 02005 if(d_realType != getBaseType(e[0])) 02006 throw TypecheckException("Expected type REAL, but got " 02007 +getBaseType(e[0]).toString() 02008 +"\n\nExpr = "+e.toString()); 02009 e.setType(boolType()); 02010 break; 02011 default: 02012 DebugAssert(false,"TheoryArithNew::computeType: unexpected expression:\n " 02013 +e.toString()); 02014 break; 02015 } 02016 } 02017 02018 Type TheoryArithNew::computeBaseType(const Type& t) { 02019 IF_DEBUG(int kind = t.getExpr().getKind();) 02020 DebugAssert(kind==INT || kind==REAL || kind==SUBRANGE, 02021 "TheoryArithNew::computeBaseType("+t.toString()+")"); 02022 return realType(); 02023 } 02024 02025 Expr TheoryArithNew::computeTCC(const Expr& e) { 02026 Expr tcc(Theory::computeTCC(e)); 02027 switch(e.getKind()) { 02028 case DIVIDE: 02029 DebugAssert(e.arity() == 2, ""); 02030 return tcc.andExpr(!(e[1].eqExpr(rat(0)))); 02031 default: 02032 return tcc; 02033 } 02034 } 02035 02036 /////////////////////////////////////////////////////////////////////////////// 02037 //parseExprOp: 02038 //translating special Exprs to regular EXPR?? 02039 /////////////////////////////////////////////////////////////////////////////// 02040 Expr TheoryArithNew::parseExprOp(const Expr& e) { 02041 TRACE("parser", "TheoryArithNew::parseExprOp(", e, ")"); 02042 //std::cout << "Were here"; 02043 // If the expression is not a list, it must have been already 02044 // parsed, so just return it as is. 02045 switch(e.getKind()) { 02046 case ID: { 02047 int kind = getEM()->getKind(e[0].getString()); 02048 switch(kind) { 02049 case NULL_KIND: return e; // nothing to do 02050 case REAL: 02051 case INT: 02052 case NEGINF: 02053 case POSINF: return getEM()->newLeafExpr(kind); 02054 default: 02055 DebugAssert(false, "Bad use of bare keyword: "+e.toString()); 02056 return e; 02057 } 02058 } 02059 case RAW_LIST: break; // break out of switch, do the hard work 02060 default: 02061 return e; 02062 } 02063 02064 DebugAssert(e.getKind() == RAW_LIST && e.arity() > 0, 02065 "TheoryArithNew::parseExprOp:\n e = "+e.toString()); 02066 02067 const Expr& c1 = e[0][0]; 02068 int kind = getEM()->getKind(c1.getString()); 02069 switch(kind) { 02070 case UMINUS: { 02071 if(e.arity() != 2) 02072 throw ParserException("UMINUS requires exactly one argument: " 02073 +e.toString()); 02074 return uminusExpr(parseExpr(e[1])); 02075 } 02076 case PLUS: { 02077 vector<Expr> k; 02078 Expr::iterator i = e.begin(), iend=e.end(); 02079 // Skip first element of the vector of kids in 'e'. 02080 // The first element is the operator. 02081 ++i; 02082 // Parse the kids of e and push them into the vector 'k' 02083 for(; i!=iend; ++i) k.push_back(parseExpr(*i)); 02084 return plusExpr(k); 02085 } 02086 case MINUS: { 02087 if(e.arity() == 2) 02088 return uminusExpr(parseExpr(e[1])); 02089 else if(e.arity() == 3) 02090 return minusExpr(parseExpr(e[1]), parseExpr(e[2])); 02091 else 02092 throw ParserException("MINUS requires one or two arguments:" 02093 +e.toString()); 02094 } 02095 case MULT: { 02096 vector<Expr> k; 02097 Expr::iterator i = e.begin(), iend=e.end(); 02098 // Skip first element of the vector of kids in 'e'. 02099 // The first element is the operator. 02100 ++i; 02101 // Parse the kids of e and push them into the vector 'k' 02102 for(; i!=iend; ++i) k.push_back(parseExpr(*i)); 02103 return multExpr(k); 02104 } 02105 case POW: { 02106 return powExpr(parseExpr(e[1]), parseExpr(e[2])); 02107 } 02108 case DIVIDE: 02109 { return divideExpr(parseExpr(e[1]), parseExpr(e[2])); } 02110 case LT: 02111 { return ltExpr(parseExpr(e[1]), parseExpr(e[2])); } 02112 case LE: 02113 { return leExpr(parseExpr(e[1]), parseExpr(e[2])); } 02114 case GT: 02115 { return gtExpr(parseExpr(e[1]), parseExpr(e[2])); } 02116 case GE: 02117 { return geExpr(parseExpr(e[1]), parseExpr(e[2])); } 02118 case INTDIV: 02119 case MOD: 02120 case SUBRANGE: { 02121 vector<Expr> k; 02122 Expr::iterator i = e.begin(), iend=e.end(); 02123 // Skip first element of the vector of kids in 'e'. 02124 // The first element is the operator. 02125 ++i; 02126 // Parse the kids of e and push them into the vector 'k' 02127 for(; i!=iend; ++i) 02128 k.push_back(parseExpr(*i)); 02129 return Expr(kind, k, e.getEM()); 02130 } 02131 case IS_INTEGER: { 02132 if(e.arity() != 2) 02133 throw ParserException("IS_INTEGER requires exactly one argument: " 02134 +e.toString()); 02135 return Expr(IS_INTEGER, parseExpr(e[1])); 02136 } 02137 default: 02138 DebugAssert(false, 02139 "TheoryArithNew::parseExprOp: invalid input " + e.toString()); 02140 break; 02141 } 02142 return e; 02143 } 02144 02145 /////////////////////////////////////////////////////////////////////////////// 02146 // Pretty-printing // 02147 /////////////////////////////////////////////////////////////////////////////// 02148 02149 02150 ExprStream& TheoryArithNew::print(ExprStream& os, const Expr& e) { 02151 switch(os.lang()) { 02152 case SIMPLIFY_LANG: 02153 switch(e.getKind()) { 02154 case RATIONAL_EXPR: 02155 e.print(os); 02156 break; 02157 case SUBRANGE: 02158 os <<"ERROR:SUBRANGE:not supported in Simplify\n"; 02159 break; 02160 case IS_INTEGER: 02161 os <<"ERROR:IS_INTEGER:not supported in Simplify\n"; 02162 break; 02163 case PLUS: { 02164 int i=0, iend=e.arity(); 02165 os << "(+ "; 02166 if(i!=iend) os << e[i]; 02167 ++i; 02168 for(; i!=iend; ++i) os << " " << e[i]; 02169 os << ")"; 02170 break; 02171 } 02172 case MINUS: 02173 os << "(- " << e[0] << " " << e[1]<< ")"; 02174 break; 02175 case UMINUS: 02176 os << "-" << e[0] ; 02177 break; 02178 case MULT: { 02179 int i=0, iend=e.arity(); 02180 os << "(* " ; 02181 if(i!=iend) os << e[i]; 02182 ++i; 02183 for(; i!=iend; ++i) os << " " << e[i]; 02184 os << ")"; 02185 break; 02186 } 02187 case POW: 02188 os << "(" << push << e[1] << space << "^ " << e[0] << push << ")"; 02189 break; 02190 case DIVIDE: 02191 os << "(" << push << e[0] << space << "/ " << e[1] << push << ")"; 02192 break; 02193 case LT: 02194 if (isInt(e[0].getType()) || isInt(e[1].getType())) { 02195 } 02196 os << "(< " << e[0] << " " << e[1] <<")"; 02197 break; 02198 case LE: 02199 os << "(<= " << e[0] << " " << e[1] << ")"; 02200 break; 02201 case GT: 02202 os << "(> " << e[0] << " " << e[1] << ")"; 02203 break; 02204 case GE: 02205 os << "(>= " << e[0] << " " << e[1] << ")"; 02206 break; 02207 case DARK_SHADOW: 02208 case GRAY_SHADOW: 02209 os <<"ERROR:SHADOW:not supported in Simplify\n"; 02210 break; 02211 default: 02212 // Print the top node in the default LISP format, continue with 02213 // pretty-printing for children. 02214 e.print(os); 02215 02216 break; 02217 } 02218 break; // end of case SIMPLIFY_LANG 02219 02220 02221 case TPTP_LANG: 02222 switch(e.getKind()) { 02223 case RATIONAL_EXPR: 02224 e.print(os); 02225 break; 02226 case SUBRANGE: 02227 os <<"ERROR:SUBRANGE:not supported in TPTP\n"; 02228 break; 02229 case IS_INTEGER: 02230 os <<"ERROR:IS_INTEGER:not supported in TPTP\n"; 02231 break; 02232 case PLUS: { 02233 if(!isInteger(e[0])){ 02234 os<<"ERRPR:plus only supports inteters now in TPTP\n"; 02235 break; 02236 } 02237 02238 int i=0, iend=e.arity(); 02239 if(iend <=1){ 02240 os<<"ERROR,plus must have more than two numbers in TPTP\n"; 02241 break; 02242 } 02243 02244 for(i=0; i <= iend-2; ++i){ 02245 os << "$plus_int("; 02246 os << e[i] << ","; 02247 } 02248 02249 os<< e[iend-1]; 02250 02251 for(i=0 ; i <= iend-2; ++i){ 02252 os << ")"; 02253 } 02254 02255 break; 02256 } 02257 case MINUS: 02258 os << "(- " << e[0] << " " << e[1]<< ")"; 02259 break; 02260 case UMINUS: 02261 os << "-" << e[0] ; 02262 break; 02263 case MULT: { 02264 int i=0, iend=e.arity(); 02265 os << "(* " ; 02266 if(i!=iend) os << e[i]; 02267 ++i; 02268 for(; i!=iend; ++i) os << " " << e[i]; 02269 os << ")"; 02270 break; 02271 } 02272 case POW: 02273 os << "(" << push << e[1] << space << "^ " << e[0] << push << ")"; 02274 break; 02275 case DIVIDE: 02276 os << "(" << push << e[0] << space << "/ " << e[1] << push << ")"; 02277 break; 02278 case LT: 02279 if (isInt(e[0].getType()) || isInt(e[1].getType())) { 02280 } 02281 os << "(< " << e[0] << " " << e[1] <<")"; 02282 break; 02283 case LE: 02284 os << "(<= " << e[0] << " " << e[1] << ")"; 02285 break; 02286 case GT: 02287 os << "(> " << e[0] << " " << e[1] << ")"; 02288 break; 02289 case GE: 02290 os << "(>= " << e[0] << " " << e[1] << ")"; 02291 break; 02292 case DARK_SHADOW: 02293 case GRAY_SHADOW: 02294 os <<"ERROR:SHADOW:not supported in TPTP\n"; 02295 break; 02296 default: 02297 // Print the top node in the default LISP format, continue with 02298 // pretty-printing for children. 02299 e.print(os); 02300 02301 break; 02302 } 02303 break; // end of case TPTP_LANG 02304 02305 02306 case PRESENTATION_LANG: 02307 switch(e.getKind()) { 02308 case REAL: 02309 case INT: 02310 case RATIONAL_EXPR: 02311 case NEGINF: 02312 case POSINF: 02313 e.print(os); 02314 break; 02315 case SUBRANGE: 02316 if(e.arity() != 2) e.printAST(os); 02317 else 02318 os << "[" << push << e[0] << ".." << e[1] << push << "]"; 02319 break; 02320 case IS_INTEGER: 02321 if(e.arity() == 1) 02322 os << "IS_INTEGER(" << push << e[0] << push << ")"; 02323 else 02324 e.printAST(os); 02325 break; 02326 case PLUS: { 02327 int i=0, iend=e.arity(); 02328 os << "(" << push; 02329 if(i!=iend) os << e[i]; 02330 ++i; 02331 for(; i!=iend; ++i) os << space << "+ " << e[i]; 02332 os << push << ")"; 02333 break; 02334 } 02335 case MINUS: 02336 os << "(" << push << e[0] << space << "- " << e[1] << push << ")"; 02337 break; 02338 case UMINUS: 02339 os << "-(" << push << e[0] << push << ")"; 02340 break; 02341 case MULT: { 02342 int i=0, iend=e.arity(); 02343 os << "(" << push; 02344 if(i!=iend) os << e[i]; 02345 ++i; 02346 for(; i!=iend; ++i) os << space << "* " << e[i]; 02347 os << push << ")"; 02348 break; 02349 } 02350 case POW: 02351 os << "(" << push << e[1] << space << "^ " << e[0] << push << ")"; 02352 break; 02353 case DIVIDE: 02354 os << "(" << push << e[0] << space << "/ " << e[1] << push << ")"; 02355 break; 02356 case LT: 02357 if (isInt(e[0].getType()) || isInt(e[1].getType())) { 02358 } 02359 os << "(" << push << e[0] << space << "< " << e[1] << push << ")"; 02360 break; 02361 case LE: 02362 os << "(" << push << e[0] << space << "<= " << e[1] << push << ")"; 02363 break; 02364 case GT: 02365 os << "(" << push << e[0] << space << "> " << e[1] << push << ")"; 02366 break; 02367 case GE: 02368 os << "(" << push << e[0] << space << ">= " << e[1] << push << ")"; 02369 break; 02370 case DARK_SHADOW: 02371 os << "DARK_SHADOW(" << push << e[0] << ", " << space << e[1] << push << ")"; 02372 break; 02373 case GRAY_SHADOW: 02374 os << "GRAY_SHADOW(" << push << e[0] << "," << space << e[1] 02375 << "," << space << e[2] << "," << space << e[3] << push << ")"; 02376 break; 02377 default: 02378 // Print the top node in the default LISP format, continue with 02379 // pretty-printing for children. 02380 e.printAST(os); 02381 02382 break; 02383 } 02384 break; // end of case PRESENTATION_LANG 02385 case SMTLIB_LANG: 02386 case SMTLIB_V2_LANG: { 02387 switch(e.getKind()) { 02388 case REAL_CONST: 02389 printRational(os, e[0].getRational(), true); 02390 break; 02391 case RATIONAL_EXPR: 02392 printRational(os, e.getRational()); 02393 break; 02394 case REAL: 02395 os << "Real"; 02396 break; 02397 case INT: 02398 os << "Int"; 02399 break; 02400 case SUBRANGE: 02401 throw SmtlibException("TheoryArithNew::print: SMTLIB: SUBRANGE not implemented"); 02402 // if(e.arity() != 2) e.print(os); 02403 // else 02404 // os << "(" << push << "SUBRANGE" << space << e[0] 02405 // << space << e[1] << push << ")"; 02406 break; 02407 case IS_INTEGER: 02408 if(e.arity() == 1) 02409 os << "(" << push << "IsInt" << space << e[0] << push << ")"; 02410 else 02411 throw SmtlibException("TheoryArithNew::print: SMTLIB: IS_INTEGER used unexpectedly"); 02412 break; 02413 case PLUS: { 02414 if(e.arity() == 1 && os.lang() == SMTLIB_V2_LANG) { 02415 os << e[0]; 02416 } else { 02417 os << "(" << push << "+"; 02418 Expr::iterator i = e.begin(), iend = e.end(); 02419 for(; i!=iend; ++i) { 02420 os << space << (*i); 02421 } 02422 os << push << ")"; 02423 } 02424 break; 02425 } 02426 case MINUS: { 02427 os << "(" << push << "- " << e[0] << space << e[1] << push << ")"; 02428 break; 02429 } 02430 case UMINUS: { 02431 os << "(" << push << "-" << space << e[0] << push << ")"; 02432 break; 02433 } 02434 case MULT: { 02435 int i=0, iend=e.arity(); 02436 if(iend == 1 && os.lang() == SMTLIB_V2_LANG) { 02437 os << e[0]; 02438 } else { 02439 for(; i!=iend; ++i) { 02440 if (i < iend-1) { 02441 os << "(" << push << "*"; 02442 } 02443 os << space << e[i]; 02444 } 02445 for (i=0; i < iend-1; ++i) os << push << ")"; 02446 } 02447 break; 02448 } 02449 case POW: 02450 throw SmtlibException("TheoryArithNew::print: SMTLIB: POW not supported"); 02451 // os << "(" << push << "^ " << e[1] << space << e[0] << push << ")"; 02452 break; 02453 case DIVIDE: { 02454 throw SmtlibException("TheoryArithNew::print: SMTLIB: unexpected use of DIVIDE"); 02455 break; 02456 } 02457 case LT: { 02458 Rational r; 02459 os << "(" << push << "<" << space; 02460 os << e[0] << space << e[1] << push << ")"; 02461 break; 02462 } 02463 case LE: { 02464 Rational r; 02465 os << "(" << push << "<=" << space; 02466 os << e[0] << space << e[1] << push << ")"; 02467 break; 02468 } 02469 case GT: { 02470 Rational r; 02471 os << "(" << push << ">" << space; 02472 os << e[0] << space << e[1] << push << ")"; 02473 break; 02474 } 02475 case GE: { 02476 Rational r; 02477 os << "(" << push << ">=" << space; 02478 os << e[0] << space << e[1] << push << ")"; 02479 break; 02480 } 02481 case DARK_SHADOW: 02482 throw SmtlibException("TheoryArithNew::print: SMTLIB: DARK_SHADOW not supported"); 02483 os << "(" << push << "DARK_SHADOW" << space << e[0] 02484 << space << e[1] << push << ")"; 02485 break; 02486 case GRAY_SHADOW: 02487 throw SmtlibException("TheoryArithNew::print: SMTLIB: GRAY_SHADOW not supported"); 02488 os << "GRAY_SHADOW(" << push << e[0] << "," << space << e[1] 02489 << "," << space << e[2] << "," << space << e[3] << push << ")"; 02490 break; 02491 default: 02492 throw SmtlibException("TheoryArithNew::print: SMTLIB: default not supported"); 02493 // Print the top node in the default LISP format, continue with 02494 // pretty-printing for children. 02495 e.printAST(os); 02496 02497 break; 02498 } 02499 break; // end of case SMTLIB_LANG 02500 } 02501 case LISP_LANG: 02502 switch(e.getKind()) { 02503 case REAL: 02504 case INT: 02505 case RATIONAL_EXPR: 02506 case NEGINF: 02507 case POSINF: 02508 e.print(os); 02509 break; 02510 case SUBRANGE: 02511 if(e.arity() != 2) e.printAST(os); 02512 else 02513 os << "(" << push << "SUBRANGE" << space << e[0] 02514 << space << e[1] << push << ")"; 02515 break; 02516 case IS_INTEGER: 02517 if(e.arity() == 1) 02518 os << "(" << push << "IS_INTEGER" << space << e[0] << push << ")"; 02519 else 02520 e.printAST(os); 02521 break; 02522 case PLUS: { 02523 int i=0, iend=e.arity(); 02524 os << "(" << push << "+"; 02525 for(; i!=iend; ++i) os << space << e[i]; 02526 os << push << ")"; 02527 break; 02528 } 02529 case MINUS: 02530 //os << "(" << push << e[0] << space << "- " << e[1] << push << ")"; 02531 os << "(" << push << "- " << e[0] << space << e[1] << push << ")"; 02532 break; 02533 case UMINUS: 02534 os << "(" << push << "-" << space << e[0] << push << ")"; 02535 break; 02536 case MULT: { 02537 int i=0, iend=e.arity(); 02538 os << "(" << push << "*"; 02539 for(; i!=iend; ++i) os << space << e[i]; 02540 os << push << ")"; 02541 break; 02542 } 02543 case POW: 02544 os << "(" << push << "^ " << e[1] << space << e[0] << push << ")"; 02545 break; 02546 case DIVIDE: 02547 os << "(" << push << "/ " << e[0] << space << e[1] << push << ")"; 02548 break; 02549 case LT: 02550 os << "(" << push << "< " << e[0] << space << e[1] << push << ")"; 02551 break; 02552 case LE: 02553 os << "(" << push << "<= " << e[0] << space << e[1] << push << ")"; 02554 break; 02555 case GT: 02556 os << "(" << push << "> " << e[1] << space << e[0] << push << ")"; 02557 break; 02558 case GE: 02559 os << "(" << push << ">= " << e[0] << space << e[1] << push << ")"; 02560 break; 02561 case DARK_SHADOW: 02562 os << "(" << push << "DARK_SHADOW" << space << e[0] 02563 << space << e[1] << push << ")"; 02564 break; 02565 case GRAY_SHADOW: 02566 os << "(" << push << "GRAY_SHADOW" << space << e[0] << space 02567 << e[1] << space << e[2] << space << e[3] << push << ")"; 02568 break; 02569 default: 02570 // Print the top node in the default LISP format, continue with 02571 // pretty-printing for children. 02572 e.printAST(os); 02573 02574 break; 02575 } 02576 break; // end of case LISP_LANG 02577 default: 02578 // Print the top node in the default LISP format, continue with 02579 // pretty-printing for children. 02580 e.printAST(os); 02581 } 02582 return os; 02583 } 02584 02585 /////////////////////////////////////////////////////////////////////////////// 02586 // SIMPLEX SOLVER // 02587 /////////////////////////////////////////////////////////////////////////////// 02588 02589 bool TheoryArithNew::isBasic(const Expr& x) const { 02590 // If it is on the right side of the tableaux the it is basic, non-basic otherwise 02591 return (tableaux.find(x) != tableaux.end()); 02592 } 02593 02594 void TheoryArithNew::pivot(const Expr& x_r, const Expr& x_s) { 02595 02596 // Check that the variable is non-basic 02597 DebugAssert(isBasic(x_r), "TheoryArithNew::pivot, given variable should be basic" + x_r.toString()); 02598 DebugAssert(!isBasic(x_s), "TheoryArithNew::pivot, given variable should be non-basic" + x_s.toString()); 02599 02600 // If trace is on for the simplex, print it out 02601 TRACE("simplex", "TheoryArithNew::pivot(", x_r.toString() + ", " + x_s.toString(), ")"); 02602 02603 // Get the iterator that points to the expression of x_r 02604 TebleauxMap::iterator it = tableaux.find(x_r); 02605 02606 // Get the expresiion of x_r 02607 Theorem x_r_Theorem = (*it).second; 02608 02609 // Erase the x_r expression from the tableaux 02610 tableaux.erase(x_r); // TODO: Add erase by iterator to ExprHashMap 02611 02612 // Update the dependencies 02613 updateDependenciesRemove(x_r, x_r_Theorem.getExpr()[1]); 02614 02615 // Construct the expresison (theorem) of x_s 02616 const Theorem& x_s_Theorem = pivotRule(x_r_Theorem, x_s); 02617 02618 // Replace all occurances of x_s with x_s_Expression 02619 substAndCanonizeTableaux(x_s_Theorem); 02620 02621 // Update the dependencies 02622 updateDependenciesAdd(x_s, x_s_Theorem.getExpr()[1]); 02623 02624 // Add the expression of x_s to the map 02625 tableaux[x_s] = x_s_Theorem; 02626 } 02627 02628 void TheoryArithNew::update(const Expr& x_i, const EpsRational& v) { 02629 02630 // Check that the variable is non-basic 02631 DebugAssert(tableaux.find(x_i) == tableaux.end(), "TheoryArithNew::update, given variable should be non-basic" + x_i.toString()); 02632 02633 // If trace is on for the simplex, print it out 02634 TRACE("simplex", "TheoryArithNew::update(", x_i.toString() + ", " + v.toString(), ")"); 02635 02636 // Remember the value of the x_i variable 02637 EpsRational old_value = getBeta(x_i); 02638 02639 // If there are dependent variables then do the work 02640 DependenciesMap::iterator find = dependenciesMap.find(x_i); 02641 if (find != dependenciesMap.end()) { 02642 02643 // Go through all the variables that depend on x_i 02644 const set<Expr>& dependent = (*find).second; 02645 set<Expr>::const_iterator it = dependent.begin(); 02646 set<Expr>::const_iterator it_end = dependent.end(); 02647 // Fix the values of all the variables 02648 while (it != it_end) { 02649 02650 // Get the current variable 02651 const Expr& x_j = *it; 02652 02653 // Get the tableaux coefficient of the of x_i in the row of x_j (the right side ofg the tableaux expression) 02654 const Rational& a_ji = getTableauxEntry(x_j, x_i); 02655 02656 // Update the beta valuation 02657 EpsRational b(getBeta(x_j)); // TODO: not necessary, beta's are all setup now 02658 EpsRational x_j_new = beta[x_j] = b + (v - old_value) * a_ji; 02659 02660 // Check if the variable is sat or unsat under the new assignment 02661 if (x_j_new < getLowerBound(x_j) || getUpperBound(x_j) < x_j_new) 02662 unsatBasicVariables.insert(x_j); 02663 else 02664 unsatBasicVariables.erase(x_j); 02665 02666 // Go to the next one 02667 it ++; 02668 } 02669 } 02670 02671 // Set the new value to x_i (x_i) is non_basic, no need to add to unsat set) 02672 beta[x_i] = v; 02673 } 02674 02675 void TheoryArithNew::pivotAndUpdate(const Expr& x_i, const Expr& x_j, const EpsRational& v) { 02676 02677 // Variable x_i should be a basic variable (left side of the tableaux) and x_j should be non_basic 02678 DebugAssert(tableaux.find(x_i) != tableaux.end(), "TheoryArithNew::pivotAndUpdate, " + x_i.toString() + " should be a basic variable"); 02679 DebugAssert(tableaux.find(x_j) == tableaux.end(), "TheoryArithNew::pivotAndUpdate, " + x_j.toString() + " should be a non-basic variable"); 02680 02681 // If trace is on for the simplex, print it out 02682 TRACE("simplex", "TheoryArithNew::pivotAndUpdate(", x_i.toString() + ", " + x_j.toString() + ", " + v.toString(), ")"); 02683 02684 // The a_ij coefficient of the tableaux 02685 const Rational& a_ij = getTableauxEntry(x_i, x_j); 02686 02687 // Let theta be the adjustment coefficient 02688 EpsRational theta((v - getBeta(x_i))/a_ij); 02689 02690 // Set the new value to x_i (x_i becomes non-basic, hance sat) 02691 beta[x_i] = v; 02692 // x_i becomes non-basic, no need ==> it is sat 02693 unsatBasicVariables.erase(x_i); 02694 02695 // Set the new value to x_j 02696 EpsRational b = getBeta(x_j); 02697 EpsRational new_x_j = beta[x_j] = b + theta; 02698 02699 // Check if the variable is sat or unsat under the new assignment 02700 if (new_x_j < getLowerBound(x_j) || getUpperBound(x_j) < new_x_j) 02701 unsatBasicVariables.insert(x_j); 02702 else 02703 unsatBasicVariables.erase(x_j); 02704 02705 // Go through all the variables that depend on x_j, and update their value (there will be at least one, i.e. x_i) // TODO: maybe optimise 02706 const set<Expr>& dependent = (*dependenciesMap.find(x_j)).second; 02707 set<Expr>::const_iterator it = dependent.begin(); 02708 set<Expr>::const_iterator it_end = dependent.end(); 02709 // Go throught all the basic variables 02710 while (it != it_end) { 02711 02712 // Get the current variable 02713 const Expr& x_k = *it; 02714 02715 // If the basic variable is different from x_i update its value 02716 if (x_k != x_i) { 02717 02718 // Get the a_kj coefficient from the tableaux 02719 const Rational& a_kj = getTableauxEntry(x_k, x_j); 02720 02721 // Adjust the value (check fort sat/unsat, x_k is basic) 02722 b = getBeta(x_k); 02723 EpsRational x_k_new = beta[x_k] = b + theta * a_kj; 02724 02725 // Check if the variable is sat or unsat under the new assignment 02726 if (x_k_new < getLowerBound(x_k) || getUpperBound(x_k) < x_k_new) 02727 unsatBasicVariables.insert(x_k); 02728 else 02729 unsatBasicVariables.erase(x_k); 02730 } 02731 02732 // Go to the next one 02733 it ++; 02734 } 02735 02736 // Last thing to do, pivot x_i and x_j 02737 pivot(x_i, x_j); 02738 } 02739 02740 QueryResult TheoryArithNew::assertUpper(const Expr& x_i, const EpsRational& c, const Theorem& thm) { 02741 02742 // If trace is on for the simplex, print it out 02743 TRACE("simplex", "TheoryArithNew::assertUpper(", x_i.toString() + ", " + c.toString(), ")"); 02744 02745 // Check if the given expression is actually a variable 02746 DebugAssert(isLeaf(x_i), "TheoryArithNew::assertUpper wrong kind, expected an arithmetic leaf (variable) got " + x_i.toString()); 02747 02748 // Check if the upper bound is worse then the last one 02749 if (getUpperBound(x_i) <= c) return (consistent == UNKNOWN? UNKNOWN : SATISFIABLE); 02750 02751 // If the new bound is lower then the lower bound */ 02752 if (c < getLowerBound(x_i)) { 02753 // Create the explaining theorem 02754 explanation = d_rules->clashingBounds(getLowerBoundThm(x_i), thm); 02755 // Return unsatisfiable 02756 return UNSATISFIABLE; 02757 } 02758 02759 // Since it is a tighter bound, propagate what can be 02760 propagate = true; 02761 02762 // Set the new upper bound */ 02763 upperBound[x_i] = BoundInfo(c, thm); 02764 02765 // If within the new bounds, return the previous state 02766 if (getBeta(x_i) <= c) return (consistent == UNKNOWN? UNKNOWN : SATISFIABLE); 02767 02768 // Otherwise, if the variable is non-basic then update it's value 02769 if (!isBasic(x_i)) update(x_i, c); 02770 // Else its basic, and non-sat, add to the unsat set 02771 else unsatBasicVariables.insert(x_i); 02772 02773 // Everything went fine, return OK (not complete, means not UNSAT) 02774 return UNKNOWN; 02775 } 02776 02777 QueryResult TheoryArithNew::assertLower(const Expr& x_i, const EpsRational& c, const Theorem& thm) { 02778 02779 // Check if the given expression is actually a variable 02780 DebugAssert(isLeaf(x_i), "TheoryArithNew::assertLower wrong kind, expected an arithmetic leaf (variable) got " + x_i.toString()); 02781 02782 // If trace is on for the simplex, print it out 02783 TRACE("simplex", "TheoryArithNew::assertLower(", x_i.toString() + ", " + c.toString(), ")"); 02784 02785 // Check if the upper bound is worse then the last one 02786 if (c <= getLowerBound(x_i)) return (consistent == UNKNOWN? UNKNOWN : SATISFIABLE); 02787 02788 // Since it is a tighter bound, propagate what can be 02789 propagate = true; 02790 02791 // If the new bound is lower then the bound */ 02792 if (c > getUpperBound(x_i)) { 02793 // Create the explaining theorem 02794 explanation = d_rules->clashingBounds(thm, getUpperBoundThm(x_i)); 02795 // Return unsatisfiable 02796 return UNSATISFIABLE; 02797 } 02798 02799 // Set the new upper bound */ 02800 lowerBound[x_i] = BoundInfo(c, thm); 02801 02802 // If within the new bounds, return the previous state 02803 if (c <= getBeta(x_i)) return (consistent == UNKNOWN? UNKNOWN : SATISFIABLE); 02804 02805 // Otherwise, if the variable is non-basic then update it's value 02806 if (!isBasic(x_i)) update(x_i, c); 02807 // Else its basic, and non-sat, add to the unsat set 02808 else unsatBasicVariables.insert(x_i); 02809 02810 // Everything went fine, return OK (not complete, means not UNSAT) 02811 return UNKNOWN; 02812 } 02813 02814 QueryResult TheoryArithNew::assertEqual(const Expr& x_i, const EpsRational& c, const Theorem& thm) { 02815 02816 // Assert the upper bound 02817 consistent = assertUpper(x_i, c, thm); // TODO: thm: = |- <= 02818 02819 // If the return value is UNSAT return UNSAT 02820 if (consistent == UNSATISFIABLE) return UNSATISFIABLE; 02821 02822 // Assert the lower bound 02823 consistent = assertLower(x_i, c, thm); // TODO: thm: = |- >= 02824 02825 // Return the consistency 02826 return consistent; 02827 } 02828 02829 02830 void TheoryArithNew::checkSat(bool fullEffort) 02831 { 02832 // We should not be here if inconsistent 02833 DebugAssert(consistent != UNSATISFIABLE, "TheoryArithNew::checkSat : we are UNSAT before entering?!?!"); 02834 02835 // Trace the check sat if simplex flag is on 02836 TRACE("simplex", "TheoryArithNew::checkSat(fullEffort=",fullEffort? "true" : "false", ")"); 02837 02838 // Check if by backtracking we have more fresh variables than we expect 02839 if (assertedExprCount < assertedExpr.size()) 02840 updateFreshVariables(); 02841 02842 // Do the simplex search if the database is not satisfiable (if inconsistent, we will not be here); 02843 if (consistent != SATISFIABLE || fullEffort) 02844 consistent = checkSatSimplex(); 02845 02846 // If the result is inconsistent set the inconsistent flag 02847 if (consistent == UNSATISFIABLE) 02848 setInconsistent(explanation); 02849 02850 // If we are not - consistent, check the integer satisfiability 02851 // if (consistent == SATISFIABLE) { 02852 // // If we asserted a lemma and it hasn't been processed yet, we just don't do anything 02853 // Theorem integer_lemma_thm = integer_lemma; 02854 // if (!integer_lemma_thm.isNull()) { 02855 // if (simplify(integer_lemma_thm.getExpr()).getRHS() == getEM()->trueExpr()) 02856 // consistent = checkSatInteger(); 02857 // else 02858 // consistent = UNKNOWN; 02859 // } else 02860 // // Lemma was not asserted, check integer sat 02861 // consistent = checkSatInteger(); 02862 // } 02863 02864 // Trace the check sat if simplex flag is on 02865 TRACE("simplex", "TheoryArithNew::checkSat ==> ", consistent == UNSATISFIABLE? "UNSATISFIABLE" : "SATISFIABLE", ""); 02866 } 02867 02868 QueryResult TheoryArithNew::checkSatInteger() { 02869 02870 // Trace the check sat if simplex flag is on 02871 TRACE("simplex", "TheoryArithNew::checkSatInteger()", "", ""); 02872 02873 // At this point we are REAL satisfiable, so we have to check the integers 02874 set<Expr>::iterator x_i_it = intVariables.begin(); 02875 set<Expr>::iterator x_i_it_end = intVariables.end(); 02876 // cerr << "Integer vars: "; 02877 // while (x_i_it != x_i_it_end) { 02878 // cerr << *x_i_it << " "; 02879 // ++ x_i_it; 02880 // } 02881 // cerr << endl; 02882 // 02883 // x_i_it = intVariables.begin(); 02884 // x_i_it_end = intVariables.end(); 02885 while (x_i_it != x_i_it_end) { 02886 02887 // Get the left-hand variable of the tableaux 02888 const Expr& x_i = (*x_i_it); 02889 02890 // Only do work for unsat integer variables 02891 if (isInteger(x_i)) { 02892 02893 // Get the current assignment of x_i 02894 const EpsRational& beta = getBeta(x_i); 02895 02896 // Check if it is an integer 02897 if (beta.isInteger()) { ++ x_i_it; continue; } 02898 02899 // Since the variable is not an integer, split on it being <= [beta] and >= [beta] + 1 02900 integer_lemma = d_rules->integerSplit(x_i, beta.getFloor()); 02901 TRACE("integer", "TheoryArithNew::checkSatInteger ==> lemma : ", integer_lemma, ""); 02902 enqueueFact(integer_lemma); 02903 02904 // One split should be enough, return unknown 02905 return UNKNOWN; 02906 } 02907 02908 // Go to the next row 02909 ++ x_i_it; 02910 } 02911 02912 // We came through, huh, we are sat 02913 return SATISFIABLE; 02914 } 02915 02916 QueryResult TheoryArithNew::checkSatSimplex() { 02917 02918 Expr x_i; // The basic variable we will use 02919 EpsRational x_i_Value; // The current value of the variable x_i 02920 Expr x_j; // The non-basic variable we will use 02921 EpsRational x_j_Value; // The current value of the variable x_j 02922 Rational a_ij; // The coefficient wwhen expanding x_i using x_j in the tableaux 02923 02924 bool x_j_Found; // Did we find a suitable one 02925 EpsRational l_i; // Lower bound of x_i 02926 EpsRational u_i; // Upper bound of x_i 02927 02928 // Trace the size of the tableaux and the unsat 02929 TRACE("arith_atoms", "Tableaux size: ", tableaux.size(), ""); 02930 TRACE("arith_atoms", "UNSAT vars: ", unsatBasicVariables.size(), ""); 02931 02932 // The main loop 02933 while (unsatBasicVariables.size()) { 02934 02935 // The first unsat variable information 02936 x_i = *unsatBasicVariables.begin(); 02937 TebleauxMap::iterator it = tableaux.find(x_i); 02938 x_i_Value = getBeta(x_i); 02939 l_i = getLowerBound(x_i); 02940 u_i = getUpperBound(x_i); 02941 02942 // If the variable doesn't obey the lower bound 02943 if (l_i > x_i_Value) { 02944 02945 // Did we find a suitable x_j, NOT YET 02946 x_j_Found = false; 02947 02948 // Find the smalles non-basic x_j that can improve x_i 02949 const Expr& x_i_RightSide = (*it).second.getExpr()[1]; 02950 int non_basics_i_end = x_i_RightSide.arity(); 02951 for(int non_basics_i = 0; non_basics_i < non_basics_i_end; ++ non_basics_i) { 02952 02953 // Get the info on the current variable 02954 x_j = x_i_RightSide[non_basics_i][1]; 02955 a_ij = x_i_RightSide[non_basics_i][0].getRational(); 02956 x_j_Value = getBeta(x_j); 02957 02958 // If there is slack for improving x_i using x_j then do it 02959 if (a_ij > 0) { 02960 if (x_j_Value < getUpperBound(x_j)) { 02961 x_j_Found = true; 02962 break; 02963 } 02964 } else { 02965 if (x_j_Value > getLowerBound(x_j)) { 02966 x_j_Found = true; 02967 break; 02968 } 02969 } 02970 } 02971 02972 // If none of the variables allows for slack, the tableaux is unsatisfiable 02973 if (!x_j_Found) { 02974 // Generate the explanation 02975 explanation = getLowerBoundExplanation(it); 02976 // Return unsat 02977 return UNSATISFIABLE; 02978 } 02979 02980 // Otherwise do pivotAndUpdate and continue with the loop 02981 pivotAndUpdate(x_i, x_j, l_i); 02982 } else 02983 // If the variable doesn't obey the upper bound 02984 if (x_i_Value > u_i) { 02985 02986 // Did we find a suitable x_j, NOT YET 02987 x_j_Found = false; 02988 02989 // Find the smalles non-basic x_j that can improve x_i 02990 const Expr& x_i_RightSide = (*it).second.getExpr()[1]; 02991 int non_basics_i_end = x_i_RightSide.arity(); 02992 for(int non_basics_i = 0; non_basics_i < non_basics_i_end; ++ non_basics_i) { 02993 02994 // Get the info on the current variable 02995 x_j = x_i_RightSide[non_basics_i][1]; 02996 a_ij = x_i_RightSide[non_basics_i][0].getRational(); 02997 x_j_Value = getBeta(x_j); 02998 02999 // If there is slack for improving x_i using x_j then do it 03000 if (a_ij < 0) { 03001 if (x_j_Value < getUpperBound(x_j)) { 03002 x_j_Found = true; 03003 break; 03004 } 03005 } else 03006 if (x_j_Value > getLowerBound(x_j)) { 03007 x_j_Found = true; 03008 break; 03009 } 03010 } 03011 03012 // If none of the variables allows for slack, the tableaux is unsatisfiable 03013 if (!x_j_Found) { 03014 // Generate the explanation 03015 explanation = getUpperBoundExplanation(it); 03016 // Return unsat 03017 return UNSATISFIABLE; 03018 } 03019 03020 // Otherwise do pivotAndUpdate and continue with the loop 03021 pivotAndUpdate(x_i, x_j, u_i); 03022 } else 03023 // Due to backtracking a unsat might become sat, just erase it 03024 unsatBasicVariables.erase(x_i); 03025 03026 03027 // If trace is on, printout the current valuation and the tableaux 03028 TRACE("simplex", "TheoryArithNew::checkSatSimplex ==> new tableaux : \n", tableauxAsString(), ""); 03029 TRACE("simplex", "TheoryArithNew::checkSatSimplex ==> new bounds : \n", boundsAsString(), ""); 03030 TRACE("simplex", "TheoryArithNew::checkSatSimplex ==> unsat : \n", unsatAsString(), ""); 03031 03032 }; 03033 03034 // Since there is no more unsat constraints we are satisfiable 03035 return SATISFIABLE; 03036 } 03037 03038 Rational TheoryArithNew::getTableauxEntry(const Expr& x_i, const Expr& x_j) { 03039 return findCoefficient(x_j, tableaux[x_i].getExpr()[1]); 03040 } 03041 03042 03043 const Rational& TheoryArithNew::findCoefficient(const Expr& var, const Expr& expr) { 03044 03045 // The zero coefficient 03046 static Rational zeroCoefficient(0); 03047 03048 // The given expression must be a sum 03049 DebugAssert(isPlus(expr), "TheoryArithNew::findCoefficient : expression must be a sum : " + expr.toString()); 03050 03051 // Go through the sum and find the coefficient 03052 int left = 0; 03053 int right = expr.arity() - 1; 03054 int i; 03055 while (left <= right) { 03056 03057 // Take the middle one 03058 i = (left + right ) / 2; 03059 03060 // Current expression 03061 const Expr& mult = expr[i]; 03062 03063 // Every summand must be a multiplication with a rational 03064 DebugAssert(isMult(mult) && isRational(mult[0]), "TheoryArithNew::findCoefficient : expression must be a sum of multiplications: " + expr.toString()); 03065 03066 // If the variable is the same return the coefficient 03067 int cmp = compare(mult[1], var); 03068 if (cmp == 0) 03069 return mult[0].getRational(); 03070 else 03071 if (cmp > 0) 03072 left = i + 1; 03073 else 03074 right = i - 1; 03075 } 03076 03077 // Not found, return 0 03078 return zeroCoefficient; 03079 } 03080 03081 03082 TheoryArithNew::EpsRational TheoryArithNew::getLowerBound(const Expr& x) const { 03083 // Try and find the lower bound in the map 03084 CDMap<Expr, BoundInfo>::iterator find = lowerBound.find(x); 03085 // If not found return +infinity as the default value, othervise return the value 03086 if (find == lowerBound.end()) return EpsRational::MinusInfinity; 03087 else return (*find).second.bound; 03088 } 03089 03090 TheoryArithNew::EpsRational TheoryArithNew::getUpperBound(const Expr& x) const { 03091 // Try and find the upper bound in the map 03092 CDMap<Expr, BoundInfo>::iterator find = upperBound.find(x); 03093 // If not found return -infinity as the default value, othervise return the value 03094 if (find == upperBound.end()) return EpsRational::PlusInfinity; 03095 else return (*find).second.bound; 03096 } 03097 03098 Theorem TheoryArithNew::getLowerBoundThm(const Expr& x) const { 03099 // Try and find the upper bound in the map 03100 CDMap<Expr, BoundInfo>::iterator find = lowerBound.find(x); 03101 // It has to be found 03102 DebugAssert(find != lowerBound.end(), "TheoryArithNew::getLowerBoundThm, theorem not found for " + x.toString()); 03103 // Return the bound theorem 03104 return (*find).second.theorem; 03105 } 03106 03107 Theorem TheoryArithNew::getUpperBoundThm(const Expr& x) const { 03108 // Try and find the upper bound in the map 03109 CDMap<Expr, BoundInfo>::iterator find = upperBound.find(x); 03110 // It has to be found 03111 DebugAssert(find != upperBound.end(), "TheoryArithNew::getUpperBoundThm, theorem not found for " + x.toString()); 03112 // Return the bound theorem 03113 return (*find).second.theorem; 03114 } 03115 03116 03117 TheoryArithNew::EpsRational TheoryArithNew::getBeta(const Expr& x) { 03118 03119 // Try to find the beta value in the map 03120 CDMap<Expr, EpsRational>::iterator find = beta.find(x); 03121 03122 if (find == beta.end()) { 03123 // If not found return 0 (no need for sat/unsat, it's allways sat) 03124 return beta[x] = EpsRational::Zero; 03125 03126 // Check if the variable is sat or unsat under the new assignment 03127 if (EpsRational::Zero < getLowerBound(x) || getUpperBound(x) < EpsRational::Zero) 03128 unsatBasicVariables.insert(x); 03129 else 03130 unsatBasicVariables.erase(x); 03131 } 03132 else 03133 // If found, just return it 03134 return (*find).second; 03135 } 03136 03137 03138 void TheoryArithNew::assertFact(const Theorem& assertThm) 03139 { 03140 // Get the expression to be asserted 03141 const Expr& expr = assertThm.getExpr(); 03142 03143 // If tracing arithmetic, print out the expression to be asserted 03144 TRACE("simplex", "TheoryArithNew::assertFact(", expr, ")"); 03145 TRACE("simplex", "asserted: ", assertedExpr.size(), ""); 03146 TRACE("simplex", "counted: ", assertedExprCount, ""); 03147 TRACE("arith_atoms", "Assert: ", expr.toString(), ""); 03148 03149 // Check if by backtracking we have more fresh variables than we expect 03150 if (assertedExprCount < assertedExpr.size()) 03151 updateFreshVariables(); 03152 03153 // Get the constraint partsreturn 03154 const Expr& leftSide = expr[0]; // The left side of the constraint 03155 const Expr& rightSide = expr[1]; // The right side of the constraint 03156 int kind = expr.getKind(); // The relational symbol, should be one of LT, LE, GT, GE. EQ was rewritten as LE and GE so its not here 03157 03158 // The expression must be an inequality (sum a_1*x_1 .. a_n*x_n) @ b 03159 DebugAssert(isIneq(expr) , "TheoryArithNew::assertFact wrong kind, expected inequality" + expr.toString()); 03160 DebugAssert(isPlus(rightSide) || (isMult(rightSide) && isRational(rightSide[0]) && isLeaf(rightSide[1])), "TheoryArithNew::assertFact wrong kind, expected sum on the right side opr a simple 1*x" + expr.toString()); 03161 DebugAssert(isRational(leftSide), "TheoryArithNew::assertFact wrong kind, expected rational on the right side" + expr.toString()); 03162 03163 // Get the rational value on the right side 03164 Rational leftSideValue = leftSide.getRational(); 03165 03166 // The rational bound on the constraint 03167 Rational c = leftSideValue; 03168 03169 // The variable to be constrained 03170 Expr var; 03171 03172 // Theorem of the assertion 03173 Theorem assert = assertThm; 03174 03175 // For now we have that leftSide @ (c1x1 + c2x2 + ... cnxn) = rightSide 03176 // If rightSide is not a sum constraint is atomic (leftSide @ a*x) 03177 if (!isPlus(rightSide)) { 03178 03179 // Tee left side in this case should be 1*x 03180 DebugAssert(rightSide[0].isRational() && rightSide[0].getRational() == 1, "TheoryArithNew::assertFact, left side should be multiplication by one"); 03181 03182 // Change the assert theorem to remove the 1*x to x 03183 assert = iffMP(assert, substitutivityRule(expr, reflexivityRule(leftSide), d_rules->oneElimination(rightSide))); 03184 03185 // The variable will just be x1 (if var is not already present in the tableaux, it will be non-basic) 03186 var = rightSide[1]; // IMPORTANT!!!, when giving explanations, it should be of the same form 03187 03188 // If an integer, add it to the integer set 03189 if (isInteger(var)) intVariables.insert(var); 03190 03191 } else { 03192 // Get the theorem that corresponds to the introduction of the new variable var = leftSide 03193 const Theorem& introductionThm = getVariableIntroThm(rightSide); 03194 03195 // Take the new variable out 03196 var = introductionThm.getExpr()[0]; 03197 03198 // Change the theorem for the assertion so that it involves the new variable, i.e. c < rightSide, var = rightSide |- c < var 03199 assert = iffMP(assertThm, substitutivityRule(expr, 1, symmetryRule(introductionThm))); 03200 03201 // Insert all the integer variables into the integer set 03202 if (isInteger(var)) { 03203 intVariables.insert(var); 03204 int i_end = rightSide.arity(); 03205 for(int i = 0; i < i_end; ++ i) 03206 intVariables.insert(rightSide[i][1]); 03207 } else { 03208 int i_end = rightSide.arity(); 03209 for(int i = 0; i < i_end; ++ i) 03210 if (isInteger(rightSide[i][1])) intVariables.insert(rightSide[i][1]); 03211 } 03212 } 03213 03214 // Make the BoundInfo object for theory propagation 03215 EpsRational bound; 03216 03217 // By default we don't propagate 03218 propagate = false; 03219 03220 // Remember the old bound 03221 EpsRational oldBound; 03222 03223 // Finnaly assert the right constraint 03224 switch (kind) { 03225 case LT: 03226 oldBound = getLowerBound(var); 03227 // c < var, convert to c + epsilon <= var and assert it 03228 consistent = assertLower(var, bound = EpsRational(c, +1), assert); 03229 break; 03230 case LE: 03231 oldBound = getLowerBound(var); 03232 // c <= var, assert the lower bound 03233 consistent = assertLower(var, bound = c, assert); 03234 break; 03235 case GT: 03236 oldBound = getUpperBound(var); 03237 // c > var, convert to c - epsilon >= var and assert it 03238 consistent = assertUpper(var, bound = EpsRational(c, -1), assert); 03239 break; 03240 case GE: 03241 oldBound = getUpperBound(var); 03242 // c >= var, assert the upper bound 03243 consistent = assertUpper(var, bound = c, assert); 03244 break; 03245 case EQ: 03246 // c == var, assert the equality 03247 consistent = assertEqual(var, bound = c, assert); 03248 // For now, don't propagate anything 03249 propagate = false; // TODO: some propagation is in place here (negations) 03250 break; 03251 default: 03252 //How did we get here 03253 FatalAssert(false, "Theory_Arith::assertFact, control should not reach here"); 03254 break; 03255 } 03256 03257 // If tracing arithmetic, print out the new tableaux and the current bounds 03258 TRACE("simplex", "TheoryArithNew::assertFact ==> ", consistent == UNSATISFIABLE? "UNSATISFIABLE" : consistent == UNKNOWN? "UNKNOWN" : "SATISFIABLE", ""); 03259 TRACE("simplex", "TheoryArithNew::assertFact ==> new tableaux : \n", tableauxAsString(), ""); 03260 TRACE("simplex", "TheoryArithNew::assertFact ==> new bounds : \n", boundsAsString(), ""); 03261 TRACE("simplex", "TheoryArithNew::assertFact ==> unsat : \n", unsatAsString(), ""); 03262 03263 // If the result is inconsistent set the inconsistent flag 03264 if (consistent == UNSATISFIABLE) 03265 setInconsistent(explanation); 03266 03267 // Not inconsistent, propagate all from this assertion 03268 if (propagate) 03269 propagateTheory(assertThm.getExpr(), bound, oldBound); 03270 } 03271 03272 03273 Theorem TheoryArithNew::getVariableIntroThm(const Expr& rightSide) { 03274 03275 // Try to find the expression in the map 03276 TebleauxMap::iterator find = freshVariables.find(rightSide); 03277 03278 // If not in tableaux, add it and assign it a new variable 03279 if (find == freshVariables.end()) { 03280 03281 // Get the common rules 03282 CommonProofRules* c_rules = getCommonRules(); 03283 03284 // Create a new variable (\exists x . rightSide = x) 03285 Theorem thm = c_rules->varIntroRule(rightSide); 03286 03287 // Skolemise it, to get an equality (\exists x . rightSide = x) <==> rightSide = c, then infer |- rightSide = c 03288 thm = c_rules->iffMP(thm, c_rules->skolemizeRewrite(thm.getExpr())); 03289 03290 // Reverse the equality into standard form 03291 thm = symmetryRule(thm); 03292 03293 // Add the theorem to the variable introduction map (this is the theorem we return) 03294 Theorem returnThm = freshVariables[rightSide] = thm; 03295 03296 // Now, flatten the equality modulo tableaux 03297 thm = substAndCanonizeModTableaux(thm); 03298 03299 // Get the skolem constant that was introduced (|- c = leftSide) 03300 const Expr& var = thm.getExpr()[0]; 03301 03302 // Also add it to the tableaux 03303 tableaux[var] = thm; 03304 03305 // Update the dependencies 03306 updateDependenciesAdd(var, thm.getExpr()[1]); 03307 03308 // Add it to the expressions map 03309 assertedExpr.push_back(Expr(EQ, var, rightSide)); 03310 assertedExprCount = assertedExprCount + 1; 03311 03312 // Compute the value of the new variable using the tableaux 03313 updateValue(var, rightSide); 03314 03315 // Return the variable 03316 return returnThm; 03317 } 03318 03319 // Otherwise we have it, so return it 03320 return (*find).second; 03321 } 03322 03323 void TheoryArithNew::updateValue(const Expr& var, const Expr& e) { 03324 03325 // The initial value 03326 EpsRational varValue(0); 03327 03328 // Go through the sum and compute the value 03329 int i_end = e.arity(); 03330 for (int i = 0; i < i_end; ++ i) 03331 varValue += getBeta(e[i][1]) * e[i][0].getRational(); 03332 03333 // Update the beta 03334 beta[var] = varValue; 03335 03336 // Check if the variable is sat or unsat under the new assignment 03337 if (varValue < getLowerBound(var) || getUpperBound(var) < varValue) 03338 unsatBasicVariables.insert(var); 03339 else 03340 unsatBasicVariables.erase(var); 03341 } 03342 03343 string TheoryArithNew::tableauxAsString() const { 03344 03345 // The string we are building 03346 string str; 03347 03348 // Start from the begining 03349 TebleauxMap::const_iterator row = tableaux.begin(); 03350 TebleauxMap::const_iterator row_end = tableaux.end(); 03351 03352 // Print all the rows 03353 while (row != tableaux.end()) { 03354 // Print the equality 03355 str = str + ((*row).second).getExpr().toString() + "\n"; 03356 03357 // Continue to the next row 03358 row ++; 03359 } 03360 03361 // Return the string representation 03362 return str; 03363 } 03364 03365 string TheoryArithNew::unsatAsString() const { 03366 03367 // The string we are building 03368 string str; 03369 03370 // Start from the begining 03371 set<Expr>::const_iterator it = unsatBasicVariables.begin(); 03372 set<Expr>::const_iterator it_end = unsatBasicVariables.end(); 03373 03374 // Print all the rows 03375 while (it != it_end) { 03376 // Print the equality 03377 str = str + (*it).toString() + " "; 03378 03379 // Continue to the next row 03380 it ++; 03381 } 03382 03383 // Return the string representation 03384 return str; 03385 } 03386 03387 03388 string TheoryArithNew::boundsAsString() { 03389 03390 // The string we are building 03391 string str; 03392 03393 // Set containing all the variables 03394 set<Expr> all_variables; 03395 03396 // Go throught the tableaux and pick up all the variables 03397 TebleauxMap::const_iterator it = tableaux.begin(); 03398 TebleauxMap::const_iterator it_end = tableaux.end(); 03399 for(; it != it_end; it ++) { 03400 03401 // Add the basic variable to the set 03402 all_variables.insert((*it).first); 03403 03404 // Go through all the expression variables and add them to the set 03405 const Expr& rightSide = (*it).second.getExpr()[1]; 03406 int term_i_end = rightSide.arity(); 03407 for(int term_i = 0; term_i < term_i_end; ++ term_i) 03408 all_variables.insert(rightSide[term_i][1]); 03409 } 03410 03411 // Go throught the bounds map and pickup all the variables 03412 CDMap<Expr, BoundInfo>::iterator bounds_it; 03413 for (bounds_it = lowerBound.begin(); bounds_it != lowerBound.end(); bounds_it ++) 03414 all_variables.insert((*bounds_it).first); 03415 for (bounds_it = upperBound.begin(); bounds_it != upperBound.end(); bounds_it ++) 03416 all_variables.insert((*bounds_it).first); 03417 03418 // Start from the begining 03419 set<Expr>::iterator var_it = all_variables.begin(); 03420 set<Expr>::iterator var_it_end = all_variables.end(); 03421 03422 // Print all the rows 03423 while (var_it != var_it_end) { 03424 03425 // The current variable 03426 const Expr& var = *var_it; 03427 03428 // Print the equality 03429 str += getLowerBound(var).toString() + " <= " + var.toString() + "(" + getBeta(var).toString() + ") <= " + getUpperBound(var).toString() + "\n"; 03430 03431 // Continue to the next variable 03432 var_it ++; 03433 } 03434 03435 // Return the string representation 03436 return str; 03437 } 03438 03439 // The infinity constant 03440 const TheoryArithNew::EpsRational TheoryArithNew::EpsRational::PlusInfinity(PLUS_INFINITY); 03441 // The negative infinity constant 03442 const TheoryArithNew::EpsRational TheoryArithNew::EpsRational::MinusInfinity(MINUS_INFINITY); 03443 // The negative infinity constant 03444 const TheoryArithNew::EpsRational TheoryArithNew::EpsRational::Zero; 03445 03446 03447 Theorem TheoryArithNew::substAndCanonizeModTableaux(const Theorem& eq) { 03448 03449 // If subst is empty, just return 03450 if(tableaux.empty()) return eq; 03451 03452 // Get the expression of the equality 03453 const Expr& eqExpr = eq.getExpr(); 03454 03455 // Check if the equality if in the canonic form 03456 DebugAssert(eqExpr.getKind() == EQ, "TheoryArithNew::substAndCanonize, expected equality " + eqExpr.toString()); 03457 03458 // Get the left side of the equality 03459 const Expr& rightSide = eqExpr[1]; 03460 03461 // Do the actual substitution in the eqExpr 03462 Theorem thm = substAndCanonizeModTableaux(rightSide); 03463 03464 // If the substitution had no result just return the original equation 03465 if(thm.getRHS() == rightSide) return eq; 03466 03467 // Return the theorem 03468 return iffMP(eq, substitutivityRule(eq.getExpr(), 1, thm)); 03469 } 03470 03471 Theorem TheoryArithNew::substAndCanonizeModTableaux(const Expr& sum) { 03472 03473 Theorem res; // The resulting theorem 03474 vector<Theorem> thms; // The theorems of the changed terms for the substitution 03475 vector<unsigned> changed; // The indices of the changed terms for the substitution 03476 03477 // Trace the canonisation 03478 TRACE("simplex", "TheoryArithNew::substAndCanonizeModTableaux(", sum, ")"); 03479 03480 // Check if the equality if in the canonic form 03481 DebugAssert(sum.getKind() == PLUS, "TheoryArithNew::substAndCanonize, expected sum " + sum.toString()); 03482 03483 // Go throught the sum and try to substitute the variables 03484 int term_index_end = sum.arity(); 03485 for(int term_index = 0; term_index < term_index_end; ++ term_index) { 03486 03487 const Expr& term = sum[term_index]; // The current term expression (a*x) 03488 const Expr& var = term[1]; // The variable of the current term 03489 03490 // Find the variable in the map 03491 TebleauxMap::iterator find = tableaux.find(var); 03492 03493 // If found, substitute it 03494 if (find != tableaux.end()) { 03495 03496 // Substitute the variable 03497 Theorem termTheorem = canonThm(substitutivityRule(term, 1, (*find).second)); 03498 03499 // Check that the result is not trivial 03500 DebugAssert(termTheorem.getExpr() != term, "substAndCanonizeModTableaux: got the same term in substitution"); 03501 03502 // Push it to the theorems vector 03503 thms.push_back(termTheorem); 03504 03505 // Add the index to the changed vector 03506 changed.push_back(term_index); 03507 } 03508 } 03509 03510 // Do the actual substitution and canonize the result 03511 if(thms.size() > 0) { 03512 // Substitute the changed subterms into the term 03513 res = substitutivityRule(sum, changed, thms); 03514 // Canonise the result 03515 res = canonThm(res); 03516 } else 03517 // Nothing happened, just return the reflexivity 03518 res = reflexivityRule(sum); 03519 03520 // Return the result 03521 return res; 03522 } 03523 03524 void TheoryArithNew::substAndCanonizeTableaux(const Theorem& eq) { 03525 03526 Theorem result; // The explaining theorem 03527 03528 // Trace 03529 TRACE("simplex", "TheoryArithNew::substAndCanonizeTableaux(", eq.getExpr(), ")"); 03530 03531 // Get the expression of the equality 03532 const Expr& eqExpr = eq.getExpr(); 03533 03534 // Check if the equality if in the canonic form 03535 DebugAssert(eqExpr.getKind() == EQ, "TheoryArithNew::substAndCanonize, expected equality " + eqExpr.toString()); 03536 03537 // Get the variable of the substitution 03538 const Expr& var = eqExpr[0]; 03539 03540 // Check if there are variables that depend on x_j 03541 DependenciesMap::iterator find = dependenciesMap.find(var); 03542 if (find != dependenciesMap.end()) { 03543 03544 // Go through all the variables that depend on x_j, and update their value 03545 set<Expr>& dependent = (*find).second; 03546 set<Expr>::iterator it = dependent.begin(); 03547 set<Expr>::iterator it_end = dependent.end(); 03548 for(; it != it_end; ++ it) { 03549 03550 // Get the expression and the right side of the row from the tableaux 03551 const Expr& leftSide = *it; 03552 TebleauxMap::iterator row = tableaux.find(leftSide); 03553 const Expr& rowExpr = (*row).second.getExpr(); 03554 const Expr& rowRightSide = rowExpr[1]; 03555 03556 // Go through the sum and try to substitute 03557 int right = rowRightSide.arity() - 1; 03558 int left = 0; 03559 int term_i; 03560 while (left <= right) { 03561 03562 // Get the middle one 03563 term_i = (left + right) / 2; 03564 03565 // Get the comparison of the variables 03566 int cmp = compare(rowRightSide[term_i][1], var); 03567 03568 // If the variable is found 03569 if (cmp == 0) { 03570 03571 // Do the substitution and canonise 03572 result = canonThm(substitutivityRule(rowRightSide[term_i], 1, eq)); 03573 // Do the substitution and canonise in the sum 03574 result = canonThm(substitutivityRule(rowRightSide, term_i, result)); 03575 // Do the substitution 03576 result = substitutivityRule(rowExpr, 1, result); 03577 03578 // Get the new expression 03579 const Expr& newRowRightSide = result.getRHS()[1]; 03580 // Update the dependencies of the varriables in the expression 03581 updateDependencies(rowRightSide, newRowRightSide, leftSide, var); 03582 03583 // That's it, remember the new row 03584 (*row).second = iffMP((*row).second, result); 03585 03586 // Variables don't repeat, we can just break out 03587 break; 03588 } else if (cmp > 0) 03589 left = term_i + 1; 03590 else 03591 right = term_i - 1; 03592 } 03593 } 03594 03595 // Now nobody depends on var anymore, just erase it 03596 dependent.clear(); 03597 } 03598 } 03599 03600 Theorem TheoryArithNew::pivotRule(const Theorem& eq, const Expr& var) { 03601 03602 Theorem result; // The theorem explaining the result 03603 03604 // Get the expression 03605 const Expr& eqExpr = eq.getExpr(); 03606 const Expr& right_side = eqExpr[1]; 03607 const Expr& left_side = eqExpr[0]; 03608 03609 // Trace if askedTheorem canonLeft = d_rules->canonMult(thm.getExpr()[0]); 03610 03611 TRACE("simplex", "TheoryArithNew::pivotRule(", eqExpr.toString() + ", ", var.toString() + ")"); 03612 03613 // Eq must be an equation with the sum on the left side and a leaf on the right side (variable) 03614 DebugAssert(eqExpr.getKind() == EQ, "TheoryArithNew::pivotRule, expected an equality : " + eqExpr.toString()); 03615 DebugAssert(right_side.getKind() == PLUS, "TheoryArithNew::pivotRule, expected a sum on the left-hand side : " + eqExpr.toString()); 03616 DebugAssert(isLeaf(left_side), "TheoryArithNew::pivotRule, expected a leaf (variable) on the right-hand side : " + eqExpr.toString()); 03617 03618 // Find the term of var in the left-hand side of eq 03619 int term_i_end = right_side.arity(); 03620 for(int term_i = 0; term_i < term_i_end; ++ term_i) 03621 // If found do the stuff 03622 if (right_side[term_i][1] == var) { 03623 03624 // This is the term we need and the rational we need 03625 const Expr& termExpr = right_side[term_i]; 03626 const Expr& termVar = termExpr[1]; 03627 const Rational& termRat = termExpr[0].getRational(); 03628 03629 // Construct the expression we will add to the equality 03630 const Expr& minusTermExpr = multExpr(rat(-termRat), termVar); 03631 const Expr& minusVarExpr = multExpr(rat(-1), left_side); 03632 03633 // Add the above expressions to the to the equality 03634 result = iffMP(eq, d_rules->plusPredicate(left_side, right_side, plusExpr(minusTermExpr, minusVarExpr), EQ)); 03635 // Canonise the right-hand side 03636 result = transitivityRule(result, canon(result.getExpr()[1])); 03637 // Canonise the left-hand side 03638 result = transitivityRule(symmetryRule(canon(result.getExpr()[0])), result); 03639 // Multiply by the inverse of the rational constant (negated and ^-1) 03640 result = iffMP(result, d_rules->multEqn(result.getExpr()[0], result.getExpr()[1], rat(-1/termRat))); 03641 // Canonise the left-hand side 03642 result = transitivityRule(result, canon(result.getExpr()[1])); 03643 // Canonise the right=hand side 03644 result = transitivityRule(symmetryRule(canon(result.getExpr()[0])), result); 03645 // Rewrite 1*x => x in the left-hand side 03646 result = transitivityRule(symmetryRule(d_rules->oneElimination(result.getExpr()[0])), result); 03647 03648 // Trace the result 03649 TRACE("simplex", "TheoryArithNew::pivotRule ==> ", result.getExpr().toString(), ""); 03650 03651 // We are done, there is just one variable there 03652 return result; 03653 } 03654 03655 // If not found, there is something wrong 03656 DebugAssert(false, "TheoryArithNew::pivotRule, " + var.toString() + " does not occur in " + eqExpr.toString()); 03657 03658 // Dummy return 03659 return result; 03660 } 03661 03662 Theorem TheoryArithNew::getLowerBoundExplanation(const TebleauxMap::iterator& var_it) { 03663 03664 vector<Theorem> upperBounds; // Vector of the upper-bound theorems 03665 03666 // Get the tableaux theorem explaining the leftside = var 03667 Theorem tableauxTheorem = (*var_it).second; 03668 03669 // Get the variable on the right side 03670 const Expr& var = (*var_it).first; 03671 03672 // Get the expression involved (leftSide = var) 03673 const Expr& rightSide = tableauxTheorem.getExpr()[1]; 03674 03675 // Go through the left side and pick up the apropriate lower and upper bounds 03676 int leftSide_i_end = rightSide.arity(); 03677 for(int leftSide_i = 0; leftSide_i < leftSide_i_end; ++ leftSide_i) { 03678 03679 // Get the rational 03680 const Expr& a = rightSide[leftSide_i][0]; 03681 03682 // Get the variable 03683 const Expr& x = rightSide[leftSide_i][1]; 03684 03685 // The positive ones make up the upper bounds (x < u => a * x < a * u) 03686 if (a.getRational() > 0) { 03687 // Get the upper bound x < u 03688 Theorem thm = getUpperBoundThm(x); 03689 03690 // Multiply if by a ==> u_i * a > x * a 03691 thm = iffMP(thm, d_rules->multIneqn(thm.getExpr(), a)); 03692 03693 // Canonise the left and the right side 03694 Theorem canonRight = d_rules->canonMultTermConst(thm.getExpr()[1][1], thm.getExpr()[1][0]); 03695 Theorem canonLeft = d_rules->canonMultConstConst(thm.getExpr()[0][0], thm.getExpr()[0][1]); 03696 03697 // Substitute the canonised to the inequality 03698 thm = iffMP(thm, substitutivityRule(thm.getExpr(), canonLeft, canonRight)); 03699 03700 // Add the bound to the vector of upper bounds (|- c_x > a * x) 03701 upperBounds.push_back(thm); 03702 } 03703 // The negative ones make up the lower bounds (x > l => a * x < a * l) 03704 else { 03705 // Get the lower bound l < x 03706 Theorem thm = getLowerBoundThm(x); 03707 03708 // Multiply if by a |- l * a < x * a 03709 thm = iffMP(thm, d_rules->multIneqn(thm.getExpr(), a)); 03710 03711 // Canonise the left and the right side 03712 Theorem canonRight = d_rules->canonMultTermConst(thm.getExpr()[1][1], thm.getExpr()[1][0]); 03713 Theorem canonLeft = d_rules->canonMultConstConst(thm.getExpr()[0][0], thm.getExpr()[0][1]); 03714 03715 // Substitute the canonised to the inequality 03716 thm = iffMP(thm, substitutivityRule(thm.getExpr(), canonLeft, canonRight)); 03717 03718 // Add the bound to the vector of upper bounds (|- c_x > a * x) 03719 upperBounds.push_back(thm); 03720 } 03721 } 03722 03723 // Add up all the inequalities to get a C = \sum c_i > rightSide 03724 Theorem sumInequalities = upperBounds[0]; 03725 for(unsigned int i = 1; i < upperBounds.size(); i ++) { 03726 // Add the inequalities 03727 sumInequalities = d_rules->addInequalities(sumInequalities, upperBounds[i]); 03728 03729 // Canonise the left and the right side 03730 Theorem canonLeft = d_rules->canonPlus(sumInequalities.getExpr()[0]); 03731 Theorem canonRight = d_rules->canonPlus(sumInequalities.getExpr()[1]); 03732 03733 // Substitute the canonised to the inequality 03734 sumInequalities = iffMP(sumInequalities, substitutivityRule(sumInequalities.getExpr(), canonLeft, canonRight)); 03735 } 03736 03737 // Substitute to get C > rightSide ==> C > var 03738 Theorem varUpperBound = substitutivityRule(sumInequalities.getExpr(), 1, symmetryRule(tableauxTheorem)); 03739 // MP to get C > var 03740 varUpperBound = iffMP(sumInequalities, varUpperBound); 03741 03742 // Get the lower bound on the rigth side variable (l_var < var) 03743 Theorem varLowerBound = getLowerBoundThm(var); 03744 03745 // Return the clashing bound theorem 03746 return d_rules->clashingBounds(varLowerBound, varUpperBound); 03747 } 03748 03749 Theorem TheoryArithNew::getUpperBoundExplanation(const TebleauxMap::iterator& var_it) { 03750 03751 vector<Theorem> lowerBounds; // Vector of the upper-bound theorems 03752 03753 // Get the tableaux theorem explaining the leftside = var 03754 Theorem tableauxTheorem = (*var_it).second; 03755 03756 // Get the variable on the right side 03757 const Expr& var = (*var_it).first; 03758 03759 // Get the expression involved (var = rightSide) 03760 const Expr& rightSide = tableauxTheorem.getExpr()[1]; 03761 03762 // Trace if requested 03763 TRACE("explanations", "Generating explanation for the tableaux row ", tableauxTheorem.getExpr(), ""); 03764 03765 // Go through the right side and pick up the apropriate lower and upper bounds 03766 int rightSide_i_end = rightSide.arity(); 03767 for(int rightSide_i = 0; rightSide_i < rightSide_i_end; ++ rightSide_i) { 03768 03769 // Get the rational 03770 const Expr& a = rightSide[rightSide_i][0]; 03771 03772 // Get the variable 03773 const Expr& x = rightSide[rightSide_i][1]; 03774 03775 // The positive ones make up the lower bounds (x > l => a * x > a * l) 03776 if (a.getRational() > 0) { 03777 // Get the lower bound l < x 03778 Theorem thm = getLowerBoundThm(x); 03779 TRACE("explanations", "Got ", thm.getExpr(), ""); 03780 03781 // Multiply if by a ==> l * a < x * a 03782 thm = iffMP(thm, d_rules->multIneqn(thm.getExpr(), a)); 03783 TRACE("explanations", "Got ", thm.getExpr(), ""); 03784 03785 // Canonise the left and the right side 03786 Theorem canonRight = d_rules->canonMultTermConst(thm.getExpr()[1][1], thm.getExpr()[1][0]); 03787 Theorem canonLeft = d_rules->canonMultConstConst(thm.getExpr()[0][0], thm.getExpr()[0][1]); 03788 03789 // Substitute the canonised to the inequality 03790 thm = iffMP(thm, substitutivityRule(thm.getExpr(), canonLeft, canonRight)); 03791 TRACE("explanations", "Got ", thm.getExpr(), ""); 03792 03793 // Add the bound to the vector of upper bounds (|- c_x < a * x) 03794 lowerBounds.push_back(thm); 03795 } 03796 // The negative ones make up the upper bounds (x < u => a * x > a * u) 03797 else { 03798 // Get the upper bound u > x 03799 Theorem thm = getUpperBoundThm(x); 03800 TRACE("explanations", "Got ", thm.getExpr(), ""); 03801 03802 // Multiply it by a |- u * a > x * a 03803 thm = iffMP(thm, d_rules->multIneqn(thm.getExpr(), a)); 03804 TRACE("explanations", "Got ", thm.getExpr(), ""); 03805 03806 // Canonise the left and the right side 03807 Theorem canonRight = d_rules->canonMultTermConst(thm.getExpr()[1][1], thm.getExpr()[1][0]); 03808 Theorem canonLeft = d_rules->canonMultConstConst(thm.getExpr()[0][0], thm.getExpr()[0][1]); 03809 03810 // Substitute the canonised to the inequality 03811 thm = iffMP(thm, substitutivityRule(thm.getExpr(), canonLeft, canonRight)); 03812 TRACE("explanations", "Got ", thm.getExpr(), ""); 03813 03814 // Add the bound to the vector of upper bounds (|- c_x < a * x) 03815 lowerBounds.push_back(thm); 03816 } 03817 } 03818 03819 // Add up all the inequalities to get a \sum c_i = C > rightSide 03820 Theorem sumInequalities = lowerBounds[0]; 03821 for(unsigned int i = 1; i < lowerBounds.size(); i ++) { 03822 // Add the inequalities 03823 sumInequalities = d_rules->addInequalities(sumInequalities, lowerBounds[i]); 03824 03825 TRACE("explanations", "Got sum ", sumInequalities.getExpr(), ""); 03826 03827 // Canonise the left and the right side 03828 Theorem canonLeft = d_rules->canonPlus(sumInequalities.getExpr()[0]); 03829 Theorem canonRight = d_rules->canonPlus(sumInequalities.getExpr()[1]); 03830 03831 // Substitute the canonised to the inequality 03832 sumInequalities = iffMP(sumInequalities, substitutivityRule(sumInequalities.getExpr(), canonLeft, canonRight)); 03833 } 03834 03835 // Trace if requested 03836 TRACE("explanations", "Got sum ", sumInequalities.getExpr(), ""); 03837 03838 // Substitute to get C < leftSide ==> C < var 03839 Theorem varLowerBound = substitutivityRule(sumInequalities.getExpr(), 1, symmetryRule(tableauxTheorem)); 03840 03841 // MP to get C < var 03842 varLowerBound = iffMP(sumInequalities, varLowerBound); 03843 03844 // Trace if requested 03845 TRACE("explanations", "Got lower bound ", varLowerBound.getExpr(), ""); 03846 03847 // Get the lower bound on the rigth side variable (var > l_var) 03848 Theorem varUpperBound = getUpperBoundThm(var); 03849 03850 // Trace if requested 03851 TRACE("explanations", "Got upper bound ", varUpperBound.getExpr(), ""); 03852 03853 TRACE("explanations", "The var value (", var, ")" + getBeta(var).toString()); 03854 03855 // Return the clashing bound theorem 03856 return d_rules->clashingBounds(varLowerBound, varUpperBound); 03857 } 03858 03859 void TheoryArithNew::updateFreshVariables() { 03860 03861 unsigned int size = assertedExpr.size(); 03862 unsigned int i; 03863 03864 for (i = assertedExprCount; i < size; ++ i) 03865 //Update the value 03866 updateValue(assertedExpr[i][0], assertedExpr[i][1]); 03867 03868 // Update the asserted count to be the size of the vector 03869 assertedExprCount = i; 03870 03871 } 03872 03873 void TheoryArithNew::updateDependenciesAdd(const Expr& var, const Expr& sum) { 03874 03875 // Trace it 03876 TRACE("tableaux_dep", "updateDependenciesAdd(", var.toString() + ", ", sum.toString() + ")"); 03877 03878 // Go through the sum and add var to the dependencies of that term variable 03879 Expr::iterator term = sum.begin(); 03880 Expr::iterator term_end = sum.end(); 03881 for(; term != term_end; term ++) 03882 dependenciesMap[(*term)[1]].insert(var); 03883 03884 } 03885 03886 void TheoryArithNew::updateDependenciesRemove(const Expr& var, const Expr& sum) { 03887 03888 // Trace it 03889 TRACE("tableaux_dep", "updateDependenciesRemove(", var.toString() + ", ", sum.toString() + ")"); 03890 03891 // Go through the sum and remove var to the dependencies of that term variable 03892 Expr::iterator term = sum.begin(); 03893 Expr::iterator term_end = sum.end(); 03894 for(; term != term_end; term ++) 03895 dependenciesMap[(*term)[1]].erase(var); 03896 03897 } 03898 03899 void TheoryArithNew::updateDependencies(const Expr& oldSum, const Expr& newSum, const Expr& dependentVar, const Expr& skipVar) { 03900 03901 // Trace it 03902 TRACE("tableaux_dep", "updateDependencies(", oldSum.toString() + ", " + newSum.toString() + ", " + dependentVar.toString(), ")"); 03903 03904 // Since the sums are ordered by variables, we can just to a "merge sort" 03905 int oldSum_i = 0, newSum_i = 0; 03906 int oldSum_end = oldSum.arity(), newSum_end = newSum.arity(); 03907 // Get the first variables 03908 while (oldSum_i < oldSum_end && newSum_i < newSum_end) { 03909 03910 // Get the variable references 03911 const Expr oldVar = oldSum[oldSum_i][1]; 03912 const Expr newVar = newSum[newSum_i][1]; 03913 03914 // If variables equal, just skip, everything is ok 03915 if (oldVar == newVar) { 03916 ++ oldSum_i; ++ newSum_i; continue; 03917 } 03918 03919 // Otherwise do the work with the smaller one 03920 if (oldVar > newVar) { 03921 // Old variable has dissapeared, remove dependent from its list 03922 if (oldVar != skipVar) 03923 dependenciesMap[oldVar].erase(dependentVar); 03924 // Move the old variable forward 03925 ++ oldSum_i; 03926 } else { 03927 // New variable has appeared, insert dependent to its list 03928 if (newVar != skipVar) 03929 dependenciesMap[newVar].insert(dependentVar); 03930 // Move the new variable forward 03931 ++ newSum_i; 03932 } 03933 } 03934 03935 // If there is leftovers in the old sum, just do the removals 03936 while (oldSum_i < oldSum_end) { 03937 // Get the var, and increase the index 03938 const Expr& var = oldSum[oldSum_i ++][1]; 03939 // Update the dependency 03940 if (var != skipVar) 03941 dependenciesMap[var].erase(dependentVar); 03942 } 03943 03944 while (newSum_i < newSum_end) { 03945 // Get the var, and increase the index 03946 const Expr& var = newSum[newSum_i ++][1]; 03947 // Update the dependency 03948 if (var != skipVar) 03949 dependenciesMap[var].insert(dependentVar); 03950 } 03951 } 03952 03953 void TheoryArithNew::registerAtom(const Expr& e) { 03954 03955 // Trace it 03956 TRACE("propagate_arith", "registerAtom(", e.toString(), ")"); 03957 TRACE("arith_atoms", "", e.toString(), ""); 03958 03959 // If it is a atomic formula, add it to the map 03960 if (e.isAbsAtomicFormula()) { 03961 Expr rightSide = e[1]; 03962 int kind = e.getKind(); 03963 Rational leftSide = e[0].getRational(); 03964 03965 // The eps bound we'll be using 03966 EpsRational bound; 03967 03968 // Depending on the type of the inequality define the bound 03969 switch (kind) { 03970 case LT: 03971 bound = EpsRational(leftSide, +1); 03972 break; 03973 case LE: 03974 bound = leftSide; 03975 break; 03976 case GT: 03977 bound = EpsRational(leftSide, -1); 03978 break; 03979 case GE: 03980 bound = leftSide; 03981 break; 03982 default: 03983 // How did we get here 03984 FatalAssert(false, "TheoryArithNew::registerAtom: control should not reach here" + e.toString()); 03985 } 03986 03987 // Bound has been set, now add the 03988 allBounds.insert(ExprBoundInfo(bound, e)); 03989 } 03990 03991 // // Printout the current set of atoms in the set 03992 // cout << "ALL BOUNDS:" << endl; 03993 // BoundInfoSet::iterator it = allBounds.begin(); 03994 // while (it != allBounds.end()) { 03995 // cout << (*it).e << endl; 03996 // ++ it; 03997 // } 03998 } 03999 04000 void TheoryArithNew::propagateTheory(const Expr& assertExpr, const EpsRational& bound, const EpsRational& oldBound) { 04001 04002 // Trace it 04003 TRACE("propagate_arith", "propagateTheory(", assertExpr.toString() + ", " + bound.toString(), ")"); 04004 04005 // Make the bound info object, so that we can search for it 04006 ExprBoundInfo boundInfo(bound, assertExpr); 04007 04008 // Get the exression on the right side hand 04009 Expr rightSide = assertExpr[1]; 04010 04011 // Get the kid of the disequality 04012 int kind = assertExpr.getKind(); 04013 04014 // Check wheather the kind is one of LT, LE, GT, GE 04015 DebugAssert(kind == LT || kind == LE || kind == GT || kind == GE , "TheoryArithNew::propagateTheory : expected an inequality"); 04016 04017 // If the bound is of the type LT or LE we go up 04018 if (kind == LT || kind == LE) { 04019 // Find the asserted fact in the set (it must be there) 04020 BoundInfoSet::iterator find = allBounds.lower_bound(boundInfo); 04021 BoundInfoSet::iterator find_end = allBounds.lower_bound(ExprBoundInfo(oldBound, assertExpr)); 04022 04023 // If we are at the begining, or not found, just exit 04024 if (find == find_end) return; 04025 04026 // Now, go up until reached wrong right side (skip the first one, its the same as given) 04027 while (find != find_end) { 04028 04029 // Go up; 04030 -- find; 04031 04032 // Get the theorem of the find 04033 const Expr& findExpr = (*find).e; 04034 04035 // Get the bound of the find 04036 const EpsRational findRat = (*find).bound; 04037 04038 // Get the kind of the expression in the theorem 04039 int findExprKind = findExpr.getKind(); 04040 04041 // Check if the right sides are the same 04042 if (rightSide != findExpr[1]) break; 04043 04044 // Construct the theorem object 04045 Theorem lemma; 04046 04047 // Check the type and equeue the lemma 04048 if (findExprKind == LT || findExprKind == LE) 04049 // Imply the weaker inequality 04050 lemma = d_rules->implyWeakerInequality(assertExpr, findExpr); 04051 else 04052 // Imply the negation of the impossible inequality 04053 lemma = d_rules->implyNegatedInequality(assertExpr, findExpr); 04054 04055 04056 TRACE("propagate_arith", "lemma ==>", lemma.toString(), ""); 04057 TRACE("arith_atoms", "Propagate: ", lemma.getExpr().toString(), ""); 04058 04059 // Put it across 04060 enqueueFact(lemma); 04061 } 04062 } 04063 // If the bound is of the type GT or GE we go down 04064 else { 04065 // Find the asserted fact in the set (it must be there) 04066 BoundInfoSet::iterator find = allBounds.upper_bound(boundInfo); 04067 BoundInfoSet::iterator find_end = allBounds.upper_bound(ExprBoundInfo(oldBound, assertExpr)); 04068 04069 // Now, go down until reached wrong right side (skip the first one, its the same as given) 04070 while (find != find_end) { 04071 04072 // Get the bound of the find 04073 const EpsRational findRat = (*find).bound; 04074 04075 // Get the expression in the theorem 04076 const Expr& findExpr = (*find).e; 04077 int findExprKind = findExpr.getKind(); 04078 04079 // Check if the right sides are the same 04080 if (rightSide != findExpr[1]) break; 04081 04082 // Construct the theorem object 04083 Theorem lemma; 04084 04085 // Check the type and equeue the lemma 04086 if (findExprKind == GT || findExprKind == GE) 04087 // Imply the weaker inequality 04088 lemma = d_rules->implyWeakerInequality(assertExpr, findExpr); 04089 else 04090 // Imply the negation of the impossible inequality (use oposite than above) 04091 lemma = d_rules->implyNegatedInequality(assertExpr, findExpr); 04092 04093 TRACE("propagate_arith", "lemma ==>", lemma.toString(), ""); 04094 TRACE("arith_atoms", "Propagate: ", lemma.getExpr().toString(), ""); 04095 04096 // Put it across 04097 enqueueFact(lemma); 04098 04099 // Go to the next one 04100 ++ find; 04101 } 04102 } 04103 } 04104 04105 Theorem TheoryArithNew::deriveGomoryCut(const Expr& x_i) { 04106 04107 Theorem res; 04108 04109 // CHECK IF APPLICABLE 04110 DebugAssert(isBasic(x_i), "TheoryArithNew::deriveGomoryCut variable must be a basic variable : " + x_i.toString()); 04111 DebugAssert(intVariables.count(x_i) > 0, "TheoryArithNew::deriveGomoryCut variable must be a basic variable : " + x_i.toString()); 04112 04113 // Get the rational value of x_i 04114 Rational x_i_Value = getBeta(x_i).getRational(); 04115 04116 // Compute f_0 04117 Rational f_0 = x_i_Value - floor(x_i_Value); 04118 04119 return res; 04120 }