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  * Copyright (C) 2003 by the Board of Trustees of Leland Stanford
00011  * Junior University and by New York University. 
00012  *
00013  * License to use, copy, modify, sell and/or distribute this software
00014  * and its documentation for any purpose is hereby granted without
00015  * royalty, subject to the terms and conditions defined in the \ref
00016  * LICENSE file provided with this distribution.  In particular:
00017  *
00018  * - The above copyright notice and this permission notice must appear
00019  * in all copies of the software and related documentation.
00020  *
00021  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00022  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00023  * 
00024  * <hr>
00025  * 
00026  */
00027 /*****************************************************************************/
00028 
00029 #include "theory_uf.h"
00030 #include "uf_proof_rules.h"
00031 #include "typecheck_exception.h"
00032 #include "parser_exception.h"
00033 #include "smtlib_exception.h"
00034 #include "command_line_flags.h"
00035 #include "theory_core.h"
00036 // HACK: include theory_records.h to access the TUPLE_TYPE kind
00037 #include "theory_records.h"
00038 
00039 
00040 using namespace std;
00041 using namespace CVCL;
00042 
00043 
00044 ///////////////////////////////////////////////////////////////////////////////
00045 // TheoryUF Public Methods                                                   //
00046 ///////////////////////////////////////////////////////////////////////////////
00047 
00048 
00049 TheoryUF::TheoryUF(TheoryCore* core)
00050   : Theory(core, "Uninterpreted Functions"),
00051     d_applicationsInModel(core->getFlags()["applications"].getBool()),
00052     d_funApplications(core->getCM()->getCurrentContext()),
00053     d_funApplicationsIdx(core->getCM()->getCurrentContext(), 0)
00054 {
00055   d_rules = createProofRules();
00056 
00057   // Register new local kinds with ExprManager
00058   getEM()->newKind(TRANS_CLOSURE, "TRANS_CLOSURE");
00059   getEM()->newKind(OLD_ARROW, "OLD_ARROW", true);
00060   getEM()->newKind(ANY_TYPE, "ANY_TYPE", true);
00061 
00062   vector<int> kinds;
00063   //TODO: should this stuff really be in theory_uf?
00064   kinds.push_back(TYPEDECL);
00065   kinds.push_back(LAMBDA);
00066   kinds.push_back(ARROW);
00067   kinds.push_back(OLD_ARROW);
00068   kinds.push_back(ANY_TYPE);
00069   kinds.push_back(UFUNC);
00070   kinds.push_back(TRANS_CLOSURE);
00071 
00072   registerTheory(this, kinds);
00073 
00074   d_anyType = Type(getEM()->newLeafExpr(ANY_TYPE));
00075 }
00076 
00077 
00078 TheoryUF::~TheoryUF() {
00079   delete d_rules;
00080 }
00081 
00082 
00083 //TODO: clean up transitive closure tables
00084 
00085 
00086 void TheoryUF::assertFact(const Theorem& e)
00087 {
00088   const Expr& expr = e.getExpr();
00089   switch (expr.getKind()) {
00090     case NOT:
00091       break;
00092     case APPLY:
00093       if (expr.getOpExpr().computeTransClosure()) {
00094         enqueueFact(d_rules->relToClosure(e));
00095       }
00096       else if (expr.getOpKind() == TRANS_CLOSURE) {
00097         // const Expr& rel = expr.getFun();
00098         DebugAssert(expr.isApply(), "Should be apply");
00099         Expr rel = resolveID(expr.getOpExpr().getName());
00100         DebugAssert(!rel.isNull(), "Expected known identifier");
00101         DebugAssert(rel.isSymbol() && rel.getKind()==UFUNC && expr.arity()==2,
00102                     "Unexpected use of transitive closure: "+expr.toString());
00103 
00104         // Insert into transitive closure table
00105         ExprMap<TCMapPair*>::iterator i = d_transClosureMap.find(rel);
00106         TCMapPair* pTable;
00107         if (i == d_transClosureMap.end()) {
00108           pTable = new TCMapPair();
00109           d_transClosureMap[rel] = pTable;
00110         }
00111         else {
00112           pTable = (*i).second;
00113         }
00114 
00115         ExprMap<CDList<Theorem>*>::iterator i2 = pTable->appearsFirstMap.find(expr[0]);
00116         CDList<Theorem>* pList;
00117         if (i2 == pTable->appearsFirstMap.end()) {
00118           pList = new CDList<Theorem>(theoryCore()->getCM()->getCurrentContext());
00119           pTable->appearsFirstMap[expr[0]] = pList;
00120         }
00121         else {
00122           pList = (*i2).second;
00123         }
00124         pList->push_back(e);
00125 
00126         i2 = pTable->appearsSecondMap.find(expr[1]);
00127         if (i2 == pTable->appearsSecondMap.end()) {
00128           pList = new CDList<Theorem>(theoryCore()->getCM()->getCurrentContext());
00129           pTable->appearsSecondMap[expr[1]] = pList;
00130         }
00131         else {
00132           pList = (*i2).second;
00133         }
00134         pList->push_back(e);
00135 
00136         // Compute transitive closure with existing relations
00137         size_t s,l;
00138         i2 = pTable->appearsFirstMap.find(expr[1]);
00139         if (i2 != pTable->appearsFirstMap.end()) {
00140           pList = (*i2).second;
00141           s = pList->size();
00142           for (l = 0; l < s; ++l) {
00143             enqueueFact(d_rules->relTrans(e,(*pList)[l]));
00144           }
00145         }
00146 
00147         i2 = pTable->appearsSecondMap.find(expr[0]);
00148         if (i2 != pTable->appearsSecondMap.end()) {
00149           pList = (*i2).second;
00150           s = pList->size();
00151           for (l = 0; l < s; ++l) {
00152             enqueueFact(d_rules->relTrans((*pList)[l],e));
00153           }
00154         }
00155       }
00156       break;
00157     default:
00158       break;
00159   }
00160 }
00161 
00162 
00163 void TheoryUF::checkSat(bool fullEffort)
00164 {
00165   // Check for any unexpanded lambdas
00166   for(; d_funApplicationsIdx < d_funApplications.size();
00167       d_funApplicationsIdx = d_funApplicationsIdx + 1) {
00168     const Expr& e = d_funApplications[d_funApplicationsIdx];
00169     if(e.getOp().getExpr().isLambda()) {
00170       IF_DEBUG(debugger.counter("Expanded lambdas (checkSat)")++);
00171       enqueueFact(d_rules->applyLambda(e));
00172     }
00173   }
00174 }
00175 
00176 
00177 Theorem TheoryUF::rewrite(const Expr& e)
00178 {
00179   if (e.isApply()) {
00180     const Expr& op = e.getOpExpr();
00181     int opKind = op.getKind(); 
00182     switch(opKind) {
00183     case CONSTDEF:
00184     case LETDECL:
00185     // Replace named functions with their definitions (but not
00186     // necessarily expand the definitions yet)
00187       return d_rules->rewriteOpDef(e);
00188     case LAMBDA: {
00189       Theorem res = d_rules->applyLambda(e);
00190       // Simplify recursively
00191       res = transitivityRule(res, simplify(res.getRHS()));
00192       IF_DEBUG(debugger.counter("Expanded lambdas")++);
00193       return res;
00194     }
00195     default: // A truly uninterpreted function
00196       if (e.getType().isBool()) return reflexivityRule(e);
00197       else return rewriteCC(e);
00198     }
00199   }
00200   else {
00201     e.setRewriteNormal();
00202     return reflexivityRule(e);
00203   }
00204 }
00205 
00206 
00207 void TheoryUF::setup(const Expr& e)
00208 {
00209   if (e.getKind() != APPLY) return;
00210   setupCC(e);
00211   // Add this function application for concrete model generation
00212   TRACE("model", "TheoryUF: add function application ", e, "");
00213   d_funApplications.push_back(e);
00214 }
00215 
00216 
00217 void TheoryUF::update(const Theorem& e, const Expr& d)
00218 {
00219   /*
00220   int k, ar(d.arity());
00221   const Theorem& dEQdsig = d.getSig();
00222   if (!dEQdsig.isNull()) {
00223     Expr dsig = dEQdsig.getRHS();
00224     Theorem thm = updateHelper(d);
00225     const Expr& sigNew = thm.getRHS();
00226     if (sigNew == dsig) return;
00227     dsig.setRep(Theorem());
00228     const Theorem& repEQsigNew = sigNew.getRep();
00229     if (!repEQsigNew.isNull()) {
00230       d.setSig(Theorem());
00231       enqueueFact(transitivityRule(repEQsigNew, symmetryRule(thm)));
00232     }
00233     else {
00234       for (k = 0; k < ar; ++k) {
00235         if (sigNew[k] != dsig[k]) {
00236           sigNew[k].addToNotify(this, d);
00237         }
00238       }
00239       d.setSig(thm);
00240       sigNew.setRep(thm);
00241 
00242       if (d_compute_trans_closure && d.getKind() == APPLY &&
00243           d.arity() == 2 && findExpr(d).isTrue()) {
00244         thm = iffTrueElim(transitivityRule(symmetryRule(thm),find(d)));
00245         enqueueFact(d_rules->relToClosure(thm));
00246       }
00247 
00248     }
00249   }
00250   */
00251   // Record the original signature
00252   Theorem dEQdsig = d.getSig();
00253   updateCC(e, d);
00254   if (!dEQdsig.isNull()) {
00255     const Expr& dsig = dEQdsig.getRHS();
00256     Theorem thm = d.getSig();
00257     if(!thm.isNull()) {
00258       const Expr& newSig = thm.getRHS();
00259 
00260       if (dsig != newSig && d.isApply() && findExpr(d).isTrue()) {
00261         if (d.getOpExpr().computeTransClosure()) {
00262           thm = getCommonRules()->iffTrueElim(transitivityRule(symmetryRule(thm),
00263                                                                find(d)));
00264           enqueueFact(d_rules->relToClosure(thm));
00265         }
00266         else if (d.getOpKind() == TRANS_CLOSURE) {
00267           thm = getCommonRules()->iffTrueElim(transitivityRule(symmetryRule(thm),
00268                                                                find(d)));
00269           enqueueFact(thm);
00270         }
00271       }
00272     }
00273   }
00274 }
00275 
00276 
00277 void TheoryUF::checkType(const Expr& e)
00278 {
00279   switch (e.getKind()) {
00280     case ARROW: {
00281       if (e.arity() < 2) throw Exception
00282             ("Function type needs at least two arguments"
00283              +e.toString());
00284       Expr::iterator i = e.begin(), iend = e.end();
00285       for (; i != iend; ) {
00286         Type t(*i);
00287         ++i;
00288         if (i == iend && t.isBool()) break;
00289         if (t.isBool()) throw Exception
00290             ("Function argument types must be non-Boolean"
00291              +e.toString());
00292         if (t.isFunction()) throw Exception
00293             ("Function domain or range types cannot be functions"
00294              +e.toString());
00295       }
00296       break;
00297     }
00298     case TYPEDECL: {
00299       break;
00300     }
00301     case ANY_TYPE: {
00302       if (e.arity() != 0) {
00303         throw Exception("Expected no children: "+e.toString());
00304       }
00305       break;
00306     }
00307     default:
00308       DebugAssert(false, "Unexpected kind in TheoryUF::checkType"
00309                   +getEM()->getKindName(e.getKind()));
00310   }
00311 }
00312 
00313 
00314 void TheoryUF::computeType(const Expr& e)
00315 {
00316   switch (e.getKind()) {
00317     case LAMBDA: {
00318       vector<Type> args;
00319       const vector<Expr>& vars = e.getVars();
00320       DebugAssert(vars.size() > 0,
00321                   "TheorySimulate::computeType("+e.toString()+")");
00322       for(vector<Expr>::const_iterator i=vars.begin(), iend=vars.end();
00323           i!=iend; ++i)
00324         args.push_back((*i).getType());
00325       e.setType(Type::funType(args, e.getBody().getType()));
00326       break;
00327     }
00328     case APPLY: {
00329       DebugAssert(e.isApply(), "Should be application");
00330       DebugAssert(e.arity() > 0, "Expected non-zero arity in APPLY");
00331       Expr funExpr = e.getOpExpr();
00332       Type funType = funExpr.getType();
00333 
00334       if(!funType.isFunction()) {
00335         throw TypecheckException
00336           ("Expected function type for:\n\n"
00337            + funExpr.toString() + "\n\n but got this: "
00338            +funType.getExpr().toString()
00339            +"\n\n in function application:\n\n"+e.toString());
00340       }
00341 
00342       if(funType.arity() != e.arity()+1)
00343         throw TypecheckException("Type mismatch for expression:\n\n   "
00344                                  + e.toString()
00345                                  + "\n\nFunction \""+funExpr.toString()
00346                                  +"\" expects "+int2string(funType.arity()-1)
00347                                  +" argument"
00348                                  +string((funType.arity()==2)? "" : "s")
00349                                  +", but received "
00350                                  +int2string(e.arity())+".");
00351 
00352       for (int k = 0; k < e.arity(); ++k) {
00353         Type valType(getBaseType(e[k]));
00354         if (funType[k] != d_anyType && valType != getBaseType(funType[k])) {
00355           throw TypecheckException("Type mismatch for expression:\n\n   "
00356                                    + e[k].toString()
00357                                    + "\n\nhas the following type:\n\n  "
00358                                    + e[k].getType().toString()
00359                                    + "\n\nbut the expected type is:\n\n  "
00360                                    + funType[k].getExpr().toString()
00361                                    + "\n\nin function application:\n\n  "
00362                                    + e.toString());
00363         }
00364       }
00365       e.setType(funType[funType.arity()-1]);
00366       break;
00367     }
00368     case TRANS_CLOSURE: {
00369       DebugAssert(e.isSymbol(), "Expected symbol");
00370       Expr funExpr = resolveID(e.getName());
00371       if (funExpr.isNull()) {
00372         throw TypecheckException
00373           ("Attempt to take transitive closure of unknown id: "
00374            +e.getName());
00375       }
00376       Type funType = funExpr.getType();
00377       if(!funType.isFunction()) {
00378         throw TypecheckException
00379           ("Attempt to take transitive closure of non-function:\n\n"
00380            +funExpr.toString() + "\n\n which has type: "
00381            +funType.toString());
00382       }
00383       if(funType.arity()!=3) {
00384         throw TypecheckException
00385           ("Attempt to take transitive closure of non-binary function:\n\n"
00386            +funExpr.toString() + "\n\n which has type: "
00387            +funType.toString());
00388       }
00389       if (!funType[2].isBool()) {
00390         throw TypecheckException
00391           ("Attempt to take transitive closure of function:\n\n"
00392            +funExpr.toString() + "\n\n which does not return BOOLEAN");
00393       }
00394       e.setType(funType);
00395       break;
00396     }
00397     default:
00398       DebugAssert(false,"Unexpected type: "+e.toString());
00399       break;
00400   }
00401 }
00402 
00403 
00404 Type TheoryUF::computeBaseType(const Type& t) {
00405   const Expr& e = t.getExpr();
00406   switch(e.getKind()) {
00407   case ARROW: {
00408     DebugAssert(e.arity() > 0, "Expected non-empty ARROW");
00409     vector<Expr> kids;
00410     for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) {
00411       kids.push_back(getBaseType(Type(*i)).getExpr());
00412     }
00413     return Type(Expr(e.getOp(), kids));
00414   }
00415   case TYPEDECL:
00416   case ANY_TYPE: return t;
00417   default:
00418     DebugAssert(false,
00419                 "TheoryUF::computeBaseType("+t.toString()+")");
00420     return t;
00421   }
00422 }
00423 
00424 
00425 void TheoryUF::computeModelTerm(const Expr& e, std::vector<Expr>& v) {
00426   for(CDList<Expr>::const_iterator i=d_funApplications.begin(),
00427         iend=d_funApplications.end(); i!=iend; ++i) {
00428     if((*i).isApply() && (*i).getOp().getExpr() == e) {
00429       // Add both the function application
00430       // getModelTerm(*i, v);
00431       v.push_back(*i);
00432       // and the arguments to the model terms.  Reason: the argument
00433       // to the function better be a concrete value, and it might not
00434       // necessarily be in the current list of model terms.
00435       for(Expr::iterator j=(*i).begin(), jend=(*i).end(); j!=jend; ++j)
00436         // getModelTerm(*j, v);
00437         v.push_back(*j);
00438     }
00439   }
00440 }
00441 
00442 
00443 void TheoryUF::computeModel(const Expr& e, std::vector<Expr>& vars) {
00444   // Repeat the same search for applications of e as in
00445   // computeModelTerm(), but this time get the concrete values of the
00446   // arguments, and return the applications of e to concrete values in
00447   // vars.
00448 
00449   // We'll assign 'e' a value later.
00450   vars.push_back(e);
00451   // Map of f(c) to val for concrete values of c and val
00452   ExprHashMap<Expr> appls;
00453   for(CDList<Expr>::const_iterator i=d_funApplications.begin(),
00454         iend=d_funApplications.end(); i!=iend; ++i) {
00455     if((*i).isApply() && (*i).getOp().getExpr() == e) {
00456       // Update all arguments with concrete values
00457       vector<Theorem> thms;
00458       vector<unsigned> changed;
00459       for(int j=0; j<(*i).arity(); ++j) {
00460         Theorem asst(getModelValue((*i)[j]));
00461         if(asst.getLHS()!=asst.getRHS()) {
00462           thms.push_back(asst);
00463           changed.push_back(j);
00464         }
00465       }
00466       Expr var;
00467       if(changed.size()>0) {
00468         // Arguments changed.  Compute the new application, and assign
00469         // it a concrete value
00470         Theorem subst = substitutivityRule(*i, changed, thms);
00471         assignValue(transitivityRule(symmetryRule(subst), getModelValue(*i)));
00472         var = subst.getRHS();
00473       } else
00474         var = *i;
00475       if(d_applicationsInModel) vars.push_back(var);
00476       // Record it in the map
00477       appls[var] = getModelValue(var).getRHS();
00478     }
00479   }
00480   // Create a LAMBDA expression for e
00481   if(appls.size()==0) { // Leave it fully uninterpreted
00482     assignValue(reflexivityRule(e));
00483   } else {
00484     // Bound vars
00485     vector<Expr> args;
00486     Type tp(e.getType());
00487     static unsigned count(0);
00488     DebugAssert(tp.isFunction(), "TheoryUF::computeModel("+e.toString()
00489                 +" : "+tp.toString()+")");
00490     for(int i=0, iend=tp.arity()-1; i<iend; ++i) {
00491       Expr v = getEM()->newBoundVarExpr("uf", int2string(count++));
00492       v.setType(tp[i]);
00493       args.push_back(v);
00494     }
00495     DebugAssert(args.size()>0, "TheoryUF::computeModel()");
00496     ExprHashMap<Expr>::iterator i=appls.begin(), iend=appls.end();
00497     DebugAssert(i!=iend, "TheoryUF::computeModel(): empty appls hash");
00498     // Use one of the concrete values as a default
00499     Expr res((*i).second); ++i;
00500     for(; i!=iend; ++i) {
00501       // Optimization: if the current value is the same as that of the
00502       // next application, skip this case; i.e. keep 'res' instead of
00503       // building ite(cond, res, res).
00504       if((*i).second == res) continue;
00505 
00506       // Create an ITE condition
00507       Expr cond;
00508       vector<Expr> eqs;
00509       for(int j=0, jend=args.size(); j<jend; ++j)
00510         eqs.push_back(args[j].eqExpr((*i).first[j]));
00511       if(eqs.size()==1)
00512         cond = eqs[0];
00513       else
00514         cond = andExpr(eqs);
00515       // Create an ITE
00516       res = cond.iteExpr((*i).second, res);
00517     }
00518     res = lambdaExpr(args, res);
00519     assignValue(e, res);
00520   }
00521 }
00522 
00523 
00524 Expr TheoryUF::computeTCC(const Expr& e)
00525 {
00526   switch (e.getKind()) {
00527     case APPLY: {
00528       // Compute subtype predicates from the domain types applied to
00529       // the corresponding arguments.  That is, if f: (T0,..,Tn)->T,
00530       // and e = f(e0,...,en), then the TCC is
00531       //
00532       //   pred_T0(e0) & ... & pred_Tn(en) & TCC(e),
00533       //
00534       // where the last TCC(e) is the conjunction of TCCs for the
00535       // arguments, which ensures that all arguments are defined.
00536       //
00537       // If the operator is a lambda-expression, compute the TCC for
00538       // the beta-reduced expression.  We do this in a somewhat sneaky
00539       // but an efficient way: first, compute TCC of the op.body
00540       // (which depends on the bound vars), then wrap that into
00541       // lambda, and apply it to the arguments:
00542       //
00543       //   (LAMBDA(x0...xn): TCC(op.body)) (e0 ... en)
00544       //
00545       // The reason it is more efficient is that TCC(op.body) is cached,
00546       // and doesn't change with the arguments.
00547       
00548       vector<Expr> preds;
00549       preds.push_back(Theory::computeTCC(e));
00550       DebugAssert(e.isApply(), "Should be application");
00551       Expr op(e.getOp().getExpr());
00552       Type funType(op.getType());
00553       DebugAssert(funType.isFunction() || funType.isBool(),
00554                   "TheoryUF::computeTCC(): funType = "
00555                   +funType.toString());
00556       if(funType.isFunction()) {
00557         DebugAssert(funType.arity() == e.arity()+1,
00558                     "TheoryUF::computeTCC(): funType = "
00559                     +funType.toString()+"\n e = "+e.toString());
00560         for(int i=0, iend=e.arity(); i<iend; ++i) {
00561           // Optimization: if the type of the formal argument is
00562           // exactly the same as the type of the actual, then skip the
00563           // type predicate for that argument
00564           if(funType[i] != e[i].getType())
00565             preds.push_back(getTypePred(funType[i], e[i]));
00566         }
00567       }
00568       // Now strip off all the CONSTDEF and LETDECL
00569       while(op.getKind()==CONSTDEF || op.getKind()==LETDECL) op = op[1];
00570       // and add a TCC for the lambda-expression
00571       if(op.isLambda()) {
00572         preds.push_back(Expr(lambdaExpr(op.getVars(),
00573                                         getTCC(op.getBody())).mkOp(),
00574                              e.getKids()));
00575       }
00576       return rewriteAnd(andExpr(preds)).getRHS();
00577     }
00578     case LAMBDA:
00579       return trueExpr();
00580     default:
00581       DebugAssert(false,"Unexpected type: "+e.toString());
00582       return trueExpr();
00583   }
00584 }
00585 
00586 ///////////////////////////////////////////////////////////////////////////////
00587 // Pretty-printing                                                           //
00588 ///////////////////////////////////////////////////////////////////////////////
00589 
00590 
00591 ExprStream& TheoryUF::print(ExprStream& os, const Expr& e) {
00592   switch(os.lang()) {
00593   case PRESENTATION_LANG:
00594     switch(e.getKind()) {
00595     case OLD_ARROW:
00596     case ARROW:
00597       if(e.arity() < 2) e.printAST(os);
00598       else {
00599         if(e.arity() == 2)
00600           os << e[0];
00601         else {
00602           os << "(" << push;
00603           bool first(true);
00604           for(int i=0, iend=e.arity()-1; i<iend; ++i) {
00605             if(first) first=false;
00606             else os << "," << space;
00607             os << e[i];
00608           }
00609           os << push << ")" << pop << pop;
00610         }
00611         os << space << "-> " << space << e[e.arity()-1];
00612       }
00613       break;
00614     case TYPEDECL:
00615       // If it's straight from the parser, we may have several type
00616       // names in one declaration.  Print these in LISP format.
00617       // Otherwise, print the name of the type.
00618       if(e.arity() != 1) e.printAST(os);
00619       else os << e[0].getString();
00620       break;
00621     case LAMBDA: {
00622       DebugAssert(e.isLambda(), "Expected Lambda");
00623       os << "(" << push <<  "LAMBDA" << space << push;
00624       const vector<Expr>& vars = e.getVars();
00625       bool first(true);
00626       os << "(" << push;
00627       for(vector<Expr>::const_iterator i=vars.begin(), iend=vars.end();
00628           i!=iend; ++i) {
00629         if(first) first = false;
00630         else os << push << "," << pop << space;
00631         os << *i;
00632         // The lambda Expr may be in a raw parsed form, in which case
00633         // the type is not assigned yet
00634         if(i->isVar())
00635           os << ":" << space << pushdag << (*i).getType() << popdag;
00636       }
00637       os << push << "): " << pushdag << push
00638          << e.getBody() << push << ")";
00639       break;
00640     }
00641     case APPLY:
00642       os << e.getOpExpr();
00643       if(e.arity() > 0) {
00644         os << "(" << push;
00645         bool first(true);
00646         for (Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) {
00647           if(first) first = false;
00648           else os << "," << space;
00649           os << *i;
00650         }
00651         os << push << ")";
00652       }
00653       break;
00654     case TRANS_CLOSURE:
00655       DebugAssert(e.isSymbol(), "Expected symbol");
00656       os << e.getName() << "*";
00657       break;
00658     case UFUNC:
00659       DebugAssert(e.isSymbol(), "Expected symbol");
00660       os << e.getName();
00661       break;
00662     case ANY_TYPE:
00663       os << "ANY_TYPE";
00664       break;
00665     default: {
00666       DebugAssert(false, "TheoryUF::print: Unexpected expression: "
00667                   +getEM()->getKindName(e.getKind()));
00668     }
00669     }
00670     break; // end of case PRESENTATION_LANGUAGE
00671   case SMTLIB_LANG:
00672     switch(e.getKind()) {
00673     case OLD_ARROW:
00674     case ARROW: {
00675       if(e.arity() < 2) {
00676         throw SmtlibException("TheoryUF::print: Expected 2 or more arguments to ARROW");
00677         //        e.print(os);
00678       }
00679       d_theoryUsed = true;
00680       os << push;
00681       int iend = e.arity();
00682       if (e[iend-1].getKind() == BOOLEAN) --iend;
00683       for(int i=0; i<iend; ++i) {
00684         if (i != 0) os << space;
00685         os << e[i];
00686       }
00687       break;
00688     }
00689     case TYPEDECL:
00690       if (e.arity() == 1 && e[0].isString()) {
00691         os << e[0].getString();
00692         break;
00693       }
00694       // If it's straight from the parser, we may have several type
00695       // names in one declaration.  Print these in LISP format.
00696       // Otherwise, print the name of the type.
00697       throw SmtlibException("TheoryUF::print: TYPEDECL not supported");
00698 //       if(e.arity() != 1) e.print(os);
00699 //       else if(e[0].isString()) os << e[0].getString();
00700 //       else e[0].print(os);
00701       break;
00702     case APPLY:
00703       if (e.arity() == 0) os << e.getOp().getExpr();
00704       else {
00705         os << "(" << push << e.getOp().getExpr();
00706         for (int i=0, iend=e.arity(); i<iend; ++i)
00707           os << space << e[i];
00708         os << push << ")";
00709       }
00710       break;
00711     case TRANS_CLOSURE:
00712       throw SmtlibException
00713         ("TheoryUF::print: SMTLIB_LANG: TRANS_CLOSURE not implemented");
00714       break;
00715     case UFUNC:
00716       DebugAssert(e.isSymbol(), "Expected symbol");
00717       os << e.getName();
00718       break;
00719     case ANY_TYPE:
00720       os << "ANY_TYPE";
00721       break;
00722     default: {
00723       DebugAssert(false, "TheoryUF::print: SMTLIB_LANG: Unexpected expression: "
00724                   +getEM()->getKindName(e.getKind()));
00725     }
00726     }
00727     break; // End of SMT_LIB
00728   case LISP_LANG:
00729     switch(e.getKind()) {
00730     case OLD_ARROW:
00731     case ARROW:
00732       if(e.arity() < 2) e.printAST(os);
00733       os << "(" << push << "ARROW";
00734       for(int i=0, iend=e.arity(); i<iend; ++i)
00735         os << space << e[i];
00736       os << push << ")";
00737       break;
00738     case TRANS_CLOSURE:
00739       e.printAST(os);
00740       break;
00741     case TYPEDECL:
00742       // If it's straight from the parser, we may have several type
00743       // names in one declaration.  Print these in LISP format.
00744       // Otherwise, print the name of the type.
00745       if(e.arity() != 1) e.printAST(os);
00746       else if(e[0].isString()) os << e[0].getString();
00747       else e[0].print(os);
00748       break;
00749     case LAMBDA: {
00750       DebugAssert(e.isLambda(), "Expected LAMBDA");
00751       os << "(" << push <<  "LAMBDA" << space;
00752       const vector<Expr>& vars = e.getVars();
00753       bool first(true);
00754       os << "(" << push;
00755       for(vector<Expr>::const_iterator i=vars.begin(), iend=vars.end();
00756           i!=iend; ++i) {
00757         if(first) first = false;
00758         else os << space;
00759         os << "(" << push << *i;
00760         // The expression may be in a raw parsed form, in which case
00761         // the type is not assigned yet
00762         if(i->isVar())
00763           os << space << pushdag << (*i).getType() << popdag;
00764         os << push << ")" << pop << pop;
00765       }
00766       os << push << ")" << pop << pop << pushdag
00767          << e.getBody() << push << ")";
00768       break;
00769     }
00770     case APPLY:
00771       DebugAssert(e.isApply(), "Expected Apply");
00772       if (e.arity() == 0) os << e.getOp().getExpr();
00773       else {
00774         os << "(" << push << e.getOp().getExpr();
00775         for (int i=0, iend=e.arity(); i<iend; ++i)
00776           os << space << e[i];
00777         os << push << ")";
00778       }
00779       break;
00780     default: {
00781       DebugAssert(false, "TheoryUF::print: Unexpected expression: "
00782                   +getEM()->getKindName(e.getKind()));
00783     }
00784     }
00785     break; // End of LISP_LANG
00786     case ANY_TYPE:
00787       os << "ANY_TYPE";
00788       break;
00789   default:
00790     // Print the top node in the default format, continue with
00791     // pretty-printing for children.
00792     e.printAST(os);
00793     break;
00794   }
00795   return os;
00796 }
00797 
00798 //////////////////////////////////////////////////////////////////////////////
00799 //parseExprOp:
00800 //translating special Exprs to regular EXPR??
00801 ///////////////////////////////////////////////////////////////////////////////
00802 Expr
00803 TheoryUF::parseExprOp(const Expr& e) {
00804   // If the expression is not a list, it must have been already
00805   // parsed, so just return it as is.
00806   if(RAW_LIST != e.getKind()) return e;
00807 
00808   DebugAssert(e.arity() > 0,
00809               "TheoryUF::parseExprOp:\n e = "+e.toString());
00810   
00811   const Expr& c1 = e[0][0];
00812   int kind = getEM()->getKind(c1.getString());
00813   switch(kind) {
00814   case OLD_ARROW: {
00815     if (!theoryCore()->getFlags()["old-func-syntax"].getBool()) {
00816       throw ParserException("You seem to be using the old syntax for function types.\n"
00817                             "Please convert to the new syntax or run with +old-func-syntax");
00818     }
00819     DebugAssert(e.arity()==3,"Expected arity 3 in OLD_ARROW");
00820     Expr arg = parseExpr(e[1]);
00821     vector<Expr> k;
00822     if (arg.getOpKind() == TUPLE_TYPE) {
00823       Expr::iterator i = arg.begin(), iend=arg.end();
00824       for (; i != iend; ++i) {
00825         k.push_back(*i);
00826       }
00827     }
00828     else k.push_back(arg);
00829     k.push_back(parseExpr(e[2]));
00830     return Expr(ARROW, k);
00831   }
00832   case ARROW:
00833   case TYPEDECL: {
00834     vector<Expr> k;
00835     Expr::iterator i = e.begin(), iend=e.end();
00836     // Skip first element of the vector of kids in 'e'.
00837     // The first element is the operator.
00838     ++i; 
00839     // Parse the kids of e and push them into the vector 'k'
00840     for(; i!=iend; ++i) 
00841       k.push_back(parseExpr(*i));
00842     return Expr(kind, k, e.getEM());
00843     break;
00844   }
00845   case TRANS_CLOSURE: {
00846     if(e.arity() != 4)
00847       throw ParserException("Wrong number of arguments to "
00848                             "TRANS_CLOSURE expression\n"
00849                             " (expected 3 arguments): "+e.toString());
00850     const string& name = e[1][0].getString();
00851     Expr funExpr = resolveID(name);
00852     if (funExpr.isNull())
00853       throw ParserException("Attempt to take transitive closure of unknown "
00854                             "predicate"+name);
00855     return transClosureExpr(name, parseExpr(e[2]), parseExpr(e[3]));
00856   }
00857   case LAMBDA: { // (LAMBDA ((v1 ... vn tp1) ...) body)
00858     if(!(e.arity() == 3 && e[1].getKind() == RAW_LIST && e[1].arity() > 0))
00859       throw ParserException("Bad LAMBDA expression: "+e.toString());
00860     // Iterate through the groups of bound variables
00861     vector<pair<string,Type> > vars; // temporary stack of bound variables
00862     for(Expr::iterator i=e[1].begin(), iend=e[1].end(); i!=iend; ++i) {
00863       if(i->getKind() != RAW_LIST || i->arity() < 2)
00864         throw ParserException("Bad variable declaration block in LAMBDA "
00865                             "expression: "+i->toString()+
00866                             "\n e = "+e.toString());
00867       // Iterate through individual bound vars in the group.  The
00868       // last element is the type, which we have to rebuild and
00869       // parse, since it is used in the creation of bound variables.
00870       Type tp(parseExpr((*i)[i->arity()-1]));
00871       for(int j=0, jend=i->arity()-1; j<jend; ++j) {
00872         if((*i)[j].getKind() != ID)
00873           throw ParserException("Bad variable declaration in LAMBDA"
00874                               " expression: "+(*i)[j].toString()+
00875                               "\n e = "+e.toString());
00876         vars.push_back(pair<string,Type>((*i)[j][0].getString(), tp));
00877       }
00878     }
00879     // Create all the bound vars and save them in a vector
00880     vector<Expr> boundVars;
00881     for(vector<pair<string,Type> >::iterator i=vars.begin(), iend=vars.end();
00882         i!=iend; ++i)
00883       boundVars.push_back(addBoundVar(i->first, i->second));
00884     // Rebuild the body
00885     Expr body(parseExpr(e[2]));
00886     // Build the resulting Expr as (LAMBDA (vars) body)
00887     return lambdaExpr(boundVars, body);
00888     break;
00889   }
00890     // case APPLY: 
00891   default: { // Application of an uninterpreted function
00892     if(e.arity() < 2)
00893       throw ParserException("Bad function application: "+e.toString());
00894     Expr::iterator i=e.begin(), iend=e.end();
00895     Expr op(parseExpr(*i)); ++i;
00896     vector<Expr> args;
00897     for(; i!=iend; ++i) args.push_back(parseExpr(*i));
00898     return Expr(op.mkOp(), args);
00899   }
00900   }
00901   return e;
00902 }
00903 
00904 
00905 Expr TheoryUF::lambdaExpr(const vector<Expr>& vars, const Expr& body) {
00906   return getEM()->newClosureExpr(LAMBDA, vars, body);
00907 }
00908 
00909 
00910 Expr TheoryUF::transClosureExpr(const std::string& name, const Expr& e1,
00911                                 const Expr& e2) {
00912   return Expr(getEM()->newSymbolExpr(name, TRANS_CLOSURE).mkOp(), e1, e2);
00913 }

Generated on Thu Apr 13 16:57:35 2006 for CVC Lite by  doxygen 1.4.4