Abstract values for SMT-LIB.
authorMorgan Deters <mdeters@gmail.com>
Wed, 10 Oct 2012 21:20:40 +0000 (21:20 +0000)
committerMorgan Deters <mdeters@gmail.com>
Wed, 10 Oct 2012 21:20:40 +0000 (21:20 +0000)
Also fix bug 421 relating to incrementality and models.

(this commit was certified error- and warning-free by the test-and-commit script.)

17 files changed:
src/expr/node.cpp
src/expr/node.h
src/expr/node_builder.h
src/options/base_options
src/parser/smt2/Smt2.g
src/parser/smt2/smt2.h
src/smt/options
src/smt/smt_engine.cpp
src/smt/smt_engine.h
src/theory/builtin/kinds
src/theory/builtin/theory_builtin_type_rules.h
src/theory/substitutions.cpp
src/util/Makefile.am
src/util/abstract_value.cpp [new file with mode: 0644]
src/util/abstract_value.h [new file with mode: 0644]
test/regress/regress0/Makefile.am
test/regress/regress0/bug421.smt2 [new file with mode: 0644]

index e303a9e5866287b12bf02f1d4f4e180f6244b9f9..f6c2250b1d7e8f8c8270741762a0f5357a1b4008 100644 (file)
@@ -43,4 +43,9 @@ NodeTemplate<true> TypeCheckingExceptionPrivate::getNode() const throw() {
   return *d_node;
 }
 
+UnknownTypeException::UnknownTypeException(TNode n) throw() :
+  TypeCheckingExceptionPrivate(n, "this expression contains an element of unknown type (such as an abstract value);"
+                               " its type cannot be computed until it is substituted away") {
+}
+
 }/* CVC4 namespace */
index b7c4b3ad8cc5a0f305604ecd8aa0ad1fa3265ae8..1c0646556c26ae82312e84448b53a9d97fd74ac8 100644 (file)
@@ -100,6 +100,13 @@ public:
 
 };/* class TypeCheckingExceptionPrivate */
 
+class UnknownTypeException : public TypeCheckingExceptionPrivate {
+public:
+
+  UnknownTypeException(NodeTemplate<false> node) throw();
+
+};/* class UnknownTypeException */
+
 /**
  * \typedef NodeTemplate<true> Node;
  *
index 0c8ac40f8f531580210eac5be030efa68d35da7e..351cf363960bfb935f9550628be41e384a9384ec 100644 (file)
@@ -1305,7 +1305,14 @@ inline void NodeBuilder<nchild_thresh>::maybeCheckType(const TNode n) const
     kind::MetaKind mk = n.getMetaKind();
     if( mk != kind::metakind::VARIABLE
         && mk != kind::metakind::CONSTANT ) {
-      d_nm->getType(n, true);
+      try {
+        d_nm->getType(n, true);
+      } catch(UnknownTypeException&) {
+        // Ignore the error; this expression doesn't have a type,
+        // because it has an abstract value in it.  If the user
+        // depends on the type of this expression, he should get an
+        // exception, but so far he's only constructed it.
+      }
     }
   }
 }
index 573a11d29332aa514573ff33e8f3be8092834ac3..d19c3b812eecb2f343ef0782aab2f7767cff033a 100644 (file)
@@ -125,7 +125,7 @@ option - debug -d --debug=TAG argument :handler CVC4::options::addDebugTag
 option printSuccess print-success --print-success bool :predicate CVC4::options::setPrintSuccess :predicate-include "options/base_options_handlers.h"
  print the "success" output required of SMT-LIBv2
 
-alias --smtlib = --lang=smt2 --output-lang=smt2 --strict-parsing --default-expr-depth=-1 --print-success --incremental
+alias --smtlib = --lang=smt2 --output-lang=smt2 --strict-parsing --default-expr-depth=-1 --print-success --incremental --abstract-values
  SMT-LIBv2 compliance mode (implies other options)
 undocumented-alias --smtlib2 = --smtlib
 
index a49ae35c50ab1a38693104352cb5edca473335a4..915113dbccac0b6a59117676ca3942cbd904779b 100644 (file)
@@ -11,7 +11,7 @@
  ** See the file COPYING in the top-level source directory for licensing
  ** information.\endverbatim
  **
- ** \brief Parser for SMT-LIB v2 input language.
+ ** \brief Parser for SMT-LIB v2 input language
  **
  ** Parser for SMT-LIB v2 input language.
  **/
@@ -355,7 +355,7 @@ command returns [CVC4::Command* cmd = NULL]
   | EXIT_TOK
     { cmd = new QuitCommand; }
 
-    /* CVC4-extended SMT-LIBv2 commands */
+    /* CVC4-extended SMT-LIB commands */
   | extendedCommand[cmd]
     { if(PARSER_STATE->strictModeEnabled()) {
         PARSER_STATE->parseError("Extended commands are not permitted while operating in strict compliance mode.");
@@ -385,7 +385,7 @@ extendedCommand[CVC4::Command*& cmd]
   std::vector<Type> sorts;
   std::vector<std::pair<std::string, Type> > sortedVarNames;
 }
-    /* Extended SMT-LIBv2 set of commands syntax, not permitted in
+    /* Extended SMT-LIB set of commands syntax, not permitted in
      * --smtlib2 compliance mode. */
   : DECLARE_DATATYPES_TOK { PARSER_STATE->checkThatLogicIsSet(); }
     { /* open a scope to keep the UnresolvedTypes contained */
@@ -407,7 +407,7 @@ extendedCommand[CVC4::Command*& cmd]
     )
   | rewriterulesCommand[cmd]
 
-    /* Support some of Z3's extended SMT-LIBv2 commands */
+    /* Support some of Z3's extended SMT-LIB commands */
 
   | DECLARE_CONST_TOK { PARSER_STATE->checkThatLogicIsSet(); }
     symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
@@ -624,7 +624,6 @@ pattern[CVC4::Expr& expr]
   : LPAREN_TOK termList[patexpr,expr] RPAREN_TOK
     {
       expr = MK_EXPR(kind::INST_PATTERN, patexpr);
-      //std::cout << "parsed pattern expr " << retExpr << std::endl;
     }
   ;
 
@@ -811,7 +810,9 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
   | symbol[name,CHECK_DECLARED,SYM_VARIABLE]
     { const bool isDefinedFunction =
         PARSER_STATE->isDefinedFunction(name);
-      if(isDefinedFunction) {
+      if(PARSER_STATE->isAbstractValue(name)) {
+        expr = PARSER_STATE->mkAbstractValue(name);
+      } else if(isDefinedFunction) {
         expr = MK_EXPR(CVC4::kind::APPLY,
                        PARSER_STATE->getFunction(name));
       } else {
@@ -1206,13 +1207,19 @@ symbol[std::string& id,
        CVC4::parser::SymbolType type]
   : SIMPLE_SYMBOL
     { id = AntlrInput::tokenText($SIMPLE_SYMBOL);
-      PARSER_STATE->checkDeclaration(id, check, type);
+      if(!PARSER_STATE->isAbstractValue(id)) {
+        // if an abstract value, SmtEngine handles declaration
+        PARSER_STATE->checkDeclaration(id, check, type);
+      }
     }
   | QUOTED_SYMBOL
     { id = AntlrInput::tokenText($QUOTED_SYMBOL);
       /* strip off the quotes */
       id = id.substr(1, id.size() - 2);
-      PARSER_STATE->checkDeclaration(id, check, type);
+      if(!PARSER_STATE->isAbstractValue(id)) {
+        // if an abstract value, SmtEngine handles declaration
+        PARSER_STATE->checkDeclaration(id, check, type);
+      }
     }
   ;
 
@@ -1521,7 +1528,7 @@ fragment HEX_DIGIT : DIGIT | 'a'..'f' | 'A'..'F';
 
 /**
  * Matches the characters that may appear as a one-character "symbol"
- * (which excludes _ and !, which are reserved words in SMT-LIBv2).
+ * (which excludes _ and !, which are reserved words in SMT-LIB).
  */
 fragment SYMBOL_CHAR_NOUNDERSCORE_NOATTRIBUTE
   : '+' | '-' | '/' | '*' | '=' | '%' | '?' | '.' | '$' | '~'
index 48942265a1e2c6abfae4ac55e4f7b8f11e9f58ff..e9c18bc97fb06a8347fcd767ff635f7d3475d3c7 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "parser/parser.h"
 #include "parser/smt1/smt1.h"
+#include "util/abstract_value.h"
 
 #include <sstream>
 
@@ -78,15 +79,23 @@ public:
   void checkThatLogicIsSet();
 
   void checkUserSymbol(const std::string& name) {
-    if( strictModeEnabled() &&
-        name.length() > 0 &&
-        ( name[0] == '.' || name[0] == '@' ) ) {
+    if(name.length() > 0 && (name[0] == '.' || name[0] == '@')) {
       std::stringstream ss;
-      ss << "cannot declare or define symbol `" << name << "'; symbols starting with . and @ are reserved in SMT-LIBv2";
+      ss << "cannot declare or define symbol `" << name << "'; symbols starting with . and @ are reserved in SMT-LIB";
       parseError(ss.str());
     }
   }
 
+  bool isAbstractValue(const std::string& name) {
+    return name.length() >= 2 && name[0] == '@' && name[1] != '0' &&
+      name.find_first_not_of("0123456789", 1) == std::string::npos;
+  }
+
+  Expr mkAbstractValue(const std::string& name) {
+    assert(isAbstractValue(name));
+    return getExprManager()->mkConst(AbstractValue(Integer(name.substr(1))));
+  }
+
 private:
 
   void addArithmeticOperators();
index ab5f9330a1910d44ee2e09c7059b3a744425a401..ab903c951a471947064ebe47ba451711661e29eb 100644 (file)
@@ -49,6 +49,9 @@ option repeatSimp --repeat-simp bool :read-write
 common-option incrementalSolving incremental -i --incremental bool
  enable incremental solving
 
+option abstractValues abstract-values --abstract-values bool :default false
+ in models, output arrays (and in future, maybe others) using abstract values, as required by the SMT-LIB standard
+
 option - regular-output-channel argument :handler CVC4::smt::setRegularOutputChannel :handler-include "smt/options_handlers.h"
  set the regular output channel of the solver
 option - diagnostic-output-channel argument :handler CVC4::smt::setDiagnosticOutputChannel :handler-include "smt/options_handlers.h"
index cc126d6cdead09cb84a1e7c23e4a5efd5ae24144..734236d8ae8e607d55f4055ba0735f9b75f07f07 100644 (file)
@@ -37,6 +37,7 @@
 #include "expr/kind.h"
 #include "expr/metakind.h"
 #include "expr/node_builder.h"
+#include "expr/node.h"
 #include "prop/prop_engine.h"
 #include "smt/modal_exception.h"
 #include "smt/smt_engine.h"
@@ -199,6 +200,26 @@ class SmtEnginePrivate : public NodeManagerListener {
   /** Assertions to push to sat */
   vector<Node> d_assertionsToCheck;
 
+  /**
+   * A context that never pushes/pops, for use by CD structures (like
+   * SubstitutionMaps) that should be "global".
+   */
+  context::Context d_fakeContext;
+
+  /**
+   * A map of AbsractValues to their actual constants.  Only used if
+   * options::abstractValues() is on.
+   */
+  theory::SubstitutionMap d_abstractValueMap;
+
+  /**
+   * A mapping of all abstract values (actual value |-> abstract) that
+   * we've handed out.  This is necessary to ensure that we give the
+   * same AbstractValues for the same real constants.  Only used if
+   * options::abstractValues() is on.
+   */
+  hash_map<Node, Node, NodeHashFunction> d_abstractValues;
+
   /**
    * Map from skolem variables to index in d_assertionsToCheck containing
    * corresponding introduced Boolean ite
@@ -206,6 +227,7 @@ class SmtEnginePrivate : public NodeManagerListener {
   IteSkolemMap d_iteSkolemMap;
 
 public:
+
   /** Instance of the ITE remover */
   RemoveITE d_iteRemover;
 
@@ -277,6 +299,9 @@ public:
     d_realAssertionsEnd(0),
     d_propagator(d_nonClausalLearnedLiterals, true, true),
     d_assertionsToCheck(),
+    d_fakeContext(),
+    d_abstractValueMap(&d_fakeContext),
+    d_abstractValues(),
     d_iteSkolemMap(),
     d_iteRemover(smt.d_userContext),
     d_topLevelSubstitutions(smt.d_userContext),
@@ -369,7 +394,31 @@ public:
   /**
    * pre-skolemize quantifiers
    */
-  Node preSkolemizeQuantifiers( Node n, bool polarity, std::vector< Node >& fvs );
+  Node preSkolemizeQuantifiers(Node n, bool polarity, std::vector<Node>& fvs);
+
+  /**
+   * Substitute away all AbstractValues in a node.
+   */
+  Node substituteAbstractValues(TNode n) {
+    // We need to do this even if options::abstractValues() is off,
+    // since the setting might have changed after we already gave out
+    // some abstract values.
+    return d_abstractValueMap.apply(n);
+  }
+
+  /**
+   * Make a new (or return an existing) abstract value for a node.
+   * Can only use this if options::abstractValues() is on.
+   */
+  Node mkAbstractValue(TNode n) {
+    Assert(options::abstractValues());
+    Node& val = d_abstractValues[n];
+    if(val.isNull()) {
+      val = d_smt.d_nodeManager->mkConst(AbstractValue(d_abstractValues.size()));
+      d_abstractValueMap.addSubstitution(val, n);
+    }
+    return val;
+  }
 
 };/* class SmtEnginePrivate */
 
@@ -910,8 +959,11 @@ void SmtEngine::defineFunction(Expr func,
   }
   SmtScope smts(this);
 
+  // Substitute out any abstract values in formula
+  Expr form = d_private->substituteAbstractValues(Node::fromExpr(formula)).toExpr();
+
   // type check body
-  Type formulaType = formula.getType(options::typeChecking());
+  Type formulaType = form.getType(options::typeChecking());
 
   Type funcType = func.getType();
   // We distinguish here between definitions of constants and functions,
@@ -949,12 +1001,12 @@ void SmtEngine::defineFunction(Expr func,
       ++i) {
     formalsNodes.push_back((*i).getNode());
   }
-  TNode formulaNode = formula.getTNode();
-  DefinedFunction def(funcNode, formalsNodes, formulaNode);
+  TNode formNode = form.getTNode();
+  DefinedFunction def(funcNode, formalsNodes, formNode);
   // Permit (check-sat) (define-fun ...) (get-value ...) sequences.
   // Otherwise, (check-sat) (get-value ((! foo :named bar))) breaks
   // d_haveAdditions = true;
-  Debug("smt") << "definedFunctions insert " << funcNode << " " << formulaNode << std::endl;
+  Debug("smt") << "definedFunctions insert " << funcNode << " " << formNode << std::endl;
   d_definedFunctions->insert(funcNode, def);
 }
 
@@ -1582,7 +1634,7 @@ bool SmtEnginePrivate::simplifyAssertions()
       unconstrainedSimp();
     }
 
-    Trace("smt") << "POST unconstraintedSimp" << std::endl;
+    Trace("smt") << "POST unconstrainedSimp" << std::endl;
     Debug("smt") << " d_assertionsToPreprocess: " << d_assertionsToPreprocess.size() << endl;
     Debug("smt") << " d_assertionsToCheck     : " << d_assertionsToCheck.size() << endl;
 
@@ -1884,15 +1936,12 @@ void SmtEngine::ensureBoolean(const Expr& e) throw(TypeCheckingException) {
   }
 }
 
-Result SmtEngine::checkSat(const Expr& e) throw(TypeCheckingException, ModalException) {
-
-  Assert(e.isNull() || e.getExprManager() == d_exprManager);
-
+Result SmtEngine::checkSat(const Expr& ex) throw(TypeCheckingException, ModalException) {
+  Assert(ex.isNull() || ex.getExprManager() == d_exprManager);
   SmtScope smts(this);
   finalOptionsAreSet();
   doPendingPops();
-
-  Trace("smt") << "SmtEngine::checkSat(" << e << ")" << endl;
+  Trace("smt") << "SmtEngine::checkSat(" << ex << ")" << endl;
 
   if(d_queryMade && !options::incrementalSolving()) {
     throw ModalException("Cannot make multiple queries unless "
@@ -1900,8 +1949,11 @@ Result SmtEngine::checkSat(const Expr& e) throw(TypeCheckingException, ModalExce
                          "(try --incremental)");
   }
 
-  // Ensure that the expression is type-checked at this point, and Boolean
-  if(!e.isNull()) {
+  Expr e;
+  if(!ex.isNull()) {
+    // Substitute out any abstract values in ex.
+    e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
+    // Ensure expr is type-checked at this point.
     ensureBoolean(e);
   }
 
@@ -1951,16 +2003,13 @@ Result SmtEngine::checkSat(const Expr& e) throw(TypeCheckingException, ModalExce
   return r;
 }/* SmtEngine::checkSat() */
 
-Result SmtEngine::query(const Expr& e) throw(TypeCheckingException, ModalException) {
-
-  Assert(!e.isNull());
-  Assert(e.getExprManager() == d_exprManager);
-
+Result SmtEngine::query(const Expr& ex) throw(TypeCheckingException, ModalException) {
+  Assert(!ex.isNull());
+  Assert(ex.getExprManager() == d_exprManager);
   SmtScope smts(this);
   finalOptionsAreSet();
   doPendingPops();
-
-  Trace("smt") << "SMT query(" << e << ")" << endl;
+  Trace("smt") << "SMT query(" << ex << ")" << endl;
 
   if(d_queryMade && !options::incrementalSolving()) {
     throw ModalException("Cannot make multiple queries unless "
@@ -1968,6 +2017,9 @@ Result SmtEngine::query(const Expr& e) throw(TypeCheckingException, ModalExcepti
                          "(try --incremental)");
   }
 
+  // Substitute out any abstract values in ex
+  Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
+
   // Ensure that the expression is type-checked at this point, and Boolean
   ensureBoolean(e);
 
@@ -2015,12 +2067,16 @@ Result SmtEngine::query(const Expr& e) throw(TypeCheckingException, ModalExcepti
   return r;
 }/* SmtEngine::query() */
 
-Result SmtEngine::assertFormula(const Expr& e) throw(TypeCheckingException) {
-  Assert(e.getExprManager() == d_exprManager);
+Result SmtEngine::assertFormula(const Expr& ex) throw(TypeCheckingException) {
+  Assert(ex.getExprManager() == d_exprManager);
   SmtScope smts(this);
   finalOptionsAreSet();
   doPendingPops();
-  Trace("smt") << "SmtEngine::assertFormula(" << e << ")" << endl;
+  Trace("smt") << "SmtEngine::assertFormula(" << ex << ")" << endl;
+
+  // Substitute out any abstract values in ex
+  Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
+
   ensureBoolean(e);
   if(d_assertionList != NULL) {
     d_assertionList->push_back(e);
@@ -2029,33 +2085,44 @@ Result SmtEngine::assertFormula(const Expr& e) throw(TypeCheckingException) {
   return quickCheck().asValidityResult();
 }
 
-Expr SmtEngine::simplify(const Expr& e) throw(TypeCheckingException) {
-  Assert(e.getExprManager() == d_exprManager);
+Expr SmtEngine::simplify(const Expr& ex) throw(TypeCheckingException) {
+  Assert(ex.getExprManager() == d_exprManager);
   SmtScope smts(this);
   finalOptionsAreSet();
   doPendingPops();
+  Trace("smt") << "SMT simplify(" << ex << ")" << endl;
+
+  if(Dump.isOn("benchmark")) {
+    Dump("benchmark") << SimplifyCommand(ex);
+  }
+
+  // Substitute out any abstract values in ex.
+  Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
   if( options::typeChecking() ) {
     e.getType(true);// ensure expr is type-checked at this point
   }
-  Trace("smt") << "SMT simplify(" << e << ")" << endl;
-  if(Dump.isOn("benchmark")) {
-    Dump("benchmark") << SimplifyCommand(e);
-  }
+  // Expand definitions.
+  hash_map<Node, Node, NodeHashFunction> cache;
+  e = d_private->expandDefinitions(Node::fromExpr(e), cache).toExpr();
   // Make sure we've done simple preprocessing, unit detection, etc.
   Trace("smt") << "SmtEngine::check(): processing assertions" << endl;
   d_private->processAssertions();
   return d_private->applySubstitutions(e).toExpr();
 }
 
-Expr SmtEngine::expandDefinitions(const Expr& e) throw(TypeCheckingException) {
-  Assert(e.getExprManager() == d_exprManager);
+Expr SmtEngine::expandDefinitions(const Expr& ex) throw(TypeCheckingException) {
+  Assert(ex.getExprManager() == d_exprManager);
   SmtScope smts(this);
   finalOptionsAreSet();
   doPendingPops();
-  if( options::typeChecking() ) {
-    e.getType(true);// ensure expr is type-checked at this point
+  Trace("smt") << "SMT expandDefinitions(" << ex << ")" << endl;
+
+  // Substitute out any abstract values in ex.
+  Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
+  if(options::typeChecking()) {
+    // Ensure expr is type-checked at this point.
+    e.getType(true);
   }
-  Trace("smt") << "SMT expandDefinitions(" << e << ")" << endl;
   if(Dump.isOn("benchmark")) {
     Dump("benchmark") << ExpandDefinitionsCommand(e);
   }
@@ -2063,17 +2130,15 @@ Expr SmtEngine::expandDefinitions(const Expr& e) throw(TypeCheckingException) {
   return d_private->expandDefinitions(Node::fromExpr(e), cache).toExpr();
 }
 
-Expr SmtEngine::getValue(const Expr& e) throw(ModalException) {
-  Assert(e.getExprManager() == d_exprManager);
+Expr SmtEngine::getValue(const Expr& ex) throw(ModalException) {
+  Assert(ex.getExprManager() == d_exprManager);
   SmtScope smts(this);
 
-  // ensure expr is type-checked at this point
-  Type type = e.getType(options::typeChecking());
-
-  Trace("smt") << "SMT getValue(" << e << ")" << endl;
+  Trace("smt") << "SMT getValue(" << ex << ")" << endl;
   if(Dump.isOn("benchmark")) {
-    Dump("benchmark") << GetValueCommand(e);
+    Dump("benchmark") << GetValueCommand(ex);
   }
+
   if(!options::produceModels()) {
     const char* msg =
       "Cannot get value when produce-models options is off.";
@@ -2087,11 +2152,18 @@ Expr SmtEngine::getValue(const Expr& e) throw(ModalException) {
     throw ModalException(msg);
   }
 
+  // Substitute out any abstract values in ex.
+  Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
+
+  // Ensure expr is type-checked at this point.
+  e.getType(options::typeChecking());
+
   // do not need to apply preprocessing substitutions (should be recorded
   // in model already)
 
   // Expand, then normalize
-  Node n = expandDefinitions(e).getNode();
+  hash_map<Node, Node, NodeHashFunction> cache;
+  Node n = d_private->expandDefinitions(Node::fromExpr(e), cache);
   n = Rewriter::rewrite(n);
 
   Trace("smt") << "--- getting value of " << n << endl;
@@ -2101,15 +2173,26 @@ Expr SmtEngine::getValue(const Expr& e) throw(ModalException) {
     resultNode = m->getValue( n );
   }
   Trace("smt") << "--- got value " << n << " = " << resultNode << endl;
+
   // type-check the result we got
-  Assert(resultNode.isNull() || resultNode.getType().isSubtypeOf( n.getType() ));
-  return Expr(d_exprManager, new Node(resultNode));
+  Assert(resultNode.isNull() || resultNode.getType().isSubtypeOf(n.getType()));
+
+  // ensure it's a constant
+  Assert(resultNode.isConst());
+
+  if(options::abstractValues() && resultNode.getType().isArray()) {
+    resultNode = d_private->mkAbstractValue(resultNode);
+  }
+
+  return resultNode.toExpr();
 }
 
-bool SmtEngine::addToAssignment(const Expr& e) throw() {
+bool SmtEngine::addToAssignment(const Expr& ex) throw() {
   SmtScope smts(this);
   finalOptionsAreSet();
   doPendingPops();
+  // Substitute out any abstract values in ex
+  Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
   Type type = e.getType(options::typeChecking());
   // must be Boolean
   CheckArgument( type.isBoolean(), e,
index 93608ec591a2fba80c85dc772e18ee6e96029707..b6eacea4ce1adcb6c4dfaf5a639f7735dbf38306 100644 (file)
@@ -34,6 +34,7 @@
 #include "options/options.h"
 #include "util/result.h"
 #include "util/sexpr.h"
+#include "util/hash.h"
 #include "util/statistics.h"
 #include "theory/logic_info.h"
 
index 86efac2f08e7ed47b852ef7728553c1a6fa6dcdb..bcf787f6b2606e80f3f00d82157f4aeffc143b0d 100644 (file)
@@ -265,12 +265,19 @@ constant UNINTERPRETED_CONSTANT \
     ::CVC4::UninterpretedConstant \
     ::CVC4::UninterpretedConstantHashFunction \
     "util/uninterpreted_constant.h" \
-    "The kind of nodes representing uninterpreted constants"
+    "The kind of expressions representing uninterpreted constants"
 typerule UNINTERPRETED_CONSTANT ::CVC4::theory::builtin::UninterpretedConstantTypeRule
 enumerator SORT_TYPE \
     ::CVC4::theory::builtin::UninterpretedSortEnumerator \
     "theory/builtin/type_enumerator.h"
 
+constant ABSTRACT_VALUE \
+    ::CVC4::AbstractValue \
+    ::CVC4::AbstractValueHashFunction \
+    "util/abstract_value.h" \
+    "The kind of expressions representing abstract values (other than uninterpreted sort constants)"
+typerule ABSTRACT_VALUE ::CVC4::theory::builtin::AbstractValueTypeRule
+
 # A kind representing "inlined" operators defined with OPERATOR
 # Conceptually, (EQUAL a b) is actually an (APPLY EQUAL a b), but it's
 # not stored that way.  If you ask for the operator of (EQUAL a b),
@@ -279,7 +286,7 @@ constant BUILTIN \
     ::CVC4::Kind \
     ::CVC4::kind::KindHashFunction \
     "expr/kind.h" \
-    "The kind of nodes representing built-in operators"
+    "The kind of expressions representing built-in operators"
 
 variable FUNCTION "function"
 parameterized APPLY FUNCTION 0: "defined function application"
index a2e8e8179f7929100d70adf5b6de96e7cf1b85ed..3cd2f628220e5efaf364d937822cfe39207c47a2 100644 (file)
@@ -150,6 +150,17 @@ public:
   }
 };/* class UninterpretedConstantTypeRule */
 
+class AbstractValueTypeRule {
+public:
+  inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
+    // An UnknownTypeException means that this node has no type.  For now,
+    // only abstract values are like this.  Assigning them a type in all
+    // cases is difficult, since then the parser and the SmtEngine must be
+    // more tightly coupled.
+    throw UnknownTypeException(n);
+  }
+};/* class AbstractValueTypeRule */
+
 class StringConstantTypeRule {
 public:
   inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) {
index b5f846735871f36f14a022e9ad3576a5e255c97d..fa4acf3fba4c41926df51426e439cdefc8ea0406 100644 (file)
@@ -2,10 +2,10 @@
 /*! \file substitutions.cpp
  ** \verbatim
  ** Original author: dejan
- ** Major contributors: none
- ** Minor contributors (to current version): none
+ ** Major contributors: barrett
+ ** Minor contributors (to current version): mdeters
  ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011  The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009-2012  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
index d69f0edf0c30ec44da26b1836ebdcea981f999d6..09802491277df647976d16dcded889f3a08c4f35 100644 (file)
@@ -79,6 +79,8 @@ libutil_la_SOURCES = \
        index.h \
        uninterpreted_constant.h \
        uninterpreted_constant.cpp \
+       abstract_value.h \
+       abstract_value.cpp \
        array_store_all.h \
        array_store_all.cpp \
        util_model.h \
diff --git a/src/util/abstract_value.cpp b/src/util/abstract_value.cpp
new file mode 100644 (file)
index 0000000..a5cb40a
--- /dev/null
@@ -0,0 +1,32 @@
+/*********************                                                        */
+/*! \file abstract_value.cpp
+ ** \verbatim
+ ** Original author: mdeters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2012  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 Representation of abstract values
+ **
+ ** Representation of abstract values.
+ **/
+
+#include "util/abstract_value.h"
+#include <iostream>
+#include <sstream>
+#include <string>
+
+using namespace std;
+
+namespace CVC4 {
+
+std::ostream& operator<<(std::ostream& out, const AbstractValue& val) {
+  return out << "@" << val.getIndex();
+}
+
+}/* CVC4 namespace */
diff --git a/src/util/abstract_value.h b/src/util/abstract_value.h
new file mode 100644 (file)
index 0000000..1fc2f42
--- /dev/null
@@ -0,0 +1,78 @@
+/*********************                                                        */
+/*! \file abstract_value.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-2012  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 Representation of abstract values
+ **
+ ** Representation of abstract values.
+ **/
+
+#include "cvc4_public.h"
+
+#pragma once
+
+#include "expr/type.h"
+#include <iostream>
+
+namespace CVC4 {
+
+class CVC4_PUBLIC AbstractValue {
+  const Integer d_index;
+
+public:
+
+  AbstractValue(Integer index) throw(IllegalArgumentException) :
+    d_index(index) {
+    CheckArgument(index >= 1, index, "index >= 1 required for abstract value, not `%s'", index.toString().c_str());
+  }
+
+  ~AbstractValue() throw() {
+  }
+
+  const Integer& getIndex() const throw() {
+    return d_index;
+  }
+
+  bool operator==(const AbstractValue& val) const throw() {
+    return d_index == val.d_index;
+  }
+  bool operator!=(const AbstractValue& val) const throw() {
+    return !(*this == val);
+  }
+
+  bool operator<(const AbstractValue& val) const throw() {
+    return d_index < val.d_index;
+  }
+  bool operator<=(const AbstractValue& val) const throw() {
+    return d_index <= val.d_index;
+  }
+  bool operator>(const AbstractValue& val) const throw() {
+    return !(*this <= val);
+  }
+  bool operator>=(const AbstractValue& val) const throw() {
+    return !(*this < val);
+  }
+
+};/* class AbstractValue */
+
+std::ostream& operator<<(std::ostream& out, const AbstractValue& val) CVC4_PUBLIC;
+
+/**
+ * Hash function for the BitVector constants.
+ */
+struct CVC4_PUBLIC AbstractValueHashFunction {
+  inline size_t operator()(const AbstractValue& val) const {
+    return IntegerHashFunction()(val.getIndex());
+  }
+};/* struct AbstractValueHashFunction */
+
+}/* CVC4 namespace */
index 8b2f05ca7512cf0ba90d461935b2d92ab44eaadd..de1c8eca593273110c14252108e130b1862c9d9c 100644 (file)
@@ -131,7 +131,8 @@ BUG_TESTS = \
        bug365.smt2 \
        bug382.smt2 \
        bug383.smt2 \
-       bug398.smt2
+       bug398.smt2 \
+       bug421.smt2
 
 TESTS =        $(SMT_TESTS) $(SMT2_TESTS) $(CVC_TESTS) $(TPTP_TESTS) $(BUG_TESTS)
 
diff --git a/test/regress/regress0/bug421.smt2 b/test/regress/regress0/bug421.smt2
new file mode 100644 (file)
index 0000000..5776d2f
--- /dev/null
@@ -0,0 +1,11 @@
+; COMMAND-LINE: --incremental --abstract-values
+; EXPECT: sat
+; EXPECT: ((a @1) (b @2))
+; EXIT: 10
+(set-logic QF_AUFLIA)
+(set-option :produce-models true)
+(declare-fun a () (Array Int Int))
+(declare-fun b () (Array Int Int))
+(assert (not (= a b)))
+(check-sat)
+(get-value (a b))