CVC3

theory_uf.cpp

Go to the documentation of this file.
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 }