Fix combinations of cegqi and non-standard triggers (#4271)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Wed, 15 Apr 2020 02:28:57 +0000 (21:28 -0500)
committerGitHub <noreply@github.com>
Wed, 15 Apr 2020 02:28:57 +0000 (21:28 -0500)
Counterexample-guided instantiation may produce quantified formulas with INST_CONSTANT nodes, which are also used as patterns for non-standard triggers for E-matching. This fixes a few combinations that were problematic.

Fixes #4250, fixes #4254, fixes #4269 and fixes #4281.

src/theory/quantifiers/ematching/inst_match_generator.cpp
src/theory/quantifiers/ematching/inst_match_generator.h
src/theory/quantifiers/ematching/trigger.cpp
src/theory/quantifiers/inst_match.cpp
src/theory/quantifiers/inst_match.h

index 6fdd6d67aad5c395347feaeede1250ae7fdbf78d..964d2e492aa67fe3a098b902a4a8c12147092afa 100644 (file)
@@ -596,7 +596,15 @@ InstMatchGenerator* InstMatchGenerator::getInstMatchGenerator(Node q, Node n)
     Node x;
     if (options::purifyTriggers())
     {
-      x = Trigger::getInversionVariable(n);
+      Node xi = Trigger::getInversionVariable(n);
+      if (!xi.isNull())
+      {
+        Node qa = quantifiers::TermUtil::getInstConstAttr(xi);
+        if (qa == q)
+        {
+          x = xi;
+        }
+      }
     }
     if (!x.isNull())
     {
@@ -624,7 +632,8 @@ int VarMatchGeneratorTermSubs::getNextMatch(Node q,
   int ret_val = -1;
   if( !d_eq_class.isNull() ){
     Trace("var-trigger-matching") << "Matching " << d_eq_class << " against " << d_var << " in " << d_subs << std::endl;
-    Node s = d_subs.substitute( d_var, d_eq_class );
+    TNode tvar = d_var;
+    Node s = d_subs.substitute(tvar, d_eq_class);
     s = Rewriter::rewrite( s );
     Trace("var-trigger-matching") << "...got " << s << ", " << s.getKind() << std::endl;
     d_eq_class = Node::null();
index 3995c67b418ce39358074d386eb3fe12974450ad..b71ff3c21067820717d9d06600677488780581b3 100644 (file)
@@ -438,7 +438,7 @@ public:
 
  private:
   /** variable we are matching (x in the example x+1). */
-  TNode d_var;
+  Node d_var;
   /** cache of d_var.getType() */
   TypeNode d_var_type;
   /** The substitution for what we match (x-1 in the example x+1). */
index e177e24a60a7c5c0d9b112c9bda1b4c6ed75c4e7..b2284d78e8bdc73d8270fb5194b05fe651a940ab 100644 (file)
@@ -298,20 +298,37 @@ Node Trigger::getIsUsableEq( Node q, Node n ) {
 bool Trigger::isUsableEqTerms( Node q, Node n1, Node n2 ) {
   if( n1.getKind()==INST_CONSTANT ){
     if( options::relationalTriggers() ){
-      if( !quantifiers::TermUtil::hasInstConstAttr(n2) ){
+      Node q1 = quantifiers::TermUtil::getInstConstAttr(n1);
+      if (q1 != q)
+      {
+        // x is a variable from another quantified formula, fail
+        return false;
+      }
+      Node q2 = quantifiers::TermUtil::getInstConstAttr(n2);
+      if (q2.isNull())
+      {
+        // x = c
         return true;
-      }else if( n2.getKind()==INST_CONSTANT ){
+      }
+      if (n2.getKind() == INST_CONSTANT && q2 == q)
+      {
+        // x = y
         return true;
       }
+      // we dont check x = f(y), which is handled symmetrically below
+      // when n1 and n2 are swapped
     }
   }else if( isUsableAtomicTrigger( n1, q ) ){
     if (options::relationalTriggers() && n2.getKind() == INST_CONSTANT
+        && quantifiers::TermUtil::getInstConstAttr(n2) == q
         && !expr::hasSubterm(n1, n2))
     {
+      // f(x) = y
       return true;
     }
     else if (!quantifiers::TermUtil::hasInstConstAttr(n2))
     {
+      // f(x) = c
       return true;
     }
   }
index bd947d70bd04fe1a549027a5dcaa5bfeec404789..af425c57077f90f25548808d1cf86bdc842fe588 100644 (file)
@@ -100,14 +100,20 @@ void InstMatch::clear() {
   }
 }
 
-Node InstMatch::get(int i) const { return d_vals[i]; }
+Node InstMatch::get(size_t i) const
+{
+  Assert(i < d_vals.size());
+  return d_vals[i];
+}
 
-void InstMatch::setValue( int i, TNode n ) {
+void InstMatch::setValue(size_t i, TNode n)
+{
+  Assert(i < d_vals.size());
   d_vals[i] = n;
 }
-bool InstMatch::set(EqualityQuery* q, int i, TNode n)
+bool InstMatch::set(EqualityQuery* q, size_t i, TNode n)
 {
-  Assert(i >= 0);
+  Assert(i < d_vals.size());
   if( !d_vals[i].isNull() ){
     if (q->areEqual(d_vals[i], n))
     {
index d298c43a8d52b5264082b19cf00d9463b36d39b3..324b2c7368fb481525db64178aa2375775c1b2b7 100644 (file)
@@ -79,15 +79,15 @@ public:
     out << " )";
   }
   /** get the i^th term in the instantiation */
-  Node get(int i) const;
+  Node get(size_t i) const;
   /** set/overwrites the i^th field in the instantiation with n */
-  void setValue( int i, TNode n );
+  void setValue(size_t i, TNode n);
   /** set the i^th term in the instantiation to n
    *
    * This method returns true if the i^th field was previously uninitialized,
    * or is equivalent to n modulo the equalities given by q.
    */
-  bool set(EqualityQuery* q, int i, TNode n);
+  bool set(EqualityQuery* q, size_t i, TNode n);
 };
 
 inline std::ostream& operator<<(std::ostream& out, const InstMatch& m) {