partially address bug 486: allow some model inspection of quantifiers
authorMorgan Deters <mdeters@cs.nyu.edu>
Wed, 23 Jan 2013 22:00:56 +0000 (17:00 -0500)
committerMorgan Deters <mdeters@cs.nyu.edu>
Wed, 23 Jan 2013 22:06:59 +0000 (17:06 -0500)
src/theory/model.cpp
src/theory/quantifiers/theory_quantifiers.cpp
test/regress/regress0/Makefile.am
test/regress/regress0/bug486.cvc [new file with mode: 0644]

index 3880aaad9f37b6f67ea46ab974eb896b94fcc25e..2333a4394ae5cd807bb51d048ea395752e5ac276 100644 (file)
@@ -77,66 +77,69 @@ Cardinality TheoryModel::getCardinality( Type t ) const{
 
 Node TheoryModel::getModelValue(TNode n, bool hasBoundVars) const
 {
-  Assert(n.getKind() != kind::FORALL && n.getKind() != kind::EXISTS);
-  if(n.getKind() == kind::LAMBDA) {
-    NodeManager* nm = NodeManager::currentNM();
-    Node body = getModelValue(n[1], true);
-    // This is a bit ugly, but cache inside simplifier can change, so can't be const
-    // The ite simplifier is needed to get rid of artifacts created by Boolean terms
-    body = const_cast<ITESimplifier*>(&d_iteSimp)->simpITE(body);
-    body = Rewriter::rewrite(body);
-    return nm->mkNode(kind::LAMBDA, n[0], body);
-  }
-  if(n.isConst() || (hasBoundVars && n.getKind() == kind::BOUND_VARIABLE)) {
-    return n;
-  }
-
-  TypeNode t = n.getType();
-  if (t.isFunction() || t.isPredicate()) {
-    if (d_enableFuncModels) {
-      std::map< Node, Node >::const_iterator it = d_uf_models.find(n);
-      if (it != d_uf_models.end()) {
-        // Existing function
-        return it->second;
-      }
-      // Unknown function symbol: return LAMBDA x. c, where c is the first constant in the enumeration of the range type
-      vector<TypeNode> argTypes = t.getArgTypes();
-      vector<Node> args;
+  if(n.getKind() == kind::EXISTS || n.getKind() == kind::FORALL) {
+    CheckArgument(d_equalityEngine.hasTerm(n), n, "Cannot get the model value for a previously-unseen quantifier: %s", n.toString().c_str());
+  } else {
+    if(n.getKind() == kind::LAMBDA) {
       NodeManager* nm = NodeManager::currentNM();
-      for (unsigned i = 0; i < argTypes.size(); ++i) {
-        args.push_back(nm->mkBoundVar(argTypes[i]));
-      }
-      Node boundVarList = nm->mkNode(kind::BOUND_VAR_LIST, args);
-      TypeEnumerator te(t.getRangeType());
-      return nm->mkNode(kind::LAMBDA, boundVarList, *te);
+      Node body = getModelValue(n[1], true);
+      // This is a bit ugly, but cache inside simplifier can change, so can't be const
+      // The ite simplifier is needed to get rid of artifacts created by Boolean terms
+      body = const_cast<ITESimplifier*>(&d_iteSimp)->simpITE(body);
+      body = Rewriter::rewrite(body);
+      return nm->mkNode(kind::LAMBDA, n[0], body);
     }
-    // TODO: if func models not enabled, throw an error?
-    Unreachable();
-  }
-
-  if (n.getNumChildren() > 0) {
-    std::vector<Node> children;
-    if (n.getKind() == APPLY_UF) {
-      Node op = getModelValue(n.getOperator(), hasBoundVars);
-      children.push_back(op);
+    if(n.isConst() || (hasBoundVars && n.getKind() == kind::BOUND_VARIABLE)) {
+      return n;
     }
-    else if (n.getMetaKind() == kind::metakind::PARAMETERIZED) {
-      children.push_back(n.getOperator());
+
+    TypeNode t = n.getType();
+    if (t.isFunction() || t.isPredicate()) {
+      if (d_enableFuncModels) {
+        std::map< Node, Node >::const_iterator it = d_uf_models.find(n);
+        if (it != d_uf_models.end()) {
+          // Existing function
+          return it->second;
+        }
+        // Unknown function symbol: return LAMBDA x. c, where c is the first constant in the enumeration of the range type
+        vector<TypeNode> argTypes = t.getArgTypes();
+        vector<Node> args;
+        NodeManager* nm = NodeManager::currentNM();
+        for (unsigned i = 0; i < argTypes.size(); ++i) {
+          args.push_back(nm->mkBoundVar(argTypes[i]));
+        }
+        Node boundVarList = nm->mkNode(kind::BOUND_VAR_LIST, args);
+        TypeEnumerator te(t.getRangeType());
+        return nm->mkNode(kind::LAMBDA, boundVarList, *te);
+      }
+      // TODO: if func models not enabled, throw an error?
+      Unreachable();
     }
-    //evaluate the children
-    for (unsigned i = 0; i < n.getNumChildren(); ++i) {
-      Node val = getModelValue(n[i], hasBoundVars);
-      children.push_back(val);
+
+    if (n.getNumChildren() > 0) {
+      std::vector<Node> children;
+      if (n.getKind() == APPLY_UF) {
+        Node op = getModelValue(n.getOperator(), hasBoundVars);
+        children.push_back(op);
+      }
+      else if (n.getMetaKind() == kind::metakind::PARAMETERIZED) {
+        children.push_back(n.getOperator());
+      }
+      //evaluate the children
+      for (unsigned i = 0; i < n.getNumChildren(); ++i) {
+        Node val = getModelValue(n[i], hasBoundVars);
+        children.push_back(val);
+      }
+      Node val = Rewriter::rewrite(NodeManager::currentNM()->mkNode(n.getKind(), children));
+      Assert(hasBoundVars || val.isConst());
+      return val;
     }
-    Node val = Rewriter::rewrite(NodeManager::currentNM()->mkNode(n.getKind(), children));
-    Assert(hasBoundVars || val.isConst());
-    return val;
-  }
 
-  if (!d_equalityEngine.hasTerm(n)) {
-    // Unknown term - return first enumerated value for this type
-    TypeEnumerator te(n.getType());
-    return *te;
+    if (!d_equalityEngine.hasTerm(n)) {
+      // Unknown term - return first enumerated value for this type
+      TypeEnumerator te(n.getType());
+      return *te;
+    }
   }
   Node val = d_equalityEngine.getRepresentative(n);
   Assert(d_reps.find(val) != d_reps.end());
index b1a7c99270fff2a26820c4410e068c42ca737c08..b5287fff4a2503363f7d338f69494113b361d912 100644 (file)
@@ -93,7 +93,9 @@ Node TheoryQuantifiers::getValue(TNode n) {
 }
 
 void TheoryQuantifiers::collectModelInfo( TheoryModel* m, bool fullModel ){
-
+  for(assertions_iterator i = facts_begin(); i != facts_end(); ++i) {
+    m->assertPredicate(*i, true);
+  }
 }
 
 void TheoryQuantifiers::check(Effort e) {
index 3b30a8d9ee846c11deef58a2420ca7aa74773f60..d5b35594fe7807823ca1b97ebb9483cd97df34bd 100644 (file)
@@ -149,7 +149,8 @@ TESTS =     $(SMT_TESTS) $(SMT2_TESTS) $(CVC_TESTS) $(TPTP_TESTS) $(BUG_TESTS)
 
 EXTRA_DIST = $(TESTS) \
        simplification_bug4.smt2.expect \
-       bug216.smt2.expect
+       bug216.smt2.expect \
+       bug486.cvc
 
 if CVC4_BUILD_PROFILE_COMPETITION
 else
diff --git a/test/regress/regress0/bug486.cvc b/test/regress/regress0/bug486.cvc
new file mode 100644 (file)
index 0000000..6e8ee00
--- /dev/null
@@ -0,0 +1,25 @@
+prin:TYPE;
+form:TYPE;
+
+signed:(prin,form)->BOOLEAN;
+says:(prin,form)->BOOLEAN;
+
+speaksfor:(prin,prin)->form;
+signedE:BOOLEAN = FORALL(x:prin,y:form) : signed(x,y) => says(x,y);
+saysE:BOOLEAN = FORALL(x,y:prin,z:form) : says(x,speaksfor(y,x)) AND says(y,z) => says(x,z); 
+
+ASSERT(signedE);
+ASSERT(saysE);
+
+julie:prin;
+dave:prin;
+alice:prin;
+openfile:form;
+
+x2:BOOLEAN = signed(alice,openfile);
+ASSERT(x2);
+x3:BOOLEAN = signed(dave,speaksfor(alice,dave));
+ASSERT(x3);
+
+QUERY NOT says(dave,openfile); % this is invalid
+QUERY says(dave,openfile); % this is valid