CVC3
|
00001 /*****************************************************************************/ 00002 /*! 00003 * \file array_theorem_producer.cpp 00004 * \brief Description: TRUSTED implementation of array proof rules. 00005 * 00006 * Author: Clark Barrett 00007 * 00008 * Created: Thu May 29 14:02:16 2003 00009 * 00010 * <hr> 00011 * 00012 * License to use, copy, modify, sell and/or distribute this software 00013 * and its documentation for any purpose is hereby granted without 00014 * royalty, subject to the terms and conditions defined in the \ref 00015 * LICENSE file provided with this distribution. 00016 * 00017 * <hr> 00018 * 00019 */ 00020 /*****************************************************************************/ 00021 00022 00023 // This code is trusted 00024 #define _CVC3_TRUSTED_ 00025 00026 00027 #include "array_theorem_producer.h" 00028 #include "theory_array.h" 00029 #include "theory_core.h" 00030 00031 00032 using namespace std; 00033 using namespace CVC3; 00034 00035 00036 //////////////////////////////////////////////////////////////////// 00037 // TheoryArray: trusted method for creating ArrayTheoremProducer 00038 //////////////////////////////////////////////////////////////////// 00039 00040 00041 ArrayProofRules* TheoryArray::createProofRules() { 00042 return new ArrayTheoremProducer(this); 00043 } 00044 00045 00046 ArrayTheoremProducer::ArrayTheoremProducer(TheoryArray* theoryArray) 00047 : TheoremProducer(theoryArray->theoryCore()->getTM()), 00048 d_theoryArray(theoryArray) 00049 {} 00050 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Proof rules 00054 //////////////////////////////////////////////////////////////////// 00055 00056 00057 #define CLASS_NAME "CVC3::ArrayTheoremProducer" 00058 00059 00060 // ==> 00061 // write(store, index_0, v_0, index_1, v_1, ..., index_n, v_n) = store IFF 00062 // 00063 // read(store, index_n) = v_n & 00064 // index_{n-1} != index_n -> read(store, index_{n-1}) = v_{n-1} & 00065 // (index_{n-2} != index_{n-1} & index_{n-2} != index_n) -> read(store, index_{n-2}) = v_{n-2} & 00066 // ... 00067 // (index_1 != index_2 & ... & index_1 != index_n) -> read(store, index_1) = v_1 00068 // (index_0 != index_1 & index_0 != index_2 & ... & index_0 != index_n) -> read(store, index_0) = v_0 00069 Theorem 00070 ArrayTheoremProducer::rewriteSameStore(const Expr& e, int n) 00071 { 00072 IF_DEBUG( 00073 DebugAssert(e.isEq(), "EQ expected"); 00074 Expr e1 = e[0]; 00075 int N = 0; 00076 while (isWrite(e1)) { N++; e1 = e1[0]; } 00077 DebugAssert(N == n && n > 0, "Counting error"); 00078 DebugAssert(e1 == e[1], "Stores do not match"); 00079 ) 00080 00081 Proof pf; 00082 Expr write_i, write_j, index_i, index_j, hyp, conc, result; 00083 int i, j; 00084 00085 write_i = e[0]; 00086 for (i = n-1; i >= 0; --i) { 00087 index_i = write_i[1]; 00088 00089 // build: [index_i /= index_n && index_i /= index_(n-1) && 00090 // ... && index_i /= index_(i+1)] -> read(store, index_i) = v_i 00091 write_j = e[0]; 00092 for (j = n - 1; j > i; --j) { 00093 index_j = write_j[1]; 00094 Expr hyp2(!((index_i.getType().isBool())? 00095 index_i.iffExpr(index_j) : index_i.eqExpr(index_j))); 00096 if (hyp.isNull()) hyp = hyp2; 00097 else hyp = hyp && hyp2; 00098 write_j = write_j[0]; 00099 } 00100 Expr r1(Expr(READ, e[1], index_i)); 00101 conc = (r1.getType().isBool())? 00102 r1.iffExpr(write_i[2]) : r1.eqExpr(write_i[2]); 00103 if (!hyp.isNull()) conc = hyp.impExpr(conc); 00104 00105 // And into result 00106 if (result.isNull()) result = conc; 00107 else result = result && conc; 00108 00109 // Prepare for next iteration 00110 write_i = write_i[0]; 00111 hyp = Expr(); 00112 } 00113 if (withProof()) pf = newPf("rewriteSameStore", e); 00114 return newRWTheorem(e, result, Assumptions::emptyAssump(), pf); 00115 } 00116 00117 00118 // ==> write(store, index, value) = write(...) IFF 00119 // store = write(write(...), index, read(store, index)) & 00120 // value = read(write(...), index) 00121 Theorem 00122 ArrayTheoremProducer::rewriteWriteWrite(const Expr& e) 00123 { 00124 IF_DEBUG( 00125 DebugAssert(e.isEq(), "EQ expected"); 00126 DebugAssert(isWrite(e[0]) && isWrite(e[1]), 00127 "Expected WRITE = WRITE"); 00128 ) 00129 Proof pf; 00130 const Expr& left = e[0]; 00131 const Expr& right = e[1]; 00132 const Expr& store = left[0]; 00133 const Expr& index = left[1]; 00134 const Expr& value = left[2]; 00135 Expr e1 = (store.getType().isBool())? 00136 store.iffExpr(Expr(WRITE, right, index, Expr(READ, store, index))) 00137 : store.eqExpr(Expr(WRITE, right, index, Expr(READ, store, index))); 00138 Expr e2 = (value.getType().isBool()) ? 00139 value.iffExpr(Expr(READ, right, index)) : 00140 value.eqExpr(Expr(READ, right, index)); 00141 if (withProof()) pf = newPf("rewriteWriteWrite", e); 00142 return newRWTheorem(e, e1.andExpr(e2), Assumptions::emptyAssump(), pf); 00143 } 00144 00145 00146 // ==> read(write(store, index1, value), index2) = 00147 // ite(index1 = index2, value, read(store, index2)) 00148 Theorem 00149 ArrayTheoremProducer::rewriteReadWrite(const Expr& e) 00150 { 00151 IF_DEBUG( 00152 DebugAssert(isRead(e), "Read expected"); 00153 DebugAssert(isWrite(e[0]), "Expected Read(Write)"); 00154 ) 00155 Proof pf; 00156 const Expr& store = e[0][0]; 00157 const Expr& index1 = e[0][1]; 00158 const Expr& value = e[0][2]; 00159 const Expr& index2 = e[1]; 00160 Expr indexCond = (index1.getType().isBool())? 00161 index1.iffExpr(index2) : index1.eqExpr(index2); 00162 if (withProof()) pf = newPf("rewriteReadWrite", e); 00163 return newRWTheorem(e, indexCond.iteExpr(value, 00164 Expr(READ, store, index2)), Assumptions::emptyAssump(), pf); 00165 } 00166 00167 00168 // e = read(write(store, index1, value), index2): 00169 // ==> ite(index1 = index2, 00170 // read(write(store, index1, value), index2) = value, 00171 // read(write(store, index1, value), index2) = read(store, index2)) 00172 Theorem 00173 ArrayTheoremProducer::rewriteReadWrite2(const Expr& e) 00174 { 00175 IF_DEBUG( 00176 DebugAssert(isRead(e), "Read expected"); 00177 DebugAssert(isWrite(e[0]), "Expected Read(Write)"); 00178 ) 00179 Proof pf; 00180 const Expr& store = e[0][0]; 00181 const Expr& index1 = e[0][1]; 00182 const Expr& value = e[0][2]; 00183 const Expr& index2 = e[1]; 00184 Expr indexCond = (index1.getType().isBool())? 00185 index1.iffExpr(index2) : index1.eqExpr(index2); 00186 if (withProof()) pf = newPf("rewriteReadWrite2", e); 00187 return newTheorem(indexCond.iteExpr(e.eqExpr(value), 00188 e.eqExpr(Expr(READ, store, index2))), 00189 Assumptions::emptyAssump(), pf); 00190 } 00191 00192 00193 // read(store, index) = value ==> 00194 // write(store, index, value) = store 00195 // 00196 // More general case: 00197 // 00198 // read(store, index_n) = value_n ==> 00199 // write(store, index_0, v_0, index_1, v_1, ..., index_n, value_n) = 00200 // write(store, index_0, ite(index_n = index_0, value_n, v_0), 00201 // index_1, ite(index_n = index_1, value_n, v_1), 00202 // ... 00203 // index_{n-1}, ite(index_n = index_{n-1}, value_n, value_{n-1})) 00204 Theorem 00205 ArrayTheoremProducer::rewriteRedundantWrite1(const Theorem& r_eq_v, 00206 const Expr& write) 00207 { 00208 DebugAssert(r_eq_v.isRewrite(), "Expected equation"); 00209 DebugAssert(isRead(r_eq_v.getLHS()), "Expected Read"); 00210 const Expr& index = r_eq_v.getLHS()[1]; 00211 const Expr& value = r_eq_v.getRHS(); 00212 DebugAssert(isWrite(write) && 00213 index == write[1] && value == write[2], 00214 "Error in parameters to rewriteRedundantWrite1"); 00215 00216 vector<Expr> indices; 00217 vector<Expr> values; 00218 Expr store = write[0]; 00219 while (isWrite(store)) { 00220 indices.push_back(store[1]); 00221 values.push_back(store[2]); 00222 store = store[0]; 00223 } 00224 DebugAssert(store == r_eq_v.getLHS()[0], 00225 "Store does not match in rewriteRedundantWrite"); 00226 while (!indices.empty()) { 00227 store = Expr(WRITE, store, indices.back(), 00228 index.eqExpr(indices.back()).iteExpr(value, values.back())); 00229 indices.pop_back(); 00230 values.pop_back(); 00231 } 00232 00233 Proof pf; 00234 if(withProof()) { 00235 pf = newPf("rewriteRedundantWrite1", write, r_eq_v.getProof()); 00236 } 00237 return newRWTheorem(write, store, r_eq_v.getAssumptionsRef(), pf); 00238 } 00239 00240 00241 // ==> 00242 // write(write(store, index, v1), index, v2) = write(store, index, v2) 00243 Theorem 00244 ArrayTheoremProducer::rewriteRedundantWrite2(const Expr& e) 00245 { 00246 DebugAssert(isWrite(e) && isWrite(e[0]) && 00247 e[0][1] == e[1], 00248 "Error in parameters to rewriteRedundantWrite2"); 00249 00250 Proof pf; 00251 00252 if(withProof()) { 00253 pf = newPf("rewriteRedundantWrite2", e); 00254 } 00255 00256 return newRWTheorem(e, Expr(WRITE, e[0][0], e[1], e[2]), Assumptions::emptyAssump(), pf); 00257 } 00258 00259 00260 // ==> 00261 // write(write(store, index1, v1), index2, v2) = 00262 // write(write(store, index2, v2), index1, ite(index1 = index2, v2, v1)) 00263 Theorem 00264 ArrayTheoremProducer::interchangeIndices(const Expr& e) 00265 { 00266 DebugAssert(isWrite(e) && isWrite(e[0]), 00267 "Error in parameters to interchangeIndices"); 00268 00269 Proof pf; 00270 00271 if(withProof()) { 00272 pf = newPf("interchangeIndices", e); 00273 } 00274 00275 Expr w0 = Expr(WRITE, e[0][0], e[1], e[2]); 00276 Expr indexCond = (e[0][1].getType().isBool())? 00277 e[0][1].iffExpr(e[1]) : e[0][1].eqExpr(e[1]); 00278 Expr w2 = Expr(WRITE, w0, e[0][1], indexCond.iteExpr(e[2], e[0][2])); 00279 00280 return newRWTheorem(e, w2, Assumptions::emptyAssump(), pf); 00281 } 00282 00283 Theorem 00284 ArrayTheoremProducer::readArrayLiteral(const Expr& e) { 00285 if(CHECK_PROOFS) { 00286 CHECK_SOUND(e.getKind() == READ, 00287 "ArrayTheoremProducer::readArrayLiteral("+e.toString() 00288 +"):\n\n expression is not a READ"); 00289 } 00290 00291 Expr arrayLit(e[0]); 00292 00293 if (CHECK_PROOFS) { 00294 CHECK_SOUND(arrayLit.isClosure() && arrayLit.getKind()==ARRAY_LITERAL, 00295 "ArrayTheoremProducer::readArrayLiteral("+e.toString()+")"); 00296 } 00297 00298 Expr body(arrayLit.getBody()); 00299 const vector<Expr>& vars = arrayLit.getVars(); 00300 00301 if(CHECK_PROOFS) { 00302 CHECK_SOUND(vars.size() == 1, 00303 "ArrayTheoremProducer::readArrayLiteral("+e.toString()+"):\n" 00304 +"wrong number of bound variables"); 00305 } 00306 00307 // Use the Expr's efficient substitution 00308 vector<Expr> ind; 00309 ind.push_back(e[1]); 00310 body = body.substExpr(vars, ind); 00311 00312 Proof pf; 00313 if(withProof()) 00314 pf = newPf("read_array_literal", e); 00315 return newRWTheorem(e, body, Assumptions::emptyAssump(), pf); 00316 } 00317 00318 00319 Theorem ArrayTheoremProducer::liftReadIte(const Expr& e) 00320 { 00321 if(CHECK_PROOFS) { 00322 CHECK_SOUND(e.getKind() == READ && e[0].getKind() == ITE, 00323 "ArrayTheoremProducer::liftReadIte("+e.toString() 00324 +"):\n\n expression is not READ(ITE..."); 00325 } 00326 00327 const Expr& ite = e[0]; 00328 00329 Proof pf; 00330 if (withProof()) 00331 pf = newPf("lift_read_ite",e); 00332 return newRWTheorem(e, Expr(ITE, ite[0], Expr(READ, ite[1], e[1]), 00333 Expr(READ, ite[2], e[1])), 00334 Assumptions::emptyAssump(), pf); 00335 } 00336 00337 00338 Theorem ArrayTheoremProducer::arrayNotEq(const Theorem& e) 00339 { 00340 if(CHECK_PROOFS) { 00341 CHECK_SOUND(e.getExpr().getKind() == NOT && 00342 e.getExpr()[0].getKind() == EQ && 00343 isArray(d_theoryArray->getBaseType(e.getExpr()[0][0])), 00344 "ArrayTheoremProducer::arrayNotEq("+e.toString() 00345 +"):\n\n expression is ill-formed"); 00346 } 00347 00348 Expr eq = e.getExpr()[0]; 00349 00350 Proof pf; 00351 if (withProof()) 00352 pf = newPf("array_not_eq", e.getProof()); 00353 00354 Type arrType = d_theoryArray->getBaseType(eq[0]); 00355 Type indType = Type(arrType.getExpr()[0]); 00356 Expr var = d_theoryArray->getEM()->newBoundVarExpr(indType); 00357 eq = Expr(READ, eq[0], var).eqExpr(Expr(READ, eq[1], var)); 00358 00359 return newTheorem(d_theoryArray->getEM()->newClosureExpr(EXISTS, var, !eq), 00360 Assumptions(e), pf); 00361 } 00362 00363 Theorem ArrayTheoremProducer::splitOnConstants(const Expr& a, const std::vector<Expr>& consts) { 00364 Theorem res; 00365 Expr result; 00366 00367 vector<Expr> eq; 00368 vector<Expr> diseq; 00369 for (unsigned i = 0; i < consts.size(); ++ i) { 00370 eq.push_back(a.eqExpr(consts[i])); 00371 diseq.push_back(a.eqExpr(consts[i]).notExpr()); 00372 } 00373 00374 if (eq.size() == 1) { 00375 result = eq[0].orExpr(diseq[0]); 00376 } else { 00377 eq.push_back(andExpr(diseq)); 00378 result = orExpr(eq); 00379 } 00380 00381 Proof pf; 00382 if (withProof()) 00383 pf = newPf("splitOnConstants"); 00384 00385 return newTheorem(result, Assumptions::emptyAssump(), pf); 00386 } 00387 00388 Theorem ArrayTheoremProducer::propagateIndexDiseq(const Theorem& read1eqread2isFalse) { 00389 Expr read1eqread2 = read1eqread2isFalse.getLHS(); 00390 Expr read1 = read1eqread2[0]; 00391 Expr read2 = read1eqread2[1]; 00392 Expr i1 = read1[1]; 00393 Expr i2 = read2[1]; 00394 00395 Proof pf; 00396 if (withProof()) 00397 pf = newPf("propagateIndexDiseq", read1eqread2isFalse.getProof()); 00398 00399 return newTheorem(i1.eqExpr(i2).notExpr(), Assumptions(read1eqread2isFalse), pf); 00400 }