SMT-LIBv2 (define-fun...) command now functional; does eager expansion at preprocessi...
authorMorgan Deters <mdeters@gmail.com>
Thu, 7 Oct 2010 07:16:49 +0000 (07:16 +0000)
committerMorgan Deters <mdeters@gmail.com>
Thu, 7 Oct 2010 07:16:49 +0000 (07:16 +0000)
21 files changed:
src/expr/command.cpp
src/expr/command.h
src/expr/expr_template.cpp
src/expr/expr_template.h
src/expr/node.h
src/expr/node_value.h
src/expr/type.cpp
src/expr/type.h
src/expr/type_node.cpp
src/expr/type_node.h
src/main/getopt.cpp
src/parser/smt2/Smt2.g
src/smt/Makefile.am
src/smt/bad_option.h [deleted file]
src/smt/bad_option_exception.h [new file with mode: 0644]
src/smt/no_such_function_exception.h [new file with mode: 0644]
src/smt/smt_engine.cpp
src/smt/smt_engine.h
src/util/options.h
test/regress/regress0/Makefile.am
test/regress/regress0/simple-rdl-definefun.smt2 [new file with mode: 0644]

index a1486fcab84f4e88529d077cd25ce2b05c31d3cb..8c90f337e420e669948a4b918735dabca840ac23 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "expr/command.h"
 #include "smt/smt_engine.h"
+#include "smt/bad_option_exception.h"
 #include "util/output.h"
 
 using namespace std;
@@ -217,26 +218,26 @@ void DeclarationCommand::toStream(std::ostream& out) const {
 
 /* class DefineFunctionCommand */
 
-DefineFunctionCommand::DefineFunctionCommand(const std::string& name,
-                                                    const std::vector<std::pair<std::string, Type> >& args,
-                                                    Type type,
-                                                    Expr formula) :
-  d_name(name),
-  d_args(args),
-  d_type(type),
+DefineFunctionCommand::DefineFunctionCommand(Expr func,
+                                             const std::vector<Expr>& formals,
+                                             Expr formula) :
+  d_func(func),
+  d_formals(formals),
   d_formula(formula) {
 }
 
 void DefineFunctionCommand::invoke(SmtEngine* smtEngine) {
-  smtEngine->defineFunction(d_name, d_args, d_type, d_formula);
+  smtEngine->defineFunction(d_func, d_formals, d_formula);
 }
 
 void DefineFunctionCommand::toStream(std::ostream& out) const {
-  out << "DefineFunction( \"" << d_name << "\", [";
-  copy( d_args.begin(), d_args.end() - 1,
-        ostream_iterator<std::pair<std::string, Type> >(out, ", ") );
-  out << d_args.back();
-  out << "], << " << d_type << " >>, << " << d_formula << " >> )";
+  out << "DefineFunction( \"" << d_func << "\", [";
+  if(d_formals.size() > 0) {
+    copy( d_formals.begin(), d_formals.end() - 1,
+          ostream_iterator<Expr>(out, ", ") );
+    out << d_formals.back();
+  }
+  out << "], << " << d_formula << " >> )";
 }
 
 /* class GetValueCommand */
@@ -324,7 +325,7 @@ void SetInfoCommand::invoke(SmtEngine* smtEngine) {
   try {
     smtEngine->setInfo(d_flag, d_sexpr);
     //d_result = "success";
-  } catch(BadOption& bo) {
+  } catch(BadOptionException& bo) {
     d_result = "unsupported";
   }
 }
@@ -352,7 +353,7 @@ GetInfoCommand::GetInfoCommand(std::string flag) :
 void GetInfoCommand::invoke(SmtEngine* smtEngine) {
   try {
     d_result = smtEngine->getInfo(d_flag).getValue();
-  } catch(BadOption& bo) {
+  } catch(BadOptionException& bo) {
     d_result = "unsupported";
   }
 }
@@ -382,7 +383,7 @@ void SetOptionCommand::invoke(SmtEngine* smtEngine) {
   try {
     smtEngine->setOption(d_flag, d_sexpr);
     //d_result = "success";
-  } catch(BadOption& bo) {
+  } catch(BadOptionException& bo) {
     d_result = "unsupported";
   }
 }
@@ -410,7 +411,7 @@ GetOptionCommand::GetOptionCommand(std::string flag) :
 void GetOptionCommand::invoke(SmtEngine* smtEngine) {
   try {
     d_result = smtEngine->getOption(d_flag).getValue();
-  } catch(BadOption& bo) {
+  } catch(BadOptionException& bo) {
     d_result = "unsupported";
   }
 }
index 0c78dd1c6c8224a60532c55dc4f7d1d9e32a14c6..4c74cfd6c838befe5d29443c6a403421af1ae68c 100644 (file)
@@ -111,14 +111,13 @@ public:
 
 class CVC4_PUBLIC DefineFunctionCommand : public Command {
 protected:
-  std::string d_name;
-  std::vector<std::pair<std::string, Type> > d_args;
-  Type d_type;
+  Expr d_func;
+  std::vector<Expr> d_formals;
   Expr d_formula;
 public:
-  DefineFunctionCommand(const std::string& name,
-                        const std::vector<std::pair<std::string, Type> >& args,
-                        Type type, Expr formula);
+  DefineFunctionCommand(Expr func,
+                        const std::vector<Expr>& formals,
+                        Expr formula);
   void invoke(SmtEngine* smtEngine);
   void toStream(std::ostream& out) const;
 };/* class DefineFunctionCommand */
index 803808b0f8c110dc77a45fc2562b270af41c2b7d..5fb931a65029df26efa0d2ac58bef6998b1c1b16 100644 (file)
@@ -223,7 +223,11 @@ void Expr::toStream(std::ostream& out, int depth, bool types) const {
   d_node->toStream(out, depth, types);
 }
 
-Node Expr::getNode() const {
+Node Expr::getNode() const throw() {
+  return *d_node;
+}
+
+TNode Expr::getTNode() const throw() {
   return *d_node;
 }
 
index 8fab13b37330a62bf9b62258b9f784f08e6d6d12..bb227f92f85c3a9ff38f2ebf43df5880804a7619 100644 (file)
@@ -43,8 +43,13 @@ class NodeTemplate;
 
 class Expr;
 class ExprManager;
+class SmtEngine;
 class Type;
 
+namespace smt {
+  class SmtEnginePrivate;
+}/* CVC4::smt namespace */
+
 namespace expr {
   class CVC4_PUBLIC ExprSetDepth;
   class CVC4_PUBLIC ExprPrintTypes;
@@ -383,10 +388,17 @@ protected:
    * Returns the actual internal node.
    * @return the internal node
    */
-  NodeTemplate<true> getNode() const;
+  NodeTemplate<true> getNode() const throw();
+
+  /**
+   * Returns the actual internal node as a TNode.
+   * @return the internal node
+   */
+  NodeTemplate<false> getTNode() const throw();
 
   // Friend to access the actual internal expr information and private methods
   friend class SmtEngine;
+  friend class smt::SmtEnginePrivate;
   friend class ExprManager;
 };
 
index 67d46a97755002ee29762910f46fe0112ec494e4..bd6b535220467076612f737b166158ff13190868 100644 (file)
@@ -379,6 +379,20 @@ public:
   TypeNode getType(bool check = false) const
     throw (CVC4::TypeCheckingExceptionPrivate, CVC4::AssertionException);
 
+  /**
+   * Substitution of Nodes.
+   */
+  Node substitute(TNode node, TNode replacement) const;
+
+  /**
+   * Simultaneous substitution of Nodes.
+   */
+  template <class Iterator1, class Iterator2>
+  Node substitute(Iterator1 nodesBegin,
+                  Iterator1 nodesEnd,
+                  Iterator2 replacementsBegin,
+                  Iterator2 replacementsEnd) const;
+
   /**
    * Returns the kind of this node.
    * @return the kind
@@ -1035,6 +1049,59 @@ TypeNode NodeTemplate<ref_count>::getType(bool check) const
   return NodeManager::currentNM()->getType(*this, check);
 }
 
+template <bool ref_count>
+Node NodeTemplate<ref_count>::substitute(TNode node,
+                                         TNode replacement) const {
+  NodeBuilder<> nb(getKind());
+  if(getMetaKind() == kind::metakind::PARAMETERIZED) {
+    // push the operator
+    nb << getOperator();
+  }
+  for(TNode::const_iterator i = begin(),
+        iend = end();
+      i != iend;
+      ++i) {
+    if(*i == node) {
+      nb << replacement;
+    } else {
+      (*i).substitute(node, replacement);
+    }
+  }
+  Node n = nb;
+  return n;
+}
+
+template <bool ref_count>
+template <class Iterator1, class Iterator2>
+Node NodeTemplate<ref_count>::substitute(Iterator1 nodesBegin,
+                                         Iterator1 nodesEnd,
+                                         Iterator2 replacementsBegin,
+                                         Iterator2 replacementsEnd) const {
+  Assert( nodesEnd - nodesBegin == replacementsEnd - replacementsBegin,
+          "Substitution iterator ranges must be equal size" );
+  Iterator1 j = find(nodesBegin, nodesEnd, *this);
+  if(j != nodesEnd) {
+    return *(replacementsBegin + (j - nodesBegin));
+  } else if(getNumChildren() == 0) {
+    return *this;
+  } else {
+    NodeBuilder<> nb(getKind());
+    if(getMetaKind() == kind::metakind::PARAMETERIZED) {
+      // push the operator
+      nb << getOperator();
+    }
+    for(TNode::const_iterator i = begin(),
+          iend = end();
+        i != iend;
+        ++i) {
+      nb << (*i).substitute(nodesBegin, nodesEnd,
+                            replacementsBegin, replacementsEnd);
+    }
+    Node n = nb;
+    return n;
+  }
+}
+
 #ifdef CVC4_DEBUG
 /**
  * Pretty printer for use within gdb.  This is not intended to be used
index e4fc479b7b3052b46bc7414877247d273d4e557d..658cb1e2d25de6b53d199186ec8dae7e0a60708a 100644 (file)
@@ -171,8 +171,48 @@ private:
       return iterator(d_i++);
     }
 
-    typedef std::input_iterator_tag iterator_category;
-  };
+    iterator& operator--() {
+      --d_i;
+      return *this;
+    }
+
+    iterator operator--(int) {
+      return iterator(d_i--);
+    }
+
+    iterator& operator+=(difference_type p) {
+      d_i += p;
+      return *this;
+    }
+
+    iterator& operator-=(difference_type p) {
+      d_i -= p;
+      return *this;
+    }
+
+    iterator operator+(difference_type p) {
+      return iterator(d_i + p);
+    }
+
+    iterator operator-(difference_type p) {
+      return iterator(d_i - p);
+    }
+
+    difference_type operator-(iterator i) {
+      return d_i - i.d_i;
+    }
+
+    typedef std::random_access_iterator_tag iterator_category;
+  };/* class NodeValue::iterator<T> */
+
+  // operator+ (as a function) cannot be a template, so we have to
+  // define two versions
+  friend NodeValue::iterator<NodeTemplate<true> >
+  operator+(NodeValue::iterator<NodeTemplate<true> >::difference_type p,
+            NodeValue::iterator<NodeTemplate<true> > i);
+  friend NodeValue::iterator<NodeTemplate<false> >
+  operator+(NodeValue::iterator<NodeTemplate<false> >::difference_type p,
+            NodeValue::iterator<NodeTemplate<false> > i);
 
   /** Decrement ref counts of children */
   inline void decrRefCounts();
@@ -258,6 +298,26 @@ private:
 
 };/* class NodeValue */
 
+/**
+ * Provides a symmetric addition operator to that already defined in
+ * the iterator class.
+ */
+inline NodeValue::iterator<NodeTemplate<true> >
+operator+(NodeValue::iterator<NodeTemplate<true> >::difference_type p,
+          NodeValue::iterator<NodeTemplate<true> > i) {
+  return i + p;
+}
+
+/**
+ * Provides a symmetric addition operator to that already defined in
+ * the iterator class.
+ */
+inline NodeValue::iterator<NodeTemplate<false> >
+operator+(NodeValue::iterator<NodeTemplate<false> >::difference_type p,
+          NodeValue::iterator<NodeTemplate<false> > i) {
+  return i + p;
+}
+
 /**
  * For hash_maps, hash_sets, etc.. but this is for expr package
  * internal use only at present!  This is likely to be POORLY
index 05b69f6f469e7a5db10e2b799c1a8a8316557fab..8cf555eb09f4abf79b5cc19dcd691b5087ca53f7 100644 (file)
@@ -111,7 +111,10 @@ Type Type::substitute(const vector<Type>& types,
     replacementsNodes.push_back(*(*i).d_typeNode);
   }
 
-  return makeType(d_typeNode->substitute(typesNodes, replacementsNodes));
+  return makeType(d_typeNode->substitute(typesNodes.begin(),
+                                         typesNodes.end(),
+                                         replacementsNodes.begin(),
+                                         replacementsNodes.end()));
 }
 
 void Type::toStream(ostream& out) const {
index 57ec3bf5ca9504e8719b4e70ca06c058c3a9b8a4..19c3d27f3570a05d747be11da2d32db70b5ebd3a 100644 (file)
@@ -60,6 +60,8 @@ struct CVC4_PUBLIC TypeHashStrategy {
  */
 class CVC4_PUBLIC Type {
 
+  friend class SmtEngine;
+  friend class SmtEnginePrivate;
   friend class ExprManager;
   friend class TypeNode;
   friend class TypeHashStrategy;
@@ -87,7 +89,7 @@ protected:
   Type(NodeManager* em, TypeNode* typeNode);
 
   /** Accessor for derived classes */
-  static TypeNode* getTypeNode(const Type& t) { return t.d_typeNode; }
+  static TypeNode* getTypeNode(const Type& t) throw() { return t.d_typeNode; }
 
 public:
 
index a55c05c5a3824102e47719f24ade9edfdc5cc2aa..badc3b72f68bf6a1be2ad07642d01b61d2a4a6d6 100644 (file)
@@ -33,7 +33,10 @@ TypeNode TypeNode::substitute(const TypeNode& type,
     // push the operator
     nb << TypeNode(d_nv->d_children[0]);
   }
-  for(TypeNode::iterator i = begin(), iend = end(); i != iend; ++i) {
+  for(TypeNode::const_iterator i = begin(),
+        iend = end();
+      i != iend;
+      ++i) {
     if(*i == type) {
       nb << replacement;
     } else {
@@ -43,26 +46,6 @@ TypeNode TypeNode::substitute(const TypeNode& type,
   return nb.constructTypeNode();
 }
 
-TypeNode TypeNode::substitute(const vector<TypeNode>& types,
-                              const vector<TypeNode>& replacements) const {
-  vector<TypeNode>::const_iterator j = find(types.begin(), types.end(), *this);
-  if(j != types.end()) {
-    return replacements[j - types.begin()];
-  } else if(getNumChildren() == 0) {
-    return *this;
-  } else {
-    NodeBuilder<> nb(getKind());
-    if(getMetaKind() == kind::metakind::PARAMETERIZED) {
-      // push the operator
-      nb << TypeNode(d_nv->d_children[0]);
-    }
-    for(TypeNode::iterator i = begin(), iend = end(); i != iend; ++i) {
-      nb << (*i).substitute(types, replacements);
-    }
-    return nb.constructTypeNode();
-  }
-}
-
 bool TypeNode::isBoolean() const {
   return getKind() == kind::TYPE_CONSTANT &&
     getConst<TypeConstant>() == BOOLEAN_TYPE;
index 6780b08f781a2d9eed099d20f504f5dc2cff798e..0e763128f04bddd34764b467e031d98354ce42a3 100644 (file)
@@ -118,8 +118,11 @@ public:
   /**
    * Simultaneous substitution of TypeNodes.
    */
-  TypeNode substitute(const std::vector<TypeNode>& types,
-                      const std::vector<TypeNode>& replacements) const;
+  template <class Iterator1, class Iterator2>
+  TypeNode substitute(Iterator1 typesBegin,
+                      Iterator1 typesEnd,
+                      Iterator2 replacementsBegin,
+                      Iterator2 replacementsEnd) const;
 
   /**
    * Structural comparison operator for expressions.
@@ -436,6 +439,35 @@ struct TypeNodeHashStrategy {
 
 namespace CVC4 {
 
+template <class Iterator1, class Iterator2>
+TypeNode TypeNode::substitute(Iterator1 typesBegin,
+                              Iterator1 typesEnd,
+                              Iterator2 replacementsBegin,
+                              Iterator2 replacementsEnd) const {
+  Assert( typesEnd - typesBegin == replacementsEnd - replacementsBegin,
+          "Substitution iterator ranges must be equal size" );
+  Iterator1 j = find(typesBegin, typesEnd, *this);
+  if(j != typesEnd) {
+    return *(replacementsBegin + (j - typesBegin));
+  } else if(getNumChildren() == 0) {
+    return *this;
+  } else {
+    NodeBuilder<> nb(getKind());
+    if(getMetaKind() == kind::metakind::PARAMETERIZED) {
+      // push the operator
+      nb << TypeNode(d_nv->d_children[0]);
+    }
+    for(TypeNode::const_iterator i = begin(),
+          iend = end();
+        i != iend;
+        ++i) {
+      nb << (*i).substitute(typesBegin, typesEnd,
+                            replacementsBegin, replacementsEnd);
+    }
+    return nb.constructTypeNode();
+  }
+}
+
 inline size_t TypeNode::getNumChildren() const {
   return d_nv->getNumChildren();
 }
index 4af882aa173368da86ff220429352496871ca5ec..82214bed3903df5457225411d6f80d6e09dbf33b 100644 (file)
@@ -71,6 +71,7 @@ enum OptionValue {
   DEFAULT_EXPR_DEPTH,
   PRINT_EXPR_TYPES,
   UF_THEORY,
+  LAZY_DEFINITION_EXPANSION,
   INTERACTIVE,
   NO_INTERACTIVE
 };/* enum OptionValue */
@@ -119,6 +120,7 @@ static struct option cmdlineOptions[] = {
   { "default-expr-depth", required_argument, NULL, DEFAULT_EXPR_DEPTH },
   { "print-expr-types", no_argument , NULL, PRINT_EXPR_TYPES },
   { "uf"         , required_argument, NULL, UF_THEORY },
+  { "lazy-definition-expansion", no_argument, NULL, LAZY_DEFINITION_EXPANSION },
   { "interactive", no_argument      , NULL, INTERACTIVE },
   { "no-interactive", no_argument   , NULL, NO_INTERACTIVE },
   { NULL         , no_argument      , NULL, '\0'        }
@@ -272,6 +274,10 @@ throw(OptionException) {
       }
       break;
 
+    case LAZY_DEFINITION_EXPANSION:
+      opts->lazyDefinitionExpansion = true;
+      break;
+
     case INTERACTIVE:
       opts->interactive = true;
       opts->interactiveSetByUser = true;
index 9ad8c31773fb37cccd21aecb163ecd7355ef9c64..a2792eaac88be0e7ce3c22c214253d1f817575e5 100644 (file)
@@ -131,7 +131,7 @@ command returns [CVC4::Command* cmd]
   Type t;
   std::vector<Expr> terms;
   std::vector<Type> sorts;
-  std::vector<std::pair<std::string, Type> > sortedVars;
+  std::vector<std::pair<std::string, Type> > sortedVarNames;
   SExpr sexpr;
 }
   : /* set the logic */
@@ -202,15 +202,15 @@ command returns [CVC4::Command* cmd]
       $cmd = new DeclarationCommand(name,t); }
   | /* function definition */
     DEFINE_FUN_TOK symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
-    LPAREN_TOK sortedVarList[sortedVars] RPAREN_TOK
+    LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
     sortSymbol[t]
     { /* add variables to parser state before parsing term */
       Debug("parser") << "define fun: '" << name << "'" << std::endl;
-      if( sortedVars.size() > 0 ) {
+      if( sortedVarNames.size() > 0 ) {
         std::vector<CVC4::Type> sorts;
-        sorts.reserve(sortedVars.size());
+        sorts.reserve(sortedVarNames.size());
         for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
-              sortedVars.begin(), iend = sortedVars.end();
+              sortedVarNames.begin(), iend = sortedVarNames.end();
             i != iend;
             ++i) {
           sorts.push_back((*i).second);
@@ -219,10 +219,10 @@ command returns [CVC4::Command* cmd]
       }
       PARSER_STATE->pushScope();
       for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
-            sortedVars.begin(), iend = sortedVars.end();
+            sortedVarNames.begin(), iend = sortedVarNames.end();
           i != iend;
           ++i) {
-        PARSER_STATE->mkVar((*i).first, (*i).second);
+        terms.push_back(PARSER_STATE->mkVar((*i).first, (*i).second));
       }
     }
     term[expr]
@@ -230,8 +230,8 @@ command returns [CVC4::Command* cmd]
       // declare the name down here (while parsing term, signature
       // must not be extended with the name itself; no recursion
       // permitted)
-      PARSER_STATE->mkFunction(name, t);
-      $cmd = new DefineFunctionCommand(name, sortedVars, t, expr);
+      Expr func = PARSER_STATE->mkFunction(name, t);
+      $cmd = new DefineFunctionCommand(func, terms, expr);
     }
   | /* value query */
     GET_VALUE_TOK LPAREN_TOK termList[terms,expr] RPAREN_TOK
index 1929151529e06f51b8ca089344dbce059374ffa4..319b25576cb0177864ba2d834bfd3c690875d8c6 100644 (file)
@@ -9,4 +9,5 @@ libsmt_la_SOURCES = \
        smt_engine.cpp \
        smt_engine.h \
        noninteractive_exception.h \
-       bad_option.h
+       bad_option_exception.h \
+       no_such_function_exception.h
diff --git a/src/smt/bad_option.h b/src/smt/bad_option.h
deleted file mode 100644 (file)
index 800d8e6..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*********************                                                        */
-/*! \file bad_option.h
- ** \verbatim
- ** Original author: mdeters
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010  The Analysis of Computer Systems Group (ACSys)
- ** Courant Institute of Mathematical Sciences
- ** New York University
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief An exception that is thrown when an option setting is not
- ** understood.
- **
- ** An exception that is thrown when an interactive-only feature while
- ** CVC4 is being used in a non-interactive setting (for example, the
- ** "(get-assertions)" command in an SMT-LIBv2 script).
- **/
-
-#include "cvc4_public.h"
-
-#ifndef __CVC4__SMT__BAD_OPTION_H
-#define __CVC4__SMT__BAD_OPTION_H
-
-#include "util/exception.h"
-
-namespace CVC4 {
-
-class CVC4_PUBLIC BadOption : public CVC4::Exception {
-public:
-  BadOption() :
-    Exception("Unrecognized informational or option key or setting") {
-  }
-
-  BadOption(const std::string& msg) :
-    Exception(msg) {
-  }
-
-  BadOption(const char* msg) :
-    Exception(msg) {
-  }
-};/* class BadOption */
-
-}/* CVC4 namespace */
-
-#endif /* __CVC4__SMT__BAD_OPTION_H */
diff --git a/src/smt/bad_option_exception.h b/src/smt/bad_option_exception.h
new file mode 100644 (file)
index 0000000..13e5d96
--- /dev/null
@@ -0,0 +1,48 @@
+/*********************                                                        */
+/*! \file bad_option_exception.h
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010  The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief An exception that is thrown when an option setting is not
+ ** understood.
+ **
+ ** An exception that is thrown when an interactive-only feature while
+ ** CVC4 is being used in a non-interactive setting (for example, the
+ ** "(get-assertions)" command in an SMT-LIBv2 script).
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef __CVC4__SMT__BAD_OPTION_EXCEPTION_H
+#define __CVC4__SMT__BAD_OPTION_EXCEPTION_H
+
+#include "util/exception.h"
+
+namespace CVC4 {
+
+class CVC4_PUBLIC BadOptionException : public CVC4::Exception {
+public:
+  BadOptionException() :
+    Exception("Unrecognized informational or option key or setting") {
+  }
+
+  BadOptionException(const std::string& msg) :
+    Exception(msg) {
+  }
+
+  BadOptionException(const char* msg) :
+    Exception(msg) {
+  }
+};/* class BadOptionException */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__SMT__BAD_OPTION_EXCEPTION_H */
diff --git a/src/smt/no_such_function_exception.h b/src/smt/no_such_function_exception.h
new file mode 100644 (file)
index 0000000..0a5f288
--- /dev/null
@@ -0,0 +1,44 @@
+/*********************                                                        */
+/*! \file no_such_function_exception.h
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010  The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief An exception that is thrown when an option setting is not
+ ** understood.
+ **
+ ** An exception that is thrown when an interactive-only feature while
+ ** CVC4 is being used in a non-interactive setting (for example, the
+ ** "(get-assertions)" command in an SMT-LIBv2 script).
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef __CVC4__SMT__NO_SUCH_FUNCTION_EXCEPTION_H
+#define __CVC4__SMT__NO_SUCH_FUNCTION_EXCEPTION_H
+
+#include "util/exception.h"
+
+namespace CVC4 {
+
+class CVC4_PUBLIC NoSuchFunctionException : public CVC4::Exception {
+public:
+  NoSuchFunctionException(Expr name) :
+    Exception(std::string("Undefined function: `") + name.toString() + "': ") {
+  }
+
+  NoSuchFunctionException(Expr name, const std::string& msg) :
+    Exception(std::string("Undefined function: `") + name.toString() + "': " + msg) {
+  }
+};/* class NoSuchFunctionException */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__SMT__NO_SUCH_FUNCTION_EXCEPTION_H */
index be4abb8abfb183ada90ef2e56228466a0efb6b28..c417370287f8578b20d934dcd5dbaa2dd0055909 100644 (file)
  ** The main entry point into the CVC4 library's SMT interface.
  **/
 
+#include <vector>
+#include <string>
+
 #include "smt/smt_engine.h"
 #include "smt/noninteractive_exception.h"
+#include "smt/bad_option_exception.h"
+#include "smt/no_such_function_exception.h"
 #include "context/context.h"
 #include "context/cdlist.h"
+#include "expr/expr.h"
 #include "expr/command.h"
 #include "expr/node_builder.h"
 #include "util/output.h"
@@ -28,6 +34,7 @@
 #include "prop/prop_engine.h"
 #include "theory/theory_engine.h"
 
+using namespace std;
 using namespace CVC4;
 using namespace CVC4::smt;
 using namespace CVC4::prop;
@@ -37,6 +44,28 @@ namespace CVC4 {
 
 namespace smt {
 
+/**
+ * Representation of a defined function.  We keep these around in
+ * SmtEngine to permit expanding definitions late (and lazily), to
+ * support getValue() over defined functions, to support user output
+ * in terms of defined functions, etc.
+ */
+class DefinedFunction {
+  Node d_func;
+  std::vector<Node> d_formals;
+  Node d_formula;
+public:
+  DefinedFunction() {}
+  DefinedFunction(Node func, vector<Node> formals, Node formula) :
+    d_func(func),
+    d_formals(formals),
+    d_formula(formula) {
+  }
+  Node getFunction() const { return d_func; }
+  vector<Node> getFormals() const { return d_formals; }
+  Node getFormula() const { return d_formula; }
+};/* class DefinedFunction */
+
 /**
  * This is an inelegant solution, but for the present, it will work.
  * The point of this is to separate the public and private portions of
@@ -60,19 +89,27 @@ public:
    * passes over the Node.  TODO: may need to specify a LEVEL of
    * preprocessing (certain contexts need more/less ?).
    */
-  static Node preprocess(SmtEngine& smt, TNode n);
+  static Node preprocess(SmtEngine& smt, TNode n)
+    throw(NoSuchFunctionException, AssertionException);
 
   /**
    * Adds a formula to the current context.
    */
-  static void addFormula(SmtEngine& smt, TNode n);
+  static void addFormula(SmtEngine& smt, TNode n)
+    throw(NoSuchFunctionException, AssertionException);
+
+  /**
+   * Expand definitions in n.
+   */
+  static Node expandDefinitions(SmtEngine& smt, TNode n)
+    throw(NoSuchFunctionException, AssertionException);
 };/* class SmtEnginePrivate */
 
 }/* namespace CVC4::smt */
 
-using ::CVC4::smt::SmtEnginePrivate;
+using namespace CVC4::smt;
 
-SmtEngine::SmtEngine(ExprManager* em, const Options* opts) throw () :
+SmtEngine::SmtEngine(ExprManager* em, const Options* opts) throw() :
   d_context(em->getContext()),
   d_exprManager(em),
   d_nodeManager(em->getNodeManager()),
@@ -94,7 +131,7 @@ SmtEngine::SmtEngine(ExprManager* em, const Options* opts) throw () :
                                 d_theoryEngine, d_context);
   d_theoryEngine->setPropEngine(d_propEngine);
 
-  d_functions = new(true) FunctionMap(d_context);
+  d_definedFunctions = new(true) DefinedFunctionMap(d_context);
 
   if(d_options->interactive) {
     d_assertionList = new(true) AssertionList(d_context);
@@ -116,46 +153,125 @@ SmtEngine::~SmtEngine() {
     d_assertionList->deleteSelf();
   }
 
-  d_functions->deleteSelf();
+  d_definedFunctions->deleteSelf();
 
   delete d_theoryEngine;
   delete d_propEngine;
   delete d_decisionEngine;
 }
 
-void SmtEngine::doCommand(Command* c) {
-  NodeManagerScope nms(d_nodeManager);
-  c->invoke(this);
-}
-
-void SmtEngine::setInfo(const std::string& key, const SExpr& value) throw(BadOption) {
+void SmtEngine::setInfo(const string& key, const SExpr& value)
+  throw(BadOptionException) {
+  if(key == ":status") {
+    return;
+  }
   // FIXME implement me
+  throw BadOptionException();
 }
 
-const SExpr& SmtEngine::getInfo(const std::string& key) const throw(BadOption) {
+const SExpr& SmtEngine::getInfo(const string& key) const
+  throw(BadOptionException) {
   // FIXME implement me
-  throw BadOption();
+  throw BadOptionException();
 }
 
-void SmtEngine::setOption(const std::string& key, const SExpr& value) throw(BadOption) {
+void SmtEngine::setOption(const string& key, const SExpr& value)
+  throw(BadOptionException) {
   // FIXME implement me
+  throw BadOptionException();
 }
 
-const SExpr& SmtEngine::getOption(const std::string& key) const throw(BadOption) {
+const SExpr& SmtEngine::getOption(const string& key) const
+  throw(BadOptionException) {
   // FIXME implement me
-  throw BadOption();
+  throw BadOptionException();
 }
 
-void SmtEngine::defineFunction(const string& name,
-                               const vector<pair<string, Type> >& args,
-                               Type type,
+void SmtEngine::defineFunction(Expr func,
+                               const vector<Expr>& formals,
                                Expr formula) {
   NodeManagerScope nms(d_nodeManager);
-  d_functions->insert(name, make_pair(make_pair(args, type), formula));
+  TNode funcNode = func.getTNode();
+  vector<Node> formalsNodes;
+  for(vector<Expr>::const_iterator i = formals.begin(),
+        iend = formals.end();
+      i != iend;
+      ++i) {
+    formalsNodes.push_back((*i).getNode());
+  }
+  TNode formulaNode = formula.getTNode();
+  DefinedFunction def(funcNode, formalsNodes, formulaNode);
+  d_definedFunctions->insert(funcNode, def);
 }
 
-Node SmtEnginePrivate::preprocess(SmtEngine& smt, TNode n) {
-  return smt.d_theoryEngine->preprocess(n);
+Node SmtEnginePrivate::expandDefinitions(SmtEngine& smt, TNode n)
+  throw(NoSuchFunctionException, AssertionException) {
+  if(n.getKind() == kind::APPLY) {
+    TNode func = n.getOperator();
+    SmtEngine::DefinedFunctionMap::const_iterator i =
+      smt.d_definedFunctions->find(func);
+    DefinedFunction def = (*i).second;
+    vector<Node> formals = def.getFormals();
+
+    if(Debug.isOn("expand")) {
+      Debug("expand") << "found: " << n << endl;
+      Debug("expand") << " func: " << func << endl;
+      string name = func.getAttribute(expr::VarNameAttr());
+      Debug("expand") << "     : \"" << name << "\"" << endl;
+      if(i == smt.d_definedFunctions->end()) {
+        throw NoSuchFunctionException(Expr(smt.d_exprManager, new Node(func)));
+      }
+      Debug("expand") << " defn: " << def.getFunction() << endl
+                      << "       [";
+      if(formals.size() > 0) {
+        copy( formals.begin(), formals.end() - 1,
+              ostream_iterator<Node>(Debug("expand"), ", ") );
+        Debug("expand") << formals.back();
+      }
+      Debug("expand") << "]" << endl
+                      << "       " << def.getFunction().getType() << endl
+                      << "       " << def.getFormula() << endl;
+    }
+
+    TNode fm = def.getFormula();
+    Node instance = fm.substitute(formals.begin(), formals.end(),
+                                  n.begin(), n.end());
+    Debug("expand") << "made : " << instance << endl;
+
+    Node expanded = expandDefinitions(smt, instance);
+    return expanded;
+  } else if(n.getNumChildren() == 0) {
+    return n;
+  } else {
+    Debug("expand") << "cons : " << n << endl;
+    NodeBuilder<> nb(n.getKind());
+    if(n.getMetaKind() == kind::metakind::PARAMETERIZED) {
+      Debug("expand") << "op   : " << n.getOperator() << endl;
+      nb << n.getOperator();
+    }
+    for(TNode::iterator i = n.begin(),
+          iend = n.end();
+        i != iend;
+        ++i) {
+      Node expanded = expandDefinitions(smt, *i);
+      Debug("expand") << "exchld: " << expanded << endl;
+      nb << expanded;
+    }
+    Node node = nb;
+    return node;
+  }
+}
+
+Node SmtEnginePrivate::preprocess(SmtEngine& smt, TNode n)
+  throw(NoSuchFunctionException, AssertionException) {
+  if(!smt.d_options->lazyDefinitionExpansion) {
+    Node node = expandDefinitions(smt, n);
+    Debug("expand") << "have: " << n << endl
+                    << "made: " << node << endl;
+    return smt.d_theoryEngine->preprocess(node);
+  } else {
+    return smt.d_theoryEngine->preprocess(n);
+  }
 }
 
 Result SmtEngine::check() {
@@ -168,7 +284,8 @@ Result SmtEngine::quickCheck() {
   return Result(Result::VALIDITY_UNKNOWN);
 }
 
-void SmtEnginePrivate::addFormula(SmtEngine& smt, TNode n) {
+void SmtEnginePrivate::addFormula(SmtEngine& smt, TNode n)
+  throw(NoSuchFunctionException, AssertionException) {
   Debug("smt") << "push_back assertion " << n << endl;
   smt.d_propEngine->assertFormula(SmtEnginePrivate::preprocess(smt, n));
 }
@@ -209,8 +326,16 @@ Model SmtEngine::getModel() {
   Unimplemented();
 }
 
-Expr SmtEngine::getValue(Expr term) {
+Expr SmtEngine::getValue(Expr term)
+  throw(NoninteractiveException, AssertionException) {
+  if(!d_options->interactive) {
+    const char* msg =
+      "Cannot query the current assertion list when not in interactive mode.";
+    throw NoninteractiveException(msg);
+  }
+
   NodeManagerScope nms(d_nodeManager);
+
   Unimplemented();
 }
 
index 97772273d55f6e8c4e3922c8573bbb93218db3e6..c9bf321b9e3ababb760d5fc6178295b6396be4ab 100644 (file)
@@ -31,7 +31,8 @@
 #include "util/sexpr.h"
 #include "util/hash.h"
 #include "smt/noninteractive_exception.h"
-#include "smt/bad_option.h"
+#include "smt/no_such_function_exception.h"
+#include "smt/bad_option_exception.h"
 
 // In terms of abstraction, this is below (and provides services to)
 // ValidityChecker and above (and requires the services of)
 
 namespace CVC4 {
 
-namespace context {
-  class Context;
-  template <class T> class CDList;
-}/* CVC4::context namespace */
-
+template <bool ref_count> class NodeTemplate;
+typedef NodeTemplate<true> Node;
+typedef NodeTemplate<false> TNode;
+class NodeHashFunction;
 class Command;
 class Options;
 class TheoryEngine;
 class DecisionEngine;
 
+namespace context {
+  class Context;
+  template <class T> class CDList;
+}/* CVC4::context namespace */
+
 namespace prop {
   class PropEngine;
 }/* CVC4::prop namespace */
 
 namespace smt {
+  /**
+   * Representation of a defined function.  We keep these around in
+   * SmtEngine to permit expanding definitions late (and lazily), to
+   * support getValue() over defined functions, to support user output
+   * in terms of defined functions, etc.
+   */
+  class DefinedFunction;
+
   class SmtEnginePrivate;
 }/* CVC4::smt namespace */
 
@@ -69,17 +82,10 @@ namespace smt {
 // The CNF conversion can go on in PropEngine.
 
 class CVC4_PUBLIC SmtEngine {
-private:
 
-  /** A name/type pair, used for signatures */
-  typedef std::pair<std::string, Type> TypedArg;
-  /** A vector of typed formals, and a return type */
-  typedef std::pair<std::vector<TypedArg>, Type> FunctionSignature;
   /** The type of our internal map of defined functions */
-  typedef context::CDMap<std::string, std::pair<FunctionSignature, Expr>,
-    StringHashFunction>
-    FunctionMap;
-
+  typedef context::CDMap<Node, smt::DefinedFunction, NodeHashFunction>
+    DefinedFunctionMap;
   /** The type of our internal assertion list */
   typedef context::CDList<Expr> AssertionList;
 
@@ -98,7 +104,7 @@ private:
   /** The propositional engine */
   prop::PropEngine* d_propEngine;
   /** An index of our defined functions */
-  FunctionMap* d_functions;
+  DefinedFunctionMap* d_definedFunctions;
   /**
    * The assertion list (before any conversion) for supporting
    * getAssertions().  Only maintained if in interactive mode.
@@ -140,30 +146,29 @@ public:
    */
   ~SmtEngine();
 
-  /**
-   * Execute a command.
-   */
-  void doCommand(Command*);
-
   /**
    * Set information about the script executing.
    */
-  void setInfo(const std::string& key, const SExpr& value) throw(BadOption);
+  void setInfo(const std::string& key, const SExpr& value)
+    throw(BadOptionException);
 
   /**
    * Query information about the SMT environment.
    */
-  const SExpr& getInfo(const std::string& key) const throw(BadOption);
+  const SExpr& getInfo(const std::string& key) const
+    throw(BadOptionException);
 
   /**
    * Set an aspect of the current SMT execution environment.
    */
-  void setOption(const std::string& key, const SExpr& value) throw(BadOption);
+  void setOption(const std::string& key, const SExpr& value)
+    throw(BadOptionException);
 
   /**
    * Get an aspect of the current SMT execution environment.
    */
-  const SExpr& getOption(const std::string& key) const throw(BadOption);
+  const SExpr& getOption(const std::string& key) const
+    throw(BadOptionException);
 
   /**
    * Add a formula to the current context: preprocess, do per-theory
@@ -171,9 +176,8 @@ public:
    * literals and conjunction of literals.  Returns false iff
    * inconsistent.
    */
-  void defineFunction(const std::string& name,
-                      const std::vector<std::pair<std::string, Type> >& args,
-                      Type type,
+  void defineFunction(Expr func,
+                      const std::vector<Expr>& formals,
                       Expr formula);
 
   /**
@@ -209,12 +213,14 @@ public:
 
   /**
    * Get the assigned value of a term (only if preceded by a SAT or
-   * INVALID query).
+   * INVALID query).  Only permitted if the SmtEngine is set to
+   * operate interactively.
    */
-  Expr getValue(Expr term);
+  Expr getValue(Expr term) throw(NoninteractiveException, AssertionException);
 
   /**
-   * Get the current set of assertions.
+   * Get the current set of assertions.  Only permitted if the
+   * SmtEngine is set to operate interactively.
    */
   std::vector<Expr> getAssertions() throw(NoninteractiveException);
 
index c504177bfa48efeaf2558acf89f7deaa1e5e8917..9bb0b0a3809ff979b709e4c440bbed00447c91ea 100644 (file)
@@ -65,6 +65,9 @@ struct CVC4_PUBLIC Options {
   /** Should we strictly enforce the language standard while parsing? */
   bool strictParsing;
 
+  /** Should we expand function definitions lazily? */
+  bool lazyDefinitionExpansion;
+
   /** Whether we're in interactive mode or not */
   bool interactive;
 
@@ -86,6 +89,7 @@ struct CVC4_PUBLIC Options {
     semanticChecks(true),
     memoryMap(false),
     strictParsing(false),
+    lazyDefinitionExpansion(false),
     interactive(false),
     interactiveSetByUser(false) {
   }
index cdd3479622be25ab20fafda66e454a597ec84f37..9bc8991ab2450e9adb63e0f57f5a7ce7334589cf 100644 (file)
@@ -33,6 +33,7 @@ SMT2_TESTS = \
        ite4.smt2 \
         simple-lra.smt2 \
         simple-rdl.smt2 \
+        simple-rdl-definefun.smt2 \
        simple-uf.smt2
 
 # Regression tests for PL inputs
diff --git a/test/regress/regress0/simple-rdl-definefun.smt2 b/test/regress/regress0/simple-rdl-definefun.smt2
new file mode 100644 (file)
index 0000000..08e9986
--- /dev/null
@@ -0,0 +1,14 @@
+(set-logic QF_RDL)
+(set-info :status unsat)
+(declare-fun x () Real)
+(declare-fun y () Real)
+(declare-sort U 0)
+(declare-sort A 2)
+(define-sort F (x) (A Real Real))
+(declare-fun x2 () (F Real))
+(define-fun minus ((x Real) (z Real)) Real (- x z))
+(define-fun less ((x Real) (z Real)) Bool (< x z))
+(define-fun foo ((x Real) (z Real)) Bool (less x z))
+(assert (not (=> (foo (minus x y) 0) (less x y))))
+(check-sat)
+(exit)