Minor refactoring of entailment tests and quantifiers util. Initial draft of instanti...
authorajreynol <andrew.j.reynolds@gmail.com>
Sat, 9 Apr 2016 18:07:11 +0000 (13:07 -0500)
committerajreynol <andrew.j.reynolds@gmail.com>
Sat, 9 Apr 2016 18:07:11 +0000 (13:07 -0500)
15 files changed:
src/Makefile.am
src/options/quantifiers_options
src/theory/quantifiers/conjecture_generator.cpp
src/theory/quantifiers/inst_propagator.cpp [new file with mode: 0644]
src/theory/quantifiers/inst_propagator.h [new file with mode: 0644]
src/theory/quantifiers/quant_conflict_find.cpp
src/theory/quantifiers/quant_conflict_find.h
src/theory/quantifiers/quant_util.cpp
src/theory/quantifiers/quant_util.h
src/theory/quantifiers/relevant_domain.cpp
src/theory/quantifiers/relevant_domain.h
src/theory/quantifiers/term_database.cpp
src/theory/quantifiers/term_database.h
src/theory/quantifiers_engine.cpp
src/theory/quantifiers_engine.h

index 610bcb30570518c6ae601533ca7c9f2f9c85ec4f..908245e63f8c59b2c5e0bfa5be30700be590b4ab 100644 (file)
@@ -364,6 +364,8 @@ libcvc4_la_SOURCES = \
        theory/quantifiers/anti_skolem.cpp \
        theory/quantifiers/equality_infer.h \
        theory/quantifiers/equality_infer.cpp \
+       theory/quantifiers/inst_propagator.h \
+       theory/quantifiers/inst_propagator.cpp \
        theory/arith/theory_arith_type_rules.h \
        theory/arith/type_enumerator.h \
        theory/arith/arithvar.h \
index 8ed4f24c01cd768a5538380c59869606a300dff1..c27b21e234c2fef11f1c0e871dc28e14c1b7e31a 100644 (file)
@@ -174,6 +174,9 @@ option qcfAllConflict --qcf-all-conflict bool :read-write :default false
 
 option instNoEntail --inst-no-entail bool :read-write :default true
  do not consider instances of quantified formulas that are currently entailed
+
+option instPropagate --inst-propagate bool :read-write :default false
+ internal propagation for instantiations for selecting relevant instances
  
 ### rewrite rules options 
  
index beec9da3b5d5c03b8d7850719804e51284573763..f8a9eefcb6df17192c58d4b4237a1f8889e836d0 100644 (file)
@@ -1273,7 +1273,7 @@ bool ConjectureGenerator::notifySubstitution( TNode glhs, std::map< TNode, TNode
   }
   Trace("sg-cconj-debug") << "Evaluate RHS : : " << rhs << std::endl;
   //get the representative of rhs with substitution subs
-  TNode grhs = getTermDatabase()->evaluateTerm( rhs, subs, true );
+  TNode grhs = getTermDatabase()->getEntailedTerm( rhs, subs, true );
   Trace("sg-cconj-debug") << "...done evaluating term, got : " << grhs << std::endl;
   if( !grhs.isNull() ){
     if( glhs!=grhs ){
diff --git a/src/theory/quantifiers/inst_propagator.cpp b/src/theory/quantifiers/inst_propagator.cpp
new file mode 100644 (file)
index 0000000..d20f3fd
--- /dev/null
@@ -0,0 +1,674 @@
+/*********************                                                        */\r
+/*! \file inst_propagator.cpp\r
+ ** \verbatim\r
+ ** Top contributors (to current version):\r
+ **   Andrew Reynolds\r
+ ** This file is part of the CVC4 project.\r
+ ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS\r
+ ** in the top-level source directory) and their institutional affiliations.\r
+ ** All rights reserved.  See the file COPYING in the top-level source\r
+ ** directory for licensing information.\endverbatim\r
+ **\r
+ ** Propagate mechanism for instantiations\r
+ **/\r
+\r
+#include <vector>\r
+\r
+#include "theory/quantifiers/inst_propagator.h"\r
+#include "theory/rewriter.h"\r
+#include "theory/quantifiers/term_database.h"\r
+\r
+using namespace CVC4;\r
+using namespace std;\r
+using namespace CVC4::theory;\r
+using namespace CVC4::theory::quantifiers;\r
+using namespace CVC4::kind;\r
+\r
+\r
+EqualityQueryInstProp::EqualityQueryInstProp( QuantifiersEngine* qe ) : d_qe( qe ){\r
+  d_true = NodeManager::currentNM()->mkConst( true );\r
+  d_false = NodeManager::currentNM()->mkConst( false );\r
+}\r
+\r
+bool EqualityQueryInstProp::reset( Theory::Effort e ) {\r
+  d_uf.clear();\r
+  d_uf_exp.clear();\r
+  d_diseq_list.clear();\r
+  return true;\r
+}\r
+\r
+/** contains term */\r
+bool EqualityQueryInstProp::hasTerm( Node a ) {\r
+  if( getEngine()->hasTerm( a ) ){\r
+    return true;\r
+  }else{\r
+    std::vector< Node > exp;\r
+    Node ar = getUfRepresentative( a, exp );\r
+    return !ar.isNull() && getEngine()->hasTerm( ar );\r
+  }\r
+}\r
+\r
+/** get the representative of the equivalence class of a */\r
+Node EqualityQueryInstProp::getRepresentative( Node a ) {\r
+  if( getEngine()->hasTerm( a ) ){\r
+    a = getEngine()->getRepresentative( a );\r
+  }\r
+  std::vector< Node > exp;\r
+  Node ar = getUfRepresentative( a, exp );\r
+  return ar.isNull() ? a : ar;\r
+}\r
+\r
+/** returns true if a and b are equal in the current context */\r
+bool EqualityQueryInstProp::areEqual( Node a, Node b ) {\r
+  if( a==b ){\r
+    return true;\r
+  }else{\r
+    eq::EqualityEngine* ee = getEngine();\r
+    if( ee->hasTerm( a ) && ee->hasTerm( b ) ){\r
+      if( ee->areEqual( a, b ) ){\r
+        return true;\r
+      }\r
+    }\r
+    return false;\r
+  }\r
+}\r
+\r
+/** returns true is a and b are disequal in the current context */\r
+bool EqualityQueryInstProp::areDisequal( Node a, Node b ) {\r
+  if( a==b ){\r
+    return true;\r
+  }else{\r
+    eq::EqualityEngine* ee = getEngine();\r
+    if( ee->hasTerm( a ) && ee->hasTerm( b ) ){\r
+      if( ee->areDisequal( a, b, false ) ){\r
+        return true;\r
+      }\r
+    }\r
+    return false;\r
+  }\r
+}\r
+\r
+/** get the equality engine associated with this query */\r
+eq::EqualityEngine* EqualityQueryInstProp::getEngine() {\r
+  return d_qe->getMasterEqualityEngine();\r
+}\r
+\r
+/** get the equivalence class of a */\r
+void EqualityQueryInstProp::getEquivalenceClass( Node a, std::vector< Node >& eqc ) {\r
+  //TODO?\r
+}\r
+\r
+TNode EqualityQueryInstProp::getCongruentTerm( Node f, std::vector< TNode >& args ) {\r
+  TNode t = d_qe->getTermDatabase()->getCongruentTerm( f, args );\r
+  if( !t.isNull() ){\r
+    return t;\r
+  }else{\r
+    //TODO?\r
+    return TNode::null();\r
+  }\r
+}\r
+\r
+Node EqualityQueryInstProp::getRepresentativeExp( Node a, std::vector< Node >& exp ) {\r
+  bool engine_has_a = getEngine()->hasTerm( a );\r
+  if( engine_has_a ){\r
+    a = getEngine()->getRepresentative( a );\r
+  }\r
+  //get union find representative, if this occurs in the equality engine, return it\r
+  unsigned prev_size = exp.size();\r
+  Node ar = getUfRepresentative( a, exp );\r
+  if( !ar.isNull() ){\r
+    if( engine_has_a || getEngine()->hasTerm( ar ) ){\r
+      Assert( getEngine()->hasTerm( ar ) );\r
+      Assert( getEngine()->getRepresentative( ar )==ar );\r
+      return ar;\r
+    }\r
+  }else{\r
+    if( engine_has_a ){\r
+      return a;\r
+    }\r
+  }\r
+  //retract explanation\r
+  while( exp.size()>prev_size ){\r
+    exp.pop_back();\r
+  }\r
+  return Node::null();\r
+}\r
+\r
+bool EqualityQueryInstProp::areEqualExp( Node a, Node b, std::vector< Node >& exp ) {\r
+  if( areEqual( a, b ) ){\r
+    return true;\r
+  }else{\r
+    std::vector< Node > exp_a;\r
+    Node ar = getUfRepresentative( a, exp_a );\r
+    if( !ar.isNull() ){\r
+      std::vector< Node > exp_b;\r
+      if( ar==getUfRepresentative( b, exp_b ) ){\r
+        merge_exp( exp, exp_a );\r
+        merge_exp( exp, exp_b );\r
+        return true;\r
+      }\r
+    }\r
+    return false;\r
+  }\r
+}\r
+\r
+bool EqualityQueryInstProp::areDisequalExp( Node a, Node b, std::vector< Node >& exp ) {\r
+  if( areDisequal( a, b ) ){\r
+    return true;\r
+  }else{\r
+    //TODO?\r
+    return false;\r
+  }\r
+}\r
+\r
+Node EqualityQueryInstProp::getUfRepresentative( Node a, std::vector< Node >& exp ) {\r
+  Assert( exp.empty() );\r
+  std::map< Node, Node >::iterator it = d_uf.find( a );\r
+  if( it!=d_uf.end() ){\r
+    if( it->second==a ){\r
+      Assert( d_uf_exp[ a ].empty() );\r
+      return it->second;\r
+    }else{\r
+      Node m = getUfRepresentative( it->second, exp );\r
+      Assert( !m.isNull() );\r
+      if( m!=it->second ){\r
+        //update union find\r
+        d_uf[ a ] = m;\r
+        //update explanation : merge the explanation of the parent\r
+        merge_exp( d_uf_exp[ a ], exp );\r
+        Trace("qip-eq") << "EqualityQueryInstProp::getUfRepresentative : merge " << a << " -> " << m << ", exp size=" << d_uf_exp[ a ].size() << std::endl;\r
+      }\r
+      //add current explanation to exp: note that exp is a subset of d_uf_exp[ a ], reset\r
+      exp.clear();\r
+      exp.insert( exp.end(), d_uf_exp[ a ].begin(), d_uf_exp[ a ].end() );\r
+      return m;\r
+    }\r
+  }else{\r
+    return Node::null();\r
+  }\r
+}\r
+\r
+// set a == b with reason, return status, modify a and b to representatives pre-merge\r
+int EqualityQueryInstProp::setEqual( Node& a, Node& b, std::vector< Node >& reason ) {\r
+  int status = STATUS_MERGED_UNKNOWN;\r
+  Trace("qip-eq") << "EqualityQueryInstProp::setEqual " << a << ", " << b << ", reason size = " << reason.size() << std::endl;\r
+  //get the representative for a\r
+  std::vector< Node > exp_a;\r
+  Node ar = getUfRepresentative( a, exp_a );\r
+  if( ar.isNull() ){\r
+    Assert( exp_a.empty() );\r
+    ar = a;\r
+  }\r
+  if( ar==b ){\r
+    Trace("qip-eq") << "EqualityQueryInstProp::setEqual : already equal" << std::endl;\r
+    return STATUS_NONE;\r
+  }\r
+  bool swap = false;\r
+  //get the representative for b\r
+  std::vector< Node > exp_b;\r
+  Node br = getUfRepresentative( b, exp_b );\r
+  if( br.isNull() ){\r
+    Assert( exp_b.empty() );\r
+    br = b;\r
+    if( !getEngine()->hasTerm( br ) ){\r
+      if( ar!=a ){\r
+        swap = true;\r
+      }\r
+    }else{\r
+      if( getEngine()->hasTerm( ar ) ){\r
+        status = STATUS_MERGED_KNOWN;\r
+      }\r
+    }\r
+  }else{\r
+    if( ar==br ){\r
+      Trace("qip-eq") << "EqualityQueryInstProp::setEqual : already equal" << std::endl;\r
+      return STATUS_NONE;\r
+    }else if( getEngine()->hasTerm( ar ) ){\r
+      if( getEngine()->hasTerm( br ) ){\r
+        status = STATUS_MERGED_KNOWN;\r
+      }else{\r
+        swap = true;\r
+      }\r
+    }\r
+  }\r
+  if( swap ){\r
+    //swap\r
+    Node temp_r = ar;\r
+    ar = br;\r
+    br = temp_r;\r
+  }\r
+\r
+  Assert( ar!=br );\r
+  Assert( !getEngine()->hasTerm( ar ) || getEngine()->hasTerm( br ) );\r
+\r
+  //update the union find\r
+  Assert( d_uf_exp[ar].empty() );\r
+  Assert( d_uf_exp[br].empty() );\r
+\r
+  d_uf[ar] = br;\r
+  merge_exp( d_uf_exp[ar], exp_a );\r
+  merge_exp( d_uf_exp[ar], exp_b );\r
+  merge_exp( d_uf_exp[ar], reason );\r
+\r
+  d_uf[br] = br;\r
+  d_uf_exp[br].clear();\r
+\r
+  Trace("qip-eq") << "EqualityQueryInstProp::setEqual : merge " << ar << " -> " << br << ", exp size = " << d_uf_exp[ar].size() << ", status = " << status << std::endl;\r
+  a = ar;\r
+  b = br;\r
+  return status;\r
+}\r
+\r
+\r
+void EqualityQueryInstProp::addArgument( std::vector< TNode >& args, std::vector< TNode >& props, Node n, bool is_prop, bool pol ) {\r
+  if( is_prop ){\r
+    if( isLiteral( n ) ){\r
+      props.push_back( pol ? n : n.negate() );\r
+      return;\r
+    }\r
+  }\r
+  args.push_back( n );\r
+}\r
+\r
+bool EqualityQueryInstProp::isLiteral( Node n ) {\r
+  Kind ak = n.getKind()==NOT ? n[0].getKind() : n.getKind();\r
+  Assert( ak!=NOT );\r
+  return ak!=AND && ak!=OR && ak!=IFF && ak!=ITE;\r
+}\r
+\r
+//this is identical to TermDb::evaluateTerm2, but tracks more information\r
+Node EqualityQueryInstProp::evaluateTermExp( TNode n, std::vector< Node >& exp, std::map< TNode, Node >& visited, bool hasPol, bool pol,\r
+                                             std::map< Node, bool >& watch_list_out, std::vector< TNode >& props ) {\r
+  std::map< TNode, Node >::iterator itv = visited.find( n );\r
+  if( itv != visited.end() ){\r
+    return itv->second;\r
+  }else{\r
+    Trace("term-db-eval") << "evaluate term : " << n << std::endl;\r
+    std::vector< Node > exp_n;\r
+    Node ret = getRepresentativeExp( n, exp_n );\r
+    if( ret.isNull() ){\r
+      //term is not known to be equal to a representative in equality engine, evaluate it\r
+      Kind k = n.getKind();\r
+      if( k==FORALL ){\r
+        ret = Node::null();\r
+      }else{\r
+        std::map< Node, bool > watch_list_out_curr;\r
+        TNode f = d_qe->getTermDatabase()->getMatchOperator( n );\r
+        std::vector< TNode > args;\r
+        bool ret_set = false;\r
+        bool childChanged = false;\r
+        int abort_i = -1;\r
+        //get the child entailed polarity\r
+        Assert( n.getKind()!=IMPLIES );\r
+        bool newHasPol, newPol;\r
+        QuantPhaseReq::getEntailPolarity( n, 0, hasPol, pol, newHasPol, newPol );\r
+        //for each child\r
+        for( unsigned i=0; i<n.getNumChildren(); i++ ){\r
+          TNode c = evaluateTermExp( n[i], exp, visited, newHasPol, newPol, watch_list_out_curr, props );\r
+          if( c.isNull() ){\r
+            ret = Node::null();\r
+            ret_set = true;\r
+            break;\r
+          }else if( c==d_true || c==d_false ){\r
+            //short-circuiting\r
+            if( k==kind::AND || k==kind::OR ){\r
+              if( (k==kind::AND)==(c==d_false) ){\r
+                ret = c;\r
+                ret_set = true;\r
+                break;\r
+              }else{\r
+                //redundant\r
+                c = Node::null();\r
+                childChanged = true;\r
+              }\r
+            }else if( k==kind::ITE && i==0 ){\r
+              Assert( watch_list_out_curr.empty() );\r
+              ret = evaluateTermExp( n[ c==d_true ? 1 : 2], exp, visited, hasPol, pol, watch_list_out_curr, props );\r
+              ret_set = true;\r
+              break;\r
+            }else if( k==kind::NOT ){\r
+              ret = c==d_true ? d_false : d_true;\r
+              ret_set = true;\r
+              break;\r
+            }\r
+          }\r
+          if( !c.isNull() ){\r
+            childChanged = childChanged || n[i]!=c;\r
+            if( !f.isNull() && !watch_list_out_curr.empty() ){\r
+              // we are done if this is an UF application and an argument is unevaluated\r
+              args.push_back( c );\r
+              abort_i = i;\r
+              break;\r
+            }else if( ( k==kind::AND || k==kind::OR ) ){\r
+              if( c.getKind()==k ){\r
+                //flatten\r
+                for( unsigned j=0; j<c.getNumChildren(); j++ ){\r
+                  addArgument( args, props, c[j], newHasPol, newPol );\r
+                }\r
+              }else{\r
+                addArgument( args, props, c, newHasPol, newPol );\r
+              }\r
+              //if we are in a branching position\r
+              if( hasPol && !newHasPol && args.size()>=2 ){\r
+                //we are done if at least two args are unevaluated\r
+                abort_i = i;\r
+                break;\r
+              }\r
+            }else if( k==kind::ITE ){\r
+              //we are done if we are ITE and condition is unevaluated\r
+              Assert( i==0 );\r
+              args.push_back( c );\r
+              abort_i = i;\r
+              break;\r
+            }else{\r
+              args.push_back( c );\r
+            }\r
+          }\r
+        }\r
+        //add remaining children if we aborted\r
+        if( abort_i!=-1 ){\r
+          for( int i=(abort_i+1); i<(int)n.getNumChildren(); i++ ){\r
+            args.push_back( n[i] );\r
+          }\r
+        }\r
+        //copy over the watch list\r
+        for( std::map< Node, bool >::iterator itc = watch_list_out_curr.begin(); itc != watch_list_out_curr.end(); ++itc ){\r
+          watch_list_out[itc->first] = itc->second;\r
+        }\r
+\r
+        //if we have not short-circuited evaluation\r
+        if( !ret_set ){\r
+          //if it is an indexed term, return the congruent term\r
+          if( !f.isNull() && watch_list_out.empty() ){\r
+            Assert( args.size()==n.getNumChildren() );\r
+            //args contains terms known by the equality engine\r
+            TNode nn = getCongruentTerm( f, args );\r
+            Trace("term-db-eval") << "  got congruent term " << nn << " from DB for " << n << std::endl;\r
+            if( !nn.isNull() ){\r
+              //successfully constructed representative in EE\r
+              Assert( exp_n.empty() );\r
+              ret = getRepresentativeExp( nn, exp_n );\r
+              Trace("term-db-eval") << "return rep, exp size = " << exp_n.size() << std::endl;\r
+              merge_exp( exp, exp_n );\r
+              ret_set = true;\r
+              Assert( !ret.isNull() );\r
+            }\r
+          }\r
+          if( !ret_set ){\r
+            if( childChanged ){\r
+              Trace("term-db-eval") << "return rewrite" << std::endl;\r
+              if( ( k==kind::AND || k==kind::OR ) ){\r
+                if( args.empty() ){\r
+                  ret = k==kind::AND ? d_true : d_false;\r
+                  ret_set = true;\r
+                }else if( args.size()==1 ){\r
+                  ret = args[0];\r
+                  ret_set = true;\r
+                }\r
+              }\r
+              if( !ret_set ){\r
+                Assert( args.size()==n.getNumChildren() );\r
+                if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){\r
+                  args.insert( args.begin(), n.getOperator() );\r
+                }\r
+                ret = NodeManager::currentNM()->mkNode( k, args );\r
+                ret = Rewriter::rewrite( ret );\r
+                watch_list_out[ret] = true;\r
+              }\r
+            }else{\r
+              ret = n;\r
+              watch_list_out[ret] = true;\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }else{\r
+      Trace("term-db-eval") << "...exists in ee, return rep, exp size = " << exp_n.size() << std::endl;\r
+      merge_exp( exp, exp_n );\r
+    }\r
+    Trace("term-db-eval") << "evaluated term : " << n << ", got : " << ret << ", exp size = " << exp.size() << std::endl;\r
+    visited[n] = ret;\r
+    return ret;\r
+  }\r
+}\r
+\r
+void EqualityQueryInstProp::merge_exp( std::vector< Node >& v, std::vector< Node >& v_to_merge, int up_to_size ) {\r
+  //TODO : optimize\r
+  if( v.empty() ){\r
+    Assert( up_to_size==-1 || up_to_size==(int)v_to_merge.size() );\r
+    v.insert( v.end(), v_to_merge.begin(), v_to_merge.end() );\r
+  }else{\r
+    //std::vector< Node >::iterator v_end = v.end();\r
+    up_to_size = up_to_size==-1 ? (int)v_to_merge.size() : up_to_size;\r
+    for( int j=0; j<up_to_size; j++ ){\r
+      if( std::find( v.begin(), v.end(), v_to_merge[j] )==v.end() ){\r
+        v.push_back( v_to_merge[j] );\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+\r
+void InstPropagator::InstInfo::init( Node q, Node lem, std::vector< Node >& terms, Node body ) {\r
+  d_active = true;\r
+  //information about the instance\r
+  d_q = q;\r
+  d_lem = lem;\r
+  Assert( d_terms.empty() );\r
+  d_terms.insert( d_terms.end(), terms.begin(), terms.end() );\r
+  //the current lemma\r
+  d_curr = body;\r
+  d_curr_exp.push_back( body );\r
+}\r
+\r
+InstPropagator::InstPropagator( QuantifiersEngine* qe ) :\r
+d_qe( qe ), d_notify(*this), d_qy( qe ){\r
+}\r
+\r
+bool InstPropagator::reset( Theory::Effort e ) {\r
+  d_icount = 0;\r
+  d_ii.clear();\r
+  for( unsigned i=0; i<2; i++ ){\r
+    d_conc_to_id[i].clear();\r
+  }\r
+  d_conflict = false;\r
+  d_watch_list.clear();\r
+  d_relevant_inst.clear();\r
+  return d_qy.reset( e );\r
+}\r
+\r
+void InstPropagator::notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) {\r
+  if( !d_conflict ){\r
+    if( Trace.isOn("qip-prop") ){\r
+      Trace("qip-prop") << "InstPropagator:: Notify instantiation " << q << " : " << std::endl;\r
+      for( unsigned i=0; i<terms.size(); i++ ){\r
+        Trace("qip-prop") << "  " << terms[i] << std::endl;\r
+      }\r
+    }\r
+    unsigned id = d_icount;\r
+    d_icount++;\r
+    Trace("qip-prop") << "...assign id=" << id << std::endl;\r
+    d_ii[id].init( q, lem, terms, body );\r
+    //initialize the information\r
+    if( cacheConclusion( id, body ) ){\r
+      Assert( d_update_list.empty() );\r
+      d_update_list.push_back( id );\r
+      bool firstTime = true;\r
+      //update infos in the update list until empty \r
+      do {\r
+        unsigned uid = d_update_list.back();\r
+        d_update_list.pop_back();\r
+        if( d_ii[uid].d_active ){\r
+          update( uid, d_ii[uid], firstTime );\r
+        }\r
+        firstTime = false;\r
+      }while( !d_update_list.empty() );\r
+    }else{\r
+      d_ii[id].d_active = false;\r
+      Trace("qip-prop") << "...duplicate." << std::endl;\r
+    }\r
+  }\r
+}\r
+\r
+bool InstPropagator::update( unsigned id, InstInfo& ii, bool firstTime ) {\r
+  Assert( !d_conflict );\r
+  Assert( ii.d_active );\r
+  Trace("qip-prop-debug") << "Update info [" << id << "]..." << std::endl;\r
+  //update the evaluation of the current lemma\r
+  std::map< TNode, Node > visited;\r
+  std::map< Node, bool > watch_list;\r
+  std::vector< TNode > props;\r
+  Node eval = d_qy.evaluateTermExp( ii.d_curr, ii.d_curr_exp, visited, true, true, watch_list, props );\r
+  if( eval.isNull() ){\r
+    ii.d_active = false;\r
+  }else if( firstTime || eval!=ii.d_curr ){\r
+    if( EqualityQueryInstProp::isLiteral( eval ) ){\r
+      props.push_back( eval );\r
+      eval = d_qy.d_true;\r
+      watch_list.clear();\r
+    }\r
+    if( Trace.isOn("qip-prop") ){\r
+      Trace("qip-prop") << "Update info [" << id << "]..." << std::endl;\r
+      Trace("qip-prop") << "...updated lemma " << ii.d_curr << " -> " << eval << ", exp = ";\r
+      debugPrintExplanation( ii.d_curr_exp, "qip-prop" );\r
+      Trace("qip-prop") << std::endl;\r
+      Trace("qip-prop") << "...watch list: " << std::endl;\r
+      for( std::map< Node, bool >::iterator itw = watch_list.begin(); itw!=watch_list.end(); ++itw ){\r
+        Trace("qip-prop") << "  " << itw->first << std::endl;\r
+      }\r
+      Trace("qip-prop") << "...new propagations: " << std::endl;\r
+      for( unsigned i=0; i<props.size(); i++ ){\r
+        Trace("qip-prop") << "  " << props[i] << std::endl;\r
+      }\r
+      Trace("qip-prop") << std::endl;\r
+    }\r
+    //determine the status of eval\r
+    if( eval==d_qy.d_false ){\r
+      Assert( props.empty() );\r
+      //we have inferred a conflict\r
+      conflict( ii.d_curr_exp );\r
+      return false;\r
+    }else{\r
+      for( unsigned i=0; i<props.size(); i++ ){\r
+        //if we haven't propagated this literal yet\r
+        if( cacheConclusion( id, props[i], 1 ) ){\r
+          Node lit = props[i].getKind()==NOT ? props[i][0] : props[i];\r
+          bool pol = props[i].getKind()!=NOT;\r
+          if( lit.getKind()==EQUAL ){\r
+            propagate( lit[0], lit[1], pol, ii.d_curr_exp );\r
+          }else{\r
+            propagate( lit, pol ? d_qy.d_true : d_qy.d_false, true, ii.d_curr_exp );\r
+          }\r
+          if( d_conflict ){\r
+            return false;\r
+          }\r
+        }\r
+      }\r
+      //if we have not inferred this conclusion yet\r
+      if( cacheConclusion( id, eval ) ){\r
+        ii.d_curr = eval;\r
+        //update the watch list\r
+        Trace("qip-prop-debug") << "...updating watch list for [" << id << "], curr is " << ii.d_curr << std::endl;\r
+        //Here, we need to be notified of enough terms such that if we are not notified, then update( ii ) will return no propagations.\r
+        //  Similar to two-watched literals, but since we are in UF, we need to watch all terms on a complete path of two terms.\r
+        for( std::map< Node, bool >::iterator itw = watch_list.begin(); itw != watch_list.end(); ++itw ){\r
+          d_watch_list[ itw->first ][ id ] = true;\r
+        }\r
+      }else{\r
+        Trace("qip-prop-debug") << "...conclusion is duplicate." << std::endl;\r
+        ii.d_active = false;\r
+      }\r
+    }\r
+  }else{\r
+    Trace("qip-prop-debug") << "...did not update." << std::endl;\r
+  }\r
+  Assert( !d_conflict );\r
+  return true;\r
+}\r
+\r
+void InstPropagator::propagate( Node a, Node b, bool pol, std::vector< Node >& exp ) {\r
+  if( Trace.isOn("qip-propagate") ){\r
+    Trace("qip-propagate") << "* Propagate " << a << ( pol ? " == " : " != " ) << b << ", exp = ";\r
+    debugPrintExplanation( exp, "qip-propagate" );\r
+    Trace("qip-propagate") << "..." << std::endl;\r
+  }\r
+  if( pol ){\r
+    std::vector< Node > exp_d;\r
+    if( d_qy.areDisequalExp( a, b, exp_d ) ){\r
+      Trace("qip-prop-debug") << "...conflict." << std::endl;\r
+      EqualityQueryInstProp::merge_exp( exp, exp_d );\r
+      conflict( exp );\r
+    }else{\r
+      //set equal\r
+      int status = d_qy.setEqual( a, b, exp );\r
+      if( status==EqualityQueryInstProp::STATUS_NONE ){\r
+        Trace("qip-prop-debug") << "...already equal." << std::endl;\r
+        return;\r
+      }else if( status==EqualityQueryInstProp::STATUS_MERGED_KNOWN ){\r
+        Assert( d_qy.getEngine()->hasTerm( a ) );\r
+        Assert( d_qy.getEngine()->hasTerm( b ) );\r
+        Trace("qip-prop-debug") << "...equality between known terms." << std::endl;\r
+        addRelevantInstances( exp, "qip-propagate" );\r
+      }\r
+      Trace("qip-prop-debug") << "...merging " << a << " and " << b << std::endl;\r
+      for( unsigned i=0; i<2; i++ ){\r
+        //update terms from watched lists\r
+        Node c = i==0 ? a : b;\r
+        std::map< Node, std::map< unsigned, bool > >::iterator it = d_watch_list.find( c );\r
+        if( it!=d_watch_list.end() ){\r
+          Trace("qip-prop-debug") << "...update ids from watch list of " << c << ", size=" << it->second.size() << "..." << std::endl;\r
+          for( std::map< unsigned, bool >::iterator itw = it->second.begin(); itw != it->second.end(); ++itw ){\r
+            unsigned idw = itw->first;\r
+            if( std::find( d_update_list.begin(), d_update_list.end(), idw )==d_update_list.end() ){\r
+              Trace("qip-prop-debug") << "...will update " << idw << std::endl;\r
+              d_update_list.push_back( idw );\r
+            }\r
+          }\r
+          d_watch_list.erase( c );\r
+        }\r
+      }\r
+    }\r
+  }else{\r
+    std::vector< Node > exp_e;\r
+    if( d_qy.areEqualExp( a, b, exp_e ) ){\r
+      EqualityQueryInstProp::merge_exp( exp, exp_e );\r
+      conflict( exp );\r
+    }else{\r
+      //TODO?\r
+    }\r
+  }\r
+}\r
+\r
+void InstPropagator::conflict( std::vector< Node >& exp ) {\r
+  Trace("qip-propagate") << "Conflict, exp size =" << exp.size() << std::endl;\r
+  d_conflict = true;\r
+  d_relevant_inst.clear();\r
+  addRelevantInstances( exp, "qip-propagate" );\r
+}\r
+\r
+bool InstPropagator::cacheConclusion( unsigned id, Node body, int prop_index ) {\r
+  Assert( prop_index==0 || prop_index==1 );\r
+  //check if the conclusion is non-redundant\r
+  if( d_conc_to_id[prop_index].find( body )==d_conc_to_id[prop_index].end() ){\r
+    d_conc_to_id[prop_index][body] = id;\r
+    return true;\r
+  }else{\r
+    return false;\r
+  }\r
+}\r
+\r
+void InstPropagator::addRelevantInstances( std::vector< Node >& exp, const char * c ) {\r
+  for( unsigned i=0; i<exp.size(); i++ ){\r
+    Assert( d_conc_to_id[0].find( exp[i] )!=d_conc_to_id[0].end() );\r
+    Trace(c) << "  relevant instance id : " << d_conc_to_id[0][ exp[i] ] << std::endl;\r
+    d_relevant_inst[ d_conc_to_id[0][ exp[i] ] ] = true;\r
+  }\r
+}\r
+\r
+void InstPropagator::debugPrintExplanation( std::vector< Node >& exp, const char * c ) {\r
+  for( unsigned i=0; i<exp.size(); i++ ){\r
+    Assert( d_conc_to_id[0].find( exp[i] )!=d_conc_to_id[0].end() );\r
+    Trace(c) << d_conc_to_id[0][ exp[i] ] << " ";\r
+  }\r
+}\r
+\r
diff --git a/src/theory/quantifiers/inst_propagator.h b/src/theory/quantifiers/inst_propagator.h
new file mode 100644 (file)
index 0000000..0e21dc0
--- /dev/null
@@ -0,0 +1,160 @@
+/*********************                                                        */\r
+/*! \file inst_propagator.h\r
+ ** \verbatim\r
+ ** Top contributors (to current version):\r
+ **   Andrew Reynolds\r
+ ** This file is part of the CVC4 project.\r
+ ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS\r
+ ** in the top-level source directory) and their institutional affiliations.\r
+ ** All rights reserved.  See the file COPYING in the top-level source\r
+ ** directory for licensing information.\endverbatim\r
+ **\r
+ ** \brief Propagate mechanism for instantiations\r
+ **/\r
+\r
+#include "cvc4_private.h"\r
+\r
+#ifndef __CVC4__QUANTIFIERS_INST_PROPAGATOR_H\r
+#define __CVC4__QUANTIFIERS_INST_PROPAGATOR_H\r
+\r
+#include <iostream>\r
+#include <string>\r
+#include <vector>\r
+#include <map>\r
+#include "expr/node.h"\r
+#include "expr/type_node.h"\r
+#include "theory/quantifiers_engine.h"\r
+#include "theory/quantifiers/term_database.h"\r
+\r
+namespace CVC4 {\r
+namespace theory {\r
+namespace quantifiers {\r
+\r
+class EqualityQueryInstProp : public EqualityQuery {\r
+private:\r
+  /** pointer to quantifiers engine */\r
+  QuantifiersEngine* d_qe;\r
+public:\r
+  EqualityQueryInstProp( QuantifiersEngine* qe );\r
+  ~EqualityQueryInstProp(){};\r
+  /** reset */\r
+  bool reset( Theory::Effort e );\r
+  /** identify */\r
+  std::string identify() const { return "EqualityQueryInstProp"; }\r
+  /** extends engine */\r
+  bool extendsEngine() { return true; }\r
+  /** contains term */\r
+  bool hasTerm( Node a );\r
+  /** get the representative of the equivalence class of a */\r
+  Node getRepresentative( Node a );\r
+  /** returns true if a and b are equal in the current context */\r
+  bool areEqual( Node a, Node b );\r
+  /** returns true is a and b are disequal in the current context */\r
+  bool areDisequal( Node a, Node b );\r
+  /** get the equality engine associated with this query */\r
+  eq::EqualityEngine* getEngine();\r
+  /** get the equivalence class of a */\r
+  void getEquivalenceClass( Node a, std::vector< Node >& eqc );\r
+  /** get congruent term */\r
+  TNode getCongruentTerm( Node f, std::vector< TNode >& args );\r
+public:\r
+  /** get the representative of the equivalence class of a, with explanation */\r
+  Node getRepresentativeExp( Node a, std::vector< Node >& exp );\r
+  /** returns true if a and b are equal in the current context */\r
+  bool areEqualExp( Node a, Node b, std::vector< Node >& exp );\r
+  /** returns true is a and b are disequal in the current context */\r
+  bool areDisequalExp( Node a, Node b, std::vector< Node >& exp );\r
+private:\r
+  /** term index */\r
+  std::map< Node, TermArgTrie > d_func_map_trie;\r
+  /** union find for terms beyond what is stored in equality engine */\r
+  std::map< Node, Node > d_uf;\r
+  std::map< Node, std::vector< Node > > d_uf_exp;\r
+  Node getUfRepresentative( Node a, std::vector< Node >& exp );\r
+  /** disequality list, stores explanations */\r
+  std::map< Node, std::map< Node, Node > > d_diseq_list;\r
+  /** add arg */\r
+  void addArgument( std::vector< TNode >& args, std::vector< TNode >& props, Node n, bool is_prop, bool pol );\r
+public:\r
+  enum {\r
+    STATUS_MERGED_KNOWN,\r
+    STATUS_MERGED_UNKNOWN,\r
+    STATUS_NONE,\r
+  };\r
+  /** set equal */\r
+  int setEqual( Node& a, Node& b, std::vector< Node >& reason );\r
+  Node d_true;\r
+  Node d_false;\r
+public:\r
+  //for explanations\r
+  static void merge_exp( std::vector< Node >& v, std::vector< Node >& v_to_merge, int up_to_size = -1 );\r
+\r
+  Node evaluateTermExp( TNode n, std::vector< Node >& exp, std::map< TNode, Node >& visited, bool hasPol, bool pol,\r
+                        std::map< Node, bool >& watch_list_out, std::vector< TNode >& props );\r
+  static bool isLiteral( Node n );\r
+};\r
+\r
+class InstPropagator : public QuantifiersUtil {\r
+private:\r
+  /** pointer to quantifiers engine */\r
+  QuantifiersEngine* d_qe;\r
+  /** notify class */\r
+  class InstantiationNotifyInstPropagator : public InstantiationNotify {\r
+    InstPropagator& d_ip;\r
+  public:\r
+    InstantiationNotifyInstPropagator(InstPropagator& ip): d_ip(ip) {}\r
+    virtual void notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) { d_ip.notifyInstantiation( quant_e, q, lem, terms, body ); }\r
+  };\r
+  InstantiationNotifyInstPropagator d_notify;\r
+  /** notify instantiation method */\r
+  void notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body );\r
+  /** equality query */\r
+  EqualityQueryInstProp d_qy;\r
+  class InstInfo {\r
+  public:\r
+    bool d_active;\r
+    Node d_q;\r
+    Node d_lem;\r
+    std::vector< Node > d_terms;\r
+    // the current entailed body\r
+    Node d_curr;\r
+    //explanation for current entailed body\r
+    std::vector< Node > d_curr_exp;\r
+    void init( Node q, Node lem, std::vector< Node >& terms, Node body );\r
+  };\r
+  /** instantiation count/info */\r
+  unsigned d_icount;\r
+  std::map< unsigned, InstInfo > d_ii;\r
+  std::map< TNode, unsigned > d_conc_to_id[2];\r
+  /** are we in conflict */\r
+  bool d_conflict;\r
+  /** watch list */\r
+  std::map< Node, std::map< unsigned, bool > > d_watch_list;\r
+  /** update list */\r
+  std::vector< unsigned > d_update_list;\r
+  /** relevant instances */\r
+  std::map< unsigned, bool > d_relevant_inst;\r
+private:\r
+  bool update( unsigned id, InstInfo& i, bool firstTime = false );\r
+  void propagate( Node a, Node b, bool pol, std::vector< Node >& exp );\r
+  void conflict( std::vector< Node >& exp );\r
+  bool cacheConclusion( unsigned id, Node body, int prop_index = 0 );\r
+  void addRelevantInstances( std::vector< Node >& exp, const char * c );\r
+\r
+  void debugPrintExplanation( std::vector< Node >& exp, const char * c );\r
+public:\r
+  InstPropagator( QuantifiersEngine* qe );\r
+  ~InstPropagator(){}\r
+  /** reset */\r
+  bool reset( Theory::Effort e );\r
+  /** identify */\r
+  std::string identify() const { return "InstPropagator"; }\r
+  /** get the notify mechanism */\r
+  InstantiationNotify* getInstantiationNotify() { return &d_notify; }\r
+};\r
+\r
+}\r
+}\r
+}\r
+\r
+#endif\r
index e1cbbcfe33644c3473c0beeef7ff1a96915c5c22..e5df41510bdc765501b579a50f5174405a178285 100644 (file)
@@ -1061,16 +1061,27 @@ void MatchGen::reset_round( QuantConflictFind * p ) {
     d_qni_gterm_rep[it->first] = p->getRepresentative( it->second );
   }
   if( d_type==typ_ground ){
-    int e = p->evaluate( d_n );
-    if( e==1 ){
-      d_ground_eval[0] = p->d_true;
-    }else if( e==-1 ){
-      d_ground_eval[0] = p->d_false;
+    //int e = p->evaluate( d_n );
+    //if( e==1 ){
+    //  d_ground_eval[0] = p->d_true;
+    //}else if( e==-1 ){
+    //  d_ground_eval[0] = p->d_false;
+    //}
+    //modified 
+    for( unsigned i=0; i<2; i++ ){ 
+      if( p->getTermDatabase()->isEntailed( d_n, i==0 ) ){
+        d_ground_eval[0] = i==0 ? p->d_true : p->d_false;
+      }
     }
   }else if( d_type==typ_eq ){
     for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
       if( !d_n[i].hasBoundVar() ){
-        d_ground_eval[i] = p->evaluateTerm( d_n[i] );
+        TNode t = p->getTermDatabase()->getEntailedTerm( d_n[i] );
+        if( t.isNull() ){
+          d_ground_eval[i] = d_n[i];
+        }else{
+          d_ground_eval[i] = t;
+        }
       }
     }
   }
@@ -1103,8 +1114,12 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
     int vn = qi->getCurrentRepVar( qi->getVarNum( n ) );
     if( vn==-1 ){
       //evaluate the value, see if it is compatible
-      int e = p->evaluate( n );
-      if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){
+      //int e = p->evaluate( n );
+      //if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){
+      //  d_child_counter = 0;
+      //}
+      //modified 
+      if( p->getTermDatabase()->isEntailed( n, d_tgt ) ){ 
         d_child_counter = 0;
       }
     }else{
@@ -1787,84 +1802,6 @@ void QuantConflictFind::registerQuantifier( Node q ) {
   }
 }
 
-int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) {
-  int ret = 0;
-  if( n.getKind()==EQUAL ){
-    Node n1 = evaluateTerm( n[0] );
-    Node n2 = evaluateTerm( n[1] );
-    Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl;
-    if( areEqual( n1, n2 ) ){
-      ret = 1;
-    }else if( areDisequal( n1, n2 ) ){
-      ret = -1;
-    }
-    //else if( d_effort>QuantConflictFind::effort_conflict ){
-    //  ret = -1;
-    //}
-  }else if( MatchGen::isHandledUfTerm( n ) ){  //predicate
-    Node nn = evaluateTerm( n );
-    Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl;
-    if( areEqual( nn, d_true ) ){
-      ret = 1;
-    }else if( areEqual( nn, d_false ) ){
-      ret = -1;
-    }
-    //else if( d_effort>QuantConflictFind::effort_conflict ){
-    //  ret = -1;
-    //}
-  }else if( n.getKind()==NOT ){
-    return -evaluate( n[0] );
-  }else if( n.getKind()==ITE ){
-    int cev1 = evaluate( n[0] );
-    int cevc[2] = { 0, 0 };
-    for( unsigned i=0; i<2; i++ ){
-      if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){
-        cevc[i] = evaluate( n[i+1] );
-        if( cev1!=0 ){
-          ret = cevc[i];
-          break;
-        }else if( cevc[i]==0 ){
-          break;
-        }
-      }
-    }
-    if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){
-      ret = cevc[0];
-    }
-  }else if( n.getKind()==IFF ){
-    int cev1 = evaluate( n[0] );
-    if( cev1!=0 ){
-      int cev2 = evaluate( n[1] );
-      if( cev2!=0 ){
-        ret = cev1==cev2 ? 1 : -1;
-      }
-    }
-
-  }else{
-    int ssval = 0;
-    if( n.getKind()==OR ){
-      ssval = 1;
-    }else if( n.getKind()==AND ){
-      ssval = -1;
-    }
-    bool isUnk = false;
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      int cev = evaluate( n[i] );
-      if( cev==ssval ){
-        ret = ssval;
-        break;
-      }else if( cev==0 ){
-        isUnk = true;
-      }
-    }
-    if( ret==0 && !isUnk ){
-      ret = -ssval;
-    }
-  }
-  Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl;
-  return ret;
-}
-
 short QuantConflictFind::getMaxQcfEffort() {
   if( options::qcfMode()==QCF_CONFLICT_ONLY ){
     return effort_conflict;
@@ -1908,38 +1845,6 @@ void QuantConflictFind::assertNode( Node q ) {
   }
 }
 
-Node QuantConflictFind::evaluateTerm( Node n ) {
-  if( MatchGen::isHandledUfTerm( n ) ){
-    Node f = MatchGen::getMatchOperator( this, n );
-    Node nn;
-    if( getEqualityEngine()->hasTerm( n ) ){
-      nn = getTermDatabase()->existsTerm( f, n );
-    }else{
-      std::vector< TNode > args;
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        Node c = evaluateTerm( n[i] );
-        args.push_back( c );
-      }
-      nn = getTermDatabase()->d_func_map_trie[f].existsTerm( args );
-    }
-    if( !nn.isNull() ){
-      Debug("qcf-eval") << "GT: Term " << nn << " for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n )  << std::endl;
-      return getRepresentative( nn );
-    }else{
-      Debug("qcf-eval") << "GT: No term for " << n << " hasTerm = " << getEqualityEngine()->hasTerm( n )  << std::endl;
-      return n;
-    }
-  }else if( n.getKind()==ITE ){
-    int v = evaluate( n[0], false, false );
-    if( v==1 ){
-      return evaluateTerm( n[1] );
-    }else if( v==-1 ){
-      return evaluateTerm( n[2] );
-    }
-  }
-  return getRepresentative( n );
-}
-
 /** new node */
 void QuantConflictFind::newEqClass( Node n ) {
 
@@ -2055,13 +1960,12 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) {
                   std::vector< Node > terms;
                   qi->getMatch( terms );
                   if( !qi->isTConstraintSpurious( this, terms ) ){
+                    //for debugging
                     if( Debug.isOn("qcf-check-inst") ){
-                      //if( e==effort_conflict ){
                       Node inst = d_quantEngine->getInstantiation( q, terms );
                       Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
-                      Assert( evaluate( inst )!=1 );
-                      Assert( evaluate( inst )==-1 || e>effort_conflict );
-                      //}
+                      Assert( !getTermDatabase()->isEntailed( inst, true ) );
+                      Assert( getTermDatabase()->isEntailed( inst, false ) || e>effort_conflict );
                     }
                     if( d_quantEngine->addInstantiation( q, terms, false ) ){
                       Trace("qcf-check") << "   ... Added instantiation" << std::endl;
index 0e0e781000218f4ef4c2913180b175d8cf92295e..36fcaddf5479d3f06a6e21eb5914fcc53000c5c9 100644 (file)
@@ -191,9 +191,6 @@ public:  //for ground terms
   Node d_true;
   Node d_false;
   TNode getZero( Kind k );
-private:
-  Node evaluateTerm( Node n );
-  int evaluate( Node n, bool pref = false, bool hasPref = false );
 private:
   //currently asserted quantifiers
   NodeList d_qassert;
index 5fbc4695443f9b50861bf3e65f5e15b5e598a8e9..3b7787a20bca2fdb903910059eb75036c0d6ccf5 100644 (file)
@@ -23,6 +23,38 @@ using namespace CVC4::kind;
 using namespace CVC4::context;
 using namespace CVC4::theory;
 
+
+unsigned QuantifiersModule::needsModel( Theory::Effort e ) {
+  return QuantifiersEngine::QEFFORT_NONE;
+}
+
+eq::EqualityEngine * QuantifiersModule::getEqualityEngine() {
+  return d_quantEngine->getMasterEqualityEngine();
+}
+
+bool QuantifiersModule::areEqual( TNode n1, TNode n2 ) {
+  eq::EqualityEngine * ee = getEqualityEngine();
+  return n1==n2 || ( ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areEqual( n1, n2 ) );
+}
+
+bool QuantifiersModule::areDisequal( TNode n1, TNode n2 ) {
+  eq::EqualityEngine * ee = getEqualityEngine();
+  return n1!=n2 && ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areDisequal( n1, n2, false );
+}
+
+TNode QuantifiersModule::getRepresentative( TNode n ) {
+  eq::EqualityEngine * ee = getEqualityEngine();
+  if( ee->hasTerm( n ) ){
+    return ee->getRepresentative( n );
+  }else{
+    return n;
+  }
+}
+
+quantifiers::TermDb * QuantifiersModule::getTermDatabase() {
+  return d_quantEngine->getTermDatabase();
+}
+
 bool QuantArith::getMonomial( Node n, Node& c, Node& v ){
   if( n.getKind()==MULT && n.getNumChildren()==2 && n[0].isConst() ){
     c = n[0];
index 8db79db9cf0d0293ab46eea4fbea72cbf163646e..79cdae437094321d2ad49a6e24d21f5c0926b5a2 100644 (file)
@@ -29,6 +29,58 @@ namespace theory {
 
 class QuantifiersEngine;
 
+namespace quantifiers {
+  class TermDb;
+}
+
+class QuantifiersModule {
+protected:
+  QuantifiersEngine* d_quantEngine;
+public:
+  QuantifiersModule( QuantifiersEngine* qe ) : d_quantEngine( qe ){}
+  virtual ~QuantifiersModule(){}
+  //get quantifiers engine
+  QuantifiersEngine* getQuantifiersEngine() { return d_quantEngine; }
+  /** presolve */
+  virtual void presolve() {}
+  /* whether this module needs to check this round */
+  virtual bool needsCheck( Theory::Effort e ) { return e>=Theory::EFFORT_LAST_CALL; }
+  /* whether this module needs a model built */
+  virtual unsigned needsModel( Theory::Effort e );
+  /* reset at a round */
+  virtual void reset_round( Theory::Effort e ){}
+  /* Call during quantifier engine's check */
+  virtual void check( Theory::Effort e, unsigned quant_e ) = 0;
+  /* check was complete (e.g. no lemmas implies a model) */
+  virtual bool checkComplete() { return true; }
+  /* Called for new quantified formulas */
+  virtual void preRegisterQuantifier( Node q ) { }
+  /* Called for new quantifiers after owners are finalized */
+  virtual void registerQuantifier( Node q ) = 0;
+  virtual void assertNode( Node n ) {}
+  virtual void propagate( Theory::Effort level ){}
+  virtual Node getNextDecisionRequest() { return TNode::null(); }
+  /** Identify this module (for debugging, dynamic configuration, etc..) */
+  virtual std::string identify() const = 0;
+public:
+  eq::EqualityEngine * getEqualityEngine();
+  bool areDisequal( TNode n1, TNode n2 );
+  bool areEqual( TNode n1, TNode n2 );
+  TNode getRepresentative( TNode n );
+  quantifiers::TermDb * getTermDatabase();
+};/* class QuantifiersModule */
+
+class QuantifiersUtil {
+public:
+  QuantifiersUtil(){}
+  virtual ~QuantifiersUtil(){}
+  /* reset at a round */
+  virtual bool reset( Theory::Effort e ) = 0;
+  /** Identify this module (for debugging, dynamic configuration, etc..) */
+  virtual std::string identify() const = 0;
+};
+
+
 class QuantArith
 {
 public:
@@ -97,7 +149,7 @@ public:
 };
 
 
-class EqualityQuery {
+class EqualityQuery : public QuantifiersUtil{
 public:
   EqualityQuery(){}
   virtual ~EqualityQuery(){};
@@ -115,6 +167,8 @@ public:
   virtual eq::EqualityEngine* getEngine() = 0;
   /** get the equivalence class of a */
   virtual void getEquivalenceClass( Node a, std::vector< Node >& eqc ) = 0;
+  /** get the term that exists in EE that is congruent to f with args (f is returned by TermDb::getMatchOperator(...) */
+  virtual TNode getCongruentTerm( Node f, std::vector< TNode >& args ) = 0;
 };/* class EqualityQuery */
 
 
index 6cc14c023f3fd292eb350a7193407f5f39d77c8a..9181677eeb18b95d45c1e20273fc274034a39576 100644 (file)
@@ -82,8 +82,9 @@ RelevantDomain::RDomain * RelevantDomain::getRDomain( Node n, int i, bool getPar
   return getParent ? d_rel_doms[n][i]->getParent() : d_rel_doms[n][i];
 }
 
-void RelevantDomain::reset(){
+bool RelevantDomain::reset( Theory::Effort e ) {
   d_is_computed = false;
+  return true;
 }
 
 void RelevantDomain::compute(){
index 819e0e7b67c57a6749b6e4610e1128bce3476bb2..2b90520fd919d9167d12f3463fcb3c88e3ab0968 100644 (file)
@@ -23,7 +23,7 @@ namespace CVC4 {
 namespace theory {
 namespace quantifiers {
 
-class RelevantDomain
+class RelevantDomain : public QuantifiersUtil
 {
 private:
   class RDomain
@@ -62,7 +62,10 @@ private:
 public:
   RelevantDomain( QuantifiersEngine* qe, FirstOrderModel* m );
   virtual ~RelevantDomain(){}
-  void reset();
+  /* reset */
+  bool reset( Theory::Effort e );
+  /** identify */
+  std::string identify() const { return "RelevantDomain"; }
   //compute the relevant domain
   void compute();
 
index 763a80af3c4e10d2de32a7c7c1047fe9cfa1517e..3d3646d7d4d95b129dd385334e9dbd5f60e280c7 100644 (file)
@@ -205,67 +205,59 @@ void TermDb::computeUfEqcTerms( TNode f ) {
   }
 }
 
-//returns a term n' equivalent to n
-//  - if hasSubs = true, then n is consider under substitution subs
-//  - if mkNewTerms = true, then n' is either null, or a term in the master equality engine
-Node TermDb::evaluateTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, std::map< TNode, Node >& visited, EqualityQuery * qy ) {
+//return a term n' equivalent to n
+//  maximal subterms of n' are representatives in the equality engine qy
+Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy ) {
   std::map< TNode, Node >::iterator itv = visited.find( n );
   if( itv != visited.end() ){
     return itv->second;
   }
-  Node ret;
+  Assert( n.getKind()!=BOUND_VARIABLE );
   Trace("term-db-eval") << "evaluate term : " << n << std::endl;
-  if( qy->hasTerm( n ) ){
-    Trace("term-db-eval") << "...exists in ee, return rep " << std::endl;
-    ret = qy->getRepresentative( n );
-  }else if( n.getKind()==BOUND_VARIABLE ){
-    if( hasSubs ){
-      Assert( subs.find( n )!=subs.end() );
-      Trace("term-db-eval") << "...substitution is : " << subs[n] << std::endl;
-      if( subsRep ){
-        Assert( qy->hasTerm( subs[n] ) );
-        Assert( qy->getRepresentative( subs[n] )==subs[n] );
-        ret = subs[n];
-      }else{
-        ret = evaluateTerm2( subs[n], subs, subsRep, hasSubs, visited, qy );
-      }
-    }
-  }else if( n.getKind()==FORALL ){
-    ret = n;
-  }else{
-    if( n.hasOperator() ){
+  Node ret;
+  if( !qy->hasTerm( n ) ){
+    //term is not known to be equal to a representative in equality engine, evaluate it
+    if( n.getKind()==FORALL ){
+      ret = Node::null();
+    }else if( n.hasOperator() ){
       TNode f = getMatchOperator( n );
       std::vector< TNode > args;
       bool ret_set = false;
       for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        TNode c = evaluateTerm2( n[i], subs, subsRep, hasSubs, visited, qy );
+        TNode c = evaluateTerm2( n[i], visited, qy );
         if( c.isNull() ){
-          ret = TNode::null();
+          ret = Node::null();
           ret_set = true;
           break;
+        }else if( c==d_true || c==d_false ){
+          //short-circuiting
+          if( ( n.getKind()==kind::AND && c==d_false ) || ( n.getKind()==kind::OR && c==d_true ) ){
+            ret = c;
+            ret_set = true;
+            break;
+          }else if( n.getKind()==kind::ITE && i==0 ){
+            ret = evaluateTerm2( n[ c==d_true ? 1 : 2], visited, qy ); 
+            ret_set = true;
+            break;
+          }
         }
-        Trace("term-db-eval") << "Child " << i << " : " << c << std::endl;
-        //short-circuit and/or
-        if( ( n.getKind()==kind::AND && c==d_false ) || ( n.getKind()==kind::OR && c==d_true ) ){
-          ret = c;
-          ret_set = true;
-          break;
-        }else{
-          args.push_back( c );
-        }
+        Trace("term-db-eval") << "  child " << i << " : " << c << std::endl;
+        args.push_back( c );
       }
       if( !ret_set ){
+        //if it is an indexed term, return the congruent term
         if( !f.isNull() ){
-          Trace("term-db-eval") << "Get term from DB" << std::endl;
-          TNode nn = d_func_map_trie[f].existsTerm( args );
-          Trace("term-db-eval") << "Got term " << nn << std::endl;
-          if( !nn.isNull() && qy->hasTerm( nn ) ){
-            Trace("term-db-eval") << "return rep " << std::endl;
+          TNode nn = qy->getCongruentTerm( f, args );
+          Trace("term-db-eval") << "  got congruent term " << nn << " from DB for " << n << std::endl;
+          if( !nn.isNull() ){
             ret = qy->getRepresentative( nn );
+            Trace("term-db-eval") << "return rep" << std::endl;
             ret_set = true;
+            Assert( !ret.isNull() );
           }
         }
         if( !ret_set ){
+          Trace("term-db-eval") << "return rewrite" << std::endl;
           //a theory symbol or a new UF term
           if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
             args.insert( args.begin(), n.getOperator() );
@@ -275,6 +267,9 @@ Node TermDb::evaluateTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRe
         }
       }
     }
+  }else{
+    Trace("term-db-eval") << "...exists in ee, return rep" << std::endl;
+    ret = qy->getRepresentative( n );
   }
   Trace("term-db-eval") << "evaluated term : " << n << ", got : " << ret << std::endl;
   visited[n] = ret;
@@ -282,22 +277,28 @@ Node TermDb::evaluateTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRe
 }
 
 
-TNode TermDb::evaluateTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, EqualityQuery * qy ) {
+TNode TermDb::getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, EqualityQuery * qy ) {
   Assert( !qy->extendsEngine() );
-  Trace("term-db-eval") << "evaluate term : " << n << std::endl;
+  Trace("term-db-entail") << "get entailed term : " << n << std::endl;
   if( qy->getEngine()->hasTerm( n ) ){
-    Trace("term-db-eval") << "...exists in ee, return rep " << std::endl;
+    Trace("term-db-entail") << "...exists in ee, return rep " << std::endl;
     return n;
   }else if( n.getKind()==BOUND_VARIABLE ){
     if( hasSubs ){
       Assert( subs.find( n )!=subs.end() );
-      Trace("term-db-eval") << "...substitution is : " << subs[n] << std::endl;
+      Trace("term-db-entail") << "...substitution is : " << subs[n] << std::endl;
       if( subsRep ){
         Assert( qy->getEngine()->hasTerm( subs[n] ) );
         Assert( qy->getEngine()->getRepresentative( subs[n] )==subs[n] );
         return subs[n];
       }else{
-        return evaluateTerm2( subs[n], subs, subsRep, hasSubs, qy );
+        return getEntailedTerm2( subs[n], subs, subsRep, hasSubs, qy );
+      }
+    }
+  }else if( n.getKind()==ITE ){
+    for( unsigned i=0; i<2; i++ ){
+      if( isEntailed2( n[0], subs, subsRep, hasSubs, i==0, qy ) ){
+        return getEntailedTerm2( n[ i==0 ? 1 : 2 ], subs, subsRep, hasSubs, qy );
       }
     }
   }else{
@@ -306,17 +307,16 @@ TNode TermDb::evaluateTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsR
       if( !f.isNull() ){
         std::vector< TNode > args;
         for( unsigned i=0; i<n.getNumChildren(); i++ ){
-          TNode c = evaluateTerm2( n[i], subs, subsRep, hasSubs, qy );
+          TNode c = getEntailedTerm2( n[i], subs, subsRep, hasSubs, qy );
           if( c.isNull() ){
             return TNode::null();
           }
           c = qy->getEngine()->getRepresentative( c );
-          Trace("term-db-eval") << "Got child : " << c << std::endl;
+          Trace("term-db-entail") << "  child " << i << " : " << c << std::endl;
           args.push_back( c );
         }
-        Trace("term-db-eval") << "Get term from DB" << std::endl;
-        TNode nn = d_func_map_trie[f].existsTerm( args );
-        Trace("term-db-eval") << "Got term " << nn << std::endl;
+        TNode nn = qy->getCongruentTerm( f, args );
+        Trace("term-db-entail") << "  got congruent term " << nn << " for " << n << std::endl;
         return nn;
       }
     }
@@ -324,39 +324,37 @@ TNode TermDb::evaluateTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsR
   return TNode::null();
 }
 
-Node TermDb::evaluateTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool mkNewTerms, EqualityQuery * qy ) {
+Node TermDb::evaluateTerm( TNode n, EqualityQuery * qy ) {
   if( qy==NULL ){
     qy = d_quantEngine->getEqualityQuery();
   }
-  if( mkNewTerms ){
-    std::map< TNode, Node > visited;
-    return evaluateTerm2( n, subs, subsRep, true, visited, qy );
-  }else{
-    return evaluateTerm2( n, subs, subsRep, true, qy );
+  std::map< TNode, Node > visited;
+  return evaluateTerm2( n, visited, qy );
+}
+
+TNode TermDb::getEntailedTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, EqualityQuery * qy ) {
+  if( qy==NULL ){
+    qy = d_quantEngine->getEqualityQuery();
   }
+  return getEntailedTerm2( n, subs, subsRep, true, qy );
 }
 
-Node TermDb::evaluateTerm( TNode n, bool mkNewTerms, EqualityQuery * qy ) {
+TNode TermDb::getEntailedTerm( TNode n, EqualityQuery * qy ) {
   if( qy==NULL ){
     qy = d_quantEngine->getEqualityQuery();
   }
   std::map< TNode, TNode > subs;
-  if( mkNewTerms ){
-    std::map< TNode, Node > visited;
-    return evaluateTerm2( n, subs, false, false, visited, qy );
-  }else{
-    return evaluateTerm2( n, subs, false, false, qy );
-  }
+  return getEntailedTerm2( n, subs, false, false, qy );
 }
 
-bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, bool pol, EqualityQuery * qy ) {
+bool TermDb::isEntailed2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, bool pol, EqualityQuery * qy ) {
   Assert( !qy->extendsEngine() );
-  Trace("term-db-eval") << "Check entailed : " << n << ", pol = " << pol << std::endl;
+  Trace("term-db-entail") << "Check entailed : " << n << ", pol = " << pol << std::endl;
   Assert( n.getType().isBoolean() );
   if( n.getKind()==EQUAL ){
-    TNode n1 = evaluateTerm2( n[0], subs, subsRep, hasSubs, qy );
+    TNode n1 = getEntailedTerm2( n[0], subs, subsRep, hasSubs, qy );
     if( !n1.isNull() ){
-      TNode n2 = evaluateTerm2( n[1], subs, subsRep, hasSubs, qy );
+      TNode n2 = getEntailedTerm2( n[1], subs, subsRep, hasSubs, qy );
       if( !n2.isNull() ){
         if( n1==n2 ){
           return pol;
@@ -372,11 +370,11 @@ bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep,
       }
     }
   }else if( n.getKind()==NOT ){
-    return isEntailed( n[0], subs, subsRep, hasSubs, !pol, qy );
+    return isEntailed2( n[0], subs, subsRep, hasSubs, !pol, qy );
   }else if( n.getKind()==OR || n.getKind()==AND ){
     bool simPol = ( pol && n.getKind()==OR ) || ( !pol && n.getKind()==AND );
     for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      if( isEntailed( n[i], subs, subsRep, hasSubs, pol, qy ) ){
+      if( isEntailed2( n[i], subs, subsRep, hasSubs, pol, qy ) ){
         if( simPol ){
           return true;
         }
@@ -389,14 +387,14 @@ bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep,
     return !simPol;
   }else if( n.getKind()==IFF || n.getKind()==ITE ){
     for( unsigned i=0; i<2; i++ ){
-      if( isEntailed( n[0], subs, subsRep, hasSubs, i==0, qy ) ){
+      if( isEntailed2( n[0], subs, subsRep, hasSubs, i==0, qy ) ){
         unsigned ch = ( n.getKind()==IFF || i==0 ) ? 1 : 2;
         bool reqPol = ( n.getKind()==ITE || i==0 ) ? pol : !pol;
-        return isEntailed( n[ch], subs, subsRep, hasSubs, reqPol, qy );
+        return isEntailed2( n[ch], subs, subsRep, hasSubs, reqPol, qy );
       }
     }
   }else if( n.getKind()==APPLY_UF ){
-    TNode n1 = evaluateTerm2( n, subs, subsRep, hasSubs, qy );
+    TNode n1 = getEntailedTerm2( n, subs, subsRep, hasSubs, qy );
     if( !n1.isNull() ){
       Assert( qy->hasTerm( n1 ) );
       if( n1==d_true ){
@@ -411,16 +409,21 @@ bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep,
   return false;
 }
 
-bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol, EqualityQuery * qy ) {
+bool TermDb::isEntailed( TNode n, bool pol, EqualityQuery * qy ) {
   if( qy==NULL ){
+    Assert( d_consistent_ee );
     qy = d_quantEngine->getEqualityQuery();
   }
-  if( d_consistent_ee ){
-    return isEntailed( n, subs, subsRep, true, pol, qy );
-  }else{
-    //don't check entailment wrt an inconsistent ee
-    return false;
+  std::map< TNode, TNode > subs;
+  return isEntailed2( n, subs, false, false, pol, qy );
+}
+
+bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol, EqualityQuery * qy ) {
+  if( qy==NULL ){
+    Assert( d_consistent_ee );
+    qy = d_quantEngine->getEqualityQuery();
   }
+  return isEntailed2( n, subs, subsRep, true, pol, qy );
 }
 
 bool TermDb::hasTermCurrent( Node n, bool useMode ) {
@@ -571,7 +574,13 @@ bool TermDb::reset( Theory::Effort effort ){
       }
     }
   }
-
+  //explicitly add inst closure terms to the equality engine to ensure only EE terms are indexed
+  for( std::hash_set< Node, NodeHashFunction >::iterator it = d_iclosure_processed.begin(); it !=d_iclosure_processed.end(); ++it ){
+    Node n = *it;
+    if( !ee->hasTerm( n ) ){
+      ee->addTerm( n );
+    }
+  }
 
   //rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms
   for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){
@@ -579,8 +588,8 @@ bool TermDb::reset( Theory::Effort effort ){
     Trace("term-db-debug") << "Adding terms for operator " << it->first << std::endl;
     for( unsigned i=0; i<it->second.size(); i++ ){
       Node n = it->second[i];
-      //to be added to term index, term must be relevant, and either exist in EE or be an inst closure term
-      if( hasTermCurrent( n ) && ( ee->hasTerm( n ) || d_iclosure_processed.find( n )!=d_iclosure_processed.end() ) ){
+      //to be added to term index, term must be relevant, and exist in EE
+      if( hasTermCurrent( n ) && ee->hasTerm( n ) ){
         if( !n.getAttribute(NoMatchAttribute()) ){
           if( options::finiteModelFind() ){
             computeModelBasisArgAttribute( n );
@@ -681,11 +690,15 @@ TermArgTrie * TermDb::getTermArgTrie( Node eqc, Node f ) {
   }
 }
 
-TNode TermDb::existsTerm( Node f, Node n ) {
+TNode TermDb::getCongruentTerm( Node f, Node n ) {
   computeArgReps( n );
   return d_func_map_trie[f].existsTerm( d_arg_reps[n] );
 }
 
+TNode TermDb::getCongruentTerm( Node f, std::vector< TNode >& args ) {
+  return d_func_map_trie[f].existsTerm( args );
+}
+
 Node TermDb::getModelBasisTerm( TypeNode tn, int i ){
   if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){
     Node mbt;
index 9177d3a1a19fcfe20b755e23e1eb190930822a54..76bd623a8f23ca606ff5d08e092679f8ad9aadc1 100644 (file)
@@ -164,7 +164,7 @@ namespace fmcheck {
 
 class TermDbSygus;
 
-class TermDb {
+class TermDb : public QuantifiersUtil {
   friend class ::CVC4::theory::QuantifiersEngine;
   friend class ::CVC4::theory::inst::Trigger;
   friend class ::CVC4::theory::quantifiers::fmcheck::FullModelChecker;
@@ -183,9 +183,9 @@ private:
   /** set has term */
   void setHasTerm( Node n );
   /** evaluate term */
-  TNode evaluateTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, EqualityQuery * qy );
-  Node evaluateTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, std::map< TNode, Node >& visited, EqualityQuery * qy );
-  bool isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, bool pol, EqualityQuery * qy );
+  Node evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy );
+  TNode getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, EqualityQuery * qy );
+  bool isEntailed2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, bool pol, EqualityQuery * qy );
 public:
   TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe );
   ~TermDb(){}
@@ -224,13 +224,16 @@ public:
   void presolve();
   /** reset (calculate which terms are active) */
   bool reset( Theory::Effort effort );
+  /** identify */
+  std::string identify() const { return "TermDb"; }
   /** get match operator */
   Node getMatchOperator( Node n );
   /** get term arg index */
   TermArgTrie * getTermArgTrie( Node f );
   TermArgTrie * getTermArgTrie( Node eqc, Node f );
   /** exists term */
-  TNode existsTerm( Node f, Node n );
+  TNode getCongruentTerm( Node f, Node n );
+  TNode getCongruentTerm( Node f, std::vector< TNode >& args );
   /** compute arg reps */
   void computeArgReps( TNode n );
   /** compute uf eqc terms */
@@ -238,10 +241,12 @@ public:
   /** evaluate a term under a substitution.  Return representative in EE if possible.
    * subsRep is whether subs contains only representatives
    */
-  Node evaluateTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool mkNewTerms = false, EqualityQuery * qy = NULL );
-  /** same as above, but without substitution */
-  Node evaluateTerm( TNode n, bool mkNewTerms = false, EqualityQuery * qy = NULL );
+  Node evaluateTerm( TNode n, EqualityQuery * qy = NULL );
+  /** get entailed term, does not construct new terms, less aggressive */
+  TNode getEntailedTerm( TNode n, EqualityQuery * qy = NULL );
+  TNode getEntailedTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, EqualityQuery * qy = NULL );
   /** is entailed (incomplete check) */
+  bool isEntailed( TNode n, bool pol, EqualityQuery * qy = NULL );
   bool isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol, EqualityQuery * qy = NULL );
   /** has term */
   bool hasTermCurrent( Node n, bool useMode = true );
index d31865f354e1cea6e841f41e2fc51e3898c3a694..839077a4027e75a57fb29d4d85d6ce843514fff6 100644 (file)
@@ -42,6 +42,7 @@
 #include "theory/quantifiers/quant_split.h"
 #include "theory/quantifiers/anti_skolem.h"
 #include "theory/quantifiers/equality_infer.h"
+#include "theory/quantifiers/inst_propagator.h"
 #include "theory/theory_engine.h"
 #include "theory/uf/equality_engine.h"
 #include "theory/uf/theory_uf.h"
@@ -54,37 +55,6 @@ using namespace CVC4::context;
 using namespace CVC4::theory;
 using namespace CVC4::theory::inst;
 
-unsigned QuantifiersModule::needsModel( Theory::Effort e ) {
-  return QuantifiersEngine::QEFFORT_NONE;
-}
-
-eq::EqualityEngine * QuantifiersModule::getEqualityEngine() {
-  return d_quantEngine->getMasterEqualityEngine();
-}
-
-bool QuantifiersModule::areEqual( TNode n1, TNode n2 ) {
-  eq::EqualityEngine * ee = getEqualityEngine();
-  return n1==n2 || ( ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areEqual( n1, n2 ) );
-}
-
-bool QuantifiersModule::areDisequal( TNode n1, TNode n2 ) {
-  eq::EqualityEngine * ee = getEqualityEngine();
-  return n1!=n2 && ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areDisequal( n1, n2, false );
-}
-
-TNode QuantifiersModule::getRepresentative( TNode n ) {
-  eq::EqualityEngine * ee = getEqualityEngine();
-  if( ee->hasTerm( n ) ){
-    return ee->getRepresentative( n );
-  }else{
-    return n;
-  }
-}
-
-quantifiers::TermDb * QuantifiersModule::getTermDatabase() {
-  return d_quantEngine->getTermDatabase();
-}
-
 QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext* u, TheoryEngine* te):
     d_te( te ),
     d_lemmas_produced_c(u),
@@ -98,8 +68,21 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext*
     d_presolve_cache(u),
     d_presolve_cache_wq(u),
     d_presolve_cache_wic(u){
+  //utilities
   d_eq_query = new EqualityQueryQuantifiersEngine( c, this );
+  d_util.push_back( d_eq_query );
+  
   d_term_db = new quantifiers::TermDb( c, u, this );
+  d_util.push_back( d_term_db );
+  
+  if( options::instPropagate() ){
+    d_inst_prop = new quantifiers::InstPropagator( this );
+    d_util.push_back( d_inst_prop );
+    d_inst_notify.push_back( d_inst_prop->getInstantiationNotify() );
+  }else{
+    d_inst_prop = NULL;
+  }
+
   d_tr_trie = new inst::TriggerTrie;
   d_hasAddedLemma = false;
   //don't add true lemma
@@ -183,6 +166,7 @@ QuantifiersEngine::~QuantifiersEngine(){
   delete d_i_cbqi;
   delete d_qsplit;
   delete d_anti_skolem;
+  delete d_inst_prop;
 }
 
 EqualityQueryQuantifiersEngine* QuantifiersEngine::getEqualityQuery() {
@@ -288,6 +272,7 @@ void QuantifiersEngine::finishInit(){
 
   if( needsRelDom ){
     d_rel_dom = new quantifiers::RelevantDomain( this, d_model );
+    d_util.push_back( d_rel_dom );
   }
 
   if( needsBuilder ){
@@ -389,6 +374,12 @@ void QuantifiersEngine::check( Theory::Effort e ){
 
   Trace("quant-engine-debug2") << "Quantifiers Engine call to check, level = " << e << ", needsCheck=" << needsCheck << std::endl;
   if( needsCheck ){
+    //flush previous lemmas (for instance, if was interupted), or other lemmas to process
+    flushLemmas();
+    if( d_hasAddedLemma ){
+      return;
+    }
+    
     if( Trace.isOn("quant-engine-debug") ){
       Trace("quant-engine-debug") << "Quantifiers Engine check, level = " << e << std::endl;
       Trace("quant-engine-debug") << "  depth : " << d_ierCounter_c << std::endl;
@@ -405,44 +396,38 @@ void QuantifiersEngine::check( Theory::Effort e ){
       Trace("quant-engine-debug") << "  Needs model effort : " << needsModelE << std::endl;
       Trace("quant-engine-debug") << "Resetting all modules..." << std::endl;
     }
-
-    //reset relevant information
-
-    //flush previous lemmas (for instance, if was interupted), or other lemmas to process
-    flushLemmas();
-    if( d_hasAddedLemma ){
-      return;
-    }
-
     if( Trace.isOn("quant-engine-ee-pre") ){
       Trace("quant-engine-ee-pre") << "Equality engine (pre-inference): " << std::endl;
       debugPrintEqualityEngine( "quant-engine-ee-pre" );
     }
-    Trace("quant-engine-debug2") << "Reset equality engine..." << std::endl;
-    if( !d_eq_query->reset( e ) ){
-      flushLemmas();
-      return;
-    }
-    
     if( Trace.isOn("quant-engine-assert") ){
       Trace("quant-engine-assert") << "Assertions : " << std::endl;
       getTheoryEngine()->printAssertions("quant-engine-assert");
     }
+    
+    //reset utilities
+    for( unsigned i=0; i<d_util.size(); i++ ){
+      Trace("quant-engine-debug2") << "Reset " << d_util[i]->identify().c_str() << "..." << std::endl;
+      if( !d_util[i]->reset( e ) ){
+        flushLemmas();
+        if( d_hasAddedLemma ){
+          return;
+        }else{
+          //should only fail reset if added a lemma
+          Assert( false );
+        }
+      }
+    }
+
     if( Trace.isOn("quant-engine-ee") ){
       Trace("quant-engine-ee") << "Equality engine : " << std::endl;
       debugPrintEqualityEngine( "quant-engine-ee" );
     }
-    
-    Trace("quant-engine-debug2") << "Reset term database..." << std::endl;
-    if( !d_term_db->reset( e ) ){
-      flushLemmas();
-      return;
-    }
-    if( d_rel_dom ){
-      d_rel_dom->reset();
-    }
+
+    //reset the model
     d_model->reset_round();
     
+    //reset the modules
     for( unsigned i=0; i<d_modules.size(); i++ ){
       Trace("quant-engine-debug2") << "Reset " << d_modules[i]->identify().c_str() << std::endl;
       d_modules[i]->reset_round( e );
@@ -1007,6 +992,7 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
   
   //check for positive entailment
   if( options::instNoEntail() ){
+    //TODO: check consistency of equality engine (if not aborting on utility's reset)
     std::map< TNode, TNode > subs;
     for( unsigned i=0; i<terms.size(); i++ ){
       subs[q[0][i]] = terms[i];
@@ -1069,9 +1055,11 @@ bool QuantifiersEngine::addInstantiation( Node q, std::vector< Node >& terms, bo
       }
       setInstantiationLevelAttr( body, q[1], maxInstLevel+1 );
     }
-    //notify listeners
-    for( unsigned j=0; j<d_inst_notify.size(); j++ ){
-      d_inst_notify[j]->notifyInstantiation( q, lem, terms, body );
+    if( d_curr_effort_level>QEFFORT_CONFLICT ){
+      //notify listeners
+      for( unsigned j=0; j<d_inst_notify.size(); j++ ){
+        d_inst_notify[j]->notifyInstantiation( d_curr_effort_level, q, lem, terms, body );
+      }
     }
     Trace("inst-add-debug") << " -> Success." << std::endl;
     ++(d_statistics.d_instantiations);
@@ -1571,6 +1559,10 @@ void EqualityQueryQuantifiersEngine::getEquivalenceClass( Node a, std::vector< N
   Assert( std::find( eqc.begin(), eqc.end(), a )!=eqc.end() );
 }
 
+TNode EqualityQueryQuantifiersEngine::getCongruentTerm( Node f, std::vector< TNode >& args ) {
+  return d_qe->getTermDatabase()->getCongruentTerm( f, args );
+}
+
 //helper functions
 
 Node EqualityQueryQuantifiersEngine::getInstance( Node n, const std::vector< Node >& eqc, std::hash_map<TNode, Node, TNodeHashFunction>& cache ){
index cdf7c3b89f9701ce5b7c8207251a1217020d3b2c..9ee967eb08abce8ac7f03eddd2cd260ccd9a014e 100644 (file)
@@ -44,47 +44,10 @@ namespace quantifiers {
   class TermDbSygus;
 }
 
-class QuantifiersModule {
-protected:
-  QuantifiersEngine* d_quantEngine;
-public:
-  QuantifiersModule( QuantifiersEngine* qe ) : d_quantEngine( qe ){}
-  virtual ~QuantifiersModule(){}
-  //get quantifiers engine
-  QuantifiersEngine* getQuantifiersEngine() { return d_quantEngine; }
-  /** presolve */
-  virtual void presolve() {}
-  /* whether this module needs to check this round */
-  virtual bool needsCheck( Theory::Effort e ) { return e>=Theory::EFFORT_LAST_CALL; }
-  /* whether this module needs a model built */
-  virtual unsigned needsModel( Theory::Effort e );
-  /* reset at a round */
-  virtual void reset_round( Theory::Effort e ){}
-  /* Call during quantifier engine's check */
-  virtual void check( Theory::Effort e, unsigned quant_e ) = 0;
-  /* check was complete (e.g. no lemmas implies a model) */
-  virtual bool checkComplete() { return true; }
-  /* Called for new quantified formulas */
-  virtual void preRegisterQuantifier( Node q ) { }
-  /* Called for new quantifiers after owners are finalized */
-  virtual void registerQuantifier( Node q ) = 0;
-  virtual void assertNode( Node n ) {}
-  virtual void propagate( Theory::Effort level ){}
-  virtual Node getNextDecisionRequest() { return TNode::null(); }
-  /** Identify this module (for debugging, dynamic configuration, etc..) */
-  virtual std::string identify() const = 0;
-public:
-  eq::EqualityEngine * getEqualityEngine();
-  bool areDisequal( TNode n1, TNode n2 );
-  bool areEqual( TNode n1, TNode n2 );
-  TNode getRepresentative( TNode n );
-  quantifiers::TermDb * getTermDatabase();
-};/* class QuantifiersModule */
-
 class InstantiationNotify {
 public:
   InstantiationNotify(){}
-  virtual void notifyInstantiation( Node q, Node lem, std::vector< Node >& terms, Node body ) = 0;
+  virtual void notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) = 0;
 };
 
 namespace quantifiers {
@@ -109,6 +72,7 @@ namespace quantifiers {
   class QuantDSplit;
   class QuantAntiSkolem;
   class EqualityInference;
+  class InstPropagator;
 }/* CVC4::theory::quantifiers */
 
 namespace inst {
@@ -132,6 +96,8 @@ class QuantifiersEngine {
 private:
   /** reference to theory engine object */
   TheoryEngine* d_te;
+  /** vector of utilities for quantifiers */
+  std::vector< QuantifiersUtil* > d_util;
   /** vector of modules for quantifiers */
   std::vector< QuantifiersModule* > d_modules;
   /** instantiation notify */
@@ -174,6 +140,8 @@ private:
   quantifiers::QuantDSplit * d_qsplit;
   /** quantifiers anti-skolemization */
   quantifiers::QuantAntiSkolem * d_anti_skolem;
+  /** quantifiers instantiation propagtor */
+  quantifiers::InstPropagator * d_inst_prop;
 public: //effort levels
   enum {
     QEFFORT_CONFLICT,
@@ -427,11 +395,15 @@ private:
   Node getInstance( Node n, const std::vector< Node >& eqc, std::hash_map<TNode, Node, TNodeHashFunction>& cache );
   /** get score */
   int getRepScore( Node n, Node f, int index, TypeNode v_tn );
+  /** flatten representatives */
+  void flattenRepresentatives( std::map< TypeNode, std::vector< Node > >& reps );
 public:
   EqualityQueryQuantifiersEngine( context::Context* c, QuantifiersEngine* qe );
   virtual ~EqualityQueryQuantifiersEngine();
   /** reset */
   bool reset( Theory::Effort e );
+  /** identify */
+  std::string identify() const { return "EqualityQueryQE"; }
   /** general queries about equality */
   bool hasTerm( Node a );
   Node getRepresentative( Node a );
@@ -439,13 +411,12 @@ public:
   bool areDisequal( Node a, Node b );
   eq::EqualityEngine* getEngine();
   void getEquivalenceClass( Node a, std::vector< Node >& eqc );
+  TNode getCongruentTerm( Node f, std::vector< TNode >& args );
   /** getInternalRepresentative gets the current best representative in the equivalence class of a, based on some criteria.
       If cbqi is active, this will return a term in the equivalence class of "a" that does
       not contain instantiation constants, if such a term exists.
    */
   Node getInternalRepresentative( Node a, Node f, int index );
-  /** flatten representatives */
-  void flattenRepresentatives( std::map< TypeNode, std::vector< Node > >& reps );
   /** get quantifiers equality inference */
   quantifiers::EqualityInference * getEqualityInference() { return d_eq_inference; }
 }; /* EqualityQueryQuantifiersEngine */