CVC3
|
00001 /*****************************************************************************/ 00002 /*! 00003 * \file theory_uf.cpp 00004 * 00005 * Author: Clark Barrett 00006 * 00007 * Created: Fri Jan 24 02:07:59 2003 00008 * 00009 * <hr> 00010 * 00011 * License to use, copy, modify, sell and/or distribute this software 00012 * and its documentation for any purpose is hereby granted without 00013 * royalty, subject to the terms and conditions defined in the \ref 00014 * LICENSE file provided with this distribution. 00015 * 00016 * <hr> 00017 * 00018 */ 00019 /*****************************************************************************/ 00020 00021 #include "theory_uf.h" 00022 #include "uf_proof_rules.h" 00023 #include "typecheck_exception.h" 00024 #include "parser_exception.h" 00025 #include "smtlib_exception.h" 00026 #include "command_line_flags.h" 00027 #include "theory_core.h" 00028 #include "translator.h" 00029 // HACK: include theory_records.h to access the TUPLE_TYPE kind 00030 #include "theory_records.h" 00031 00032 00033 using namespace std; 00034 using namespace CVC3; 00035 00036 00037 /////////////////////////////////////////////////////////////////////////////// 00038 // TheoryUF Public Methods // 00039 /////////////////////////////////////////////////////////////////////////////// 00040 00041 00042 TheoryUF::TheoryUF(TheoryCore* core)//, bool useAckermann) 00043 : Theory(core, "Uninterpreted Functions"), 00044 d_applicationsInModel(core->getFlags()["applications"].getBool()), 00045 d_funApplications(core->getCM()->getCurrentContext()), 00046 d_funApplicationsIdx(core->getCM()->getCurrentContext(), 0), 00047 d_sharedIdx1(core->getCM()->getCurrentContext(), 0), 00048 d_sharedIdx2(core->getCM()->getCurrentContext(), 0), 00049 d_sharedTermsMap(core->getCM()->getCurrentContext()) 00050 // d_useAckermann(useAckermann) 00051 { 00052 d_rules = createProofRules(); 00053 00054 // Register new local kinds with ExprManager 00055 getEM()->newKind(TRANS_CLOSURE, "_TRANS_CLOSURE"); 00056 getEM()->newKind(OLD_ARROW, "_OLD_ARROW", true); 00057 00058 vector<int> kinds; 00059 //TODO: should this stuff really be in theory_uf? 00060 kinds.push_back(TYPEDECL); 00061 kinds.push_back(LAMBDA); 00062 kinds.push_back(ARROW); 00063 kinds.push_back(OLD_ARROW); 00064 kinds.push_back(UFUNC); 00065 kinds.push_back(TRANS_CLOSURE); 00066 00067 registerTheory(this, kinds); 00068 } 00069 00070 00071 TheoryUF::~TheoryUF() { 00072 delete d_rules; 00073 } 00074 00075 00076 //TODO: clean up transitive closure tables 00077 // be sure to free CD objects 00078 00079 void TheoryUF::assertFact(const Theorem& e) 00080 { 00081 const Expr& expr = e.getExpr(); 00082 switch (expr.getKind()) { 00083 case NOT: 00084 break; 00085 case APPLY: 00086 if (expr.getOpExpr().computeTransClosure()) { 00087 enqueueFact(d_rules->relToClosure(e)); 00088 } 00089 else if (expr.getOpKind() == TRANS_CLOSURE) { 00090 // const Expr& rel = expr.getFun(); 00091 DebugAssert(expr.isApply(), "Should be apply"); 00092 Expr rel = resolveID(expr.getOpExpr().getName()); 00093 DebugAssert(!rel.isNull(), "Expected known identifier"); 00094 DebugAssert(rel.isSymbol() && rel.getKind()==UFUNC && expr.arity()==2, 00095 "Unexpected use of transitive closure: "+expr.toString()); 00096 00097 // Insert into transitive closure table 00098 ExprMap<TCMapPair*>::iterator i = d_transClosureMap.find(rel); 00099 TCMapPair* pTable; 00100 if (i == d_transClosureMap.end()) { 00101 pTable = new TCMapPair(); 00102 d_transClosureMap[rel] = pTable; 00103 } 00104 else { 00105 pTable = (*i).second; 00106 } 00107 00108 ExprMap<CDList<Theorem>*>::iterator i2 = pTable->appearsFirstMap.find(expr[0]); 00109 CDList<Theorem>* pList; 00110 if (i2 == pTable->appearsFirstMap.end()) { 00111 pList = new(true) CDList<Theorem>(theoryCore()->getCM()->getCurrentContext()); 00112 pTable->appearsFirstMap[expr[0]] = pList; 00113 } 00114 else { 00115 pList = (*i2).second; 00116 } 00117 pList->push_back(e); 00118 00119 i2 = pTable->appearsSecondMap.find(expr[1]); 00120 if (i2 == pTable->appearsSecondMap.end()) { 00121 pList = new(true) CDList<Theorem>(theoryCore()->getCM()->getCurrentContext()); 00122 pTable->appearsSecondMap[expr[1]] = pList; 00123 } 00124 else { 00125 pList = (*i2).second; 00126 } 00127 pList->push_back(e); 00128 00129 // Compute transitive closure with existing relations 00130 size_t s,l; 00131 i2 = pTable->appearsFirstMap.find(expr[1]); 00132 if (i2 != pTable->appearsFirstMap.end()) { 00133 pList = (*i2).second; 00134 s = pList->size(); 00135 for (l = 0; l < s; ++l) { 00136 enqueueFact(d_rules->relTrans(e,(*pList)[l])); 00137 } 00138 } 00139 00140 i2 = pTable->appearsSecondMap.find(expr[0]); 00141 if (i2 != pTable->appearsSecondMap.end()) { 00142 pList = (*i2).second; 00143 s = pList->size(); 00144 for (l = 0; l < s; ++l) { 00145 enqueueFact(d_rules->relTrans((*pList)[l],e)); 00146 } 00147 } 00148 } 00149 break; 00150 default: 00151 break; 00152 } 00153 } 00154 00155 00156 void TheoryUF::checkSat(bool fullEffort) 00157 { 00158 // Check for any unexpanded lambdas 00159 bool enqueued = false; 00160 for(; d_funApplicationsIdx < d_funApplications.size(); 00161 d_funApplicationsIdx = d_funApplicationsIdx + 1) { 00162 const Expr& e = d_funApplications[d_funApplicationsIdx]; 00163 if(e.getOp().getExpr().isLambda()) { 00164 IF_DEBUG(debugger.counter("Expanded lambdas (checkSat)")++;) 00165 enqueueFact(d_rules->applyLambda(e)); 00166 enqueued = true; 00167 } 00168 } 00169 00170 // If something has been returned, we are done 00171 if (!fullEffort || enqueued) return; 00172 00173 // Expand on the shared terms 00174 for( ; d_sharedIdx1 < d_funApplications.size(); d_sharedIdx1 = d_sharedIdx1 00175 + 1, d_sharedIdx2 = 0 ) { 00176 Expr f1 = d_funApplications[d_sharedIdx1]; 00177 if( f1.getOpKind() == UFUNC && !f1.getSig().isNull() ) { 00178 f1 = f1.getSig().getRHS(); 00179 Expr f1_fun = f1.getOp().getExpr(); 00180 for( ; d_sharedIdx2 < d_sharedIdx1; d_sharedIdx2 = d_sharedIdx2 + 1 ) { 00181 Expr f2 = d_funApplications[d_sharedIdx2]; 00182 if (f2.getOpKind() == UFUNC && !f2.getSig().isNull() ) { 00183 f2 = f2.getSig().getRHS(); 00184 Expr f2_fun = f2.getOp().getExpr(); 00185 if( f1 != f2 && find(f1).getRHS() != find(f2).getRHS() && f1_fun == f2_fun ) { 00186 for( int k = 0; k < f1.arity(); ++k ) { 00187 Expr x_k = f1[k]; 00188 Expr y_k = f2[k]; 00189 if( d_sharedTermsMap.find(x_k) == d_sharedTermsMap.end() ) 00190 continue; 00191 if( d_sharedTermsMap.find(y_k) == d_sharedTermsMap.end() ) 00192 continue; 00193 Expr eq = x_k.eqExpr(y_k); 00194 if( !simplify(eq).getRHS().isBoolConst() ) { 00195 TRACE("sharing", "splitting " + y_k.toString(), " and ", x_k.toString()); 00196 TRACE("sharing", "from " + f2.toString(), " and ", f1.toString()); 00197 addSplitter(eq); 00198 enqueued = true; 00199 } 00200 } 00201 if( enqueued ) 00202 return; 00203 } 00204 } 00205 } 00206 } 00207 } 00208 } 00209 00210 00211 Theorem TheoryUF::rewrite(const Expr& e) 00212 { 00213 if (e.isApply()) { 00214 const Expr& op = e.getOpExpr(); 00215 int opKind = op.getKind(); 00216 switch(opKind) { 00217 case LAMBDA: { 00218 Theorem res = d_rules->applyLambda(e); 00219 // Simplify recursively 00220 res = transitivityRule(res, simplify(res.getRHS())); 00221 IF_DEBUG(debugger.counter("Expanded lambdas")++;) 00222 return res; 00223 } 00224 default: // A truly uninterpreted function 00225 if (e.getType().isBool()) return reflexivityRule(e); 00226 else return rewriteCC(e); 00227 } 00228 } 00229 else { 00230 e.setRewriteNormal(); 00231 return reflexivityRule(e); 00232 } 00233 } 00234 00235 00236 void TheoryUF::setup(const Expr& e) 00237 { 00238 if (e.isTerm() && e.getType().card() != CARD_INFINITE) { 00239 addSharedTerm(e); 00240 theoryOf(e.getType())->addSharedTerm(e); 00241 } 00242 if (e.getKind() != APPLY) return; 00243 // if (d_useAckermann) { 00244 // Theorem thm = getCommonRules()->varIntroSkolem(e); 00245 // theoryCore()->addToVarDB(thm.getRHS()); 00246 // enqueueFact(thm); 00247 // } 00248 // else { 00249 setupCC(e); 00250 // } 00251 // Add this function application for concrete model generation 00252 TRACE("model", "TheoryUF: add function application ", e, ""); 00253 d_funApplications.push_back(e); 00254 } 00255 00256 00257 void TheoryUF::update(const Theorem& e, const Expr& d) 00258 { 00259 /* 00260 int k, ar(d.arity()); 00261 const Theorem& dEQdsig = d.getSig(); 00262 if (!dEQdsig.isNull()) { 00263 Expr dsig = dEQdsig.getRHS(); 00264 Theorem thm = updateHelper(d); 00265 const Expr& sigNew = thm.getRHS(); 00266 if (sigNew == dsig) return; 00267 dsig.setRep(Theorem()); 00268 const Theorem& repEQsigNew = sigNew.getRep(); 00269 if (!repEQsigNew.isNull()) { 00270 d.setSig(Theorem()); 00271 enqueueFact(transitivityRule(repEQsigNew, symmetryRule(thm))); 00272 } 00273 else { 00274 for (k = 0; k < ar; ++k) { 00275 if (sigNew[k] != dsig[k]) { 00276 sigNew[k].addToNotify(this, d); 00277 } 00278 } 00279 d.setSig(thm); 00280 sigNew.setRep(thm); 00281 00282 if (d_compute_trans_closure && d.getKind() == APPLY && 00283 d.arity() == 2 && findExpr(d).isTrue()) { 00284 thm = iffTrueElim(transitivityRule(symmetryRule(thm),find(d))); 00285 enqueueFact(d_rules->relToClosure(thm)); 00286 } 00287 00288 } 00289 } 00290 */ 00291 // Record the original signature 00292 const Theorem& dEQdsig = d.getSig(); 00293 if (!dEQdsig.isNull()) { 00294 const Expr& dsig = dEQdsig.getRHS(); 00295 Theorem thm = updateHelper(d); 00296 const Expr& sigNew = thm.getRHS(); 00297 if (sigNew == dsig) { 00298 // TRACE_MSG("facts update", "updateCC["+getName()+"]() [no change] => }"); 00299 return; 00300 } 00301 dsig.setRep(Theorem()); 00302 const Theorem& repEQsigNew = sigNew.getRep(); 00303 if (!repEQsigNew.isNull()) { 00304 d.setSig(Theorem()); 00305 enqueueFact(transitivityRule(repEQsigNew, symmetryRule(thm))); 00306 } 00307 else if (d.getType().isBool()) { 00308 d.setSig(Theorem()); 00309 enqueueFact(thm); 00310 } 00311 else { 00312 int k, ar(d.arity()); 00313 for (k = 0; k < ar; ++k) { 00314 if (sigNew[k] != dsig[k]) { 00315 sigNew[k].addToNotify(this, d); 00316 } 00317 } 00318 d.setSig(thm); 00319 sigNew.setRep(thm); 00320 if (dsig != sigNew && d.isApply() && findExpr(d).isTrue()) { 00321 if (d.getOpExpr().computeTransClosure()) { 00322 thm = getCommonRules()->iffTrueElim(transitivityRule(symmetryRule(thm), 00323 find(d))); 00324 enqueueFact(d_rules->relToClosure(thm)); 00325 } 00326 else if (d.getOpKind() == TRANS_CLOSURE) { 00327 thm = getCommonRules()->iffTrueElim(transitivityRule(symmetryRule(thm), 00328 find(d))); 00329 enqueueFact(thm); 00330 } 00331 } 00332 } 00333 } 00334 } 00335 00336 00337 void TheoryUF::checkType(const Expr& e) 00338 { 00339 switch (e.getKind()) { 00340 case ARROW: { 00341 if (e.arity() < 2) throw Exception 00342 ("Function type needs at least two arguments" 00343 +e.toString()); 00344 Expr::iterator i = e.begin(), iend = e.end(); 00345 for (; i != iend; ) { 00346 Type t(*i); 00347 ++i; 00348 if (i == iend && t.isBool()) break; 00349 if (t.isBool()) throw Exception 00350 ("Function argument types must be non-Boolean: " 00351 +e.toString()); 00352 if (t.isFunction()) throw Exception 00353 ("Function domain or range types cannot be functions: " 00354 +e.toString()); 00355 } 00356 break; 00357 } 00358 case TYPEDECL: { 00359 break; 00360 } 00361 default: 00362 DebugAssert(false, "Unexpected kind in TheoryUF::checkType" 00363 +getEM()->getKindName(e.getKind())); 00364 } 00365 } 00366 00367 00368 Cardinality TheoryUF::finiteTypeInfo(Expr& e, Unsigned& n, 00369 bool enumerate, bool computeSize) 00370 { 00371 if (e.getKind() != ARROW) { 00372 // uninterpreted type 00373 return CARD_UNKNOWN; 00374 } 00375 Expr::iterator i = e.begin(), iend = e.end(); 00376 Cardinality card = CARD_FINITE, cardTmp; 00377 Unsigned thisSize = 1, size; 00378 bool getSize = enumerate || computeSize; 00379 for (; i != iend; ) { 00380 Expr e2 = (*i); 00381 cardTmp = theoryOf(e2)->finiteTypeInfo(e2, size, getSize, false); 00382 if (cardTmp == CARD_INFINITE) { 00383 return CARD_INFINITE; 00384 } 00385 else if (cardTmp == CARD_UNKNOWN) { 00386 card = CARD_UNKNOWN; 00387 getSize = false; 00388 // Keep looking to see if we can determine it is infinite 00389 } 00390 else if (getSize) { 00391 thisSize = thisSize * size; 00392 // Give up if it gets too big 00393 if (thisSize > 1000000) thisSize = 0; 00394 if (thisSize == 0) { 00395 getSize = false; 00396 } 00397 } 00398 } 00399 00400 if (card == CARD_FINITE) { 00401 00402 if (enumerate) { 00403 // TODO: enumerate functions? maybe at least n == 0 00404 e = Expr(); 00405 } 00406 00407 if (computeSize) { 00408 n = thisSize; 00409 } 00410 00411 } 00412 00413 return card; 00414 } 00415 00416 00417 void TheoryUF::computeType(const Expr& e) 00418 { 00419 switch (e.getKind()) { 00420 case LAMBDA: { 00421 vector<Type> args; 00422 const vector<Expr>& vars = e.getVars(); 00423 DebugAssert(vars.size() > 0, 00424 "TheorySimulate::computeType("+e.toString()+")"); 00425 for(vector<Expr>::const_iterator i=vars.begin(), iend=vars.end(); 00426 i!=iend; ++i) 00427 args.push_back((*i).getType()); 00428 e.setType(Type::funType(args, e.getBody().getType())); 00429 break; 00430 } 00431 case APPLY: { 00432 theoryOf(APPLY)->computeType(e); 00433 break; 00434 } 00435 case TRANS_CLOSURE: { 00436 DebugAssert(e.isSymbol(), "Expected symbol"); 00437 Expr funExpr = resolveID(e.getName()); 00438 if (funExpr.isNull()) { 00439 throw TypecheckException 00440 ("Attempt to take transitive closure of unknown id: " 00441 +e.getName()); 00442 } 00443 Type funType = funExpr.getType(); 00444 if(!funType.isFunction()) { 00445 throw TypecheckException 00446 ("Attempt to take transitive closure of non-function:\n\n" 00447 +funExpr.toString() + "\n\n which has type: " 00448 +funType.toString()); 00449 } 00450 if(funType.arity()!=3) { 00451 throw TypecheckException 00452 ("Attempt to take transitive closure of non-binary function:\n\n" 00453 +funExpr.toString() + "\n\n which has type: " 00454 +funType.toString()); 00455 } 00456 if (!funType[2].isBool()) { 00457 throw TypecheckException 00458 ("Attempt to take transitive closure of function:\n\n" 00459 +funExpr.toString() + "\n\n which does not return BOOLEAN"); 00460 } 00461 e.setType(funType); 00462 break; 00463 } 00464 default: 00465 DebugAssert(false,"Unexpected type: "+e.toString()); 00466 break; 00467 } 00468 } 00469 00470 00471 Type TheoryUF::computeBaseType(const Type& t) { 00472 const Expr& e = t.getExpr(); 00473 switch(e.getKind()) { 00474 case ARROW: { 00475 DebugAssert(e.arity() > 0, "Expected non-empty ARROW"); 00476 vector<Expr> kids; 00477 for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { 00478 kids.push_back(getBaseType(Type(*i)).getExpr()); 00479 } 00480 return Type(Expr(e.getOp(), kids)); 00481 } 00482 case TYPEDECL: return t; 00483 default: 00484 DebugAssert(false, 00485 "TheoryUF::computeBaseType("+t.toString()+")"); 00486 return t; 00487 } 00488 } 00489 00490 00491 void TheoryUF::computeModelTerm(const Expr& e, std::vector<Expr>& v) { 00492 for(CDList<Expr>::const_iterator i=d_funApplications.begin(), 00493 iend=d_funApplications.end(); i!=iend; ++i) { 00494 if((*i).isApply() && (*i).getOp().getExpr() == e) { 00495 // Add both the function application 00496 // getModelTerm(*i, v); 00497 v.push_back(*i); 00498 // and the arguments to the model terms. Reason: the argument 00499 // to the function better be a concrete value, and it might not 00500 // necessarily be in the current list of model terms. 00501 for(Expr::iterator j=(*i).begin(), jend=(*i).end(); j!=jend; ++j) 00502 // getModelTerm(*j, v); 00503 v.push_back(*j); 00504 } 00505 } 00506 } 00507 00508 00509 void TheoryUF::computeModel(const Expr& e, std::vector<Expr>& vars) { 00510 // Repeat the same search for applications of e as in 00511 // computeModelTerm(), but this time get the concrete values of the 00512 // arguments, and return the applications of e to concrete values in 00513 // vars. 00514 00515 // We'll assign 'e' a value later. 00516 vars.push_back(e); 00517 // Map of f(c) to val for concrete values of c and val 00518 ExprHashMap<Expr> appls; 00519 for(CDList<Expr>::const_iterator i=d_funApplications.begin(), 00520 iend=d_funApplications.end(); i!=iend; ++i) { 00521 if((*i).isApply() && (*i).getOp().getExpr() == e) { 00522 // Update all arguments with concrete values 00523 vector<Theorem> thms; 00524 vector<unsigned> changed; 00525 for(int j=0; j<(*i).arity(); ++j) { 00526 Theorem asst(getModelValue((*i)[j])); 00527 if(asst.getLHS()!=asst.getRHS()) { 00528 thms.push_back(asst); 00529 changed.push_back(j); 00530 } 00531 } 00532 Expr var; 00533 if(changed.size()>0) { 00534 // Arguments changed. Compute the new application, and assign 00535 // it a concrete value 00536 Theorem subst = substitutivityRule(*i, changed, thms); 00537 assignValue(transitivityRule(symmetryRule(subst), getModelValue(*i))); 00538 var = subst.getRHS(); 00539 } else 00540 var = *i; 00541 if(d_applicationsInModel) vars.push_back(var); 00542 // Record it in the map 00543 appls[var] = getModelValue(var).getRHS(); 00544 } 00545 } 00546 // Create a LAMBDA expression for e 00547 if(appls.size()==0) { // Leave it fully uninterpreted 00548 assignValue(reflexivityRule(e)); 00549 } else { 00550 // Bound vars 00551 vector<Expr> args; 00552 Type tp(e.getType()); 00553 static unsigned count(0); 00554 DebugAssert(tp.isFunction(), "TheoryUF::computeModel("+e.toString() 00555 +" : "+tp.toString()+")"); 00556 for(int i=0, iend=tp.arity()-1; i<iend; ++i) { 00557 string str = "uf_"+int2string(count); 00558 Expr v = getEM()->newBoundVarExpr(str, int2string(count++)); 00559 v.setType(tp[i]); 00560 args.push_back(v); 00561 } 00562 DebugAssert(args.size()>0, "TheoryUF::computeModel()"); 00563 ExprHashMap<Expr>::iterator i=appls.begin(), iend=appls.end(); 00564 DebugAssert(i!=iend, "TheoryUF::computeModel(): empty appls hash"); 00565 // Use one of the concrete values as a default 00566 Expr res((*i).second); ++i; 00567 for(; i!=iend; ++i) { 00568 // Optimization: if the current value is the same as that of the 00569 // next application, skip this case; i.e. keep 'res' instead of 00570 // building ite(cond, res, res). 00571 if((*i).second == res) continue; 00572 00573 // Create an ITE condition 00574 Expr cond; 00575 vector<Expr> eqs; 00576 for(int j=0, jend=args.size(); j<jend; ++j) 00577 eqs.push_back(args[j].eqExpr((*i).first[j])); 00578 if(eqs.size()==1) 00579 cond = eqs[0]; 00580 else 00581 cond = andExpr(eqs); 00582 // Create an ITE 00583 res = cond.iteExpr((*i).second, res); 00584 } 00585 res = lambdaExpr(args, res); 00586 assignValue(e, res); 00587 } 00588 } 00589 00590 00591 Expr TheoryUF::computeTCC(const Expr& e) 00592 { 00593 switch (e.getKind()) { 00594 case APPLY: { 00595 // Compute subtype predicates from the domain types applied to 00596 // the corresponding arguments. That is, if f: (T0,..,Tn)->T, 00597 // and e = f(e0,...,en), then the TCC is 00598 // 00599 // pred_T0(e0) & ... & pred_Tn(en) & TCC(e), 00600 // 00601 // where the last TCC(e) is the conjunction of TCCs for the 00602 // arguments, which ensures that all arguments are defined. 00603 // 00604 // If the operator is a lambda-expression, compute the TCC for 00605 // the beta-reduced expression. We do this in a somewhat sneaky 00606 // but an efficient way: first, compute TCC of the op.body 00607 // (which depends on the bound vars), then wrap that into 00608 // lambda, and apply it to the arguments: 00609 // 00610 // (LAMBDA(x0...xn): TCC(op.body)) (e0 ... en) 00611 // 00612 // The reason it is more efficient is that TCC(op.body) is cached, 00613 // and doesn't change with the arguments. 00614 00615 vector<Expr> preds; 00616 preds.push_back(Theory::computeTCC(e)); 00617 DebugAssert(e.isApply(), "Should be application"); 00618 Expr op(e.getOp().getExpr()); 00619 Type funType(op.getType()); 00620 DebugAssert(funType.isFunction() || funType.isBool(), 00621 "TheoryUF::computeTCC(): funType = " 00622 +funType.toString()); 00623 if(funType.isFunction()) { 00624 DebugAssert(funType.arity() == e.arity()+1, 00625 "TheoryUF::computeTCC(): funType = " 00626 +funType.toString()+"\n e = "+e.toString()); 00627 for(int i=0, iend=e.arity(); i<iend; ++i) { 00628 // Optimization: if the type of the formal argument is 00629 // exactly the same as the type of the actual, then skip the 00630 // type predicate for that argument 00631 if(funType[i] != e[i].getType()) 00632 preds.push_back(getTypePred(funType[i], e[i])); 00633 } 00634 } 00635 // Now strip off all the LETDECL 00636 while(op.getKind()==LETDECL) op = op[1]; 00637 // and add a TCC for the lambda-expression 00638 if(op.isLambda()) { 00639 preds.push_back(Expr(lambdaExpr(op.getVars(), 00640 getTCC(op.getBody())).mkOp(), 00641 e.getKids())); 00642 } 00643 return rewriteAnd(andExpr(preds)).getRHS(); 00644 } 00645 case LAMBDA: 00646 return trueExpr(); 00647 default: 00648 DebugAssert(false,"Unexpected type: "+e.toString()); 00649 return trueExpr(); 00650 } 00651 } 00652 00653 /////////////////////////////////////////////////////////////////////////////// 00654 // Pretty-printing // 00655 /////////////////////////////////////////////////////////////////////////////// 00656 00657 void TheoryUF::printSmtLibShared(ExprStream& os, const Expr& e) { 00658 DebugAssert( os.lang() == SMTLIB_LANG || os.lang() == SMTLIB_V2_LANG, "Illegal state in printSmtLibShared"); 00659 switch( e.getKind() ) { 00660 case TYPEDECL: 00661 if( e.arity() == 1 && e[0].isString() ) { 00662 os << e[0].getString(); 00663 break; 00664 } 00665 // If it's straight from the parser, we may have several type 00666 // names in one declaration. Print these in LISP format. 00667 // Otherwise, print the name of the type. 00668 throw SmtlibException("TheoryUF::print: TYPEDECL not supported"); 00669 // if(e.arity() != 1) e.print(os); 00670 // else if(e[0].isString()) os << e[0].getString(); 00671 // else e[0].print(os); 00672 break; 00673 case APPLY: 00674 if( e.arity() == 0 ) 00675 os << e.getOp().getExpr(); 00676 else { 00677 os << "(" << push << e.getOp().getExpr(); 00678 for( int i = 0, iend = e.arity(); i < iend; ++i ) 00679 os << space << e[i]; 00680 if( e.getOpKind() == TRANS_CLOSURE ) { 00681 os << space << ":transclose"; 00682 } 00683 os << push << ")"; 00684 } 00685 break; 00686 case TRANS_CLOSURE: 00687 os << e.getName(); 00688 break; 00689 case UFUNC: 00690 DebugAssert(e.isSymbol(), "Expected symbol"); 00691 os << theoryCore()->getTranslator()->fixConstName(e.getName()); 00692 break; 00693 default: { 00694 DebugAssert(false, "TheoryUF::print: SMTLIB_LANG: Unexpected expression: " 00695 +getEM()->getKindName(e.getKind())); 00696 } 00697 } 00698 } 00699 00700 ExprStream& TheoryUF::print(ExprStream& os, const Expr& e) { 00701 switch(os.lang()) { 00702 case SIMPLIFY_LANG: 00703 switch(e.getKind()) { 00704 case OLD_ARROW: 00705 case ARROW: 00706 os<<"ERROR:ARROW:unsupported in Simplify\n"; 00707 break; 00708 case LAMBDA: { 00709 os<<"ERROR:LAMBDA:unsupported in Simplify\n"; 00710 break; 00711 } 00712 case TRANS_CLOSURE: 00713 os<<"ERROR:TRANS_CLOSURE:unsupported in Simplify\n"; 00714 break; 00715 case TYPEDECL: 00716 os<<"ERROR:TYPEDECL:unsupported in Simplify\n"; 00717 break; 00718 case UFUNC: 00719 case APPLY: 00720 if(e.isApply()) os << "(" << e.getOp().getExpr()<<" "; 00721 if(e.arity() > 0) { 00722 bool first(true); 00723 for (Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { 00724 if(first) first = false; 00725 else os << " " ; 00726 os << *i; 00727 } 00728 os << ")"; 00729 } 00730 break; 00731 default: { 00732 DebugAssert(false, "TheoryUF::print: Unexpected expression: " 00733 +getEM()->getKindName(e.getKind())); 00734 } 00735 } 00736 break; // end of case SIMPLIFY_LANGUAGE 00737 00738 case TPTP_LANG: 00739 switch(e.getKind()) { 00740 case OLD_ARROW: 00741 case ARROW: 00742 if(e.arity() < 2) e.printAST(os); 00743 else { 00744 os << "(" << push; 00745 bool first(true); 00746 for(int i=0, iend=e.arity()-1; i<iend; ++i) { 00747 if(first) first=false; 00748 else os << " * " ; 00749 os << e[i]; 00750 } 00751 os << ")" ; 00752 os << " > " << e[e.arity()-1]; 00753 } 00754 break; 00755 00756 case LAMBDA: { 00757 os<<"ERROR:LAMBDA:unsupported in TPTP\n"; 00758 break; 00759 } 00760 case TRANS_CLOSURE: 00761 os<<"ERROR:TRANS_CLOSURE:unsupported in TPTP\n"; 00762 break; 00763 case TYPEDECL: 00764 if(e.arity() != 1) e.printAST(os); 00765 else os << e[0].getString(); 00766 break; 00767 00768 case UFUNC: 00769 DebugAssert(e.isSymbol(), "Expected symbol"); 00770 os << to_lower(e.getName()); 00771 break; 00772 00773 case APPLY: 00774 if(e.isApply()) os <<e.getOpExpr()<<"("; 00775 if(e.arity() > 0) { 00776 bool first(true); 00777 for (Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { 00778 if(first) first = false; 00779 else os << "," ; 00780 os << *i; 00781 } 00782 os << ")"; 00783 } 00784 break; 00785 default: { 00786 DebugAssert(false, "TheoryUF::print: Unexpected expression: " 00787 +getEM()->getKindName(e.getKind())); 00788 } 00789 } 00790 break; // end of case TPTP_LANGUAGE 00791 00792 00793 case PRESENTATION_LANG: 00794 switch(e.getKind()) { 00795 case OLD_ARROW: 00796 case ARROW: 00797 if(e.arity() < 2) e.printAST(os); 00798 else { 00799 if(e.arity() == 2) 00800 os << e[0]; 00801 else { 00802 os << "(" << push; 00803 bool first(true); 00804 for(int i=0, iend=e.arity()-1; i<iend; ++i) { 00805 if(first) first=false; 00806 else os << "," << space; 00807 os << e[i]; 00808 } 00809 os << push << ")" << pop << pop; 00810 } 00811 os << space << "->" << space << e[e.arity()-1]; 00812 } 00813 break; 00814 case TYPEDECL: 00815 // If it's straight from the parser, we may have several type 00816 // names in one declaration. Print these in LISP format. 00817 // Otherwise, print the name of the type. 00818 if(e.arity() != 1) e.printAST(os); 00819 else os << e[0].getString(); 00820 break; 00821 case LAMBDA: { 00822 DebugAssert(e.isLambda(), "Expected Lambda"); 00823 os << "(" << push << "LAMBDA" << space << push; 00824 const vector<Expr>& vars = e.getVars(); 00825 bool first(true); 00826 os << "(" << push; 00827 for(vector<Expr>::const_iterator i=vars.begin(), iend=vars.end(); 00828 i!=iend; ++i) { 00829 if(first) first = false; 00830 else os << push << "," << pop << space; 00831 os << *i; 00832 // The lambda Expr may be in a raw parsed form, in which case 00833 // the type is not assigned yet 00834 if(i->isVar()) 00835 os << ":" << space << pushdag << (*i).getType() << popdag; 00836 } 00837 os << push << "): " << pushdag << push 00838 << e.getBody() << push << ")"; 00839 break; 00840 } 00841 case APPLY: 00842 os << e.getOpExpr(); 00843 if(e.arity() > 0) { 00844 os << "(" << push; 00845 bool first(true); 00846 for (Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) { 00847 if(first) first = false; 00848 else os << "," << space; 00849 os << *i; 00850 } 00851 os << push << ")"; 00852 } 00853 break; 00854 case TRANS_CLOSURE: 00855 DebugAssert(e.isSymbol(), "Expected symbol"); 00856 os << e.getName() << "*"; 00857 break; 00858 case UFUNC: 00859 DebugAssert(e.isSymbol(), "Expected symbol"); 00860 os << e.getName(); 00861 break; 00862 default: { 00863 DebugAssert(false, "TheoryUF::print: Unexpected expression: " 00864 +getEM()->getKindName(e.getKind())); 00865 } 00866 } 00867 break; // end of case PRESENTATION_LANGUAGE 00868 case SMTLIB_LANG: 00869 switch(e.getKind()) { 00870 case OLD_ARROW: 00871 case ARROW: { 00872 if(e.arity() < 2) { 00873 throw SmtlibException("TheoryUF::print: Expected 2 or more arguments to ARROW"); 00874 // e.print(os); 00875 } 00876 d_theoryUsed = true; 00877 os << push; 00878 bool oldDagFlag = os.dagFlag(false); 00879 int iend = e.arity(); 00880 if (e[iend-1].getKind() == BOOLEAN) --iend; 00881 for(int i=0; i<iend; ++i) { 00882 if (i != 0) os << space; 00883 os << e[i]; 00884 } 00885 os.dagFlag(oldDagFlag); 00886 break; 00887 } 00888 default: 00889 printSmtLibShared(os,e); 00890 } 00891 break; // End of SMT_LIB 00892 case SMTLIB_V2_LANG: 00893 switch(e.getKind()) { 00894 case OLD_ARROW: 00895 case ARROW: { 00896 /* Prints out a function type (A,B,C) -> D as "(A B C) D" */ 00897 if(e.arity() < 2) { 00898 throw SmtlibException("TheoryUF::print: Expected 2 or more arguments to ARROW"); 00899 // e.print(os); 00900 } 00901 d_theoryUsed = true; 00902 bool oldDagFlag = os.dagFlag(false); 00903 os << push << "("; 00904 for( int i = 0; i < e.arity() - 1; ++i ) { 00905 if( i != 0 ) { 00906 os << space; 00907 } 00908 os << e[i]; 00909 } 00910 os << ")" << space << e[e.arity() - 1] << pop ; 00911 os.dagFlag(oldDagFlag); 00912 break; 00913 } 00914 default: 00915 printSmtLibShared(os,e); 00916 } 00917 break; // End of SMT-LIB v2 00918 case LISP_LANG: 00919 switch(e.getKind()) { 00920 case OLD_ARROW: 00921 case ARROW: 00922 if(e.arity() < 2) e.printAST(os); 00923 os << "(" << push << "ARROW"; 00924 for(int i=0, iend=e.arity(); i<iend; ++i) 00925 os << space << e[i]; 00926 os << push << ")"; 00927 break; 00928 case TRANS_CLOSURE: 00929 e.printAST(os); 00930 break; 00931 case TYPEDECL: 00932 // If it's straight from the parser, we may have several type 00933 // names in one declaration. Print these in LISP format. 00934 // Otherwise, print the name of the type. 00935 if(e.arity() != 1) e.printAST(os); 00936 else if(e[0].isString()) os << e[0].getString(); 00937 else e[0].print(os); 00938 break; 00939 case LAMBDA: { 00940 DebugAssert(e.isLambda(), "Expected LAMBDA"); 00941 os << "(" << push << "LAMBDA" << space; 00942 const vector<Expr>& vars = e.getVars(); 00943 bool first(true); 00944 os << "(" << push; 00945 for(vector<Expr>::const_iterator i=vars.begin(), iend=vars.end(); 00946 i!=iend; ++i) { 00947 if(first) first = false; 00948 else os << space; 00949 os << "(" << push << *i; 00950 // The expression may be in a raw parsed form, in which case 00951 // the type is not assigned yet 00952 if(i->isVar()) 00953 os << space << pushdag << (*i).getType() << popdag; 00954 os << push << ")" << pop << pop; 00955 } 00956 os << push << ")" << pop << pop << pushdag 00957 << e.getBody() << push << ")"; 00958 break; 00959 } 00960 case APPLY: 00961 DebugAssert(e.isApply(), "Expected Apply"); 00962 if (e.arity() == 0) os << e.getOp().getExpr(); 00963 else { 00964 os << "(" << push << e.getOp().getExpr(); 00965 for (int i=0, iend=e.arity(); i<iend; ++i) 00966 os << space << e[i]; 00967 os << push << ")"; 00968 } 00969 break; 00970 default: { 00971 DebugAssert(false, "TheoryUF::print: Unexpected expression: " 00972 +getEM()->getKindName(e.getKind())); 00973 } 00974 } 00975 break; // End of LISP_LANG 00976 case SPASS_LANG: 00977 switch(e.getKind()) { 00978 case UFUNC: 00979 os << e.getName(); 00980 break; 00981 case APPLY: 00982 os << push << e.getOp().getExpr(); 00983 if(e.arity() > 0) { 00984 os << "(" << e[0]; 00985 for (int i=1, iend=e.arity(); i<iend; ++i) 00986 os << "," << space << e[i]; 00987 os << ")"; 00988 } 00989 os << push; 00990 break; 00991 case OLD_ARROW: 00992 case ARROW: 00993 case TRANS_CLOSURE: 00994 case TYPEDECL: 00995 case LAMBDA: 00996 default: 00997 throw SmtlibException("TheoryUF::print: Unexpected expression for SPASS_LANG: " 00998 +getEM()->getKindName(e.getKind())); 00999 } 01000 break; 01001 default: 01002 // Print the top node in the default format, continue with 01003 // pretty-printing for children. 01004 e.printAST(os); 01005 break; 01006 } 01007 return os; 01008 } 01009 01010 ////////////////////////////////////////////////////////////////////////////// 01011 //parseExprOp: 01012 //translating special Exprs to regular EXPR?? 01013 /////////////////////////////////////////////////////////////////////////////// 01014 Expr 01015 TheoryUF::parseExprOp(const Expr& e) { 01016 // If the expression is not a list, it must have been already 01017 // parsed, so just return it as is. 01018 if(RAW_LIST != e.getKind()) return e; 01019 01020 DebugAssert(e.arity() > 0, 01021 "TheoryUF::parseExprOp:\n e = "+e.toString()); 01022 01023 if (e[0].getKind() == RAW_LIST) { 01024 if(e.arity() < 2) 01025 throw ParserException("Bad function application: "+e.toString()); 01026 Expr::iterator i=e.begin(), iend=e.end(); 01027 Expr op(parseExpr(*i)); ++i; 01028 vector<Expr> args; 01029 for(; i!=iend; ++i) args.push_back(parseExpr(*i)); 01030 return Expr(op.mkOp(), args); 01031 } 01032 01033 DebugAssert(e[0].getKind() == ID || e[0][0].getKind() == ID, 01034 "Expected identifier"); 01035 int kind = e[0].getKind(); 01036 if (kind == ID) kind = getEM()->getKind(e[0][0].getString()); 01037 switch(kind) { 01038 case OLD_ARROW: { 01039 if (!theoryCore()->getFlags()["old-func-syntax"].getBool()) { 01040 throw ParserException("You seem to be using the old syntax for function types.\n" 01041 "Please convert to the new syntax or run with +old-func-syntax"); 01042 } 01043 DebugAssert(e.arity()==3,"Expected arity 3 in OLD_ARROW"); 01044 Expr arg = parseExpr(e[1]); 01045 vector<Expr> k; 01046 if (arg.getOpKind() == TUPLE_TYPE) { 01047 Expr::iterator i = arg.begin(), iend=arg.end(); 01048 for (; i != iend; ++i) { 01049 k.push_back(*i); 01050 } 01051 } 01052 else k.push_back(arg); 01053 k.push_back(parseExpr(e[2])); 01054 return Expr(ARROW, k); 01055 } 01056 case ARROW: 01057 case TYPEDECL: { 01058 vector<Expr> k; 01059 Expr::iterator i = e.begin(), iend=e.end(); 01060 // Skip first element of the vector of kids in 'e'. 01061 // The first element is the operator. 01062 ++i; 01063 // Parse the kids of e and push them into the vector 'k' 01064 for(; i!=iend; ++i) 01065 k.push_back(parseExpr(*i)); 01066 return Expr(kind, k, e.getEM()); 01067 break; 01068 } 01069 case TRANS_CLOSURE: { 01070 if(e.arity() != 4) 01071 throw ParserException("Wrong number of arguments to " 01072 "TRANS_CLOSURE expression\n" 01073 " (expected 3 arguments): "+e.toString()); 01074 const string& name = e[1][0].getString(); 01075 Expr funExpr = resolveID(name); 01076 if (funExpr.isNull()) 01077 throw ParserException("Attempt to take transitive closure of unknown " 01078 "predicate"+name); 01079 return transClosureExpr(name, parseExpr(e[2]), parseExpr(e[3])); 01080 } 01081 case LAMBDA: { // (LAMBDA ((v1 ... vn tp1) ...) body) 01082 if(!(e.arity() == 3 && e[1].getKind() == RAW_LIST && e[1].arity() > 0)) 01083 throw ParserException("Bad LAMBDA expression: "+e.toString()); 01084 // Iterate through the groups of bound variables 01085 vector<pair<string,Type> > vars; // temporary stack of bound variables 01086 for(Expr::iterator i=e[1].begin(), iend=e[1].end(); i!=iend; ++i) { 01087 if(i->getKind() != RAW_LIST || i->arity() < 2) 01088 throw ParserException("Bad variable declaration block in LAMBDA " 01089 "expression: "+i->toString()+ 01090 "\n e = "+e.toString()); 01091 // Iterate through individual bound vars in the group. The 01092 // last element is the type, which we have to rebuild and 01093 // parse, since it is used in the creation of bound variables. 01094 Type tp(parseExpr((*i)[i->arity()-1])); 01095 for(int j=0, jend=i->arity()-1; j<jend; ++j) { 01096 if((*i)[j].getKind() != ID) 01097 throw ParserException("Bad variable declaration in LAMBDA" 01098 " expression: "+(*i)[j].toString()+ 01099 "\n e = "+e.toString()); 01100 vars.push_back(pair<string,Type>((*i)[j][0].getString(), tp)); 01101 } 01102 } 01103 // Create all the bound vars and save them in a vector 01104 vector<Expr> boundVars; 01105 for(vector<pair<string,Type> >::iterator i=vars.begin(), iend=vars.end(); 01106 i!=iend; ++i) 01107 boundVars.push_back(addBoundVar(i->first, i->second)); 01108 // Rebuild the body 01109 Expr body(parseExpr(e[2])); 01110 // Build the resulting Expr as (LAMBDA (vars) body) 01111 return lambdaExpr(boundVars, body); 01112 break; 01113 } 01114 case RAW_LIST: // Lambda application 01115 default: { // Application of an uninterpreted function 01116 if(e.arity() < 2) 01117 throw ParserException("Bad function application: "+e.toString()); 01118 Expr::iterator i=e.begin(), iend=e.end(); 01119 Expr op(parseExpr(*i)); ++i; 01120 vector<Expr> args; 01121 for(; i!=iend; ++i) args.push_back(parseExpr(*i)); 01122 return Expr(op.mkOp(), args); 01123 } 01124 } 01125 return e; 01126 } 01127 01128 01129 Expr TheoryUF::lambdaExpr(const vector<Expr>& vars, const Expr& body) { 01130 return getEM()->newClosureExpr(LAMBDA, vars, body); 01131 } 01132 01133 01134 Expr TheoryUF::transClosureExpr(const std::string& name, const Expr& e1, 01135 const Expr& e2) { 01136 return Expr(getEM()->newSymbolExpr(name, TRANS_CLOSURE).mkOp(), e1, e2); 01137 } 01138 01139 void TheoryUF::addSharedTerm(const CVC3::Expr& e) { 01140 d_sharedTermsMap[e] = true; 01141 }