Quantifiers subdirectories (#1608)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Wed, 14 Feb 2018 23:55:23 +0000 (17:55 -0600)
committerGitHub <noreply@github.com>
Wed, 14 Feb 2018 23:55:23 +0000 (17:55 -0600)
120 files changed:
src/Makefile.am
src/smt/smt_engine.cpp
src/theory/arith/theory_arith_private.cpp
src/theory/datatypes/datatypes_sygus.cpp
src/theory/datatypes/datatypes_sygus.h
src/theory/quantifiers/ambqi_builder.cpp [deleted file]
src/theory/quantifiers/ambqi_builder.h [deleted file]
src/theory/quantifiers/bounded_integers.cpp [deleted file]
src/theory/quantifiers/bounded_integers.h [deleted file]
src/theory/quantifiers/ce_guided_conjecture.cpp [deleted file]
src/theory/quantifiers/ce_guided_conjecture.h [deleted file]
src/theory/quantifiers/ce_guided_instantiation.cpp [deleted file]
src/theory/quantifiers/ce_guided_instantiation.h [deleted file]
src/theory/quantifiers/ce_guided_pbe.cpp [deleted file]
src/theory/quantifiers/ce_guided_pbe.h [deleted file]
src/theory/quantifiers/ce_guided_single_inv.cpp [deleted file]
src/theory/quantifiers/ce_guided_single_inv.h [deleted file]
src/theory/quantifiers/ce_guided_single_inv_sol.cpp [deleted file]
src/theory/quantifiers/ce_guided_single_inv_sol.h [deleted file]
src/theory/quantifiers/ceg_instantiator.cpp [deleted file]
src/theory/quantifiers/ceg_instantiator.h [deleted file]
src/theory/quantifiers/ceg_t_instantiator.cpp [deleted file]
src/theory/quantifiers/ceg_t_instantiator.h [deleted file]
src/theory/quantifiers/cegqi/ceg_instantiator.cpp [new file with mode: 0644]
src/theory/quantifiers/cegqi/ceg_instantiator.h [new file with mode: 0644]
src/theory/quantifiers/cegqi/ceg_t_instantiator.cpp [new file with mode: 0644]
src/theory/quantifiers/cegqi/ceg_t_instantiator.h [new file with mode: 0644]
src/theory/quantifiers/cegqi/inst_strategy_cbqi.cpp [new file with mode: 0644]
src/theory/quantifiers/cegqi/inst_strategy_cbqi.h [new file with mode: 0644]
src/theory/quantifiers/conjecture_generator.cpp
src/theory/quantifiers/ematching/ho_trigger.cpp [new file with mode: 0644]
src/theory/quantifiers/ematching/ho_trigger.h [new file with mode: 0644]
src/theory/quantifiers/ematching/inst_match_generator.cpp [new file with mode: 0644]
src/theory/quantifiers/ematching/inst_match_generator.h [new file with mode: 0644]
src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp [new file with mode: 0644]
src/theory/quantifiers/ematching/inst_strategy_e_matching.h [new file with mode: 0644]
src/theory/quantifiers/ematching/instantiation_engine.cpp [new file with mode: 0644]
src/theory/quantifiers/ematching/instantiation_engine.h [new file with mode: 0644]
src/theory/quantifiers/ematching/trigger.cpp [new file with mode: 0644]
src/theory/quantifiers/ematching/trigger.h [new file with mode: 0644]
src/theory/quantifiers/first_order_model.cpp
src/theory/quantifiers/fmf/ambqi_builder.cpp [new file with mode: 0644]
src/theory/quantifiers/fmf/ambqi_builder.h [new file with mode: 0644]
src/theory/quantifiers/fmf/bounded_integers.cpp [new file with mode: 0644]
src/theory/quantifiers/fmf/bounded_integers.h [new file with mode: 0644]
src/theory/quantifiers/fmf/full_model_check.cpp [new file with mode: 0644]
src/theory/quantifiers/fmf/full_model_check.h [new file with mode: 0644]
src/theory/quantifiers/fmf/model_builder.cpp [new file with mode: 0644]
src/theory/quantifiers/fmf/model_builder.h [new file with mode: 0644]
src/theory/quantifiers/fmf/model_engine.cpp [new file with mode: 0644]
src/theory/quantifiers/fmf/model_engine.h [new file with mode: 0644]
src/theory/quantifiers/full_model_check.cpp [deleted file]
src/theory/quantifiers/full_model_check.h [deleted file]
src/theory/quantifiers/ho_trigger.cpp [deleted file]
src/theory/quantifiers/ho_trigger.h [deleted file]
src/theory/quantifiers/inst_match_generator.cpp [deleted file]
src/theory/quantifiers/inst_match_generator.h [deleted file]
src/theory/quantifiers/inst_strategy_cbqi.cpp [deleted file]
src/theory/quantifiers/inst_strategy_cbqi.h [deleted file]
src/theory/quantifiers/inst_strategy_e_matching.cpp [deleted file]
src/theory/quantifiers/inst_strategy_e_matching.h [deleted file]
src/theory/quantifiers/instantiate.cpp
src/theory/quantifiers/instantiation_engine.cpp [deleted file]
src/theory/quantifiers/instantiation_engine.h [deleted file]
src/theory/quantifiers/macros.cpp
src/theory/quantifiers/model_builder.cpp [deleted file]
src/theory/quantifiers/model_builder.h [deleted file]
src/theory/quantifiers/model_engine.cpp [deleted file]
src/theory/quantifiers/model_engine.h [deleted file]
src/theory/quantifiers/quant_conflict_find.cpp
src/theory/quantifiers/quantifiers_attributes.cpp
src/theory/quantifiers/quantifiers_rewriter.cpp
src/theory/quantifiers/rewrite_engine.cpp
src/theory/quantifiers/rewrite_engine.h
src/theory/quantifiers/sygus/ce_guided_conjecture.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/ce_guided_conjecture.h [new file with mode: 0644]
src/theory/quantifiers/sygus/ce_guided_instantiation.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/ce_guided_instantiation.h [new file with mode: 0644]
src/theory/quantifiers/sygus/ce_guided_single_inv.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/ce_guided_single_inv.h [new file with mode: 0644]
src/theory/quantifiers/sygus/ce_guided_single_inv_sol.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/ce_guided_single_inv_sol.h [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_explain.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_explain.h [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_grammar_cons.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_grammar_cons.h [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_grammar_norm.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_grammar_norm.h [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_grammar_red.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_grammar_red.h [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_invariance.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_invariance.h [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_pbe.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_pbe.h [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_process_conj.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/sygus_process_conj.h [new file with mode: 0644]
src/theory/quantifiers/sygus/term_database_sygus.cpp [new file with mode: 0644]
src/theory/quantifiers/sygus/term_database_sygus.h [new file with mode: 0644]
src/theory/quantifiers/sygus_explain.cpp [deleted file]
src/theory/quantifiers/sygus_explain.h [deleted file]
src/theory/quantifiers/sygus_grammar_cons.cpp [deleted file]
src/theory/quantifiers/sygus_grammar_cons.h [deleted file]
src/theory/quantifiers/sygus_grammar_norm.cpp [deleted file]
src/theory/quantifiers/sygus_grammar_norm.h [deleted file]
src/theory/quantifiers/sygus_grammar_red.cpp [deleted file]
src/theory/quantifiers/sygus_grammar_red.h [deleted file]
src/theory/quantifiers/sygus_invariance.cpp [deleted file]
src/theory/quantifiers/sygus_invariance.h [deleted file]
src/theory/quantifiers/sygus_process_conj.cpp [deleted file]
src/theory/quantifiers/sygus_process_conj.h [deleted file]
src/theory/quantifiers/sygus_sampler.h
src/theory/quantifiers/term_database.cpp
src/theory/quantifiers/term_database_sygus.cpp [deleted file]
src/theory/quantifiers/term_database_sygus.h [deleted file]
src/theory/quantifiers/theory_quantifiers.cpp
src/theory/quantifiers/trigger.cpp [deleted file]
src/theory/quantifiers/trigger.h [deleted file]
src/theory/quantifiers_engine.cpp
src/theory/theory_engine.cpp
test/unit/theory/theory_quantifiers_bv_instantiator_white.h

index 4d5c85707011b21f4915c77f5e89c6b56c957450..8e516a00dc3cdfcfe0ebec07e8d79f2e5a20f909 100644 (file)
@@ -360,34 +360,32 @@ libcvc4_la_SOURCES = \
        theory/idl/theory_idl.h \
        theory/quantifiers/alpha_equivalence.cpp \
        theory/quantifiers/alpha_equivalence.h \
-       theory/quantifiers/ambqi_builder.cpp \
-       theory/quantifiers/ambqi_builder.h \
        theory/quantifiers/anti_skolem.cpp \
        theory/quantifiers/anti_skolem.h \
-       theory/quantifiers/bounded_integers.cpp \
-       theory/quantifiers/bounded_integers.h \
        theory/quantifiers/bv_inverter.cpp \
        theory/quantifiers/bv_inverter.h \
        theory/quantifiers/candidate_generator.cpp \
        theory/quantifiers/candidate_generator.h \
-       theory/quantifiers/ce_guided_conjecture.cpp \
-       theory/quantifiers/ce_guided_conjecture.h \
-       theory/quantifiers/ce_guided_instantiation.cpp \
-       theory/quantifiers/ce_guided_instantiation.h \
-       theory/quantifiers/ce_guided_single_inv.cpp \
-       theory/quantifiers/ce_guided_single_inv.h \
-       theory/quantifiers/ce_guided_pbe.cpp \
-       theory/quantifiers/ce_guided_pbe.h \
-       theory/quantifiers/ce_guided_single_inv_sol.cpp \
-       theory/quantifiers/ce_guided_single_inv_sol.h \
-       theory/quantifiers/ceg_instantiator.cpp \
-       theory/quantifiers/ceg_instantiator.h \
-       theory/quantifiers/ceg_t_instantiator.cpp \
-       theory/quantifiers/ceg_t_instantiator.h \
+       theory/quantifiers/cegqi/ceg_instantiator.cpp \
+       theory/quantifiers/cegqi/ceg_instantiator.h \
+       theory/quantifiers/cegqi/ceg_t_instantiator.cpp \
+       theory/quantifiers/cegqi/ceg_t_instantiator.h \
+       theory/quantifiers/cegqi/inst_strategy_cbqi.cpp \
+       theory/quantifiers/cegqi/inst_strategy_cbqi.h \
        theory/quantifiers/conjecture_generator.cpp \
        theory/quantifiers/conjecture_generator.h \
        theory/quantifiers/dynamic_rewrite.cpp \
        theory/quantifiers/dynamic_rewrite.h \
+       theory/quantifiers/ematching/ho_trigger.cpp \
+       theory/quantifiers/ematching/ho_trigger.h \
+       theory/quantifiers/ematching/inst_match_generator.cpp \
+       theory/quantifiers/ematching/inst_match_generator.h \
+       theory/quantifiers/ematching/inst_strategy_e_matching.cpp \
+       theory/quantifiers/ematching/inst_strategy_e_matching.h \
+       theory/quantifiers/ematching/instantiation_engine.cpp \
+       theory/quantifiers/ematching/instantiation_engine.h \
+       theory/quantifiers/ematching/trigger.cpp \
+       theory/quantifiers/ematching/trigger.h \
        theory/quantifiers/equality_query.cpp \
        theory/quantifiers/equality_query.h \
        theory/quantifiers/equality_infer.cpp \
@@ -396,42 +394,36 @@ libcvc4_la_SOURCES = \
        theory/quantifiers/extended_rewrite.h \
        theory/quantifiers/first_order_model.cpp \
        theory/quantifiers/first_order_model.h \
-       theory/quantifiers/full_model_check.cpp \
-       theory/quantifiers/full_model_check.h \
+       theory/quantifiers/fmf/ambqi_builder.cpp \
+       theory/quantifiers/fmf/ambqi_builder.h \
+       theory/quantifiers/fmf/bounded_integers.cpp \
+       theory/quantifiers/fmf/bounded_integers.h \
+       theory/quantifiers/fmf/full_model_check.cpp \
+       theory/quantifiers/fmf/full_model_check.h \
+       theory/quantifiers/fmf/model_builder.cpp \
+       theory/quantifiers/fmf/model_builder.h \
+       theory/quantifiers/fmf/model_engine.cpp \
+       theory/quantifiers/fmf/model_engine.h \
        theory/quantifiers/fun_def_engine.cpp \
        theory/quantifiers/fun_def_engine.h \
        theory/quantifiers/fun_def_process.cpp \
        theory/quantifiers/fun_def_process.h \
        theory/quantifiers/global_negate.cpp \
        theory/quantifiers/global_negate.h \
-       theory/quantifiers/ho_trigger.cpp \
-       theory/quantifiers/ho_trigger.h \
        theory/quantifiers/instantiate.cpp \
        theory/quantifiers/instantiate.h \
        theory/quantifiers/inst_match.cpp \
        theory/quantifiers/inst_match.h \
        theory/quantifiers/inst_match_trie.cpp \
        theory/quantifiers/inst_match_trie.h \
-       theory/quantifiers/inst_match_generator.cpp \
-       theory/quantifiers/inst_match_generator.h \
        theory/quantifiers/inst_propagator.cpp \
        theory/quantifiers/inst_propagator.h \
-       theory/quantifiers/inst_strategy_cbqi.cpp \
-       theory/quantifiers/inst_strategy_cbqi.h \
-       theory/quantifiers/inst_strategy_e_matching.cpp \
-       theory/quantifiers/inst_strategy_e_matching.h \
        theory/quantifiers/inst_strategy_enumerative.cpp \
        theory/quantifiers/inst_strategy_enumerative.h \
-       theory/quantifiers/instantiation_engine.cpp \
-       theory/quantifiers/instantiation_engine.h \
        theory/quantifiers/local_theory_ext.cpp \
        theory/quantifiers/local_theory_ext.h \
        theory/quantifiers/macros.cpp \
        theory/quantifiers/macros.h \
-       theory/quantifiers/model_builder.cpp \
-       theory/quantifiers/model_builder.h \
-       theory/quantifiers/model_engine.cpp \
-       theory/quantifiers/model_engine.h \
        theory/quantifiers/quant_conflict_find.cpp \
        theory/quantifiers/quant_conflict_find.h \
        theory/quantifiers/quant_epr.cpp \
@@ -456,26 +448,36 @@ libcvc4_la_SOURCES = \
        theory/quantifiers/single_inv_partition.h \
        theory/quantifiers/skolemize.cpp \
        theory/quantifiers/skolemize.h \
-       theory/quantifiers/sygus_explain.cpp \
-       theory/quantifiers/sygus_explain.h \
-       theory/quantifiers/sygus_invariance.cpp \
-       theory/quantifiers/sygus_invariance.h \
-       theory/quantifiers/sygus_grammar_cons.cpp \
-       theory/quantifiers/sygus_grammar_cons.h \
-       theory/quantifiers/sygus_grammar_norm.cpp \
-       theory/quantifiers/sygus_grammar_norm.h \
-       theory/quantifiers/sygus_grammar_red.cpp \
-       theory/quantifiers/sygus_grammar_red.h \
-       theory/quantifiers/sygus_process_conj.cpp \
-       theory/quantifiers/sygus_process_conj.h \
+       theory/quantifiers/sygus/ce_guided_conjecture.cpp \
+       theory/quantifiers/sygus/ce_guided_conjecture.h \
+       theory/quantifiers/sygus/ce_guided_instantiation.cpp \
+       theory/quantifiers/sygus/ce_guided_instantiation.h \
+       theory/quantifiers/sygus/ce_guided_single_inv.cpp \
+       theory/quantifiers/sygus/ce_guided_single_inv.h \
+       theory/quantifiers/sygus/sygus_pbe.cpp \
+       theory/quantifiers/sygus/sygus_pbe.h \
+       theory/quantifiers/sygus/ce_guided_single_inv_sol.cpp \
+       theory/quantifiers/sygus/ce_guided_single_inv_sol.h \
+       theory/quantifiers/sygus/sygus_explain.cpp \
+       theory/quantifiers/sygus/sygus_explain.h \
+       theory/quantifiers/sygus/sygus_invariance.cpp \
+       theory/quantifiers/sygus/sygus_invariance.h \
+       theory/quantifiers/sygus/sygus_grammar_cons.cpp \
+       theory/quantifiers/sygus/sygus_grammar_cons.h \
+       theory/quantifiers/sygus/sygus_grammar_norm.cpp \
+       theory/quantifiers/sygus/sygus_grammar_norm.h \
+       theory/quantifiers/sygus/sygus_grammar_red.cpp \
+       theory/quantifiers/sygus/sygus_grammar_red.h \
+       theory/quantifiers/sygus/sygus_process_conj.cpp \
+       theory/quantifiers/sygus/sygus_process_conj.h \
+       theory/quantifiers/sygus/term_database_sygus.cpp \
+       theory/quantifiers/sygus/term_database_sygus.h \
        theory/quantifiers/sygus_sampler.cpp \
        theory/quantifiers/sygus_sampler.h \
        theory/quantifiers/symmetry_breaking.cpp \
        theory/quantifiers/symmetry_breaking.h \
        theory/quantifiers/term_database.cpp \
        theory/quantifiers/term_database.h \
-       theory/quantifiers/term_database_sygus.cpp \
-       theory/quantifiers/term_database_sygus.h \
        theory/quantifiers/term_enumeration.cpp \
        theory/quantifiers/term_enumeration.h \
        theory/quantifiers/term_util.cpp \
@@ -483,8 +485,6 @@ libcvc4_la_SOURCES = \
        theory/quantifiers/theory_quantifiers.cpp \
        theory/quantifiers/theory_quantifiers.h \
        theory/quantifiers/theory_quantifiers_type_rules.h \
-       theory/quantifiers/trigger.cpp \
-       theory/quantifiers/trigger.h \
        theory/sep/theory_sep.cpp \
        theory/sep/theory_sep.h \
        theory/sep/theory_sep_rewriter.cpp \
index 7e2f6c38c40805f09ff245a364a4636e1687aa18..8176ba3e9401a570746f42657ad11dc143555a93 100644 (file)
@@ -93,7 +93,7 @@
 #include "theory/bv/bvintropow2.h"
 #include "theory/bv/theory_bv_rewriter.h"
 #include "theory/logic_info.h"
-#include "theory/quantifiers/ce_guided_instantiation.h"
+#include "theory/quantifiers/sygus/ce_guided_instantiation.h"
 #include "theory/quantifiers/fun_def_process.h"
 #include "theory/quantifiers/global_negate.h"
 #include "theory/quantifiers/macros.h"
index fc0673d21d2c0fe5765107cd0a474284b8f5bdaf..d7706201dc9e6708d355930705eaabbbb780746b 100644 (file)
@@ -64,7 +64,7 @@
 #include "theory/arith/simplex.h"
 #include "theory/arith/theory_arith.h"
 #include "theory/ite_utilities.h"
-#include "theory/quantifiers/bounded_integers.h"
+#include "theory/quantifiers/fmf/bounded_integers.h"
 #include "theory/rewriter.h"
 #include "theory/theory_model.h"
 #include "theory/valuation.h"
index 91400479f4ff9001707150079fbf61dc015b8590..556b07f7f4b4b84da142d739901778f561b919e7 100644 (file)
@@ -22,9 +22,9 @@
 #include "printer/printer.h"
 #include "theory/datatypes/datatypes_rewriter.h"
 #include "theory/datatypes/theory_datatypes.h"
-#include "theory/quantifiers/ce_guided_conjecture.h"
-#include "theory/quantifiers/sygus_explain.h"
-#include "theory/quantifiers/term_database_sygus.h"
+#include "theory/quantifiers/sygus/ce_guided_conjecture.h"
+#include "theory/quantifiers/sygus/sygus_explain.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
 #include "theory/quantifiers/term_util.h"
 #include "theory/theory_model.h"
 
index ff2d2a873b23a0f9702c0fdfe929dc897db1821e..2c1f85deb2c60cc373a1529b959cc51ca4829082 100644 (file)
@@ -29,7 +29,7 @@
 #include "context/context.h"
 #include "expr/datatype.h"
 #include "expr/node.h"
-#include "theory/quantifiers/ce_guided_conjecture.h"
+#include "theory/quantifiers/sygus/ce_guided_conjecture.h"
 #include "theory/quantifiers/sygus_sampler.h"
 #include "theory/quantifiers/term_database.h"
 
diff --git a/src/theory/quantifiers/ambqi_builder.cpp b/src/theory/quantifiers/ambqi_builder.cpp
deleted file mode 100644 (file)
index 0a6df7d..0000000
+++ /dev/null
@@ -1,968 +0,0 @@
-/*********************                                                        */
-/*! \file ambqi_builder.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Morgan Deters, Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of abstract MBQI builder
- **/
-
-#include "theory/quantifiers/ambqi_builder.h"
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-
-using namespace std;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-
-void AbsDef::construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth ) {
-  d_def.clear();
-  Assert( !fapps.empty() );
-  if( depth==fapps[0].getNumChildren() ){
-    //if( fapps.size()>1 ){
-    //  for( unsigned i=0; i<fapps.size(); i++ ){
-    //    std::cout << "...." << fapps[i] << " -> " << m->getRepresentativeId( fapps[i] ) << std::endl;
-    //  }
-    //}
-    //get representative in model for this term
-    d_value = m->getRepresentativeId( fapps[0] );
-    Assert( d_value!=val_none );
-  }else{
-    TypeNode tn = fapps[0][depth].getType();
-    std::map< unsigned, std::vector< TNode > > fapp_child;
-
-    //partition based on evaluations of fapps[1][depth]....fapps[n][depth]
-    for( unsigned i=0; i<fapps.size(); i++ ){
-      unsigned r = m->getRepresentativeId( fapps[i][depth] );
-      Assert( r < 32 );
-      fapp_child[r].push_back( fapps[i] );
-    }
-
-    //do completion
-    std::map< unsigned, unsigned > fapp_child_index;
-    unsigned def = m->d_domain[ tn ];
-    unsigned minSize = fapp_child.begin()->second.size();
-    unsigned minSizeIndex = fapp_child.begin()->first;
-    for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){
-      fapp_child_index[it->first] = ( 1 << it->first );
-      def = def & ~( 1 << it->first );
-      if( it->second.size()<minSize ){
-        minSize = it->second.size();
-        minSizeIndex = it->first;
-      }
-    }
-    fapp_child_index[minSizeIndex] |= def;
-    d_default = fapp_child_index[minSizeIndex];
-
-    //construct children
-    for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){
-      Trace("abs-model-debug") << "Construct " << it->first << " : " << fapp_child_index[it->first] << " : ";
-      const RepSet* rs = m->getRepSet();
-      debugPrintUInt("abs-model-debug",
-                     rs->getNumRepresentatives(tn),
-                     fapp_child_index[it->first]);
-      Trace("abs-model-debug") << " : " << it->second.size() << " terms." << std::endl;
-      d_def[fapp_child_index[it->first]].construct_func( m, it->second, depth+1 );
-    }
-  }
-}
-
-void AbsDef::simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth ) {
-  if( d_value==val_none && !d_def.empty() ){
-    //process the default
-    std::map< unsigned, AbsDef >::iterator defd = d_def.find( d_default );
-    Assert( defd!=d_def.end() );
-    unsigned newDef = d_default;
-    std::vector< unsigned > to_erase;
-    defd->second.simplify( m, q, n, depth+1 );
-    int defVal = defd->second.d_value;
-    bool isConstant = ( defVal!=val_none );
-    //process each child
-    for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
-      if( it->first!=d_default ){
-        it->second.simplify( m, q, n, depth+1 );
-        if( it->second.d_value==defVal && it->second.d_value!=val_none ){
-          newDef = newDef | it->first;
-          to_erase.push_back( it->first );
-        }else{
-          isConstant = false;
-        }
-      }
-    }
-    if( !to_erase.empty() ){
-      //erase old default
-      int defVal = defd->second.d_value;
-      d_def.erase( d_default );
-      //set new default
-      d_default = newDef;
-      d_def[d_default].construct_def_entry( m, q, n, defVal, depth+1 );
-      //erase redundant entries
-      for( unsigned i=0; i<to_erase.size(); i++ ){
-        d_def.erase( to_erase[i] );
-      }
-    }
-    //if constant, propagate the value upwards
-    if( isConstant ){
-      d_value = defVal;
-    }else{
-      d_value = val_none;
-    }
-  }
-}
-
-void AbsDef::debugPrintUInt( const char * c, unsigned dSize, unsigned u ) const{
-  for( unsigned i=0; i<dSize; i++ ){
-    Trace(c) << ( ( u & ( 1 << i ) )!=0 ? "1" : "0");
-  }
-  //Trace(c) << "(";
-  //for( unsigned i=0; i<32; i++ ){
-  //  Trace(c) << ( ( u & ( 1 << i ) )!=0 ? "1" : "0");
-  //}
-  //Trace(c) << ")";
-}
-
-void AbsDef::debugPrint( const char * c, FirstOrderModelAbs * m, TNode f, unsigned depth ) const{
-  if( Trace.isOn(c) ){
-    if( depth==f.getNumChildren() ){
-      for( unsigned i=0; i<depth; i++ ){ Trace(c) << "  ";}
-      Trace(c) << "V[" << d_value << "]" << std::endl;
-    }else{
-      TypeNode tn = f[depth].getType();
-      const RepSet* rs = m->getRepSet();
-      unsigned dSize = rs->getNumRepresentatives(tn);
-      Assert( dSize<32 );
-      for( std::map< unsigned, AbsDef >::const_iterator it = d_def.begin(); it != d_def.end(); ++it ){
-        for( unsigned i=0; i<depth; i++ ){ Trace(c) << "  ";}
-        debugPrintUInt( c, dSize, it->first );
-        if( it->first==d_default ){
-          Trace(c) << "*";
-        }
-        if( it->second.d_value!=val_none ){
-          Trace(c) << " -> V[" << it->second.d_value << "]";
-        }
-        Trace(c) << std::endl;
-        it->second.debugPrint( c, m, f, depth+1 );
-      }
-    }
-  }
-}
-
-bool AbsDef::addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth ) {
-  if( inst==0 || !options::fmfOneInstPerRound() ){
-    if( d_value==1 ){
-      //instantiations are all true : ignore this
-      return true;
-    }else{
-      if( depth==q[0].getNumChildren() ){
-        if (qe->getInstantiate()->addInstantiation(q, terms, true))
-        {
-          Trace("ambqi-inst-debug") << "-> Added instantiation." << std::endl;
-          inst++;
-          return true;
-        }else{
-          Trace("ambqi-inst-debug") << "-> Failed to add instantiation." << std::endl;
-          //we are incomplete
-          return false;
-        }
-      }else{
-        bool osuccess = true;
-        TypeNode tn = m->getVariable( q, depth ).getType();
-        for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
-          //get witness term
-          unsigned index = 0;
-          bool success;
-          do {
-            success = false;
-            index = getId( it->first, index );
-            if( index<32 ){
-              const RepSet* rs = m->getRepSet();
-              Assert(index < rs->getNumRepresentatives(tn));
-              terms[m->d_var_order[q][depth]] =
-                  rs->getRepresentative(tn, index);
-              if( !it->second.addInstantiations( m, qe, q, terms, inst, depth+1 ) && inst==0 ){
-                //if we are incomplete, and have not yet added an instantiation, keep trying
-                index++;
-                Trace("ambqi-inst-debug") << "At depth " << depth << ", failed branch, no instantiations and incomplete, increment index : " << index << std::endl;
-              }else{
-                success = true;
-              }
-            }
-          }while( !qe->inConflict() && !success && index<32 );
-          //mark if we are incomplete
-          osuccess = osuccess && success;
-        }
-        return osuccess;
-      }
-    }
-  }else{
-    return true;
-  }
-}
-
-void AbsDef::construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth ) {
-  if( depth==entry.size() ){
-    d_value = v;
-  }else{
-    d_def[entry[depth]].construct_entry( entry, entry_def, v, depth+1 );
-    if( entry_def[depth] ){
-      d_default = entry[depth];
-    }
-  }
-}
-
-void AbsDef::get_defs( unsigned u, std::vector< AbsDef * >& defs ) {
-  for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
-    if( ( u & it->first )!=0 ){
-      Assert( (u & it->first)==u );
-      defs.push_back( &it->second );
-    }
-  }
-}
-
-void AbsDef::construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth ) {
-  if( depth==q[0].getNumChildren() ){
-    Assert( defs.size()==1 );
-    d_value = defs[0]->d_value;
-  }else{
-    TypeNode tn = m->getVariable( q, depth ).getType();
-    unsigned def = m->d_domain[tn];
-    for( unsigned i=0; i<defs.size(); i++ ){
-      //process each simple child
-      for( std::map< unsigned, AbsDef >::iterator itd = defs[i]->d_def.begin(); itd != defs[i]->d_def.end(); ++itd ){
-        if( isSimple( itd->first ) && ( def & itd->first )!=0 ){
-          def &= ~( itd->first );
-          //process this value
-          std::vector< AbsDef * > cdefs;
-          for( unsigned j=0; j<defs.size(); j++ ){
-            defs[j]->get_defs( itd->first, cdefs );
-          }
-          d_def[itd->first].construct_normalize( m, q, cdefs, depth+1 );
-          if( def==0 ){
-            d_default = itd->first;
-            break;
-          }
-        }
-      }
-      if( def==0 ){
-        break;
-      }
-    }
-    if( def!=0 ){
-      d_default = def;
-      //process the default
-      std::vector< AbsDef * > cdefs;
-      for( unsigned j=0; j<defs.size(); j++ ){
-        defs[j]->get_defs( d_default, cdefs );
-      }
-      d_def[d_default].construct_normalize( m, q, cdefs, depth+1 );
-    }
-  }
-}
-
-void AbsDef::construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth ) {
-  d_value = v;
-  if( depth<n.getNumChildren() ){
-    TypeNode tn = q.isNull() ? n[depth].getType() : m->getVariable( q, depth ).getType();
-    unsigned dom = m->d_domain[tn] ;
-    d_def[dom].construct_def_entry( m, q, n, v, depth+1 );
-    d_default = dom;
-  }
-}
-
-void AbsDef::apply_ucompose( FirstOrderModelAbs * m, TNode q,
-                             std::vector< unsigned >& entry, std::vector< bool >& entry_def,
-                             std::vector< int >& terms, std::map< unsigned, int >& vchildren,
-                             AbsDef * a, unsigned depth ) {
-  if( depth==terms.size() ){
-    if( Trace.isOn("ambqi-check-debug2") ){
-      Trace("ambqi-check-debug2") << "Add entry ( ";
-      const RepSet* rs = m->getRepSet();
-      for( unsigned i=0; i<entry.size(); i++ ){
-        unsigned dSize =
-            rs->getNumRepresentatives(m->getVariable(q, i).getType());
-        debugPrintUInt( "ambqi-check-debug2", dSize, entry[i] );
-        Trace("ambqi-check-debug2") << " ";
-      }
-      Trace("ambqi-check-debug2") << ")" << std::endl;
-    }
-    a->construct_entry( entry, entry_def, d_value );
-  }else{
-    unsigned id;
-    if( terms[depth]==val_none ){
-      //a variable
-      std::map< unsigned, int >::iterator itv = vchildren.find( depth );
-      Assert( itv!=vchildren.end() );
-      unsigned prev_v = entry[itv->second];
-      bool prev_vd = entry_def[itv->second];
-      for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
-        entry[itv->second] = it->first & prev_v;
-        entry_def[itv->second] = ( it->first==d_default ) && prev_vd;
-        if( entry[itv->second]!=0 ){
-          it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
-        }
-      }
-      entry[itv->second] = prev_v;
-      entry_def[itv->second] = prev_vd;
-    }else{
-      id = (unsigned)terms[depth];
-      Assert( id<32 );
-      unsigned fid = 1 << id;
-      std::map< unsigned, AbsDef >::iterator it = d_def.find( fid );
-      if( it!=d_def.end() ){
-        it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
-      }else{
-        d_def[d_default].apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
-      }
-    }
-  }
-}
-
-void AbsDef::construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth ) {
-  if( depth==q[0].getNumChildren() ){
-    Assert( currv!=val_none );
-    d_value = currv;
-  }else{
-    TypeNode tn = m->getVariable( q, depth ).getType();
-    unsigned dom = m->d_domain[tn];
-    int vindex = depth==v1 ? 0 : ( depth==v2 ? 1 : val_none );
-    if( vindex==val_none ){
-      d_def[dom].construct_var_eq( m, q, v1, v2, curr, currv, depth+1 );
-      d_default = dom;
-    }else{
-      Assert( currv==val_none );
-      if( curr==val_none ){
-        unsigned numReps = m->getRepSet()->getNumRepresentatives(tn);
-        Assert( numReps < 32 );
-        for( unsigned i=0; i<numReps; i++ ){
-          curr = 1 << i;
-          d_def[curr].construct_var_eq( m, q, v1, v2, curr, currv, depth+1 );
-        }
-        d_default = curr;
-      }else{
-        d_def[curr].construct_var_eq( m, q, v1, v2, curr, 1, depth+1 );
-        dom = dom & ~curr;
-        d_def[dom].construct_var_eq( m, q, v1, v2, curr, 0, depth+1 );
-        d_default = dom;
-      }
-    }
-  }
-}
-
-void AbsDef::construct_var( FirstOrderModelAbs * m, TNode q, unsigned v, int currv, unsigned depth ) {
-  if( depth==q[0].getNumChildren() ){
-    Assert( currv!=val_none );
-    d_value = currv;
-  }else{
-    TypeNode tn = m->getVariable( q, depth ).getType();
-    if( v==depth ){
-      unsigned numReps = m->getRepSet()->getNumRepresentatives(tn);
-      Assert( numReps>0 && numReps < 32 );
-      for( unsigned i=0; i<numReps; i++ ){
-        d_def[ 1 << i ].construct_var( m, q, v, i, depth+1 );
-      }
-      d_default = 1 << (numReps - 1);
-    }else{
-      unsigned dom = m->d_domain[tn];
-      d_def[dom].construct_var( m, q, v, currv, depth+1 );
-      d_default = dom;
-    }
-  }
-}
-
-void AbsDef::construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
-                                std::map< unsigned, AbsDef * >& children,
-                                std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
-                                std::vector< unsigned >& entry, std::vector< bool >& entry_def ) {
-  const RepSet* rs = m->getRepSet();
-  if( n.getKind()==OR || n.getKind()==AND ){
-    // short circuiting
-    for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
-      if( ( it->second->d_value==0 && n.getKind()==AND ) ||
-          ( it->second->d_value==1 && n.getKind()==OR ) ){
-        //std::cout << "Short circuit " << it->second->d_value << " " << entry.size() << "/" << q[0].getNumChildren() << std::endl;
-        unsigned count = q[0].getNumChildren() - entry.size();
-        for( unsigned i=0; i<count; i++ ){
-          entry.push_back( m->d_domain[m->getVariable( q, entry.size() ).getType()] );
-          entry_def.push_back( true );
-        }
-        construct_entry( entry, entry_def, it->second->d_value );
-        for( unsigned i=0; i<count; i++ ){
-          entry.pop_back();
-          entry_def.pop_back();
-        }
-        return;
-      }
-    }
-  }
-  if( entry.size()==q[0].getNumChildren() ){
-    if( f ){
-      if( Trace.isOn("ambqi-check-debug2") ){
-        for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
-        Trace("ambqi-check-debug2") << "Evaluate uninterpreted function entry..." << std::endl;
-      }
-      //we are composing with an uninterpreted function
-      std::vector< int > values;
-      values.resize( n.getNumChildren(), val_none );
-      for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
-        values[it->first] = it->second->d_value;
-      }
-      for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){
-        values[it->first] = it->second;
-      }
-      //look up value(s)
-      f->apply_ucompose( m, q, entry, entry_def, values, vchildren, this );
-    }else{
-      bool incomplete = false;
-      //we are composing with an interpreted function
-      std::vector< TNode > values;
-      values.resize( n.getNumChildren(), TNode::null() );
-      for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
-        Trace("ambqi-check-debug2") << "composite : " << it->first << " : " << it->second->d_value;
-        if( it->second->d_value>=0 ){
-          if (it->second->d_value
-              >= (int)rs->getNumRepresentatives(n[it->first].getType()))
-          {
-            std::cout << it->second->d_value << " " << n[it->first] << " "
-                      << n[it->first].getType() << " "
-                      << rs->getNumRepresentatives(n[it->first].getType())
-                      << std::endl;
-          }
-          Assert(it->second->d_value
-                 < (int)rs->getNumRepresentatives(n[it->first].getType()));
-          values[it->first] = rs->getRepresentative(n[it->first].getType(),
-                                                    it->second->d_value);
-        }else{
-          incomplete = true;
-        }
-        Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl;
-      }
-      for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){
-        Trace("ambqi-check-debug2") << "   basic :  " << it->first << " : " << it->second;
-        if( it->second>=0 ){
-          Assert(it->second
-                 < (int)rs->getNumRepresentatives(n[it->first].getType()));
-          values[it->first] =
-              rs->getRepresentative(n[it->first].getType(), it->second);
-        }else{
-          incomplete = true;
-        }
-        Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl;
-      }
-      Assert( vchildren.empty() );
-      if( incomplete ){
-        Trace("ambqi-check-debug2") << "Construct incomplete entry." << std::endl;
-
-        //if a child is unknown, we must return unknown
-        construct_entry( entry, entry_def, val_unk );
-      }else{
-        if( Trace.isOn("ambqi-check-debug2") ){
-          for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
-          Trace("ambqi-check-debug2") << "Evaluate interpreted function entry ( ";
-          for( unsigned i=0; i<values.size(); i++ ){
-            Assert( !values[i].isNull() );
-            Trace("ambqi-check-debug2") << values[i] << " ";
-          }
-          Trace("ambqi-check-debug2") << ")..." << std::endl;
-        }
-        //evaluate
-        Node vv = NodeManager::currentNM()->mkNode( n.getKind(), values );
-        vv = Rewriter::rewrite( vv );
-        int v = m->getRepresentativeId( vv );
-        construct_entry( entry, entry_def, v );
-      }
-    }
-  }else{
-    //take product of arguments
-    TypeNode tn = m->getVariable( q, entry.size() ).getType();
-    Assert( m->isValidType( tn ) );
-    unsigned def = m->d_domain[tn];
-    if( Trace.isOn("ambqi-check-debug2") ){
-      for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
-      Trace("ambqi-check-debug2") << "Take product of arguments" << std::endl;
-    }
-    for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
-      Assert( it->second!=NULL );
-      //process each child
-      for( std::map< unsigned, AbsDef >::iterator itd = it->second->d_def.begin(); itd != it->second->d_def.end(); ++itd ){
-        if( itd->first!=it->second->d_default && ( def & itd->first )!=0 ){
-          def &= ~( itd->first );
-          //process this value
-          std::map< unsigned, AbsDef * > cchildren;
-          for( std::map< unsigned, AbsDef * >::iterator it2 = children.begin(); it2 != children.end(); ++it2 ){
-            Assert( it2->second!=NULL );
-            std::map< unsigned, AbsDef >::iterator itdf = it2->second->d_def.find( itd->first );
-            if( itdf!=it2->second->d_def.end() ){
-              cchildren[it2->first] = &itdf->second;
-            }else{
-              Assert( it2->second->getDefault()!=NULL );
-              cchildren[it2->first] = it2->second->getDefault();
-            }
-          }
-          if( Trace.isOn("ambqi-check-debug2") ){
-            for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
-            Trace("ambqi-check-debug2") << "...process : ";
-            debugPrintUInt("ambqi-check-debug2",
-                           rs->getNumRepresentatives(tn),
-                           itd->first);
-            Trace("ambqi-check-debug2") << " " << children.size() << " " << cchildren.size() << std::endl;
-          }
-          entry.push_back( itd->first );
-          entry_def.push_back( def==0 );
-          construct_compose( m, q, n, f, cchildren, bchildren, vchildren, entry, entry_def );
-          entry_def.pop_back();
-          entry.pop_back();
-          if( def==0 ){
-            break;
-          }
-        }
-      }
-      if( def==0 ){
-        break;
-      }
-    }
-    if( def!=0 ){
-      if( Trace.isOn("ambqi-check-debug2") ){
-        for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
-        Trace("ambqi-check-debug2") << "Make default argument" << std::endl;
-      }
-      std::map< unsigned, AbsDef * > cdchildren;
-      for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
-        Assert( it->second->getDefault()!=NULL );
-        cdchildren[it->first] = it->second->getDefault();
-      }
-      if( Trace.isOn("ambqi-check-debug2") ){
-        for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
-        Trace("ambqi-check-debug2") << "...process default : ";
-        debugPrintUInt(
-            "ambqi-check-debug2", rs->getNumRepresentatives(tn), def);
-        Trace("ambqi-check-debug2") << " " << children.size() << " " << cdchildren.size() << std::endl;
-      }
-      entry.push_back( def );
-      entry_def.push_back( true );
-      construct_compose( m, q, n, f, cdchildren, bchildren, vchildren, entry, entry_def );
-      entry_def.pop_back();
-      entry.pop_back();
-    }
-  }
-}
-
-bool AbsDef::construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
-                        std::map< unsigned, AbsDef * >& children,
-                        std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
-                        int varChCount ) {
-  if( Trace.isOn("ambqi-check-debug3") ){
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      Trace("ambqi-check-debug3") << i << " : ";
-      Trace("ambqi-check-debug3") << ((children.find( i )!=children.end()) ? "X" : ".");
-      if( bchildren.find( i )!=bchildren.end() ){
-        Trace("ambqi-check-debug3") << bchildren[i];
-      }else{
-        Trace("ambqi-check-debug3") << ".";
-      }
-      if( vchildren.find( i )!=vchildren.end() ){
-        Trace("ambqi-check-debug3") << vchildren[i];
-      }else{
-        Trace("ambqi-check-debug3") << ".";
-      }
-      Trace("ambqi-check-debug3") << std::endl;
-    }
-    Trace("ambqi-check-debug3") << "varChCount : " << varChCount << std::endl;
-  }
-  if( varChCount==0 || f ){
-    //short-circuit
-    if( n.getKind()==AND || n.getKind()==OR ){
-      for( std::map< unsigned, int >::iterator it = bchildren.begin(); it !=bchildren.end(); ++it ){
-        if( ( it->second==0 && n.getKind()==AND ) ||
-            ( it->second==1 && n.getKind()==OR ) ){
-          construct_def_entry( m, q, q[0], it->second );
-          return true;
-        }
-      }
-    }
-    Trace("ambqi-check-debug2") << "Construct compose..." << std::endl;
-    std::vector< unsigned > entry;
-    std::vector< bool > entry_def;
-    if( f && varChCount>0 ){
-      AbsDef unorm;
-      unorm.construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
-      //normalize
-      std::vector< AbsDef* > defs;
-      defs.push_back( &unorm );
-      construct_normalize( m, q, defs );
-    }else{
-      construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
-    }
-    Assert( is_normalized() );
-    //if( !is_normalized() ){
-    //  std::cout << "NON NORMALIZED DEFINITION" << std::endl;
-    //  exit( 10 );
-    //}
-    return true;
-  }else if( varChCount==1 && ( n.getKind()==EQUAL && !n[0].getType().isBoolean() ) ){
-    Trace("ambqi-check-debug2") << "Expand variable child..." << std::endl;
-    //expand the variable based on its finite domain
-    AbsDef a;
-    a.construct_var( m, q, vchildren.begin()->second, val_none );
-    children[vchildren.begin()->first] = &a;
-    vchildren.clear();
-    std::vector< unsigned > entry;
-    std::vector< bool > entry_def;
-    Trace("ambqi-check-debug2") << "Construct compose with variable..." << std::endl;
-    construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
-    return true;
-  }else if( varChCount==2 && ( n.getKind()==EQUAL && !n[0].getType().isBoolean() ) ){
-    Trace("ambqi-check-debug2") << "Construct variable equality..." << std::endl;
-    //efficient expansion of the equality
-    construct_var_eq( m, q, vchildren[0], vchildren[1], val_none, val_none );
-    return true;
-  }else{
-    return false;
-  }
-}
-
-void AbsDef::negate() {
-  for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
-    it->second.negate();
-  }
-  if( d_value==0 ){
-    d_value = 1;
-  }else if( d_value==1 ){
-    d_value = 0;
-  }
-}
-
-Node AbsDef::getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth ) {
-  const RepSet* rs = m->getRepSet();
-  if( depth==vars.size() ){
-    TypeNode tn = op.getType();
-    if( tn.getNumChildren()>0 ){
-      tn = tn[tn.getNumChildren() - 1];
-    }
-    if( d_value>=0 ){
-      Assert(d_value < (int)rs->getNumRepresentatives(tn));
-      if( tn.isBoolean() ){
-        return NodeManager::currentNM()->mkConst( d_value==1 );
-      }else{
-        return rs->getRepresentative(tn, d_value);
-      }
-    }else{
-      return Node::null();
-    }
-  }else{
-    TypeNode tn = vars[depth].getType();
-    Node curr;
-    curr = d_def[d_default].getFunctionValue( m, op, vars, depth+1 );
-    for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
-      if( it->first!=d_default ){
-        unsigned id = getId( it->first );
-        Assert(id < rs->getNumRepresentatives(tn));
-        TNode n = rs->getRepresentative(tn, id);
-        Node fv = it->second.getFunctionValue( m, op, vars, depth+1 );
-        if( !curr.isNull() && !fv.isNull() ){
-          curr = NodeManager::currentNM()->mkNode( ITE, vars[depth].eqNode( n ), fv, curr );
-        }else{
-          curr = Node::null();
-        }
-      }
-    }
-    return curr;
-  }
-}
-
-bool AbsDef::isSimple( unsigned n ) {
-  return (n & (n - 1))==0;
-}
-
-unsigned AbsDef::getId( unsigned n, unsigned start, unsigned end ) {
-  Assert( n!=0 );
-  while( (n & ( 1 << start )) == 0 ){
-    start++;
-    if( start==end ){
-      return start;
-    }
-  }
-  return start;
-}
-
-Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< Node >& args ) {
-  std::vector< unsigned > iargs;
-  for( unsigned i=0; i<args.size(); i++ ){
-    unsigned v = 1 << m->getRepresentativeId( args[i] );
-    iargs.push_back( v );
-  }
-  return evaluate( m, retTyp, iargs, 0 );
-}
-
-Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< unsigned >& iargs, unsigned depth ) {
-  if( d_value!=val_none ){
-    if( d_value==val_unk ){
-      return Node::null();
-    }else{
-      const RepSet* rs = m->getRepSet();
-      Assert(d_value >= 0 && d_value < (int)rs->getNumRepresentatives(retTyp));
-      return rs->getRepresentative(retTyp, d_value);
-    }
-  }else{
-    std::map< unsigned, AbsDef >::iterator it = d_def.find( iargs[depth] );
-    if( it==d_def.end() ){
-      return d_def[d_default].evaluate( m, retTyp, iargs, depth+1 );
-    }else{
-      return it->second.evaluate( m, retTyp, iargs, depth+1 );
-    }
-  }
-}
-
-bool AbsDef::is_normalized() {
-  for( std::map< unsigned, AbsDef >::iterator it1 = d_def.begin(); it1 != d_def.end(); ++it1 ){
-    if( !it1->second.is_normalized() ){
-      return false;
-    }
-    for( std::map< unsigned, AbsDef >::iterator it2 = d_def.begin(); it2 != d_def.end(); ++it2 ){
-      if( it1->first!=it2->first && (( it1->first & it2->first )!=0) ){
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-AbsMbqiBuilder::AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe ) :
-QModelBuilder( c, qe ){
-  d_true = NodeManager::currentNM()->mkConst( true );
-  d_false = NodeManager::currentNM()->mkConst( false );
-}
-
-
-//------------------------model construction----------------------------
-
-bool AbsMbqiBuilder::processBuildModel(TheoryModel* m) {
-  Trace("ambqi-debug") << "process build model " << std::endl;
-  FirstOrderModel* f = (FirstOrderModel*)m;
-  FirstOrderModelAbs* fm = f->asFirstOrderModelAbs();
-  RepSet* rs = m->getRepSetPtr();
-  fm->initialize();
-  //process representatives
-  fm->d_rep_id.clear();
-  fm->d_domain.clear();
-
-  //initialize boolean sort
-  TypeNode b = d_true.getType();
-  rs->d_type_reps[b].clear();
-  rs->d_type_reps[b].push_back(d_false);
-  rs->d_type_reps[b].push_back(d_true);
-  fm->d_rep_id[d_false] = 0;
-  fm->d_rep_id[d_true] = 1;
-
-  //initialize unintpreted sorts
-  Trace("ambqi-model") << std::endl << "Making representatives..." << std::endl;
-  for (std::map<TypeNode, std::vector<Node> >::iterator it =
-           rs->d_type_reps.begin();
-       it != rs->d_type_reps.end();
-       ++it)
-  {
-    if( it->first.isSort() ){
-      Assert( !it->second.empty() );
-      //set the domain
-      fm->d_domain[it->first] = 0;
-      Trace("ambqi-model") << "Representatives for " << it->first << " : " << std::endl;
-      for( unsigned i=0; i<it->second.size(); i++ ){
-        if( i<32 ){
-          fm->d_domain[it->first] |= ( 1 << i );
-        }
-        Trace("ambqi-model") << i << " : " << it->second[i] << std::endl;
-        fm->d_rep_id[it->second[i]] = i;
-      }
-      if( it->second.size()>=32 ){
-        fm->d_domain.erase( it->first );
-      }
-    }
-  }
-
-  Trace("ambqi-model") << std::endl << "Making function definitions..." << std::endl;
-  //construct the models for functions
-  for( std::map<Node, AbsDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
-    Node f = it->first;
-    Trace("ambqi-model-debug") << "Building Model for " << f << std::endl;
-    //reset the model
-    it->second->clear();
-    //get all (non-redundant) f-applications
-    std::vector< TNode > fapps;
-    Trace("ambqi-model-debug") << "Initial terms: " << std::endl;
-    std::map< Node, std::vector< Node > >::iterator itut = fm->d_uf_terms.find( f );
-    if( itut!=fm->d_uf_terms.end() ){
-      for( size_t i=0; i<itut->second.size(); i++ ){
-        Node n = itut->second[i];
-        // only consider unique up to congruence (in model equality engine)?
-        Trace("ambqi-model-debug") << "  " << n << " -> " << fm->getRepresentativeId( n ) << std::endl;
-        fapps.push_back( n );
-      }
-    }
-    if( fapps.empty() ){
-      //choose arbitrary value
-      Node mbt = fm->getModelBasisOpTerm(f);
-      Trace("ambqi-model-debug") << "Initial terms empty, add " << mbt << std::endl;
-      fapps.push_back( mbt );
-    }
-    bool fValid = true;
-    for( unsigned i=0; i<fapps[0].getNumChildren(); i++ ){
-      if( fm->d_domain.find( fapps[0][i].getType() )==fm->d_domain.end() ){
-        Trace("ambqi-model") << "Interpretation of " << f << " is not valid.";
-        Trace("ambqi-model") << " (domain for " << fapps[0][i].getType() << " is too large)." << std::endl;
-        fValid = false;
-        break;
-      }
-    }
-    fm->d_models_valid[f] = fValid;
-    if( fValid ){
-      //construct the ambqi model
-      it->second->construct_func( fm, fapps );
-      Trace("ambqi-model-debug") << "Interpretation of " << f << " : " << std::endl;
-      it->second->debugPrint("ambqi-model-debug", fm, fapps[0] );
-      Trace("ambqi-model-debug") << "Simplifying " << f << "..." << std::endl;
-      it->second->simplify( fm, TNode::null(), fapps[0] );
-      Trace("ambqi-model") << "(Simplified) interpretation of " << f << " : " << std::endl;
-      it->second->debugPrint("ambqi-model", fm, fapps[0] );
-
-/*
-      if( Debug.isOn("ambqi-model-debug") ){
-        for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
-          Node e = it->second->evaluate_n( fm, fm->d_uf_terms[f][i] );
-          Debug("ambqi-model-debug") << fm->d_uf_terms[f][i] << " evaluates to " << e << std::endl;
-          Assert( fm->areEqual( e, fm->d_uf_terms[f][i] ) );
-        }
-      }
-*/
-    }
-  }
-  Trace("ambqi-model") << "Construct model representation..." << std::endl;
-  //make function values
-  for( std::map<Node, AbsDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
-    if( it->first.getType().getNumChildren()>1 ){
-      Trace("ambqi-model") << "Construct for " << it->first << "..." << std::endl;
-      Node f_def = fm->getFunctionValue( it->first, "$x" );
-      m->assignFunctionDefinition( it->first, f_def );
-    }
-  }
-  Assert( d_addedLemmas==0 );
-  return TheoryEngineModelBuilder::processBuildModel( m );
-}
-
-
-//--------------------model checking---------------------------------------
-
-//do exhaustive instantiation
-int AbsMbqiBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) {
-  Trace("ambqi-check") << "Exhaustive instantiation " << q << " " << effort << std::endl;
-  if (effort==0) {
-    FirstOrderModelAbs * fma = fm->asFirstOrderModelAbs();
-    bool quantValid = true;
-    for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
-      if( !fma->isValidType( q[0][i].getType() ) ){
-        quantValid = false;
-        Trace("ambqi-inst") << "Interpretation of " << q << " is not valid because of type " << q[0][i].getType() << std::endl;
-        break;
-      }
-    }
-    if( quantValid ){
-      Trace("ambqi-check") << "Compute interpretation..." << std::endl;
-      AbsDef ad;
-      doCheck( fma, q, ad, q[1] );
-      //now process entries
-      Trace("ambqi-inst-debug") << "...Current : " << d_addedLemmas << std::endl;
-      Trace("ambqi-inst") << "Interpretation of " << q << " is : " << std::endl;
-      ad.debugPrint( "ambqi-inst", fma, q[0] );
-      Trace("ambqi-inst") << std::endl;
-      Trace("ambqi-check") << "Add instantiations..." << std::endl;
-      int lem = 0;
-      quantValid = ad.addInstantiations( fma, d_qe, q, lem );
-      Trace("ambqi-inst") << "...Added " << lem << " lemmas." << std::endl;
-      if( lem>0 ){
-        //if we were incomplete but added at least one lemma, we are ok
-        quantValid = true;
-      }
-      d_addedLemmas += lem;
-      Trace("ambqi-inst-debug") << "...Total : " << d_addedLemmas << std::endl;
-    }
-    return quantValid ? 1 : 0;
-  }else{
-    return 1;
-  }
-}
-
-bool AbsMbqiBuilder::doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n ) {
-  Assert( n.getKind()!=FORALL );
-  if( n.getKind()==NOT && n[0].getKind()!=FORALL ){
-    doCheck( m, q, ad, n[0] );
-    ad.negate();
-    return true;
-  }else{
-    std::map< unsigned, AbsDef > children;
-    std::map< unsigned, int > bchildren;
-    std::map< unsigned, int > vchildren;
-    int varChCount = 0;
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      if( n[i].getKind()==FORALL ){
-        bchildren[i] = AbsDef::val_unk;
-      }else if( n[i].getKind() == BOUND_VARIABLE ){
-        varChCount++;
-        vchildren[i] = m->d_var_index[q][ m->getVariableId( q, n[i] ) ];
-        //vchildren[i] = m->getVariableId( q, n[i] );
-      }else if( m->hasTerm( n[i] ) ){
-        bchildren[i] = m->getRepresentativeId( n[i] );
-      }else{
-        if( !doCheck( m, q, children[i], n[i] ) ){
-          bchildren[i] = AbsDef::val_unk;
-          children.erase( i );
-        }
-      }
-    }
-    //convert to pointers
-    std::map< unsigned, AbsDef * > pchildren;
-    for( std::map< unsigned, AbsDef >::iterator it = children.begin(); it != children.end(); ++it ){
-      pchildren[it->first] = &it->second;
-    }
-    //construct the interpretation
-    Trace("ambqi-check-debug") << "Compute Interpretation of " << n << " " << n.getKind() << std::endl;
-    if( n.getKind() == APPLY_UF || n.getKind() == VARIABLE || n.getKind() == SKOLEM ){
-      Node op;
-      if( n.getKind() == APPLY_UF ){
-        op = n.getOperator();
-      }else{
-        op = n;
-      }
-      //uninterpreted compose
-      if( m->d_models_valid[op] ){
-        ad.construct( m, q, n, m->d_models[op], pchildren, bchildren, vchildren, varChCount );
-      }else{
-        Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (no function model)" << std::endl;
-        return false;
-      }
-    }else if( !ad.construct( m, q, n, NULL, pchildren, bchildren, vchildren, varChCount ) ){
-      Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (variables are children of interpreted symbol)" << std::endl;
-      return false;
-    }
-    Trace("ambqi-check-try") << "Interpretation for " << n << " is : " << std::endl;
-    ad.debugPrint("ambqi-check-try", m, q[0] );
-    ad.simplify( m, q, q[0] );
-    Trace("ambqi-check-debug") << "(Simplified) Interpretation for " << n << " is : " << std::endl;
-    ad.debugPrint("ambqi-check-debug", m, q[0] );
-    Trace("ambqi-check-debug") << std::endl;
-    return true;
-  }
-}
-
-}/* namespace CVC4::theory::quantifiers */
-}/* namespace CVC4::theory */
-}/* namespace CVC4 */
diff --git a/src/theory/quantifiers/ambqi_builder.h b/src/theory/quantifiers/ambqi_builder.h
deleted file mode 100644 (file)
index c451f04..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*********************                                                        */
-/*! \file ambqi_builder.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Morgan Deters, Tim King, Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Abstract MBQI model builder class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef ABSTRACT_MBQI_BUILDER
-#define ABSTRACT_MBQI_BUILDER
-
-#include "theory/quantifiers/model_builder.h"
-#include "theory/quantifiers/first_order_model.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class FirstOrderModelAbs;
-
-//representiation of function and term interpretations
-class AbsDef
-{
-private:
-  bool addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth );
-  void construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
-                          std::map< unsigned, AbsDef * >& children,
-                          std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
-                          std::vector< unsigned >& entry, std::vector< bool >& entry_def );
-  void construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth = 0 );
-  void construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth = 0 );
-  void apply_ucompose( FirstOrderModelAbs * m, TNode q,
-                       std::vector< unsigned >& entry, std::vector< bool >& entry_def, std::vector< int >& terms,
-                       std::map< unsigned, int >& vchildren, AbsDef * a, unsigned depth = 0 );
-  void construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth = 0 );
-  void construct_var( FirstOrderModelAbs * m, TNode q, unsigned v, int currv, unsigned depth = 0 );
-  void get_defs( unsigned u, std::vector< AbsDef * >& defs );
-  void construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth = 0 );
-public:
-  enum {
-    val_none = -1,
-    val_unk = -2,
-  };
-  AbsDef() : d_default( 0 ), d_value( -1 ){}
-  std::map< unsigned, AbsDef > d_def;
-  unsigned d_default;
-  int d_value;
-
-  void clear() { d_def.clear(); d_default = 0; d_value = -1; }
-  AbsDef * getDefault() { return &d_def[d_default]; }
-  void construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth = 0 );
-  void debugPrintUInt( const char * c, unsigned dSize, unsigned u ) const;
-  void debugPrint( const char * c, FirstOrderModelAbs * m, TNode f, unsigned depth = 0 ) const;
-  void simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth = 0 );
-  int addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, Node q, int& inst ){
-    std::vector< Node > terms;
-    terms.resize( q[0].getNumChildren() );
-    return addInstantiations( m, qe, q, terms, inst, 0 );
-  }
-  bool construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
-                  std::map< unsigned, AbsDef * >& children,
-                  std::map< unsigned, int >& bchildren,
-                  std::map< unsigned, int >& vchildren,
-                  int varChCount );
-  void negate();
-  Node getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth = 0 );
-  static bool isSimple( unsigned n );
-  static unsigned getId( unsigned n, unsigned start=0, unsigned end=32 );
-  Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< Node >& args );
-  Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< unsigned >& iargs, unsigned depth = 0 );
-  //for debugging
-  bool is_normalized();
-};
-
-class AbsMbqiBuilder : public QModelBuilder
-{
-  friend class AbsDef;
-private:
-  Node d_true;
-  Node d_false;
-  bool doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n );
-public:
-  AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe );
-
-  //process build model
-  bool processBuildModel(TheoryModel* m) override;
-  //do exhaustive instantiation
-  int doExhaustiveInstantiation(FirstOrderModel* fm,
-                                Node q,
-                                int effort) override;
-};
-
-}
-}
-}
-
-#endif
diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp
deleted file mode 100644 (file)
index 963aba6..0000000
+++ /dev/null
@@ -1,893 +0,0 @@
-/*********************                                                        */
-/*! \file bounded_integers.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Morgan Deters, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Bounded integers module
- **
- ** This class manages integer bounds for quantifiers
- **/
-
-#include "theory/quantifiers/bounded_integers.h"
-#include "options/quantifiers_options.h"
-#include "theory/arith/arith_msum.h"
-#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/model_engine.h"
-#include "theory/quantifiers/term_enumeration.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/theory_engine.h"
-
-using namespace CVC4;
-using namespace std;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace CVC4::kind;
-
-
-BoundedIntegers::IntRangeModel::IntRangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy) : d_bi(bi),
-      d_range(r), d_curr_max(-1), d_lit_to_range(u), d_range_assertions(c), d_has_range(c,false), d_curr_range(c,-1), d_ranges_proxied(u) { 
-  if( options::fmfBoundLazy() ){
-    d_proxy_range = isProxy ? r : NodeManager::currentNM()->mkSkolem( "pbir", r.getType() );
-  }else{
-    d_proxy_range = r;
-  }
-  if( !isProxy ){
-    Trace("bound-int") << "Introduce proxy " << d_proxy_range << " for " << d_range << std::endl;
-  }
-}
-
-void BoundedIntegers::IntRangeModel::initialize() {
-  //add initial split lemma
-  Node ltr = NodeManager::currentNM()->mkNode( LT, d_proxy_range, NodeManager::currentNM()->mkConst( Rational(0) ) );
-  ltr = Rewriter::rewrite( ltr );
-  Trace("bound-int-lemma") << " *** bound int: initial split on " << ltr << std::endl;
-  d_bi->getQuantifiersEngine()->getOutputChannel().split( ltr );
-  Node ltr_lit = ltr.getKind()==NOT ? ltr[0] : ltr;
-  d_range_literal[-1] = ltr_lit;
-  d_lit_to_range[ltr_lit] = -1;
-  d_lit_to_pol[ltr_lit] = ltr.getKind()!=NOT;
-  //register with bounded integers
-  Trace("bound-int-debug") << "Literal " << ltr_lit << " is literal for " << d_range << std::endl;
-  d_bi->addLiteralFromRange(ltr_lit, d_range);
-}
-
-void BoundedIntegers::IntRangeModel::assertNode(Node n) {
-  bool pol = n.getKind()!=NOT;
-  Node nlit = n.getKind()==NOT ? n[0] : n;
-  if( d_lit_to_range.find( nlit )!=d_lit_to_range.end() ){
-    int vrange = d_lit_to_range[nlit];
-    Trace("bound-int-assert") << "With polarity = " << pol << " (req "<< d_lit_to_pol[nlit] << ")";
-    Trace("bound-int-assert") << ", found literal " << nlit;
-    Trace("bound-int-assert") << ", it is bound literal " << vrange << " for " << d_range << std::endl;
-    d_range_assertions[nlit] = (pol==d_lit_to_pol[nlit]);
-    if( pol!=d_lit_to_pol[nlit] ){
-      //check if we need a new split?
-      if( !d_has_range ){
-        bool needsRange = true;
-        for( NodeIntMap::iterator it = d_lit_to_range.begin(); it != d_lit_to_range.end(); ++it ){
-          if( d_range_assertions.find( (*it).first )==d_range_assertions.end() ){
-            Trace("bound-int-debug") << "Does not need range because of " << (*it).first << std::endl;
-            needsRange = false;
-            break;
-          }
-        }
-        if( needsRange ){
-          allocateRange();
-        }
-      }
-    }else{
-      if (!d_has_range || vrange<d_curr_range ){
-        Trace("bound-int-bound") << "Successfully bound " << d_range << " to " << vrange << std::endl;
-        d_curr_range = vrange;
-      }
-      //set the range
-      d_has_range = true;
-    }
-  }else{
-    Message() << "Could not find literal " << nlit << " for range " << d_range << std::endl;
-    exit(0);
-  }
-}
-
-void BoundedIntegers::IntRangeModel::allocateRange() {
-  d_curr_max++;
-  int newBound = d_curr_max;
-  Trace("bound-int-proc") << "Allocate range bound " << newBound << " for " << d_range << std::endl;
-  //TODO: newBound should be chosen in a smarter way
-  Node ltr = NodeManager::currentNM()->mkNode( LEQ, d_proxy_range, NodeManager::currentNM()->mkConst( Rational(newBound) ) );
-  ltr = Rewriter::rewrite( ltr );
-  Trace("bound-int-lemma") << " *** bound int: split on " << ltr << std::endl;
-  d_bi->getQuantifiersEngine()->getOutputChannel().split( ltr );
-  Node ltr_lit = ltr.getKind()==NOT ? ltr[0] : ltr;
-  d_range_literal[newBound] = ltr_lit;
-  d_lit_to_range[ltr_lit] = newBound;
-  d_lit_to_pol[ltr_lit] = ltr.getKind()!=NOT;
-  //register with bounded integers
-  d_bi->addLiteralFromRange(ltr_lit, d_range);
-}
-
-Node BoundedIntegers::IntRangeModel::getNextDecisionRequest() {
-  //request the current cardinality as a decision literal, if not already asserted
-  for( NodeIntMap::iterator it = d_lit_to_range.begin(); it != d_lit_to_range.end(); ++it ){
-    int i = (*it).second;
-    if( !d_has_range || i<d_curr_range ){
-      Node rn = (*it).first;
-      Assert( !rn.isNull() );
-      if( d_range_assertions.find( rn )==d_range_assertions.end() ){
-        if (!d_lit_to_pol[rn]) {
-          rn = rn.negate();
-        }
-        Trace("bound-int-dec-debug") << "For " << d_range << ", make decision " << rn << " to make range " << i << std::endl;
-        return rn;
-      }
-    }
-  }
-  return Node::null();
-}
-
-bool BoundedIntegers::IntRangeModel::proxyCurrentRange() {
-  //Trace("model-engine") << "Range(" << d_range << ") currently is " << d_curr_max.get() << std::endl;
-  if( d_range!=d_proxy_range ){
-    //int curr = d_curr_range.get();
-    int curr = d_curr_max;
-    if( d_ranges_proxied.find( curr )==d_ranges_proxied.end() ){
-      d_ranges_proxied[curr] = true;
-      Assert( d_range_literal.find( curr )!=d_range_literal.end() );
-      Node lem = NodeManager::currentNM()->mkNode( EQUAL, d_range_literal[curr].negate(),
-                   NodeManager::currentNM()->mkNode( LEQ, d_range, NodeManager::currentNM()->mkConst( Rational(curr) ) ) );
-      Trace("bound-int-lemma") << "*** bound int : proxy lemma : " << lem << std::endl;
-      d_bi->getQuantifiersEngine()->addLemma( lem );
-      return true;
-    }
-  }
-  return false;
-}
-
-
-
-
-
-BoundedIntegers::BoundedIntegers(context::Context* c, QuantifiersEngine* qe) :
-QuantifiersModule(qe), d_assertions(c){
-
-}
-
-BoundedIntegers::~BoundedIntegers() { 
-  for( std::map< Node, RangeModel * >::iterator it = d_rms.begin(); it != d_rms.end(); ++it ){
-    delete it->second;
-  }
-}
-
-void BoundedIntegers::presolve() {
-  d_bnd_it.clear();
-}
-
-bool BoundedIntegers::isBound( Node f, Node v ) {
-  return std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end();
-}
-
-bool BoundedIntegers::hasNonBoundVar( Node f, Node b, std::map< Node, bool >& visited ) {
-  if( visited.find( b )==visited.end() ){
-    visited[b] = true;
-    if( b.getKind()==BOUND_VARIABLE ){
-      if( !isBound( f, b ) ){
-        return true;
-      }
-    }else{
-      for( unsigned i=0; i<b.getNumChildren(); i++ ){
-        if( hasNonBoundVar( f, b[i], visited ) ){
-          return true;
-        }
-      }
-    }
-  }
-  return false;
-}
-bool BoundedIntegers::hasNonBoundVar( Node f, Node b ) {
-  std::map< Node, bool > visited;
-  return hasNonBoundVar( f, b, visited );
-}
-
-bool BoundedIntegers::processEqDisjunct( Node q, Node n, Node& v, std::vector< Node >& v_cases ) {
-  if( n.getKind()==EQUAL ){
-    for( unsigned i=0; i<2; i++ ){
-      Node t = n[i];
-      if( !hasNonBoundVar( q, n[1-i] ) ){
-        if( t==v ){
-          v_cases.push_back( n[1-i] );
-          return true;
-        }else if( v.isNull() && t.getKind()==BOUND_VARIABLE ){
-          v = t;
-          v_cases.push_back( n[1-i] );
-          return true;
-        }
-      }
-    }
-  }
-  return false;
-}
-
-void BoundedIntegers::processMatchBoundVars( Node q, Node n, std::vector< Node >& bvs, std::map< Node, bool >& visited ){
-  if( visited.find( n )==visited.end() ){
-    visited[n] = true;
-    if( n.getKind()==BOUND_VARIABLE && !isBound( q, n ) ){
-      bvs.push_back( n );
-    //injective operators
-    }else if( n.getKind()==kind::APPLY_CONSTRUCTOR ){
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        processMatchBoundVars( q, n[i], bvs, visited );
-      }
-    }    
-  }
-}
-
-void BoundedIntegers::process( Node q, Node n, bool pol,
-                               std::map< Node, unsigned >& bound_lit_type_map,
-                               std::map< int, std::map< Node, Node > >& bound_lit_map,
-                               std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
-                               std::map< int, std::map< Node, Node > >& bound_int_range_term,
-                               std::map< Node, std::vector< Node > >& bound_fixed_set ){
-  if( n.getKind()==OR || n.getKind()==AND ){
-    if( (n.getKind()==OR)==pol ){
-      for( unsigned i=0; i<n.getNumChildren(); i++) {
-        process( q, n[i], pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set );
-      }
-    }else{
-      //if we are ( x != t1 ^ ...^ x != tn ), then x can be bound to { t1...tn }
-      Node conj = n;
-      if( !pol ){
-        conj = TermUtil::simpleNegate( conj );
-      }
-      Trace("bound-int-debug") << "Process possible finite disequality conjunction : " << conj << std::endl;
-      Assert( conj.getKind()==AND );
-      Node v;
-      std::vector< Node > v_cases;
-      bool success = true;
-      for( unsigned i=0; i<conj.getNumChildren(); i++ ){
-        if( conj[i].getKind()==NOT && processEqDisjunct( q, conj[i][0], v, v_cases ) ){
-          //continue
-        }else{
-          Trace("bound-int-debug") << "...failed due to " << conj[i] << std::endl;
-          success = false;
-          break;
-        }
-      }
-      if( success && !isBound( q, v ) ){
-        Trace("bound-int-debug") << "Success with variable " << v << std::endl;
-        bound_lit_type_map[v] = BOUND_FIXED_SET;
-        bound_lit_map[3][v] = n;
-        bound_lit_pol_map[3][v] = pol;
-        bound_fixed_set[v].clear();
-        bound_fixed_set[v].insert( bound_fixed_set[v].end(), v_cases.begin(), v_cases.end() );
-      }
-    }
-  }else if( n.getKind()==EQUAL ){
-    if( !pol ){
-      // non-applied DER on x != t, x can be bound to { t }
-      Node v;
-      std::vector< Node > v_cases;
-      if( processEqDisjunct( q, n, v, v_cases ) ){
-        if( !isBound( q, v ) ){
-          bound_lit_type_map[v] = BOUND_FIXED_SET;
-          bound_lit_map[3][v] = n;
-          bound_lit_pol_map[3][v] = pol;
-          Assert( v_cases.size()==1 );
-          bound_fixed_set[v].clear();
-          bound_fixed_set[v].push_back( v_cases[0] );
-        }
-      }
-    }  
-  }else if( n.getKind()==NOT ){
-    process( q, n[0], !pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set );
-  }else if( n.getKind()==GEQ ){
-    if( n[0].getType().isInteger() ){
-      std::map< Node, Node > msum;
-      if (ArithMSum::getMonomialSumLit(n, msum))
-      {
-        Trace("bound-int-debug") << "literal (polarity = " << pol << ") " << n << " is monomial sum : " << std::endl;
-        ArithMSum::debugPrintMonomialSum(msum, "bound-int-debug");
-        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
-          if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( q, it->first ) ){
-            //if not bound in another way
-            if( bound_lit_type_map.find( it->first )==bound_lit_type_map.end() || bound_lit_type_map[it->first] == BOUND_INT_RANGE ){
-              Node veq;
-              if (ArithMSum::isolate(it->first, msum, veq, GEQ) != 0)
-              {
-                Node n1 = veq[0];
-                Node n2 = veq[1];
-                if(pol){
-                  //flip
-                  n1 = veq[1];
-                  n2 = veq[0];
-                  if( n1.getKind()==BOUND_VARIABLE ){
-                    n2 = ArithMSum::offset(n2, 1);
-                  }else{
-                    n1 = ArithMSum::offset(n1, -1);
-                  }
-                  veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 );
-                }
-                Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl;
-                Node t = n1==it->first ? n2 : n1;
-                if( !hasNonBoundVar( q, t ) ) {
-                  Trace("bound-int-debug") << "The bound is relevant." << std::endl;
-                  int loru = n1==it->first ? 0 : 1;
-                  bound_lit_type_map[it->first] = BOUND_INT_RANGE;
-                  bound_int_range_term[loru][it->first] = t;
-                  bound_lit_map[loru][it->first] = n;
-                  bound_lit_pol_map[loru][it->first] = pol;
-                }else{
-                  Trace("bound-int-debug") << "The term " << t << " has non-bound variable." << std::endl;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }else if( n.getKind()==MEMBER ){
-    if( !pol && !hasNonBoundVar( q, n[1] ) ){
-      std::vector< Node > bound_vars;
-      std::map< Node, bool > visited;
-      processMatchBoundVars( q, n[0], bound_vars, visited );
-      for( unsigned i=0; i<bound_vars.size(); i++ ){
-        Node v = bound_vars[i];
-        Trace("bound-int-debug") << "literal (polarity = " << pol << ") " << n << " is membership." << std::endl;
-        bound_lit_type_map[v] = BOUND_SET_MEMBER;
-        bound_lit_map[2][v] = n;
-        bound_lit_pol_map[2][v] = pol;
-      }
-    }
-  }else{
-    Assert( n.getKind()!=LEQ && n.getKind()!=LT && n.getKind()!=GT );
-  }
-}
-
-bool BoundedIntegers::needsCheck( Theory::Effort e ) {
-  return e==Theory::EFFORT_LAST_CALL;
-}
-
-void BoundedIntegers::check(Theory::Effort e, QEffort quant_e)
-{
-  if (quant_e == QEFFORT_STANDARD)
-  {
-    Trace("bint-engine") << "---Bounded Integers---" << std::endl;
-    bool addedLemma = false;
-    //make sure proxies are up-to-date with range
-    for( unsigned i=0; i<d_ranges.size(); i++) {
-      if( d_rms[d_ranges[i]]->proxyCurrentRange() ){
-        addedLemma = true;
-      }
-    }
-    Trace("bint-engine") << "   addedLemma = " << addedLemma << std::endl;
-  }
-}
-
-
-void BoundedIntegers::addLiteralFromRange( Node lit, Node r ) {
-  d_lit_to_ranges[lit].push_back(r);
-  //check if it is already asserted?
-  if(d_assertions.find(lit)!=d_assertions.end()){
-    d_rms[r]->assertNode( d_assertions[lit] ? lit : lit.negate() );
-  }
-}
-
-void BoundedIntegers::setBoundedVar( Node q, Node v, unsigned bound_type ) {
-  d_bound_type[q][v] = bound_type;
-  d_set_nums[q][v] = d_set[q].size();
-  d_set[q].push_back( v );
-  Trace("bound-int-var") << "Bound variable #" << d_set_nums[q][v] << " : " << v << std::endl; 
-}
-
-void BoundedIntegers::preRegisterQuantifier( Node f ) {
-  //this needs to be done at preregister since it affects e.g. QuantDSplit's preregister
-  Trace("bound-int") << "preRegister quantifier " << f << std::endl;
-  
-  bool success;
-  do{
-    std::map< Node, unsigned > bound_lit_type_map;
-    std::map< int, std::map< Node, Node > > bound_lit_map;
-    std::map< int, std::map< Node, bool > > bound_lit_pol_map;
-    std::map< int, std::map< Node, Node > > bound_int_range_term;
-    std::map< Node, std::vector< Node > > bound_fixed_set;
-    success = false;
-    process( f, f[1], true, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set );
-    //for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){
-    for( std::map< Node, unsigned >::iterator it = bound_lit_type_map.begin(); it != bound_lit_type_map.end(); ++it ){
-      Node v = it->first;
-      if( !isBound( f, v ) ){
-        bool setBoundVar = false;
-        if( it->second==BOUND_INT_RANGE ){
-          //must have both
-          if( bound_lit_map[0].find( v )!=bound_lit_map[0].end() && bound_lit_map[1].find( v )!=bound_lit_map[1].end() ){
-            setBoundedVar( f, v, BOUND_INT_RANGE );
-            setBoundVar = true;
-            for( unsigned b=0; b<2; b++ ){
-              //set the bounds
-              Assert( bound_int_range_term[b].find( v )!=bound_int_range_term[b].end() );
-              d_bounds[b][f][v] = bound_int_range_term[b][v];
-            }
-            if( options::fmfBoundMinMode()==FMF_BOUND_MIN_ALL || options::fmfBoundMinMode()==FMF_BOUND_MIN_INT_RANGE ){
-              Node r = NodeManager::currentNM()->mkNode( MINUS, d_bounds[1][f][v], d_bounds[0][f][v] );
-              d_range[f][v] = Rewriter::rewrite( r );
-            }
-            Trace("bound-int") << "Variable " << v << " is bound because of int range literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl;
-          }
-        }else if( it->second==BOUND_SET_MEMBER ){
-          setBoundedVar( f, v, BOUND_SET_MEMBER );
-          setBoundVar = true;
-          d_setm_range[f][v] = bound_lit_map[2][v][1];
-          d_setm_range_lit[f][v] = bound_lit_map[2][v];
-          if( options::fmfBoundMinMode()==FMF_BOUND_MIN_ALL || options::fmfBoundMinMode()==FMF_BOUND_MIN_SET_CARD ){
-            d_range[f][v] = NodeManager::currentNM()->mkNode( CARD, d_setm_range[f][v] );
-          }
-          Trace("bound-int") << "Variable " << v << " is bound because of set membership literal " << bound_lit_map[2][v] << std::endl;
-        }else if( it->second==BOUND_FIXED_SET ){
-          setBoundedVar( f, v, BOUND_FIXED_SET );
-          setBoundVar = true;
-          for( unsigned i=0; i<bound_fixed_set[v].size(); i++ ){
-            Node t = bound_fixed_set[v][i];
-            if( t.hasBoundVar() ){
-              d_fixed_set_ngr_range[f][v].push_back( t ); 
-            }else{
-              d_fixed_set_gr_range[f][v].push_back( t ); 
-            }
-          } 
-          Trace("bound-int") << "Variable " << v << " is bound because of disequality conjunction " << bound_lit_map[3][v] << std::endl;
-        }
-        if( setBoundVar ){
-          success = true;
-          //set Attributes on literals
-          for( unsigned b=0; b<2; b++ ){
-            if( bound_lit_map[b].find( v )!=bound_lit_map[b].end() ){
-              Assert( bound_lit_pol_map[b].find( v )!=bound_lit_pol_map[b].end() );
-              BoundIntLitAttribute bila;
-              bound_lit_map[b][v].setAttribute( bila, bound_lit_pol_map[b][v] ? 1 : 0 );
-            }else{
-              Assert( it->second!=BOUND_INT_RANGE );
-            }
-          }
-        }
-      }
-    }
-    if( !success ){
-      //resort to setting a finite bound on a variable
-      for( unsigned i=0; i<f[0].getNumChildren(); i++) {
-        if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){
-          TypeNode tn = f[0][i].getType();
-          if (tn.isSort()
-              || d_quantEngine->getTermEnumeration()->mayComplete(tn))
-          {
-            success = true;
-            setBoundedVar( f, f[0][i], BOUND_FINITE );
-            break;
-          }
-        }
-      }
-    }
-  }while( success );
-  
-  if( Trace.isOn("bound-int") ){
-    Trace("bound-int") << "Bounds are : " << std::endl;
-    for( unsigned i=0; i<f[0].getNumChildren(); i++) {
-      Node v = f[0][i];
-      if( std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end() ){
-        Assert( d_bound_type[f].find( v )!=d_bound_type[f].end() );
-        if( d_bound_type[f][v]==BOUND_INT_RANGE ){
-          Trace("bound-int") << "  " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl;
-        }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){
-          if( d_setm_range_lit[f][v][0]==v ){
-            Trace("bound-int") << "  " << v << " in " << d_setm_range[f][v] << std::endl;
-          }else{
-            Trace("bound-int") << "  " << v << " unifiable in " << d_setm_range_lit[f][v] << std::endl;
-          }
-        }else if( d_bound_type[f][v]==BOUND_FIXED_SET ){
-          Trace("bound-int") << "  " << v << " in { ";
-          for( unsigned i=0; i<d_fixed_set_ngr_range[f][v].size(); i++ ){ 
-            Trace("bound-int") << d_fixed_set_ngr_range[f][v][i] << " ";
-          }
-          for( unsigned i=0; i<d_fixed_set_gr_range[f][v].size(); i++ ){ 
-            Trace("bound-int") << d_fixed_set_gr_range[f][v][i] << " ";
-          }
-          Trace("bound-int") << "}" << std::endl;
-        }else if( d_bound_type[f][v]==BOUND_FINITE ){
-          Trace("bound-int") << "  " << v << " has small finite type." << std::endl;
-        }else{
-          Trace("bound-int") << "  " << v << " has unknown bound." << std::endl;
-          Assert( false );
-        }
-      }else{
-        Trace("bound-int") << "  " << "*** " << v << " is unbounded." << std::endl;
-      }
-    }
-  }
-  
-  bool bound_success = true;
-  for( unsigned i=0; i<f[0].getNumChildren(); i++) {
-    if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){
-      Trace("bound-int-warn") << "Warning : Bounded Integers : Due to quantification on " << f[0][i] << ", could not find bounds for " << f << std::endl;
-      bound_success = false;
-      break;
-    }
-  }
-  
-  if( bound_success ){
-    d_bound_quants.push_back( f );
-    for( unsigned i=0; i<d_set[f].size(); i++) {
-      Node v = d_set[f][i];
-      std::map< Node, Node >::iterator itr = d_range[f].find( v );
-      if( itr != d_range[f].end() ){
-        Node r = itr->second;
-        Assert( !r.isNull() );
-        bool isProxy = false;
-        if( r.hasBoundVar() ){
-          //introduce a new bound
-          Node new_range = NodeManager::currentNM()->mkSkolem( "bir", r.getType(), "bound for term" );
-          d_nground_range[f][v] = r;
-          d_range[f][v] = new_range;
-          r = new_range;
-          isProxy = true;
-        }
-        if( !r.isConst() ){
-          if( std::find(d_ranges.begin(), d_ranges.end(), r)==d_ranges.end() ){
-            Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << std::endl;
-            d_ranges.push_back( r );
-            d_rms[r] = new IntRangeModel( this, r, d_quantEngine->getSatContext(), d_quantEngine->getUserContext(), isProxy );
-            d_rms[r]->initialize();
-          }
-        }
-      }
-    }
-  }
-}
-
-void BoundedIntegers::registerQuantifier( Node q ) {
-
-}
-
-void BoundedIntegers::assertNode( Node n ) {
-  Trace("bound-int-assert") << "Assert " << n << std::endl;
-  Node nlit = n.getKind()==NOT ? n[0] : n;
-  if( d_lit_to_ranges.find(nlit)!=d_lit_to_ranges.end() ){
-    Trace("bound-int-assert") << "This is the bounding literal for " << d_lit_to_ranges[nlit].size() << " ranges." << std::endl;
-    for( unsigned i=0; i<d_lit_to_ranges[nlit].size(); i++) {
-      Node r = d_lit_to_ranges[nlit][i];
-      Trace("bound-int-assert") << "  ...this is a bounding literal for " << r << std::endl;
-      d_rms[r]->assertNode( n );
-    }
-  }
-  d_assertions[nlit] = n.getKind()!=NOT;
-}
-
-Node BoundedIntegers::getNextDecisionRequest( unsigned& priority ) {
-  Trace("bound-int-dec-debug") << "bi: Get next decision request?" << std::endl;
-  for( unsigned i=0; i<d_ranges.size(); i++) {
-    Node d = d_rms[d_ranges[i]]->getNextDecisionRequest();
-    if (!d.isNull()) {
-      bool polLit = d.getKind()!=NOT;
-      Node lit = d.getKind()==NOT ? d[0] : d;
-      bool value;
-      if( d_quantEngine->getValuation().hasSatValue( lit, value ) ) {
-        if( value==polLit ){
-          Trace("bound-int-dec-debug") << "...already asserted properly." << std::endl;
-          //already true, we're already fine
-        }else{
-          Trace("bound-int-dec-debug") << "...already asserted with wrong polarity, re-assert." << std::endl;
-          assertNode( d.negate() );
-          i--;
-        }
-      }else{
-        priority = 1;
-        Trace("bound-int-dec") << "Bounded Integers : Decide " << d << std::endl;
-        return d;
-      }
-    }
-  }
-  Trace("bound-int-dec-debug") << "No decision request." << std::endl;
-  return Node::null();
-}
-
-unsigned BoundedIntegers::getBoundVarType( Node q, Node v ) {
-  std::map< Node, unsigned >::iterator it = d_bound_type[q].find( v );
-  if( it==d_bound_type[q].end() ){
-    return BOUND_NONE;
-  }else{
-    return it->second;
-  }
-}
-
-void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
-  l = d_bounds[0][f][v];
-  u = d_bounds[1][f][v];
-  if( d_nground_range[f].find(v)!=d_nground_range[f].end() ){
-    //get the substitution
-    std::vector< Node > vars;
-    std::vector< Node > subs;
-    if( getRsiSubsitution( f, v, vars, subs, rsi ) ){
-      u = u.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
-      l = l.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
-    }else{
-      u = Node::null();
-      l = Node::null();
-    }
-  }
-}
-
-void BoundedIntegers::getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
-  getBounds( f, v, rsi, l, u );
-  Trace("bound-int-rsi") << "Get value in model for..." << l << " and " << u << std::endl;
-  if( !l.isNull() ){
-    l = d_quantEngine->getModel()->getValue( l );
-  }
-  if( !u.isNull() ){
-    u = d_quantEngine->getModel()->getValue( u );
-  }
-  Trace("bound-int-rsi") << "Value is " << l << " ... " << u << std::endl;
-  return;
-}
-
-bool BoundedIntegers::isGroundRange( Node q, Node v ) {
-  if( isBoundVar(q,v) ){
-    if( d_bound_type[q][v]==BOUND_INT_RANGE ){
-      return !getLowerBound(q,v).hasBoundVar() && !getUpperBound(q,v).hasBoundVar();
-    }else if( d_bound_type[q][v]==BOUND_SET_MEMBER ){
-      return !d_setm_range[q][v].hasBoundVar();
-    }else if( d_bound_type[q][v]==BOUND_FIXED_SET ){
-      return !d_fixed_set_ngr_range[q][v].empty();
-    }
-  }
-  return false;
-}
-
-Node BoundedIntegers::getSetRange( Node q, Node v, RepSetIterator * rsi ) {
-  Node sr = d_setm_range[q][v];
-  if( d_nground_range[q].find(v)!=d_nground_range[q].end() ){
-    //get the substitution
-    std::vector< Node > vars;
-    std::vector< Node > subs;
-    if( getRsiSubsitution( q, v, vars, subs, rsi ) ){
-      sr = sr.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
-    }else{
-      sr = Node::null();
-    }
-  }
-  return sr;
-}
-
-Node BoundedIntegers::getSetRangeValue( Node q, Node v, RepSetIterator * rsi ) {
-  Node sr = getSetRange( q, v, rsi );
-  if( !sr.isNull() ){
-    Trace("bound-int-rsi") << "Get value in model for..." << sr << std::endl;
-    sr = d_quantEngine->getModel()->getValue( sr );
-    //if non-constant, then sr does not occur in the model, we fail
-    if( !sr.isConst() ){
-      return Node::null();
-    }
-    Trace("bound-int-rsi") << "Value is " << sr << std::endl;
-    //as heuristic, map to term model
-    if( sr.getKind()!=EMPTYSET ){
-      std::map< Node, Node > val_to_term;
-      while( sr.getKind()==UNION ){
-        Assert( sr[1].getKind()==kind::SINGLETON );
-        val_to_term[ sr[1][0] ] = sr[1][0];
-        sr = sr[0];
-      }
-      Assert( sr.getKind()==kind::SINGLETON );
-      val_to_term[ sr[0] ] = sr[0];
-      //must look back at assertions, not term database (theory of sets introduces extraneous terms internally)
-      Theory* theory = d_quantEngine->getTheoryEngine()->theoryOf( THEORY_SETS );
-      if( theory ){
-        context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end();
-        for( unsigned i = 0; it != it_end; ++ it, ++i ){
-          Node lit = (*it).assertion;
-          if( lit.getKind()==kind::MEMBER ){
-            Node vr = d_quantEngine->getModel()->getValue( lit[0] );
-            Trace("bound-int-rsi-debug") << "....membership for " << lit << " ==> " << vr << std::endl;
-            Trace("bound-int-rsi-debug") << "  " << (val_to_term.find( vr )!=val_to_term.end()) << " " << d_quantEngine->getEqualityQuery()->areEqual( d_setm_range_lit[q][v][1], lit[1] ) << std::endl;
-            if( val_to_term.find( vr )!=val_to_term.end() ){
-              if( d_quantEngine->getEqualityQuery()->areEqual( d_setm_range_lit[q][v][1], lit[1] ) ){
-                Trace("bound-int-rsi") << "  Map value to term : " << vr << " -> " << lit[0] << std::endl;
-                val_to_term[ vr ] = lit[0];
-              }
-            }
-          }
-        }
-      }
-      //rebuild value
-      Node nsr;
-      for( std::map< Node, Node >::iterator it = val_to_term.begin(); it != val_to_term.end(); ++it ){
-        Node nv = NodeManager::currentNM()->mkNode( kind::SINGLETON, it->second );
-        if( nsr.isNull() ){
-          nsr = nv;
-        }else{
-          nsr = NodeManager::currentNM()->mkNode( kind::UNION, nsr, nv );
-        }
-      }
-      Trace("bound-int-rsi") << "...reconstructed " << nsr << std::endl;
-      return nsr;
-      
-      /*
-      Node lit = d_setm_range_lit[q][v];
-      Trace("bound-int-rsi-debug") << "Bounded from lit " << lit << std::endl;
-      Node f = d_quantEngine->getTermDatabase()->getMatchOperator( lit );
-      TermArgTrie * ta = d_quantEngine->getTermDatabase()->getTermArgTrie( f );
-      if( ta ){
-        Trace("bound-int-rsi-debug") << "Got term index for " << f << std::endl;
-        for( std::map< TNode, TermArgTrie >::iterator it = ta->d_data.begin(); it != ta->d_data.end(); ++it ){
-
-        }
-
-      }
-      */
-    }
-    
-  }
-  return sr;
-}
-
-bool BoundedIntegers::getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi ) {
-
-  Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl;
-  Assert( d_set_nums[q].find( v )!=d_set_nums[q].end() );
-  int vindex = d_set_nums[q][v];
-  Assert( d_set_nums[q][v]==vindex );
-  Trace("bound-int-rsi-debug") << "  index order is " << vindex << std::endl;
-  //must take substitution for all variables that are iterating at higher level
-  for( int i=0; i<vindex; i++) {
-    Assert( d_set_nums[q][d_set[q][i]]==i );
-    Trace("bound-int-rsi") << "Look up the value for " << d_set[q][i] << " " << i << std::endl;
-    int v = rsi->getVariableOrder( i );
-    Assert( q[0][v]==d_set[q][i] );
-    Node t = rsi->getCurrentTerm(v, true);
-    Trace("bound-int-rsi") << "term : " << t << std::endl;
-    vars.push_back( d_set[q][i] );
-    subs.push_back( t );
-  }
-  
-  //check if it has been instantiated
-  if( !vars.empty() && !d_bnd_it[q][v].hasInstantiated(subs) ){
-    if( d_bound_type[q][v]==BOUND_INT_RANGE || d_bound_type[q][v]==BOUND_SET_MEMBER ){
-      //must add the lemma
-      Node nn = d_nground_range[q][v];
-      nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
-      Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[q][v] );
-      Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl;
-      d_quantEngine->getOutputChannel().lemma(lem, false, true);
-    }
-    return false;
-  }else{
-    return true;
-  }
-}
-
-Node BoundedIntegers::matchBoundVar( Node v, Node t, Node e ){
-  if( t==v ){
-    return e;
-  }else if( t.getKind()==kind::APPLY_CONSTRUCTOR ){
-    if( e.getKind()==kind::APPLY_CONSTRUCTOR ){
-      if( t.getOperator() != e.getOperator() ) {
-        return Node::null();
-      }
-    }
-    const Datatype& dt = Datatype::datatypeOf( t.getOperator().toExpr() );
-    unsigned index = Datatype::indexOf( t.getOperator().toExpr() );
-    for( unsigned i=0; i<t.getNumChildren(); i++ ){
-      Node u;
-      if( e.getKind()==kind::APPLY_CONSTRUCTOR ){
-        u = matchBoundVar( v, t[i], e[i] );
-      }else{
-        Node se = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[index].getSelectorInternal( e.getType().toType(), i ) ), e );
-        u = matchBoundVar( v, t[i], se );
-      }
-      if( !u.isNull() ){
-        return u;
-      }
-    }
-  }
-  return Node::null();
-}
-
-bool BoundedIntegers::getBoundElements( RepSetIterator * rsi, bool initial, Node q, Node v, std::vector< Node >& elements ) {
-  if( initial || !isGroundRange( q, v ) ){
-    elements.clear();
-    unsigned bvt = getBoundVarType( q, v );
-    if( bvt==BOUND_INT_RANGE ){
-      Node l, u;
-      getBoundValues( q, v, rsi, l, u );
-      if( l.isNull() || u.isNull() ){
-        Trace("bound-int-warn") << "WARNING: Could not find integer bounds in model for " << v << " in " << q << std::endl;
-        //failed, abort the iterator
-        return false;
-      }else{
-        Trace("bound-int-rsi") << "Can limit bounds of " << v << " to " << l << "..." << u << std::endl;
-        Node range = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MINUS, u, l ) );
-        Node ra = Rewriter::rewrite( NodeManager::currentNM()->mkNode( LEQ, range, NodeManager::currentNM()->mkConst( Rational( 9999 ) ) ) );
-        Node tl = l;
-        Node tu = u;
-        getBounds( q, v, rsi, tl, tu );
-        Assert( !tl.isNull() && !tu.isNull() );
-        if( ra==d_quantEngine->getTermUtil()->d_true ){
-          long rr = range.getConst<Rational>().getNumerator().getLong()+1;
-          Trace("bound-int-rsi")  << "Actual bound range is " << rr << std::endl;
-          for( unsigned k=0; k<rr; k++ ){
-            Node t = NodeManager::currentNM()->mkNode(PLUS, tl, NodeManager::currentNM()->mkConst( Rational(k) ) );
-            t = Rewriter::rewrite( t );
-            elements.push_back( t );
-          }
-          return true;
-        }else{
-          Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << v << "." << std::endl;
-          return false;
-        }
-      }
-    }else if( bvt==BOUND_SET_MEMBER  ){ 
-      Node srv = getSetRangeValue( q, v, rsi );
-      if( srv.isNull() ){
-        Trace("bound-int-warn") << "WARNING: Could not find set bound in model for " << v << " in " << q << std::endl;
-        return false;
-      }else{
-        Trace("bound-int-rsi") << "Bounded by set membership : " << srv << std::endl;
-        if( srv.getKind()!=EMPTYSET ){
-          //collect the elements
-          while( srv.getKind()==UNION ){
-            Assert( srv[1].getKind()==kind::SINGLETON );
-            elements.push_back( srv[1][0] );
-            srv = srv[0];
-          }
-          Assert( srv.getKind()==kind::SINGLETON );
-          elements.push_back( srv[0] );
-          //check if we need to do matching, for literals like ( tuple( v ) in S )
-          Node t = d_setm_range_lit[q][v][0];
-          if( t!=v ){
-            std::vector< Node > elements_tmp;
-            elements_tmp.insert( elements_tmp.end(), elements.begin(), elements.end() );
-            elements.clear();
-            for( unsigned i=0; i<elements_tmp.size(); i++ ){
-              //do matching to determine v -> u
-              Node u = matchBoundVar( v, t, elements_tmp[i] );
-              Trace("bound-int-rsi-debug") << "  unification : " << elements_tmp[i] << " = " << t << " yields " << v << " -> " << u << std::endl;
-              if( !u.isNull() ){
-                elements.push_back( u );
-              }
-            }
-          }
-        }
-        return true;
-      }
-    }else if( bvt==BOUND_FIXED_SET ){
-      std::map< Node, std::vector< Node > >::iterator it = d_fixed_set_gr_range[q].find( v );
-      if( it!=d_fixed_set_gr_range[q].end() ){
-        for( unsigned i=0; i<it->second.size(); i++ ){
-          elements.push_back( it->second[i] );
-        }
-      }
-      it = d_fixed_set_ngr_range[q].find( v );
-      if( it!=d_fixed_set_ngr_range[q].end() ){
-        std::vector< Node > vars;
-        std::vector< Node > subs;
-        if( getRsiSubsitution( q, v, vars, subs, rsi ) ){
-          for( unsigned i=0; i<it->second.size(); i++ ){
-            Node t = it->second[i].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
-            elements.push_back( t );
-          }
-          return true;
-        }else{
-          return false;
-        }
-      }else{
-        return true;
-      }
-    }else{
-      return false;
-    }
-  }else{
-    //no change required
-    return true;
-  }
-}
-
diff --git a/src/theory/quantifiers/bounded_integers.h b/src/theory/quantifiers/bounded_integers.h
deleted file mode 100644 (file)
index 99d77a8..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*********************                                                        */
-/*! \file bounded_integers.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Morgan Deters, Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
-**/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__BOUNDED_INTEGERS_H
-#define __CVC4__BOUNDED_INTEGERS_H
-
-
-#include "theory/quantifiers_engine.h"
-
-#include "context/context.h"
-#include "context/context_mm.h"
-
-namespace CVC4 {
-namespace theory {
-
-class RepSetIterator;
-
-namespace quantifiers {
-
-
-class BoundedIntegers : public QuantifiersModule
-{
-  typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
-  typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
-  typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
-  typedef context::CDHashMap<int, bool> IntBoolMap;
-public:
-  enum {
-    BOUND_FINITE,
-    BOUND_INT_RANGE,
-    BOUND_SET_MEMBER,
-    BOUND_FIXED_SET,
-    BOUND_NONE
-  };
-private:
-  //for determining bounds
-  bool isBound( Node f, Node v );
-  bool hasNonBoundVar( Node f, Node b, std::map< Node, bool >& visited );
-  bool hasNonBoundVar( Node f, Node b );
-  //bound type
-  std::map< Node, std::map< Node, unsigned > > d_bound_type;
-  std::map< Node, std::vector< Node > > d_set;
-  std::map< Node, std::map< Node, int > > d_set_nums;
-  std::map< Node, std::map< Node, Node > > d_range;
-  std::map< Node, std::map< Node, Node > > d_nground_range;
-  //integer lower/upper bounds
-  std::map< Node, std::map< Node, Node > > d_bounds[2];
-  //set membership range
-  std::map< Node, std::map< Node, Node > > d_setm_range;
-  std::map< Node, std::map< Node, Node > > d_setm_range_lit;
-  //fixed finite set range
-  std::map< Node, std::map< Node, std::vector< Node > > > d_fixed_set_gr_range;
-  std::map< Node, std::map< Node, std::vector< Node > > > d_fixed_set_ngr_range;
-  void hasFreeVar( Node f, Node n );
-  void process( Node q, Node n, bool pol,
-                std::map< Node, unsigned >& bound_lit_type_map,
-                std::map< int, std::map< Node, Node > >& bound_lit_map,
-                std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
-                std::map< int, std::map< Node, Node > >& bound_int_range_term,
-                std::map< Node, std::vector< Node > >& bound_fixed_set );
-  bool processEqDisjunct( Node q, Node n, Node& v, std::vector< Node >& v_cases );
-  void processMatchBoundVars( Node q, Node n, std::vector< Node >& bvs, std::map< Node, bool >& visited );
-  std::vector< Node > d_bound_quants;
-private:
-  class RangeModel {
-  public:
-    RangeModel(){}
-    virtual ~RangeModel(){}
-    virtual void initialize() = 0;
-    virtual void assertNode(Node n) = 0;
-    virtual Node getNextDecisionRequest() = 0;
-    virtual bool proxyCurrentRange() = 0;
-  };
-  class IntRangeModel : public RangeModel {
-  private:
-    BoundedIntegers * d_bi;
-    void allocateRange();
-    Node d_proxy_range;
-  public:
-    IntRangeModel( BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy);
-    virtual ~IntRangeModel(){}
-    Node d_range;
-    int d_curr_max;
-    std::map< int, Node > d_range_literal;
-    std::map< Node, bool > d_lit_to_pol;
-    NodeIntMap d_lit_to_range;
-    NodeBoolMap d_range_assertions;
-    context::CDO< bool > d_has_range;
-    context::CDO< int > d_curr_range;
-    IntBoolMap d_ranges_proxied;
-    void initialize();
-    void assertNode(Node n);
-    Node getNextDecisionRequest();
-    bool proxyCurrentRange();
-  };
-private:
-  //information for minimizing ranges
-  std::vector< Node > d_ranges;
-  //map to range model objects
-  std::map< Node, RangeModel * > d_rms;
-  //literal to range
-  std::map< Node, std::vector< Node > > d_lit_to_ranges;
-  //list of currently asserted arithmetic literals
-  NodeBoolMap d_assertions;
-private:
-  //class to store whether bounding lemmas have been added
-  class BoundInstTrie
-  {
-  public:
-    std::map< Node, BoundInstTrie > d_children;
-    bool hasInstantiated( std::vector< Node > & vals, int index = 0, bool madeNew = false ){
-      if( index>=(int)vals.size() ){
-        return !madeNew;
-      }else{
-        Node n = vals[index];
-        if( d_children.find(n)==d_children.end() ){
-          madeNew = true;
-        }
-        return d_children[n].hasInstantiated(vals,index+1,madeNew);
-      }
-    }
-  };
-  std::map< Node, std::map< Node, BoundInstTrie > > d_bnd_it;
-private:
-  void addLiteralFromRange( Node lit, Node r );
-  
-  void setBoundedVar( Node f, Node v, unsigned bound_type );
-public:
-  BoundedIntegers( context::Context* c, QuantifiersEngine* qe );
-  virtual ~BoundedIntegers();
-  
-  void presolve();
-  bool needsCheck( Theory::Effort e );
-  void check(Theory::Effort e, QEffort quant_e);
-  void registerQuantifier( Node q );
-  void preRegisterQuantifier( Node q );
-  void assertNode( Node n );
-  Node getNextDecisionRequest( unsigned& priority );
-  bool isBoundVar( Node q, Node v ) { return std::find( d_set[q].begin(), d_set[q].end(), v )!=d_set[q].end(); }
-  unsigned getBoundVarType( Node q, Node v );
-  unsigned getNumBoundVars( Node q ) { return d_set[q].size(); }
-  Node getBoundVar( Node q, int i ) { return d_set[q][i]; }
-private:
-  //for integer range
-  Node getLowerBound( Node q, Node v ){ return d_bounds[0][q][v]; }
-  Node getUpperBound( Node q, Node v ){ return d_bounds[1][q][v]; }
-  void getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u );
-  void getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u );
-  bool isGroundRange(Node f, Node v);
-  //for set range
-  Node getSetRange( Node q, Node v, RepSetIterator * rsi );
-  Node getSetRangeValue( Node q, Node v, RepSetIterator * rsi );
-  Node matchBoundVar( Node v, Node t, Node e );
-  
-  bool getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi );
-public:
-  bool getBoundElements( RepSetIterator * rsi, bool initial, Node q, Node v, std::vector< Node >& elements );
-
-  /** Identify this module */
-  std::string identify() const { return "BoundedIntegers"; }
-};
-
-}
-}
-}
-
-#endif
diff --git a/src/theory/quantifiers/ce_guided_conjecture.cpp b/src/theory/quantifiers/ce_guided_conjecture.cpp
deleted file mode 100644 (file)
index 0ce9b7c..0000000
+++ /dev/null
@@ -1,894 +0,0 @@
-/*********************                                                        */
-/*! \file ce_guided_conjecture.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief implementation of class that encapsulates counterexample-guided instantiation
- **        techniques for a single SyGuS synthesis conjecture
- **/
-#include "theory/quantifiers/ce_guided_conjecture.h"
-
-#include "expr/datatype.h"
-#include "options/base_options.h"
-#include "options/quantifiers_options.h"
-#include "printer/printer.h"
-#include "prop/prop_engine.h"
-#include "smt/smt_statistics_registry.h"
-#include "theory/quantifiers/ce_guided_instantiation.h"
-#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/quantifiers_attributes.h"
-#include "theory/quantifiers/skolemize.h"
-#include "theory/quantifiers/term_database_sygus.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/theory_engine.h"
-
-using namespace CVC4::kind;
-using namespace std;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-// recursion is not an issue since OR nodes are flattened by the (quantifiers) rewriter
-// this function is for sanity since solution correctness in SyGuS depends on fully miniscoping based on this function
-void collectDisjuncts( Node n, std::vector< Node >& d ) {
-  if( n.getKind()==OR ){
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      collectDisjuncts( n[i], d );
-    }
-  }else{
-    d.push_back( n );
-  }
-}
-
-CegConjecture::CegConjecture(QuantifiersEngine* qe)
-    : d_qe(qe),
-      d_ceg_si(new CegConjectureSingleInv(qe, this)),
-      d_ceg_pbe(new CegConjecturePbe(qe, this)),
-      d_ceg_proc(new CegConjectureProcess(qe)),
-      d_ceg_gc(new CegGrammarConstructor(qe, this)),
-      d_refine_count(0),
-      d_syntax_guided(false) {}
-
-CegConjecture::~CegConjecture() {}
-
-void CegConjecture::assign( Node q ) {
-  Assert( d_embed_quant.isNull() );
-  Assert( q.getKind()==FORALL );
-  Trace("cegqi") << "CegConjecture : assign : " << q << std::endl;
-  d_quant = q;
-
-  // pre-simplify the quantified formula based on the process utility
-  d_simp_quant = d_ceg_proc->preSimplify(d_quant);
-
-  std::map< Node, Node > templates; 
-  std::map< Node, Node > templates_arg;
-  //register with single invocation if applicable
-  if (d_qe->getQuantAttributes()->isSygus(q))
-  {
-    d_ceg_si->initialize(d_simp_quant);
-    d_simp_quant = d_ceg_si->getSimplifiedConjecture();
-    // carry the templates
-    for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
-      Node v = q[0][i];
-      Node templ = d_ceg_si->getTemplate(v);
-      if( !templ.isNull() ){
-        templates[v] = templ;
-        templates_arg[v] = d_ceg_si->getTemplateArg(v);
-      }
-    }
-  }
-
-  // post-simplify the quantified formula based on the process utility
-  d_simp_quant = d_ceg_proc->postSimplify(d_simp_quant);
-
-  // finished simplifying the quantified formula at this point
-
-  // convert to deep embedding and finalize single invocation here
-  d_embed_quant = d_ceg_gc->process(d_simp_quant, templates, templates_arg);
-  Trace("cegqi") << "CegConjecture : converted to embedding : " << d_embed_quant << std::endl;
-
-  // we now finalize the single invocation module, based on the syntax restrictions
-  if (d_qe->getQuantAttributes()->isSygus(q))
-  {
-    d_ceg_si->finishInit( d_ceg_gc->isSyntaxRestricted(), d_ceg_gc->hasSyntaxITE() );
-  }
-
-  Assert( d_candidates.empty() );
-  std::vector< Node > vars;
-  for( unsigned i=0; i<d_embed_quant[0].getNumChildren(); i++ ){
-    vars.push_back( d_embed_quant[0][i] );
-    Node e = NodeManager::currentNM()->mkSkolem( "e", d_embed_quant[0][i].getType() );
-    d_candidates.push_back( e );
-  }
-  Trace("cegqi") << "Base quantified formula is : " << d_embed_quant << std::endl;
-  //construct base instantiation
-  d_base_inst = Rewriter::rewrite(d_qe->getInstantiate()->getInstantiation(
-      d_embed_quant, vars, d_candidates));
-  Trace("cegqi") << "Base instantiation is :      " << d_base_inst << std::endl;
-  d_base_body = d_base_inst;
-  if (d_base_body.getKind() == NOT && d_base_body[0].getKind() == FORALL)
-  {
-    for (const Node& v : d_base_body[0][0])
-    {
-      d_base_vars.push_back(v);
-    }
-    d_base_body = d_base_body[0][1];
-  }
-
-  // register this term with sygus database and other utilities that impact
-  // the enumerative sygus search
-  std::vector< Node > guarded_lemmas;
-  if( !isSingleInvocation() ){
-    d_ceg_proc->initialize(d_base_inst, d_candidates);
-    if( options::sygusPbe() ){
-      d_ceg_pbe->initialize(d_base_inst, d_candidates, guarded_lemmas);
-    } else {
-      for (unsigned i = 0; i < d_candidates.size(); i++) {
-        Node e = d_candidates[i];
-        d_qe->getTermDatabaseSygus()->registerEnumerator(e, e, this);
-      }
-    }
-  }
-
-  if (d_qe->getQuantAttributes()->isSygus(q))
-  {
-    collectDisjuncts( d_base_inst, d_base_disj );
-    Trace("cegqi") << "Conjecture has " << d_base_disj.size() << " disjuncts." << std::endl;
-    //store the inner variables for each disjunct
-    for( unsigned j=0; j<d_base_disj.size(); j++ ){
-      Trace("cegqi") << "  " << j << " : " << d_base_disj[j] << std::endl;
-      d_inner_vars_disj.push_back( std::vector< Node >() );
-      //if the disjunct is an existential, store it
-      if( d_base_disj[j].getKind()==NOT && d_base_disj[j][0].getKind()==FORALL ){
-        for( unsigned k=0; k<d_base_disj[j][0][0].getNumChildren(); k++ ){
-          d_inner_vars.push_back( d_base_disj[j][0][0][k] );
-          d_inner_vars_disj[j].push_back( d_base_disj[j][0][0][k] );
-        }
-      }
-    }
-    d_syntax_guided = true;
-  }
-  else if (d_qe->getQuantAttributes()->isSynthesis(q))
-  {
-    d_syntax_guided = false;
-  }else{
-    Assert( false );
-  }
-  
-  // initialize the guard
-  if( !d_syntax_guided ){
-    if( d_nsg_guard.isNull() ){
-      d_nsg_guard = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "G", NodeManager::currentNM()->booleanType() ) );
-      d_nsg_guard = d_qe->getValuation().ensureLiteral( d_nsg_guard );
-      AlwaysAssert( !d_nsg_guard.isNull() );
-      d_qe->getOutputChannel().requirePhase( d_nsg_guard, true );
-      // negated base as a guarded lemma
-      guarded_lemmas.push_back( d_base_inst.negate() );
-    }
-  }else if( d_ceg_si->getGuard().isNull() ){
-    std::vector< Node > lems;
-    d_ceg_si->getInitialSingleInvLemma( lems );
-    for( unsigned i=0; i<lems.size(); i++ ){
-      Trace("cegqi-lemma") << "Cegqi::Lemma : single invocation " << i << " : " << lems[i] << std::endl;
-      d_qe->getOutputChannel().lemma( lems[i] );
-      if( Trace.isOn("cegqi-debug") ){
-        Node rlem = Rewriter::rewrite( lems[i] );
-        Trace("cegqi-debug") << "...rewritten : " << rlem << std::endl;
-      }
-    }
-  }
-  Assert( !getGuard().isNull() );
-  Node gneg = getGuard().negate();
-  for( unsigned i=0; i<guarded_lemmas.size(); i++ ){
-    Node lem = NodeManager::currentNM()->mkNode( OR, gneg, guarded_lemmas[i] );
-    Trace("cegqi-lemma") << "Cegqi::Lemma : initial (guarded) lemma : " << lem << std::endl;
-    d_qe->getOutputChannel().lemma( lem );
-  }
-
-  // assign the cegis sampler if applicable
-  if (options::cegisSample() != CEGIS_SAMPLE_NONE)
-  {
-    Trace("cegis-sample") << "Initialize sampler for " << d_base_body << "..."
-                          << std::endl;
-    TypeNode bt = d_base_body.getType();
-    d_cegis_sampler.initialize(bt, d_base_vars, options::sygusSamples());
-  }
-
-  Trace("cegqi") << "...finished, single invocation = " << isSingleInvocation() << std::endl;
-}
-
-Node CegConjecture::getGuard() {
-  return !d_syntax_guided ? d_nsg_guard : d_ceg_si->getGuard();
-}
-
-bool CegConjecture::isSingleInvocation() const {
-  return d_ceg_si->isSingleInvocation();
-}
-
-bool CegConjecture::needsCheck( std::vector< Node >& lem ) {
-  if( isSingleInvocation() && !d_ceg_si->needsCheck() ){
-    return false;
-  }else{
-    bool value;
-    Assert( !getGuard().isNull() );
-    // non or fully single invocation : look at guard only
-    if( d_qe->getValuation().hasSatValue( getGuard(), value ) ) {
-      if( !value ){
-        Trace("cegqi-engine-debug") << "Conjecture is infeasible." << std::endl;
-        return false;
-      }
-    }else{
-      Assert( false );
-    }
-    return true;
-  }
-}
-
-
-void CegConjecture::doSingleInvCheck(std::vector< Node >& lems) {
-  if( d_ceg_si!=NULL ){
-    d_ceg_si->check(lems);
-  }
-}
-
-void CegConjecture::doBasicCheck(std::vector< Node >& lems) {
-  std::vector< Node > model_terms;
-  std::vector< Node > clist;
-  getCandidateList( clist, true );
-  Assert( clist.size()==d_quant[0].getNumChildren() );
-  getModelValues( clist, model_terms );
-  if (d_qe->getInstantiate()->addInstantiation(d_quant, model_terms))
-  {
-    //record the instantiation
-    recordInstantiation( model_terms );
-  }else{
-    Assert( false );
-  }
-}
-
-bool CegConjecture::needsRefinement() { 
-  return !d_ce_sk.empty();
-}
-
-void CegConjecture::getCandidateList( std::vector< Node >& clist, bool forceOrig ) {
-  if( d_ceg_pbe->isPbe() && !forceOrig ){
-    d_ceg_pbe->getCandidateList( d_candidates, clist );
-  }else{
-    clist.insert( clist.end(), d_candidates.begin(), d_candidates.end() );
-  }
-}
-
-bool CegConjecture::constructCandidates( std::vector< Node >& clist, std::vector< Node >& model_values, std::vector< Node >& candidate_values, 
-                                         std::vector< Node >& lems ) {
-  Assert( clist.size()==model_values.size() );
-  if( d_ceg_pbe->isPbe() ){
-    return d_ceg_pbe->constructCandidates( clist, model_values, d_candidates, candidate_values, lems );
-  }else{
-    Assert( model_values.size()==d_candidates.size() );
-    candidate_values.insert( candidate_values.end(), model_values.begin(), model_values.end() );
-  }
-  return true;
-}
-
-void CegConjecture::doCheck(std::vector< Node >& lems, std::vector< Node >& model_values) {
-  std::vector< Node > clist;
-  getCandidateList( clist );
-  std::vector< Node > c_model_values;
-  Trace("cegqi-check") << "CegConjuncture : check, build candidates..." << std::endl;
-  bool constructed_cand = constructCandidates( clist, model_values, c_model_values, lems );
-
-  //must get a counterexample to the value of the current candidate
-  Node inst;
-  if( constructed_cand ){
-    if( Trace.isOn("cegqi-check")  ){
-      Trace("cegqi-check") << "CegConjuncture : check candidate : " << std::endl;
-      for( unsigned i=0; i<c_model_values.size(); i++ ){
-        Trace("cegqi-check") << "  " << i << " : " << d_candidates[i] << " -> " << c_model_values[i] << std::endl;
-      }
-    }
-    Assert( c_model_values.size()==d_candidates.size() );
-    inst = d_base_inst.substitute( d_candidates.begin(), d_candidates.end(), c_model_values.begin(), c_model_values.end() );
-  }else{
-    inst = d_base_inst;
-  }
-  
-  //check whether we will run CEGIS on inner skolem variables
-  bool sk_refine = ( !isGround() || d_refine_count==0 ) && ( !d_ceg_pbe->isPbe() || constructed_cand );
-  if( sk_refine ){
-    if (options::cegisSample() == CEGIS_SAMPLE_TRUST)
-    {
-      // we have that the current candidate passed a sample test
-      // since we trust sampling in this mode, we assert there is no
-      // counterexample to the conjecture here.
-      NodeManager* nm = NodeManager::currentNM();
-      Node lem = nm->mkNode(OR, d_quant.negate(), nm->mkConst(false));
-      lem = getStreamGuardedLemma(lem);
-      lems.push_back(lem);
-      recordInstantiation(c_model_values);
-      return;
-    }
-    Assert( d_ce_sk.empty() );
-    d_ce_sk.push_back( std::vector< Node >() );
-  }else{
-    if( !constructed_cand ){
-      return;
-    }
-  }
-  
-  std::vector< Node > ic;
-  ic.push_back( d_quant.negate() );
-  std::vector< Node > d;
-  collectDisjuncts( inst, d );
-  Assert( d.size()==d_base_disj.size() );
-  //immediately skolemize inner existentials
-  for( unsigned i=0; i<d.size(); i++ ){
-    Node dr = Rewriter::rewrite( d[i] );
-    if( dr.getKind()==NOT && dr[0].getKind()==FORALL ){
-      if( constructed_cand ){
-        ic.push_back(d_qe->getSkolemize()->getSkolemizedBody(dr[0]).negate());
-      }
-      if( sk_refine ){
-        Assert( !isGround() );
-        d_ce_sk.back().push_back( dr[0] );
-      }
-    }else{
-      if( constructed_cand ){
-        ic.push_back( dr );
-        if( !d_inner_vars_disj[i].empty() ){
-          Trace("cegqi-debug") << "*** quantified disjunct : " << d[i] << " simplifies to " << dr << std::endl;
-        }
-      }
-      if( sk_refine ){
-        d_ce_sk.back().push_back( Node::null() );
-      }
-    }
-  }
-  if( constructed_cand ){
-    Node lem = NodeManager::currentNM()->mkNode( OR, ic );
-    lem = Rewriter::rewrite( lem );
-    //eagerly unfold applications of evaluation function
-    if( options::sygusDirectEval() ){
-      Trace("cegqi-debug") << "pre-unfold counterexample : " << lem << std::endl;
-      std::map< Node, Node > visited_n;
-      lem = d_qe->getTermDatabaseSygus()->getEagerUnfold( lem, visited_n );
-    }
-    lem = getStreamGuardedLemma(lem);
-    lems.push_back( lem );
-    recordInstantiation( c_model_values );
-  }
-}
-        
-void CegConjecture::doRefine( std::vector< Node >& lems ){
-  Assert( lems.empty() );
-  Assert( d_ce_sk.size()==1 );
-
-  //first, make skolem substitution
-  Trace("cegqi-refine") << "doRefine : construct skolem substitution..." << std::endl;
-  std::vector< Node > sk_vars;
-  std::vector< Node > sk_subs;
-  //collect the substitution over all disjuncts
-  for( unsigned k=0; k<d_ce_sk[0].size(); k++ ){
-    Node ce_q = d_ce_sk[0][k];
-    if( !ce_q.isNull() ){
-      Assert( !d_inner_vars_disj[k].empty() );
-      std::vector<Node> skolems;
-      d_qe->getSkolemize()->getSkolemConstants(ce_q, skolems);
-      Assert(d_inner_vars_disj[k].size() == skolems.size());
-      std::vector< Node > model_values;
-      getModelValues(skolems, model_values);
-      sk_vars.insert( sk_vars.end(), d_inner_vars_disj[k].begin(), d_inner_vars_disj[k].end() );
-      sk_subs.insert( sk_subs.end(), model_values.begin(), model_values.end() );
-    }else{
-      if( !d_inner_vars_disj[k].empty() ){
-        //denegrate case : quantified disjunct was trivially true and does not need to be refined
-        //add trivial substitution (in case we need substitution for previous cex's)
-        for( unsigned i=0; i<d_inner_vars_disj[k].size(); i++ ){
-          sk_vars.push_back( d_inner_vars_disj[k][i] );
-          sk_subs.push_back( getModelValue( d_inner_vars_disj[k][i] ) ); // will return dummy value
-        }
-      }
-    }
-  } 
-  
-  //for conditional evaluation
-  std::vector< Node > lem_c;
-  Assert( d_ce_sk[0].size()==d_base_disj.size() );
-  std::vector< Node > inst_cond_c;
-  Trace("cegqi-refine") << "doRefine : Construct refinement lemma..." << std::endl;
-  for( unsigned k=0; k<d_ce_sk[0].size(); k++ ){
-    Node ce_q = d_ce_sk[0][k];
-    Trace("cegqi-refine-debug") << "  For counterexample point, disjunct " << k << " : " << ce_q << " " << d_base_disj[k] << std::endl;
-    Node c_disj;
-    if( !ce_q.isNull() ){
-      Assert( d_base_disj[k].getKind()==kind::NOT && d_base_disj[k][0].getKind()==kind::FORALL );
-      c_disj = d_base_disj[k][0][1];
-    }else{
-      if( d_inner_vars_disj[k].empty() ){
-        c_disj = d_base_disj[k].negate();
-      }else{
-        //denegrate case : quantified disjunct was trivially true and does not need to be refined
-        Trace("cegqi-refine-debug") << "*** skip " << d_base_disj[k] << std::endl;
-      }
-    }
-    if( !c_disj.isNull() ){
-      //compute the body, inst_cond
-      //standard CEGIS refinement : plug in values, assert that d_candidates must satisfy entire specification
-      lem_c.push_back( c_disj );
-    }
-  }
-  Assert( sk_vars.size()==sk_subs.size() );
-  
-  Node base_lem = lem_c.size()==1 ? lem_c[0] : NodeManager::currentNM()->mkNode( AND, lem_c );
-  
-  Trace("cegqi-refine") << "doRefine : construct and finalize lemmas..." << std::endl;
-  
-  
-  base_lem = base_lem.substitute( sk_vars.begin(), sk_vars.end(), sk_subs.begin(), sk_subs.end() );
-  base_lem = Rewriter::rewrite( base_lem );
-  d_refinement_lemmas.push_back(base_lem);
-
-  Node lem =
-      NodeManager::currentNM()->mkNode(OR, getGuard().negate(), base_lem);
-  lems.push_back( lem );
-
-  d_ce_sk.clear();
-}
-
-void CegConjecture::preregisterConjecture( Node q ) {
-  d_ceg_si->preregisterConjecture( q );
-}
-
-void CegConjecture::getModelValues( std::vector< Node >& n, std::vector< Node >& v ) {
-  Trace("cegqi-engine") << "  * Value is : ";
-  for( unsigned i=0; i<n.size(); i++ ){
-    Node nv = getModelValue( n[i] );
-    v.push_back( nv );
-    if( Trace.isOn("cegqi-engine") ){
-      TypeNode tn = nv.getType();
-      Trace("cegqi-engine") << n[i] << " -> ";
-      std::stringstream ss;
-      Printer::getPrinter(options::outputLanguage())->toStreamSygus(ss, nv);
-      Trace("cegqi-engine") << ss.str() << " ";
-      if (Trace.isOn("cegqi-engine-rr"))
-      {
-        Node bv = d_qe->getTermDatabaseSygus()->sygusToBuiltin(nv, tn);
-        bv = Rewriter::rewrite(bv);
-        Trace("cegqi-engine-rr") << " -> " << bv << std::endl;
-      }
-    }
-    Assert( !nv.isNull() );
-  }
-  Trace("cegqi-engine") << std::endl;
-}
-
-Node CegConjecture::getModelValue( Node n ) {
-  Trace("cegqi-mv") << "getModelValue for : " << n << std::endl;
-  return d_qe->getModel()->getValue( n );
-}
-
-void CegConjecture::debugPrint( const char * c ) {
-  Trace(c) << "Synthesis conjecture : " << d_embed_quant << std::endl;
-  Trace(c) << "  * Candidate program/output symbol : ";
-  for( unsigned i=0; i<d_candidates.size(); i++ ){
-    Trace(c) << d_candidates[i] << " ";
-  }
-  Trace(c) << std::endl;
-  Trace(c) << "  * Candidate ce skolems : ";
-  for( unsigned i=0; i<d_ce_sk.size(); i++ ){
-    Trace(c) << d_ce_sk[i] << " ";
-  }
-}
-
-Node CegConjecture::getCurrentStreamGuard() const {
-  if( d_stream_guards.empty() ){
-    return Node::null();
-  }else{
-    return d_stream_guards.back();
-  }
-}
-
-Node CegConjecture::getStreamGuardedLemma(Node n) const
-{
-  if (options::sygusStream())
-  {
-    // if we are in streaming mode, we guard with the current stream guard
-    Node csg = getCurrentStreamGuard();
-    Assert(!csg.isNull());
-    return NodeManager::currentNM()->mkNode(kind::OR, csg.negate(), n);
-  }
-  return n;
-}
-
-Node CegConjecture::getNextDecisionRequest( unsigned& priority ) {
-  // first, must try the guard
-  // which denotes "this conjecture is feasible"
-  Node feasible_guard = getGuard();
-  bool value;
-  if( !d_qe->getValuation().hasSatValue( feasible_guard, value ) ) {
-    priority = 0;
-    return feasible_guard;
-  }else{
-    if( value ){  
-      // the conjecture is feasible
-      if( options::sygusStream() ){
-        Assert( !isSingleInvocation() );
-        // if we are in sygus streaming mode, then get the "next guard" 
-        // which denotes "we have not yet generated the next solution to the conjecture"
-        Node curr_stream_guard = getCurrentStreamGuard();
-        bool needs_new_stream_guard = false;
-        if( curr_stream_guard.isNull() ){
-          needs_new_stream_guard = true;
-        }else{
-          // check the polarity of the guard
-          if( !d_qe->getValuation().hasSatValue( curr_stream_guard, value ) ) {
-            priority = 0;
-            return curr_stream_guard;
-          }else{
-            if( !value ){
-              Trace("cegqi-debug") << "getNextDecision : we have a new solution since stream guard was propagated false: " << curr_stream_guard << std::endl;
-              // we have generated a solution, print it
-              // get the current output stream
-              // this output stream should coincide with wherever --dump-synth is output on
-              Options& nodeManagerOptions = NodeManager::currentNM()->getOptions();
-              printSynthSolution( *nodeManagerOptions.getOut(), false );
-              // need to make the next stream guard
-              needs_new_stream_guard = true;
-              
-              // We will not refine the current candidate solution since it is a solution
-              // thus, we clear information regarding the current refinement
-              d_ce_sk.clear();
-              // However, we need to exclude the current solution using an explicit refinement 
-              // so that we proceed to the next solution. 
-              std::vector< Node > clist;
-              getCandidateList( clist );
-              Trace("cegqi-debug") << "getNextDecision : solution was : " << std::endl;
-              std::vector< Node > exp;
-              for( unsigned i=0; i<clist.size(); i++ ){
-                Node cprog = clist[i];
-                Node sol = cprog;
-                if( !d_cinfo[cprog].d_inst.empty() ){
-                  sol = d_cinfo[cprog].d_inst.back();
-                  // add to explanation of exclusion
-                  d_qe->getTermDatabaseSygus()
-                      ->getExplain()
-                      ->getExplanationForConstantEquality(cprog, sol, exp);
-                }
-                Trace("cegqi-debug") << "  " << cprog << " -> " << sol << std::endl;
-              }
-              Assert( !exp.empty() );
-              Node exc_lem = exp.size()==1 ? exp[0] : NodeManager::currentNM()->mkNode( kind::AND, exp );
-              exc_lem = exc_lem.negate();
-              Trace("cegqi-lemma") << "Cegqi::Lemma : stream exclude current solution : " << exc_lem << std::endl;
-              d_qe->getOutputChannel().lemma( exc_lem );
-            }
-          }
-        }
-        if( needs_new_stream_guard ){
-          // generate a new stream guard
-          curr_stream_guard = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "G_Stream", NodeManager::currentNM()->booleanType() ) );
-          curr_stream_guard = d_qe->getValuation().ensureLiteral( curr_stream_guard );
-          AlwaysAssert( !curr_stream_guard.isNull() );
-          d_qe->getOutputChannel().requirePhase( curr_stream_guard, true );
-          d_stream_guards.push_back( curr_stream_guard );
-          Trace("cegqi-debug") << "getNextDecision : allocate new stream guard : " << curr_stream_guard << std::endl;
-          // return it as a decision
-          priority = 0;
-          return curr_stream_guard;
-        }
-      }
-    }else{
-      Trace("cegqi-debug") << "getNextDecision : conjecture is infeasible." << std::endl;
-    } 
-  }
-  return Node::null();
-}
-
-void CegConjecture::printSynthSolution( std::ostream& out, bool singleInvocation ) {
-  Trace("cegqi-debug") << "Printing synth solution..." << std::endl;
-  Assert( d_quant[0].getNumChildren()==d_embed_quant[0].getNumChildren() );
-  std::vector<Node> sols;
-  std::vector<int> statuses;
-  getSynthSolutionsInternal(sols, statuses, singleInvocation);
-  for (unsigned i = 0, size = d_embed_quant[0].getNumChildren(); i < size; i++)
-  {
-    Node sol = sols[i];
-    if (!sol.isNull())
-    {
-      Node prog = d_embed_quant[0][i];
-      int status = statuses[i];
-      TypeNode tn = prog.getType();
-      const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
-      std::stringstream ss;
-      ss << prog;
-      std::string f(ss.str());
-      f.erase(f.begin());
-      out << "(define-fun " << f << " ";
-      if( dt.getSygusVarList().isNull() ){
-        out << "() ";
-      }else{
-        out << dt.getSygusVarList() << " ";
-      }
-      out << dt.getSygusType() << " ";
-      if( status==0 ){
-        out << sol;
-      }else{
-        Printer::getPrinter(options::outputLanguage())->toStreamSygus(out, sol);
-      }
-      out << ")" << std::endl;
-      CegInstantiation* cei = d_qe->getCegInstantiation();
-      ++(cei->d_statistics.d_solutions);
-
-      if (status != 0 && options::sygusRewSynth())
-      {
-        TermDbSygus* sygusDb = d_qe->getTermDatabaseSygus();
-        std::map<Node, SygusSamplerExt>::iterator its = d_sampler.find(prog);
-        if (its == d_sampler.end())
-        {
-          d_sampler[prog].initializeSygusExt(
-              d_qe, prog, options::sygusSamples());
-          its = d_sampler.find(prog);
-        }
-        Node solb = sygusDb->sygusToBuiltin(sol, prog.getType());
-        Node eq_sol = its->second.registerTerm(solb);
-        // eq_sol is a candidate solution that is equivalent to sol
-        if (eq_sol != solb)
-        {
-          ++(cei->d_statistics.d_candidate_rewrites);
-          if (!eq_sol.isNull())
-          {
-            // Terms solb and eq_sol are equivalent under sample points but do
-            // not rewrite to the same term. Hence, this indicates a candidate
-            // rewrite.
-            out << "(candidate-rewrite " << solb << " " << eq_sol << ")"
-                << std::endl;
-            ++(cei->d_statistics.d_candidate_rewrites_print);
-            // debugging information
-            if (Trace.isOn("sygus-rr-debug"))
-            {
-              ExtendedRewriter* er = sygusDb->getExtRewriter();
-              Node solbr = er->extendedRewrite(solb);
-              Node eq_solr = er->extendedRewrite(eq_sol);
-              Trace("sygus-rr-debug")
-                  << "; candidate #1 ext-rewrites to: " << solbr << std::endl;
-              Trace("sygus-rr-debug")
-                  << "; candidate #2 ext-rewrites to: " << eq_solr << std::endl;
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-void CegConjecture::getSynthSolutions(std::map<Node, Node>& sol_map,
-                                      bool singleInvocation)
-{
-  NodeManager* nm = NodeManager::currentNM();
-  TermDbSygus* sygusDb = d_qe->getTermDatabaseSygus();
-  std::vector<Node> sols;
-  std::vector<int> statuses;
-  getSynthSolutionsInternal(sols, statuses, singleInvocation);
-  for (unsigned i = 0, size = d_embed_quant[0].getNumChildren(); i < size; i++)
-  {
-    Node sol = sols[i];
-    int status = statuses[i];
-    // get the builtin solution
-    Node bsol = sol;
-    if (status != 0)
-    {
-      // convert sygus to builtin here
-      bsol = sygusDb->sygusToBuiltin(sol, sol.getType());
-    }
-    // convert to lambda
-    TypeNode tn = d_embed_quant[0][i].getType();
-    const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
-    Node bvl = Node::fromExpr(dt.getSygusVarList());
-    if (!bvl.isNull())
-    {
-      bsol = nm->mkNode(LAMBDA, bvl, bsol);
-    }
-    // store in map
-    Node fvar = d_quant[0][i];
-    Assert(fvar.getType() == bsol.getType());
-    sol_map[fvar] = bsol;
-  }
-}
-
-void CegConjecture::getSynthSolutionsInternal(std::vector<Node>& sols,
-                                              std::vector<int>& statuses,
-                                              bool singleInvocation)
-{
-  for (unsigned i = 0, size = d_embed_quant[0].getNumChildren(); i < size; i++)
-  {
-    Node prog = d_embed_quant[0][i];
-    Trace("cegqi-debug") << "  get solution for " << prog << std::endl;
-    TypeNode tn = prog.getType();
-    Assert(tn.isDatatype());
-    // get the solution
-    Node sol;
-    int status = -1;
-    if (singleInvocation)
-    {
-      Assert(d_ceg_si != NULL);
-      sol = d_ceg_si->getSolution(i, tn, status, true);
-      if (!sol.isNull())
-      {
-        sol = sol.getKind() == LAMBDA ? sol[1] : sol;
-      }
-    }
-    else
-    {
-      Node cprog = getCandidate(i);
-      if (!d_cinfo[cprog].d_inst.empty())
-      {
-        // the solution is just the last instantiated term
-        sol = d_cinfo[cprog].d_inst.back();
-        status = 1;
-
-        // check if there was a template
-        Node sf = d_quant[0][i];
-        Node templ = d_ceg_si->getTemplate(sf);
-        if (!templ.isNull())
-        {
-          Trace("cegqi-inv-debug")
-              << sf << " used template : " << templ << std::endl;
-          // if it was not embedded into the grammar
-          if (!options::sygusTemplEmbedGrammar())
-          {
-            TNode templa = d_ceg_si->getTemplateArg(sf);
-            // make the builtin version of the full solution
-            TermDbSygus* sygusDb = d_qe->getTermDatabaseSygus();
-            sol = sygusDb->sygusToBuiltin(sol, sol.getType());
-            Trace("cegqi-inv") << "Builtin version of solution is : " << sol
-                               << ", type : " << sol.getType() << std::endl;
-            TNode tsol = sol;
-            sol = templ.substitute(templa, tsol);
-            Trace("cegqi-inv-debug") << "With template : " << sol << std::endl;
-            sol = Rewriter::rewrite(sol);
-            Trace("cegqi-inv-debug") << "Simplified : " << sol << std::endl;
-            // now, reconstruct to the syntax
-            sol = d_ceg_si->reconstructToSyntax(sol, tn, status, true);
-            sol = sol.getKind() == LAMBDA ? sol[1] : sol;
-            Trace("cegqi-inv-debug")
-                << "Reconstructed to syntax : " << sol << std::endl;
-          }
-          else
-          {
-            Trace("cegqi-inv-debug")
-                << "...was embedding into grammar." << std::endl;
-          }
-        }
-        else
-        {
-          Trace("cegqi-inv-debug")
-              << sf << " did not use template" << std::endl;
-        }
-      }
-      else
-      {
-        Trace("cegqi-warn") << "WARNING : No recorded instantiations for "
-                               "syntax-guided solution!"
-                            << std::endl;
-      }
-    }
-    sols.push_back(sol);
-    statuses.push_back(status);
-  }
-}
-
-Node CegConjecture::getSymmetryBreakingPredicate(
-    Node x, Node e, TypeNode tn, unsigned tindex, unsigned depth)
-{
-  std::vector<Node> sb_lemmas;
-
-  // based on simple preprocessing
-  Node ppred =
-      d_ceg_proc->getSymmetryBreakingPredicate(x, e, tn, tindex, depth);
-  if (!ppred.isNull())
-  {
-    sb_lemmas.push_back(ppred);
-  }
-
-  // other static conjecture-dependent symmetry breaking goes here
-
-  if (!sb_lemmas.empty())
-  {
-    return sb_lemmas.size() == 1
-               ? sb_lemmas[0]
-               : NodeManager::currentNM()->mkNode(kind::AND, sb_lemmas);
-  }
-  else
-  {
-    return Node::null();
-  }
-}
-
-bool CegConjecture::sampleAddRefinementLemma(std::vector<Node>& vals,
-                                             std::vector<Node>& lems)
-{
-  if (Trace.isOn("cegis-sample"))
-  {
-    Trace("cegis-sample") << "Check sampling for candidate solution"
-                          << std::endl;
-    for (unsigned i = 0, size = vals.size(); i < size; i++)
-    {
-      Trace("cegis-sample")
-          << "  " << d_candidates[i] << " -> " << vals[i] << std::endl;
-    }
-  }
-  Assert(vals.size() == d_candidates.size());
-  Node sbody = d_base_body.substitute(
-      d_candidates.begin(), d_candidates.end(), vals.begin(), vals.end());
-  Trace("cegis-sample-debug") << "Sample " << sbody << std::endl;
-  // do eager unfolding
-  std::map<Node, Node> visited_n;
-  sbody = d_qe->getTermDatabaseSygus()->getEagerUnfold(sbody, visited_n);
-  Trace("cegis-sample") << "Sample (after unfolding): " << sbody << std::endl;
-
-  NodeManager* nm = NodeManager::currentNM();
-  for (unsigned i = 0, size = d_cegis_sampler.getNumSamplePoints(); i < size;
-       i++)
-  {
-    if (d_cegis_sample_refine.find(i) == d_cegis_sample_refine.end())
-    {
-      Node ev = d_cegis_sampler.evaluate(sbody, i);
-      Trace("cegis-sample-debug")
-          << "...evaluate point #" << i << " to " << ev << std::endl;
-      Assert(ev.isConst());
-      Assert(ev.getType().isBoolean());
-      if (!ev.getConst<bool>())
-      {
-        Trace("cegis-sample-debug") << "...false for point #" << i << std::endl;
-        // mark this as a CEGIS point (no longer sampled)
-        d_cegis_sample_refine.insert(i);
-        std::vector<Node> vars;
-        std::vector<Node> pt;
-        d_cegis_sampler.getSamplePoint(i, vars, pt);
-        Assert(d_base_vars.size() == pt.size());
-        Node rlem = d_base_body.substitute(
-            d_base_vars.begin(), d_base_vars.end(), pt.begin(), pt.end());
-        rlem = Rewriter::rewrite(rlem);
-        if (std::find(
-                d_refinement_lemmas.begin(), d_refinement_lemmas.end(), rlem)
-            == d_refinement_lemmas.end())
-        {
-          if (Trace.isOn("cegis-sample"))
-          {
-            Trace("cegis-sample") << "   false for point #" << i << " : ";
-            for (const Node& cn : pt)
-            {
-              Trace("cegis-sample") << cn << " ";
-            }
-            Trace("cegis-sample") << std::endl;
-          }
-          Trace("cegqi-engine") << "  *** Refine by sampling" << std::endl;
-          d_refinement_lemmas.push_back(rlem);
-          // if trust, we are not interested in sending out refinement lemmas
-          if (options::cegisSample() != CEGIS_SAMPLE_TRUST)
-          {
-            Node lem = nm->mkNode(OR, getGuard().negate(), rlem);
-            lems.push_back(lem);
-          }
-          return true;
-        }
-        else
-        {
-          Trace("cegis-sample-debug") << "...duplicate." << std::endl;
-        }
-      }
-    }
-  }
-  return false;
-}
-
-}/* namespace CVC4::theory::quantifiers */
-}/* namespace CVC4::theory */
-}/* namespace CVC4 */
diff --git a/src/theory/quantifiers/ce_guided_conjecture.h b/src/theory/quantifiers/ce_guided_conjecture.h
deleted file mode 100644 (file)
index ebcecbe..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/*********************                                                        */
-/*! \file ce_guided_conjecture.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief class that encapsulates counterexample-guided instantiation
- **        techniques for a single SyGuS synthesis conjecture
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_CONJECTURE_H
-#define __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_CONJECTURE_H
-
-#include <memory>
-
-#include "theory/quantifiers/ce_guided_pbe.h"
-#include "theory/quantifiers/ce_guided_single_inv.h"
-#include "theory/quantifiers/sygus_grammar_cons.h"
-#include "theory/quantifiers/sygus_process_conj.h"
-#include "theory/quantifiers/sygus_sampler.h"
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-/** a synthesis conjecture
- * This class implements approaches for a synthesis conecjture, given by data
- * member d_quant.
- * This includes both approaches for synthesis in Reynolds et al CAV 2015. It
- * determines which approach and optimizations are applicable to the
- * conjecture, and has interfaces for implementing them.
- */
-class CegConjecture {
-public:
-  CegConjecture( QuantifiersEngine * qe );
-  ~CegConjecture();
-  /** get original version of conjecture */
-  Node getConjecture() { return d_quant; }
-  /** get deep embedding version of conjecture */
-  Node getEmbeddedConjecture() { return d_embed_quant; }
-  /** get next decision request */
-  Node getNextDecisionRequest( unsigned& priority );
-
-  //-------------------------------for counterexample-guided check/refine
-  /** increment the number of times we have successfully done candidate
-   * refinement */
-  void incrementRefineCount() { d_refine_count++; }
-  /** whether the conjecture is waiting for a call to doCheck below */
-  bool needsCheck( std::vector< Node >& lem );
-  /** whether the conjecture is waiting for a call to doRefine below */
-  bool needsRefinement();
-  /** get the list of candidates */
-  void getCandidateList( std::vector< Node >& clist, bool forceOrig = false );
-  /** do single invocation check 
-  * This updates Gamma for an iteration of step 2 of Figure 1 of Reynolds et al CAV 2015.
-  */
-  void doSingleInvCheck(std::vector< Node >& lems);
-  /** do syntax-guided enumerative check 
-  * This is step 2(a) of Figure 3 of Reynolds et al CAV 2015.
-  */
-  void doCheck(std::vector< Node >& lems, std::vector< Node >& model_values);
-  /** do basic check 
-  * This is called for non-SyGuS synthesis conjectures
-  */
-  void doBasicCheck(std::vector< Node >& lems);
-  /** do refinement 
-  * This is step 2(b) of Figure 3 of Reynolds et al CAV 2015.
-  */
-  void doRefine(std::vector< Node >& lems);
-  //-------------------------------end for counterexample-guided check/refine
-  /**
-   * prints the synthesis solution to output stream out.
-   *
-   * singleInvocation : set to true if we should consult the single invocation
-   * module to get synthesis solutions.
-   */
-  void printSynthSolution( std::ostream& out, bool singleInvocation );
-  /** get synth solutions
-   *
-   * This returns a map from function-to-synthesize variables to their
-   * builtin solution, which has the same type. For example, for synthesis
-   * conjecture exists f. forall x. f( x )>x, this function may return the map
-   * containing the entry:
-   *   f -> (lambda x. x+1)
-   *
-   * singleInvocation : set to true if we should consult the single invocation
-   * module to get synthesis solutions.
-   */
-  void getSynthSolutions(std::map<Node, Node>& sol_map, bool singleInvocation);
-  /** get guard, this is "G" in Figure 3 of Reynolds et al CAV 2015 */
-  Node getGuard();
-  /** is ground */
-  bool isGround() { return d_inner_vars.empty(); }
-  /** does this conjecture correspond to a syntax-guided synthesis input */
-  bool isSyntaxGuided() const { return d_syntax_guided; }
-  /** are we using single invocation techniques */
-  bool isSingleInvocation() const;
-  /** preregister conjecture 
-  * This is used as a heuristic for solution reconstruction, so that we 
-  * remember expressions in the conjecture before preprocessing, since they
-  * may be helpful during solution reconstruction (Figure 5 of Reynolds et al CAV 2015)
-  */
-  void preregisterConjecture( Node q );
-  /** assign conjecture q to this class */
-  void assign( Node q );
-  /** has a conjecture been assigned to this class */
-  bool isAssigned() { return !d_embed_quant.isNull(); }
-  /** get model values for terms n, store in vector v */
-  void getModelValues( std::vector< Node >& n, std::vector< Node >& v );
-  /** get model value for term n */
-  Node getModelValue( Node n );
-
-  //-----------------------------------refinement lemmas
-  /** get number of refinement lemmas we have added so far */
-  unsigned getNumRefinementLemmas() { return d_refinement_lemmas.size(); }
-  /** get refinement lemma
-   *
-   * If d_embed_quant is forall d. exists y. P( d, y ), then a refinement
-   * lemma is one of the form ~P( d_candidates, c ) for some c.
-   */
-  Node getRefinementLemma( unsigned i ) { return d_refinement_lemmas[i]; }
-  /** sample add refinement lemma
-   *
-   * This function will check if there is a sample point in d_sampler that
-   * refutes the candidate solution (d_quant_vars->vals). If so, it adds a
-   * refinement lemma to the lists d_refinement_lemmas that corresponds to that
-   * sample point, and adds a lemma to lems if cegisSample mode is not trust.
-   */
-  bool sampleAddRefinementLemma(std::vector<Node>& vals,
-                                std::vector<Node>& lems);
-  //-----------------------------------end refinement lemmas
-
-  /** get program by examples utility */
-  CegConjecturePbe* getPbe() { return d_ceg_pbe.get(); }
-  /** get utility for static preprocessing and analysis of conjectures */
-  CegConjectureProcess* getProcess() { return d_ceg_proc.get(); }
-  /** get the symmetry breaking predicate for type */
-  Node getSymmetryBreakingPredicate(
-      Node x, Node e, TypeNode tn, unsigned tindex, unsigned depth);
-  /** print out debug information about this conjecture */
-  void debugPrint( const char * c );
-private:
-  /** reference to quantifier engine */
-  QuantifiersEngine * d_qe;
-  /** single invocation utility */
-  std::unique_ptr<CegConjectureSingleInv> d_ceg_si;
-  /** program by examples utility */
-  std::unique_ptr<CegConjecturePbe> d_ceg_pbe;
-  /** utility for static preprocessing and analysis of conjectures */
-  std::unique_ptr<CegConjectureProcess> d_ceg_proc;
-  /** grammar utility */
-  std::unique_ptr<CegGrammarConstructor> d_ceg_gc;
-  /** list of constants for quantified formula
-  * The outer Skolems for the negation of d_embed_quant.
-  */
-  std::vector< Node > d_candidates;
-  /** base instantiation
-  * If d_embed_quant is forall d. exists y. P( d, y ), then
-  * this is the formula  exists y. P( d_candidates, y ).
-  */
-  Node d_base_inst;
-  /** If d_base_inst is exists y. P( d, y ), then this is y. */
-  std::vector<Node> d_base_vars;
-  /**
-   * If d_base_inst is exists y. P( d, y ), then this is the formula
-   * P( d_candidates, y ).
-   */
-  Node d_base_body;
-  /** expand base inst to disjuncts */
-  std::vector< Node > d_base_disj;
-  /** list of variables on inner quantification */
-  std::vector< Node > d_inner_vars;
-  std::vector< std::vector< Node > > d_inner_vars_disj;
-  /** current extential quantifeirs whose couterexamples we must refine */
-  std::vector< std::vector< Node > > d_ce_sk;
-
-  //-----------------------------------refinement lemmas
-  /** refinement lemmas */
-  std::vector< Node > d_refinement_lemmas;
-  //-----------------------------------end refinement lemmas
-
-  /** the asserted (negated) conjecture */
-  Node d_quant;
-  /** (negated) conjecture after simplification */
-  Node d_simp_quant;
-  /** (negated) conjecture after simplification, conversion to deep embedding */
-  Node d_embed_quant;
-  /** candidate information */
-  class CandidateInfo {
-  public:
-    CandidateInfo(){}
-    /** list of terms we have instantiated candidates with */
-    std::vector< Node > d_inst;
-  };
-  std::map< Node, CandidateInfo > d_cinfo;  
-  /** number of times we have called doRefine */
-  unsigned d_refine_count;
-  /** construct candidates */
-  bool constructCandidates( std::vector< Node >& clist, std::vector< Node >& model_values, 
-                            std::vector< Node >& candidate_values, std::vector< Node >& lems );
-  /** get candidadate */
-  Node getCandidate( unsigned int i ) { return d_candidates[i]; }
-  /** record instantiation (this is used to construct solutions later) */
-  void recordInstantiation( std::vector< Node >& vs ) {
-    Assert( vs.size()==d_candidates.size() );
-    for( unsigned i=0; i<vs.size(); i++ ){
-      d_cinfo[d_candidates[i]].d_inst.push_back( vs[i] );
-    }
-  }
-  /** get synth solutions internal
-   *
-   * This function constructs the body of solutions for all
-   * functions-to-synthesize in this conjecture and stores them in sols, in
-   * order. For each solution added to sols, we add an integer indicating what
-   * kind of solution n is, where if sols[i] = n, then
-   *   if status[i] = 0: n is the (builtin term) corresponding to the solution,
-   *   if status[i] = 1: n is the sygus representation of the solution.
-   * We store builtin versions under some conditions (such as when the sygus
-   * grammar is being ignored).
-   *
-   * singleInvocation : set to true if we should consult the single invocation
-   * module to get synthesis solutions.
-   *
-   * For example, for conjecture exists fg. forall x. f(x)>g(x), this function
-   * may set ( sols, status ) to ( { x+1, d_x() }, { 1, 0 } ), where d_x() is
-   * the sygus datatype constructor corresponding to variable x.
-   */
-  void getSynthSolutionsInternal(std::vector<Node>& sols,
-                                 std::vector<int>& status,
-                                 bool singleInvocation);
-  //-------------------------------- sygus stream
-  /** the streaming guards for sygus streaming mode */
-  std::vector< Node > d_stream_guards;
-  /** get current stream guard */
-  Node getCurrentStreamGuard() const;
-  /** get stream guarded lemma
-   *
-   * If sygusStream is enabled, this returns ( G V n ) where G is the guard
-   * returned by getCurrentStreamGuard, otherwise this returns n.
-   */
-  Node getStreamGuardedLemma(Node n) const;
-  //-------------------------------- end sygus stream
-  //-------------------------------- non-syntax guided (deprecated)
-  /** Whether we are syntax-guided (e.g. was the input in SyGuS format).
-   * This includes SyGuS inputs where no syntactic restrictions are provided.
-   */
-  bool d_syntax_guided;
-  /** the guard for non-syntax-guided synthesis */
-  Node d_nsg_guard;
-  //-------------------------------- end non-syntax guided (deprecated)
-  /** sygus sampler objects for each program variable
-   *
-   * This is used for the sygusRewSynth() option to synthesize new candidate
-   * rewrite rules.
-   */
-  std::map<Node, SygusSamplerExt> d_sampler;
-  /** sampler object for the option cegisSample()
-   *
-   * This samples points of the type of the inner variables of the synthesis
-   * conjecture (d_base_vars).
-   */
-  SygusSampler d_cegis_sampler;
-  /** cegis sample refine points
-   *
-   * Stores the list of indices of sample points in d_cegis_sampler we have
-   * added as refinement lemmas.
-   */
-  std::unordered_set<unsigned> d_cegis_sample_refine;
-};
-
-} /* namespace CVC4::theory::quantifiers */
-} /* namespace CVC4::theory */
-} /* namespace CVC4 */
-
-#endif
diff --git a/src/theory/quantifiers/ce_guided_instantiation.cpp b/src/theory/quantifiers/ce_guided_instantiation.cpp
deleted file mode 100644 (file)
index ea2a2d1..0000000
+++ /dev/null
@@ -1,388 +0,0 @@
-/*********************                                                        */
-/*! \file ce_guided_instantiation.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Tim King, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief counterexample guided instantiation class
- **   This class is the entry point for both synthesis algorithms in Reynolds et al CAV 2015
- **
- **/
-#include "theory/quantifiers/ce_guided_instantiation.h"
-
-#include "options/quantifiers_options.h"
-#include "smt/smt_statistics_registry.h"
-#include "theory/theory_engine.h"
-#include "theory/quantifiers/quantifiers_attributes.h"
-#include "theory/quantifiers/term_database_sygus.h"
-#include "theory/quantifiers/term_util.h"
-//FIXME : remove this include (github issue #1156)
-#include "theory/bv/theory_bv_rewriter.h"
-
-using namespace CVC4::kind;
-using namespace std;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-CegInstantiation::CegInstantiation( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ){
-  d_conj = new CegConjecture( qe );
-  d_last_inst_si = false;
-}
-
-CegInstantiation::~CegInstantiation(){ 
-  delete d_conj;
-}
-
-bool CegInstantiation::needsCheck( Theory::Effort e ) {
-  return e>=Theory::EFFORT_LAST_CALL;
-}
-
-QuantifiersModule::QEffort CegInstantiation::needsModel(Theory::Effort e)
-{
-  return d_conj->isSingleInvocation() ? QEFFORT_STANDARD : QEFFORT_MODEL;
-}
-
-void CegInstantiation::check(Theory::Effort e, QEffort quant_e)
-{
-  unsigned echeck =
-      d_conj->isSingleInvocation() ? QEFFORT_STANDARD : QEFFORT_MODEL;
-  if( quant_e==echeck ){
-    Trace("cegqi-engine") << "---Counterexample Guided Instantiation Engine---" << std::endl;
-    Trace("cegqi-engine-debug") << std::endl;
-    bool active = false;
-    bool value;
-    if( d_quantEngine->getValuation().hasSatValue( d_conj->getConjecture(), value ) ) {
-      active = value;
-    }else{
-      Trace("cegqi-engine-debug") << "...no value for quantified formula." << std::endl;
-    }
-    Trace("cegqi-engine-debug") << "Current conjecture status : active : " << active << std::endl;
-    std::vector< Node > lem;
-    if( active && d_conj->needsCheck( lem ) ){
-      checkCegConjecture( d_conj );
-    }else{
-      Trace("cegqi-engine-debug") << "...does not need check." << std::endl;
-      for( unsigned i=0; i<lem.size(); i++ ){
-        Trace("cegqi-lemma") << "Cegqi::Lemma : check lemma : " << lem[i] << std::endl;
-        d_quantEngine->addLemma( lem[i] );
-      }
-    }
-    Trace("cegqi-engine") << "Finished Counterexample Guided Instantiation engine." << std::endl;
-  }
-}
-
-void CegInstantiation::registerQuantifier( Node q ) {
-  if( d_quantEngine->getOwner( q )==this ){ // && d_eval_axioms.find( q )==d_eval_axioms.end() ){
-    if( !d_conj->isAssigned() ){
-      Trace("cegqi") << "Register conjecture : " << q << std::endl;
-      d_conj->assign( q );
-    }else{
-      Assert( d_conj->getEmbeddedConjecture()==q );
-    }
-  }else{
-    Trace("cegqi-debug") << "Register quantifier : " << q << std::endl;
-  }
-}
-
-Node CegInstantiation::getNextDecisionRequest( unsigned& priority ) {
-  if( d_conj->isAssigned() ){
-    Node dec_req = d_conj->getNextDecisionRequest( priority );
-    if( !dec_req.isNull() ){
-      Trace("cegqi-debug") << "CEGQI : Decide next on : " << dec_req << "..." << std::endl;
-      return dec_req;
-    }
-  }
-  return Node::null();
-}
-
-void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
-  Node q = conj->getEmbeddedConjecture();
-  Node aq = conj->getConjecture();
-  if( Trace.isOn("cegqi-engine-debug") ){
-    conj->debugPrint("cegqi-engine-debug");
-    Trace("cegqi-engine-debug") << std::endl;
-  }
-
-  if( !conj->needsRefinement() ){
-    Trace("cegqi-engine-debug") << "Do conjecture check..." << std::endl;
-    if( conj->isSyntaxGuided() ){
-      std::vector< Node > clems;
-      conj->doSingleInvCheck( clems );
-      if( !clems.empty() ){
-        d_last_inst_si = true;
-        for( unsigned j=0; j<clems.size(); j++ ){
-          Trace("cegqi-lemma") << "Cegqi::Lemma : single invocation instantiation : " << clems[j] << std::endl;
-          d_quantEngine->addLemma( clems[j] );
-        }
-        d_statistics.d_cegqi_si_lemmas += clems.size();
-        Trace("cegqi-engine") << "  ...try single invocation." << std::endl;
-        return;
-      }
-      //ignore return value here
-      std::vector< Node > clist;
-      conj->getCandidateList( clist );
-      std::vector< Node > model_values;
-      conj->getModelValues( clist, model_values );
-      if( options::sygusDirectEval() ){
-        bool addedEvalLemmas = false;
-        if( options::sygusCRefEval() ){
-          Trace("cegqi-engine") << "  *** Do conjecture refinement evaluation..." << std::endl;
-          // see if any refinement lemma is refuted by evaluation
-          std::vector< Node > cre_lems;
-          getCRefEvaluationLemmas( conj, clist, model_values, cre_lems );
-          if( !cre_lems.empty() ){
-            for( unsigned j=0; j<cre_lems.size(); j++ ){
-              Node lem = cre_lems[j];
-              if( d_quantEngine->addLemma( lem ) ){
-                Trace("cegqi-lemma") << "Cegqi::Lemma : cref evaluation : " << lem << std::endl;
-                addedEvalLemmas = true;
-              }
-            }
-            if( addedEvalLemmas ){
-              //return;
-            }
-          }
-        }
-        Trace("cegqi-engine") << "  *** Do direct evaluation..." << std::endl;
-        std::vector< Node > eager_terms; 
-        std::vector< Node > eager_vals; 
-        std::vector< Node > eager_exps;
-        for( unsigned j=0; j<clist.size(); j++ ){
-          Trace("cegqi-debug") << "  register " << clist[j] << " -> " << model_values[j] << std::endl;
-          d_quantEngine->getTermDatabaseSygus()->registerModelValue( clist[j], model_values[j], eager_terms, eager_vals, eager_exps );
-        }
-        Trace("cegqi-debug") << "...produced " << eager_terms.size()  << " eager evaluation lemmas." << std::endl;
-        if( !eager_terms.empty() ){
-          for( unsigned j=0; j<eager_terms.size(); j++ ){
-            Node lem = NodeManager::currentNM()->mkNode( kind::OR, eager_exps[j].negate(), eager_terms[j].eqNode( eager_vals[j] ) );
-            if( d_quantEngine->getTheoryEngine()->isTheoryEnabled(THEORY_BV) ){
-              //FIXME: hack to incorporate hacks from BV for division by zero (github issue #1156)
-              lem = bv::TheoryBVRewriter::eliminateBVSDiv( lem );
-            }
-            if( d_quantEngine->addLemma( lem ) ){
-              Trace("cegqi-lemma") << "Cegqi::Lemma : evaluation : " << lem << std::endl;
-              addedEvalLemmas = true;
-            }
-          }
-        }
-        if( addedEvalLemmas ){
-          return;
-        }
-      }
-      
-      Trace("cegqi-engine") << "  *** Check candidate phase..." << std::endl;
-      std::vector< Node > cclems;
-      conj->doCheck( cclems, model_values );
-      bool addedLemma = false;
-      for( unsigned i=0; i<cclems.size(); i++ ){
-        Node lem = cclems[i];
-        d_last_inst_si = false;
-        Trace("cegqi-lemma") << "Cegqi::Lemma : counterexample : " << lem << std::endl;
-        if( d_quantEngine->addLemma( lem ) ){
-          ++(d_statistics.d_cegqi_lemmas_ce);
-          addedLemma = true;
-        }else{
-          //this may happen if we eagerly unfold, simplify to true
-          if( !options::sygusDirectEval() ){
-            Trace("cegqi-warn") << "  ...FAILED to add candidate!" << std::endl;
-          }else{
-            Trace("cegqi-engine-debug") << "  ...FAILED to add candidate!" << std::endl;
-          }
-        }
-      }
-      if( addedLemma ){
-        Trace("cegqi-engine") << "  ...check for counterexample." << std::endl;
-      }else{
-        if( conj->needsRefinement() ){
-          //immediately go to refine candidate
-          checkCegConjecture( conj );
-          return;
-        }
-      } 
-    }else{
-      Assert( aq==q );
-      Trace("cegqi-engine") << "  *** Check candidate phase (non-SyGuS)." << std::endl;
-      std::vector< Node > lems;
-      conj->doBasicCheck(lems);
-      Assert(lems.empty());
-    }
-  }else{
-    Trace("cegqi-engine") << "  *** Refine candidate phase..." << std::endl;
-    std::vector< Node > rlems;
-    conj->doRefine( rlems );
-    bool addedLemma = false;
-    for( unsigned i=0; i<rlems.size(); i++ ){
-      Node lem = rlems[i];
-      Trace("cegqi-lemma") << "Cegqi::Lemma : candidate refinement : " << lem << std::endl;
-      bool res = d_quantEngine->addLemma( lem );
-      if( res ){
-        ++(d_statistics.d_cegqi_lemmas_refine);
-        conj->incrementRefineCount();
-        addedLemma = true;
-      }else{
-        Trace("cegqi-warn") << "  ...FAILED to add refinement!" << std::endl;
-      }
-    }
-    if( addedLemma ){
-      Trace("cegqi-engine") << "  ...refine candidate." << std::endl;
-    }
-  }
-}
-
-void CegInstantiation::getCRefEvaluationLemmas( CegConjecture * conj, std::vector< Node >& vs, std::vector< Node >& ms, std::vector< Node >& lems ) {
-  Trace("sygus-cref-eval") << "Cref eval : conjecture has " << conj->getNumRefinementLemmas() << " refinement lemmas." << std::endl;
-  unsigned nlemmas = conj->getNumRefinementLemmas();
-  if (nlemmas > 0 || options::cegisSample() != CEGIS_SAMPLE_NONE)
-  {
-    Assert( vs.size()==ms.size() );
-
-    TermDbSygus* tds = d_quantEngine->getTermDatabaseSygus();
-    Node nfalse = d_quantEngine->getTermUtil()->d_false;
-    Node neg_guard = conj->getGuard().negate();
-    for (unsigned i = 0; i <= nlemmas; i++)
-    {
-      if (i == nlemmas)
-      {
-        bool addedSample = false;
-        // find a new one by sampling, if applicable
-        if (options::cegisSample() != CEGIS_SAMPLE_NONE)
-        {
-          addedSample = conj->sampleAddRefinementLemma(ms, lems);
-        }
-        if (!addedSample)
-        {
-          return;
-        }
-      }
-      Node lem;
-      std::map< Node, Node > visited;
-      std::map< Node, std::vector< Node > > exp;
-      lem = conj->getRefinementLemma(i);
-      if( !lem.isNull() ){
-        std::vector< Node > lem_conj;
-        //break into conjunctions
-        if( lem.getKind()==kind::AND ){
-          for( unsigned i=0; i<lem.getNumChildren(); i++ ){
-            lem_conj.push_back( lem[i] );
-          }
-        }else{
-          lem_conj.push_back( lem );
-        }
-        EvalSygusInvarianceTest vsit;
-        for( unsigned j=0; j<lem_conj.size(); j++ ){
-          Node lemc = lem_conj[j];
-          Trace("sygus-cref-eval") << "Check refinement lemma conjunct " << lemc << " against current model." << std::endl;
-          Trace("sygus-cref-eval2") << "Check refinement lemma conjunct " << lemc << " against current model." << std::endl;
-          Node cre_lem;
-          Node lemcs = lemc.substitute( vs.begin(), vs.end(), ms.begin(), ms.end() );
-          Trace("sygus-cref-eval2") << "...under substitution it is : " << lemcs << std::endl;
-          Node lemcsu = vsit.doEvaluateWithUnfolding(tds, lemcs);
-          Trace("sygus-cref-eval2") << "...after unfolding is : " << lemcsu << std::endl;
-          if( lemcsu==d_quantEngine->getTermUtil()->d_false ){
-            std::vector< Node > msu;
-            std::vector< Node > mexp;
-            msu.insert( msu.end(), ms.begin(), ms.end() );
-            for( unsigned k=0; k<vs.size(); k++ ){
-              vsit.setUpdatedTerm(msu[k]);
-              msu[k] = vs[k];
-              // substitute for everything except this
-              Node sconj =
-                  lemc.substitute(vs.begin(), vs.end(), msu.begin(), msu.end());
-              vsit.init(sconj, vs[k], nfalse);
-              // get minimal explanation for this
-              Node ut = vsit.getUpdatedTerm();
-              Trace("sygus-cref-eval2-debug")
-                  << "  compute min explain of : " << vs[k] << " = " << ut
-                  << std::endl;
-              d_quantEngine->getTermDatabaseSygus()
-                  ->getExplain()
-                  ->getExplanationFor(vs[k], ut, mexp, vsit);
-              msu[k] = ut;
-            }
-            if( !mexp.empty() ){
-              Node en = mexp.size()==1 ? mexp[0] : NodeManager::currentNM()->mkNode( kind::AND, mexp );
-              cre_lem = NodeManager::currentNM()->mkNode( kind::OR, en.negate(), neg_guard );
-            }else{
-              cre_lem = neg_guard;
-            }
-          }
-          if( !cre_lem.isNull() ){
-            if( std::find( lems.begin(), lems.end(), cre_lem )==lems.end() ){
-              Trace("sygus-cref-eval") << "...produced lemma : " << cre_lem << std::endl;
-              lems.push_back( cre_lem );
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-void CegInstantiation::printSynthSolution( std::ostream& out ) {
-  if( d_conj->isAssigned() )
-  {
-    d_conj->printSynthSolution( out, d_last_inst_si );
-  }
-  else
-  {
-    Assert( false );
-  }
-}
-
-void CegInstantiation::getSynthSolutions(std::map<Node, Node>& sol_map)
-{
-  if (d_conj->isAssigned())
-  {
-    d_conj->getSynthSolutions(sol_map, d_last_inst_si);
-  }
-  else
-  {
-    Assert(false);
-  }
-}
-
-void CegInstantiation::preregisterAssertion( Node n ) {
-  //check if it sygus conjecture
-  if( QuantAttributes::checkSygusConjecture( n ) ){
-    //this is a sygus conjecture
-    Trace("cegqi") << "Preregister sygus conjecture : " << n << std::endl;
-    d_conj->preregisterConjecture( n );
-  }
-}
-
-CegInstantiation::Statistics::Statistics()
-    : d_cegqi_lemmas_ce("CegInstantiation::cegqi_lemmas_ce", 0),
-      d_cegqi_lemmas_refine("CegInstantiation::cegqi_lemmas_refine", 0),
-      d_cegqi_si_lemmas("CegInstantiation::cegqi_lemmas_si", 0),
-      d_solutions("CegConjecture::solutions", 0),
-      d_candidate_rewrites_print("CegConjecture::candidate_rewrites_print", 0),
-      d_candidate_rewrites("CegConjecture::candidate_rewrites", 0)
-
-{
-  smtStatisticsRegistry()->registerStat(&d_cegqi_lemmas_ce);
-  smtStatisticsRegistry()->registerStat(&d_cegqi_lemmas_refine);
-  smtStatisticsRegistry()->registerStat(&d_cegqi_si_lemmas);
-  smtStatisticsRegistry()->registerStat(&d_solutions);
-  smtStatisticsRegistry()->registerStat(&d_candidate_rewrites_print);
-  smtStatisticsRegistry()->registerStat(&d_candidate_rewrites);
-}
-
-CegInstantiation::Statistics::~Statistics(){
-  smtStatisticsRegistry()->unregisterStat(&d_cegqi_lemmas_ce);
-  smtStatisticsRegistry()->unregisterStat(&d_cegqi_lemmas_refine);
-  smtStatisticsRegistry()->unregisterStat(&d_cegqi_si_lemmas);
-  smtStatisticsRegistry()->unregisterStat(&d_solutions);
-  smtStatisticsRegistry()->unregisterStat(&d_candidate_rewrites_print);
-  smtStatisticsRegistry()->unregisterStat(&d_candidate_rewrites);
-}
-
-}/* namespace CVC4::theory::quantifiers */
-}/* namespace CVC4::theory */
-}/* namespace CVC4 */
diff --git a/src/theory/quantifiers/ce_guided_instantiation.h b/src/theory/quantifiers/ce_guided_instantiation.h
deleted file mode 100644 (file)
index 2dc74dc..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*********************                                                        */
-/*! \file ce_guided_instantiation.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief counterexample guided instantiation class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_INSTANTIATION_H
-#define __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_INSTANTIATION_H
-
-#include "context/cdhashmap.h"
-#include "theory/quantifiers/ce_guided_conjecture.h"
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class CegInstantiation : public QuantifiersModule
-{
-  typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
-private:
-  /** the quantified formula stating the synthesis conjecture */
-  CegConjecture * d_conj;
-  /** last instantiation by single invocation module? */
-  bool d_last_inst_si;
-private: //for direct evaluation
-  /** get refinement evaluation */
-  void getCRefEvaluationLemmas( CegConjecture * conj, std::vector< Node >& vs, std::vector< Node >& ms, std::vector< Node >& lems );
-private:
-  /** check conjecture */
-  void checkCegConjecture( CegConjecture * conj );
-public:
-  CegInstantiation( QuantifiersEngine * qe, context::Context* c );
-  ~CegInstantiation();
-public:
-  bool needsCheck( Theory::Effort e );
-  QEffort needsModel(Theory::Effort e);
-  /* Call during quantifier engine's check */
-  void check(Theory::Effort e, QEffort quant_e);
-  /* Called for new quantifiers */
-  void registerQuantifier( Node q );
-  /** get the next decision request */
-  Node getNextDecisionRequest( unsigned& priority );
-  /** Identify this module (for debugging, dynamic configuration, etc..) */
-  std::string identify() const { return "CegInstantiation"; }
-  /** print solution for synthesis conjectures */
-  void printSynthSolution( std::ostream& out );
-  /** get synth solutions
-   *
-   * This function adds entries to sol_map that map functions-to-synthesize
-   * with their solutions, for all active conjectures (currently just the one
-   * assigned to d_conj). This should be called immediately after the solver
-   * answers unsat for sygus input.
-   *
-   * For details on what is added to sol_map, see
-   * CegConjecture::getSynthSolutions.
-   */
-  void getSynthSolutions(std::map<Node, Node>& sol_map);
-  /** preregister assertion (before rewrite) */
-  void preregisterAssertion( Node n );
-public:
-  class Statistics {
-  public:
-    IntStat d_cegqi_lemmas_ce;
-    IntStat d_cegqi_lemmas_refine;
-    IntStat d_cegqi_si_lemmas;
-    IntStat d_solutions;
-    IntStat d_candidate_rewrites_print;
-    IntStat d_candidate_rewrites;
-    Statistics();
-    ~Statistics();
-  };/* class CegInstantiation::Statistics */
-  Statistics d_statistics;
-}; /* class CegInstantiation */
-
-} /* namespace CVC4::theory::quantifiers */
-} /* namespace CVC4::theory */
-} /* namespace CVC4 */
-
-#endif
diff --git a/src/theory/quantifiers/ce_guided_pbe.cpp b/src/theory/quantifiers/ce_guided_pbe.cpp
deleted file mode 100644 (file)
index 7f339be..0000000
+++ /dev/null
@@ -1,2460 +0,0 @@
-/*********************                                                        */
-/*! \file ce_guided_pbe.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief utility for processing programming by examples synthesis conjectures
- **
- **/
-#include "theory/quantifiers/ce_guided_pbe.h"
-
-#include "expr/datatype.h"
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/term_database_sygus.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/datatypes/datatypes_rewriter.h"
-#include "util/random.h"
-
-using namespace CVC4;
-using namespace CVC4::kind;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-void indent( const char * c, int ind ) {
-  if( Trace.isOn(c) ){
-    for( int i=0; i<ind; i++ ){ 
-      Trace(c) << "  "; 
-    }
-  } 
-}
-
-void print_val( const char * c, std::vector< Node >& vals, bool pol = true ){
-  if( Trace.isOn(c) ){
-    for( unsigned i=0; i<vals.size(); i++ ){
-      //Trace(c) << ( pol ? vals[i] : !vals[i] );
-      Trace(c) << ( ( pol ? vals[i].getConst<bool>() : !vals[i].getConst<bool>() ) ? "1" : "0" );
-    }
-  }
-}
-
-std::ostream& operator<<(std::ostream& os, EnumRole r)
-{
-  switch(r){
-    case enum_invalid: os << "INVALID"; break;
-    case enum_io: os << "IO"; break;
-    case enum_ite_condition: os << "CONDITION"; break;
-    case enum_concat_term: os << "CTERM"; break;
-    default: os << "enum_" << static_cast<unsigned>(r); break;
-  }
-  return os;
-}
-
-std::ostream& operator<<(std::ostream& os, NodeRole r)
-{
-  switch (r)
-  {
-    case role_equal: os << "equal"; break;
-    case role_string_prefix: os << "string_prefix"; break;
-    case role_string_suffix: os << "string_suffix"; break;
-    case role_ite_condition: os << "ite_condition"; break;
-    default: os << "role_" << static_cast<unsigned>(r); break;
-  }
-  return os;
-}
-
-EnumRole getEnumeratorRoleForNodeRole(NodeRole r)
-{
-  switch (r)
-  {
-    case role_equal: return enum_io; break;
-    case role_string_prefix: return enum_concat_term; break;
-    case role_string_suffix: return enum_concat_term; break;
-    case role_ite_condition: return enum_ite_condition; break;
-    default: break;
-  }
-  return enum_invalid;
-}
-
-std::ostream& operator<<(std::ostream& os, StrategyType st)
-{
-  switch (st)
-  {
-    case strat_ITE: os << "ITE"; break;
-    case strat_CONCAT_PREFIX: os << "CONCAT_PREFIX"; break;
-    case strat_CONCAT_SUFFIX: os << "CONCAT_SUFFIX"; break;
-    case strat_ID: os << "ID"; break;
-    default: os << "strat_" << static_cast<unsigned>(st); break;
-  }
-  return os;
-}
-
-CegConjecturePbe::CegConjecturePbe(QuantifiersEngine* qe, CegConjecture* p)
-    : d_qe(qe),
-      d_parent(p){
-  d_tds = d_qe->getTermDatabaseSygus();
-  d_true = NodeManager::currentNM()->mkConst(true);
-  d_false = NodeManager::currentNM()->mkConst(false);
-  d_is_pbe = false;
-}
-
-CegConjecturePbe::~CegConjecturePbe() {
-
-}
-
-//--------------------------------- collecting finite input/output domain information
-
-void CegConjecturePbe::collectExamples( Node n, std::map< Node, bool >& visited, bool hasPol, bool pol ) {
-  if( visited.find( n )==visited.end() ){
-    visited[n] = true;
-    Node neval;
-    Node n_output;
-    if( n.getKind()==APPLY_UF && n.getNumChildren()>0 ){
-      neval = n;
-      if( hasPol ){
-        n_output = !pol ? d_true : d_false;
-      }
-    }else if( n.getKind()==EQUAL && hasPol && !pol ){
-      for( unsigned r=0; r<2; r++ ){
-        if( n[r].getKind()==APPLY_UF && n[r].getNumChildren()>0 ){
-          neval = n[r];
-          if( n[1-r].isConst() ){
-            n_output = n[1-r];
-          }
-        }
-      }
-    }
-    if( !neval.isNull() ){
-      if( neval.getKind()==APPLY_UF && neval.getNumChildren()>0 ){
-        // is it an evaluation function?
-        if( d_examples.find( neval[0] )!=d_examples.end() ){
-          std::map< Node, bool >::iterator itx = d_examples_invalid.find( neval[0] );
-          if( itx==d_examples_invalid.end() ){
-            //collect example
-            bool success = true;
-            std::vector< Node > ex;
-            for( unsigned j=1; j<neval.getNumChildren(); j++ ){
-              if( !neval[j].isConst() ){
-                success = false;
-                break;
-              }else{
-                ex.push_back( neval[j] );
-              }
-            }
-            if( success ){
-              d_examples[neval[0]].push_back( ex );
-              d_examples_out[neval[0]].push_back( n_output );
-              d_examples_term[neval[0]].push_back( neval );
-              if( n_output.isNull() ){
-                d_examples_out_invalid[neval[0]] = true;
-              }else{
-                Assert( n_output.isConst() );
-              }
-              //finished processing this node
-              return;
-            }else{
-              d_examples_invalid[neval[0]] = true;
-              d_examples_out_invalid[neval[0]] = true;
-            }
-          }
-        }
-      }
-    }
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      bool newHasPol;
-      bool newPol;
-      QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
-      collectExamples( n[i], visited, newHasPol, newPol );
-    }
-  }
-}
-
-void CegConjecturePbe::initialize(Node n,
-                                  std::vector<Node>& candidates,
-                                  std::vector<Node>& lemmas)
-{
-  Trace("sygus-pbe") << "Initialize PBE : " << n << std::endl;
-  
-  for( unsigned i=0; i<candidates.size(); i++ ){
-    Node v = candidates[i];
-    d_examples[v].clear();
-    d_examples_out[v].clear();
-    d_examples_term[v].clear();
-  }
-  
-  std::map< Node, bool > visited;
-  collectExamples( n, visited, true, true );
-  
-  for( unsigned i=0; i<candidates.size(); i++ ){
-    Node v = candidates[i];
-    Trace("sygus-pbe") << "  examples for " << v << " : ";
-    if( d_examples_invalid.find( v )!=d_examples_invalid.end() ){
-      Trace("sygus-pbe") << "INVALID" << std::endl;
-    }else{
-      Trace("sygus-pbe") << std::endl;
-      for( unsigned j=0; j<d_examples[v].size(); j++ ){
-        Trace("sygus-pbe") << "    ";
-        for( unsigned k=0; k<d_examples[v][j].size(); k++ ){
-          Trace("sygus-pbe") << d_examples[v][j][k] << " ";
-        }
-        if( !d_examples_out[v][j].isNull() ){
-          Trace("sygus-pbe") << " -> " << d_examples_out[v][j];
-        }
-        Trace("sygus-pbe") << std::endl;
-      }
-    }
-  }
-  
-  //register candidates
-  if( options::sygusUnifCondSol() ){
-    if( candidates.size()==1 ){// conditional solutions for multiple function conjectures TODO?
-      // collect a pool of types over which we will enumerate terms 
-      Node c = candidates[0];
-      //the candidate must be input/output examples
-      if( d_examples_out_invalid.find( c )==d_examples_out_invalid.end() ){
-        Assert( d_examples.find( c )!=d_examples.end() );
-        Trace("sygus-unif") << "It is input/output examples..." << std::endl;
-        TypeNode ctn = c.getType();
-        d_cinfo[c].initialize( c );
-        // collect the enumerator types / form the strategy
-        collectEnumeratorTypes(c, ctn, role_equal);
-        // if we have non-trivial strategies, then use pbe
-        if( d_cinfo[c].isNonTrivial() ){
-          // static learning of redundant constructors
-          staticLearnRedundantOps( c, lemmas );
-          d_is_pbe = true;
-        }
-      }
-    }
-  }
-  if( !d_is_pbe ){
-    Trace("sygus-unif") << "Do not do PBE optimizations, register..." << std::endl;
-    for( unsigned i=0; i<candidates.size(); i++ ){
-      d_qe->getTermDatabaseSygus()->registerEnumerator(
-          candidates[i], candidates[i], d_parent);
-    }
-  }
-}
-
-Node CegConjecturePbe::PbeTrie::addPbeExample(TypeNode etn, Node e, Node b,
-                                              CegConjecturePbe* cpbe,
-                                              unsigned index, unsigned ntotal) {
-  if (index == ntotal) {
-    // lazy child holds the leaf data
-    if (d_lazy_child.isNull()) {
-      d_lazy_child = b;
-    }
-    return d_lazy_child;
-  } else {
-    std::vector<Node> ex;
-    if (d_children.empty()) {
-      if (d_lazy_child.isNull()) {
-        d_lazy_child = b;
-        return d_lazy_child;
-      } else {
-        // evaluate the lazy child
-        Assert(cpbe->d_examples.find(e) != cpbe->d_examples.end());
-        Assert(index < cpbe->d_examples[e].size());
-        ex = cpbe->d_examples[e][index];
-        addPbeExampleEval(etn, e, d_lazy_child, ex, cpbe, index, ntotal);
-        Assert(!d_children.empty());
-        d_lazy_child = Node::null();
-      }
-    } else {
-      Assert(cpbe->d_examples.find(e) != cpbe->d_examples.end());
-      Assert(index < cpbe->d_examples[e].size());
-      ex = cpbe->d_examples[e][index];
-    }
-    return addPbeExampleEval(etn, e, b, ex, cpbe, index, ntotal);
-  }
-}
-
-Node CegConjecturePbe::PbeTrie::addPbeExampleEval(TypeNode etn, Node e, Node b,
-                                                  std::vector<Node>& ex,
-                                                  CegConjecturePbe* cpbe,
-                                                  unsigned index,
-                                                  unsigned ntotal) {
-  Node eb = cpbe->d_tds->evaluateBuiltin(etn, b, ex);
-  return d_children[eb].addPbeExample(etn, e, b, cpbe, index + 1, ntotal);
-}
-
-bool CegConjecturePbe::hasExamples(Node e) {
-  if (isPbe()) {
-    e = d_tds->getSynthFunForEnumerator(e);
-    Assert(!e.isNull());
-    std::map<Node, bool>::iterator itx = d_examples_invalid.find(e);
-    if (itx == d_examples_invalid.end()) {
-      return d_examples.find(e) != d_examples.end();
-    }
-  }
-  return false;
-}
-
-unsigned CegConjecturePbe::getNumExamples(Node e) {
-  e = d_tds->getSynthFunForEnumerator(e);
-  Assert(!e.isNull());
-  std::map<Node, std::vector<std::vector<Node> > >::iterator it =
-      d_examples.find(e);
-  if (it != d_examples.end()) {
-    return it->second.size();
-  } else {
-    return 0;
-  }
-}
-
-void CegConjecturePbe::getExample(Node e, unsigned i, std::vector<Node>& ex) {
-  e = d_tds->getSynthFunForEnumerator(e);
-  Assert(!e.isNull());
-  std::map<Node, std::vector<std::vector<Node> > >::iterator it =
-      d_examples.find(e);
-  if (it != d_examples.end()) {
-    Assert(i < it->second.size());
-    ex.insert(ex.end(), it->second[i].begin(), it->second[i].end());
-  } else {
-    Assert(false);
-  }
-}
-
-Node CegConjecturePbe::getExampleOut(Node e, unsigned i) {
-  e = d_tds->getSynthFunForEnumerator(e);
-  Assert(!e.isNull());
-  std::map<Node, std::vector<Node> >::iterator it = d_examples_out.find(e);
-  if (it != d_examples_out.end()) {
-    Assert(i < it->second.size());
-    return it->second[i];
-  } else {
-    Assert(false);
-    return Node::null();
-  }
-}
-
-Node CegConjecturePbe::addSearchVal(TypeNode tn, Node e, Node bvr) {
-  Assert(isPbe());
-  Assert(!e.isNull());
-  e = d_tds->getSynthFunForEnumerator(e);
-  Assert(!e.isNull());
-  std::map<Node, bool>::iterator itx = d_examples_invalid.find(e);
-  if (itx == d_examples_invalid.end()) {
-    unsigned nex = d_examples[e].size();
-    Node ret = d_pbe_trie[e][tn].addPbeExample(tn, e, bvr, this, 0, nex);
-    Assert(ret.getType() == bvr.getType());
-    return ret;
-  }
-  return Node::null();
-}
-
-Node CegConjecturePbe::evaluateBuiltin(TypeNode tn, Node bn, Node e,
-                                       unsigned i) {
-  e = d_tds->getSynthFunForEnumerator(e);
-  Assert(!e.isNull());
-  std::map<Node, bool>::iterator itx = d_examples_invalid.find(e);
-  if (itx == d_examples_invalid.end()) {
-    std::map<Node, std::vector<std::vector<Node> > >::iterator it =
-        d_examples.find(e);
-    if (it != d_examples.end()) {
-      Assert(i < it->second.size());
-      return d_tds->evaluateBuiltin(tn, bn, it->second[i]);
-    }
-  }
-  return Rewriter::rewrite(bn);
-}
-
-// ----------------------------- establishing enumeration types
-
-void CegConjecturePbe::registerEnumerator(
-    Node et, Node c, TypeNode tn, EnumRole enum_role, bool inSearch)
-{
-  if (d_einfo.find(et) == d_einfo.end())
-  {
-    Trace("sygus-unif-debug")
-        << "...register " << et << " for "
-        << ((DatatypeType)tn.toType()).getDatatype().getName();
-    Trace("sygus-unif-debug") << ", role = " << enum_role
-                              << ", in search = " << inSearch << std::endl;
-    d_einfo[et].initialize(c, enum_role);
-    // if we are actually enumerating this (could be a compound node in the
-    // strategy)
-    if (inSearch)
-    {
-      std::map<TypeNode, Node>::iterator itn =
-          d_cinfo[c].d_search_enum.find(tn);
-      if (itn == d_cinfo[c].d_search_enum.end())
-      {
-        // use this for the search
-        d_cinfo[c].d_search_enum[tn] = et;
-        d_cinfo[c].d_esym_list.push_back(et);
-        d_einfo[et].d_enum_slave.push_back(et);
-        // register measured term with database
-        d_qe->getTermDatabaseSygus()->registerEnumerator(et, c, d_parent, true);
-        d_einfo[et].d_active_guard =
-            d_qe->getTermDatabaseSygus()->getActiveGuardForEnumerator(et);
-      }
-      else
-      {
-        Trace("sygus-unif-debug") << "Make " << et << " a slave of "
-                                  << itn->second << std::endl;
-        d_einfo[itn->second].d_enum_slave.push_back(et);
-      }
-    }
-  }
-}
-
-void CegConjecturePbe::collectEnumeratorTypes(Node e,
-                                              TypeNode tn,
-                                              NodeRole nrole)
-{
-  NodeManager* nm = NodeManager::currentNM();
-  if (d_cinfo[e].d_tinfo.find(tn) == d_cinfo[e].d_tinfo.end())
-  {
-    // register type
-    Trace("sygus-unif") << "Register enumerating type : " << tn << std::endl;
-    d_cinfo[e].initializeType( tn );
-  }
-  EnumTypeInfo& eti = d_cinfo[e].d_tinfo[tn];
-  std::map<NodeRole, StrategyNode>::iterator itsn = eti.d_snodes.find(nrole);
-  if (itsn != eti.d_snodes.end())
-  {
-    // already initialized
-    return;
-  }
-  StrategyNode& snode = eti.d_snodes[nrole];
-
-  // get the enumerator for this
-  EnumRole erole = getEnumeratorRoleForNodeRole(nrole);
-
-  Node ee;
-  std::map<EnumRole, Node>::iterator iten = eti.d_enum.find(erole);
-  if (iten == eti.d_enum.end())
-  {
-    ee = nm->mkSkolem("ee", tn);
-    eti.d_enum[erole] = ee;
-    Trace("sygus-unif-debug")
-        << "...enumerator " << ee << " for "
-        << ((DatatypeType)tn.toType()).getDatatype().getName()
-        << ", role = " << erole << std::endl;
-  }
-  else
-  {
-    ee = iten->second;
-  }
-
-  // roles that we do not recurse on
-  if (nrole == role_ite_condition)
-  {
-    Trace("sygus-unif-debug") << "...this register (non-io)" << std::endl;
-    registerEnumerator(ee, e, tn, erole, true);
-    return;
-  }
-
-  // look at information on how we will construct solutions for this type
-  Assert(tn.isDatatype());
-  const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
-  Assert(dt.isSygus());
-
-  std::map<Node, std::vector<StrategyType> > cop_to_strat;
-  std::map<Node, unsigned> cop_to_cindex;
-  std::map<Node, std::map<unsigned, Node> > cop_to_child_templ;
-  std::map<Node, std::map<unsigned, Node> > cop_to_child_templ_arg;
-  std::map<Node, std::vector<unsigned> > cop_to_carg_list;
-  std::map<Node, std::vector<TypeNode> > cop_to_child_types;
-  std::map<Node, std::vector<Node> > cop_to_sks;
-
-  // whether we will enumerate the current type
-  bool search_this = false;
-  for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++)
-  {
-    Node cop = Node::fromExpr(dt[j].getConstructor());
-    Node op = Node::fromExpr(dt[j].getSygusOp());
-    Trace("sygus-unif-debug") << "--- Infer strategy from " << cop
-                              << " with sygus op " << op << "..." << std::endl;
-
-    // expand the evaluation to see if this constuctor induces a strategy
-    std::vector<Node> utchildren;
-    utchildren.push_back(cop);
-    std::vector<Node> sks;
-    std::vector<TypeNode> sktns;
-    for (unsigned k = 0, nargs = dt[j].getNumArgs(); k < nargs; k++)
-    {
-      Type t = dt[j][k].getRangeType();
-      TypeNode ttn = TypeNode::fromType(t);
-      Node kv = nm->mkSkolem("ut", ttn);
-      sks.push_back(kv);
-      cop_to_sks[cop].push_back(kv);
-      sktns.push_back(ttn);
-      utchildren.push_back(kv);
-    }
-    Node ut = nm->mkNode(APPLY_CONSTRUCTOR, utchildren);
-    std::vector<Node> echildren;
-    echildren.push_back(Node::fromExpr(dt.getSygusEvaluationFunc()));
-    echildren.push_back(ut);
-    Node sbvl = Node::fromExpr(dt.getSygusVarList());
-    for (const Node& sbv : sbvl)
-    {
-      echildren.push_back(sbv);
-    }
-    Node eut = nm->mkNode(APPLY_UF, echildren);
-    Trace("sygus-unif-debug2") << "  Test evaluation of " << eut << "..."
-                               << std::endl;
-    eut = d_qe->getTermDatabaseSygus()->unfold(eut);
-    Trace("sygus-unif-debug2") << "  ...got " << eut;
-    Trace("sygus-unif-debug2") << ", type : " << eut.getType() << std::endl;
-
-    // candidate strategy
-    if (eut.getKind() == ITE)
-    {
-      cop_to_strat[cop].push_back(strat_ITE);
-    }
-    else if (eut.getKind() == STRING_CONCAT)
-    {
-      if (nrole != role_string_suffix)
-      {
-        cop_to_strat[cop].push_back(strat_CONCAT_PREFIX);
-      }
-      if (nrole != role_string_prefix)
-      {
-        cop_to_strat[cop].push_back(strat_CONCAT_SUFFIX);
-      }
-    }
-    else if (dt[j].isSygusIdFunc())
-    {
-      cop_to_strat[cop].push_back(strat_ID);
-    }
-
-    // the kinds for which there is a strategy
-    if (cop_to_strat.find(cop) != cop_to_strat.end())
-    {
-      // infer an injection from the arguments of the datatype
-      std::map<unsigned, unsigned> templ_injection;
-      std::vector<Node> vs;
-      std::vector<Node> ss;
-      std::map<Node, unsigned> templ_var_index;
-      for (unsigned k = 0, sksize = sks.size(); k < sksize; k++)
-      {
-        Assert(sks[k].getType().isDatatype());
-        const Datatype& cdt =
-            static_cast<DatatypeType>(sks[k].getType().toType()).getDatatype();
-        echildren[0] = Node::fromExpr(cdt.getSygusEvaluationFunc());
-        echildren[1] = sks[k];
-        Trace("sygus-unif-debug2") << "...set eval dt to " << sks[k]
-                                   << std::endl;
-        Node esk = nm->mkNode(APPLY_UF, echildren);
-        vs.push_back(esk);
-        Node tvar = nm->mkSkolem("templ", esk.getType());
-        templ_var_index[tvar] = k;
-        Trace("sygus-unif-debug2") << "* template inference : looking for "
-                                   << tvar << " for arg " << k << std::endl;
-        ss.push_back(tvar);
-        Trace("sygus-unif-debug2") << "* substitute : " << esk << " -> " << tvar
-                                   << std::endl;
-      }
-      eut = eut.substitute(vs.begin(), vs.end(), ss.begin(), ss.end());
-      Trace("sygus-unif-debug2") << "Constructor " << j << ", base term is "
-                                 << eut << std::endl;
-      std::map<unsigned, Node> test_args;
-      if (dt[j].isSygusIdFunc())
-      {
-        test_args[0] = eut;
-      }
-      else
-      {
-        for (unsigned k = 0, size = eut.getNumChildren(); k < size; k++)
-        {
-          test_args[k] = eut[k];
-        }
-      }
-
-      // TODO : prefix grouping prefix/suffix
-      bool isAssoc = TermUtil::isAssoc(eut.getKind());
-      Trace("sygus-unif-debug2") << eut.getKind() << " isAssoc = " << isAssoc
-                                 << std::endl;
-      std::map<unsigned, std::vector<unsigned> > assoc_combine;
-      std::vector<unsigned> assoc_waiting;
-      int assoc_last_valid_index = -1;
-      for (std::pair<const unsigned, Node>& ta : test_args)
-      {
-        unsigned k = ta.first;
-        Node eut_c = ta.second;
-        // success if we can find a injection from args to sygus args
-        if (!inferTemplate(k, eut_c, templ_var_index, templ_injection))
-        {
-          Trace("sygus-unif-debug")
-              << "...fail: could not find injection (range)." << std::endl;
-          cop_to_strat.erase(cop);
-          break;
-        }
-        std::map<unsigned, unsigned>::iterator itti = templ_injection.find(k);
-        if (itti != templ_injection.end())
-        {
-          // if associative, combine arguments if it is the same variable
-          if (isAssoc && assoc_last_valid_index >= 0
-              && itti->second == templ_injection[assoc_last_valid_index])
-          {
-            templ_injection.erase(k);
-            assoc_combine[assoc_last_valid_index].push_back(k);
-          }
-          else
-          {
-            assoc_last_valid_index = (int)k;
-            if (!assoc_waiting.empty())
-            {
-              assoc_combine[k].insert(assoc_combine[k].end(),
-                                      assoc_waiting.begin(),
-                                      assoc_waiting.end());
-              assoc_waiting.clear();
-            }
-            assoc_combine[k].push_back(k);
-          }
-        }
-        else
-        {
-          // a ground argument
-          if (!isAssoc)
-          {
-            Trace("sygus-unif-debug")
-                << "...fail: could not find injection (functional)."
-                << std::endl;
-            cop_to_strat.erase(cop);
-            break;
-          }
-          else
-          {
-            if (assoc_last_valid_index >= 0)
-            {
-              assoc_combine[assoc_last_valid_index].push_back(k);
-            }
-            else
-            {
-              assoc_waiting.push_back(k);
-            }
-          }
-        }
-      }
-      if (cop_to_strat.find(cop) != cop_to_strat.end())
-      {
-        // construct the templates
-        if (!assoc_waiting.empty())
-        {
-          // could not find a way to fit some arguments into injection
-          cop_to_strat.erase(cop);
-        }
-        else
-        {
-          for (std::pair<const unsigned, Node>& ta : test_args)
-          {
-            unsigned k = ta.first;
-            Trace("sygus-unif-debug2") << "- processing argument " << k << "..."
-                                       << std::endl;
-            if (templ_injection.find(k) != templ_injection.end())
-            {
-              unsigned sk_index = templ_injection[k];
-              if (std::find(cop_to_carg_list[cop].begin(),
-                            cop_to_carg_list[cop].end(),
-                            sk_index)
-                  == cop_to_carg_list[cop].end())
-              {
-                cop_to_carg_list[cop].push_back(sk_index);
-              }else{
-                Trace("sygus-unif-debug") << "...fail: duplicate argument used"
-                                          << std::endl;
-                cop_to_strat.erase(cop);
-                break;
-              }
-              // also store the template information, if necessary
-              Node teut;
-              if (isAssoc)
-              {
-                std::vector<unsigned>& ac = assoc_combine[k];
-                Assert(!ac.empty());
-                std::vector<Node> children;
-                for (unsigned ack = 0, size_ac = ac.size(); ack < size_ac;
-                     ack++)
-                {
-                  children.push_back(eut[ac[ack]]);
-                }
-                teut = children.size() == 1
-                           ? children[0]
-                           : nm->mkNode(eut.getKind(), children);
-                teut = Rewriter::rewrite(teut);
-              }
-              else
-              {
-                teut = ta.second;
-              }
-
-              if (!teut.isVar())
-              {
-                cop_to_child_templ[cop][k] = teut;
-                cop_to_child_templ_arg[cop][k] = ss[sk_index];
-                Trace("sygus-unif-debug")
-                    << "  Arg " << k << " (template : " << teut << " arg "
-                    << ss[sk_index] << "), index " << sk_index << std::endl;
-              }
-              else
-              {
-                Trace("sygus-unif-debug") << "  Arg " << k << ", index "
-                                          << sk_index << std::endl;
-                Assert(teut == ss[sk_index]);
-              }
-            }
-            else
-            {
-              Assert(isAssoc);
-            }
-          }
-        }
-      }
-    }
-    if (cop_to_strat.find(cop) == cop_to_strat.end())
-    {
-      Trace("sygus-unif") << "...constructor " << cop
-                          << " does not correspond to a strategy." << std::endl;
-      search_this = true;
-    }
-    else
-    {
-      Trace("sygus-unif") << "-> constructor " << cop
-                          << " matches strategy for " << eut.getKind() << "..."
-                          << std::endl;
-      // collect children types
-      for (unsigned k = 0, size = cop_to_carg_list[cop].size(); k < size; k++)
-      {
-        TypeNode tn = sktns[cop_to_carg_list[cop][k]];
-        Trace("sygus-unif-debug")
-            << "   Child type " << k << " : "
-            << static_cast<DatatypeType>(tn.toType()).getDatatype().getName()
-            << std::endl;
-        cop_to_child_types[cop].push_back(tn);
-      }
-    }
-  }
-
-  // check whether we should also enumerate the current type
-  Trace("sygus-unif-debug2") << "  register this enumerator..." << std::endl;
-  registerEnumerator(ee, e, tn, erole, search_this);
-
-  if (cop_to_strat.empty())
-  {
-    Trace("sygus-unif") << "...consider " << dt.getName() << " a basic type"
-                        << std::endl;
-  }
-  else
-  {
-    for (std::pair<const Node, std::vector<StrategyType> >& cstr : cop_to_strat)
-    {
-      Node cop = cstr.first;
-      Trace("sygus-unif-debug") << "Constructor " << cop << " has "
-                                << cstr.second.size() << " strategies..."
-                                << std::endl;
-      for (unsigned s = 0, ssize = cstr.second.size(); s < ssize; s++)
-      {
-        EnumTypeInfoStrat* cons_strat = new EnumTypeInfoStrat;
-        StrategyType strat = cstr.second[s];
-
-        cons_strat->d_this = strat;
-        cons_strat->d_cons = cop;
-        Trace("sygus-unif-debug") << "Process strategy #" << s
-                                  << " for operator : " << cop << " : " << strat
-                                  << std::endl;
-        Assert(cop_to_child_types.find(cop) != cop_to_child_types.end());
-        std::vector<TypeNode>& childTypes = cop_to_child_types[cop];
-        Assert(cop_to_carg_list.find(cop) != cop_to_carg_list.end());
-        std::vector<unsigned>& cargList = cop_to_carg_list[cop];
-
-        std::vector<Node> sol_templ_children;
-        sol_templ_children.resize(cop_to_sks[cop].size());
-
-        for (unsigned j = 0, csize = childTypes.size(); j < csize; j++)
-        {
-          // calculate if we should allocate a new enumerator : should be true
-          // if we have a new role
-          NodeRole nrole_c = nrole;
-          if (strat == strat_ITE)
-          {
-            if (j == 0)
-            {
-              nrole_c = role_ite_condition;
-            }
-          }
-          else if (strat == strat_CONCAT_PREFIX)
-          {
-            if ((j + 1) < childTypes.size())
-            {
-              nrole_c = role_string_prefix;
-            }
-          }
-          else if (strat == strat_CONCAT_SUFFIX)
-          {
-            if (j > 0)
-            {
-              nrole_c = role_string_suffix;
-            }
-          }
-          // in all other cases, role is same as parent
-
-          // register the child type
-          TypeNode ct = childTypes[j];
-          Node csk = cop_to_sks[cop][cargList[j]];
-          cons_strat->d_sol_templ_args.push_back(csk);
-          sol_templ_children[cargList[j]] = csk;
-
-          EnumRole erole_c = getEnumeratorRoleForNodeRole(nrole_c);
-          // make the enumerator
-          Node et;
-          if (cop_to_child_templ[cop].find(j) != cop_to_child_templ[cop].end())
-          {
-            // it is templated, allocate a fresh variable
-            et = nm->mkSkolem("et", ct);
-            Trace("sygus-unif-debug")
-                << "...enumerate " << et << " of type "
-                << ((DatatypeType)ct.toType()).getDatatype().getName();
-            Trace("sygus-unif-debug")
-                << " for arg " << j << " of "
-                << ((DatatypeType)tn.toType()).getDatatype().getName()
-                << std::endl;
-            registerEnumerator(et, e, ct, erole_c, true);
-            d_einfo[et].d_template = cop_to_child_templ[cop][j];
-            d_einfo[et].d_template_arg = cop_to_child_templ_arg[cop][j];
-            Assert(!d_einfo[et].d_template.isNull());
-            Assert(!d_einfo[et].d_template_arg.isNull());
-          }
-          else
-          {
-            Trace("sygus-unif-debug")
-                << "...child type enumerate "
-                << ((DatatypeType)ct.toType()).getDatatype().getName()
-                << ", node role = " << nrole_c << std::endl;
-            collectEnumeratorTypes(e, ct, nrole_c);
-            // otherwise use the previous
-            Assert(d_cinfo[e].d_tinfo[ct].d_enum.find(erole_c)
-                   != d_cinfo[e].d_tinfo[ct].d_enum.end());
-            et = d_cinfo[e].d_tinfo[ct].d_enum[erole_c];
-          }
-          Trace("sygus-unif-debug") << "Register child enumerator " << et
-                                    << ", arg " << j << " of " << cop
-                                    << ", role = " << erole_c << std::endl;
-          Assert(!et.isNull());
-          cons_strat->d_cenum.push_back(std::pair<Node, NodeRole>(et, nrole_c));
-        }
-        // children that are unused in the strategy can be arbitrary
-        for (unsigned j = 0, stsize = sol_templ_children.size(); j < stsize;
-             j++)
-        {
-          if (sol_templ_children[j].isNull())
-          {
-            sol_templ_children[j] = cop_to_sks[cop][j].getType().mkGroundTerm();
-          }
-        }
-        sol_templ_children.insert(sol_templ_children.begin(), cop);
-        cons_strat->d_sol_templ =
-            nm->mkNode(APPLY_CONSTRUCTOR, sol_templ_children);
-        if (strat == strat_CONCAT_SUFFIX)
-        {
-          std::reverse(cons_strat->d_cenum.begin(), cons_strat->d_cenum.end());
-          std::reverse(cons_strat->d_sol_templ_args.begin(),
-                       cons_strat->d_sol_templ_args.end());
-        }
-        if (Trace.isOn("sygus-unif"))
-        {
-          Trace("sygus-unif") << "Initialized strategy " << strat;
-          Trace("sygus-unif") << " for " << ((DatatypeType)tn.toType()).getDatatype().getName() << ", operator " << cop;
-          Trace("sygus-unif") << ", #children = " << cons_strat->d_cenum.size()
-                              << ", solution template = (lambda ( ";
-          for (const Node& targ : cons_strat->d_sol_templ_args)
-          {
-            Trace("sygus-unif") << targ << " ";
-          }
-          Trace("sygus-unif") << ") " << cons_strat->d_sol_templ << ")";
-          Trace("sygus-unif") << std::endl;
-        }
-        // make the strategy
-        snode.d_strats.push_back(cons_strat);
-      }
-    }
-  }
-}
-
-bool CegConjecturePbe::inferTemplate( unsigned k, Node n, std::map< Node, unsigned >& templ_var_index, std::map< unsigned, unsigned >& templ_injection ){
-  if( n.getNumChildren()==0 ){
-    std::map< Node, unsigned >::iterator itt = templ_var_index.find( n );
-    if( itt!=templ_var_index.end() ){
-      unsigned kk = itt->second;
-      std::map< unsigned, unsigned >::iterator itti = templ_injection.find( k );
-      if( itti==templ_injection.end() ){
-        Trace("sygus-unif-debug") << "...set template injection " << k <<  " -> " << kk << std::endl;
-        templ_injection[k] = kk;
-      }else if( itti->second!=kk ){
-        // two distinct variables in this term, we fail
-        return false;
-      }
-    }
-    return true;
-  }else{
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      if( !inferTemplate( k, n[i], templ_var_index, templ_injection ) ){
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-void CegConjecturePbe::staticLearnRedundantOps( Node c, std::vector< Node >& lemmas ) {
-  for( unsigned i=0; i<d_cinfo[c].d_esym_list.size(); i++ ){
-    Node e = d_cinfo[c].d_esym_list[i];
-    std::map< Node, EnumInfo >::iterator itn = d_einfo.find( e );
-    Assert( itn!=d_einfo.end() );
-    // see if there is anything we can eliminate
-    Trace("sygus-unif") << "* Search enumerator #" << i << " : type " << ((DatatypeType)e.getType().toType()).getDatatype().getName() << " : ";
-    Trace("sygus-unif") << e << " has " << itn->second.d_enum_slave.size() << " slaves:" << std::endl;
-    for( unsigned j=0; j<itn->second.d_enum_slave.size(); j++ ){
-      Node es = itn->second.d_enum_slave[j];
-      std::map< Node, EnumInfo >::iterator itns = d_einfo.find( es );
-      Assert( itns!=d_einfo.end() );
-      Trace("sygus-unif") << "  " << es << ", role = " << itns->second.getRole()
-                          << std::endl;
-    }
-  }
-  Trace("sygus-unif") << std::endl;
-  Trace("sygus-unif") << "Strategy for candidate " << c << " is : " << std::endl;
-  std::map<Node, std::map<NodeRole, bool> > visited;
-  std::map<Node, std::map<unsigned, bool> > needs_cons;
-  staticLearnRedundantOps(c,
-                          d_cinfo[c].getRootEnumerator(),
-                          role_equal,
-                          visited,
-                          needs_cons,
-                          0,
-                          false);
-  // now, check the needs_cons map
-  for (std::pair<const Node, std::map<unsigned, bool> >& nce : needs_cons)
-  {
-    Node em = nce.first;
-    const Datatype& dt =
-        static_cast<DatatypeType>(em.getType().toType()).getDatatype();
-    for (std::pair<const unsigned, bool>& nc : nce.second)
-    {
-      Assert(nc.first < dt.getNumConstructors());
-      if (!nc.second)
-      {
-        Node tst =
-            datatypes::DatatypesRewriter::mkTester(em, nc.first, dt).negate();
-        if (std::find(lemmas.begin(), lemmas.end(), tst) == lemmas.end())
-        {
-          Trace("sygus-unif") << "...can exclude based on  : " << tst
-                              << std::endl;
-          lemmas.push_back(tst);
-        }
-      }
-    }
-  }
-}
-
-void CegConjecturePbe::staticLearnRedundantOps(
-    Node c,
-    Node e,
-    NodeRole nrole,
-    std::map<Node, std::map<NodeRole, bool> >& visited,
-    std::map<Node, std::map<unsigned, bool> >& needs_cons,
-    int ind,
-    bool isCond)
-{
-  std::map< Node, EnumInfo >::iterator itn = d_einfo.find( e );
-  Assert( itn!=d_einfo.end() );
-
-  if (visited[e].find(nrole) == visited[e].end()
-      || (isCond && !itn->second.isConditional()))
-  {
-    visited[e][nrole] = true;
-    // if conditional
-    if (isCond)
-    {
-      itn->second.setConditional();
-    }
-    indent("sygus-unif", ind);
-    Trace("sygus-unif") << e << " :: node role : " << nrole;
-    Trace("sygus-unif")
-        << ", type : "
-        << ((DatatypeType)e.getType().toType()).getDatatype().getName();
-    if (isCond)
-    {
-      Trace("sygus-unif") << ", conditional";
-    }
-    Trace("sygus-unif") << ", enum role : " << itn->second.getRole();
-
-    if( itn->second.isTemplated() ){
-      Trace("sygus-unif") << ", templated : (lambda "
-                          << itn->second.d_template_arg << " "
-                          << itn->second.d_template << ")" << std::endl;
-    }else{
-      Trace("sygus-unif") << std::endl;
-      TypeNode etn = e.getType();
-
-      // enumerator type info
-      std::map< TypeNode, EnumTypeInfo >::iterator itt = d_cinfo[c].d_tinfo.find( etn );
-      Assert( itt!=d_cinfo[c].d_tinfo.end() );
-      EnumTypeInfo& tinfo = itt->second;
-
-      // strategy info
-      std::map<NodeRole, StrategyNode>::iterator itsn =
-          tinfo.d_snodes.find(nrole);
-      Assert(itsn != tinfo.d_snodes.end());
-      StrategyNode& snode = itsn->second;
-
-      if (snode.d_strats.empty())
-      {
-        return;
-      }
-      std::map<unsigned, bool> needs_cons_curr;
-      // various strategies
-      for (unsigned j = 0, size = snode.d_strats.size(); j < size; j++)
-      {
-        EnumTypeInfoStrat* etis = snode.d_strats[j];
-        StrategyType strat = etis->d_this;
-        bool newIsCond = isCond || strat == strat_ITE;
-        indent("sygus-unif", ind + 1);
-        Trace("sygus-unif") << "Strategy : " << strat
-                            << ", from cons : " << etis->d_cons << std::endl;
-        int cindex = Datatype::indexOf(etis->d_cons.toExpr());
-        Assert(cindex != -1);
-        needs_cons_curr[static_cast<unsigned>(cindex)] = false;
-        for (std::pair<Node, NodeRole>& cec : etis->d_cenum)
-        {
-          // recurse
-          staticLearnRedundantOps(c,
-                                  cec.first,
-                                  cec.second,
-                                  visited,
-                                  needs_cons,
-                                  ind + 2,
-                                  newIsCond);
-        }
-      }
-      // get the master enumerator for the type of this enumerator
-      std::map<TypeNode, Node>::iterator itse =
-          d_cinfo[c].d_search_enum.find(etn);
-      if (itse == d_cinfo[c].d_search_enum.end())
-      {
-        return;
-      }
-      Node em = itse->second;
-      Assert(!em.isNull());
-      // get the current datatype
-      const Datatype& dt =
-          static_cast<DatatypeType>(etn.toType()).getDatatype();
-      // all constructors that are not a part of a strategy are needed
-      for (unsigned j = 0, size = dt.getNumConstructors(); j < size; j++)
-      {
-        if (needs_cons_curr.find(j) == needs_cons_curr.end())
-        {
-          needs_cons_curr[j] = true;
-        }
-      }
-      // update the constructors that the master enumerator needs
-      if (needs_cons.find(em) == needs_cons.end())
-      {
-        needs_cons[em] = needs_cons_curr;
-      }
-      else
-      {
-        for (unsigned j = 0, size = dt.getNumConstructors(); j < size; j++)
-        {
-          needs_cons[em][j] = needs_cons[em][j] || needs_cons_curr[j];
-        }
-      }
-    }
-  }else{
-    indent("sygus-unif", ind);
-    Trace("sygus-unif") << e << " :: node role : " << nrole << std::endl;
-  }
-}
-
-// ------------------------------------------- solution construction from enumeration
-
-void CegConjecturePbe::getCandidateList( std::vector< Node >& candidates, std::vector< Node >& clist ) {
-  Valuation& valuation = d_qe->getValuation();
-  for( unsigned i=0; i<candidates.size(); i++ ){
-    Node v = candidates[i];
-    std::map< Node, CandidateInfo >::iterator it = d_cinfo.find( v );
-    if( it!=d_cinfo.end() ){
-      for( unsigned j=0; j<it->second.d_esym_list.size(); j++ ){
-        Node e = it->second.d_esym_list[j];
-        std::map< Node, EnumInfo >::iterator it = d_einfo.find( e );
-        Assert( it != d_einfo.end() );
-        Node gstatus = valuation.getSatValue(it->second.d_active_guard);
-        if (!gstatus.isNull() && gstatus.getConst<bool>())
-        {
-          clist.push_back( e );
-        }
-      }
-    }
-  }
-}
-
-bool CegConjecturePbe::constructCandidates( std::vector< Node >& enums, std::vector< Node >& enum_values, 
-                                            std::vector< Node >& candidates, std::vector< Node >& candidate_values, 
-                                            std::vector< Node >& lems ) {
-  Assert( enums.size()==enum_values.size() );
-  if( !enums.empty() ){
-    unsigned min_term_size = 0;
-    std::vector< unsigned > enum_consider;
-    Trace("sygus-pbe-enum") << "Register new enumerated values : " << std::endl;
-    for( unsigned i=0; i<enums.size(); i++ ){
-      Trace("sygus-pbe-enum") << "  " << enums[i] << " -> " << enum_values[i] << std::endl;
-      unsigned sz = d_tds->getSygusTermSize( enum_values[i] );
-      if( i==0 || sz<min_term_size ){
-        enum_consider.clear();
-        min_term_size = sz;
-        enum_consider.push_back( i );
-      }else if( sz==min_term_size ){
-        enum_consider.push_back( i );
-      }
-    }
-    // only consider the enumerators that are at minimum size (for fairness)
-    Trace("sygus-pbe-enum") << "...register " << enum_consider.size() << " / " << enums.size() << std::endl;
-    for( unsigned i=0; i<enum_consider.size(); i++ ){
-      unsigned j = enum_consider[i];
-      addEnumeratedValue( enums[j], enum_values[j], lems );
-    }
-  }
-  for( unsigned i=0; i<candidates.size(); i++ ){
-    Node c = candidates[i];
-    //build decision tree for candidate
-    Node vc = constructSolution( c );
-    if( vc.isNull() ){     
-      return false;
-    }else{
-      candidate_values.push_back( vc );
-    }
-  }
-  return true;
-}
-
-void CegConjecturePbe::addEnumeratedValue( Node x, Node v, std::vector< Node >& lems ) {
-  std::map< Node, EnumInfo >::iterator it = d_einfo.find( x );
-  Assert( it != d_einfo.end() );
-  Node gstatus = d_qe->getValuation().getSatValue(it->second.d_active_guard);
-  if (gstatus.isNull() || !gstatus.getConst<bool>())
-  {
-    Trace("sygus-pbe-enum-debug") << "  ...guard is inactive." << std::endl;
-    return;
-  }
-  Assert(
-      std::find(it->second.d_enum_vals.begin(), it->second.d_enum_vals.end(), v)
-      == it->second.d_enum_vals.end());
-  Node c = it->second.d_parent_candidate;
-  // The explanation for why the current value should be excluded in future
-  // iterations.
-  Node exp_exc;
-  if (d_examples_out_invalid.find(c) == d_examples_out_invalid.end())
-  {
-    std::map<Node, CandidateInfo>::iterator itc = d_cinfo.find(c);
-    Assert(itc != d_cinfo.end());
-    TypeNode xtn = x.getType();
-    Node bv = d_tds->sygusToBuiltin(v, xtn);
-    std::map<Node, std::vector<std::vector<Node> > >::iterator itx =
-        d_examples.find(c);
-    std::map<Node, std::vector<Node> >::iterator itxo = d_examples_out.find(c);
-    Assert(itx != d_examples.end());
-    Assert(itxo != d_examples_out.end());
-    Assert(itx->second.size() == itxo->second.size());
-    std::vector<Node> base_results;
-    // compte the results
-    for (unsigned j = 0, size = itx->second.size(); j < size; j++)
-    {
-      Node res = d_tds->evaluateBuiltin(xtn, bv, itx->second[j]);
-      Trace("sygus-pbe-enum-debug")
-          << "...got res = " << res << " from " << bv << std::endl;
-      base_results.push_back(res);
-    }
-    // is it excluded for domain-specific reason?
-    std::vector<Node> exp_exc_vec;
-    if (getExplanationForEnumeratorExclude(
-            c, x, v, base_results, it->second, exp_exc_vec))
-    {
-      Assert(!exp_exc_vec.empty());
-      exp_exc = exp_exc_vec.size() == 1
-                    ? exp_exc_vec[0]
-                    : NodeManager::currentNM()->mkNode(AND, exp_exc_vec);
-      Trace("sygus-pbe-enum")
-          << "  ...fail : term is excluded (domain-specific)" << std::endl;
-    }
-    else
-    {
-      // notify all slaves
-      Assert( !it->second.d_enum_slave.empty() );
-      //explanation for why this value should be excluded
-      for( unsigned s=0; s<it->second.d_enum_slave.size(); s++ ){
-        Node xs = it->second.d_enum_slave[s];
-        std::map< Node, EnumInfo >::iterator itv = d_einfo.find( xs );
-        Assert( itv!=d_einfo.end() );
-        Trace("sygus-pbe-enum") << "Process " << xs << " from " << s << std::endl;
-        //bool prevIsCover = false;
-        if (itv->second.getRole() == enum_io)
-        {
-          Trace("sygus-pbe-enum") << "   IO-Eval of ";
-          //prevIsCover = itv->second.isFeasible();
-        }else{
-          Trace("sygus-pbe-enum") << "Evaluation of ";
-        }
-        Trace("sygus-pbe-enum")  << xs <<  " : ";
-        //evaluate all input/output examples
-        std::vector< Node > results;
-        Node templ = itv->second.d_template;
-        TNode templ_var = itv->second.d_template_arg;
-        std::map< Node, bool > cond_vals;
-        for (unsigned j = 0, size = base_results.size(); j < size; j++)
-        {
-          Node res = base_results[j];
-          Assert( res.isConst() );
-          if( !templ.isNull() ){
-            TNode tres = res;
-            res = templ.substitute( templ_var, res );
-            res = Rewriter::rewrite( res );
-            Assert( res.isConst() );
-          }
-          Node resb;
-          if (itv->second.getRole() == enum_io)
-          {
-            Node out = itxo->second[j];
-            Assert( out.isConst() );
-            resb = res==out ? d_true : d_false;
-          }else{
-            resb = res;
-          }
-          cond_vals[resb] = true;
-          results.push_back( resb );
-          if( Trace.isOn("sygus-pbe-enum") ){
-            if( resb.getType().isBoolean() ){
-              Trace("sygus-pbe-enum") << ( resb==d_true ? "1" : "0" );
-            }else{
-              Trace("sygus-pbe-enum") << "?";
-            }
-          }
-        }
-        bool keep = false;
-        if (itv->second.getRole() == enum_io)
-        {
-          // latter is the degenerate case of no examples
-          if (cond_vals.find(d_true) != cond_vals.end() || cond_vals.empty())
-          {
-            //check subsumbed/subsuming
-            std::vector< Node > subsume;
-            if( cond_vals.find( d_false )==cond_vals.end() ){
-              // it is the entire solution, we are done
-              Trace("sygus-pbe-enum") << "  ...success, full solution added to PBE pool : " << d_tds->sygusToBuiltin( v ) << std::endl;
-              if( !itv->second.isSolved() ){
-                itv->second.setSolved( v );
-                // it subsumes everything
-                itv->second.d_term_trie.clear();
-                itv->second.d_term_trie.addTerm( this, v, results, true, subsume );
-              }
-              keep = true;
-            }else{
-              Node val = itv->second.d_term_trie.addTerm( this, v, results, true, subsume );
-              if( val==v ){
-                Trace("sygus-pbe-enum") << "  ...success"; 
-                if( !subsume.empty() ){
-                  itv->second.d_enum_subsume.insert( itv->second.d_enum_subsume.end(), subsume.begin(), subsume.end() );
-                  Trace("sygus-pbe-enum") << " and subsumed " << subsume.size() << " terms";
-                }
-                Trace("sygus-pbe-enum") << "!   add to PBE pool : " << d_tds->sygusToBuiltin( v ) << std::endl;
-                keep = true;
-              }else{
-                Assert( subsume.empty() );
-                Trace("sygus-pbe-enum") << "  ...fail : subsumed" << std::endl;
-              }
-            }
-          }else{
-            Trace("sygus-pbe-enum") << "  ...fail : it does not satisfy examples." << std::endl;
-          }
-        }else{
-          // must be unique up to examples
-          Node val = itv->second.d_term_trie.addCond(this, v, results, true);
-          if (val == v)
-          {
-            Trace("sygus-pbe-enum") << "  ...success!   add to PBE pool : "
-                                    << d_tds->sygusToBuiltin(v) << std::endl;
-            keep = true;
-          }else{
-            Trace("sygus-pbe-enum")
-                << "  ...fail : term is not unique" << std::endl;
-          }
-          itc->second.d_cond_count++;
-        }
-        if( keep ){
-          // notify the parent to retry the build of PBE
-          itc->second.d_check_sol = true;
-          itv->second.addEnumValue( this, v, results );
-        }
-      }
-    }
-  }else{
-    Trace("sygus-pbe-enum-debug")
-        << "  ...examples do not have output." << std::endl;
-  }
-  // exclude this value on subsequent iterations
-  Node g = it->second.d_active_guard;
-  if (exp_exc.isNull())
-  {
-    // if we did not already explain why this should be excluded, use default
-    exp_exc = d_tds->getExplain()->getExplanationForConstantEquality(x, v);
-  }
-  Node exlem =
-      NodeManager::currentNM()->mkNode(OR, g.negate(), exp_exc.negate());
-  Trace("sygus-pbe-enum-lemma")
-      << "CegConjecturePbe : enumeration exclude lemma : " << exlem
-      << std::endl;
-  lems.push_back(exlem);
-}
-
-bool CegConjecturePbe::useStrContainsEnumeratorExclude(Node x, EnumInfo& ei)
-{
-  TypeNode xbt = d_tds->sygusToBuiltinType(x.getType());
-  if (xbt.isString())
-  {
-    std::map<Node, bool>::iterator itx = d_use_str_contains_eexc.find(x);
-    if (itx != d_use_str_contains_eexc.end())
-    {
-      return itx->second;
-    }
-    Trace("sygus-pbe-enum-debug")
-        << "Is " << x << " is str.contains exclusion?" << std::endl;
-    d_use_str_contains_eexc[x] = true;
-    for (const Node& sn : ei.d_enum_slave)
-    {
-      std::map<Node, EnumInfo>::iterator itv = d_einfo.find(sn);
-      EnumRole er = itv->second.getRole();
-      if (er != enum_io && er != enum_concat_term)
-      {
-        Trace("sygus-pbe-enum-debug") << "  incompatible slave : " << sn
-                                      << ", role = " << er << std::endl;
-        d_use_str_contains_eexc[x] = false;
-        return false;
-      }
-      if (itv->second.isConditional())
-      {
-        Trace("sygus-pbe-enum-debug")
-            << "  conditional slave : " << sn << std::endl;
-        d_use_str_contains_eexc[x] = false;
-        return false;
-      }
-    }
-    Trace("sygus-pbe-enum-debug")
-        << "...can use str.contains exclusion." << std::endl;
-    return d_use_str_contains_eexc[x];
-  }
-  return false;
-}
-
-bool CegConjecturePbe::getExplanationForEnumeratorExclude(
-    Node c,
-    Node x,
-    Node v,
-    std::vector<Node>& results,
-    EnumInfo& ei,
-    std::vector<Node>& exp)
-{
-  if (useStrContainsEnumeratorExclude(x, ei))
-  {
-    NodeManager* nm = NodeManager::currentNM();
-    // This check whether the example evaluates to something that is larger than
-    // the output for some input/output pair. If so, then this term is never
-    // useful. We generalize its explanation below.
-
-    if (Trace.isOn("sygus-pbe-cterm-debug"))
-    {
-      Trace("sygus-pbe-enum") << std::endl;
-    }
-    // check if all examples had longer length that the output
-    std::map<Node, std::vector<Node> >::iterator itxo = d_examples_out.find(c);
-    Assert(itxo != d_examples_out.end());
-    Assert(itxo->second.size() == results.size());
-    Trace("sygus-pbe-cterm-debug")
-        << "Check enumerator exclusion for " << x << " -> "
-        << d_tds->sygusToBuiltin(v) << " based on str.contains." << std::endl;
-    std::vector<unsigned> cmp_indices;
-    for (unsigned i = 0, size = results.size(); i < size; i++)
-    {
-      Assert(results[i].isConst());
-      Assert(itxo->second[i].isConst());
-      Trace("sygus-pbe-cterm-debug")
-          << "  " << results[i] << " <> " << itxo->second[i];
-      Node cont = nm->mkNode(STRING_STRCTN, itxo->second[i], results[i]);
-      Node contr = Rewriter::rewrite(cont);
-      if (contr == d_false)
-      {
-        cmp_indices.push_back(i);
-        Trace("sygus-pbe-cterm-debug") << "...not contained." << std::endl;
-      }
-      else
-      {
-        Trace("sygus-pbe-cterm-debug") << "...contained." << std::endl;
-      }
-    }
-    if (!cmp_indices.empty())
-    {
-      // we check invariance with respect to a negative contains test
-      NegContainsSygusInvarianceTest ncset;
-      ncset.init(d_parent, x, itxo->second, cmp_indices);
-      // construct the generalized explanation
-      d_tds->getExplain()->getExplanationFor(x, v, exp, ncset);
-      Trace("sygus-pbe-cterm")
-          << "PBE-cterm : enumerator exclude " << d_tds->sygusToBuiltin(v)
-          << " due to negative containment." << std::endl;
-      return true;
-    }
-  }
-  return false;
-}
-
-
-
-void CegConjecturePbe::EnumInfo::addEnumValue( CegConjecturePbe * pbe, Node v, std::vector< Node >& results ) {
-  d_enum_val_to_index[v] = d_enum_vals.size();
-  d_enum_vals.push_back( v );
-  d_enum_vals_res.push_back( results );
-  /*
-  if( getRole()==enum_io ){
-    // compute
-    if( d_enum_total.empty() ){
-      d_enum_total = results;
-    }else if( !d_enum_total_true ){
-      d_enum_total_true = true;
-      Assert( d_enum_total.size()==results.size() );
-      for( unsigned i=0; i<results.size(); i++ ){
-        if( d_enum_total[i]==pbe->d_true || results[i]==pbe->d_true ){
-          d_enum_total[i] = pbe->d_true;
-        }else{
-          d_enum_total[i] = pbe->d_false;
-          d_enum_total_true = false;
-        }
-      }
-    }
-  }
-  */
-}
-
-void CegConjecturePbe::EnumInfo::initialize(Node c, EnumRole role)
-{
-  d_parent_candidate = c;
-  d_role = role;
-}
-
-void CegConjecturePbe::EnumInfo::setSolved( Node slv ) {
-  d_enum_solved = slv;
-  //d_enum_total_true = true;
-}
-    
-void CegConjecturePbe::CandidateInfo::initialize( Node c ) {
-  d_this_candidate = c;
-  d_root = c.getType();
-}
-
-void CegConjecturePbe::CandidateInfo::initializeType( TypeNode tn ) {
-  d_tinfo[tn].d_this_type = tn;
-  d_tinfo[tn].d_parent = this;
-}
-
-Node CegConjecturePbe::CandidateInfo::getRootEnumerator() {
-  std::map<EnumRole, Node>::iterator it = d_tinfo[d_root].d_enum.find(enum_io);
-  Assert( it!=d_tinfo[d_root].d_enum.end() );
-  return it->second;
-}
-
-bool CegConjecturePbe::CandidateInfo::isNonTrivial() {
-  //TODO
-  return true;
-}
-
-// status : 0 : exact, -1 : vals is subset, 1 : vals is superset
-Node CegConjecturePbe::SubsumeTrie::addTermInternal( CegConjecturePbe * pbe, Node t, std::vector< Node >& vals, bool pol, 
-                                                     std::vector< Node >& subsumed, bool spol, IndexFilter * f, 
-                                                     unsigned index, int status, bool checkExistsOnly, bool checkSubsume ) {
-  if( index==vals.size() ){
-    if( status==0 ){
-      // set the term if checkExistsOnly = false
-      if( d_term.isNull() && !checkExistsOnly ){
-        d_term = t;
-      }
-    }else if( status==1 ){
-      Assert( checkSubsume );
-      // found a subsumed term
-      if( !d_term.isNull() ){
-        subsumed.push_back( d_term );
-        if( !checkExistsOnly ){
-          // remove it if checkExistsOnly = false
-          d_term = Node::null();
-        }
-      }
-    }else{
-      Assert( !checkExistsOnly && checkSubsume );
-    }
-    return d_term;
-  }else{
-    // the current value 
-    Assert( pol || ( vals[index].isConst() && vals[index].getType().isBoolean() ) );
-    Node cv = pol ? vals[index] : ( vals[index]==pbe->d_true ? pbe->d_false : pbe->d_true );
-    // if checkExistsOnly = false, check if the current value is subsumed if checkSubsume = true, if so, don't add
-    if( !checkExistsOnly && checkSubsume ){
-      std::vector< bool > check_subsumed_by;
-      if( status==0 ){
-        if( cv==pbe->d_false ){
-          check_subsumed_by.push_back( spol );
-        }
-      }else if( status==-1 ){
-        check_subsumed_by.push_back( spol );
-        if( cv==pbe->d_false ){
-          check_subsumed_by.push_back( !spol );
-        }
-      }
-      // check for subsumed nodes
-      for( unsigned i=0; i<check_subsumed_by.size(); i++ ){
-        Node csval = check_subsumed_by[i] ? pbe->d_true : pbe->d_false;
-        // check if subsumed
-        std::map< Node, SubsumeTrie >::iterator itc = d_children.find( csval );
-        if( itc!=d_children.end() ){
-          unsigned next_index = f ? f->next( index ) : index+1;
-          Node ret = itc->second.addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, -1, checkExistsOnly, checkSubsume );
-          // ret subsumes t
-          if( !ret.isNull() ){
-            return ret;
-          }
-        }
-      }
-    }
-    Node ret;
-    std::vector< bool > check_subsume;
-    if( status==0 ){
-      unsigned next_index = f ? f->next( index ) : index+1;
-      if( checkExistsOnly ){
-        std::map< Node, SubsumeTrie >::iterator itc = d_children.find( cv );
-        if( itc!=d_children.end() ){
-          ret = itc->second.addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, 0, checkExistsOnly, checkSubsume );
-        }
-      }else{
-        Assert( spol );
-        ret = d_children[cv].addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, 0, checkExistsOnly, checkSubsume );
-        if( ret!=t ){
-          // we were subsumed by ret, return
-          return ret;
-        }
-      }
-      if( checkSubsume ){
-        // check for subsuming
-        if( cv==pbe->d_true ){
-          check_subsume.push_back( !spol );
-        }
-      }
-    }else if( status==1 ){
-      Assert( checkSubsume );
-      check_subsume.push_back( !spol );
-      if( cv==pbe->d_true ){
-        check_subsume.push_back( spol );
-      }
-    }
-    if( checkSubsume ){
-      // check for subsumed terms
-      for( unsigned i=0; i<check_subsume.size(); i++ ){
-        Node csval = check_subsume[i] ? pbe->d_true : pbe->d_false;
-        std::map< Node, SubsumeTrie >::iterator itc = d_children.find( csval );
-        if( itc!=d_children.end() ){
-          unsigned next_index = f ? f->next( index ) : index+1;
-          itc->second.addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, 1, checkExistsOnly, checkSubsume );
-          // clean up
-          if( itc->second.isEmpty() ){
-            Assert( !checkExistsOnly );
-            d_children.erase( csval );
-          }
-        }
-      }
-    }
-    return ret;
-  }
-}
-
-Node CegConjecturePbe::SubsumeTrie::addTerm( CegConjecturePbe * pbe, Node t, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f ) {
-  unsigned start_index = f ? f->start() : 0;
-  return addTermInternal( pbe, t, vals, pol, subsumed, true, f, start_index, 0, false, true );
-}
-
-Node CegConjecturePbe::SubsumeTrie::addCond( CegConjecturePbe * pbe, Node c, std::vector< Node >& vals, bool pol, IndexFilter * f ) {
-  unsigned start_index = f ? f->start() : 0;
-  std::vector< Node > subsumed;
-  return addTermInternal( pbe, c, vals, pol, subsumed, true, f, start_index, 0, false, false );
-}
-
-void CegConjecturePbe::SubsumeTrie::getSubsumed( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f ){
-  unsigned start_index = f ? f->start() : 0;
-  addTermInternal( pbe, Node::null(), vals, pol, subsumed, true, f, start_index, 1, true, true );
-}
-
-void CegConjecturePbe::SubsumeTrie::getSubsumedBy( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed_by, IndexFilter * f ){
-  // flip polarities
-  unsigned start_index = f ? f->start() : 0;
-  addTermInternal( pbe, Node::null(), vals, !pol, subsumed_by, false, f, start_index, 1, true, true );
-}
-
-void CegConjecturePbe::SubsumeTrie::getLeavesInternal( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::map< int, std::vector< Node > >& v, 
-                                                       IndexFilter * f, unsigned index, int status ) {
-  if( index==vals.size() ){
-    Assert( !d_term.isNull() );
-    Assert( std::find( v[status].begin(), v[status].end(), d_term )==v[status].end() );
-    v[status].push_back( d_term );
-  }else{
-    Assert( vals[index].isConst() && vals[index].getType().isBoolean() );
-    // filter should be for cv
-    Assert( f==NULL || vals[index]==( pol ? pbe->d_true : pbe->d_false ) );
-    for( std::map< Node, SubsumeTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
-      int new_status = status;
-      // if the current value is true
-      if( vals[index]==( pol ? pbe->d_true : pbe->d_false ) ){
-        if( status!=0 ){
-          new_status = ( it->first == pbe->d_true ? 1 : -1 );
-          if( status!=-2 && new_status!=status ){
-            new_status = 0;
-          }
-        }
-      }
-      unsigned next_index = f ? f->next( index ) : index+1;
-      it->second.getLeavesInternal( pbe, vals, pol, v, f, next_index, new_status );
-    }
-  }
-}
-
-void CegConjecturePbe::SubsumeTrie::getLeaves( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::map< int, std::vector< Node > >& v, IndexFilter * f ) {
-  unsigned start_index = f ? f->start() : 0;
-  getLeavesInternal( pbe, vals, pol, v, f, start_index, -2 );
-}
-
-void CegConjecturePbe::IndexFilter::mk( std::vector< Node >& vals, bool pol ) {
-  Trace("sygus-pbe-debug") << "Make for : ";
-  print_val( "sygus-pbe-debug", vals, pol );
-  Trace("sygus-pbe-debug") << std::endl;
-  Node poln = NodeManager::currentNM()->mkConst( pol );
-  
-  unsigned curr_index = 0;
-  while( curr_index<vals.size() && vals[curr_index]!=poln ){
-    curr_index++;
-  }
-  d_next[0] = curr_index;
-  Trace("sygus-pbe-debug") << "0 -> " << curr_index << std::endl;
-  unsigned i = curr_index;
-  while( i<vals.size() ){
-    while( i<vals.size() && vals[i]!=poln ){
-      i++;
-    }
-    i++;
-    d_next[curr_index+1] = i;
-    Trace("sygus-pbe-debug") << curr_index+1 << " -> " << i << std::endl;
-    curr_index = i;
-  }
-  
-  // verify it is correct
-  unsigned j = start();
-  for( unsigned k=0; k<j; k++ ){
-    AlwaysAssert( vals[k]!=poln );
-  }
-  Trace("sygus-pbe-debug") << "...start : " << j << std::endl;
-  unsigned counter = 0;
-  while( j<vals.size() ){
-    Trace("sygus-pbe-debug") << "...at : " << j << std::endl;
-    AlwaysAssert( vals[j]==poln );
-    unsigned jj = next( j );
-    AlwaysAssert( jj>j );
-    for( unsigned k=(j+1); k<jj; k++ ){
-      AlwaysAssert( vals[k]!=poln );
-    }
-    AlwaysAssert( counter<=vals.size() );
-    counter++;
-    j = jj;
-  }
-  
-  
-}
-
-unsigned CegConjecturePbe::IndexFilter::start() {
-  std::map< unsigned, unsigned >::iterator it = d_next.find( 0 );
-  if( it==d_next.end() ){
-    return 0;
-  }else{
-    return it->second;
-  }
-}
-
-unsigned CegConjecturePbe::IndexFilter::next( unsigned i ) {
-  std::map< unsigned, unsigned >::iterator it = d_next.find( i+1 );
-  if( it==d_next.end() ){
-    return i+1;
-  }else{
-    return it->second;
-  }      
-}
-
-bool CegConjecturePbe::IndexFilter::isEq( std::vector< Node >& vals, Node v ) {
-  unsigned index = start();
-  while( index<vals.size() ){
-    if( vals[index]!=v ){
-      return false;
-    }
-    index = next( index );
-  }
-  return true;
-}
-
-Node CegConjecturePbe::constructSolution( Node c ){
-  std::map< Node, CandidateInfo >::iterator itc = d_cinfo.find( c );
-  Assert( itc!=d_cinfo.end() );
-  if( !itc->second.d_solution.isNull() ){
-    // already has a solution
-    return itc->second.d_solution;
-  }else{
-    // only check if an enumerator updated
-    if( itc->second.d_check_sol ){
-      Trace("sygus-pbe") << "Construct solution, #iterations = " << itc->second.d_cond_count << std::endl;
-      itc->second.d_check_sol = false;
-      // try multiple times if we have done multiple conditions, due to non-determinism
-      Node vc;
-      for( unsigned i=0; i<=itc->second.d_cond_count; i++ ){
-        Trace("sygus-pbe-dt") << "ConstructPBE for candidate: " << c << std::endl;
-        Node e = itc->second.getRootEnumerator();
-        UnifContext x;
-        x.initialize( this, c );
-        Node vcc = constructSolution(c, e, role_equal, x, 1);
-        if( !vcc.isNull() ){
-          if( vc.isNull() || ( !vc.isNull() && d_tds->getSygusTermSize( vcc )<d_tds->getSygusTermSize( vc ) ) ){
-            Trace("sygus-pbe") << "**** PBE SOLVED : " << c << " = " << vcc << std::endl;
-            Trace("sygus-pbe") << "...solved at iteration " << i << std::endl;
-            vc = vcc;
-          }
-        }
-      }
-      if( !vc.isNull() ){
-        itc->second.d_solution = vc;
-        return vc;
-      }
-      Trace("sygus-pbe") << "...failed to solve." << std::endl;
-    }
-    return Node::null();
-  }
-}
-
-Node CegConjecturePbe::constructBestSolvedTerm( std::vector< Node >& solved, UnifContext& x ){
-  Assert( !solved.empty() );
-  // TODO
-  return solved[0];
-}
-
-Node CegConjecturePbe::constructBestStringSolvedTerm( std::vector< Node >& solved, UnifContext& x ) {
-  Assert( !solved.empty() );
-  // TODO
-  return solved[0];
-}
-
-Node CegConjecturePbe::constructBestSolvedConditional( std::vector< Node >& solved, UnifContext& x ){
-  Assert( !solved.empty() );
-  // TODO
-  return solved[0];
-}
-
-Node CegConjecturePbe::constructBestConditional( std::vector< Node >& conds, UnifContext& x ) {
-  Assert( !conds.empty() );
-  // TODO
-  double r = Random::getRandom().pickDouble(0.0, 1.0);
-  unsigned cindex = r*conds.size();
-  if( cindex>conds.size() ){
-    cindex = conds.size() - 1;
-  }
-  return conds[cindex];
-}
-
-Node CegConjecturePbe::constructBestStringToConcat( std::vector< Node > strs,
-                                                    std::map< Node, unsigned > total_inc, 
-                                                    std::map< Node, std::vector< unsigned > > incr,
-                                                    UnifContext& x ) {
-  Assert( !strs.empty() );
-  std::random_shuffle(strs.begin(), strs.end());
-  // prefer one that has incremented by more than 0
-  for (const Node& ns : strs)
-  {
-    if (total_inc[ns] > 0)
-    {
-      return ns;
-    }
-  }
-  return strs[0];
-}
-
-Node CegConjecturePbe::constructSolution(
-    Node c, Node e, NodeRole nrole, UnifContext& x, int ind)
-{
-  TypeNode etn = e.getType();
-  if (Trace.isOn("sygus-pbe-dt-debug"))
-  {
-    indent("sygus-pbe-dt-debug", ind);
-    Trace("sygus-pbe-dt-debug") << "ConstructPBE: (" << e << ", " << nrole
-                                << ") for type " << etn << " in context ";
-    print_val("sygus-pbe-dt-debug", x.d_vals);
-    if (x.d_has_string_pos != role_invalid)
-    {
-      Trace("sygus-pbe-dt-debug") << ", string context [" << x.d_has_string_pos;
-      for (unsigned i = 0, size = x.d_str_pos.size(); i < size; i++)
-      {
-        Trace("sygus-pbe-dt-debug") << " " << x.d_str_pos[i];
-      }
-      Trace("sygus-pbe-dt-debug") << "]";
-    }
-    Trace("sygus-pbe-dt-debug") << std::endl;
-  }
-  // enumerator type info
-  std::map<TypeNode, EnumTypeInfo>::iterator itt = d_cinfo[c].d_tinfo.find(etn);
-  Assert(itt != d_cinfo[c].d_tinfo.end());
-  EnumTypeInfo& tinfo = itt->second;
-
-  // get the enumerator information
-  std::map< Node, EnumInfo >::iterator itn = d_einfo.find( e );
-  Assert( itn!=d_einfo.end() );
-  EnumInfo& einfo = itn->second;
-
-  Node ret_dt;
-  if (nrole == role_equal)
-  {
-    if (!x.isReturnValueModified())
-    {
-      if (einfo.isSolved())
-      {
-        // this type has a complete solution
-        ret_dt = einfo.getSolved();
-        indent("sygus-pbe-dt", ind);
-        Trace("sygus-pbe-dt") << "return PBE: success : solved "
-                              << d_tds->sygusToBuiltin(ret_dt) << std::endl;
-        Assert(!ret_dt.isNull());
-      }
-      else
-      {
-        // could be conditionally solved
-        std::vector<Node> subsumed_by;
-        einfo.d_term_trie.getSubsumedBy(this, x.d_vals, true, subsumed_by);
-        if (!subsumed_by.empty())
-        {
-          ret_dt = constructBestSolvedTerm(subsumed_by, x);
-          indent("sygus-pbe-dt", ind);
-          Trace("sygus-pbe-dt") << "return PBE: success : conditionally solved"
-                                << d_tds->sygusToBuiltin(ret_dt) << std::endl;
-        }
-        else
-        {
-          indent("sygus-pbe-dt-debug", ind);
-          Trace("sygus-pbe-dt-debug")
-              << "  ...not currently conditionally solved." << std::endl;
-        }
-      }
-    }
-    if (ret_dt.isNull())
-    {
-      if (d_tds->sygusToBuiltinType(e.getType()).isString())
-      {
-        // check if a current value that closes all examples
-        // get the term enumerator for this type
-        bool success = true;
-        std::map<Node, EnumInfo>::iterator itet;
-        std::map<EnumRole, Node>::iterator itnt =
-            tinfo.d_enum.find(enum_concat_term);
-        if( itnt != itt->second.d_enum.end() ){
-          Node et = itnt->second;
-          itet = d_einfo.find( et );
-          Assert(itet != d_einfo.end());
-        }else{
-          success = false;
-        }
-        if (success)
-        {
-          // get the current examples
-          std::map<Node, std::vector<Node> >::iterator itx =
-              d_examples_out.find(c);
-          Assert(itx != d_examples_out.end());
-          std::vector<String> ex_vals;
-          x.getCurrentStrings(this, itx->second, ex_vals);
-          Assert(itn->second.d_enum_vals.size()
-                 == itn->second.d_enum_vals_res.size());
-
-          // test each example in the term enumerator for the type
-          std::vector<Node> str_solved;
-          for (unsigned i = 0, size = itet->second.d_enum_vals.size(); i < size;
-               i++)
-          {
-            if (x.isStringSolved(
-                    this, ex_vals, itet->second.d_enum_vals_res[i]))
-            {
-              str_solved.push_back(itet->second.d_enum_vals[i]);
-            }
-          }
-          if (!str_solved.empty())
-          {
-            ret_dt = constructBestStringSolvedTerm(str_solved, x);
-            indent("sygus-pbe-dt", ind);
-            Trace("sygus-pbe-dt") << "return PBE: success : string solved "
-                                  << d_tds->sygusToBuiltin(ret_dt) << std::endl;
-          }
-          else
-          {
-            indent("sygus-pbe-dt-debug", ind);
-            Trace("sygus-pbe-dt-debug") << "  ...not currently string solved."
-                                        << std::endl;
-          }
-        }
-      }
-    }
-  }
-  else if (nrole == role_string_prefix || nrole == role_string_suffix)
-  {
-    // check if each return value is a prefix/suffix of all open examples
-    if (!x.isReturnValueModified() || x.d_has_string_pos == nrole)
-    {
-      std::map<Node, std::vector<unsigned> > incr;
-      bool isPrefix = nrole == role_string_prefix;
-      std::map<Node, unsigned> total_inc;
-      std::vector<Node> inc_strs;
-      std::map<Node, std::vector<Node> >::iterator itx = d_examples_out.find(c);
-      Assert(itx != d_examples_out.end());
-      // make the value of the examples
-      std::vector<String> ex_vals;
-      x.getCurrentStrings(this, itx->second, ex_vals);
-      if (Trace.isOn("sygus-pbe-dt-debug"))
-      {
-        indent("sygus-pbe-dt-debug", ind);
-        Trace("sygus-pbe-dt-debug") << "current strings : " << std::endl;
-        for (unsigned i = 0, size = ex_vals.size(); i < size; i++)
-        {
-          indent("sygus-pbe-dt-debug", ind + 1);
-          Trace("sygus-pbe-dt-debug") << ex_vals[i] << std::endl;
-        }
-      }
-
-      // check if there is a value for which is a prefix/suffix of all active
-      // examples
-      Assert(einfo.d_enum_vals.size() == einfo.d_enum_vals_res.size());
-
-      for (unsigned i = 0, size = einfo.d_enum_vals.size(); i < size; i++)
-      {
-        Node val_t = einfo.d_enum_vals[i];
-        indent("sygus-pbe-dt-debug", ind);
-        Trace("sygus-pbe-dt-debug") << "increment string values : " << val_t
-                                    << " : ";
-        Assert(einfo.d_enum_vals_res[i].size() == itx->second.size());
-        unsigned tot = 0;
-        bool exsuccess = x.getStringIncrement(this,
-                                              isPrefix,
-                                              ex_vals,
-                                              einfo.d_enum_vals_res[i],
-                                              incr[val_t],
-                                              tot);
-        if (!exsuccess)
-        {
-          incr.erase(val_t);
-          Trace("sygus-pbe-dt-debug") << "...fail" << std::endl;
-        }
-        else
-        {
-          total_inc[val_t] = tot;
-          inc_strs.push_back(val_t);
-          Trace("sygus-pbe-dt-debug") << "...success, total increment = " << tot
-                                      << std::endl;
-        }
-      }
-
-      if (!incr.empty())
-      {
-        ret_dt = constructBestStringToConcat(inc_strs, total_inc, incr, x);
-        Assert(!ret_dt.isNull());
-        indent("sygus-pbe-dt", ind);
-        Trace("sygus-pbe-dt") << "PBE: CONCAT strategy : choose "
-                              << (isPrefix ? "pre" : "suf") << "fix value "
-                              << d_tds->sygusToBuiltin(ret_dt) << std::endl;
-        // update the context
-        bool ret = x.updateStringPosition(this, incr[ret_dt]);
-        AlwaysAssert(ret == (total_inc[ret_dt] > 0));
-        x.d_has_string_pos = nrole;
-      }else{
-        indent("sygus-pbe-dt", ind);
-        Trace("sygus-pbe-dt") << "PBE: failed CONCAT strategy, no values are "
-                              << (isPrefix ? "pre" : "suf")
-                              << "fix of all examples." << std::endl;
-      }
-    }
-    else
-    {
-      indent("sygus-pbe-dt", ind);
-      Trace("sygus-pbe-dt")
-          << "PBE: failed CONCAT strategy, prefix/suffix mismatch."
-          << std::endl;
-    }
-  }
-  if (ret_dt.isNull() && !einfo.isTemplated())
-  {
-    // we will try a single strategy
-    EnumTypeInfoStrat* etis = nullptr;
-    std::map<NodeRole, StrategyNode>::iterator itsn =
-        tinfo.d_snodes.find(nrole);
-    if (itsn != tinfo.d_snodes.end())
-    {
-      // strategy info
-      StrategyNode& snode = itsn->second;
-      if (x.d_visit_role[e].find(nrole) == x.d_visit_role[e].end())
-      {
-        x.d_visit_role[e][nrole] = true;
-        // try a random strategy
-        if (snode.d_strats.size() > 1)
-        {
-          std::random_shuffle(snode.d_strats.begin(), snode.d_strats.end());
-        }
-        // get an eligible strategy index
-        unsigned sindex = 0;
-        while (sindex < snode.d_strats.size()
-               && !x.isValidStrategy(snode.d_strats[sindex]))
-        {
-          sindex++;
-        }
-        // if we found a eligible strategy
-        if (sindex < snode.d_strats.size())
-        {
-          etis = snode.d_strats[sindex];
-        }
-      }
-    }
-    if (etis != nullptr)
-    {
-      StrategyType strat = etis->d_this;
-      indent("sygus-pbe-dt", ind + 1);
-      Trace("sygus-pbe-dt") << "...try STRATEGY " << strat << "..."
-                            << std::endl;
-
-      std::map<unsigned, Node> look_ahead_solved_children;
-      std::vector<Node> dt_children_cons;
-      bool success = true;
-
-      // for ITE
-      Node split_cond_enum;
-      int split_cond_res_index = -1;
-
-      for (unsigned sc = 0, size = etis->d_cenum.size(); sc < size; sc++)
-      {
-        indent("sygus-pbe-dt", ind + 1);
-        Trace("sygus-pbe-dt") << "construct PBE child #" << sc << "..."
-                              << std::endl;
-        Node rec_c;
-        std::map<unsigned, Node>::iterator itla =
-            look_ahead_solved_children.find(sc);
-        if (itla != look_ahead_solved_children.end())
-        {
-          rec_c = itla->second;
-          indent("sygus-pbe-dt-debug", ind + 1);
-          Trace("sygus-pbe-dt-debug") << "ConstructPBE: look ahead solved : "
-                                      << d_tds->sygusToBuiltin(rec_c)
-                                      << std::endl;
-        }
-        else
-        {
-          std::pair<Node, NodeRole>& cenum = etis->d_cenum[sc];
-
-          // update the context
-          std::vector<Node> prev;
-          if (strat == strat_ITE && sc > 0)
-          {
-            std::map<Node, EnumInfo>::iterator itnc =
-                d_einfo.find(split_cond_enum);
-            Assert(itnc != d_einfo.end());
-            Assert(split_cond_res_index >= 0);
-            Assert(split_cond_res_index
-                   < (int)itnc->second.d_enum_vals_res.size());
-            prev = x.d_vals;
-            bool ret = x.updateContext(
-                this,
-                itnc->second.d_enum_vals_res[split_cond_res_index],
-                sc == 1);
-            AlwaysAssert(ret);
-          }
-
-          // recurse
-          if (strat == strat_ITE && sc == 0)
-          {
-            Node ce = cenum.first;
-
-            // register the condition enumerator
-            std::map<Node, EnumInfo>::iterator itnc = d_einfo.find(ce);
-            Assert(itnc != d_einfo.end());
-            EnumInfo& einfo_child = itnc->second;
-
-            // only used if the return value is not modified
-            if (!x.isReturnValueModified())
-            {
-              if (x.d_uinfo.find(ce) == x.d_uinfo.end())
-              {
-                Trace("sygus-pbe-dt-debug2")
-                    << "  reg : PBE: Look for direct solutions for conditional "
-                       "enumerator "
-                    << ce << " ... " << std::endl;
-                Assert(einfo_child.d_enum_vals.size()
-                       == einfo_child.d_enum_vals_res.size());
-                for (unsigned i = 1; i <= 2; i++)
-                {
-                  std::pair<Node, NodeRole>& te_pair = etis->d_cenum[i];
-                  Node te = te_pair.first;
-                  std::map<Node, EnumInfo>::iterator itnt = d_einfo.find(te);
-                  Assert(itnt != d_einfo.end());
-                  bool branch_pol = (i == 1);
-                  // for each condition, get terms that satisfy it in this
-                  // branch
-                  for (unsigned k = 0, size = einfo_child.d_enum_vals.size();
-                       k < size;
-                       k++)
-                  {
-                    Node cond = einfo_child.d_enum_vals[k];
-                    std::vector<Node> solved;
-                    itnt->second.d_term_trie.getSubsumedBy(
-                        this,
-                        einfo_child.d_enum_vals_res[k],
-                        branch_pol,
-                        solved);
-                    Trace("sygus-pbe-dt-debug2")
-                        << "  reg : PBE: " << d_tds->sygusToBuiltin(cond)
-                        << " has " << solved.size() << " solutions in branch "
-                        << i << std::endl;
-                    if (!solved.empty())
-                    {
-                      Node slv = constructBestSolvedTerm(solved, x);
-                      Trace("sygus-pbe-dt-debug2")
-                          << "  reg : PBE: ..." << d_tds->sygusToBuiltin(slv)
-                          << " is a solution under branch " << i;
-                      Trace("sygus-pbe-dt-debug2")
-                          << " of condition " << d_tds->sygusToBuiltin(cond)
-                          << std::endl;
-                      x.d_uinfo[ce].d_look_ahead_sols[cond][i] = slv;
-                    }
-                  }
-                }
-              }
-            }
-
-            // get the conditionals in the current context : they must be
-            // distinguishable
-            std::map<int, std::vector<Node> > possible_cond;
-            std::map<Node, int> solved_cond;  // stores branch
-            einfo_child.d_term_trie.getLeaves(
-                this, x.d_vals, true, possible_cond);
-
-            std::map<int, std::vector<Node> >::iterator itpc =
-                possible_cond.find(0);
-            if (itpc != possible_cond.end())
-            {
-              if (Trace.isOn("sygus-pbe-dt-debug"))
-              {
-                indent("sygus-pbe-dt-debug", ind + 1);
-                Trace("sygus-pbe-dt-debug")
-                    << "PBE : We have " << itpc->second.size()
-                    << " distinguishable conditionals:" << std::endl;
-                for (Node& cond : itpc->second)
-                {
-                  indent("sygus-pbe-dt-debug", ind + 2);
-                  Trace("sygus-pbe-dt-debug") << d_tds->sygusToBuiltin(cond)
-                                              << std::endl;
-                }
-              }
-
-              // static look ahead conditional : choose conditionals that have
-              // solved terms in at least one branch
-              //    only applicable if we have not modified the return value
-              std::map<int, std::vector<Node> > solved_cond;
-              if (!x.isReturnValueModified())
-              {
-                Assert(x.d_uinfo.find(ce) != x.d_uinfo.end());
-                int solve_max = 0;
-                for (Node& cond : itpc->second)
-                {
-                  std::map<Node, std::map<unsigned, Node> >::iterator itla =
-                      x.d_uinfo[ce].d_look_ahead_sols.find(cond);
-                  if (itla != x.d_uinfo[ce].d_look_ahead_sols.end())
-                  {
-                    int nsolved = itla->second.size();
-                    solve_max = nsolved > solve_max ? nsolved : solve_max;
-                    solved_cond[nsolved].push_back(cond);
-                  }
-                }
-                int n = solve_max;
-                while (n > 0)
-                {
-                  if (!solved_cond[n].empty())
-                  {
-                    rec_c = constructBestSolvedConditional(solved_cond[n], x);
-                    indent("sygus-pbe-dt", ind + 1);
-                    Trace("sygus-pbe-dt")
-                        << "PBE: ITE strategy : choose solved conditional "
-                        << d_tds->sygusToBuiltin(rec_c) << " with " << n
-                        << " solved children..." << std::endl;
-                    std::map<Node, std::map<unsigned, Node> >::iterator itla =
-                        x.d_uinfo[ce].d_look_ahead_sols.find(rec_c);
-                    Assert(itla != x.d_uinfo[ce].d_look_ahead_sols.end());
-                    for (std::pair<const unsigned, Node>& las : itla->second)
-                    {
-                      look_ahead_solved_children[las.first] = las.second;
-                    }
-                    break;
-                  }
-                  n--;
-                }
-              }
-
-              // otherwise, guess a conditional
-              if (rec_c.isNull())
-              {
-                rec_c = constructBestConditional(itpc->second, x);
-                Assert(!rec_c.isNull());
-                indent("sygus-pbe-dt", ind);
-                Trace("sygus-pbe-dt")
-                    << "PBE: ITE strategy : choose random conditional "
-                    << d_tds->sygusToBuiltin(rec_c) << std::endl;
-              }
-            }
-            else
-            {
-              // TODO (#1250) : degenerate case where children have different
-              // types?
-              indent("sygus-pbe-dt", ind);
-              Trace("sygus-pbe-dt") << "return PBE: failed ITE strategy, "
-                                       "cannot find a distinguishable condition"
-                                    << std::endl;
-            }
-            if( !rec_c.isNull() ){
-              Assert(einfo_child.d_enum_val_to_index.find(rec_c)
-                     != einfo_child.d_enum_val_to_index.end());
-              split_cond_res_index = einfo_child.d_enum_val_to_index[rec_c];
-              split_cond_enum = ce;
-              Assert(split_cond_res_index >= 0);
-              Assert(split_cond_res_index
-                     < (int)einfo_child.d_enum_vals_res.size());
-            }
-          }
-          else
-          {
-            rec_c = constructSolution(c, cenum.first, cenum.second, x, ind + 2);
-          }
-
-          // undo update the context
-          if (strat == strat_ITE && sc > 0)
-          {
-            x.d_vals = prev;
-          }
-        }
-        if (!rec_c.isNull())
-        {
-          dt_children_cons.push_back(rec_c);
-        }
-        else
-        {
-          success = false;
-          break;
-        }
-      }
-      if (success)
-      {
-        Assert(dt_children_cons.size() == etis->d_sol_templ_args.size());
-        // ret_dt = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR,
-        // dt_children );
-        ret_dt = etis->d_sol_templ;
-        ret_dt = ret_dt.substitute(etis->d_sol_templ_args.begin(),
-                                   etis->d_sol_templ_args.end(),
-                                   dt_children_cons.begin(),
-                                   dt_children_cons.end());
-        indent("sygus-pbe-dt-debug", ind);
-        Trace("sygus-pbe-dt-debug")
-            << "PBE: success : constructed for strategy " << strat << std::endl;
-      }else{
-        indent("sygus-pbe-dt-debug", ind);
-        Trace("sygus-pbe-dt-debug") << "PBE: failed for strategy " << strat
-                                    << std::endl;
-      }
-    }
-  }
-
-  if( !ret_dt.isNull() ){
-    Assert( ret_dt.getType()==e.getType() );
-  }
-  indent("sygus-pbe-dt", ind);
-  Trace("sygus-pbe-dt") << "ConstructPBE: returned " << ret_dt << std::endl;
-  return ret_dt;
-}
-
-bool CegConjecturePbe::UnifContext::updateContext( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol ) {
-  Assert( d_vals.size()==vals.size() );
-  bool changed = false;
-  Node poln = pol ? pbe->d_true : pbe->d_false;
-  for( unsigned i=0; i<vals.size(); i++ ){
-    if( vals[i]!=poln ){
-      if( d_vals[i]==pbe->d_true ){
-        d_vals[i] = pbe->d_false;
-        changed = true;
-      }
-    }
-  }
-  if (changed)
-  {
-    d_visit_role.clear();
-  }
-  return changed;
-}
-
-bool CegConjecturePbe::UnifContext::updateStringPosition( CegConjecturePbe * pbe, std::vector< unsigned >& pos ) {
-  Assert( pos.size()==d_str_pos.size() );
-  bool changed = false;
-  for( unsigned i=0; i<pos.size(); i++ ){
-    if( pos[i]>0 ){
-      d_str_pos[i] += pos[i];
-      changed = true;
-    }
-  }
-  if (changed)
-  {
-    d_visit_role.clear();
-  }
-  return changed;
-}
-
-bool CegConjecturePbe::UnifContext::isReturnValueModified() {
-  if (d_has_string_pos != role_invalid)
-  {
-    return true;
-  }
-  return false;
-}
-
-bool CegConjecturePbe::UnifContext::isValidStrategy(EnumTypeInfoStrat* etis)
-{
-  StrategyType st = etis->d_this;
-  if (d_has_string_pos == role_string_prefix && st == strat_CONCAT_SUFFIX)
-  {
-    return false;
-  }
-  if (d_has_string_pos == role_string_suffix && st == strat_CONCAT_PREFIX)
-  {
-    return false;
-  }
-  return true;
-}
-
-void CegConjecturePbe::UnifContext::initialize( CegConjecturePbe * pbe, Node c ) {
-  Assert( d_vals.empty() );
-  Assert( d_str_pos.empty() );
-  
-  // initialize with #examples
-  Assert( pbe->d_examples.find( c )!=pbe->d_examples.end() );
-  unsigned sz = pbe->d_examples[c].size();
-  for( unsigned i=0; i<sz; i++ ){
-    d_vals.push_back( pbe->d_true );
-  }
-  
-  if( !pbe->d_examples_out[c].empty() ){
-    // output type of the examples
-    TypeNode exotn = pbe->d_examples_out[c][0].getType();
-    
-    if( exotn.isString() ){
-      for( unsigned i=0; i<sz; i++ ){
-        d_str_pos.push_back( 0 );
-      }
-    }
-  }
-  d_visit_role.clear();
-}
-
-void CegConjecturePbe::UnifContext::getCurrentStrings(
-    CegConjecturePbe* pbe,
-    const std::vector<Node>& vals,
-    std::vector<String>& ex_vals)
-{
-  bool isPrefix = d_has_string_pos == role_string_prefix;
-  String dummy;
-  for( unsigned i=0; i<vals.size(); i++ ){
-    if( d_vals[i]==pbe->d_true ){
-      Assert( vals[i].isConst() );
-      unsigned pos_value = d_str_pos[i];
-      if( pos_value>0 ){
-        Assert(d_has_string_pos != role_invalid);
-        String s = vals[i].getConst<String>();
-        Assert( pos_value<=s.size() );
-        ex_vals.push_back( isPrefix ? s.suffix( s.size()-pos_value ) : 
-                                      s.prefix( s.size()-pos_value ) );
-      }else{
-        ex_vals.push_back( vals[i].getConst<String>() );
-      }
-    }else{
-      // irrelevant, add dummy
-      ex_vals.push_back( dummy );
-    }
-  }
-}
-
-bool CegConjecturePbe::UnifContext::getStringIncrement(
-    CegConjecturePbe* pbe,
-    bool isPrefix,
-    const std::vector<String>& ex_vals,
-    const std::vector<Node>& vals,
-    std::vector<unsigned>& inc,
-    unsigned& tot)
-{
-  for( unsigned j=0; j<vals.size(); j++ ){
-    unsigned ival = 0;
-    if( d_vals[j]==pbe->d_true ){
-      // example is active in this context
-      Assert( vals[j].isConst() );
-      String mystr = vals[j].getConst<String>();
-      ival = mystr.size();
-      if( mystr.size()<=ex_vals[j].size() ){
-        if( !( isPrefix ? ex_vals[j].strncmp(mystr, ival) : ex_vals[j].rstrncmp(mystr, ival) ) ){
-          Trace("sygus-pbe-dt-debug") << "X";
-          return false;
-        }
-      }else{
-        Trace("sygus-pbe-dt-debug") << "X";
-        return false;
-      }
-    }
-    Trace("sygus-pbe-dt-debug") << ival;
-    tot += ival;
-    inc.push_back( ival );
-  }
-  return true;
-}
-bool CegConjecturePbe::UnifContext::isStringSolved(
-    CegConjecturePbe* pbe,
-    const std::vector<String>& ex_vals,
-    const std::vector<Node>& vals)
-{
-  for( unsigned j=0; j<vals.size(); j++ ){
-    if( d_vals[j]==pbe->d_true ){
-      // example is active in this context
-      Assert( vals[j].isConst() );
-      String mystr = vals[j].getConst<String>();
-      if( ex_vals[j]!=mystr ){
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-CegConjecturePbe::StrategyNode::~StrategyNode()
-{
-  for (unsigned j = 0, size = d_strats.size(); j < size; j++)
-  {
-    delete d_strats[j];
-  }
-  d_strats.clear();
-}
-}
-}
-}
diff --git a/src/theory/quantifiers/ce_guided_pbe.h b/src/theory/quantifiers/ce_guided_pbe.h
deleted file mode 100644 (file)
index ce1f2bf..0000000
+++ /dev/null
@@ -1,802 +0,0 @@
-/*********************                                                        */
-/*! \file ce_guided_pbe.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief utility for processing programming by examples synthesis conjectures
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_PBE_H
-#define __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_PBE_H
-
-#include "context/cdhashmap.h"
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-/** roles for enumerators
- *
- * This indicates the role of an enumerator that is allocated by approaches
- * for synthesis-by-unification (see details below).
- *   io : the enumerator should enumerate values that are overall solutions
- *        for the function-to-synthesize,
- *   ite_condition : the enumerator should enumerate values that are useful
- *                   in ite conditions in the ITE strategy,
- *   concat_term : the enumerator should enumerate values that are used as
- *                 components of string concatenation solutions.
- */
-enum EnumRole
-{
-  enum_invalid,
-  enum_io,
-  enum_ite_condition,
-  enum_concat_term,
-};
-std::ostream& operator<<(std::ostream& os, EnumRole r);
-
-/** roles for strategy nodes
- *
- * This indicates the role of a strategy node, which is a subprocedure of
- * CegConjecturePbe::constructSolution (see details below).
- *   equal : the node constructed must be equal to the overall solution for
- *           the function-to-synthesize,
- *   string_prefix/suffix : the node constructed must be a prefix/suffix
- *                          of the function-to-synthesize,
- *   ite_condition : the node constructed must be a condition that makes some
- *                   active input examples true and some input examples false.
- */
-enum NodeRole
-{
-  role_invalid,
-  role_equal,
-  role_string_prefix,
-  role_string_suffix,
-  role_ite_condition,
-};
-std::ostream& operator<<(std::ostream& os, NodeRole r);
-
-/** enumerator role for node role */
-EnumRole getEnumeratorRoleForNodeRole(NodeRole r);
-
-/** strategy types
- *
- * This indicates a strategy for synthesis-by-unification (see details below).
- *   ITE : strategy for constructing if-then-else solutions via decision
- *         tree learning techniques,
- *   CONCAT_PREFIX/SUFFIX : strategy for constructing string concatenation
- *         solutions via a divide and conquer approach,
- *   ID : identity strategy used for calling strategies on child type through
- *        an identity function.
- */
-enum StrategyType
-{
-  strat_INVALID,
-  strat_ITE,
-  strat_CONCAT_PREFIX,
-  strat_CONCAT_SUFFIX,
-  strat_ID,
-};
-std::ostream& operator<<(std::ostream& os, StrategyType st);
-
-class CegConjecture;
-
-/** CegConjecturePbe
-*
-* This class implements optimizations that target synthesis conjectures
-* that are in Programming-By-Examples (PBE) form.
-*
-* [EX#1] An example of a synthesis conjecture in PBE form is :
-* exists f. forall x.
-* ( x = 0 => f( x ) = 2 ) ^ ( x = 5 => f( x ) = 7 ) ^ ( x = 6 => f( x ) = 8 )
-*
-* We say that the above conjecture has I/O examples (0)->2, (5)->7, (6)->8.
-*
-* Internally, this class does the following for SyGuS inputs:
-*
-* (1) Infers whether the input conjecture is in PBE form or not.
-* (2) Based on this information and on the syntactic restrictions, it
-*     devises a strategy for enumerating terms and construction solutions,
-*     which is inspired by Alur et al. "Scaling Enumerative Program Synthesis
-*     via Divide and Conquer" TACAS 2017. In particular, it may consider
-*     strategies for constructing decision trees when the grammar permits ITEs
-*     and a strategy for divide-and-conquer string synthesis when the grammar
-*     permits string concatenation. This is stored in a set of data structures
-*     within d_cinfo.
-* (3) It makes (possibly multiple) calls to
-*     TermDatabaseSygus::registerMeasuredTerm(...) based
-*     on the strategy, which inform the rest of the system to enumerate values
-*     of particular types in the grammar through use of fresh variables which
-*     we call "enumerators".
-*
-* Points (1)-(3) happen within a call to CegConjecturePbe::initialize(...).
-*
-* Notice that each enumerator is associated with a single
-* function-to-synthesize, but a function-to-sythesize may be mapped to multiple 
-* enumerators. Some public functions of this class expect an enumerator as 
-* input, which we map to a function-to-synthesize via 
-* TermDatabaseSygus::getSynthFunFor(e).
-*
-* An enumerator is initially "active" but may become inactive if the enumeration
-* exhausts all possible values in the datatype corresponding to syntactic
-* restrictions for it. The search may continue unless all enumerators become 
-* inactive.
-*
-* (4) During search, the extension of quantifier-free datatypes procedure for
-*     SyGuS datatypes may ask this class whether current candidates can be
-*     discarded based on
-*     inferring when two candidate solutions are equivalent up to examples.
-*     For example, the candidate solutions:
-*     f = \x ite( x<0, x+1, x ) and f = \x x
-*     are equivalent up to examples on the above conjecture, since they have the
-*     same value on the points x = 0,5,6. Hence, we need only consider one of
-*     them. The interface for querying this is
-*       CegConjecturePbe::addSearchVal(...).
-*     For details, see Reynolds et al. SYNT 2017.
-*
-* (5) When the extension of quantifier-free datatypes procedure for SyGuS
-*     datatypes terminates with a model, the parent of this class calls
-*     CegConjecturePbe::getCandidateList(...), where this class returns the list
-*     of active enumerators.
-* (6) The parent class subsequently calls
-*     CegConjecturePbe::constructValues(...), which
-*     informs this class that new values have been enumerated for active
-*     enumerators, as indicated by the current model. This call also requests
-*     that based on these
-*     newly enumerated values, whether this class is now able to construct a
-*     solution based on the high-level strategy (stored in d_c_info).
-*
-* This class is not designed to work in incremental mode, since there is no way
-* to specify incremental problems in SyguS.
-*/
-class CegConjecturePbe {
- public:
-  CegConjecturePbe(QuantifiersEngine* qe, CegConjecture* p);
-  ~CegConjecturePbe();
-
-  /** initialize this class
-  *
-  * n is the "base instantiation" of the deep-embedding version of
-  *   the synthesis conjecture under "candidates".
-  *   (see CegConjecture::d_base_inst)
-  *
-  * This function may add lemmas to the vector lemmas corresponding
-  * to initial lemmas regarding static analysis of enumerators it
-  * introduced. For example, we may say that the top-level symbol
-  * of an enumerator is not ITE if it is being used to construct
-  * return values for decision trees.
-  */
-  void initialize(Node n,
-                  std::vector<Node>& candidates,
-                  std::vector<Node>& lemmas);
-  /** get candidate list
-  * Adds all active enumerators associated with functions-to-synthesize in
-  * candidates to clist.
-  */
-  void getCandidateList(std::vector<Node>& candidates,
-                        std::vector<Node>& clist);
-  /** construct candidates
-  * (1) Indicates that the list of enumerators in "enums" currently have model
-  *     values "enum_values".
-  * (2) Asks whether based on these new enumerated values, we can construct a
-  *     solution for
-  *     the functions-to-synthesize in "candidates". If so, this function
-  *     returns "true" and
-  *     adds solutions for candidates into "candidate_values".
-  * During this class, this class may add auxiliary lemmas to "lems", which the
-  * caller should send on the output channel via lemma(...).
-  */
-  bool constructCandidates(std::vector<Node>& enums,
-                           std::vector<Node>& enum_values,
-                           std::vector<Node>& candidates,
-                           std::vector<Node>& candidate_values,
-                           std::vector<Node>& lems);
-  /** is PBE enabled for any enumerator? */
-  bool isPbe() { return d_is_pbe; }
-  /** is the enumerator e associated with I/O example pairs? */
-  bool hasExamples(Node e);
-  /** get number of I/O example pairs for enumerator e */
-  unsigned getNumExamples(Node e);
-  /** get the input arguments for i^th I/O example for e, which is added to the
-   * vector ex */
-  void getExample(Node e, unsigned i, std::vector<Node>& ex);
-  /** get the output value of the i^th I/O example for enumerator e */
-  Node getExampleOut(Node e, unsigned i);
-
-  /** add the search val
-  * This function is called by the extension of quantifier-free datatypes
-  * procedure for SyGuS datatypes when we are considering a value of
-  * enumerator e of sygus type tn whose analog in the signature of builtin
-  * theory is bvr.
-  *
-  * For example, bvr = x + 1 when e is the datatype value Plus( x(), One() ) and
-  * tn is a sygus datatype that encodes a subsignature of the integers.
-  *
-  * This returns either:
-  * - A SyGuS term whose analog is equivalent to bvr up to examples
-  *   In the above example,
-  *   it may return a term t of the form Plus( One(), x() ), such that this
-  *   function was previously called with t as input.
-  * - e, indicating that no previous terms are equivalent to e up to examples.
-  */
-  Node addSearchVal(TypeNode tn, Node e, Node bvr);
-  /** evaluate builtin
-  * This returns the evaluation of bn on the i^th example for the
-  * function-to-synthesis
-  * associated with enumerator e. If there are not at least i examples, it
-  * returns the rewritten form of bn.
-  * For example, if bn = x+5, e is an enumerator for f in the above example
-  * [EX#1], then
-  *   evaluateBuiltin( tn, bn, e, 0 ) = 7
-  *   evaluateBuiltin( tn, bn, e, 1 ) = 9
-  *   evaluateBuiltin( tn, bn, e, 2 ) = 10
-  */
-  Node evaluateBuiltin(TypeNode tn, Node bn, Node e, unsigned i);
-
- private:
-  /** quantifiers engine associated with this class */
-  QuantifiersEngine* d_qe;
-  /** sygus term database of d_qe */
-  quantifiers::TermDbSygus * d_tds;
-  /** true and false nodes */
-  Node d_true;
-  Node d_false;
-  /** A reference to the conjecture that owns this class. */
-  CegConjecture* d_parent;
-  /** is this a PBE conjecture for any function? */
-  bool d_is_pbe;
-  /** for each candidate variable f (a function-to-synthesize), whether the
-  * conjecture is purely PBE for that variable
-  * In other words, all occurrences of f are guarded by equalities that
-  * constraint its arguments to constants.
-  */
-  std::map< Node, bool > d_examples_invalid;
-  /** for each candidate variable (function-to-synthesize), whether the
-  * conjecture is purely PBE for that variable.
-  * An example of a conjecture for which d_examples_invalid is false but
-  * d_examples_out_invalid is true is:
-  *   exists f. forall x. ( x = 0 => f( x ) > 2 )
-  * another example is:
-  *   exists f. forall x. ( ( x = 0 => f( x ) = 2 ) V ( x = 3 => f( x ) = 3 ) )
-  * since the formula is not a conjunction (the example values are not
-  * entailed).
-  * However, the domain of f in both cases is finite, which can be used for
-  * search space pruning.
-  */
-  std::map< Node, bool > d_examples_out_invalid;
-  /** for each candidate variable (function-to-synthesize), input of I/O
-   * examples */
-  std::map< Node, std::vector< std::vector< Node > > > d_examples;
-  /** for each candidate variable (function-to-synthesize), output of I/O
-   * examples */
-  std::map< Node, std::vector< Node > > d_examples_out;
-  /** the list of example terms
-   * For the example [EX#1] above, this is f( 0 ), f( 5 ), f( 6 )
-   */
-  std::map< Node, std::vector< Node > > d_examples_term;
-  /** collect the PBE examples in n
-  * This is called on the input conjecture, and will populate the above vectors.
-  *   hasPol/pol denote the polarity of n in the conjecture.
-  */
-  void collectExamples( Node n, std::map< Node, bool >& visited, bool hasPol, bool pol );
-
-  //--------------------------------- PBE search values
-  /** this class is an index of candidate solutions for PBE synthesis */
-  class PbeTrie {
-   public:
-    PbeTrie() {}
-    ~PbeTrie() {}
-    Node d_lazy_child;
-    std::map<Node, PbeTrie> d_children;
-    void clear() { d_children.clear(); }
-    Node addPbeExample(TypeNode etn, Node e, Node b, CegConjecturePbe* cpbe,
-                       unsigned index, unsigned ntotal);
-
-   private:
-    Node addPbeExampleEval(TypeNode etn, Node e, Node b, std::vector<Node>& ex,
-                           CegConjecturePbe* cpbe, unsigned index,
-                           unsigned ntotal);
-  };
-  /** trie of candidate solutions tried
-  * This stores information for each (enumerator, type),
-  * where type is a type in the grammar of the space of solutions for a subterm
-  * of e. This is used for symmetry breaking in quantifier-free reasoning
-  * about SyGuS datatypes.
-  */
-  std::map<Node, std::map<TypeNode, PbeTrie> > d_pbe_trie;
-  //--------------------------------- end PBE search values
-
-  // -------------------------------- decision tree learning
-  // index filter
-  class IndexFilter {
-  public:
-    IndexFilter(){}
-    void mk( std::vector< Node >& vals, bool pol = true );
-    std::map< unsigned, unsigned > d_next;
-    unsigned start();
-    unsigned next( unsigned i );
-    void clear() { d_next.clear(); }
-    bool isEq( std::vector< Node >& vs, Node v );
-  };
-  // subsumption trie
-  class SubsumeTrie {
-  public:
-    SubsumeTrie(){}
-    // adds term to the trie, removes based on subsumption
-    Node addTerm( CegConjecturePbe * pbe, Node t, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f = NULL );
-    // adds condition to the trie (does not do subsumption)
-    Node addCond( CegConjecturePbe * pbe, Node c, std::vector< Node >& vals, bool pol, IndexFilter * f = NULL );
-    // returns the set of terms that are subsets of vals
-    void getSubsumed( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f = NULL );
-    // returns the set of terms that are supersets of vals
-    void getSubsumedBy( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed_by, IndexFilter * f = NULL );
-    // v[-1,1,0] -> children always false, always true, both
-    void getLeaves( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::map< int, std::vector< Node > >& v, IndexFilter * f = NULL );
-    /** is this trie empty? */
-    bool isEmpty() { return d_term.isNull() && d_children.empty(); }
-    /** clear this trie */
-    void clear() {
-      d_term = Node::null();
-      d_children.clear(); 
-    }
-
-   private:
-    /** the term at this node */
-    Node d_term;
-    /** the children nodes of this trie */
-    std::map<Node, SubsumeTrie> d_children;
-    /** helper function for above functions */
-    Node addTermInternal(CegConjecturePbe* pbe,
-                         Node t,
-                         std::vector<Node>& vals,
-                         bool pol,
-                         std::vector<Node>& subsumed,
-                         bool spol,
-                         IndexFilter* f,
-                         unsigned index,
-                         int status,
-                         bool checkExistsOnly,
-                         bool checkSubsume);
-    /** helper function for above functions */
-    void getLeavesInternal(CegConjecturePbe* pbe,
-                           std::vector<Node>& vals,
-                           bool pol,
-                           std::map<int, std::vector<Node> >& v,
-                           IndexFilter* f,
-                           unsigned index,
-                           int status);
-  };
-  // -------------------------------- end decision tree learning
-
-  //------------------------------ representation of a enumeration strategy
-
-  /** information about an enumerator
-   *
-   * We say an enumerator is a master enumerator if it is the variable that
-   * we use to enumerate values for its sort. Master enumerators may have
-   * (possibly multiple) slave enumerators, stored in d_enum_slave,
-   */
-  class EnumInfo {
-   public:
-    EnumInfo() : d_role(enum_io), d_is_conditional(false) {}
-    /** initialize this class
-    * c is the parent function-to-synthesize
-    * role is the "role" the enumerator plays in the high-level strategy,
-    *   which is one of enum_* above.
-    */
-    void initialize(Node c, EnumRole role);
-    /** is this enumerator associated with a template? */
-    bool isTemplated() { return !d_template.isNull(); }
-    /** set conditional
-      *
-      * This flag is set to true if this enumerator may not apply to all
-      * input/output examples. For example, if this enumerator is used
-      * as an output value beneath a conditional in an instance of strat_ITE,
-      * then this enumerator is conditional.
-      */
-    void setConditional() { d_is_conditional = true; }
-    /** is conditional */
-    bool isConditional() { return d_is_conditional; }
-    void addEnumValue(CegConjecturePbe* pbe,
-                      Node v,
-                      std::vector<Node>& results);
-    void setSolved(Node slv);
-    bool isSolved() { return !d_enum_solved.isNull(); }
-    Node getSolved() { return d_enum_solved; }
-    EnumRole getRole() { return d_role; }
-    Node d_parent_candidate;
-    // for template
-    Node d_template;
-    Node d_template_arg;
-
-    Node d_active_guard;
-    std::vector<Node> d_enum_slave;
-    /** values we have enumerated */
-    std::vector<Node> d_enum_vals;
-    /**
-      * This either stores the values of f( I ) for inputs
-      * or the value of f( I ) = O if d_role==enum_io
-      */
-    std::vector<std::vector<Node> > d_enum_vals_res;
-    std::vector<Node> d_enum_subsume;
-    std::map<Node, unsigned> d_enum_val_to_index;
-    SubsumeTrie d_term_trie;
-
-   private:
-    /**
-     * Whether an enumerated value for this conjecture has solved the entire
-     * conjecture.
-     */
-    Node d_enum_solved;
-    /** the role of this enumerator (one of enum_* above). */
-    EnumRole d_role;
-    /** is this enumerator conditional */
-    bool d_is_conditional;
-  };
-  /** maps enumerators to the information above */
-  std::map< Node, EnumInfo > d_einfo;
-
-  class CandidateInfo;
-
-  /** represents a strategy for a SyGuS datatype type
-   *
-   * This represents a possible strategy to apply when processing a strategy
-   * node in constructSolution. When applying the strategy represented by this
-   * class, we may make recursive calls to the children of the strategy,
-   * given in d_cenum. If all recursive calls to constructSolution are
-   * successful, say:
-   *   constructSolution( c, d_cenum[1], ... ) = t1,
-   *    ...,
-   *   constructSolution( c, d_cenum[n], ... ) = tn,
-   * Then, the solution returned by this strategy is
-   *   d_sol_templ * { d_sol_templ_args -> (t1,...,tn) }
-   */
-  class EnumTypeInfoStrat {
-   public:
-    /** the type of strategy this represents */
-    StrategyType d_this;
-    /** the sygus datatype constructor that induced this strategy
-     *
-     * For example, this may be a sygus datatype whose sygus operator is ITE,
-     * if the strategy type above is strat_ITE.
-     */
-    Node d_cons;
-    /** children of this strategy */
-    std::vector<std::pair<Node, NodeRole> > d_cenum;
-    /** the arguments for the (templated) solution */
-    std::vector<Node> d_sol_templ_args;
-    /** the template for the solution */
-    Node d_sol_templ;
-  };
-
-  /** represents a node in the strategy graph
-   *
-   * It contains a list of possible strategies which are tried during calls
-   * to constructSolution.
-   */
-  class StrategyNode
-  {
-   public:
-    StrategyNode() {}
-    ~StrategyNode();
-    /** the set of strategies to try at this node in the strategy graph */
-    std::vector<EnumTypeInfoStrat*> d_strats;
-  };
-
-  /** stores enumerators and strategies for a SyGuS datatype type */
-  class EnumTypeInfo {
-  public:
-    EnumTypeInfo() : d_parent( NULL ){}
-    /** the parent candidate info (see below) */
-    CandidateInfo * d_parent;
-    /** the type that this information is for */
-    TypeNode d_this_type;
-    /** map from enum roles to enumerators for this type */
-    std::map<EnumRole, Node> d_enum;
-    /** map from node roles to strategy nodes */
-    std::map<NodeRole, StrategyNode> d_snodes;
-  };
-
-  /** stores strategy and enumeration information for a function-to-synthesize
-   */
-  class CandidateInfo {
-  public:
-    CandidateInfo() : d_check_sol( false ), d_cond_count( 0 ){}
-    Node d_this_candidate;
-    /**
-     * The root sygus datatype for the function-to-synthesize,
-     * which encodes the overall syntactic restrictions on the space
-     * of solutions.
-     */
-    TypeNode d_root;
-    /** Info for sygus datatype type occurring in a field of d_root */
-    std::map< TypeNode, EnumTypeInfo > d_tinfo;
-    /** list of all enumerators for the function-to-synthesize */
-    std::vector< Node > d_esym_list;
-    /**
-     * Maps sygus datatypes to their search enumerator. This is the (single)
-     * enumerator of that type that we enumerate values for.
-     */
-    std::map< TypeNode, Node > d_search_enum;
-    bool d_check_sol;
-    unsigned d_cond_count;
-    Node d_solution;
-    void initialize( Node c );
-    void initializeType( TypeNode tn );
-    Node getRootEnumerator();
-    bool isNonTrivial();
-  };
-  /** maps a function-to-synthesize to the above information */
-  std::map< Node, CandidateInfo > d_cinfo;
-
-  //------------------------------ representation of an enumeration strategy
-  /** add enumerated value
-   *
-   * We have enumerated the value v for x. This function adds x->v to the
-   * relevant data structures that are used for strategy-specific construction
-   * of solutions when necessary, and returns a set of lemmas, which are added
-   * to the input argument lems. These lemmas are used to rule out models where
-   * x = v, to force that a new value is enumerated for x.
-   */
-  void addEnumeratedValue( Node x, Node v, std::vector< Node >& lems );
-  /** domain-specific enumerator exclusion techniques
-   *
-   * Returns true if the value v for x can be excluded based on a
-   * domain-specific exclusion technique like the ones below.
-   *
-   * c : the candidate variable that x is enumerating for,
-   * results : the values of v under the input examples of c,
-   * ei : the enumerator information for x,
-   * exp : if this function returns true, then exp contains a (possibly
-   * generalize) explanation for why v can be excluded.
-   */
-  bool getExplanationForEnumeratorExclude( Node c, Node x, Node v, std::vector< Node >& results, EnumInfo& ei, std::vector< Node >& exp );
-  /** returns true if we can exlude values of x based on negative str.contains
-   *
-   * Values v for x may be excluded if we realize that the value of v under the
-   * substitution for some input example will never be contained in some output
-   * example. For details on this technique, see NegContainsSygusInvarianceTest
-   * in sygus_invariance.h.
-   *
-   * This function depends on whether x is being used to enumerate values
-   * for any node that is conditional in the strategy graph. For example,
-   * nodes that are children of ITE strategy nodes are conditional. If any node
-   * is conditional, then this function returns false.
-   */
-  bool useStrContainsEnumeratorExclude(Node x, EnumInfo& ei);
-  /** cache for the above function */
-  std::map<Node, bool> d_use_str_contains_eexc;
-
-  //------------------------------ strategy registration
-  /** collect enumerator types
-   *
-   * This builds the strategy for enumerated values of type tn for the given
-   * role of nrole, for solutions to function-to-synthesize c.
-   */
-  void collectEnumeratorTypes(Node c, TypeNode tn, NodeRole nrole);
-  /** register enumerator
-   *
-   * This registers that et is an enumerator for function-to-synthesize c
-   * of type tn, having enumerator role enum_role.
-   *
-   * inSearch is whether we will enumerate values based on this enumerator.
-   * A strategy node is represented by a (enumerator, node role) pair. Hence,
-   * we may use enumerators for which this flag is false to represent strategy
-   * nodes that have child strategies.
-   */
-  void registerEnumerator(
-      Node et, Node c, TypeNode tn, EnumRole enum_role, bool inSearch);
-  /** infer template */
-  bool inferTemplate(unsigned k,
-                     Node n,
-                     std::map<Node, unsigned>& templ_var_index,
-                     std::map<unsigned, unsigned>& templ_injection);
-  /** static learn redundant operators
-   *
-   * This learns static lemmas for pruning enumerative space based on the
-   * strategy for the function-to-synthesize c, and stores these into lemmas.
-   */
-  void staticLearnRedundantOps(Node c, std::vector<Node>& lemmas);
-  /** helper for static learn redundant operators
-   *
-   * (e, nrole) specify the strategy node in the graph we are currently
-   * analyzing, visited stores the nodes we have already visited.
-   *
-   * This method builds the mapping needs_cons, which maps (master) enumerators
-   * to a map from the constructors that it needs.
-   *
-   * ind is the depth in the strategy graph we are at (for debugging).
-   *
-   * isCond is whether the current enumerator is conditional (beneath a
-   * conditional of an strat_ITE strategy).
-   */
-  void staticLearnRedundantOps(
-      Node c,
-      Node e,
-      NodeRole nrole,
-      std::map<Node, std::map<NodeRole, bool> >& visited,
-      std::map<Node, std::map<unsigned, bool> >& needs_cons,
-      int ind,
-      bool isCond);
-  //------------------------------ end strategy registration
-
-  //------------------------------ constructing solutions
-  class UnifContext {
-  public:
-   UnifContext() : d_has_string_pos(role_invalid) {}
-   /** this intiializes this context for function-to-synthesize c */
-   void initialize(CegConjecturePbe* pbe, Node c);
-
-   //----------for ITE strategy
-   /** the value of the context conditional
-    *
-    * This stores a list of Boolean constants that is the same length of the
-    * number of input/output example pairs we are considering. For each i,
-    * if d_vals[i] = true, i/o pair #i is active according to this context
-    * if d_vals[i] = false, i/o pair #i is inactive according to this context
-    */
-   std::vector<Node> d_vals;
-   /** update the examples
-    *
-    * if pol=true, this method updates d_vals to d_vals & vals
-    * if pol=false, this method updates d_vals to d_vals & ( ~vals )
-    */
-   bool updateContext(CegConjecturePbe* pbe, std::vector<Node>& vals, bool pol);
-   //----------end for ITE strategy
-
-   //----------for CONCAT strategies
-   /** the position in the strings
-    *
-    * For each i/o example pair, this stores the length of the current solution
-    * for the input of the pair, where the solution for that input is a prefix
-    * or
-    * suffix of the output of the pair. For example, if our i/o pairs are:
-    *   f( "abcd" ) = "abcdcd"
-    *   f( "aa" ) = "aacd"
-    * If the solution we have currently constructed is str.++( x1, "c", ... ),
-    * then d_str_pos = ( 5, 3 ), where notice that
-    *   str.++( "abc", "c" ) is a prefix of "abcdcd" and
-    *   str.++( "aa", "c" ) is a prefix of "aacd".
-    */
-   std::vector<unsigned> d_str_pos;
-   /** has string position
-    *
-    * Whether the solution positions indicate a prefix or suffix of the output
-    * examples. If this is role_invalid, then we have not updated the string
-    * position.
-    */
-   NodeRole d_has_string_pos;
-   /** update the string examples
-    *
-    * This method updates d_str_pos to d_str_pos + pos.
-    */
-   bool updateStringPosition(CegConjecturePbe* pbe, std::vector<unsigned>& pos);
-   /** get current strings
-    *
-    * This returns the prefix/suffix of the string constants stored in vals
-    * of size d_str_pos, and stores the result in ex_vals. For example, if vals
-    * is (abcdcd", "aacde") and d_str_pos = ( 5, 3 ), then we add
-    * "d" and "de" to ex_vals.
-    */
-   void getCurrentStrings(CegConjecturePbe* pbe,
-                          const std::vector<Node>& vals,
-                          std::vector<String>& ex_vals);
-   /** get string increment
-    *
-    * If this method returns true, then inc and tot are updated such that
-    *   for all active indices i,
-    *      vals[i] is a prefix (or suffix if isPrefix=false) of ex_vals[i], and
-    *      inc[i] = str.len(vals[i])
-    *   for all inactive indices i, inc[i] = 0
-    * We set tot to the sum of inc[i] for i=1,...,n. This indicates the total
-    * number of characters incremented across all examples.
-    */
-   bool getStringIncrement(CegConjecturePbe* pbe,
-                           bool isPrefix,
-                           const std::vector<String>& ex_vals,
-                           const std::vector<Node>& vals,
-                           std::vector<unsigned>& inc,
-                           unsigned& tot);
-   /** returns true if ex_vals[i] = vals[i] for all active indices i. */
-   bool isStringSolved(CegConjecturePbe* pbe,
-                       const std::vector<String>& ex_vals,
-                       const std::vector<Node>& vals);
-   //----------end for CONCAT strategies
-
-   /** is return value modified?
-    *
-    * This returns true if we are currently in a state where the return value
-    * of the solution has been modified, e.g. by a previous node that solved
-    * for a prefix.
-    */
-   bool isReturnValueModified();
-   /** returns true if argument is valid strategy in this context */
-   bool isValidStrategy(EnumTypeInfoStrat* etis);
-   /** visited role
-    *
-    * This is the current set of enumerator/node role pairs we are currently
-    * visiting. This set is cleared when the context is updated.
-    */
-   std::map<Node, std::map<NodeRole, bool> > d_visit_role;
-
-   /** unif context enumerator information */
-   class UEnumInfo
-   {
-    public:
-     UEnumInfo() {}
-     /** map from conditions and branch positions to a solved node
-      *
-      * For example, if we have:
-      *   f( 1 ) = 2 ^ f( 3 ) = 4 ^ f( -1 ) = 1
-      * Then, valid entries in this map is:
-      *   d_look_ahead_sols[x>0][1] = x+1
-      *   d_look_ahead_sols[x>0][2] = 1
-      * For the first entry, notice that  for all input examples such that x>0
-      * evaluates to true, which are (1) and (3), we have that their output
-      * values for x+1 under the substitution that maps x to the input value,
-      * resulting in 2 and 4, are equal to the output value for the respective
-      * pairs.
-      */
-     std::map<Node, std::map<unsigned, Node> > d_look_ahead_sols;
-    };
-    /** map from enumerators to the above info class */
-    std::map< Node, UEnumInfo > d_uinfo;
-  };
-
-  /** construct solution
-   *
-   * This method tries to construct a solution for function-to-synthesize c
-   * based on the strategy stored for c in d_cinfo, which may include
-   * synthesis-by-unification approaches for ite and string concatenation terms.
-   * These approaches include the work of Alur et al. TACAS 2017.
-   * If it cannot construct a solution, it returns the null node.
-   */
-  Node constructSolution( Node c );
-  /** helper function for construct solution.
-   *
-   * Construct a solution based on enumerator e for function-to-synthesize c
-   * with node role nrole in context x.
-   *
-   * ind is the term depth of the context (for debugging).
-   */
-  Node constructSolution(
-      Node c, Node e, NodeRole nrole, UnifContext& x, int ind);
-  /** Heuristically choose the best solved term from solved in context x,
-   * currently return the first. */
-  Node constructBestSolvedTerm( std::vector< Node >& solved, UnifContext& x );
-  /** Heuristically choose the best solved string term  from solved in context
-   * x, currently  return the first. */
-  Node constructBestStringSolvedTerm( std::vector< Node >& solved, UnifContext& x );
-  /** Heuristically choose the best solved conditional term  from solved in
-   * context x, currently random */
-  Node constructBestSolvedConditional( std::vector< Node >& solved, UnifContext& x );
-  /** Heuristically choose the best conditional term  from conds in context x,
-   * currently random */
-  Node constructBestConditional( std::vector< Node >& conds, UnifContext& x );
-  /** Heuristically choose the best string to concatenate from strs to the
-  * solution in context x, currently random
-  * incr stores the vector of indices that are incremented by this solution in
-  * example outputs.
-  * total_inc[x] is the sum of incr[x] for each x in strs.
-  */
-  Node constructBestStringToConcat( std::vector< Node > strs,
-                                    std::map< Node, unsigned > total_inc, 
-                                    std::map< Node, std::vector< unsigned > > incr,
-                                    UnifContext& x );
-  //------------------------------ end constructing solutions
-};
-
-}/* namespace CVC4::theory::quantifiers */
-}/* namespace CVC4::theory */
-}/* namespace CVC4 */
-
-#endif
diff --git a/src/theory/quantifiers/ce_guided_single_inv.cpp b/src/theory/quantifiers/ce_guided_single_inv.cpp
deleted file mode 100644 (file)
index b2b4fe1..0000000
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*********************                                                        */
-/*! \file ce_guided_single_inv.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief utility for processing single invocation synthesis conjectures
- **
- **/
-#include "theory/quantifiers/ce_guided_single_inv.h"
-
-#include "options/quantifiers_options.h"
-#include "theory/arith/arith_msum.h"
-#include "theory/quantifiers/term_enumeration.h"
-#include "theory/quantifiers/term_util.h"
-
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace std;
-
-namespace CVC4 {
-
-bool CegqiOutputSingleInv::doAddInstantiation( std::vector< Node >& subs ) {
-  return d_out->doAddInstantiation( subs );
-}
-
-bool CegqiOutputSingleInv::isEligibleForInstantiation( Node n ) {
-  return d_out->isEligibleForInstantiation( n );
-}
-
-bool CegqiOutputSingleInv::addLemma( Node n ) {
-  return d_out->addLemma( n );
-}
-
-CegConjectureSingleInv::CegConjectureSingleInv(QuantifiersEngine* qe,
-                                               CegConjecture* p)
-    : d_qe(qe),
-      d_parent(p),
-      d_sip(new SingleInvocationPartition),
-      d_sol(new CegConjectureSingleInvSol(qe)),
-      d_cosi(new CegqiOutputSingleInv(this)),
-      d_cinst(NULL),
-      d_c_inst_match_trie(NULL),
-      d_has_ites(true),
-      d_single_invocation(false) {
-  //  third and fourth arguments set to (false,false) until we have solution
-  //  reconstruction for delta and infinity
-  d_cinst = new CegInstantiator(d_qe, d_cosi, false, false);
-
-  if (options::incrementalSolving()) {
-    d_c_inst_match_trie = new inst::CDInstMatchTrie(qe->getUserContext());
-  }
-}
-
-CegConjectureSingleInv::~CegConjectureSingleInv() {
-  if (d_c_inst_match_trie) {
-    delete d_c_inst_match_trie;
-  }
-  delete d_cinst;
-  delete d_cosi;
-  delete d_sol;  // (new CegConjectureSingleInvSol(qe)),
-  delete d_sip;  // d_sip(new SingleInvocationPartition),
-}
-
-void CegConjectureSingleInv::getInitialSingleInvLemma( std::vector< Node >& lems ) {
-  Assert( d_si_guard.isNull() );
-  //single invocation guard
-  d_si_guard = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "G", NodeManager::currentNM()->booleanType() ) );
-  d_si_guard = d_qe->getValuation().ensureLiteral( d_si_guard );
-  AlwaysAssert( !d_si_guard.isNull() );
-  d_qe->getOutputChannel().requirePhase( d_si_guard, true );
-
-  if( !d_single_inv.isNull() ) {
-    //make for new var/sk
-    d_single_inv_var.clear();
-    d_single_inv_sk.clear();
-    Node inst;
-    if( d_single_inv.getKind()==FORALL ){
-      for( unsigned i=0; i<d_single_inv[0].getNumChildren(); i++ ){
-        std::stringstream ss;
-        ss << "k_" << d_single_inv[0][i];
-        Node k = NodeManager::currentNM()->mkSkolem( ss.str(), d_single_inv[0][i].getType(), "single invocation function skolem" );
-        d_single_inv_var.push_back( d_single_inv[0][i] );
-        d_single_inv_sk.push_back( k );
-        d_single_inv_sk_index[k] = i;
-      }
-      inst = d_single_inv[1].substitute( d_single_inv_var.begin(), d_single_inv_var.end(), d_single_inv_sk.begin(), d_single_inv_sk.end() );
-    }else{
-      inst = d_single_inv;
-    }
-    inst = TermUtil::simpleNegate( inst );
-    Trace("cegqi-si") << "Single invocation initial lemma : " << inst << std::endl;
-
-    //register with the instantiator
-    Node ginst = NodeManager::currentNM()->mkNode( OR, d_si_guard.negate(), inst );
-    lems.push_back( ginst );
-    //make and register the instantiator
-    if( d_cinst ){
-      delete d_cinst;
-    }
-    d_cinst = new CegInstantiator( d_qe, d_cosi, false, false );
-    d_cinst->registerCounterexampleLemma( lems, d_single_inv_sk );
-  }
-}
-
-void CegConjectureSingleInv::initialize( Node q ) {
-  // can only register one quantified formula with this
-  Assert( d_quant.isNull() );
-  d_quant = q;
-  d_simp_quant = q;
-  Trace("cegqi-si") << "CegConjectureSingleInv::initialize : " << q << std::endl;
-  // infer single invocation-ness
-  std::vector< Node > progs;
-  std::map< Node, std::vector< Node > > prog_vars;
-  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
-    Node sf = q[0][i];
-    progs.push_back( sf );
-    Node sfvl = sf.getAttribute(SygusSynthFunVarListAttribute());
-    for( unsigned j=0; j<sfvl.getNumChildren(); j++ ){
-      prog_vars[sf].push_back( sfvl[j] );
-    }
-  }
-  // compute single invocation partition
-  if( options::cegqiSingleInvMode()!=CEGQI_SI_MODE_NONE ){
-    Node qq;
-    if( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ){
-      qq = q[1][0][1];
-    }else{
-      qq = TermUtil::simpleNegate( q[1] );
-    }
-    //process the single invocation-ness of the property
-    if( !d_sip->init( progs, qq ) ){
-      Trace("cegqi-si") << "...not single invocation (type mismatch)" << std::endl;
-    }else{
-      Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl;
-      d_sip->debugPrint( "cegqi-si" );
-
-      //map from program to bound variables
-      std::vector<Node> funcs;
-      d_sip->getFunctions(funcs);
-      for (unsigned j = 0, size = funcs.size(); j < size; j++)
-      {
-        Assert(std::find(progs.begin(), progs.end(), funcs[j]) != progs.end());
-        d_prog_to_sol_index[funcs[j]] = j;
-      }
-
-      //check if it is single invocation
-      if (!d_sip->isPurelySingleInvocation())
-      {
-        if( options::sygusInvTemplMode() != SYGUS_INV_TEMPL_MODE_NONE ){
-          //if we are doing invariant templates, then construct the template
-          Trace("cegqi-si") << "- Do transition inference..." << std::endl;
-          d_ti[q].process( qq );
-          Trace("cegqi-inv") << std::endl;
-          if( !d_ti[q].d_func.isNull() ){
-            // map the program back via non-single invocation map
-            Node prog = d_ti[q].d_func;
-            std::vector< Node > prog_templ_vars;
-            prog_templ_vars.insert( prog_templ_vars.end(), d_ti[q].d_vars.begin(), d_ti[q].d_vars.end() );
-            d_trans_pre[prog] = d_ti[q].getComponent( 1 );
-            d_trans_post[prog] = d_ti[q].getComponent( -1 );
-            Trace("cegqi-inv") << "   precondition : " << d_trans_pre[prog] << std::endl;
-            Trace("cegqi-inv") << "  postcondition : " << d_trans_post[prog] << std::endl;
-            std::vector<Node> sivars;
-            d_sip->getSingleInvocationVariables(sivars);
-            Node invariant = d_sip->getFunctionInvocationFor(prog);
-            Assert(!invariant.isNull());
-            invariant = invariant.substitute(sivars.begin(),
-                                             sivars.end(),
-                                             prog_templ_vars.begin(),
-                                             prog_templ_vars.end());
-            Trace("cegqi-inv") << "      invariant : " << invariant << std::endl;
-            
-            // store simplified version of quantified formula
-            d_simp_quant = d_sip->getFullSpecification();
-            std::vector< Node > new_bv;
-            for (unsigned j = 0, size = sivars.size(); j < size; j++)
-            {
-              new_bv.push_back(
-                  NodeManager::currentNM()->mkBoundVar(sivars[j].getType()));
-            }
-            d_simp_quant = d_simp_quant.substitute(
-                sivars.begin(), sivars.end(), new_bv.begin(), new_bv.end());
-            Assert( q[1].getKind()==NOT && q[1][0].getKind()==FORALL );
-            for( unsigned j=0; j<q[1][0][0].getNumChildren(); j++ ){
-              new_bv.push_back( q[1][0][0][j] );
-            }
-            d_simp_quant = NodeManager::currentNM()->mkNode( kind::FORALL, NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, new_bv ), d_simp_quant ).negate();
-            d_simp_quant = Rewriter::rewrite( d_simp_quant );
-            d_simp_quant = NodeManager::currentNM()->mkNode( kind::FORALL, q[0], d_simp_quant, q[2] );
-            Trace("cegqi-si") << "Rewritten quantifier : " << d_simp_quant << std::endl;
-
-            //construct template argument
-            d_templ_arg[prog] = NodeManager::currentNM()->mkSkolem( "I", invariant.getType() );
-            
-            //construct template
-            Node templ;
-            if( options::sygusInvAutoUnfold() ){
-              if( d_ti[q].isComplete() ){
-                Trace("cegqi-inv-auto-unfold") << "Automatic deterministic unfolding... " << std::endl;
-                // auto-unfold
-                DetTrace dt;
-                int init_dt = d_ti[q].initializeTrace( dt );
-                if( init_dt==0 ){
-                  Trace("cegqi-inv-auto-unfold") << "  Init : ";
-                  dt.print("cegqi-inv-auto-unfold");
-                  Trace("cegqi-inv-auto-unfold") << std::endl;
-                  unsigned counter = 0;
-                  unsigned status = 0;
-                  while( counter<100 && status==0 ){
-                    status = d_ti[q].incrementTrace( dt );
-                    counter++;
-                    Trace("cegqi-inv-auto-unfold") << "  #" << counter << " : ";
-                    dt.print("cegqi-inv-auto-unfold");
-                    Trace("cegqi-inv-auto-unfold") << "...status = " << status << std::endl;
-                  }
-                  if( status==1 ){
-                    // we have a trivial invariant
-                    templ = d_ti[q].constructFormulaTrace( dt );
-                    Trace("cegqi-inv") << "By finite deterministic terminating trace, a solution invariant is : " << std::endl;
-                    Trace("cegqi-inv") << "   " << templ << std::endl;
-                    // FIXME : this should be unnecessary
-                    templ = NodeManager::currentNM()->mkNode( AND, templ, d_templ_arg[prog] );
-                  }
-                }else{
-                  Trace("cegqi-inv-auto-unfold") << "...failed initialize." << std::endl;
-                }
-              }
-            }
-            if( templ.isNull() ){
-              if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){
-                //d_templ[prog] = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] );
-                templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], d_templ_arg[prog] );
-              }else{
-                Assert( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST );
-                //d_templ[prog] = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) );
-                templ = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], d_templ_arg[prog] );
-              }
-            }
-            Trace("cegqi-inv") << "       template (pre-substitution) : " << templ << std::endl;
-            Assert( !templ.isNull() );
-            // subsitute the template arguments
-            templ = templ.substitute( prog_templ_vars.begin(), prog_templ_vars.end(), prog_vars[prog].begin(), prog_vars[prog].end() );
-            Trace("cegqi-inv") << "       template : " << templ << std::endl;
-            d_templ[prog] = templ;
-          }
-        }
-      }else{
-        //we are fully single invocation
-        d_single_invocation = true;
-      }
-    }
-  }
-}
-
-void CegConjectureSingleInv::finishInit( bool syntaxRestricted, bool hasItes ) {
-  d_has_ites = hasItes;
-  // do not do single invocation if grammar is restricted and CEGQI_SI_MODE_ALL is not enabled
-  if( options::cegqiSingleInvMode()==CEGQI_SI_MODE_USE && d_single_invocation && syntaxRestricted ){
-    d_single_invocation = false;
-    Trace("cegqi-si") << "...grammar is restricted, do not use single invocation techniques." << std::endl;
-  }
-
-  // we now have determined whether we will do single invocation techniques
-  if( d_single_invocation ){
-    d_single_inv = d_sip->getSingleInvocation();
-    d_single_inv = TermUtil::simpleNegate( d_single_inv );
-    std::vector<Node> func_vars;
-    d_sip->getFunctionVariables(func_vars);
-    if (!func_vars.empty())
-    {
-      Node pbvl = NodeManager::currentNM()->mkNode(BOUND_VAR_LIST, func_vars);
-      d_single_inv = NodeManager::currentNM()->mkNode( FORALL, pbvl, d_single_inv );
-    }
-    //now, introduce the skolems
-    std::vector<Node> sivars;
-    d_sip->getSingleInvocationVariables(sivars);
-    for (unsigned i = 0, size = sivars.size(); i < size; i++)
-    {
-      Node v = NodeManager::currentNM()->mkSkolem(
-          "a", sivars[i].getType(), "single invocation arg");
-      d_single_inv_arg_sk.push_back( v );
-    }
-    d_single_inv = d_single_inv.substitute(sivars.begin(),
-                                           sivars.end(),
-                                           d_single_inv_arg_sk.begin(),
-                                           d_single_inv_arg_sk.end());
-    Trace("cegqi-si") << "Single invocation formula is : " << d_single_inv << std::endl;
-    if( options::cbqiPreRegInst() && d_single_inv.getKind()==FORALL ){
-      //just invoke the presolve now
-      d_cinst->presolve( d_single_inv );
-    }
-  }else{
-    d_single_inv = Node::null();
-    Trace("cegqi-si") << "Formula is not single invocation." << std::endl;
-    if( options::cegqiSingleInvAbort() ){
-      Notice() << "Property is not single invocation." << std::endl;
-      exit( 1 );
-    }
-  }
-}
-
-bool CegConjectureSingleInv::doAddInstantiation( std::vector< Node >& subs ){
-  Assert( d_single_inv_sk.size()==subs.size() );
-  Trace("cegqi-si-inst-debug") << "CegConjectureSingleInv::doAddInstantiation, #vars = ";
-  Trace("cegqi-si-inst-debug") << d_single_inv_sk.size() << "..." << std::endl;
-  std::stringstream siss;
-  if( Trace.isOn("cegqi-si-inst-debug") || Trace.isOn("cegqi-engine") ){
-    siss << "  * single invocation: " << std::endl;
-    for( unsigned j=0; j<d_single_inv_sk.size(); j++ ){
-      Node op = d_sip->getFunctionForFirstOrderVariable(d_single_inv[0][j]);
-      Assert(!op.isNull());
-      siss << "    * " << op;
-      siss << " (" << d_single_inv_sk[j] << ")";
-      siss << " -> " << subs[j] << std::endl;
-    }
-  }
-  Trace("cegqi-si-inst-debug") << siss.str();
-
-  bool alreadyExists;
-  Node lem;
-  if( subs.empty() ){
-    Assert( d_single_inv.getKind()!=FORALL );
-    alreadyExists = false;
-    lem = d_single_inv;
-  }else{
-    Assert( d_single_inv.getKind()==FORALL );
-    if( options::incrementalSolving() ){
-      alreadyExists = !d_c_inst_match_trie->addInstMatch( d_qe, d_single_inv, subs, d_qe->getUserContext() );
-    }else{
-      alreadyExists = !d_inst_match_trie.addInstMatch( d_qe, d_single_inv, subs );
-    }
-    Trace("cegqi-si-inst-debug") << "  * success = " << !alreadyExists << std::endl;
-    //Trace("cegqi-si-inst-debug") << siss.str();
-    //Trace("cegqi-si-inst-debug") << "  * success = " << !alreadyExists << std::endl;
-    if( alreadyExists ){
-      return false;
-    }else{
-      Trace("cegqi-engine") << siss.str() << std::endl;
-      Assert( d_single_inv_var.size()==subs.size() );
-      lem = d_single_inv[1].substitute( d_single_inv_var.begin(), d_single_inv_var.end(), subs.begin(), subs.end() );
-      if( d_qe->getTermUtil()->containsVtsTerm( lem ) ){
-        Trace("cegqi-engine-debug") << "Rewrite based on vts symbols..." << std::endl;
-        lem = d_qe->getTermUtil()->rewriteVtsSymbols( lem );
-      }
-    }
-  }
-  Trace("cegqi-engine-debug") << "Rewrite..." << std::endl;
-  lem = Rewriter::rewrite( lem );
-  Trace("cegqi-si") << "Single invocation lemma : " << lem << std::endl;
-  if( std::find( d_lemmas_produced.begin(), d_lemmas_produced.end(), lem )==d_lemmas_produced.end() ){
-    d_curr_lemmas.push_back( lem );
-    d_lemmas_produced.push_back( lem );
-    d_inst.push_back( std::vector< Node >() );
-    d_inst.back().insert( d_inst.back().end(), subs.begin(), subs.end() );
-  }
-  return true;
-}
-
-bool CegConjectureSingleInv::isEligibleForInstantiation( Node n ) {
-  return n.getKind()!=SKOLEM || std::find( d_single_inv_arg_sk.begin(), d_single_inv_arg_sk.end(), n )!=d_single_inv_arg_sk.end();
-}
-
-bool CegConjectureSingleInv::addLemma( Node n ) {
-  d_curr_lemmas.push_back( n );
-  return true;
-}
-
-bool CegConjectureSingleInv::check( std::vector< Node >& lems ) {
-  if( !d_single_inv.isNull() ) {
-    Trace("cegqi-si-debug") << "CegConjectureSingleInv::check..." << std::endl;
-    Trace("cegqi-si-debug") << "CegConjectureSingleInv::check consulting ceg instantiation..." << std::endl;
-    d_curr_lemmas.clear();
-    Assert( d_cinst!=NULL );
-    //call check for instantiator
-    d_cinst->check();
-    Trace("cegqi-si-debug") << "...returned " << d_curr_lemmas.size() << " lemmas " <<  std::endl;
-    //add lemmas
-    lems.insert( lems.end(), d_curr_lemmas.begin(), d_curr_lemmas.end() );
-    return !lems.empty();
-  }else{
-    // not single invocation
-    return false;
-  }
-}
-
-Node CegConjectureSingleInv::constructSolution( std::vector< unsigned >& indices, unsigned i, unsigned index, std::map< Node, Node >& weak_imp ) {
-  Assert( index<d_inst.size() );
-  Assert( i<d_inst[index].size() );
-  unsigned uindex = indices[index];
-  if( index==indices.size()-1 ){
-    return d_inst[uindex][i];
-  }else{
-    Node cond = d_lemmas_produced[uindex];
-    //weaken based on unsat core
-    std::map< Node, Node >::iterator itw = weak_imp.find( cond );
-    if( itw!=weak_imp.end() ){
-      cond = itw->second;
-    }
-    cond = TermUtil::simpleNegate( cond );
-    Node ite1 = d_inst[uindex][i];
-    Node ite2 = constructSolution( indices, i, index+1, weak_imp );
-    return NodeManager::currentNM()->mkNode( ITE, cond, ite1, ite2 );
-  }
-}
-
-//TODO: use term size?
-struct sortSiInstanceIndices {
-  CegConjectureSingleInv* d_ccsi;
-  int d_i;
-  bool operator() (unsigned i, unsigned j) {
-    if( d_ccsi->d_inst[i][d_i].isConst() && !d_ccsi->d_inst[j][d_i].isConst() ){
-      return true;
-    }else{
-      return false;
-    }
-  }
-};
-
-
-Node CegConjectureSingleInv::postProcessSolution( Node n ){
-  ////remove boolean ITE (not allowed for sygus comp 2015)
-  //if( n.getKind()==ITE && n.getType().isBoolean() ){
-  //  Node n1 = postProcessSolution( n[1] );
-  //  Node n2 = postProcessSolution( n[2] );
-  //  return NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, n[0], n1 ),
-  //                                               NodeManager::currentNM()->mkNode( AND, n[0].negate(), n2 ) );
-  //}else{
-  bool childChanged = false;
-  Kind k = n.getKind();
-  if( n.getKind()==INTS_DIVISION_TOTAL ){
-    k = INTS_DIVISION;
-    childChanged = true;
-  }else if( n.getKind()==INTS_MODULUS_TOTAL ){
-    k = INTS_MODULUS;
-    childChanged = true;
-  }
-  std::vector< Node > children;
-  for( unsigned i=0; i<n.getNumChildren(); i++ ){
-    Node nn = postProcessSolution( n[i] );
-    children.push_back( nn );
-    childChanged = childChanged || nn!=n[i];
-  }
-  if( childChanged ){
-    if( n.hasOperator() && k==n.getKind() ){
-      children.insert( children.begin(), n.getOperator() );
-    }
-    return NodeManager::currentNM()->mkNode( k, children );
-  }else{
-    return n;
-  }
-  //}
-}
-
-
-Node CegConjectureSingleInv::getSolution( unsigned sol_index, TypeNode stn, int& reconstructed, bool rconsSygus ){
-  Assert( d_sol!=NULL );
-  Assert( !d_lemmas_produced.empty() );
-  const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
-  Node varList = Node::fromExpr( dt.getSygusVarList() );
-  Node prog = d_quant[0][sol_index];
-  std::vector< Node > vars;
-  Node s;
-  if( d_prog_to_sol_index.find( prog )==d_prog_to_sol_index.end() ){
-    Trace("csi-sol") << "Get solution for (unconstrained) " << prog << std::endl;
-    s = d_qe->getTermEnumeration()->getEnumerateTerm(
-        TypeNode::fromType(dt.getSygusType()), 0);
-  }else{
-    Trace("csi-sol") << "Get solution for " << prog << ", with skolems : ";
-    sol_index = d_prog_to_sol_index[prog];
-    d_sol->d_varList.clear();
-    Assert( d_single_inv_arg_sk.size()==varList.getNumChildren() );
-    for( unsigned i=0; i<d_single_inv_arg_sk.size(); i++ ){
-      Trace("csi-sol") << d_single_inv_arg_sk[i] << " ";
-      vars.push_back( d_single_inv_arg_sk[i] );
-      d_sol->d_varList.push_back( varList[i] );
-    }
-    Trace("csi-sol") << std::endl;
-
-    //construct the solution
-    Trace("csi-sol") << "Sort solution return values " << sol_index << std::endl;
-    bool useUnsatCore = false;
-    std::vector< Node > active_lemmas;
-    //minimize based on unsat core, if possible
-    std::map< Node, Node > weak_imp;
-    if( options::cegqiSolMinCore() ){
-      if( options::cegqiSolMinInst() ){
-        if( d_qe->getUnsatCoreLemmas( active_lemmas, weak_imp ) ){
-          useUnsatCore = true;
-        }
-      }else{
-        if( d_qe->getUnsatCoreLemmas( active_lemmas ) ){
-          useUnsatCore = true;
-        }
-      }
-    } 
-    Assert( d_lemmas_produced.size()==d_inst.size() );
-    std::vector< unsigned > indices;
-    for( unsigned i=0; i<d_lemmas_produced.size(); i++ ){
-      bool incl = true;
-      if( useUnsatCore ){
-        incl = std::find( active_lemmas.begin(), active_lemmas.end(), d_lemmas_produced[i] )!=active_lemmas.end();
-      }
-      if( incl ){
-        Assert( sol_index<d_inst[i].size() );
-        indices.push_back( i );
-      }
-    }
-    Trace("csi-sol") << "...included " << indices.size() << " / " << d_lemmas_produced.size() << " instantiations." << std::endl;
-    Assert( !indices.empty() );
-    //sort indices based on heuristic : currently, do all constant returns first (leads to simpler conditions)
-    // TODO : to minimize solution size, put the largest term last
-    sortSiInstanceIndices ssii;
-    ssii.d_ccsi = this;
-    ssii.d_i = sol_index;
-    std::sort( indices.begin(), indices.end(), ssii );
-    Trace("csi-sol") << "Construct solution" << std::endl;
-    s = constructSolution( indices, sol_index, 0, weak_imp );
-    Assert( vars.size()==d_sol->d_varList.size() );
-    s = s.substitute( vars.begin(), vars.end(), d_sol->d_varList.begin(), d_sol->d_varList.end() );
-  }
-  d_orig_solution = s;
-
-  //simplify the solution
-  Trace("csi-sol") << "Solution (pre-simplification): " << d_orig_solution << std::endl;
-  s = d_sol->simplifySolution( s, stn );
-  Trace("csi-sol") << "Solution (post-simplification): " << s << std::endl;
-  return reconstructToSyntax( s, stn, reconstructed, rconsSygus );
-}
-
-Node CegConjectureSingleInv::reconstructToSyntax( Node s, TypeNode stn, int& reconstructed, bool rconsSygus ) {
-  d_solution = s;
-  const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
-
-  //reconstruct the solution into sygus if necessary
-  reconstructed = 0;
-  if( options::cegqiSingleInvReconstruct() && !dt.getSygusAllowAll() && !stn.isNull() && rconsSygus ){
-    d_sol->preregisterConjecture( d_orig_conjecture );
-    d_sygus_solution = d_sol->reconstructSolution( s, stn, reconstructed );
-    if( reconstructed==1 ){
-      Trace("csi-sol") << "Solution (post-reconstruction into Sygus): " << d_sygus_solution << std::endl;
-    }
-  }else{
-    Trace("csi-sol") << "Post-process solution..." << std::endl;
-    Node prev = d_solution;
-    d_solution = postProcessSolution( d_solution );
-    if( prev!=d_solution ){
-      Trace("csi-sol") << "Solution (after post process) : " << d_solution << std::endl;
-    }
-  }
-
-
-  if( Trace.isOn("csi-sol") ){
-    //debug solution
-    if( !d_sol->debugSolution( d_solution ) ){
-      Trace("csi-sol") << "WARNING : solution " << d_solution << " contains free constants." << std::endl;
-      //exit( 47 );
-    }else{
-      //exit( 49 );
-    }
-  }
-  if( Trace.isOn("cegqi-stats") ){
-    int tsize, itesize;
-    tsize = 0;itesize = 0;
-    d_sol->debugTermSize( d_orig_solution, tsize, itesize );
-    Trace("cegqi-stats") << tsize << " " << itesize << " ";
-    tsize = 0;itesize = 0;
-    d_sol->debugTermSize( d_solution, tsize, itesize );
-    Trace("cegqi-stats") << tsize << " " << itesize << " ";
-    if( !d_sygus_solution.isNull() ){
-      tsize = 0;itesize = 0;
-      d_sol->debugTermSize( d_sygus_solution, tsize, itesize );
-      Trace("cegqi-stats") << tsize << " - ";
-    }else{
-      Trace("cegqi-stats") << "null ";
-    }
-    Trace("cegqi-stats") << std::endl;
-  }
-  Node sol;
-  if( reconstructed==1 ){
-    sol = d_sygus_solution;
-  }else if( reconstructed==-1 ){
-    return Node::null();
-  }else{
-    sol = d_solution;
-  }
-  //make into lambda
-  if( !dt.getSygusVarList().isNull() ){
-    Node varList = Node::fromExpr( dt.getSygusVarList() );
-    return NodeManager::currentNM()->mkNode( LAMBDA, varList, sol );
-  }else{
-    return sol;
-  }
-}
-
-bool CegConjectureSingleInv::needsCheck() {
-  if( options::cegqiSingleInvMode()==CEGQI_SI_MODE_ALL_ABORT ){
-    if( !d_has_ites ){
-      return d_inst.empty();
-    }
-  }
-  return true;
-}
-
-void CegConjectureSingleInv::preregisterConjecture( Node q ) {
-  d_orig_conjecture = q;
-}
-
-bool DetTrace::DetTraceTrie::add( Node loc, std::vector< Node >& val, unsigned index ){
-  if( index==val.size() ){
-    if( d_children.empty() ){
-      d_children[loc].clear();
-      return true;
-    }else{
-      return false;
-    }
-  }else{
-    return d_children[val[index]].add( loc, val, index+1 );
-  }
-}
-
-Node DetTrace::DetTraceTrie::constructFormula( std::vector< Node >& vars, unsigned index ){
-  if( index==vars.size() ){
-    return NodeManager::currentNM()->mkConst( true );    
-  }else{
-    std::vector< Node > disj;
-    for( std::map< Node, DetTraceTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
-      Node eq = vars[index].eqNode( it->first );
-      if( index<vars.size()-1 ){
-        Node conc = it->second.constructFormula( vars, index+1 );
-        disj.push_back( NodeManager::currentNM()->mkNode( kind::AND, eq, conc ) );
-      }else{
-        disj.push_back( eq );
-      }
-    }
-    Assert( !disj.empty() );
-    return disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( kind::OR, disj );
-  }
-}
-
-bool DetTrace::increment( Node loc, std::vector< Node >& vals ){
-  if( d_trie.add( loc, vals ) ){
-    for( unsigned i=0; i<vals.size(); i++ ){
-      d_curr[i] = vals[i];
-    }
-    return true;
-  }else{
-    return false;
-  }
-}
-
-Node DetTrace::constructFormula( std::vector< Node >& vars ) {
-  return d_trie.constructFormula( vars );
-}
-
-
-void DetTrace::print( const char* c ) {
-  for( unsigned i=0; i<d_curr.size(); i++ ){
-    Trace(c) << d_curr[i] << " ";
-  }
-}
-
-void TransitionInference::initialize( Node f, std::vector< Node >& vars ) {
-  Assert( d_vars.empty() );
-  d_func = f;
-  d_vars.insert( d_vars.end(), vars.begin(), vars.end() );
-}
-
-
-void TransitionInference::getConstantSubstitution( std::vector< Node >& vars, std::vector< Node >& disjuncts, std::vector< Node >& const_var, std::vector< Node >& const_subs, bool reqPol ) {
-  for( unsigned j=0; j<disjuncts.size(); j++ ){
-    Node sn;
-    if( !const_var.empty() ){
-      sn = disjuncts[j].substitute( const_var.begin(), const_var.end(), const_subs.begin(), const_subs.end() );
-      sn = Rewriter::rewrite( sn );
-    }else{
-      sn = disjuncts[j];
-    }
-    bool slit_pol = sn.getKind()!=NOT;
-    Node slit = sn.getKind()==NOT ? sn[0] : sn;
-    if( slit.getKind()==EQUAL && slit_pol==reqPol ){
-      // check if it is a variable equality
-      TNode v;
-      Node s;
-      for( unsigned r=0; r<2; r++ ){
-        if( std::find( vars.begin(), vars.end(), slit[r] )!=vars.end() ){
-          if( !TermUtil::containsTerm( slit[1-r], slit[r] ) ){
-            v = slit[r];
-            s = slit[1-r];
-            break;
-          }
-        }
-      }
-      if( v.isNull() ){
-        //solve for var
-        std::map< Node, Node > msum;
-        if (ArithMSum::getMonomialSumLit(slit, msum))
-        {
-          for( std::map< Node, Node >::iterator itm = msum.begin(); itm != msum.end(); ++itm ){
-            if( std::find( vars.begin(), vars.end(), itm->first )!=vars.end() ){  
-              Node veq_c;
-              Node val;
-              int ires =
-                  ArithMSum::isolate(itm->first, msum, veq_c, val, EQUAL);
-              if( ires!=0 && veq_c.isNull() && !TermUtil::containsTerm( val, itm->first ) ){
-                v = itm->first;
-                s = val;
-              }
-            }
-          }
-        }
-      }
-      if( !v.isNull() ){
-        TNode ts = s;
-        for( unsigned k=0; k<const_subs.size(); k++ ){
-          const_subs[k] = Rewriter::rewrite( const_subs[k].substitute( v, ts ) );
-        }
-        Trace("cegqi-inv-debug2") << "...substitution : " << v << " -> " << s << std::endl;
-        const_var.push_back( v );
-        const_subs.push_back( s );
-      }
-    }
-  }
-}
-
-void TransitionInference::process( Node n ) {
-  d_complete = true;
-  std::vector< Node > n_check;
-  if( n.getKind()==AND ){
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      n_check.push_back( n[i] );
-    }
-  }else{
-    n_check.push_back( n );
-  }
-  for( unsigned i=0; i<n_check.size(); i++ ){
-    Node nn = n_check[i];
-    std::map< Node, bool > visited;
-    std::map< bool, Node > terms;
-    std::vector< Node > disjuncts;
-    Trace("cegqi-inv") << "TransitionInference : Process disjunct : " << nn << std::endl;
-    if( processDisjunct( nn, terms, disjuncts, visited, true ) ){
-      if( !terms.empty() ){
-        Node norm_args;
-        int comp_num;
-        std::map< bool, Node >::iterator itt = terms.find( false );
-        if( itt!=terms.end() ){
-          norm_args = itt->second;
-          if( terms.find( true )!=terms.end() ){
-            comp_num = 0;
-          }else{
-            comp_num = -1;
-          }
-        }else{
-          norm_args = terms[true];
-          comp_num = 1;
-        }
-        std::vector< Node > subs;
-        for( unsigned j=0; j<norm_args.getNumChildren(); j++ ){
-          subs.push_back( norm_args[j] );
-        }        
-        Trace("cegqi-inv-debug2") << "  normalize based on " << norm_args << std::endl;
-        Assert( d_vars.size()==subs.size() );
-        for( unsigned j=0; j<disjuncts.size(); j++ ){
-          disjuncts[j] = Rewriter::rewrite( disjuncts[j].substitute( subs.begin(), subs.end(), d_vars.begin(), d_vars.end() ) );
-          Trace("cegqi-inv-debug2") << "  ..." << disjuncts[j] << std::endl;
-        }
-        std::vector< Node > const_var;
-        std::vector< Node > const_subs;
-        if( comp_num==0 ){
-          //transition
-          Assert( terms.find( true )!=terms.end() );
-          Node next = terms[true];
-          next = Rewriter::rewrite( next.substitute( subs.begin(), subs.end(), d_vars.begin(), d_vars.end() ) );
-          Trace("cegqi-inv-debug") << "transition next predicate : " << next << std::endl;
-          // normalize the other direction
-          std::vector< Node > rvars;
-          for( unsigned i=0; i<next.getNumChildren(); i++ ){
-            rvars.push_back( next[i] );
-          }
-          if( d_prime_vars.size()<next.getNumChildren() ){
-            for( unsigned i=0; i<next.getNumChildren(); i++ ){
-              Node v = NodeManager::currentNM()->mkSkolem( "ir", next[i].getType(), "template inference rev argument" );
-              d_prime_vars.push_back( v );
-            }
-          }
-          Trace("cegqi-inv-debug2") << "  normalize based on " << next << std::endl;
-          Assert( d_vars.size()==subs.size() );
-          for( unsigned j=0; j<disjuncts.size(); j++ ){
-            disjuncts[j] = Rewriter::rewrite( disjuncts[j].substitute( rvars.begin(), rvars.end(), d_prime_vars.begin(), d_prime_vars.end() ) );
-            Trace("cegqi-inv-debug2") << "  ..." << disjuncts[j] << std::endl;
-          }
-          getConstantSubstitution( d_prime_vars, disjuncts, const_var, const_subs, false );
-        }else{
-          getConstantSubstitution( d_vars, disjuncts, const_var, const_subs, false );
-        }
-        Node res;
-        if( disjuncts.empty() ){
-          res = NodeManager::currentNM()->mkConst( false );
-        }else if( disjuncts.size()==1 ){
-          res = disjuncts[0];
-        }else{
-          res = NodeManager::currentNM()->mkNode( kind::OR, disjuncts );
-        }
-        if( !res.hasBoundVar() ){
-          Trace("cegqi-inv") << "*** inferred " << ( comp_num==1 ? "pre" : ( comp_num==-1 ? "post" : "trans" ) ) << "-condition : " << res << std::endl;
-          d_com[comp_num].d_conjuncts.push_back( res );
-          if( !const_var.empty() ){
-            bool has_const_eq = const_var.size()==d_vars.size();
-            Trace("cegqi-inv") << "    with constant substitution, complete = " << has_const_eq << " : " << std::endl;
-            for( unsigned i=0; i<const_var.size(); i++ ){
-              Trace("cegqi-inv") << "      " << const_var[i] << " -> " << const_subs[i] << std::endl;
-              if( has_const_eq ){
-                d_com[comp_num].d_const_eq[res][const_var[i]] = const_subs[i];
-              }
-            }
-            Trace("cegqi-inv") << "...size = " << const_var.size() << ", #vars = " << d_vars.size() << std::endl;
-          }
-        }else{
-          Trace("cegqi-inv-debug2") << "...failed, free variable." << std::endl;
-          d_complete = false;
-        }
-      }
-    }else{
-      d_complete = false;
-    }
-  }
-  
-  // finalize the components
-  for( int i=-1; i<=1; i++ ){
-    Node ret;
-    if( d_com[i].d_conjuncts.empty() ){
-      ret = NodeManager::currentNM()->mkConst( true );
-    }else if( d_com[i].d_conjuncts.size()==1 ){
-      ret = d_com[i].d_conjuncts[0];
-    }else{
-      ret = NodeManager::currentNM()->mkNode( kind::AND, d_com[i].d_conjuncts );
-    }
-    if( i==0 || i==1 ){
-      // pre-condition and transition are negated
-      ret = TermUtil::simpleNegate( ret );
-    }
-    d_com[i].d_this = ret;
-  }
-}
-
-bool TransitionInference::processDisjunct( Node n, std::map< bool, Node >& terms, std::vector< Node >& disjuncts, 
-                                           std::map< Node, bool >& visited, bool topLevel ) {
-  if( visited.find( n )==visited.end() ){
-    visited[n] = true;
-    bool childTopLevel = n.getKind()==OR && topLevel;
-    //if another part mentions UF or a free variable, then fail
-    bool lit_pol = n.getKind()!=NOT;
-    Node lit = n.getKind()==NOT ? n[0] : n;
-    if( lit.getKind()==APPLY_UF ){
-      Node op = lit.getOperator();
-      if( d_func.isNull() ){
-        d_func = op;
-        Trace("cegqi-inv-debug") << "Use " << op << " with args ";
-        for( unsigned i=0; i<lit.getNumChildren(); i++ ){
-          Node v = NodeManager::currentNM()->mkSkolem( "i", lit[i].getType(), "template inference argument" );
-          d_vars.push_back( v );
-          Trace("cegqi-inv-debug") << v << " ";
-        }
-        Trace("cegqi-inv-debug") << std::endl;
-      }
-      if( op!=d_func ){
-        Trace("cegqi-inv-debug") << "...failed, free function : " << n << std::endl;
-        return false;
-      }else if( topLevel ){
-        if( terms.find( lit_pol )==terms.end() ){
-          terms[lit_pol] = lit;
-          return true;
-        }else{
-          Trace("cegqi-inv-debug") << "...failed, repeated inv-app : " << lit << std::endl;
-          return false;
-        }
-      }else{
-        Trace("cegqi-inv-debug") << "...failed, non-entailed inv-app : " << lit << std::endl;
-        return false;
-      }
-    }else if( topLevel && !childTopLevel ){
-      disjuncts.push_back( n );
-    }
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      if( !processDisjunct( n[i], terms, disjuncts, visited, childTopLevel ) ){
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-Node TransitionInference::getComponent( int i ) {
-  return d_com[i].d_this;
-}
-
-int TransitionInference::initializeTrace( DetTrace& dt, Node loc, bool fwd ) {
-  int index = fwd ? 1 : -1;
-  Assert( d_com[index].has( loc ) );
-  std::map< Node, std::map< Node, Node > >::iterator it = d_com[index].d_const_eq.find( loc );
-  if( it!=d_com[index].d_const_eq.end() ){
-    std::vector< Node > next;
-    for( unsigned i=0; i<d_vars.size(); i++ ){
-      Node v = d_vars[i];
-      Assert( it->second.find( v )!=it->second.end() );
-      next.push_back( it->second[v] );
-      dt.d_curr.push_back( it->second[v] );
-    }
-    Trace("cegqi-inv-debug2") << "dtrace : initial increment" << std::endl;
-    bool ret = dt.increment( loc, next );
-    AlwaysAssert( ret );
-    return 0;
-  }
-  return -1;
-}
-  
-int TransitionInference::incrementTrace( DetTrace& dt, Node loc, bool fwd ) {
-  Assert( d_com[0].has( loc ) );
-  // check if it satisfies the pre/post condition
-  int check_index = fwd ? -1 : 1;
-  Node cc = getComponent( check_index );
-  Assert( !cc.isNull() );
-  Node ccr = Rewriter::rewrite( cc.substitute( d_vars.begin(), d_vars.end(), dt.d_curr.begin(), dt.d_curr.end() ) );
-  if( ccr.isConst() ){
-    if( ccr.getConst<bool>()==( fwd ? false : true ) ){
-      Trace("cegqi-inv-debug2") << "dtrace : counterexample" << std::endl;
-      return 2;
-    }
-  }
-
-
-  // terminates?
-  Node c = getComponent( 0 );
-  Assert( !c.isNull() );
-
-  Assert( d_vars.size()==dt.d_curr.size() );
-  Node cr = Rewriter::rewrite( c.substitute( d_vars.begin(), d_vars.end(), dt.d_curr.begin(), dt.d_curr.end() ) );
-  if( cr.isConst() ){
-    if( !cr.getConst<bool>() ){
-      Trace("cegqi-inv-debug2") << "dtrace : terminated" << std::endl;
-      return 1;
-    }else{
-      return -1;
-    }
-  }
-  if( fwd ){
-    std::map< Node, std::map< Node, Node > >::iterator it = d_com[0].d_const_eq.find( loc );
-    if( it!=d_com[0].d_const_eq.end() ){
-      std::vector< Node > next;
-      for( unsigned i=0; i<d_prime_vars.size(); i++ ){
-        Node pv = d_prime_vars[i];
-        Assert( it->second.find( pv )!=it->second.end() );
-        Node pvs = it->second[pv];
-        Assert( d_vars.size()==dt.d_curr.size() );
-        Node pvsr = Rewriter::rewrite( pvs.substitute( d_vars.begin(), d_vars.end(), dt.d_curr.begin(), dt.d_curr.end() ) );
-        next.push_back( pvsr );
-      }
-      if( dt.increment( loc, next ) ){
-        Trace("cegqi-inv-debug2") << "dtrace : success increment" << std::endl;
-        return 0;
-      }else{
-        // looped
-        Trace("cegqi-inv-debug2") << "dtrace : looped" << std::endl;
-        return 1;
-      }
-    }
-  }else{
-    //TODO
-  }
-  return -1;
-}
-
-int TransitionInference::initializeTrace( DetTrace& dt, bool fwd ) {
-  Trace("cegqi-inv-debug2") << "Initialize trace" << std::endl;
-  int index = fwd ? 1 : -1;
-  if( d_com[index].d_conjuncts.size()==1 ){
-    return initializeTrace( dt, d_com[index].d_conjuncts[0], fwd );
-  }else{
-    return -1;
-  }
-}
-
-int TransitionInference::incrementTrace( DetTrace& dt, bool fwd ) {
-  if( d_com[0].d_conjuncts.size()==1 ){
-    return incrementTrace( dt, d_com[0].d_conjuncts[0], fwd );
-  }else{
-    return -1;
-  }
-}
-
-Node TransitionInference::constructFormulaTrace( DetTrace& dt ) {
-  return dt.constructFormula( d_vars );
-}
-  
-} //namespace CVC4
-
diff --git a/src/theory/quantifiers/ce_guided_single_inv.h b/src/theory/quantifiers/ce_guided_single_inv.h
deleted file mode 100644 (file)
index 888e078..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*********************                                                        */
-/*! \file ce_guided_single_inv.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief utility for processing single invocation synthesis conjectures
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_SINGLE_INV_H
-#define __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_SINGLE_INV_H
-
-#include "context/cdlist.h"
-#include "theory/quantifiers/ce_guided_single_inv_sol.h"
-#include "theory/quantifiers/inst_match_trie.h"
-#include "theory/quantifiers/inst_strategy_cbqi.h"
-#include "theory/quantifiers/single_inv_partition.h"
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class CegConjecture;
-class CegConjectureSingleInv;
-class CegEntailmentInfer;
-
-class CegqiOutputSingleInv : public CegqiOutput {
-public:
-  CegqiOutputSingleInv( CegConjectureSingleInv * out ) : d_out( out ){}
-  virtual ~CegqiOutputSingleInv() {}
-  CegConjectureSingleInv * d_out;
-  bool doAddInstantiation( std::vector< Node >& subs );
-  bool isEligibleForInstantiation( Node n );
-  bool addLemma( Node lem );
-};
-
-class DetTrace {
-private:
-  class DetTraceTrie {
-  public:
-    std::map< Node, DetTraceTrie > d_children;
-    bool add( Node loc, std::vector< Node >& val, unsigned index = 0 );
-    void clear() { d_children.clear(); }
-    Node constructFormula( std::vector< Node >& vars, unsigned index = 0 );
-  };
-  DetTraceTrie d_trie;
-public:
-  std::vector< Node > d_curr;
-  bool increment( Node loc, std::vector< Node >& vals );
-  Node constructFormula( std::vector< Node >& vars );
-  void print( const char* c );
-};
-
-class TransitionInference {
-private:
-  bool processDisjunct( Node n, std::map< bool, Node >& terms, std::vector< Node >& disjuncts, std::map< Node, bool >& visited, bool topLevel );
-  void getConstantSubstitution( std::vector< Node >& vars, std::vector< Node >& disjuncts, std::vector< Node >& const_var, std::vector< Node >& const_subs, bool reqPol );
-  bool d_complete;
-public:
-  TransitionInference() : d_complete( false ) {}
-  std::vector< Node > d_vars;
-  std::vector< Node > d_prime_vars;
-  Node d_func;
-  
-  class Component {
-  public:
-    Component(){}
-    Node d_this;
-    std::vector< Node > d_conjuncts;
-    std::map< Node, std::map< Node, Node > > d_const_eq;
-    bool has( Node c ) { return std::find( d_conjuncts.begin(), d_conjuncts.end(), c )!=d_conjuncts.end(); }
-  };
-  std::map< int, Component > d_com;
-  
-  void initialize( Node f, std::vector< Node >& vars );
-  void process( Node n );
-  Node getComponent( int i );
-  bool isComplete() { return d_complete; }
-  
-  // 0 : success, 1 : terminated, 2 : counterexample, -1 : invalid
-  int initializeTrace( DetTrace& dt, Node loc, bool fwd = true );
-  int incrementTrace( DetTrace& dt, Node loc, bool fwd = true );
-  int initializeTrace( DetTrace& dt, bool fwd = true );
-  int incrementTrace( DetTrace& dt, bool fwd = true );
-  Node constructFormulaTrace( DetTrace& dt );
-};
-
-// this class infers whether a conjecture is single invocation (Reynolds et al CAV 2015), and sets up the
-// counterexample-guided quantifier instantiation utility (d_cinst), and methods for solution
-// reconstruction (d_sol).
-// It also has more advanced techniques for:
-// (1) partitioning a conjecture into single invocation / non-single invocation portions for invariant synthesis,
-// (2) inferring whether the conjecture corresponds to a deterministic transistion system (by utility d_ti).
-// For these techniques, we may generate a template (d_templ) which specifies a restricted
-// solution space. We may in turn embed this template as a SyGuS grammar.
-class CegConjectureSingleInv {
- private:
-  friend class CegqiOutputSingleInv;
-  //presolve
-  void collectPresolveEqTerms( Node n,
-                               std::map< Node, std::vector< Node > >& teq );
-  void getPresolveEqConjuncts( std::vector< Node >& vars,
-                               std::vector< Node >& terms,
-                               std::map< Node, std::vector< Node > >& teq,
-                               Node n, std::vector< Node >& conj );
-  // constructing solution
-  Node constructSolution(std::vector<unsigned>& indices, unsigned i,
-                         unsigned index, std::map<Node, Node>& weak_imp);
-  Node postProcessSolution(Node n);
- private:
-  QuantifiersEngine* d_qe;
-  CegConjecture* d_parent;
-  // single invocation inference utility
-  SingleInvocationPartition* d_sip;
-  // transition inference module for each function to synthesize
-  std::map< Node, TransitionInference > d_ti;
-  // solution reconstruction
-  CegConjectureSingleInvSol* d_sol;
-  // the instantiator's output channel
-  CegqiOutputSingleInv* d_cosi;
-  // the instantiator
-  CegInstantiator* d_cinst;
-
-  // list of skolems for each argument of programs
-  std::vector<Node> d_single_inv_arg_sk;
-  // list of variables/skolems for each program
-  std::vector<Node> d_single_inv_var;
-  std::vector<Node> d_single_inv_sk;
-  std::map<Node, int> d_single_inv_sk_index;
-  // program to solution index
-  std::map<Node, unsigned> d_prog_to_sol_index;
-  // lemmas produced
-  inst::InstMatchTrie d_inst_match_trie;
-  inst::CDInstMatchTrie* d_c_inst_match_trie;
-  // original conjecture
-  Node d_orig_conjecture;
-  // solution
-  Node d_orig_solution;
-  Node d_solution;
-  Node d_sygus_solution;
-  // whether the grammar for our solution allows ITEs, this tells us when reconstruction is infeasible
-  bool d_has_ites;
-
- public:
-  // lemmas produced
-  std::vector<Node> d_lemmas_produced;
-  std::vector<std::vector<Node> > d_inst;
-
- private:
-  std::vector<Node> d_curr_lemmas;
-  // add instantiation
-  bool doAddInstantiation( std::vector< Node >& subs );
-  //is eligible for instantiation
-  bool isEligibleForInstantiation( Node n );
-  // add lemma
-  bool addLemma( Node lem );
-  // conjecture
-  Node d_quant;
-  Node d_simp_quant;
-  // are we single invocation?
-  bool d_single_invocation;
-  // single invocation portion of quantified formula
-  Node d_single_inv;
-  Node d_si_guard;
-  // transition relation version per program
-  std::map< Node, Node > d_trans_pre;
-  std::map< Node, Node > d_trans_post;
-  // the template for each function to synthesize
-  std::map< Node, Node > d_templ;
-  // the template argument for each function to synthesize (occurs in exactly one position of its template)
-  std::map< Node, Node > d_templ_arg;
-  
- public:
-  CegConjectureSingleInv( QuantifiersEngine * qe, CegConjecture * p );
-  ~CegConjectureSingleInv();
-
-  // get simplified conjecture
-  Node getSimplifiedConjecture() { return d_simp_quant; }
-  // get single invocation guard
-  Node getGuard() { return d_si_guard; }
- public:
-  //get the single invocation lemma(s)
-  void getInitialSingleInvLemma( std::vector< Node >& lems );
-  // initialize this class for synthesis conjecture q
-  void initialize( Node q );
-  // finish initialize, sets up final decisions about whether to use single invocation techniques
-  //  syntaxRestricted is whether the syntax for solutions for the initialized conjecture is restricted
-  //  hasItes is whether the syntax for solutions for the initialized conjecture allows ITEs
-  void finishInit( bool syntaxRestricted, bool hasItes );
-  //check
-  bool check( std::vector< Node >& lems );
-  //get solution
-  Node getSolution( unsigned sol_index, TypeNode stn, int& reconstructed, bool rconsSygus = true );
-  //reconstruct to syntax
-  Node reconstructToSyntax( Node s, TypeNode stn, int& reconstructed,
-                            bool rconsSygus = true );
-  // has ites
-  bool hasITEs() { return d_has_ites; }
-  // is single invocation
-  bool isSingleInvocation() const { return !d_single_inv.isNull(); }
-  //needs check
-  bool needsCheck();
-  /** preregister conjecture */
-  void preregisterConjecture( Node q );
-
-  Node getTransPre(Node prog) const {
-    std::map<Node, Node>::const_iterator location = d_trans_pre.find(prog);
-    return location->second;
-  }
-
-  Node getTransPost(Node prog) const {
-    std::map<Node, Node>::const_iterator location = d_trans_post.find(prog);
-    return location->second;
-  }
-  // get template for program prog. This returns a term of the form t[x] where x is the template argument (see below)
-  Node getTemplate(Node prog) const {
-    std::map<Node, Node>::const_iterator tmpl = d_templ.find(prog);
-    if( tmpl!=d_templ.end() ){
-      return tmpl->second;
-    }else{
-      return Node::null();
-    }
-  }
-  // get the template argument for program prog.
-  // This is a variable which indicates the position of the function/predicate to synthesize.
-  Node getTemplateArg(Node prog) const {
-    std::map<Node, Node>::const_iterator tmpla = d_templ_arg.find(prog);
-    if( tmpla != d_templ_arg.end() ){
-      return tmpla->second;
-    }else{
-      return Node::null();
-    }
-  }
-};
-
-}/* namespace CVC4::theory::quantifiers */
-}/* namespace CVC4::theory */
-}/* namespace CVC4 */
-
-#endif
diff --git a/src/theory/quantifiers/ce_guided_single_inv_sol.cpp b/src/theory/quantifiers/ce_guided_single_inv_sol.cpp
deleted file mode 100644 (file)
index 74408a7..0000000
+++ /dev/null
@@ -1,1512 +0,0 @@
-/*********************                                                        */
-/*! \file ce_guided_single_inv_sol.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Paul Meng, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief utility for processing single invocation synthesis conjectures
- **
- **/
-#include "theory/quantifiers/ce_guided_single_inv_sol.h"
-
-#include "expr/datatype.h"
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/ce_guided_instantiation.h"
-#include "theory/quantifiers/ce_guided_single_inv.h"
-#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/quantifiers_attributes.h"
-#include "theory/quantifiers/term_database_sygus.h"
-#include "theory/quantifiers/term_enumeration.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
-#include "theory/theory_engine.h"
-
-using namespace CVC4::kind;
-using namespace std;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-bool doCompare(Node a, Node b, Kind k)
-{
-  Node com = NodeManager::currentNM()->mkNode(k, a, b);
-  com = Rewriter::rewrite(com);
-  Assert(com.getType().isBoolean());
-  return com.isConst() && com.getConst<bool>();
-}
-
-CegConjectureSingleInvSol::CegConjectureSingleInvSol(QuantifiersEngine* qe)
-    : d_qe(qe), d_id_count(0), d_root_id() {}
-
-bool CegConjectureSingleInvSol::debugSolution( Node sol ) {
-  if( sol.getKind()==SKOLEM ){
-    return false;
-  }else{
-    for( unsigned i=0; i<sol.getNumChildren(); i++ ){
-      if( !debugSolution( sol[i] ) ){
-        return false;
-      }
-    }
-    return true;
-  }
-
-}
-
-void CegConjectureSingleInvSol::debugTermSize( Node sol, int& t_size, int& num_ite ) {
-  std::map< Node, int >::iterator it = d_dterm_size.find( sol );
-  if( it==d_dterm_size.end() ){
-    int prev = t_size;
-    int prev_ite = num_ite;
-    t_size++;
-    if( sol.getKind()==ITE ){
-      num_ite++;
-    }
-    for( unsigned i=0; i<sol.getNumChildren(); i++ ){
-      debugTermSize( sol[i], t_size, num_ite );
-    }
-    d_dterm_size[sol] = t_size-prev;
-    d_dterm_ite_size[sol] = num_ite-prev_ite;
-  }else{
-    t_size += it->second;
-    num_ite += d_dterm_ite_size[sol];
-  }
-}
-
-
-Node CegConjectureSingleInvSol::pullITEs( Node s ) {
-  if( s.getKind()==ITE ){
-    bool success;
-    do {
-      success = false;
-      std::vector< Node > conj;
-      Node t;
-      Node rem;
-      if( pullITECondition( s, s, conj, t, rem, 0 ) ){
-        Assert( !conj.empty() );
-        Node cond = conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj );
-        Trace("csi-sol-debug") << "For " << s << ", can pull " << cond << " -> " << t << " with remainder " << rem << std::endl;
-        t = pullITEs( t );
-        rem = pullITEs( rem );
-        Trace("csi-pull-ite") << "PI: Rewrite : " << s << std::endl;
-        Node prev = s;
-        s = NodeManager::currentNM()->mkNode( ITE, TermUtil::simpleNegate( cond ), t, rem );
-        Trace("csi-pull-ite") << "PI: Rewrite Now : " << s << std::endl;
-        Trace("csi-pull-ite") << "(= " << prev << " " << s << ")" << std::endl;
-        success = true;
-      }
-    }while( success );
-  }
-  return s;
-}
-
-// pull condition common to all ITE conditions in path of size > 1
-bool CegConjectureSingleInvSol::pullITECondition( Node root, Node n_ite, std::vector< Node >& conj, Node& t, Node& rem, int depth ) {
-  Assert( n_ite.getKind()==ITE );
-  std::vector< Node > curr_conj;
-  std::vector< Node > orig_conj;
-  bool isAnd;
-  if( n_ite[0].getKind()==AND || n_ite[0].getKind()==OR ){
-    isAnd = n_ite[0].getKind()==AND;
-    for( unsigned i=0; i<n_ite[0].getNumChildren(); i++ ){
-      Node cond = n_ite[0][i];
-      orig_conj.push_back( cond );
-      if( n_ite[0].getKind()==OR ){
-        cond = TermUtil::simpleNegate( cond );
-      }
-      curr_conj.push_back( cond );
-    }
-  }else{
-    Node neg = n_ite[0].negate();
-    if( std::find( conj.begin(), conj.end(), neg )!=conj.end() ){
-      //if negation of condition exists, use it
-      isAnd = false;
-      curr_conj.push_back( neg );
-    }else{
-      //otherwise, use condition
-      isAnd = true;
-      curr_conj.push_back( n_ite[0] );
-    }
-    orig_conj.push_back( n_ite[0] );
-  }
-  // take intersection with current conditions
-  std::vector< Node > new_conj;
-  std::vector< Node > prev_conj;
-  if( n_ite==root ){
-    new_conj.insert( new_conj.end(), curr_conj.begin(), curr_conj.end() );
-    Trace("csi-sol-debug") << "Pull ITE root " << n_ite << ", #conj = " << new_conj.size() << std::endl;
-  }else{
-    for( unsigned i=0; i<curr_conj.size(); i++ ){
-      if( std::find( conj.begin(), conj.end(), curr_conj[i] )!=conj.end() ){
-        new_conj.push_back( curr_conj[i] );
-      }
-    }
-    Trace("csi-sol-debug") << "Pull ITE " << n_ite << ", #conj = " << conj.size() << " intersect " << curr_conj.size() << " = " << new_conj.size() << std::endl;
-  }
-  //cannot go further
-  if( new_conj.empty() ){
-    return false;
-  }
-  //it is an intersection with current
-  conj.clear();
-  conj.insert( conj.end(), new_conj.begin(), new_conj.end() );
-  //recurse if possible
-  Node trec = n_ite[ isAnd ? 2 : 1 ];
-  Node tval = n_ite[ isAnd ? 1 : 2 ];
-  bool success = false;
-  if( trec.getKind()==ITE ){
-    prev_conj.insert( prev_conj.end(), conj.begin(), conj.end() );
-    success = pullITECondition( root, trec, conj, t, rem, depth+1 );
-  }
-  if( !success && depth>0 ){
-    t = trec;
-    rem = trec;
-    success = true;
-    if( trec.getKind()==ITE ){
-      //restore previous state
-      conj.clear();
-      conj.insert( conj.end(), prev_conj.begin(), prev_conj.end() );
-    }
-  }
-  if( success ){
-    //make remainder : strip out conditions in conj
-    Assert( !conj.empty() );
-    std::vector< Node > cond_c;
-    Assert( orig_conj.size()==curr_conj.size() );
-    for( unsigned i=0; i<curr_conj.size(); i++ ){
-      if( std::find( conj.begin(), conj.end(), curr_conj[i] )==conj.end() ){
-        cond_c.push_back( orig_conj[i] );
-      }
-    }
-    if( cond_c.empty() ){
-      rem = tval;
-    }else{
-      Node new_cond = cond_c.size()==1 ? cond_c[0] : NodeManager::currentNM()->mkNode( n_ite[0].getKind(), cond_c );
-      rem = NodeManager::currentNM()->mkNode( ITE, new_cond, isAnd ? tval : rem, isAnd ? rem : tval );
-    }
-    return true;
-  }else{
-    return false;
-  }
-}
-
-Node CegConjectureSingleInvSol::flattenITEs( Node n, bool rec ) {
-  Assert( !n.isNull() );
-  if( n.getKind()==ITE ){
-    Trace("csi-sol-debug") << "Flatten ITE." << std::endl;
-    Node ret;
-    Node n0 = rec ? flattenITEs( n[0] ) : n[0];
-    Node n1 = rec ? flattenITEs( n[1] ) : n[1];
-    Node n2 = rec ? flattenITEs( n[2] ) : n[2];
-    Assert( !n0.isNull() );
-    Assert( !n1.isNull() );
-    Assert( !n2.isNull() );
-    if( n0.getKind()==NOT ){
-      ret = NodeManager::currentNM()->mkNode( ITE, n0[0], n2, n1 );
-    }else if( n0.getKind()==AND || n0.getKind()==OR ){
-      std::vector< Node > children;
-      for( unsigned i=1; i<n0.getNumChildren(); i++ ){
-        children.push_back( n0[i] );
-      }
-      Node rem = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( n0.getKind(), children );
-      if( n0.getKind()==AND ){
-        ret = NodeManager::currentNM()->mkNode( ITE, rem, NodeManager::currentNM()->mkNode( ITE, n0[0], n1, n2 ), n2 );
-      }else{
-        ret = NodeManager::currentNM()->mkNode( ITE, rem, n1, NodeManager::currentNM()->mkNode( ITE, n0[0], n1, n2 ) );
-      }
-    }else{
-      if( n0.getKind()==ITE ){
-        n0 = NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, n0, n1 ),
-                                                   NodeManager::currentNM()->mkNode( AND, n0.negate(), n2 ) );
-      }else if( n0.getKind()==EQUAL && n0[0].getType().isBoolean() ){
-        n0 = NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, n0, n1 ),
-                                                   NodeManager::currentNM()->mkNode( AND, n0.negate(), n1.negate() ) );
-      }else{
-        return NodeManager::currentNM()->mkNode( ITE, n0, n1, n2 );
-      }
-      ret = NodeManager::currentNM()->mkNode( ITE, n0, n1, n2 );
-    }
-    Assert( !ret.isNull() );
-    return flattenITEs( ret, false );
-  }else{
-    if( n.getNumChildren()>0 ){
-      std::vector< Node > children;
-      if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
-        children.push_back( n.getOperator() );
-      }
-      bool childChanged = false;
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        Node nc = flattenITEs( n[i] );
-        children.push_back( nc );
-        childChanged = childChanged || nc!=n[i];
-      }
-      if( !childChanged ){
-        return n;
-      }else{
-        return NodeManager::currentNM()->mkNode( n.getKind(), children );
-      }
-    }else{
-      return n;
-    }
-  }
-}
-
-// assign is from literals to booleans
-// union_find is from args to values
-
-bool CegConjectureSingleInvSol::getAssign( bool pol, Node n, std::map< Node, bool >& assign, std::vector< Node >& new_assign, std::vector< Node >& vars,
-                                        std::vector< Node >& new_vars, std::vector< Node >& new_subs ) {
-  std::map< Node, bool >::iterator ita = assign.find( n );
-  if( ita!=assign.end() ){
-    Trace("csi-simp-debug") << "---already assigned, lookup " << pol << " " << ita->second << std::endl;
-    return pol==ita->second;
-  }else if( n.isConst() ){
-    return pol==(n==d_qe->getTermUtil()->d_true);
-  }else{
-    Trace("csi-simp-debug") << "---assign " << n << " " << pol << std::endl;
-    assign[n] = pol;
-    new_assign.push_back( n );
-    if( ( pol && n.getKind()==AND ) || ( !pol && n.getKind()==OR ) ){
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        if( !getAssign( pol, n[i], assign, new_assign, vars, new_vars, new_subs ) ){
-          return false;
-        }
-      }
-    }else if( n.getKind()==NOT ){
-      return getAssign( !pol, n[0], assign, new_assign, vars, new_vars, new_subs );
-    }else if( pol && n.getKind()==EQUAL ){
-      getAssignEquality( n, vars, new_vars, new_subs );
-    }
-  }
-  return true;
-}
-
-bool CegConjectureSingleInvSol::getAssignEquality( Node eq, std::vector< Node >& vars, std::vector< Node >& new_vars, std::vector< Node >& new_subs ) {
-  Assert( eq.getKind()==EQUAL );
-  //try to find valid argument
-  for( unsigned r=0; r<2; r++ ){
-    if( std::find( d_varList.begin(), d_varList.end(), eq[r] )!=d_varList.end() ){
-      Assert( std::find( vars.begin(), vars.end(), eq[r] )==vars.end() );
-      if( std::find( new_vars.begin(), new_vars.end(), eq[r] )==new_vars.end() ){
-        Node eqro = eq[r==0 ? 1 : 0 ];
-        if( !d_qe->getTermUtil()->containsTerm( eqro, eq[r] ) ){
-          Trace("csi-simp-debug") << "---equality " << eq[r] << " = " << eqro << std::endl;
-          new_vars.push_back( eq[r] );
-          new_subs.push_back( eqro );
-          return true;
-        }
-      }
-    }
-  }
-  return false;
-}
-
-Node CegConjectureSingleInvSol::simplifySolution( Node sol, TypeNode stn ){
-  int tsize, itesize;
-  if( Trace.isOn("csi-sol") ){
-    tsize = 0;itesize = 0;
-    debugTermSize( sol, tsize, itesize );
-    Trace("csi-sol") << tsize << " " << itesize << " rewrite..." << std::endl;
-    Trace("csi-sol-debug") << "sol : " << sol << "..." << std::endl;
-  }
-  Node sol0 = Rewriter::rewrite( sol );
-  Trace("csi-sol") << "now : " << sol0 << std::endl;
-
-  Node curr_sol = sol0;
-  Node prev_sol;
-  do{
-    prev_sol = curr_sol;
-    //first, pull ITE conditions
-    if( Trace.isOn("csi-sol") ){
-      tsize = 0;itesize = 0;
-      debugTermSize( curr_sol, tsize, itesize );
-      Trace("csi-sol") << tsize << " " << itesize << " pull ITE..." << std::endl;
-      Trace("csi-sol-debug") << "sol : " << curr_sol << "..." << std::endl;
-    }
-    Node sol1 = pullITEs( curr_sol );
-    Trace("csi-sol") << "now : " << sol1 << std::endl;
-    //do standard rewriting
-    if( sol1!=curr_sol ){
-      if( Trace.isOn("csi-sol") ){
-        tsize = 0;itesize = 0;
-        debugTermSize( sol1, tsize, itesize );
-        Trace("csi-sol") << tsize << " " << itesize << " rewrite..." << std::endl;
-        Trace("csi-sol-debug") << "sol : " << sol1 << "..." << std::endl;
-      }
-      Node sol2 = Rewriter::rewrite( sol1 );
-      Trace("csi-sol") << "now : " << sol2 << std::endl;
-      curr_sol = sol2;
-    }
-    //now do branch analysis
-    if( Trace.isOn("csi-sol") ){
-      tsize = 0;itesize = 0;
-      debugTermSize( curr_sol, tsize, itesize );
-      Trace("csi-sol") << tsize << " " << itesize << " simplify solution..." << std::endl;
-      Trace("csi-sol-debug") << "sol : " << curr_sol << "..." << std::endl;
-    }
-    std::map< Node, bool > sassign;
-    std::vector< Node > svars;
-    std::vector< Node > ssubs;
-    Node sol3 = simplifySolutionNode( curr_sol, stn, sassign, svars, ssubs, 0 );
-    Trace("csi-sol") << "now : " << sol3 << std::endl;
-    if( sol3!=curr_sol ){
-      //do standard rewriting again
-      if( Trace.isOn("csi-sol" ) ){
-        tsize = 0;itesize = 0;
-        debugTermSize( sol3, tsize, itesize );
-        Trace("csi-sol") << tsize << " " << itesize << " rewrite..." << std::endl;
-      }
-      Node sol4 = Rewriter::rewrite( sol3 );
-      Trace("csi-sol") << "now : " << sol4 << std::endl;
-      curr_sol = sol4;
-    }
-  }while( curr_sol!=prev_sol );
-
-  return curr_sol;
-}
-
-Node CegConjectureSingleInvSol::simplifySolutionNode( Node sol, TypeNode stn, std::map< Node, bool >& assign,
-                                                      std::vector< Node >& vars, std::vector< Node >& subs, int status ) {
-
-  Assert( vars.size()==subs.size() );
-  std::map< Node, bool >::iterator ita = assign.find( sol );
-  if( ita!=assign.end() ){
-    //it is currently assigned a boolean value
-    return NodeManager::currentNM()->mkConst( ita->second );
-  }else{
-    d_qe->getTermDatabaseSygus()->registerSygusType( stn );
-    std::map< int, TypeNode > stnc;
-    if( !stn.isNull() ){
-      int karg = d_qe->getTermDatabaseSygus()->getKindConsNum( stn, sol.getKind() );
-      if( karg!=-1 ){
-        const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
-        if( dt[karg].getNumArgs()==sol.getNumChildren() ){
-          for( unsigned i=0; i<dt[karg].getNumArgs(); i++ ){
-            stnc[i] = d_qe->getTermDatabaseSygus()->getArgType( dt[karg], i );
-          }
-        }
-      }
-    }
-
-    if( sol.getKind()==ITE ){
-      Trace("csi-simp") << "Simplify ITE " << std::endl;
-      std::vector< Node > children;
-      for( unsigned r=1; r<=2; r++ ){
-        std::vector< Node > new_assign;
-        std::vector< Node > new_vars;
-        std::vector< Node > new_subs;
-        if( getAssign( r==1, sol[0], assign, new_assign, vars, new_vars, new_subs ) ){
-          Trace("csi-simp") << "- branch " << r << " led to " << new_assign.size() << " assignments, " << new_vars.size() << " equalities." << std::endl;
-          unsigned prev_size = vars.size();
-          Node nc = sol[r];
-          if( !new_vars.empty() ){
-            nc = nc.substitute( new_vars.begin(), new_vars.end(), new_subs.begin(), new_subs.end() );
-            vars.insert( vars.end(), new_vars.begin(), new_vars.end() );
-            subs.insert( subs.end(), new_subs.begin(), new_subs.end() );
-          }
-          nc = simplifySolutionNode( nc, stnc[r], assign, vars, subs, 0 );
-          children.push_back( nc );
-          //clean up substitution
-          if( !new_vars.empty() ){
-            vars.resize( prev_size );
-            subs.resize( prev_size );
-          }
-        }else{
-          Trace("csi-simp") << "- branch " << r << " of " << sol[0] << " is infeasible." << std::endl;
-        }
-        //clean up assignment
-        for( unsigned i=0; i<new_assign.size(); i++ ){
-          assign.erase( new_assign[i] );
-        }
-      }
-      if( children.size()==1 || ( children.size()==2 && children[0]==children[1] ) ){
-        return children[0];
-      }else{
-        Assert( children.size()==2 );
-        Node ncond = simplifySolutionNode( sol[0], stnc[0], assign, vars, subs, 0 );
-        Node ret = NodeManager::currentNM()->mkNode( ITE, ncond, children[0], children[1] );
-
-        //expand/flatten if necessary
-        Node orig_ret = ret;
-        if( !stnc[0].isNull() ){
-          d_qe->getTermDatabaseSygus()->registerSygusType( stnc[0] );
-          Node prev_ret;
-          while( !d_qe->getTermDatabaseSygus()->hasKind( stnc[0], ret[0].getKind() ) && ret!=prev_ret ){
-            prev_ret = ret;
-            Node exp_c = d_qe->getTermDatabaseSygus()->expandBuiltinTerm( ret[0] );
-            if( !exp_c.isNull() ){
-              Trace("csi-simp-debug") << "Pre expand to " << ret[0] << " to " << exp_c << std::endl;
-              ret = NodeManager::currentNM()->mkNode( ITE, exp_c, ret[1], ret[2] );
-            }
-            if( !d_qe->getTermDatabaseSygus()->hasKind( stnc[0], ret[0].getKind() ) ){
-              Trace("csi-simp-debug") << "Flatten based on " << ret[0] << "." << std::endl;
-              ret = flattenITEs( ret, false );
-            }
-          }
-        }
-        return ret;
-        /*
-        if( orig_ret!=ret ){
-          Trace("csi-simp") << "Try expanded ITE" << std::endl;
-          return ret;//simplifySolutionNode( ret, stn, assign, vars, subs, status );
-        }else{
-          return ret;
-        }
-        */
-      }
-    }else if( sol.getKind()==OR || sol.getKind()==AND ){
-      Trace("csi-simp") << "Simplify " << sol.getKind() << std::endl;
-      //collect new equalities
-      std::map< Node, bool > atoms;
-      std::vector< Node > inc;
-      std::vector< Node > children;
-      std::vector< Node > new_vars;
-      std::vector< Node > new_subs;
-      Node bc = sol.getKind()==OR ? d_qe->getTermUtil()->d_true : d_qe->getTermUtil()->d_false;
-      for( unsigned i=0; i<sol.getNumChildren(); i++ ){
-        bool do_exc = false;
-        Node c;
-        std::map< Node, bool >::iterator ita = assign.find( sol[i] );
-        if( ita==assign.end() ){
-          c = sol[i];
-        }else{
-          c = NodeManager::currentNM()->mkConst( ita->second );
-        }
-        Trace("csi-simp") << "  - child " << i << " : " << c << std::endl;
-        if( c.isConst() ){
-          if( c==bc ){
-            Trace("csi-simp") << "  ...singularity." << std::endl;
-            return bc;
-          }else{
-            do_exc = true;
-          }
-        }else{
-          Node atom = c.getKind()==NOT ? c[0] : c;
-          bool pol = c.getKind()!=NOT;
-          std::map< Node, bool >::iterator it = atoms.find( atom );
-          if( it==atoms.end() ){
-            atoms[atom] = pol;
-            if( status==0 && atom.getKind()==EQUAL ){
-              if( pol==( sol.getKind()==AND ) ){
-                Trace("csi-simp") << "  ...equality." << std::endl;
-                if( getAssignEquality( atom, vars, new_vars, new_subs ) ){
-                  children.push_back( sol[i] );
-                  do_exc = true;
-                }
-              }
-            }
-          }else{
-            //repeated atom
-            if( it->second!=pol ){
-              return NodeManager::currentNM()->mkConst( sol.getKind()==OR );
-            }else{
-              do_exc = true;
-            }
-          }
-        }
-        if( !do_exc ){
-          inc.push_back( sol[i] );
-        }else{
-          Trace("csi-simp") << "  ...exclude." << std::endl;
-        }
-      }
-      if( !new_vars.empty() ){
-        if( !inc.empty() ){
-          Node ret = inc.size()==1 ? inc[0] : NodeManager::currentNM()->mkNode( sol.getKind(), inc );
-          Trace("csi-simp") << "Base return is : " << ret << std::endl;
-          // apply substitution
-          ret = ret.substitute( new_vars.begin(), new_vars.end(), new_subs.begin(), new_subs.end() );
-          ret = Rewriter::rewrite( ret );
-          Trace("csi-simp") << "After substitution : " << ret << std::endl;
-          unsigned prev_size = vars.size();
-          vars.insert( vars.end(), new_vars.begin(), new_vars.end() );
-          subs.insert( subs.end(), new_subs.begin(), new_subs.end() );
-          ret = simplifySolutionNode( ret, TypeNode::null(), assign, vars, subs, 1 );
-          //clean up substitution
-          if( !vars.empty() ){
-            vars.resize( prev_size );
-            subs.resize( prev_size );
-          }
-          //Trace("csi-simp") << "After simplification : " << ret << std::endl;
-          if( ret.isConst() ){
-            if( ret==bc ){
-              return bc;
-            }
-          }else{
-            if( ret.getKind()==sol.getKind() ){
-              for( unsigned i=0; i<ret.getNumChildren(); i++ ){
-                children.push_back( ret[i] );
-              }
-            }else{
-              children.push_back( ret );
-            }
-          }
-        }
-      }else{
-        //recurse on children
-        for( unsigned i=0; i<inc.size(); i++ ){
-          Node retc = simplifySolutionNode( inc[i], TypeNode::null(), assign, vars, subs, 0 );
-          if( retc.isConst() ){
-            if( retc==bc ){
-              return bc;
-            }
-          }else{
-            children.push_back( retc );
-          }
-        }
-      }
-      // now, remove all equalities that are implied
-      std::vector< Node > final_children;
-      for( unsigned i=0; i<children.size(); i++ ){
-        bool red = false;
-        Node atom = children[i].getKind()==NOT ? children[i][0] : children[i];
-        bool pol = children[i].getKind()!=NOT;
-        if( status==0 && atom.getKind()==EQUAL ){
-          if( pol!=( sol.getKind()==AND ) ){
-            std::vector< Node > tmp_vars;
-            std::vector< Node > tmp_subs;
-            if( getAssignEquality( atom, vars, tmp_vars, tmp_subs ) ){
-              Trace("csi-simp-debug") << "Check if " << children[i] << " is redundant in " << sol << std::endl;
-              for( unsigned j=0; j<children.size(); j++ ){
-                if( j!=i && ( j>i || std::find( final_children.begin(), final_children.end(), children[j] )!=final_children.end() ) ){
-                  Node sj = children[j].substitute( tmp_vars.begin(), tmp_vars.end(), tmp_subs.begin(), tmp_subs.end() );
-                  sj = Rewriter::rewrite( sj );
-                  if( sj==( sol.getKind()==AND ? d_qe->getTermUtil()->d_false : d_qe->getTermUtil()->d_true ) ){
-                    Trace("csi-simp") << "--- " << children[i].negate() << " is implied by " << children[j].negate() << std::endl;
-                    red = true;
-                    break;
-                  }
-                }
-              }
-              if( !red ){
-                Trace("csi-simp-debug") << "...is not." << std::endl;
-              }
-            }
-          }
-        }
-        if( !red ){
-          final_children.push_back( children[i] );
-        }
-      }
-      return final_children.size()==0 ? NodeManager::currentNM()->mkConst( sol.getKind()==AND ) :
-             ( final_children.size()==1 ? final_children[0] : NodeManager::currentNM()->mkNode( sol.getKind(), final_children ) );
-    }else{
-      //generic simplification
-      std::vector< Node > children;
-      if( sol.getMetaKind() == kind::metakind::PARAMETERIZED ){
-        children.push_back( sol.getOperator() );
-      }
-      bool childChanged = false;
-      for( unsigned i=0; i<sol.getNumChildren(); i++ ){
-        Node nc = simplifySolutionNode( sol[i], stnc[i], assign, vars, subs, 0 );
-        childChanged = childChanged || nc!=sol[i];
-        children.push_back( nc );
-      }
-      if( childChanged ){
-        return NodeManager::currentNM()->mkNode( sol.getKind(), children );
-      }
-    }
-    return sol;
-  }
-}
-
-
-void CegConjectureSingleInvSol::preregisterConjecture( Node q ) {
-  Trace("csi-sol") << "Preregister conjecture : " << q << std::endl;
-  Node n = q;
-  if( n.getKind()==FORALL ){
-    n = n[1];
-  }
-  if( n.getKind()==EXISTS ){
-    if( n[0].getNumChildren()==d_varList.size() ){
-      std::vector< Node > evars;
-      for( unsigned i=0; i<n[0].getNumChildren(); i++ ){
-        evars.push_back( n[0][i] );
-      }
-      n = n[1].substitute( evars.begin(), evars.end(), d_varList.begin(), d_varList.end() );
-    }else{
-      Trace("csi-sol") << "Not the same number of variables, return." << std::endl;
-      return;
-    }
-  }
-  Trace("csi-sol") << "Preregister node for solution reconstruction : " << n << std::endl;
-  registerEquivalentTerms( n );
-}
-
-Node CegConjectureSingleInvSol::reconstructSolution( Node sol, TypeNode stn, int& reconstructed ) {
-  Trace("csi-rcons") << "Solution (pre-reconstruction) is : " << sol << std::endl;
-  int status;
-  d_root_id = collectReconstructNodes( sol, stn, status );
-  if( status==0 ){
-    Node ret = getReconstructedSolution( d_root_id );
-    Trace("csi-rcons") << "Sygus solution is : " << ret << std::endl;
-    Assert( !ret.isNull() );
-    reconstructed = 1;
-    return ret;
-  }else{
-    //Trace("csi-debug-sol") << "Induced solution template is : " << d_templ_solution << std::endl;
-    if( Trace.isOn("csi-rcons") ){
-      for( std::map< TypeNode, std::map< Node, int > >::iterator it = d_rcons_to_id.begin(); it != d_rcons_to_id.end(); ++it ){
-        TypeNode tn = it->first;
-        Assert( tn.isDatatype() );
-        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-        Trace("csi-rcons") << "Terms to reconstruct of type " << dt.getName() << " : " << std::endl;
-        for( std::map< Node, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
-          if( d_reconstruct.find( it2->second )==d_reconstruct.end() ){
-            Trace("csi-rcons") << "  " << it2->first << std::endl;
-          }
-        }
-        Assert( !it->second.empty() );
-      }
-    }
-    unsigned index = 0;
-    std::map< TypeNode, bool > active;
-    for( std::map< TypeNode, std::map< Node, int > >::iterator it = d_rcons_to_id.begin(); it != d_rcons_to_id.end(); ++it ){
-      active[it->first] = true;
-    }
-    //enumerate for all types
-    do {
-      std::vector< TypeNode > to_erase;
-      for( std::map< TypeNode, bool >::iterator it = active.begin(); it != active.end(); ++it ){
-        TypeNode stn = it->first;
-        Node ns = d_qe->getTermEnumeration()->getEnumerateTerm(stn, index);
-        if( ns.isNull() ){
-          to_erase.push_back( stn );
-        }else{
-          Node nb = d_qe->getTermDatabaseSygus()->sygusToBuiltin( ns, stn );
-          Node nr = Rewriter::rewrite( nb );//d_qe->getTermDatabaseSygus()->getNormalized( stn, nb, false, false );
-          Trace("csi-rcons-debug2") << "  - try " << ns << " -> " << nr << " for " << stn << " " << nr.getKind() << std::endl;
-          std::map< Node, int >::iterator itt = d_rcons_to_id[stn].find( nr );
-          if( itt!= d_rcons_to_id[stn].end() ){
-            // if it is not already reconstructed
-            if( d_reconstruct.find( itt->second )==d_reconstruct.end() ){
-              Trace("csi-rcons") << "...reconstructed " << ns << " for term " << nr << std::endl;
-              bool do_check = true;//getPathToRoot( itt->second );
-              setReconstructed( itt->second, ns );
-              if( do_check ){
-                Trace("csi-rcons-debug") << "...path to root, try reconstruction." << std::endl;
-                d_tmp_fail.clear();
-                Node ret = getReconstructedSolution( d_root_id );
-                if( !ret.isNull() ){
-                  Trace("csi-rcons") << "Sygus solution (after enumeration) is : " << ret << std::endl;
-                  reconstructed = 1;
-                  return ret;
-                }
-              }else{
-                Trace("csi-rcons-debug") << "...no path to root." << std::endl;
-              }
-            }
-          }
-        }
-      }
-      for( unsigned i=0; i<to_erase.size(); i++ ){
-        active.erase( to_erase[i] );
-      }
-      index++;
-      if( index%100==0 ){
-        Trace("csi-rcons-stats") << "Tried " << index << " for each type."  << std::endl;
-      }
-    }while( !active.empty() );
-
-    // we ran out of elements, return null
-    reconstructed = -1;
-    Warning() << CommandFailure("Cannot get synth function: reconstruction to syntax failed.");
-    return Node::null(); // return sol;
-  }
-}
-
-int CegConjectureSingleInvSol::collectReconstructNodes( Node t, TypeNode stn, int& status ) {
-  std::map< Node, int >::iterator itri = d_rcons_to_status[stn].find( t );
-  if( itri!=d_rcons_to_status[stn].end() ){
-    status = itri->second;
-    //Trace("csi-rcons-debug") << "-> (cached) " << status << " for " << d_rcons_to_id[stn][t] << std::endl;
-    return d_rcons_to_id[stn][t];
-  }else{
-    status = 1;
-    // register the type
-    registerType(stn);
-    int id = allocate( t, stn );
-    d_rcons_to_status[stn][t] = -1;
-    TypeNode tn = t.getType();
-    Assert( stn.isDatatype() );
-    const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
-    Assert( dt.isSygus() );
-    Trace("csi-rcons-debug") << "Check reconstruct " << t << ", sygus type " << dt.getName() << ", kind " << t.getKind() << ", id : " << id << std::endl;
-    int carg = -1;
-    int karg = -1;
-    // first, do standard minimizations
-    Node min_t = d_qe->getTermDatabaseSygus()->minimizeBuiltinTerm( t );
-    Trace("csi-rcons-debug") << "Minimized term is : " << min_t << std::endl;
-    //check if op is in syntax sort
-    carg = d_qe->getTermDatabaseSygus()->getOpConsNum( stn, min_t );
-    if( carg!=-1 ){
-      Trace("csi-rcons-debug") << "  Type has operator." << std::endl;
-      d_reconstruct[id] = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, Node::fromExpr( dt[carg].getConstructor() ) );
-      status = 0;
-    }else{
-      //check if kind is in syntax sort
-      karg = d_qe->getTermDatabaseSygus()->getKindConsNum( stn, min_t.getKind() );
-      if( karg!=-1 ){
-        //collect the children of min_t
-        std::vector< Node > tchildren;
-        if( min_t.getNumChildren()>dt[karg].getNumArgs() && quantifiers::TermUtil::isAssoc( min_t.getKind() ) && dt[karg].getNumArgs()==2 ){
-          tchildren.push_back( min_t[0] );
-          std::vector< Node > rem_children;
-          for( unsigned i=1; i<min_t.getNumChildren(); i++ ){
-            rem_children.push_back( min_t[i] );
-          }
-          Node t2 = NodeManager::currentNM()->mkNode( min_t.getKind(), rem_children );
-          tchildren.push_back( t2 );
-          Trace("csi-rcons-debug") << "...split n-ary to binary " << min_t[0] << " " << t2 << "." << std::endl;
-        }else{
-          for( unsigned i=0; i<min_t.getNumChildren(); i++ ){
-            tchildren.push_back( min_t[i] );
-          }
-        }
-        //recurse on the children
-        if( tchildren.size()==dt[karg].getNumArgs() ){
-          Trace("csi-rcons-debug") << "Type for " << id << " has kind " << min_t.getKind() << ", recurse." << std::endl;
-          status = 0;
-          Node cons = Node::fromExpr( dt[karg].getConstructor() );
-          if( !collectReconstructNodes( id, tchildren, dt[karg], d_reconstruct_op[id][cons], status ) ){
-            Trace("csi-rcons-debug") << "...failure for " << id << " " << dt[karg].getName() << std::endl;
-            d_reconstruct_op[id].erase( cons );
-            status = 1;
-          }
-        }else{
-          Trace("csi-rcons-debug") << "Type for " << id << " has kind " << min_t.getKind() << ", but argument # mismatch." << std::endl;
-        }
-      }
-      if( status!=0 ){
-        //try constant reconstruction
-        if( min_t.isConst() ){
-          Trace("csi-rcons-debug") << "...try constant reconstruction." << std::endl;
-          Node min_t_c = builtinToSygusConst(min_t, stn);
-          if( !min_t_c.isNull() ){
-            Trace("csi-rcons-debug") << "   constant reconstruction success for " << id << ", result = " << min_t_c << std::endl;
-            d_reconstruct[id] = min_t_c;
-            status = 0;
-          }
-        }
-        if( status!=0 ){
-          //try identity functions
-          for (unsigned ii : d_id_funcs[stn])
-          {
-            Assert( dt[ii].getNumArgs()==1 );
-            //try to directly reconstruct from single argument
-            std::vector< Node > tchildren;
-            tchildren.push_back( min_t );
-            TypeNode stnc = TypeNode::fromType( ((SelectorType)dt[ii][0].getType()).getRangeType() );
-            Trace("csi-rcons-debug") << "...try identity function " << dt[ii].getSygusOp() << ", child type is " << stnc << std::endl;
-            status = 0;
-            Node cons = Node::fromExpr( dt[ii].getConstructor() );
-            if( !collectReconstructNodes( id, tchildren, dt[ii], d_reconstruct_op[id][cons], status ) ){
-              d_reconstruct_op[id].erase( cons );
-              status = 1;
-            }else{
-              Trace("csi-rcons-debug") << "   identity function success for " << id << std::endl;
-              break;
-            }
-          }
-          if( status!=0 ){
-            //try other options, such as matching against other constructors
-            Trace("csi-rcons-debug") << "Try matching for " << id << "." << std::endl;
-            bool success;
-            int c_index = 0;
-            do{
-              success = false;
-              int index_found;
-              std::vector< Node > args;
-              if (getMatch(min_t, stn, index_found, args, karg, c_index))
-              {
-                success = true;
-                status = 0;
-                Node cons = Node::fromExpr( dt[index_found].getConstructor() );
-                Trace("csi-rcons-debug") << "Try alternative for " << id << ", matching " << dt[index_found].getName() << " with children : " << std::endl;
-                for( unsigned i=0; i<args.size(); i++ ){
-                  Trace("csi-rcons-debug") << "  " << args[i] << std::endl;
-                }
-                if( !collectReconstructNodes( id, args, dt[index_found], d_reconstruct_op[id][cons], status ) ){
-                  d_reconstruct_op[id].erase( cons );
-                  status = 1;
-                }else{
-                  c_index = index_found+1;
-                }
-              }
-            }while( success && status!=0 );
-
-            if( status!=0 ){
-              // construct an equivalence class of terms that are equivalent to t
-              if( d_rep[id]==id ){
-                Trace("csi-rcons-debug") << "Try rewriting for " << id << "." << std::endl;
-                //get equivalence class of term
-                std::vector< Node > equiv;
-                if( tn.isBoolean() ){
-                  Node curr = min_t;
-                  Node new_t;
-                  do{
-                    new_t = Node::null();
-                    if( curr.getKind()==EQUAL ){
-                      if( curr[0].getType().isInteger() || curr[0].getType().isReal() ){
-                        new_t = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( LEQ, curr[0], curr[1] ),
-                                                                      NodeManager::currentNM()->mkNode( LEQ, curr[1], curr[0] ) );
-                      }else if( curr[0].getType().isBoolean() ){
-                        new_t = NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, curr[0], curr[1] ),
-                                                                      NodeManager::currentNM()->mkNode( AND, curr[0].negate(), curr[1].negate() ) );
-                      }else{
-                        new_t = NodeManager::currentNM()->mkNode( NOT, NodeManager::currentNM()->mkNode( NOT, curr ) );
-                      }
-                    }else if( curr.getKind()==ITE ){
-                      new_t = NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, curr[0], curr[1] ),
-                                                                    NodeManager::currentNM()->mkNode( AND, curr[0].negate(), curr[2] ) );
-                    }else if( curr.getKind()==OR || curr.getKind()==AND ){
-                      new_t = TermUtil::simpleNegate( curr ).negate();
-                    }else if( curr.getKind()==NOT ){
-                      new_t = TermUtil::simpleNegate( curr[0] );
-                    }else{
-                      new_t = NodeManager::currentNM()->mkNode( NOT, NodeManager::currentNM()->mkNode( NOT, curr ) );
-                    }
-                    if( !new_t.isNull() ){
-                      if( new_t!=min_t && std::find( equiv.begin(), equiv.end(), new_t )==equiv.end() ){
-                        curr = new_t;
-                        equiv.push_back( new_t );
-                      }else{
-                        new_t = Node::null();
-                      }
-                    }
-                  }while( !new_t.isNull() );
-                }
-                //get decompositions
-                for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-                  Kind k = d_qe->getTermDatabaseSygus()->getConsNumKind( stn, i );
-                  getEquivalentTerms( k, min_t, equiv );
-                }
-                //assign ids to terms
-                Trace("csi-rcons-debug") << "Term " << id << " is equivalent to " << equiv.size() << " terms : " << std::endl;
-                std::vector< int > equiv_ids;
-                for( unsigned i=0; i<equiv.size(); i++ ){
-                  Trace("csi-rcons-debug") << "  " << equiv[i] << std::endl;
-                  if( d_rcons_to_id[stn].find( equiv[i] )==d_rcons_to_id[stn].end() ){
-                    int eq_id = allocate( equiv[i], stn );
-                    d_eqc.erase( eq_id );
-                    d_rep[eq_id] = id;
-                    d_eqc[id].push_back( eq_id );
-                    equiv_ids.push_back( eq_id );
-                  }else{
-                    equiv_ids.push_back( -1 );
-                  }
-                }
-                // now, try each of them
-                for( unsigned i=0; i<equiv.size(); i++ ){
-                  if( equiv_ids[i]!=-1 ){
-                    collectReconstructNodes( equiv[i], stn, status );
-                    //if one succeeds
-                    if( status==0 ){
-                      Node rsol = getReconstructedSolution( equiv_ids[i] );
-                      Assert( !rsol.isNull() );
-                      //set all members of the equivalence class that this is the reconstructed solution
-                      setReconstructed( id, rsol );
-                      break;
-                    }
-                  }
-                }
-              }else{
-                Trace("csi-rcons-debug") << "Do not try rewriting for " << id << ", rep = " << d_rep[id] << std::endl;
-              }
-            }
-          }
-        }
-      }
-    }
-    if( status!=0 ){
-      Trace("csi-rcons-debug") << "-> *** reconstruction required for id " << id << std::endl;
-    }else{
-      Trace("csi-rcons-debug") << "-> success for " << id << std::endl;
-    }
-    d_rcons_to_status[stn][t] = status;
-    return id;
-  }
-}
-
-bool CegConjectureSingleInvSol::collectReconstructNodes( int pid, std::vector< Node >& ts, const DatatypeConstructor& dtc, std::vector< int >& ids, int& status ) {
-  Assert( dtc.getNumArgs()==ts.size() );
-  for( unsigned i=0; i<ts.size(); i++ ){
-    TypeNode cstn = d_qe->getTermDatabaseSygus()->getArgType( dtc, i );
-    int cstatus;
-    int c_id = collectReconstructNodes( ts[i], cstn, cstatus );
-    if( cstatus==-1 ){
-      return false;
-    }else if( cstatus!=0 ){
-      status = 1;
-    }
-    ids.push_back( c_id );
-  }
-  for( unsigned i=0; i<ids.size(); i++ ){
-    d_parents[ids[i]].push_back( pid );
-  }
-  return true;
-}
-
-  /*
-  //flatten ITEs if necessary  TODO : carry assignment or move this elsewhere
-  if( t.getKind()==ITE ){
-    TypeNode cstn = tds->getArgType( dt[karg], 0 );
-    tds->registerSygusType( cstn );
-    Node prev_t;
-    while( !tds->hasKind( cstn, t[0].getKind() ) && t!=prev_t ){
-      prev_t = t;
-      Node exp_c = tds->expandBuiltinTerm( t[0] );
-      if( !exp_c.isNull() ){
-        t = NodeManager::currentNM()->mkNode( ITE, exp_c, t[1], t[2] );
-        Trace("csi-rcons-debug") << "Pre expand to " << t << std::endl;
-      }
-      t = flattenITEs( t, false );
-      if( t!=prev_t ){
-        Trace("csi-rcons-debug") << "Flatten ITE to " << t << std::endl;
-        std::map< Node, bool > sassign;
-        std::vector< Node > svars;
-        std::vector< Node > ssubs;
-        t = simplifySolutionNode( t, sassign, svars, ssubs, 0 );
-      }
-      Assert( t.getKind()==ITE );
-    }
-  }
-  */
-
-
-Node CegConjectureSingleInvSol::CegConjectureSingleInvSol::getReconstructedSolution( int id, bool mod_eq ) {
-  std::map< int, Node >::iterator it = d_reconstruct.find( id );
-  if( it!=d_reconstruct.end() ){
-    return it->second;
-  }else{
-    if( std::find( d_tmp_fail.begin(), d_tmp_fail.end(), id )!=d_tmp_fail.end() ){
-      return Node::null();
-    }else{
-      // try each child option
-      std::map< int, std::map< Node, std::vector< int > > >::iterator ito = d_reconstruct_op.find( id );
-      if( ito!=d_reconstruct_op.end() ){
-        for( std::map< Node, std::vector< int > >::iterator itt = ito->second.begin(); itt != ito->second.end(); ++itt ){
-          std::vector< Node > children;
-          children.push_back( itt->first );
-          bool success = true;
-          for( unsigned i=0; i<itt->second.size(); i++ ){
-            Node nc = getReconstructedSolution( itt->second[i] );
-            if( nc.isNull() ){
-              success = false;
-              break;
-            }else{
-              children.push_back( nc );
-            }
-          }
-          if( success ){
-            Node ret = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
-            setReconstructed( id, ret );
-            return ret;
-          }
-        }
-      }
-      // try terms in the equivalence class of this
-      if( mod_eq ){
-        int rid = d_rep[id];
-        for( unsigned i=0; i<d_eqc[rid].size(); i++ ){
-          int tid = d_eqc[rid][i];
-          if( tid!=id ){
-            Node eret = getReconstructedSolution( tid, false );
-            if( !eret.isNull() ){
-              setReconstructed( id, eret );
-              return eret;
-            }
-          }
-        }
-      }
-      d_tmp_fail.push_back( id );
-      return Node::null();
-    }
-  }
-}
-
-int CegConjectureSingleInvSol::allocate( Node n, TypeNode stn ) {
-  std::map< Node, int >::iterator it = d_rcons_to_id[stn].find( n );
-  if( it==d_rcons_to_id[stn].end() ){
-    int ret = d_id_count;
-    if( Trace.isOn("csi-rcons-debug") ){
-      const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
-      Trace("csi-rcons-debug") << "id " << ret << " : " << n << " " <<  dt.getName() << std::endl;
-    }
-    d_id_node[d_id_count] = n;
-    d_id_type[d_id_count] = stn;
-    d_rep[d_id_count] = d_id_count;
-    d_eqc[d_id_count].push_back( d_id_count );
-    d_rcons_to_id[stn][n] = d_id_count;
-    d_id_count++;
-    return ret;
-  }else{
-    return it->second;
-  }
-}
-
-bool CegConjectureSingleInvSol::getPathToRoot( int id ) {
-  if( id==d_root_id ){
-    return true;
-  }else{
-    std::map< int, Node >::iterator it = d_reconstruct.find( id );
-    if( it!=d_reconstruct.end() ){
-      return false;
-    }else{
-      int rid = d_rep[id];
-      for( unsigned j=0; j<d_parents[rid].size(); j++ ){
-        if( getPathToRoot( d_parents[rid][j] ) ){
-          return true;
-        }
-      }
-      return false;
-    }
-  }
-}
-
-void CegConjectureSingleInvSol::setReconstructed( int id, Node n ) {
-  //set all equivalent to this as reconstructed
-  int rid = d_rep[id];
-  for( unsigned i=0; i<d_eqc[rid].size(); i++ ){
-    d_reconstruct[d_eqc[rid][i]] = n;
-  }
-}
-
-void CegConjectureSingleInvSol::getEquivalentTerms( Kind k, Node n, std::vector< Node >& equiv ) {
-  if( k==AND || k==OR ){
-    equiv.push_back( NodeManager::currentNM()->mkNode( k, n, n ) );
-    equiv.push_back( NodeManager::currentNM()->mkNode( k, n, NodeManager::currentNM()->mkConst( k==AND ) ) );
-  }
-  //multiplication for integers
-  //TODO for bitvectors
-  Kind mk = ( k==PLUS || k==MINUS ) ? MULT : UNDEFINED_KIND;
-  if( mk!=UNDEFINED_KIND ){
-    if( n.getKind()==mk && n[0].isConst() && n[0].getType().isInteger() ){
-      bool success = true;
-      for( unsigned i=0; i<2; i++ ){
-        Node eq;
-        if( k==PLUS || k==MINUS ){
-          Node oth = NodeManager::currentNM()->mkConst( Rational(i==0 ? 1000 : -1000) );
-          eq = i==0 ? NodeManager::currentNM()->mkNode( LEQ, n[0], oth ) : NodeManager::currentNM()->mkNode( GEQ, n[0], oth );
-        }
-        if( !eq.isNull() ){
-          eq = Rewriter::rewrite( eq );
-          if( eq!=d_qe->getTermUtil()->d_true ){
-            success = false;
-            break;
-          }
-        }
-      }
-      if( success ){
-        Node var = n[1];
-        Node rem;
-        if( k==PLUS || k==MINUS ){
-          int rem_coeff = (int)n[0].getConst<Rational>().getNumerator().getSignedInt();
-          if( rem_coeff>0 && k==PLUS ){
-            rem_coeff--;
-          }else if( rem_coeff<0 && k==MINUS ){
-            rem_coeff++;
-          }else{
-            success = false;
-          }
-          if( success ){
-            rem = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(rem_coeff) ), var );
-            rem = Rewriter::rewrite( rem );
-          }
-        }
-        if( !rem.isNull() ){
-          equiv.push_back( NodeManager::currentNM()->mkNode( k, rem, var ) );
-        }
-      }
-    }
-  }
-  //negative constants
-  if( k==MINUS ){
-    if( n.isConst() && n.getType().isInteger() && n.getConst<Rational>().getNumerator().strictlyNegative() ){
-      Node nn = NodeManager::currentNM()->mkNode( UMINUS, n );
-      nn = Rewriter::rewrite( nn );
-      equiv.push_back( NodeManager::currentNM()->mkNode( MINUS, NodeManager::currentNM()->mkConst( Rational(0) ), nn ) );
-    }
-  }
-  //inequalities
-  if( k==GEQ || k==LEQ || k==LT || k==GT || k==NOT ){
-    Node atom = n.getKind()==NOT ? n[0] : n;
-    bool pol = n.getKind()!=NOT;
-    Kind ak = atom.getKind();
-    if( ( ak==GEQ || ak==LEQ || ak==LT || ak==GT ) && ( pol || k!=NOT ) ){
-      Node t1 = atom[0];
-      Node t2 = atom[1];
-      if( !pol ){
-        ak = ak==GEQ ? LT : ( ak==LEQ ? GT : ( ak==LT ? GEQ : LEQ ) );
-      }
-      if( k==NOT ){
-        equiv.push_back( NodeManager::currentNM()->mkNode( ak==GEQ ? LT : ( ak==LEQ ? GT : ( ak==LT ? GEQ : LEQ ) ), t1, t2 ).negate() );
-      }else if( k==ak ){
-        equiv.push_back( NodeManager::currentNM()->mkNode( k, t1, t2 ) );
-      }else if( (k==GEQ || k==LEQ)==(ak==GEQ || ak==LEQ) ){
-        equiv.push_back( NodeManager::currentNM()->mkNode( k, t2, t1 ) );
-      }else if( t1.getType().isInteger() && t2.getType().isInteger() ){
-        if( (k==GEQ || k==GT)!=(ak==GEQ || ak==GT) ){
-          Node ts = t1;
-          t1 = t2;
-          t2 = ts;
-          ak = ak==GEQ ? LEQ : ( ak==LEQ ? GEQ : ( ak==LT ? GT : LT ) );
-        }
-        t2 = NodeManager::currentNM()->mkNode( PLUS, t2, NodeManager::currentNM()->mkConst( Rational( (ak==GT || ak==LEQ) ? 1 : -1 ) ) );
-        t2 = Rewriter::rewrite( t2 );
-        equiv.push_back( NodeManager::currentNM()->mkNode( k, t1, t2 ) );
-      }
-    }
-  }
-
-  //based on eqt cache
-  std::map< Node, Node >::iterator itet = d_eqt_rep.find( n );
-  if( itet!=d_eqt_rep.end() ){
-    Node rn = itet->second;
-    for( unsigned i=0; i<d_eqt_eqc[rn].size(); i++ ){
-      if( d_eqt_eqc[rn][i]!=n && d_eqt_eqc[rn][i].getKind()==k ){
-        if( std::find( equiv.begin(), equiv.end(), d_eqt_eqc[rn][i] )==equiv.end() ){
-          equiv.push_back( d_eqt_eqc[rn][i] );
-        }
-      }
-    }
-  }
-}
-
-void CegConjectureSingleInvSol::registerEquivalentTerms( Node n ) {
-  for( unsigned i=0; i<n.getNumChildren(); i++ ){
-    registerEquivalentTerms( n[i] );
-  }
-  Node rn = Rewriter::rewrite( n );
-  if( rn!=n ){
-    Trace("csi-equiv") << "  eq terms : " << n << " " << rn << std::endl;
-    d_eqt_rep[n] = rn;
-    d_eqt_rep[rn] = rn;
-    if( std::find( d_eqt_eqc[rn].begin(), d_eqt_eqc[rn].end(), rn )==d_eqt_eqc[rn].end() ){
-      d_eqt_eqc[rn].push_back( rn );
-    }
-    if( std::find( d_eqt_eqc[rn].begin(), d_eqt_eqc[rn].end(), n )==d_eqt_eqc[rn].end() ){
-      d_eqt_eqc[rn].push_back( n );
-    }
-  }
-}
-
-Node CegConjectureSingleInvSol::builtinToSygusConst(Node c,
-                                                    TypeNode tn,
-                                                    int rcons_depth)
-{
-  std::map<Node, Node>::iterator it = d_builtin_const_to_sygus[tn].find(c);
-  if (it != d_builtin_const_to_sygus[tn].end())
-  {
-    return it->second;
-  }
-  TermDbSygus* tds = d_qe->getTermDatabaseSygus();
-  NodeManager* nm = NodeManager::currentNM();
-  Node sc;
-  d_builtin_const_to_sygus[tn][c] = sc;
-  Assert(c.isConst());
-  Assert(tn.isDatatype());
-  const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
-  Trace("csi-rcons-debug") << "Try to reconstruct " << c << " in "
-                           << dt.getName() << std::endl;
-  Assert(dt.isSygus());
-  // if we are not interested in reconstructing constants, or the grammar allows
-  // them, return a proxy
-  if (!options::cegqiSingleInvReconstructConst() || dt.getSygusAllowConst())
-  {
-    Node k = nm->mkSkolem("sy", tn, "sygus proxy");
-    SygusPrintProxyAttribute spa;
-    k.setAttribute(spa, c);
-    sc = k;
-  }
-  else
-  {
-    int carg = tds->getOpConsNum(tn, c);
-    if (carg != -1)
-    {
-      sc = nm->mkNode(APPLY_CONSTRUCTOR,
-                      Node::fromExpr(dt[carg].getConstructor()));
-    }
-    else
-    {
-      // identity functions
-      for (unsigned ii : d_id_funcs[tn])
-      {
-        Assert(dt[ii].getNumArgs() == 1);
-        // try to directly reconstruct from single argument
-        TypeNode tnc = tds->getArgType(dt[ii], 0);
-        Trace("csi-rcons-debug")
-            << "Based on id function " << dt[ii].getSygusOp()
-            << ", try reconstructing " << c << " instead in " << tnc
-            << std::endl;
-        Node n = builtinToSygusConst(c, tnc, rcons_depth);
-        if (!n.isNull())
-        {
-          sc = nm->mkNode(
-              APPLY_CONSTRUCTOR, Node::fromExpr(dt[ii].getConstructor()), n);
-          break;
-        }
-      }
-      if (sc.isNull())
-      {
-        if (rcons_depth < 1000)
-        {
-          // accelerated, recursive reconstruction of constants
-          Kind pk = tds->getPlusKind(TypeNode::fromType(dt.getSygusType()));
-          if (pk != UNDEFINED_KIND)
-          {
-            int arg = tds->getKindConsNum(tn, pk);
-            if (arg != -1)
-            {
-              Kind ck =
-                  tds->getComparisonKind(TypeNode::fromType(dt.getSygusType()));
-              Kind pkm =
-                  tds->getPlusKind(TypeNode::fromType(dt.getSygusType()), true);
-              // get types
-              Assert(dt[arg].getNumArgs() == 2);
-              TypeNode tn1 = tds->getArgType(dt[arg], 0);
-              TypeNode tn2 = tds->getArgType(dt[arg], 1);
-              // initialize d_const_list for tn1
-              registerType(tn1);
-              // iterate over all positive constants, largest to smallest
-              int start = d_const_list[tn1].size() - 1;
-              int end = d_const_list[tn1].size() - d_const_list_pos[tn1];
-              for (int i = start; i >= end; --i)
-              {
-                Node c1 = d_const_list[tn1][i];
-                // only consider if smaller than c, and
-                if (doCompare(c1, c, ck))
-                {
-                  Node c2 = nm->mkNode(pkm, c, c1);
-                  c2 = Rewriter::rewrite(c2);
-                  if (c2.isConst())
-                  {
-                    // reconstruct constant on the other side
-                    Node sc2 = builtinToSygusConst(c2, tn2, rcons_depth + 1);
-                    if (!sc2.isNull())
-                    {
-                      Node sc1 = builtinToSygusConst(c1, tn1, rcons_depth);
-                      Assert(!sc1.isNull());
-                      sc = nm->mkNode(APPLY_CONSTRUCTOR,
-                                      Node::fromExpr(dt[arg].getConstructor()),
-                                      sc1,
-                                      sc2);
-                      break;
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-  d_builtin_const_to_sygus[tn][c] = sc;
-  return sc;
-}
-
-struct sortConstants
-{
-  Kind d_comp_kind;
-  bool operator()(Node i, Node j)
-  {
-    return i != j && doCompare(i, j, d_comp_kind);
-  }
-};
-
-void CegConjectureSingleInvSol::registerType(TypeNode tn)
-{
-  if (d_const_list_pos.find(tn) != d_const_list_pos.end())
-  {
-    return;
-  }
-  d_const_list_pos[tn] = 0;
-  Assert(tn.isDatatype());
-
-  TermDbSygus* tds = d_qe->getTermDatabaseSygus();
-  // ensure it is registered
-  tds->registerSygusType(tn);
-  const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
-  TypeNode btn = TypeNode::fromType(dt.getSygusType());
-  // for constant reconstruction
-  Kind ck = tds->getComparisonKind(btn);
-  Node z = d_qe->getTermUtil()->getTypeValue(btn, 0);
-
-  // iterate over constructors
-  for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
-  {
-    Node n = Node::fromExpr(dt[i].getSygusOp());
-    if (n.getKind() != kind::BUILTIN && n.isConst())
-    {
-      d_const_list[tn].push_back(n);
-      if (ck != UNDEFINED_KIND && doCompare(z, n, ck))
-      {
-        d_const_list_pos[tn]++;
-      }
-    }
-    if (dt[i].isSygusIdFunc())
-    {
-      d_id_funcs[tn].push_back(i);
-    }
-  }
-  // sort the constant list
-  if (!d_const_list[tn].empty())
-  {
-    if (ck != UNDEFINED_KIND)
-    {
-      sortConstants sc;
-      sc.d_comp_kind = ck;
-      std::sort(d_const_list[tn].begin(), d_const_list[tn].end(), sc);
-    }
-    Trace("csi-rcons") << "Type has " << d_const_list[tn].size()
-                       << " constants..." << std::endl
-                       << "  ";
-    for (unsigned i = 0; i < d_const_list[tn].size(); i++)
-    {
-      Trace("csi-rcons") << d_const_list[tn][i] << " ";
-    }
-    Trace("csi-rcons") << std::endl;
-    Trace("csi-rcons") << "Of these, " << d_const_list_pos[tn]
-                       << " are marked as positive." << std::endl;
-  }
-}
-
-bool CegConjectureSingleInvSol::getMatch(Node p,
-                                         Node n,
-                                         std::map<int, Node>& s,
-                                         std::vector<int>& new_s)
-{
-  TermDbSygus* tds = d_qe->getTermDatabaseSygus();
-  if (tds->isFreeVar(p))
-  {
-    unsigned vnum = tds->getVarNum(p);
-    Node prev = s[vnum];
-    s[vnum] = n;
-    if (prev.isNull())
-    {
-      new_s.push_back(vnum);
-    }
-    return prev.isNull() || prev == n;
-  }
-  if (n.getNumChildren() == 0)
-  {
-    return p == n;
-  }
-  if (n.getKind() == p.getKind() && n.getNumChildren() == p.getNumChildren())
-  {
-    // try both ways?
-    unsigned rmax =
-        TermUtil::isComm(n.getKind()) && n.getNumChildren() == 2 ? 2 : 1;
-    std::vector<int> new_tmp;
-    for (unsigned r = 0; r < rmax; r++)
-    {
-      bool success = true;
-      for (unsigned i = 0, size = n.getNumChildren(); i < size; i++)
-      {
-        int io = r == 0 ? i : (i == 0 ? 1 : 0);
-        if (!getMatch(p[i], n[io], s, new_tmp))
-        {
-          success = false;
-          for (unsigned j = 0; j < new_tmp.size(); j++)
-          {
-            s.erase(new_tmp[j]);
-          }
-          new_tmp.clear();
-          break;
-        }
-      }
-      if (success)
-      {
-        new_s.insert(new_s.end(), new_tmp.begin(), new_tmp.end());
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
-bool CegConjectureSingleInvSol::getMatch(Node t,
-                                         TypeNode st,
-                                         int& index_found,
-                                         std::vector<Node>& args,
-                                         int index_exc,
-                                         int index_start)
-{
-  Assert(st.isDatatype());
-  const Datatype& dt = static_cast<DatatypeType>(st.toType()).getDatatype();
-  Assert(dt.isSygus());
-  std::map<Kind, std::vector<Node> > kgens;
-  std::vector<Node> gens;
-  for (unsigned i = index_start, ncons = dt.getNumConstructors(); i < ncons;
-       i++)
-  {
-    if ((int)i != index_exc)
-    {
-      Node g = getGenericBase(st, dt, i);
-      gens.push_back(g);
-      kgens[g.getKind()].push_back(g);
-      Trace("csi-sol-debug") << "Check generic base : " << g << " from "
-                             << dt[i].getName() << std::endl;
-      if (g.getKind() == t.getKind())
-      {
-        Trace("csi-sol-debug") << "Possible match ? " << g << " " << t
-                               << " for " << dt[i].getName() << std::endl;
-        std::map<int, Node> sigma;
-        std::vector<int> new_s;
-        if (getMatch(g, t, sigma, new_s))
-        {
-          // we found an exact match
-          bool msuccess = true;
-          for (unsigned j = 0, nargs = dt[i].getNumArgs(); j < nargs; j++)
-          {
-            if (sigma[j].isNull())
-            {
-              msuccess = false;
-              break;
-            }
-            else
-            {
-              args.push_back(sigma[j]);
-            }
-          }
-          if (msuccess)
-          {
-            index_found = i;
-            return true;
-          }
-        }
-      }
-    }
-  }
-  return false;
-}
-
-Node CegConjectureSingleInvSol::getGenericBase(TypeNode tn,
-                                               const Datatype& dt,
-                                               int c)
-{
-  std::map<int, Node>::iterator it = d_generic_base[tn].find(c);
-  if (it != d_generic_base[tn].end())
-  {
-    return it->second;
-  }
-  TermDbSygus* tds = d_qe->getTermDatabaseSygus();
-  Assert(tds->isRegistered(tn));
-  std::map<TypeNode, int> var_count;
-  std::map<int, Node> pre;
-  Node g = tds->mkGeneric(dt, c, var_count, pre);
-  Trace("csi-sol-debug") << "Generic is " << g << std::endl;
-  Node gr = Rewriter::rewrite(g);
-  Trace("csi-sol-debug") << "Generic rewritten is " << gr << std::endl;
-  d_generic_base[tn][c] = gr;
-  return gr;
-}
-}
-}
-}
diff --git a/src/theory/quantifiers/ce_guided_single_inv_sol.h b/src/theory/quantifiers/ce_guided_single_inv_sol.h
deleted file mode 100644 (file)
index 7043e1e..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/*********************                                                        */
-/*! \file ce_guided_single_inv_sol.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Paul Meng
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief utility for reconstructing solutions for single invocation synthesis conjectures
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_SINGLE_INV_SOL_H
-#define __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_SINGLE_INV_SOL_H
-
-#include "context/cdhashmap.h"
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-
-class CegConjectureSingleInv;
-
-/** CegConjectureSingleInvSol
- *
- * This function implements Figure 5 of "Counterexample-Guided Quantifier
- * Instantiation for Synthesis in SMT", Reynolds et al CAV 2015.
- *
- */
-class CegConjectureSingleInvSol
-{
-  friend class CegConjectureSingleInv;
-private:
-  QuantifiersEngine * d_qe;
-  std::vector< Node > d_varList;
-  std::map< Node, int > d_dterm_size;
-  std::map< Node, int > d_dterm_ite_size;
-//solution simplification
-private:
-  bool debugSolution( Node sol );
-  void debugTermSize( Node sol, int& t_size, int& num_ite );
-  Node pullITEs( Node n );
-  bool pullITECondition( Node root, Node n, std::vector< Node >& conj, Node& t, Node& rem, int depth );
-  Node flattenITEs( Node n, bool rec = true );
-  bool getAssign( bool pol, Node n, std::map< Node, bool >& assign, std::vector< Node >& new_assign,
-                  std::vector< Node >& vars, std::vector< Node >& new_vars, std::vector< Node >& new_subs );
-  bool getAssignEquality( Node eq, std::vector< Node >& vars, std::vector< Node >& new_vars, std::vector< Node >& new_subs );
-  Node simplifySolutionNode( Node sol, TypeNode stn, std::map< Node, bool >& assign,
-                             std::vector< Node >& vars, std::vector< Node >& subs, int status );
-
- public:
-  CegConjectureSingleInvSol(QuantifiersEngine* qe);
-  /** simplify solution
-   *
-   * Returns the simplified version of node sol whose syntax is restricted by
-   * the grammar corresponding to sygus datatype stn.
-   */
-  Node simplifySolution( Node sol, TypeNode stn );
-  /** reconstruct solution
-   *
-   * Returns (if possible) a node that is equivalent to sol those syntax
-   * matches the grammar corresponding to sygus datatype stn.
-   * The value reconstructed is set to 1 if we successfully return a node,
-   * otherwise it is set to -1.
-   */
-  Node reconstructSolution(Node sol, TypeNode stn, int& reconstructed);
-  /** preregister conjecture
-   *
-   * q : the synthesis conjecture this class is for.
-   * This is used as a heuristic to find terms in the original conjecture which
-   * may be helpful for using during reconstruction.
-   */
-  void preregisterConjecture(Node q);
-
- private:
-  int d_id_count;
-  int d_root_id;
-  std::map< int, Node > d_id_node;
-  std::map< int, TypeNode > d_id_type;
-  std::map< TypeNode, std::map< Node, int > > d_rcons_to_id;
-  std::map< TypeNode, std::map< Node, int > > d_rcons_to_status;
-
-  std::map< int, std::map< Node, std::vector< int > > > d_reconstruct_op;
-  std::map< int, Node > d_reconstruct;
-  std::map< int, std::vector< int > > d_parents;
-
-  std::map< int, std::vector< int > > d_eqc;
-  std::map< int, int > d_rep;
-  
-  //equivalent terms
-  std::map< Node, Node > d_eqt_rep;
-  std::map< Node, std::vector< Node > > d_eqt_eqc;
-
-  //cache when reconstructing solutions
-  std::vector< int > d_tmp_fail;
-  // get reconstructed solution
-  Node getReconstructedSolution( int id, bool mod_eq = true );
-
-  // allocate node with type
-  int allocate( Node n, TypeNode stn );
-  // term t with sygus type st, returns inducted templated form of t
-  int collectReconstructNodes( Node t, TypeNode stn, int& status );
-  bool collectReconstructNodes( int pid, std::vector< Node >& ts, const DatatypeConstructor& dtc, std::vector< int >& ids, int& status );
-  bool getPathToRoot( int id );
-  void setReconstructed( int id, Node n );
-  //get equivalent terms to n with top symbol k
-  void getEquivalentTerms( Kind k, Node n, std::vector< Node >& equiv );
-  //register equivalent terms
-  void registerEquivalentTerms( Node n );
-  /** builtin to sygus const
-   *
-   * Returns a sygus term of type tn that encodes the builtin constant c.
-   * If the sygus datatype tn allows any constant, this may return a variable
-   * with the attribute SygusPrintProxyAttribute that associates it with c.
-   *
-   * rcons_depth limits the number of recursive calls when doing accelerated
-   * constant reconstruction (currently limited to 1000). Notice this is hacky:
-   * depending upon order of calls, constant rcons may succeed, e.g. 1001, 999
-   * vs. 999, 1001.
-   */
-  Node builtinToSygusConst(Node c, TypeNode tn, int rcons_depth = 0);
-  /** cache for the above function */
-  std::map<TypeNode, std::map<Node, Node> > d_builtin_const_to_sygus;
-  /** sorted list of constants, per type */
-  std::map<TypeNode, std::vector<Node> > d_const_list;
-  /** number of positive constants, per type */
-  std::map<TypeNode, unsigned> d_const_list_pos;
-  /** list of constructor indices whose operators are identity functions */
-  std::map<TypeNode, std::vector<int> > d_id_funcs;
-  /** initialize the above information for sygus type tn */
-  void registerType(TypeNode tn);
-  /** get generic base
-   *
-   * This returns the builtin term that is the analog of an application of the
-   * c^th constructor of dt to fresh variables.
-   */
-  Node getGenericBase(TypeNode tn, const Datatype& dt, int c);
-  /** cache for the above function */
-  std::map<TypeNode, std::map<int, Node> > d_generic_base;
-  /** get match
-   *
-   * This function attempts to find a substitution for which p = n. If
-   * successful, this function returns a substitution in the form of s/new_s,
-   * where:
-   * s : substitution, where the domain are indices of terms in the sygus
-   * term database, and
-   * new_s : the members that were added to s on this call.
-   * Otherwise, this function returns false and s and new_s are unmodified.
-   */
-  bool getMatch(Node p,
-                Node n,
-                std::map<int, Node>& s,
-                std::vector<int>& new_s);
-  /** get match
-   *
-   * This function attempts to find a builtin term that is analog to a value
-   * of the sygus datatype st that is equivalent to n. If this function returns
-   * true, then it has found such a term. Then we set:
-   *   index_found : updated to the constructor index of the sygus term whose
-   *   analog to equivalent to n.
-   *   args : builtin terms corresponding to the match, in order.
-   * Otherwise, this function returns false and index_found and args are
-   * unmodified.
-   * For example, for grammar:
-   *   A -> 0 | 1 | x | +( A, A )
-   * Given input ( 5 + (x+1) ) and A we would return true, where:
-   *   index_found is set to 3 and args is set to { 5, x+1 }.
-   *
-   * index_exc : (if applicable) exclude a constructor index of st
-   * index_start : start index of constructors of st to try
-   */
-  bool getMatch(Node n,
-                TypeNode st,
-                int& index_found,
-                std::vector<Node>& args,
-                int index_exc = -1,
-                int index_start = 0);
-};
-
-
-}
-}
-}
-
-#endif
diff --git a/src/theory/quantifiers/ceg_instantiator.cpp b/src/theory/quantifiers/ceg_instantiator.cpp
deleted file mode 100644 (file)
index 0e8b229..0000000
+++ /dev/null
@@ -1,1337 +0,0 @@
-/*********************                                                        */
-/*! \file ceg_instantiator.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of counterexample-guided quantifier instantiation
- **/
-
-#include "theory/quantifiers/ceg_instantiator.h"
-#include "theory/quantifiers/ceg_t_instantiator.h"
-
-#include "options/quantifiers_options.h"
-#include "smt/term_formula_removal.h"
-#include "theory/arith/arith_msum.h"
-#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/quantifiers_rewriter.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_enumeration.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
-#include "theory/theory_engine.h"
-
-using namespace std;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-std::ostream& operator<<(std::ostream& os, CegInstEffort e)
-{
-  switch (e)
-  {
-    case CEG_INST_EFFORT_NONE: os << "?"; break;
-    case CEG_INST_EFFORT_STANDARD: os << "STANDARD"; break;
-    case CEG_INST_EFFORT_STANDARD_MV: os << "STANDARD_MV"; break;
-    case CEG_INST_EFFORT_FULL: os << "FULL"; break;
-    default: Unreachable();
-  }
-  return os;
-}
-
-std::ostream& operator<<(std::ostream& os, CegInstPhase phase)
-{
-  switch (phase)
-  {
-    case CEG_INST_PHASE_NONE: os << "?"; break;
-    case CEG_INST_PHASE_EQC: os << "eqc"; break;
-    case CEG_INST_PHASE_EQUAL: os << "eq"; break;
-    case CEG_INST_PHASE_ASSERTION: os << "as"; break;
-    case CEG_INST_PHASE_MVALUE: os << "mv"; break;
-    default: Unreachable();
-  }
-  return os;
-}
-
-CegInstantiator::CegInstantiator(QuantifiersEngine* qe,
-                                 CegqiOutput* out,
-                                 bool use_vts_delta,
-                                 bool use_vts_inf)
-    : d_qe(qe),
-      d_out(out),
-      d_use_vts_delta(use_vts_delta),
-      d_use_vts_inf(use_vts_inf),
-      d_is_nested_quant(false),
-      d_effort(CEG_INST_EFFORT_NONE)
-{
-}
-
-CegInstantiator::~CegInstantiator() {
-  for (std::pair<Node, Instantiator*> inst : d_instantiator)
-  {
-    delete inst.second;
-  }
-  for (std::pair<TheoryId, InstantiatorPreprocess*> instp : d_tipp)
-  {
-    delete instp.second;
-  }
-}
-
-void CegInstantiator::computeProgVars( Node n ){
-  if( d_prog_var.find( n )==d_prog_var.end() ){
-    d_prog_var[n].clear();
-    if (n.getKind() == kind::CHOICE)
-    {
-      Assert(d_prog_var.find(n[0][0]) == d_prog_var.end());
-      d_prog_var[n[0][0]].clear();
-    }
-    if (d_vars_set.find(n) != d_vars_set.end())
-    {
-      d_prog_var[n].insert(n);
-    }else if( !d_out->isEligibleForInstantiation( n ) ){
-      d_inelig.insert(n);
-      return;
-    }
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      computeProgVars( n[i] );
-      if( d_inelig.find( n[i] )!=d_inelig.end() ){
-        d_inelig.insert(n);
-      }
-      // all variables in child are contained in this
-      d_prog_var[n].insert(d_prog_var[n[i]].begin(), d_prog_var[n[i]].end());
-    }
-    // selectors applied to program variables are also variables
-    if (n.getKind() == APPLY_SELECTOR_TOTAL
-        && d_prog_var[n].find(n[0]) != d_prog_var[n].end())
-    {
-      d_prog_var[n].insert(n);
-    }
-    if (n.getKind() == kind::CHOICE)
-    {
-      d_prog_var.erase(n[0][0]);
-    }
-  }
-}
-
-bool CegInstantiator::isEligible( Node n ) {
-  //compute d_subs_fv, which program variables are contained in n, and determines if eligible
-  computeProgVars( n );
-  return d_inelig.find( n )==d_inelig.end();
-}
-
-bool CegInstantiator::hasVariable( Node n, Node pv ) {
-  computeProgVars( n );
-  return d_prog_var[n].find( pv )!=d_prog_var[n].end();
-}
-
-void CegInstantiator::activateInstantiationVariable(Node v, unsigned index)
-{
-  if( d_instantiator.find( v )==d_instantiator.end() ){
-    TypeNode tn = v.getType();
-    Instantiator * vinst;
-    if( tn.isReal() ){
-      vinst = new ArithInstantiator( d_qe, tn );
-    }else if( tn.isSort() ){
-      Assert( options::quantEpr() );
-      vinst = new EprInstantiator( d_qe, tn );
-    }else if( tn.isDatatype() ){
-      vinst = new DtInstantiator( d_qe, tn );
-    }else if( tn.isBitVector() ){
-      vinst = new BvInstantiator( d_qe, tn );
-    }else if( tn.isBoolean() ){
-      vinst = new ModelValueInstantiator( d_qe, tn );
-    }else{
-      //default
-      vinst = new Instantiator( d_qe, tn );
-    }
-    d_instantiator[v] = vinst;
-  }
-  d_curr_subs_proc[v].clear();
-  d_curr_index[v] = index;
-  d_curr_iphase[v] = CEG_INST_PHASE_NONE;
-}
-
-void CegInstantiator::registerTheoryIds(TypeNode tn,
-                                        std::map<TypeNode, bool>& visited)
-{
-  if (visited.find(tn) == visited.end())
-  {
-    visited[tn] = true;
-    TheoryId tid = Theory::theoryOf(tn);
-    registerTheoryId(tid);
-    if (tn.isDatatype())
-    {
-      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-      for (unsigned i = 0; i < dt.getNumConstructors(); i++)
-      {
-        for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
-        {
-          registerTheoryIds(
-              TypeNode::fromType(
-                  ((SelectorType)dt[i][j].getType()).getRangeType()),
-              visited);
-        }
-      }
-    }
-  }
-}
-
-void CegInstantiator::registerTheoryId(TheoryId tid)
-{
-  if (std::find(d_tids.begin(), d_tids.end(), tid) == d_tids.end())
-  {
-    // setup any theory-specific preprocessors here
-    if (tid == THEORY_BV)
-    {
-      d_tipp[tid] = new BvInstantiatorPreprocess;
-    }
-    d_tids.push_back(tid);
-  }
-}
-
-void CegInstantiator::registerVariable(Node v, bool is_aux)
-{
-  Assert(std::find(d_vars.begin(), d_vars.end(), v) == d_vars.end());
-  Assert(std::find(d_aux_vars.begin(), d_aux_vars.end(), v)
-         == d_aux_vars.end());
-  if (!is_aux)
-  {
-    d_vars.push_back(v);
-    d_vars_set.insert(v);
-  }
-  else
-  {
-    d_aux_vars.push_back(v);
-  }
-  TypeNode vtn = v.getType();
-  Trace("cbqi-proc-debug") << "Collect theory ids from type " << vtn << " of "
-                           << v << std::endl;
-  // collect relevant theories for this variable
-  std::map<TypeNode, bool> visited;
-  registerTheoryIds(vtn, visited);
-}
-
-void CegInstantiator::deactivateInstantiationVariable(Node v)
-{
-  d_curr_subs_proc.erase( v );
-  d_curr_index.erase( v );
-  d_curr_iphase.erase(v);
-}
-
-bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i)
-{
-  if( i==d_vars.size() ){
-    //solved for all variables, now construct instantiation
-    bool needsPostprocess =
-        sf.d_vars.size() > d_input_vars.size() || !d_var_order_index.empty();
-    std::vector< Instantiator * > pp_inst;
-    std::map< Instantiator *, Node > pp_inst_to_var;
-    std::vector< Node > lemmas;
-    for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){
-      if (ita->second->needsPostProcessInstantiationForVariable(
-              this, sf, ita->first, d_effort))
-      {
-        needsPostprocess = true;
-        pp_inst_to_var[ ita->second ] = ita->first;
-      }
-    }
-    if( needsPostprocess ){
-      //must make copy so that backtracking reverts sf
-      SolvedForm sf_tmp = sf;
-      bool postProcessSuccess = true;
-      for( std::map< Instantiator *, Node >::iterator itp = pp_inst_to_var.begin(); itp != pp_inst_to_var.end(); ++itp ){
-        if (!itp->first->postProcessInstantiationForVariable(
-                this, sf_tmp, itp->second, d_effort, lemmas))
-        {
-          postProcessSuccess = false;
-          break;
-        }
-      }
-      if( postProcessSuccess ){
-        return doAddInstantiation( sf_tmp.d_vars, sf_tmp.d_subs, lemmas );
-      }else{
-        return false;
-      }
-    }else{
-      return doAddInstantiation( sf.d_vars, sf.d_subs, lemmas );
-    }
-  }else{
-    //Node v = d_single_inv_map_to_prog[d_single_inv[0][i]];
-    bool is_cv = false;
-    Node pv;
-    if( d_stack_vars.empty() ){
-      pv = d_vars[i];
-    }else{
-      pv = d_stack_vars.back();
-      is_cv = true;
-      d_stack_vars.pop_back();
-    }
-    activateInstantiationVariable(pv, i);
-
-    //get the instantiator object
-    Instantiator * vinst = NULL;
-    std::map< Node, Instantiator * >::iterator itin = d_instantiator.find( pv );
-    if( itin!=d_instantiator.end() ){
-      vinst = itin->second;
-    }
-    Assert( vinst!=NULL );
-    d_active_instantiators[pv] = vinst;
-    vinst->reset(this, sf, pv, d_effort);
-
-    TypeNode pvtn = pv.getType();
-    TypeNode pvtnb = pvtn.getBaseType();
-    Node pvr = pv;
-    if( d_qe->getMasterEqualityEngine()->hasTerm( pv ) ){
-      pvr = d_qe->getMasterEqualityEngine()->getRepresentative( pv );
-    }
-    Trace("cbqi-inst-debug") << "[Find instantiation for " << pv << "], rep=" << pvr << ", instantiator is " << vinst->identify() << std::endl;
-    Node pv_value;
-    if( options::cbqiModel() ){
-      pv_value = getModelValue( pv );
-      Trace("cbqi-bound2") << "...M( " << pv << " ) = " << pv_value << std::endl;
-    }
-
-    // if d_effort is full, we must choose at least one model value
-    if ((i + 1) < d_vars.size() || d_effort != CEG_INST_EFFORT_FULL)
-    {
-      //[1] easy case : pv is in the equivalence class as another term not containing pv
-      Trace("cbqi-inst-debug") << "[1] try based on equivalence class." << std::endl;
-      d_curr_iphase[pv] = CEG_INST_PHASE_EQC;
-      std::map< Node, std::vector< Node > >::iterator it_eqc = d_curr_eqc.find( pvr );
-      if( it_eqc!=d_curr_eqc.end() ){
-        //std::vector< Node > eq_candidates;
-        Trace("cbqi-inst-debug2") << "...eqc has size " << it_eqc->second.size() << std::endl;
-        for( unsigned k=0; k<it_eqc->second.size(); k++ ){
-          Node n = it_eqc->second[k];
-          if( n!=pv ){
-            Trace("cbqi-inst-debug") << "...try based on equal term " << n << std::endl;
-            //must be an eligible term
-            if( isEligible( n ) ){
-              Node ns;
-              TermProperties pv_prop;  //coefficient of pv in the equality we solve (null is 1)
-              bool proc = false;
-              if( !d_prog_var[n].empty() ){
-                ns = applySubstitution( pvtn, n, sf, pv_prop, false );
-                if( !ns.isNull() ){
-                  computeProgVars( ns );
-                  //substituted version must be new and cannot contain pv
-                  proc = d_prog_var[ns].find( pv )==d_prog_var[ns].end();
-                }
-              }else{
-                ns = n;
-                proc = true;
-              }
-              if( proc ){
-                if (vinst->processEqualTerm(
-                        this, sf, pv, pv_prop, ns, d_effort))
-                {
-                  return true;
-                }
-                // Do not consider more than one equal term,
-                // this helps non-monotonic strategies that may encounter
-                // duplicate instantiations.
-                break;
-              }
-            }
-          }
-        }
-        if (vinst->processEqualTerms(this, sf, pv, it_eqc->second, d_effort))
-        {
-          return true;
-        }
-      }else{
-        Trace("cbqi-inst-debug2") << "...eqc not found." << std::endl;
-      }
-
-      //[2] : we can solve an equality for pv
-      /// iterate over equivalence classes to find cases where we can solve for
-      /// the variable
-      if (vinst->hasProcessEquality(this, sf, pv, d_effort))
-      {
-        Trace("cbqi-inst-debug") << "[2] try based on solving equalities." << std::endl;
-        d_curr_iphase[pv] = CEG_INST_PHASE_EQUAL;
-        for( unsigned k=0; k<d_curr_type_eqc[pvtnb].size(); k++ ){
-          Node r = d_curr_type_eqc[pvtnb][k];
-          std::map< Node, std::vector< Node > >::iterator it_reqc = d_curr_eqc.find( r );
-          std::vector< Node > lhs;
-          std::vector< bool > lhs_v;
-          std::vector< TermProperties > lhs_prop;
-          Assert( it_reqc!=d_curr_eqc.end() );
-          for( unsigned kk=0; kk<it_reqc->second.size(); kk++ ){
-            Node n = it_reqc->second[kk];
-            Trace("cbqi-inst-debug2") << "...look at term " << n << std::endl;
-            //must be an eligible term
-            if( isEligible( n ) ){
-              Node ns;
-              TermProperties pv_prop;
-              if( !d_prog_var[n].empty() ){
-                ns = applySubstitution( pvtn, n, sf, pv_prop );
-                if( !ns.isNull() ){
-                  computeProgVars( ns );
-                }
-              }else{
-                ns = n;
-              }
-              if( !ns.isNull() ){
-                bool hasVar = d_prog_var[ns].find( pv )!=d_prog_var[ns].end();
-                Trace("cbqi-inst-debug2") << "... " << ns << " has var " << pv << " : " << hasVar << std::endl;
-                std::vector< TermProperties > term_props;
-                std::vector< Node > terms;
-                term_props.push_back( pv_prop );
-                terms.push_back( ns );
-                for( unsigned j=0; j<lhs.size(); j++ ){
-                  //if this term or the another has pv in it, try to solve for it
-                  if( hasVar || lhs_v[j] ){
-                    Trace("cbqi-inst-debug") << "... " << i << "...try based on equality " << lhs[j] << " = " << ns << std::endl;
-                    term_props.push_back( lhs_prop[j] );
-                    terms.push_back( lhs[j] );
-                    if (vinst->processEquality(
-                            this, sf, pv, term_props, terms, d_effort))
-                    {
-                      return true;
-                    }
-                    term_props.pop_back();
-                    terms.pop_back();
-                  }
-                }
-                lhs.push_back( ns );
-                lhs_v.push_back( hasVar );
-                lhs_prop.push_back( pv_prop );
-              }else{
-                Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible after substitution." << std::endl;
-              }
-            }else{
-              Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible." << std::endl;
-            }
-          }
-        }
-      }
-
-      //[3] directly look at assertions
-      if (vinst->hasProcessAssertion(this, sf, pv, d_effort))
-      {
-        Trace("cbqi-inst-debug") << "[3] try based on assertions." << std::endl;
-        d_curr_iphase[pv] = CEG_INST_PHASE_ASSERTION;
-        std::unordered_set< Node, NodeHashFunction > lits;
-        //unsigned rmax = Theory::theoryOf( pv )==Theory::theoryOf( pv.getType() ) ? 1 : 2;
-        for( unsigned r=0; r<2; r++ ){
-          TheoryId tid = r==0 ? Theory::theoryOf( pvtn ) : THEORY_UF;
-          Trace("cbqi-inst-debug2") << "  look at assertions of " << tid << std::endl;
-          std::map< TheoryId, std::vector< Node > >::iterator ita = d_curr_asserts.find( tid );
-          if( ita!=d_curr_asserts.end() ){
-            for (unsigned j = 0; j<ita->second.size(); j++) {
-              Node lit = ita->second[j];
-              if( lits.find(lit)==lits.end() ){
-                lits.insert(lit);
-                Node plit;
-                if (options::cbqiRepeatLit() || !isSolvedAssertion(lit))
-                {
-                  plit =
-                      vinst->hasProcessAssertion(this, sf, pv, lit, d_effort);
-                }
-                if (!plit.isNull()) {
-                  Trace("cbqi-inst-debug2") << "  look at " << lit;
-                  if (plit != lit) {
-                    Trace("cbqi-inst-debug2") << "...processed to : " << plit;
-                  }
-                  Trace("cbqi-inst-debug2") << std::endl;
-                  // apply substitutions
-                  Node slit = applySubstitutionToLiteral(plit, sf);
-                  if( !slit.isNull() ){
-                    // check if contains pv
-                    if( hasVariable( slit, pv ) ){
-                      Trace("cbqi-inst-debug") << "...try based on literal "
-                                               << slit << "," << std::endl;
-                      Trace("cbqi-inst-debug") << "...from " << lit
-                                               << std::endl;
-                      if (vinst->processAssertion(
-                              this, sf, pv, slit, lit, d_effort))
-                      {
-                        return true;
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-        if (vinst->processAssertions(this, sf, pv, d_effort))
-        {
-          return true;
-        }
-      }
-    }
-
-    //[4] resort to using value in model. We do so if:
-    // - if the instantiator uses model values at this effort, or
-    // - if we are solving for a subfield of a datatype (is_cv).
-    if ((vinst->useModelValue(this, sf, pv, d_effort) || is_cv)
-        && vinst->allowModelValue(this, sf, pv, d_effort))
-    {
-#ifdef CVC4_ASSERTIONS
-      if( pvtn.isReal() && options::cbqiNestedQE() && !options::cbqiAll() ){
-        Trace("cbqi-warn") << "Had to resort to model value." << std::endl;
-        Assert( false );
-      }
-#endif
-      Node mv = getModelValue( pv );
-      TermProperties pv_prop_m;
-      Trace("cbqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl;
-      d_curr_iphase[pv] = CEG_INST_PHASE_MVALUE;
-      CegInstEffort prev = d_effort;
-      if (d_effort < CEG_INST_EFFORT_STANDARD_MV)
-      {
-        // update the effort level to indicate we have used a model value
-        d_effort = CEG_INST_EFFORT_STANDARD_MV;
-      }
-      if (constructInstantiationInc(pv, mv, pv_prop_m, sf))
-      {
-        return true;
-      }
-      d_effort = prev;
-    }
-    Trace("cbqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl;
-    if( is_cv ){
-      d_stack_vars.push_back( pv );
-    }
-    d_active_instantiators.erase( pv );
-    deactivateInstantiationVariable(pv);
-    return false;
-  }
-}
-
-void CegInstantiator::pushStackVariable( Node v ) {
-  d_stack_vars.push_back( v );
-}
-
-void CegInstantiator::popStackVariable() {
-  Assert( !d_stack_vars.empty() );
-  d_stack_vars.pop_back();
-}
-
-bool CegInstantiator::constructInstantiationInc(Node pv,
-                                                Node n,
-                                                TermProperties& pv_prop,
-                                                SolvedForm& sf,
-                                                bool revertOnSuccess)
-{
-  Node cnode = pv_prop.getCacheNode();
-  if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){
-    d_curr_subs_proc[pv][n][cnode] = true;
-    if( Trace.isOn("cbqi-inst-debug") ){
-      for( unsigned j=0; j<sf.d_subs.size(); j++ ){
-        Trace("cbqi-inst-debug") << " ";
-      }
-      Trace("cbqi-inst-debug") << sf.d_subs.size() << ": (" << d_curr_iphase[pv]
-                         << ") ";
-      Node mod_pv = pv_prop.getModifiedTerm( pv );
-      Trace("cbqi-inst-debug") << mod_pv << " -> " << n << std::endl;
-      Assert( n.getType().isSubtypeOf( pv.getType() ) );
-    }
-    //must ensure variables have been computed for n
-    computeProgVars( n );
-    Assert( d_inelig.find( n )==d_inelig.end() );
-
-    //substitute into previous substitutions, when applicable
-    std::vector< Node > a_var;
-    a_var.push_back( pv );
-    std::vector< Node > a_subs;
-    a_subs.push_back( n );
-    std::vector< TermProperties > a_prop;
-    a_prop.push_back( pv_prop );
-    std::vector< Node > a_non_basic;
-    if( !pv_prop.isBasic() ){
-      a_non_basic.push_back( pv );
-    }
-    bool success = true;
-    std::map< int, Node > prev_subs;
-    std::map< int, TermProperties > prev_prop;
-    std::map< int, Node > prev_sym_subs;
-    std::vector< Node > new_non_basic;
-    Trace("cbqi-inst-debug2") << "Applying substitutions to previous substitution terms..." << std::endl;
-    for( unsigned j=0; j<sf.d_subs.size(); j++ ){
-      Trace("cbqi-inst-debug2") << "  Apply for " << sf.d_subs[j]  << std::endl;
-      Assert( d_prog_var.find( sf.d_subs[j] )!=d_prog_var.end() );
-      if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){
-        prev_subs[j] = sf.d_subs[j];
-        TNode tv = pv;
-        TNode ts = n;
-        TermProperties a_pv_prop;
-        Node new_subs = applySubstitution( sf.d_vars[j].getType(), sf.d_subs[j], a_var, a_subs, a_prop, a_non_basic, a_pv_prop, true );
-        if( !new_subs.isNull() ){
-          sf.d_subs[j] = new_subs;
-          // the substitution apply to this term resulted in a non-basic substitution relationship
-          if( !a_pv_prop.isBasic() ){
-            // we are processing:
-            //    sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n } 
-          
-            // based on the above substitution, we have:
-            //   x = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n } 
-            // is equivalent to
-            //   a_pv_prop.getModifiedTerm( x ) = new_subs
-            
-            // thus we must compose substitutions:
-            //   a_pv_prop.getModifiedTerm( sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) ) = new_subs
-            
-            prev_prop[j] = sf.d_props[j];
-            bool prev_basic = sf.d_props[j].isBasic();
-            
-            // now compose the property
-            sf.d_props[j].composeProperty( a_pv_prop );
-            
-            // if previously was basic, becomes non-basic
-            if( prev_basic && !sf.d_props[j].isBasic() ){
-              Assert( std::find( sf.d_non_basic.begin(), sf.d_non_basic.end(), sf.d_vars[j] )==sf.d_non_basic.end() );
-              new_non_basic.push_back( sf.d_vars[j] );
-              sf.d_non_basic.push_back( sf.d_vars[j] );
-            }
-          }
-          if( sf.d_subs[j]!=prev_subs[j] ){
-            computeProgVars( sf.d_subs[j] );
-            Assert( d_inelig.find( sf.d_subs[j] )==d_inelig.end() );
-          }
-          Trace("cbqi-inst-debug2") << "Subs " << j << " " << sf.d_subs[j] << std::endl;
-        }else{
-          Trace("cbqi-inst-debug2") << "...failed to apply substitution to " << sf.d_subs[j] << std::endl;
-          success = false;
-          break;
-        }
-      }else{
-        Trace("cbqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl;
-      }
-    }
-    if( success ){
-      Trace("cbqi-inst-debug2") << "Adding to vectors..." << std::endl;
-      sf.push_back( pv, n, pv_prop );
-      Trace("cbqi-inst-debug2") << "Recurse..." << std::endl;
-      unsigned i = d_curr_index[pv];
-      success = constructInstantiation(sf, d_stack_vars.empty() ? i + 1 : i);
-      if (!success || revertOnSuccess)
-      {
-        Trace("cbqi-inst-debug2") << "Removing from vectors..." << std::endl;
-        sf.pop_back( pv, n, pv_prop );
-      }
-    }
-    if (success && !revertOnSuccess)
-    {
-      return true;
-    }else{
-      Trace("cbqi-inst-debug2") << "Revert substitutions..." << std::endl;
-      //revert substitution information
-      for( std::map< int, Node >::iterator it = prev_subs.begin(); it != prev_subs.end(); it++ ){
-        sf.d_subs[it->first] = it->second;
-      }
-      for( std::map< int, TermProperties >::iterator it = prev_prop.begin(); it != prev_prop.end(); it++ ){
-        sf.d_props[it->first] = it->second;
-      }
-      for( unsigned i=0; i<new_non_basic.size(); i++ ){
-        sf.d_non_basic.pop_back();
-      }
-      return success;
-    }
-  }else{
-    //already tried this substitution
-    return false;
-  }
-}
-
-bool CegInstantiator::doAddInstantiation( std::vector< Node >& vars, std::vector< Node >& subs, std::vector< Node >& lemmas ) {
-  if (vars.size() > d_input_vars.size() || !d_var_order_index.empty())
-  {
-    Trace("cbqi-inst-debug") << "Reconstructing instantiations...." << std::endl;
-    std::map< Node, Node > subs_map;
-    for( unsigned i=0; i<subs.size(); i++ ){
-      subs_map[vars[i]] = subs[i];
-    }
-    subs.clear();
-    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
-    {
-      std::map<Node, Node>::iterator it = subs_map.find(d_input_vars[i]);
-      Assert( it!=subs_map.end() );
-      Node n = it->second;
-      Trace("cbqi-inst-debug") << "  " << d_input_vars[i] << " -> " << n
-                               << std::endl;
-      Assert(n.getType().isSubtypeOf(d_input_vars[i].getType()));
-      subs.push_back( n );
-    }
-  }
-  if (Trace.isOn("cbqi-inst"))
-  {
-    Trace("cbqi-inst") << "Ceg Instantiator produced : " << std::endl;
-    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
-    {
-      Node v = d_input_vars[i];
-      Trace("cbqi-inst") << i << " (" << d_curr_iphase[v] << ") : " 
-                         << v << " -> " << subs[i] << std::endl;
-      Assert(subs[i].getType().isSubtypeOf(v.getType()));
-    }
-  }
-  Trace("cbqi-inst-debug") << "Do the instantiation...." << std::endl;
-  bool ret = d_out->doAddInstantiation( subs );
-  for( unsigned i=0; i<lemmas.size(); i++ ){
-    d_out->addLemma( lemmas[i] );
-  }
-  return ret;
-}
-
-bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){
-  Assert( d_prog_var.find( n )!=d_prog_var.end() );
-  if( !non_basic.empty() ){
-    for (std::unordered_set<Node, NodeHashFunction>::iterator it =
-             d_prog_var[n].begin();
-         it != d_prog_var[n].end();
-         ++it)
-    {
-      if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end())
-      {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, 
-                                         std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff ) {
-  computeProgVars( n );
-  Assert( n==Rewriter::rewrite( n ) );
-  bool is_basic = canApplyBasicSubstitution( n, non_basic );
-  if( Trace.isOn("cegqi-si-apply-subs-debug") ){
-    Trace("cegqi-si-apply-subs-debug") << "is_basic = " << is_basic << "  " << tn << std::endl;
-    for( unsigned i=0; i<subs.size(); i++ ){
-      Trace("cegqi-si-apply-subs-debug") << "  " << vars[i] << " -> " << subs[i] << "   types : " << vars[i].getType() << " -> " << subs[i].getType() << std::endl;
-      Assert( subs[i].getType().isSubtypeOf( vars[i].getType() ) );
-    }
-  }
-  Node nret;
-  if( is_basic ){
-    nret = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
-  }else{
-    if( !tn.isInteger() ){
-      //can do basic substitution instead with divisions
-      std::vector< Node > nvars;
-      std::vector< Node > nsubs;
-      for( unsigned i=0; i<vars.size(); i++ ){
-        if( !prop[i].d_coeff.isNull() ){
-          Assert( vars[i].getType().isInteger() );
-          Assert( prop[i].d_coeff.isConst() );
-          Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst<Rational>() ) );
-          nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn );
-          nn =  Rewriter::rewrite( nn );
-          nsubs.push_back( nn );
-        }else{
-          nsubs.push_back( subs[i] );
-        }
-      }
-      nret = n.substitute( vars.begin(), vars.end(), nsubs.begin(), nsubs.end() );
-    }else if( try_coeff ){
-      //must convert to monomial representation
-      std::map< Node, Node > msum;
-      if (ArithMSum::getMonomialSum(n, msum))
-      {
-        std::map< Node, Node > msum_coeff;
-        std::map< Node, Node > msum_term;
-        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
-          //check if in substitution
-          std::vector< Node >::iterator its = std::find( vars.begin(), vars.end(), it->first );
-          if( its!=vars.end() ){
-            int index = its-vars.begin();
-            if( prop[index].d_coeff.isNull() ){
-              //apply substitution
-              msum_term[it->first] = subs[index];
-            }else{
-              //apply substitution, multiply to ensure no divisibility conflict
-              msum_term[it->first] = subs[index];
-              //relative coefficient
-              msum_coeff[it->first] = prop[index].d_coeff;
-              if( pv_prop.d_coeff.isNull() ){
-                pv_prop.d_coeff = prop[index].d_coeff;
-              }else{
-                pv_prop.d_coeff = NodeManager::currentNM()->mkNode( MULT, pv_prop.d_coeff, prop[index].d_coeff );
-              }
-            }
-          }else{
-            msum_term[it->first] = it->first;
-          }
-        }
-        //make sum with normalized coefficient
-        if( !pv_prop.d_coeff.isNull() ){
-          pv_prop.d_coeff = Rewriter::rewrite( pv_prop.d_coeff );
-          Trace("cegqi-si-apply-subs-debug") << "Combined coeff : " << pv_prop.d_coeff << std::endl;
-          std::vector< Node > children;
-          for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
-            Node c_coeff;
-            if( !msum_coeff[it->first].isNull() ){
-              c_coeff = Rewriter::rewrite( NodeManager::currentNM()->mkConst( pv_prop.d_coeff.getConst<Rational>() / msum_coeff[it->first].getConst<Rational>() ) );
-            }else{
-              c_coeff = pv_prop.d_coeff;
-            }
-            if( !it->second.isNull() ){
-              c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second );
-            }
-            Assert( !c_coeff.isNull() );
-            Node c;
-            if( msum_term[it->first].isNull() ){
-              c = c_coeff;
-            }else{
-              c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
-            }
-            children.push_back( c );
-            Trace("cegqi-si-apply-subs-debug") << "Add child : " << c << std::endl;
-          }
-          Node nretc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children );
-          nretc = Rewriter::rewrite( nretc );
-          //ensure that nret does not contain vars
-          if( !TermUtil::containsTerms( nretc, vars ) ){
-            //result is ( nret / pv_prop.d_coeff )
-            nret = nretc;
-          }else{
-            Trace("cegqi-si-apply-subs-debug") << "Failed, since result " << nretc << " contains free variable." << std::endl;
-          }
-        }else{
-          //implies that we have a monomial that has a free variable
-          Trace("cegqi-si-apply-subs-debug") << "Failed to find coefficient during substitution, implies monomial with free variable." << std::endl;
-        }
-      }else{
-        Trace("cegqi-si-apply-subs-debug") << "Failed to find monomial sum " << n << std::endl;
-      }
-    }
-  }
-  if( n!=nret && !nret.isNull() ){
-    nret = Rewriter::rewrite( nret );
-  }
-  return nret;
-}
-
-Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs, 
-                                                  std::vector< TermProperties >& prop, std::vector< Node >& non_basic ) {
-  computeProgVars( lit );
-  bool is_basic = canApplyBasicSubstitution( lit, non_basic );
-  Node lret;
-  if( is_basic ){
-   lret = lit.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
-  }else{
-    Node atom = lit.getKind()==NOT ? lit[0] : lit;
-    bool pol = lit.getKind()!=NOT;
-    //arithmetic inequalities and disequalities
-    if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){
-      Assert( atom.getKind()!=GEQ || atom[1].isConst() );
-      Node atom_lhs;
-      Node atom_rhs;
-      if( atom.getKind()==GEQ ){
-        atom_lhs = atom[0];
-        atom_rhs = atom[1];
-      }else{
-        atom_lhs = NodeManager::currentNM()->mkNode( MINUS, atom[0], atom[1] );
-        atom_lhs = Rewriter::rewrite( atom_lhs );
-        atom_rhs = getQuantifiersEngine()->getTermUtil()->d_zero;
-      }
-      //must be an eligible term
-      if( isEligible( atom_lhs ) ){
-        //apply substitution to LHS of atom
-        TermProperties atom_lhs_prop;
-        atom_lhs = applySubstitution( NodeManager::currentNM()->realType(), atom_lhs, vars, subs, prop, non_basic, atom_lhs_prop );
-        if( !atom_lhs.isNull() ){
-          if( !atom_lhs_prop.d_coeff.isNull() ){
-            atom_rhs = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, atom_lhs_prop.d_coeff, atom_rhs ) );
-          }
-          lret = NodeManager::currentNM()->mkNode( atom.getKind(), atom_lhs, atom_rhs );
-          if( !pol ){
-            lret = lret.negate();
-          }
-        }
-      }
-    }else{
-      // don't know how to apply substitution to literal
-    }
-  }
-  if( lit!=lret && !lret.isNull() ){
-    lret = Rewriter::rewrite( lret );
-  }
-  return lret;
-}
-  
-bool CegInstantiator::check() {
-  if( d_qe->getTheoryEngine()->needCheck() ){
-    Trace("cbqi-engine") << "  CEGQI instantiator : wait until all ground theories are finished." << std::endl;
-    return false;
-  }
-  processAssertions();
-  for( unsigned r=0; r<2; r++ ){
-    d_effort = r == 0 ? CEG_INST_EFFORT_STANDARD : CEG_INST_EFFORT_FULL;
-    SolvedForm sf;
-    d_stack_vars.clear();
-    d_bound_var_index.clear();
-    d_solved_asserts.clear();
-    //try to add an instantiation
-    if (constructInstantiation(sf, 0))
-    {
-      return true;
-    }
-  }
-  Trace("cbqi-engine") << "  WARNING : unable to find CEGQI single invocation instantiation." << std::endl;
-  return false;
-}
-
-void collectPresolveEqTerms( Node n, std::map< Node, std::vector< Node > >& teq ) {
-  if( n.getKind()==FORALL || n.getKind()==EXISTS ){
-    //do nothing
-  }else{
-    if( n.getKind()==EQUAL ){
-      for( unsigned i=0; i<2; i++ ){
-        std::map< Node, std::vector< Node > >::iterator it = teq.find( n[i] );
-        if( it!=teq.end() ){
-          Node nn = n[ i==0 ? 1 : 0 ];
-          if( std::find( it->second.begin(), it->second.end(), nn )==it->second.end() ){
-            it->second.push_back( nn );
-            Trace("cbqi-presolve") << "  - " << n[i] << " = " << nn << std::endl;
-          }
-        }
-      }
-    }
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      collectPresolveEqTerms( n[i], teq );
-    }
-  }
-}
-
-void getPresolveEqConjuncts( std::vector< Node >& vars, std::vector< Node >& terms,
-                             std::map< Node, std::vector< Node > >& teq, Node f, std::vector< Node >& conj ) {
-  if( conj.size()<1000 ){
-    if( terms.size()==f[0].getNumChildren() ){
-      Node c = f[1].substitute( vars.begin(), vars.end(), terms.begin(), terms.end() );
-      conj.push_back( c );
-    }else{
-      unsigned i = terms.size();
-      Node v = f[0][i];
-      terms.push_back( Node::null() );
-      for( unsigned j=0; j<teq[v].size(); j++ ){
-        terms[i] = teq[v][j];
-        getPresolveEqConjuncts( vars, terms, teq, f, conj );
-      }
-      terms.pop_back();
-    }
-  }
-}
-
-void CegInstantiator::presolve( Node q ) {
-  //at preregister time, add proxy of obvious instantiations up front, which helps learning during preprocessing
-  //only if no nested quantifiers
-  if( !QuantifiersRewriter::containsQuantifiers( q[1] ) ){
-    std::vector< Node > ps_vars;
-    std::map< Node, std::vector< Node > > teq;
-    for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
-      ps_vars.push_back( q[0][i] );
-      teq[q[0][i]].clear();
-    }
-    collectPresolveEqTerms( q[1], teq );
-    std::vector< Node > terms;
-    std::vector< Node > conj;
-    getPresolveEqConjuncts( ps_vars, terms, teq, q, conj );
-
-    if( !conj.empty() ){
-      Node lem = conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj );
-      Node g = NodeManager::currentNM()->mkSkolem( "g", NodeManager::currentNM()->booleanType() );
-      lem = NodeManager::currentNM()->mkNode( OR, g, lem );
-      Trace("cbqi-presolve-debug") << "Presolve lemma : " << lem << std::endl;
-      d_qe->getOutputChannel().lemma( lem, false, true );
-    }
-  }
-}
-
-void CegInstantiator::processAssertions() {
-  Trace("cbqi-proc") << "--- Process assertions, #var = " << d_vars.size() << ", #aux-var = " << d_aux_vars.size() << std::endl;
-  d_curr_asserts.clear();
-  d_curr_eqc.clear();
-  d_curr_type_eqc.clear();
-
-  // must use master equality engine to avoid value instantiations
-  eq::EqualityEngine* ee = d_qe->getMasterEqualityEngine();
-  //to eliminate identified illegal terms
-  std::map< Node, Node > aux_subs;
-
-  //for each variable
-  for( unsigned i=0; i<d_vars.size(); i++ ){
-    Node pv = d_vars[i];
-    TypeNode pvtn = pv.getType();
-    Trace("cbqi-proc-debug") << "Collect theory ids from type " << pvtn << " of " << pv << std::endl;
-    //collect information about eqc
-    if( ee->hasTerm( pv ) ){
-      Node pvr = ee->getRepresentative( pv );
-      if( d_curr_eqc.find( pvr )==d_curr_eqc.end() ){
-        Trace("cbqi-proc") << "Collect equivalence class " << pvr << std::endl;
-        eq::EqClassIterator eqc_i = eq::EqClassIterator( pvr, ee );
-        while( !eqc_i.isFinished() ){
-          d_curr_eqc[pvr].push_back( *eqc_i );
-          ++eqc_i;
-        }
-      }
-    }
-  }
-  //collect assertions for relevant theories
-  for( unsigned i=0; i<d_tids.size(); i++ ){
-    TheoryId tid = d_tids[i];
-    Theory* theory = d_qe->getTheoryEngine()->theoryOf( tid );
-    if( theory && d_qe->getTheoryEngine()->isTheoryEnabled(tid) ){
-      Trace("cbqi-proc") << "Collect assertions from theory " << tid << std::endl;
-      d_curr_asserts[tid].clear();
-      //collect all assertions from theory
-      for( context::CDList<Assertion>::const_iterator it = theory->facts_begin(); it != theory->facts_end(); ++ it) {
-        Node lit = (*it).assertion;
-        Node atom = lit.getKind()==NOT ? lit[0] : lit;
-        if( d_is_nested_quant || std::find( d_ce_atoms.begin(), d_ce_atoms.end(), atom )!=d_ce_atoms.end() ){
-          d_curr_asserts[tid].push_back( lit );
-          Trace("cbqi-proc-debug") << "...add : " << lit << std::endl;
-        }else{
-          Trace("cbqi-proc") << "...do not consider literal " << tid << " : " << lit << " since it is not part of CE body." << std::endl;
-        }
-        if( lit.getKind()==EQUAL ){
-          std::map< Node, std::map< Node, Node > >::iterator itae = d_aux_eq.find( lit );
-          if( itae!=d_aux_eq.end() ){
-            for( std::map< Node, Node >::iterator itae2 = itae->second.begin(); itae2 != itae->second.end(); ++itae2 ){
-              aux_subs[ itae2->first ] = itae2->second;
-              Trace("cbqi-proc") << "......add substitution : " << itae2->first << " -> " << itae2->second << std::endl;
-            }
-          }
-        }else if( atom.getKind()==BOOLEAN_TERM_VARIABLE ){
-          if( std::find( d_aux_vars.begin(), d_aux_vars.end(), atom )!=d_aux_vars.end() ){
-            Node val = NodeManager::currentNM()->mkConst( lit.getKind()!=NOT );
-            aux_subs[ atom ] = val;
-            Trace("cbqi-proc") << "......add substitution : " << atom << " -> " << val << std::endl;
-          }
-        }
-      }
-    }
-  }
-  //collect equivalence classes that correspond to relevant theories
-  Trace("cbqi-proc-debug") << "...collect typed equivalence classes" << std::endl;
-  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
-  while( !eqcs_i.isFinished() ){
-    Node r = *eqcs_i;
-    TypeNode rtn = r.getType();
-    TheoryId tid = Theory::theoryOf( rtn );
-    //if we care about the theory of this eqc
-    if( std::find( d_tids.begin(), d_tids.end(), tid )!=d_tids.end() ){
-      if( rtn.isInteger() || rtn.isReal() ){
-        rtn = rtn.getBaseType();
-      }
-      Trace("cbqi-proc-debug") << "...type eqc: " << r << std::endl;
-      d_curr_type_eqc[rtn].push_back( r );
-      if( d_curr_eqc.find( r )==d_curr_eqc.end() ){
-        Trace("cbqi-proc") << "Collect equivalence class " << r << std::endl;
-        Trace("cbqi-proc-debug") << "  ";
-        eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
-        while( !eqc_i.isFinished() ){
-          Trace("cbqi-proc-debug") << *eqc_i << " ";
-          d_curr_eqc[r].push_back( *eqc_i );
-          ++eqc_i;
-        }
-        Trace("cbqi-proc-debug") << std::endl;
-      }
-    }
-    ++eqcs_i;
-  }
-  //construct substitution from auxiliary variable equalities (if e.g. ITE removal was applied to CE body of quantified formula)
-  std::vector< Node > subs_lhs;
-  std::vector< Node > subs_rhs;
-  for( unsigned i=0; i<d_aux_vars.size(); i++ ){
-    Node r = d_aux_vars[i];
-    std::map< Node, Node >::iterator it = aux_subs.find( r );
-    if( it!=aux_subs.end() ){
-      addToAuxVarSubstitution( subs_lhs, subs_rhs, r, it->second );
-    }else{
-      Trace("cbqi-proc") << "....no substitution found for auxiliary variable " << r << "!!! type is " << r.getType() << std::endl;
-      Assert( false );
-    }
-  }
-
-  //apply substitutions to everything, if necessary
-  if( !subs_lhs.empty() ){
-    Trace("cbqi-proc") << "Applying substitution : " << std::endl;
-    for( unsigned i=0; i<subs_lhs.size(); i++ ){
-      Trace("cbqi-proc") << "  " << subs_lhs[i] << " -> " << subs_rhs[i] << std::endl;
-    }
-    for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){
-      for( unsigned i=0; i<it->second.size(); i++ ){
-        Node lit = it->second[i];
-        lit = lit.substitute( subs_lhs.begin(), subs_lhs.end(), subs_rhs.begin(), subs_rhs.end() );
-        lit = Rewriter::rewrite( lit );
-        it->second[i] = lit;
-      }
-    }
-    for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){
-      for( unsigned i=0; i<it->second.size(); i++ ){
-        Node n = it->second[i];
-        n = n.substitute( subs_lhs.begin(), subs_lhs.end(), subs_rhs.begin(), subs_rhs.end() );
-        n = Rewriter::rewrite( n  );
-        it->second[i] = n;
-      }
-    }
-  }
-
-  //remove unecessary assertions
-  for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){
-    std::vector< Node > akeep;
-    for( unsigned i=0; i<it->second.size(); i++ ){
-      Node n = it->second[i];
-      //must be an eligible term
-      if( isEligible( n ) ){
-        //must contain at least one variable
-        if( !d_prog_var[n].empty() ){
-          Trace("cbqi-proc") << "...literal[" << it->first << "] : " << n << std::endl;
-          akeep.push_back( n );
-        }else{
-          Trace("cbqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains no relevant variables." << std::endl;
-        }
-      }else{
-        Trace("cbqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains ineligible terms." << std::endl;
-      }
-    }
-    it->second.clear();
-    it->second.insert( it->second.end(), akeep.begin(), akeep.end() );
-  }
-
-  //remove duplicate terms from eqc
-  for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){
-    std::vector< Node > new_eqc;
-    for( unsigned i=0; i<it->second.size(); i++ ){
-      if( std::find( new_eqc.begin(), new_eqc.end(), it->second[i] )==new_eqc.end() ){
-        new_eqc.push_back( it->second[i] );
-      }
-    }
-    it->second.clear();
-    it->second.insert( it->second.end(), new_eqc.begin(), new_eqc.end() );
-  }
-}
-
-void CegInstantiator::addToAuxVarSubstitution( std::vector< Node >& subs_lhs, std::vector< Node >& subs_rhs, Node l, Node r ) {
-  r = r.substitute( subs_lhs.begin(), subs_lhs.end(), subs_rhs.begin(), subs_rhs.end() );
-
-  std::vector< Node > cl;
-  cl.push_back( l );
-  std::vector< Node > cr;
-  cr.push_back( r );
-  for( unsigned i=0; i<subs_lhs.size(); i++ ){
-    Node nr = subs_rhs[i].substitute( cl.begin(), cl.end(), cr.begin(), cr.end() );
-    nr = Rewriter::rewrite( nr );
-    subs_rhs[i] = nr;
-  }
-
-  subs_lhs.push_back( l );
-  subs_rhs.push_back( r );
-}
-
-Node CegInstantiator::getModelValue( Node n ) {
-  return d_qe->getModel()->getValue( n );
-}
-
-Node CegInstantiator::getBoundVariable(TypeNode tn)
-{
-  unsigned index = 0;
-  std::unordered_map<TypeNode, unsigned, TypeNodeHashFunction>::iterator itb =
-      d_bound_var_index.find(tn);
-  if (itb != d_bound_var_index.end())
-  {
-    index = itb->second;
-  }
-  d_bound_var_index[tn] = index + 1;
-  while (index >= d_bound_var[tn].size())
-  {
-    std::stringstream ss;
-    ss << "x" << index;
-    Node x = NodeManager::currentNM()->mkBoundVar(ss.str(), tn);
-    d_bound_var[tn].push_back(x);
-  }
-  return d_bound_var[tn][index];
-}
-
-bool CegInstantiator::isSolvedAssertion(Node n) const
-{
-  return d_solved_asserts.find(n) != d_solved_asserts.end();
-}
-
-void CegInstantiator::markSolved(Node n, bool solved)
-{
-  if (solved)
-  {
-    d_solved_asserts.insert(n);
-  }
-  else if (isSolvedAssertion(n))
-  {
-    d_solved_asserts.erase(n);
-  }
-}
-
-void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) {
-  if( n.getKind()==FORALL ){
-    d_is_nested_quant = true;
-  }else if( visited.find( n )==visited.end() ){
-    visited[n] = true;
-    if( TermUtil::isBoolConnectiveTerm( n ) ){
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        collectCeAtoms( n[i], visited );
-      }
-    }else{
-      if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){
-        Trace("cbqi-ce-atoms") << "CE atoms : " << n << std::endl;
-        d_ce_atoms.push_back( n );
-      }
-    }
-  }
-}
-
-void CegInstantiator::registerCounterexampleLemma( std::vector< Node >& lems, std::vector< Node >& ce_vars ) {
-  Trace("cbqi-reg") << "Register counterexample lemma..." << std::endl;
-  d_input_vars.clear();
-  d_input_vars.insert(d_input_vars.end(), ce_vars.begin(), ce_vars.end());
-
-  //Assert( d_vars.empty() );
-  d_vars.clear();
-  registerTheoryId(THEORY_UF);
-  for (unsigned i = 0; i < ce_vars.size(); i++)
-  {
-    Trace("cbqi-reg") << "  register input variable : " << ce_vars[i] << std::endl;
-    registerVariable(ce_vars[i]);
-  }
-
-  // preprocess with all relevant instantiator preprocessors
-  Trace("cbqi-debug") << "Preprocess based on theory-specific methods..."
-                      << std::endl;
-  std::vector<Node> pvars;
-  pvars.insert(pvars.end(), d_vars.begin(), d_vars.end());
-  for (std::pair<const TheoryId, InstantiatorPreprocess*>& p : d_tipp)
-  {
-    p.second->registerCounterexampleLemma(lems, pvars);
-  }
-  // must register variables generated by preprocessors
-  Trace("cbqi-debug") << "Register variables from theory-specific methods "
-                      << d_input_vars.size() << " " << pvars.size() << " ..."
-                      << std::endl;
-  for (unsigned i = d_input_vars.size(), size = pvars.size(); i < size; ++i)
-  {
-    Trace("cbqi-reg") << "  register theory preprocess variable : " << pvars[i]
-                      << std::endl;
-    registerVariable(pvars[i]);
-  }
-
-  //remove ITEs
-  IteSkolemMap iteSkolemMap;
-  d_qe->getTheoryEngine()->getTermFormulaRemover()->run(lems, iteSkolemMap);
-  //Assert( d_aux_vars.empty() );
-  d_aux_vars.clear();
-  d_aux_eq.clear();
-  for(IteSkolemMap::iterator i = iteSkolemMap.begin(); i != iteSkolemMap.end(); ++i) {
-    Trace("cbqi-reg") << "  register aux variable : " << i->first << std::endl;
-    registerVariable(i->first, true);
-  }
-  for( unsigned i=0; i<lems.size(); i++ ){
-    Trace("cbqi-debug") << "Counterexample lemma (pre-rewrite)  " << i << " : " << lems[i] << std::endl;
-    Node rlem = lems[i];
-    rlem = Rewriter::rewrite( rlem );
-    Trace("cbqi-debug") << "Counterexample lemma (post-rewrite) " << i << " : " << rlem << std::endl;
-    //record the literals that imply auxiliary variables to be equal to terms
-    if( lems[i].getKind()==ITE && rlem.getKind()==ITE ){
-      if( lems[i][1].getKind()==EQUAL && lems[i][2].getKind()==EQUAL && lems[i][1][0]==lems[i][2][0] ){
-        if( std::find( d_aux_vars.begin(), d_aux_vars.end(), lems[i][1][0] )!=d_aux_vars.end() ){
-          Node v = lems[i][1][0];
-          for( unsigned r=1; r<=2; r++ ){
-            d_aux_eq[rlem[r]][v] = lems[i][r][1];
-            Trace("cbqi-debug") << "  " << rlem[r] << " implies " << v << " = " << lems[i][r][1] << std::endl;
-          }
-        }
-      }
-    }
-    /*else if( lems[i].getKind()==EQUAL && lems[i][0].getType().isBoolean() ){
-      //Boolean terms
-      if( std::find( d_aux_vars.begin(), d_aux_vars.end(), lems[i][0] )!=d_aux_vars.end() ){
-        Node v = lems[i][0];
-        d_aux_eq[rlem][v] = lems[i][1];
-         Trace("cbqi-debug") << "  " << rlem << " implies " << v << " = " << lems[i][1] << std::endl;
-      }
-    }*/
-    lems[i] = rlem;
-  }
-
-  // determine variable order: must do Reals before Ints
-  Trace("cbqi-debug") << "Determine variable order..." << std::endl;
-  if (!d_vars.empty())
-  {
-    std::map<Node, unsigned> voo;
-    bool doSort = false;
-    std::vector<Node> vars;
-    std::map<TypeNode, std::vector<Node> > tvars;
-    for (unsigned i = 0, size = d_vars.size(); i < size; i++)
-    {
-      voo[d_vars[i]] = i;
-      d_var_order_index.push_back(0);
-      TypeNode tn = d_vars[i].getType();
-      if (tn.isInteger())
-      {
-        doSort = true;
-        tvars[tn].push_back(d_vars[i]);
-      }
-      else
-      {
-        vars.push_back(d_vars[i]);
-      }
-    }
-    if (doSort)
-    {
-      Trace("cbqi-debug") << "Sort variables based on ordering." << std::endl;
-      for (std::pair<const TypeNode, std::vector<Node> >& vs : tvars)
-      {
-        vars.insert(vars.end(), vs.second.begin(), vs.second.end());
-      }
-
-      Trace("cbqi-debug") << "Consider variables in this order : " << std::endl;
-      for (unsigned i = 0; i < vars.size(); i++)
-      {
-        d_var_order_index[voo[vars[i]]] = i;
-        Trace("cbqi-debug") << "  " << vars[i] << " : " << vars[i].getType()
-                            << ", index was : " << voo[vars[i]] << std::endl;
-        d_vars[i] = vars[i];
-      }
-      Trace("cbqi-debug") << std::endl;
-    }
-    else
-    {
-      d_var_order_index.clear();
-    }
-  }
-
-  //collect atoms from all lemmas: we will only do bounds coming from original body
-  d_is_nested_quant = false;
-  std::map< Node, bool > visited;
-  for( unsigned i=0; i<lems.size(); i++ ){
-    collectCeAtoms( lems[i], visited );
-  }
-}
-
-
-Instantiator::Instantiator( QuantifiersEngine * qe, TypeNode tn ) : d_type( tn ){
-  d_closed_enum_type = qe->getTermEnumeration()->isClosedEnumerableType(tn);
-}
-
-bool Instantiator::processEqualTerm(CegInstantiator* ci,
-                                    SolvedForm& sf,
-                                    Node pv,
-                                    TermProperties& pv_prop,
-                                    Node n,
-                                    CegInstEffort effort)
-{
-  pv_prop.d_type = 0;
-  return ci->constructInstantiationInc(pv, n, pv_prop, sf);
-}
-
-} /* CVC4::theory::quantifiers namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/ceg_instantiator.h b/src/theory/quantifiers/ceg_instantiator.h
deleted file mode 100644 (file)
index 03983fe..0000000
+++ /dev/null
@@ -1,783 +0,0 @@
-/*********************                                                        */
-/*! \file ceg_instantiator.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief counterexample-guided quantifier instantiation
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__CEG_INSTANTIATOR_H
-#define __CVC4__THEORY__QUANTIFIERS__CEG_INSTANTIATOR_H
-
-#include "theory/quantifiers_engine.h"
-#include "util/statistics_registry.h"
-
-namespace CVC4 {
-namespace theory {
-
-namespace arith {
-  class TheoryArith;
-}
-
-namespace quantifiers {
-
-class CegqiOutput {
-public:
-  virtual ~CegqiOutput() {}
-  virtual bool doAddInstantiation( std::vector< Node >& subs ) = 0;
-  virtual bool isEligibleForInstantiation( Node n ) = 0;
-  virtual bool addLemma( Node lem ) = 0;
-};
-
-class Instantiator;
-class InstantiatorPreprocess;
-
-/** Term Properties
- *
- * Stores properties for a variable to solve for in counterexample-guided
- * instantiation.
- *
- * For LIA, this includes the coefficient of the variable, and the bound type
- * for the variable.
- */
-class TermProperties {
-public:
-  TermProperties() : d_type(0) {}
-  virtual ~TermProperties() {}
-
-  // type of property for a term
-  //  for arithmetic this corresponds to bound type (0:equal, 1:upper bound, -1:lower bound)
-  int d_type;
-  // for arithmetic
-  Node d_coeff;
-  // get cache node
-  // we consider terms + TermProperties that are unique up to their cache node
-  // (see constructInstantiationInc)
-  virtual Node getCacheNode() const { return d_coeff; }
-  // is non-basic 
-  virtual bool isBasic() const { return d_coeff.isNull(); }
-  // get modified term 
-  virtual Node getModifiedTerm( Node pv ) const {
-    if( !d_coeff.isNull() ){
-      return NodeManager::currentNM()->mkNode( kind::MULT, d_coeff, pv );
-    }else{
-      return pv;
-    }
-  }
-  // compose property, should be such that: 
-  //   p.getModifiedTerm( this.getModifiedTerm( x ) ) = this_updated.getModifiedTerm( x )
-  virtual void composeProperty( TermProperties& p ){
-    if( !p.d_coeff.isNull() ){
-      if( d_coeff.isNull() ){
-        d_coeff = p.d_coeff;
-      }else{
-        d_coeff = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::MULT, d_coeff, p.d_coeff ) );
-      }
-    }
-  }
-};
-
-/** Solved form
- *  This specifies a substitution:
- *  { d_props[i].getModifiedTerm(d_vars[i]) -> d_subs[i] | i = 0...|d_vars| }
- */
-class SolvedForm {
-public:
-  // list of variables
-  std::vector< Node > d_vars;
-  // list of terms that they are substituted to
-  std::vector< Node > d_subs;
-  // properties for each variable
-  std::vector< TermProperties > d_props;
-  // the variables that have non-basic information regarding how they are substituted
-  //   an example is for linear arithmetic, we store "substitution with coefficients".
-  std::vector<Node> d_non_basic;
-  // push the substitution pv_prop.getModifiedTerm(pv) -> n
-  void push_back( Node pv, Node n, TermProperties& pv_prop ){
-    d_vars.push_back( pv );
-    d_subs.push_back( n );
-    d_props.push_back( pv_prop );
-    if( !pv_prop.isBasic() ){
-      d_non_basic.push_back( pv );
-      // update theta value
-      Node new_theta = getTheta();
-      if( new_theta.isNull() ){
-        new_theta = pv_prop.d_coeff;
-      }else{
-        new_theta = NodeManager::currentNM()->mkNode( kind::MULT, new_theta, pv_prop.d_coeff );
-        new_theta = Rewriter::rewrite( new_theta );
-      }
-      d_theta.push_back( new_theta );
-    }
-  }
-  // pop the substitution pv_prop.getModifiedTerm(pv) -> n
-  void pop_back( Node pv, Node n, TermProperties& pv_prop ){
-    d_vars.pop_back();
-    d_subs.pop_back();
-    d_props.pop_back();
-    if( !pv_prop.isBasic() ){
-      d_non_basic.pop_back();
-      // update theta value
-      d_theta.pop_back();
-    }
-  }
-  // is this solved form empty?
-  bool empty() { return d_vars.empty(); }
-public:
-  // theta values (for LIA, see Section 4 of Reynolds/King/Kuncak FMSD 2017)
-  std::vector< Node > d_theta;
-  // get the current value for theta (for LIA, see Section 4 of Reynolds/King/Kuncak FMSD 2017)
-  Node getTheta() {
-    if( d_theta.empty() ){
-      return Node::null();
-    }else{
-      return d_theta[d_theta.size()-1];
-    }
-  }
-};
-
-/** instantiation effort levels
- *
- * This effort is used to stratify the construction of
- * instantiations for some theories that may result to
- * using model value instantiations.
- */
-enum CegInstEffort
-{
-  // uninitialized
-  CEG_INST_EFFORT_NONE,
-  // standard effort level
-  CEG_INST_EFFORT_STANDARD,
-  // standard effort level, but we have used model values
-  CEG_INST_EFFORT_STANDARD_MV,
-  // full effort level
-  CEG_INST_EFFORT_FULL
-};
-
-std::ostream& operator<<(std::ostream& os, CegInstEffort e);
-
-/** instantiation phase for variables
- *
- * This indicates the phase in which we constructed
- * a substitution for individual variables.
- */
-enum CegInstPhase
-{
-  // uninitialized
-  CEG_INST_PHASE_NONE,
-  // instantiation constructed during traversal of equivalence classes
-  CEG_INST_PHASE_EQC,
-  // instantiation constructed during solving equalities
-  CEG_INST_PHASE_EQUAL,
-  // instantiation constructed by looking at theory assertions
-  CEG_INST_PHASE_ASSERTION,
-  // instantiation constructed by querying model value
-  CEG_INST_PHASE_MVALUE,
-};
-
-std::ostream& operator<<(std::ostream& os, CegInstPhase phase);
-
-/** Ceg instantiator
- *
- * This class manages counterexample-guided quantifier instantiation
- * for a single quantified formula.
- *
- * For details on counterexample-guided quantifier instantiation
- * (for linear arithmetic), see Reynolds/King/Kuncak FMSD 2017.
- */
-class CegInstantiator {
- public:
-  CegInstantiator(QuantifiersEngine* qe,
-                  CegqiOutput* out,
-                  bool use_vts_delta = true,
-                  bool use_vts_inf = true);
-  virtual ~CegInstantiator();
-  /** check
-   * This adds instantiations based on the state of d_vars in current context
-   * on the output channel d_out of this class.
-   */
-  bool check();
-  /** presolve for quantified formula
-   *
-   * This initializes formulas that help static learning of the quantifier-free
-   * solver. It is only called if the option --cbqi-prereg-inst is used.
-   */
-  void presolve(Node q);
-  /** Register the counterexample lemma
-   *
-   * lems : contains the conjuncts of the counterexample lemma of the
-   *        quantified formula we are processing. The counterexample
-   *        lemma is the formula { ~phi[e/x] } in Figure 1 of Reynolds
-   *        et al. FMSD 2017.
-   * ce_vars : contains the variables e. Notice these are variables of
-   *           INST_CONSTANT kind, since we do not permit bound
-   *           variables in assertions.
-   *
-   * This method may modify the set of lemmas lems based on:
-   * - ITE removal,
-   * - Theory-specific preprocessing of instantiation lemmas.
-   * It may also introduce new variables to ce_vars if necessary.
-   */
-  void registerCounterexampleLemma(std::vector<Node>& lems,
-                                   std::vector<Node>& ce_vars);
-  /** get the output channel of this class */
-  CegqiOutput* getOutput() { return d_out; }
-  //------------------------------interface for instantiators
-  /** get quantifiers engine */
-  QuantifiersEngine* getQuantifiersEngine() { return d_qe; }
-  /** push stack variable
-   * This adds a new variable to solve for in the stack
-   * of variables we are processing. This stack is only
-   * used for datatypes, where e.g. the DtInstantiator
-   * solving for a list x may push the stack "variables"
-   * head(x) and tail(x).
-   */
-  void pushStackVariable(Node v);
-  /** pop stack variable */
-  void popStackVariable();
-  /** construct instantiation increment
-   *
-   * Adds the substitution { pv_prop.getModifiedTerm(pv) -> n } to the current
-   * instantiation, specified by sf.
-   *
-   * This function returns true if a call to
-   * QuantifiersEngine::addInstantiation(...)
-   * was successfully made in a recursive call.
-   *
-   * The solved form sf is reverted to its original state if
-   *   this function returns false, or
-   *   revertOnSuccess is true and this function returns true.
-   */
-  bool constructInstantiationInc(Node pv,
-                                 Node n,
-                                 TermProperties& pv_prop,
-                                 SolvedForm& sf,
-                                 bool revertOnSuccess = false);
-  /** get the current model value of term n */
-  Node getModelValue(Node n);
-  /** get bound variable for type
-   *
-   * This gets the next (canonical) bound variable of
-   * type tn. This can be used for instance when
-   * constructing instantiations that involve choice expressions.
-   */
-  Node getBoundVariable(TypeNode tn);
-  /** has this assertion been marked as solved? */
-  bool isSolvedAssertion(Node n) const;
-  /** marked solved */
-  void markSolved(Node n, bool solved = true);
-  //------------------------------end interface for instantiators
-
-  /**
-   * Get the number of atoms in the counterexample lemma of the quantified
-   * formula we are processing with this class.
-   */
-  unsigned getNumCEAtoms() { return d_ce_atoms.size(); }
-  /**
-   * Get the i^th atom of the counterexample lemma of the quantified
-   * formula we are processing with this class.
-   */
-  Node getCEAtom(unsigned i) { return d_ce_atoms[i]; }
-  /** is n a term that is eligible for instantiation? */
-  bool isEligible(Node n);
-  /** does n have variable pv? */
-  bool hasVariable(Node n, Node pv);
-  /** are we using delta for LRA virtual term substitution? */
-  bool useVtsDelta() { return d_use_vts_delta; }
-  /** are we using infinity for LRA virtual term substitution? */
-  bool useVtsInfinity() { return d_use_vts_inf; }
-  /** are we processing a nested quantified formula? */
-  bool hasNestedQuantification() { return d_is_nested_quant; }
- private:
-  /** quantified formula associated with this instantiator */
-  QuantifiersEngine* d_qe;
-  /** output channel of this instantiator */
-  CegqiOutput* d_out;
-  /** whether we are using delta for virtual term substitution
-    * (for quantified LRA).
-    */
-  bool d_use_vts_delta;
-  /** whether we are using infinity for virtual term substitution
-    * (for quantified LRA).
-    */
-  bool d_use_vts_inf;
-
-  //-------------------------------globally cached
-  /** cache from nodes to the set of variables it contains
-    * (from the quantified formula we are instantiating).
-    */
-  std::unordered_map<Node,
-                     std::unordered_set<Node, NodeHashFunction>,
-                     NodeHashFunction>
-      d_prog_var;
-  /** cache of the set of terms that we have established are
-   * ineligible for instantiation.
-    */
-  std::unordered_set<Node, NodeHashFunction> d_inelig;
-  /** ensures n is in d_prog_var and d_inelig. */
-  void computeProgVars(Node n);
-  //-------------------------------end globally cached
-
-  //-------------------------------cached per round
-  /** current assertions per theory */
-  std::map<TheoryId, std::vector<Node> > d_curr_asserts;
-  /** map from representatives to the terms in their equivalence class */
-  std::map<Node, std::vector<Node> > d_curr_eqc;
-  /** map from types to representatives of that type */
-  std::map<TypeNode, std::vector<Node> > d_curr_type_eqc;
-  /** solved asserts */
-  std::unordered_set<Node, NodeHashFunction> d_solved_asserts;
-  /** process assertions
-   * This is called once at the beginning of check to
-   * set up all necessary information for constructing instantiations,
-   * such as the above data structures.
-   */
-  void processAssertions();
-  /** add to auxiliary variable substitution
-   * This adds the substitution l -> r to the auxiliary
-   * variable substitution subs_lhs -> subs_rhs, and serializes
-   * it (applies it to existing substitutions).
-   */
-  void addToAuxVarSubstitution(std::vector<Node>& subs_lhs,
-                               std::vector<Node>& subs_rhs,
-                               Node l,
-                               Node r);
-  /** cache bound variables for type returned
-   * by getBoundVariable(...).
-   */
-  std::unordered_map<TypeNode, std::vector<Node>, TypeNodeHashFunction>
-      d_bound_var;
-  /** current index of bound variables for type.
-   * The next call to getBoundVariable(...) for
-   * type tn returns the d_bound_var_index[tn]^th
-   * element of d_bound_var[tn], or a fresh variable
-   * if not in bounds.
-   */
-  std::unordered_map<TypeNode, unsigned, TypeNodeHashFunction>
-      d_bound_var_index;
-  //-------------------------------end cached per round
-
-  //-------------------------------data per theory
-  /** relevant theory ids
-   * A list of theory ids that contain at least one
-   * constraint in the body of the quantified formula we
-   * are processing.
-   */
-  std::vector<TheoryId> d_tids;
-  /** map from theory ids to instantiator preprocessors */
-  std::map<TheoryId, InstantiatorPreprocess*> d_tipp;
-  /** registers all theory ids associated with type tn
-   *
-   * This recursively calls registerTheoryId for typeOf(tn') for
-   * all parameters and datatype subfields of type tn.
-   * visited stores the types we have already visited.
-   */
-  void registerTheoryIds(TypeNode tn, std::map<TypeNode, bool>& visited);
-  /** register theory id tid
-   *
-   * This is called when the quantified formula we are processing
-   * with this class involves theory tid. In this case, we will
-   * construct instantiations based on the assertion list of this theory.
-   */
-  void registerTheoryId(TheoryId tid);
-  //-------------------------------end data per theory
-
-  //-------------------------------the variables
-  /** the variables we are instantiating
-   *
-   * This is a superset of the variables for the instantiations we are
-   * generating and sending on the output channel of this class.
-   */
-  std::vector<Node> d_vars;
-  /** set form of d_vars */
-  std::unordered_set<Node, NodeHashFunction> d_vars_set;
-  /** index of variables reported in instantiation */
-  std::vector<unsigned> d_var_order_index;
-  /** number of input variables
-   *
-   * These are the variables, in order, for the instantiations we are generating
-   * and sending on the output channel of this class.
-   */
-  std::vector<Node> d_input_vars;
-  /** literals to equalities for aux vars
-   * This stores entries of the form
-   *   L -> ( k -> t )
-   * where
-   *   k is a variable in d_aux_vars,
-   *   L is a literal that if asserted implies that our
-   *    instantiation should map { k -> t }.
-   * For example, if a term of the form
-   *   ite( C, t1, t2 )
-   * was replaced by k, we get this (top-level) assertion:
-   *   ite( C, k=t1, k=t2 )
-   * The vector d_aux_eq contains the exact form of
-   * the literals in the above constraint that they would
-   * appear in assertions, meaning d_aux_eq may contain:
-   *   t1=k -> ( k -> t1 )
-   *   t2=k -> ( k -> t2 )
-   * where t1=k and t2=k are the rewritten form of
-   * k=t1 and k=t2 respectively.
-   */
-  std::map<Node, std::map<Node, Node> > d_aux_eq;
-  /** auxiliary variables
-   * These variables include the result of removing ITE
-   * terms from the quantified formula we are processing.
-   * These variables must be eliminated from constraints
-   * as a preprocess step to check().
-   */
-  std::vector<Node> d_aux_vars;
-  /** register variable */
-  void registerVariable(Node v, bool is_aux = false);
-  //-------------------------------the variables
-
-  //-------------------------------quantified formula info
-  /** are we processing a nested quantified formula? */
-  bool d_is_nested_quant;
-  /** the atoms of the CE lemma */
-  std::vector<Node> d_ce_atoms;
-  /** collect atoms */
-  void collectCeAtoms(Node n, std::map<Node, bool>& visited);
-  //-------------------------------end quantified formula info
-
-  //-------------------------------current state
-  /** the current effort level of the instantiator
-   * This indicates the effort Instantiator objects
-   * will put into the terms they return.
-   */
-  CegInstEffort d_effort;
-  /** for each variable, the instantiator used for that variable */
-  std::map<Node, Instantiator*> d_active_instantiators;
-  /** map from variables to the index in the prefix of the quantified
-   * formula we are processing.
-   */
-  std::map<Node, unsigned> d_curr_index;
-  /** map from variables to the phase in which we instantiated them */
-  std::map<Node, CegInstPhase> d_curr_iphase;
-  /** cache of current substitutions tried between activate/deactivate */
-  std::map<Node, std::map<Node, std::map<Node, bool> > > d_curr_subs_proc;
-  /** stack of temporary variables we are solving for,
-   * e.g. subfields of datatypes.
-   */
-  std::vector<Node> d_stack_vars;
-  /** activate instantiation variable v at index
-   *
-   * This is called when variable (inst constant) v is activated
-   * for the quantified formula we are processing.
-   * This method initializes the instantiator class for
-   * that variable if necessary, where this class is
-   * determined by the type of v. It also initializes
-   * the cache of values we have tried substituting for v
-   * (in d_curr_subs_proc), and stores its index.
-   */
-  void activateInstantiationVariable(Node v, unsigned index);
-  /** deactivate instantiation variable
-   *
-   * This is called when variable (inst constant) v is deactivated
-   * for the quantified formula we are processing.
-   */
-  void deactivateInstantiationVariable(Node v);
-  //-------------------------------end current state
-
-  //---------------------------------for applying substitutions
-  /** can use basic substitution */
-  bool canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic );
-  /** apply substitution
-  * We wish to process the substitution: 
-  *   ( pv = n * sf )
-  * where pv is a variable with type tn, and * denotes application of substitution.
-  * The return value "ret" and pv_prop is such that the above equality is equivalent to
-  *   ( pv_prop.getModifiedTerm(pv) = ret )
-  */
-  Node applySubstitution( TypeNode tn, Node n, SolvedForm& sf, TermProperties& pv_prop, bool try_coeff = true ) {
-    return applySubstitution( tn, n, sf.d_vars, sf.d_subs, sf.d_props, sf.d_non_basic, pv_prop, try_coeff );
-  }
-  /** apply substitution, with solved form expanded to subs/prop/non_basic/vars */
-  Node applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, 
-                          std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff = true );
-  /** apply substitution to literal lit 
-  * The return value is equivalent to ( lit * sf )
-  * where * denotes application of substitution.
-  */
-  Node applySubstitutionToLiteral( Node lit, SolvedForm& sf ) {
-    return applySubstitutionToLiteral( lit, sf.d_vars, sf.d_subs, sf.d_props, sf.d_non_basic );
-  }
-  /** apply substitution to literal lit, with solved form expanded to subs/prop/non_basic/vars */
-  Node applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, 
-                                   std::vector< Node >& non_basic );
-  //---------------------------------end for applying substitutions
-
-  /** map from variables to their instantiators */
-  std::map<Node, Instantiator*> d_instantiator;
-
-  /** construct instantiation
-   * This method constructs the current instantiation, where we
-   * are currently processing the i^th variable in d_vars.
-   * It returns true if a successful call to the output channel's
-   * doAddInstantiation was made.
-   */
-  bool constructInstantiation(SolvedForm& sf, unsigned i);
-  /** do add instantiation
-   * This method is called by the above function after we finalize the
-   * variables/substitution and auxiliary lemmas.
-   * It returns true if a successful call to the output channel's
-   * doAddInstantiation was made.
-   */
-  bool doAddInstantiation(std::vector<Node>& vars,
-                          std::vector<Node>& subs,
-                          std::vector<Node>& lemmas);
-};
-
-/** Instantiator class
- *
- * This is a virtual class that is used for methods for constructing
- * substitutions for individual variables in counterexample-guided
- * instantiation techniques.
- *
- * This class contains a set of interface functions below, which are called
- * based on a fixed instantiation method implemented by CegInstantiator.
- * In these calls, the Instantiator in turn makes calls to methods in
- * CegInstanatior (primarily constructInstantiationInc).
- */
-class Instantiator {
-public:
-  Instantiator( QuantifiersEngine * qe, TypeNode tn );
-  virtual ~Instantiator(){}
-  /** reset
-   * This is called once, prior to any of the below methods are called.
-   * This function sets up any initial information necessary for constructing
-   * instantiations for pv based on the current context.
-   */
-  virtual void reset(CegInstantiator* ci,
-                     SolvedForm& sf,
-                     Node pv,
-                     CegInstEffort effort)
-  {
-  }
-
-  /** process equal term
-   *
-   * This method is called when the entailment:
-   *   E |= pv_prop.getModifiedTerm(pv) = n
-   * holds in the current context E, and n is eligible for instantiation.
-   *
-   * Returns true if an instantiation was successfully added via a call to
-   * CegInstantiator::constructInstantiationInc.
-   */
-  virtual bool processEqualTerm(CegInstantiator* ci,
-                                SolvedForm& sf,
-                                Node pv,
-                                TermProperties& pv_prop,
-                                Node n,
-                                CegInstEffort effort);
-  /** process equal terms
-   *
-   * This method is called after process equal term, where eqc is the list of
-   * eligible terms in the equivalence class of pv.
-   *
-   * Returns true if an instantiation was successfully added via a call to
-   * CegInstantiator::constructInstantiationInc.
-   */
-  virtual bool processEqualTerms(CegInstantiator* ci,
-                                 SolvedForm& sf,
-                                 Node pv,
-                                 std::vector<Node>& eqc,
-                                 CegInstEffort effort)
-  {
-    return false;
-  }
-
-  /** whether the instantiator implements processEquality */
-  virtual bool hasProcessEquality(CegInstantiator* ci,
-                                  SolvedForm& sf,
-                                  Node pv,
-                                  CegInstEffort effort)
-  {
-    return false;
-  }
-  /** process equality
-   *  The input is such that term_props.size() = terms.size() = 2
-   *  This method is called when the entailment:
-   *    E ^ term_props[0].getModifiedTerm(x0) =
-   *    terms[0] ^ term_props[1].getModifiedTerm(x1) = terms[1] |= x0 = x1
-   *  holds in current context E for fresh variables xi, terms[i] are eligible,
-   *  and at least one terms[i] contains pv for i = 0,1.
-   *  Notice in the basic case, E |= terms[0] = terms[1].
-   *
-   *  Returns true if an instantiation was successfully added via a call to
-   *  CegInstantiator::constructInstantiationInc.
-   */
-  virtual bool processEquality(CegInstantiator* ci,
-                               SolvedForm& sf,
-                               Node pv,
-                               std::vector<TermProperties>& term_props,
-                               std::vector<Node>& terms,
-                               CegInstEffort effort)
-  {
-    return false;
-  }
-
-  /** whether the instantiator implements processAssertion for any literal */
-  virtual bool hasProcessAssertion(CegInstantiator* ci,
-                                   SolvedForm& sf,
-                                   Node pv,
-                                   CegInstEffort effort)
-  {
-    return false;
-  }
-  /** has process assertion
-  *
-  * This method is called when the entailment:
-  *   E |= lit
-  * holds in current context E. Typically, lit belongs to the list of current
-  * assertions.
-  *
-  * This method is used to determine whether the instantiator implements
-  * processAssertion for literal lit.
-  *   If this method returns null, then this intantiator does not handle the
-  *   literal lit. Otherwise, this method returns a literal lit' such that:
-  *   (1) lit' is true in the current model,
-  *   (2) lit' implies lit.
-  *   where typically lit' = lit.
-  */
-  virtual Node hasProcessAssertion(CegInstantiator* ci,
-                                   SolvedForm& sf,
-                                   Node pv,
-                                   Node lit,
-                                   CegInstEffort effort)
-  {
-    return Node::null();
-  }
-  /** process assertion
-   * This method processes the assertion slit for variable pv.
-   * lit : the substituted form (under sf) of a literal returned by
-   *       hasProcessAssertion
-   * alit : the asserted literal, given as input to hasProcessAssertion
-   *
-   *  Returns true if an instantiation was successfully added via a call to
-   *  CegInstantiator::constructInstantiationInc.
-   */
-  virtual bool processAssertion(CegInstantiator* ci,
-                                SolvedForm& sf,
-                                Node pv,
-                                Node lit,
-                                Node alit,
-                                CegInstEffort effort)
-  {
-    return false;
-  }
-  /** process assertions
-   *
-   * Called after processAssertion is called for each literal asserted to the
-   * instantiator.
-   *
-   * Returns true if an instantiation was successfully added via a call to
-   * CegInstantiator::constructInstantiationInc.
-   */
-  virtual bool processAssertions(CegInstantiator* ci,
-                                 SolvedForm& sf,
-                                 Node pv,
-                                 CegInstEffort effort)
-  {
-    return false;
-  }
-
-  /** do we use the model value as instantiation for pv?
-   * This method returns true if we use model value instantiations
-   * at the same effort level as those determined by this instantiator.
-   */
-  virtual bool useModelValue(CegInstantiator* ci,
-                             SolvedForm& sf,
-                             Node pv,
-                             CegInstEffort effort)
-  {
-    return effort > CEG_INST_EFFORT_STANDARD;
-  }
-  /** do we allow the model value as instantiation for pv? */
-  virtual bool allowModelValue(CegInstantiator* ci,
-                               SolvedForm& sf,
-                               Node pv,
-                               CegInstEffort effort)
-  {
-    return d_closed_enum_type;
-  }
-
-  /** do we need to postprocess the solved form for pv? */
-  virtual bool needsPostProcessInstantiationForVariable(CegInstantiator* ci,
-                                                        SolvedForm& sf,
-                                                        Node pv,
-                                                        CegInstEffort effort)
-  {
-    return false;
-  }
-  /** postprocess the solved form for pv
-   *
-   * This method returns true if we successfully postprocessed the solved form.
-   * lemmas is a set of lemmas we wish to return along with the instantiation.
-   */
-  virtual bool postProcessInstantiationForVariable(CegInstantiator* ci,
-                                                   SolvedForm& sf,
-                                                   Node pv,
-                                                   CegInstEffort effort,
-                                                   std::vector<Node>& lemmas)
-  {
-    return true;
-  }
-
-  /** Identify this module (for debugging) */
-  virtual std::string identify() const { return "Default"; }
- protected:
-  /** the type of the variable we are instantiating */
-  TypeNode d_type;
-  /** whether d_type is a closed enumerable type */
-  bool d_closed_enum_type;
-};
-
-class ModelValueInstantiator : public Instantiator {
-public:
-  ModelValueInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){}
-  virtual ~ModelValueInstantiator(){}
-  bool useModelValue(CegInstantiator* ci,
-                     SolvedForm& sf,
-                     Node pv,
-                     CegInstEffort effort)
-  {
-    return true;
-  }
-  std::string identify() const { return "ModelValue"; }
-};
-
-/** instantiator preprocess
- *
- * This class implements techniques for preprocessing the counterexample lemma
- * generated for counterexample-guided quantifier instantiation.
- */
-class InstantiatorPreprocess
-{
- public:
-  InstantiatorPreprocess() {}
-  virtual ~InstantiatorPreprocess() {}
-  /** register counterexample lemma
-   * This implements theory-specific preprocessing and registration
-   * of counterexample lemmas, with the same contract as
-   * CegInstantiation::registerCounterexampleLemma.
-   */
-  virtual void registerCounterexampleLemma(std::vector<Node>& lems,
-                                           std::vector<Node>& ce_vars)
-  {
-  }
-};
-
-} /* CVC4::theory::quantifiers namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
-
-#endif
diff --git a/src/theory/quantifiers/ceg_t_instantiator.cpp b/src/theory/quantifiers/ceg_t_instantiator.cpp
deleted file mode 100644 (file)
index e617819..0000000
+++ /dev/null
@@ -1,1990 +0,0 @@
-/*********************                                                        */
-/*! \file ceg_t_instantiator.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of theory-specific counterexample-guided quantifier instantiation
- **/
-
-#include "theory/quantifiers/ceg_t_instantiator.h"
-
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/quantifiers_rewriter.h"
-#include "theory/quantifiers/trigger.h"
-
-#include "theory/arith/arith_msum.h"
-#include "theory/arith/partial_model.h"
-#include "theory/arith/theory_arith.h"
-#include "theory/arith/theory_arith_private.h"
-#include "theory/bv/theory_bv_utils.h"
-#include "util/bitvector.h"
-#include "util/random.h"
-
-#include <algorithm>
-#include <stack>
-
-using namespace std;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-struct BvLinearAttributeId {};
-using BvLinearAttribute = expr::Attribute<BvLinearAttributeId, bool>;
-
-Node ArithInstantiator::getModelBasedProjectionValue( CegInstantiator * ci, Node e, Node t, bool isLower, Node c, Node me, Node mt, Node theta, Node inf_coeff, Node delta_coeff ) {
-  Node val = t;
-  Trace("cegqi-arith-bound2") << "Value : " << val << std::endl;
-  Assert( !e.getType().isInteger() || t.getType().isInteger() );
-  Assert( !e.getType().isInteger() || mt.getType().isInteger() );
-  //add rho value
-  //get the value of c*e
-  Node ceValue = me;
-  Node new_theta = theta;
-  if( !c.isNull() ){
-    Assert( c.getType().isInteger() );
-    ceValue = NodeManager::currentNM()->mkNode( MULT, ceValue, c );
-    ceValue = Rewriter::rewrite( ceValue );
-    if( new_theta.isNull() ){
-      new_theta = c;
-    }else{
-      new_theta = NodeManager::currentNM()->mkNode( MULT, new_theta, c );
-      new_theta = Rewriter::rewrite( new_theta );
-    }
-    Trace("cegqi-arith-bound2") << "...c*e = " << ceValue << std::endl;
-    Trace("cegqi-arith-bound2") << "...theta = " << new_theta << std::endl;
-  }
-  if( !new_theta.isNull() && e.getType().isInteger() ){
-    Node rho;
-    //if( !mt.getType().isInteger() ){
-      //round up/down
-      //mt = NodeManager::currentNM()->mkNode(
-    //}
-    if( isLower ){
-      rho = NodeManager::currentNM()->mkNode( MINUS, ceValue, mt );
-    }else{
-      rho = NodeManager::currentNM()->mkNode( MINUS, mt, ceValue );
-    }
-    rho = Rewriter::rewrite( rho );
-    Trace("cegqi-arith-bound2") << "...rho = " << me << " - " << mt << " = " << rho << std::endl;
-    Trace("cegqi-arith-bound2") << "..." << rho << " mod " << new_theta << " = ";
-    rho = NodeManager::currentNM()->mkNode( INTS_MODULUS_TOTAL, rho, new_theta );
-    rho = Rewriter::rewrite( rho );
-    Trace("cegqi-arith-bound2") << rho << std::endl;
-    Kind rk = isLower ? PLUS : MINUS;
-    val = NodeManager::currentNM()->mkNode( rk, val, rho );
-    val = Rewriter::rewrite( val );
-    Trace("cegqi-arith-bound2") << "(after rho) : " << val << std::endl;
-  }
-  if( !inf_coeff.isNull() ){
-    Assert( !d_vts_sym[0].isNull() );
-    val = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkNode( MULT, inf_coeff, d_vts_sym[0] ) );
-    val = Rewriter::rewrite( val );
-  }
-  if( !delta_coeff.isNull() ){
-    //create delta here if necessary
-    val = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkNode( MULT, delta_coeff, ci->getQuantifiersEngine()->getTermUtil()->getVtsDelta() ) );
-    val = Rewriter::rewrite( val );
-  }
-  return val;
-}
-
-//this isolates the atom into solved form
-//     veq_c * pv <> val + vts_coeff_delta * delta + vts_coeff_inf * inf
-//  ensures val is Int if pv is Int, and val does not contain vts symbols
-int ArithInstantiator::solve_arith( CegInstantiator * ci, Node pv, Node atom, Node& veq_c, Node& val, Node& vts_coeff_inf, Node& vts_coeff_delta ) {
-  int ires = 0;
-  Trace("cegqi-arith-debug") << "isolate for " << pv << " in " << atom << std::endl;
-  std::map< Node, Node > msum;
-  if (ArithMSum::getMonomialSumLit(atom, msum))
-  {
-    Trace("cegqi-arith-debug") << "got monomial sum: " << std::endl;
-    if( Trace.isOn("cegqi-arith-debug") ){
-      ArithMSum::debugPrintMonomialSum(msum, "cegqi-arith-debug");
-    }
-    TypeNode pvtn = pv.getType();
-    //remove vts symbols from polynomial
-    Node vts_coeff[2];
-    for( unsigned t=0; t<2; t++ ){
-      if( !d_vts_sym[t].isNull() ){
-        std::map< Node, Node >::iterator itminf = msum.find( d_vts_sym[t] );
-        if( itminf!=msum.end() ){
-          vts_coeff[t] = itminf->second;
-          if( vts_coeff[t].isNull() ){
-            vts_coeff[t] = NodeManager::currentNM()->mkConst( Rational( 1 ) );
-          }
-          //negate if coefficient on variable is positive
-          std::map< Node, Node >::iterator itv = msum.find( pv );
-          if( itv!=msum.end() ){
-            //multiply by the coefficient we will isolate for
-            if( itv->second.isNull() ){
-              vts_coeff[t] = ArithMSum::negate(vts_coeff[t]);
-            }else{
-              if( !pvtn.isInteger() ){
-                vts_coeff[t] = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(-1) / itv->second.getConst<Rational>() ), vts_coeff[t] );
-                vts_coeff[t] = Rewriter::rewrite( vts_coeff[t] );
-              }else if( itv->second.getConst<Rational>().sgn()==1 ){
-                vts_coeff[t] = ArithMSum::negate(vts_coeff[t]);
-              }
-            }
-          }
-          Trace("cegqi-arith-debug") << "vts[" << t << "] coefficient is " << vts_coeff[t] << std::endl;
-          msum.erase( d_vts_sym[t] );
-        }
-      }
-    }
-
-    ires = ArithMSum::isolate(pv, msum, veq_c, val, atom.getKind());
-    if( ires!=0 ){
-      Node realPart;
-      if( Trace.isOn("cegqi-arith-debug") ){
-        Trace("cegqi-arith-debug") << "Isolate : ";
-        if( !veq_c.isNull() ){
-          Trace("cegqi-arith-debug") << veq_c << " * ";
-        }
-        Trace("cegqi-arith-debug") << pv << " " << atom.getKind() << " " << val << std::endl;
-      }
-      if( options::cbqiAll() ){
-        // when not pure LIA/LRA, we must check whether the lhs contains pv
-        if( TermUtil::containsTerm( val, pv ) ){
-          Trace("cegqi-arith-debug") << "fail : contains bad term" << std::endl;
-          return 0;
-        }
-      }
-      if( pvtn.isInteger() && ( ( !veq_c.isNull() && !veq_c.getType().isInteger() ) || !val.getType().isInteger() ) ){
-        //redo, split integer/non-integer parts
-        bool useCoeff = false;
-        Integer coeff = ci->getQuantifiersEngine()->getTermUtil()->d_one.getConst<Rational>().getNumerator();
-        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
-          if( it->first.isNull() || it->first.getType().isInteger() ){
-            if( !it->second.isNull() ){
-              coeff = coeff.lcm( it->second.getConst<Rational>().getDenominator() );
-              useCoeff = true;
-            }
-          }
-        }
-        //multiply everything by this coefficient
-        Node rcoeff = NodeManager::currentNM()->mkConst( Rational( coeff ) );
-        std::vector< Node > real_part;
-        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
-          if( useCoeff ){
-            if( it->second.isNull() ){
-              msum[it->first] = rcoeff;
-            }else{
-              msum[it->first] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, it->second, rcoeff ) );
-            }
-          }
-          if( !it->first.isNull() && !it->first.getType().isInteger() ){
-            real_part.push_back( msum[it->first].isNull() ? it->first : NodeManager::currentNM()->mkNode( MULT, msum[it->first], it->first ) );
-          }
-        }
-        //remove delta  TODO: check this
-        vts_coeff[1] = Node::null();
-        //multiply inf
-        if( !vts_coeff[0].isNull() ){
-          vts_coeff[0] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, rcoeff, vts_coeff[0] ) );
-        }
-        realPart = real_part.empty() ? ci->getQuantifiersEngine()->getTermUtil()->d_zero : ( real_part.size()==1 ? real_part[0] : NodeManager::currentNM()->mkNode( PLUS, real_part ) );
-        Assert( ci->getOutput()->isEligibleForInstantiation( realPart ) );
-        //re-isolate
-        Trace("cegqi-arith-debug") << "Re-isolate..." << std::endl;
-        ires = ArithMSum::isolate(pv, msum, veq_c, val, atom.getKind());
-        Trace("cegqi-arith-debug") << "Isolate for mixed Int/Real : " << veq_c << " * " << pv << " " << atom.getKind() << " " << val << std::endl;
-        Trace("cegqi-arith-debug") << "                 real part : " << realPart << std::endl;
-        if( ires!=0 ){
-          int ires_use = ( msum[pv].isNull() || msum[pv].getConst<Rational>().sgn()==1 ) ? 1 : -1;
-          val = Rewriter::rewrite( NodeManager::currentNM()->mkNode( ires_use==-1 ? PLUS : MINUS,
-                                    NodeManager::currentNM()->mkNode( ires_use==-1 ? MINUS : PLUS, val, realPart ),
-                                    NodeManager::currentNM()->mkNode( TO_INTEGER, realPart ) ) );  //TODO: round up for upper bounds?
-          Trace("cegqi-arith-debug") << "result : " << val << std::endl;
-          Assert( val.getType().isInteger() );
-        }
-      }
-    }
-    vts_coeff_inf = vts_coeff[0];
-    vts_coeff_delta = vts_coeff[1];
-    Trace("cegqi-arith-debug") << "Return " << veq_c << " * " << pv << " " << atom.getKind() << " " << val << ", vts = (" << vts_coeff_inf << ", " << vts_coeff_delta << ")" << std::endl;
-  }else{
-    Trace("cegqi-arith-debug") << "fail : could not get monomial sum" << std::endl;
-  }
-  return ires;
-}
-
-void ArithInstantiator::reset(CegInstantiator* ci,
-                              SolvedForm& sf,
-                              Node pv,
-                              CegInstEffort effort)
-{
-  d_vts_sym[0] = ci->getQuantifiersEngine()->getTermUtil()->getVtsInfinity( d_type, false, false );
-  d_vts_sym[1] = ci->getQuantifiersEngine()->getTermUtil()->getVtsDelta( false, false );
-  for( unsigned i=0; i<2; i++ ){
-    d_mbp_bounds[i].clear();
-    d_mbp_coeff[i].clear();
-    for( unsigned j=0; j<2; j++ ){
-      d_mbp_vts_coeff[i][j].clear();
-    }
-    d_mbp_lit[i].clear();
-  }
-}
-
-bool ArithInstantiator::processEquality(CegInstantiator* ci,
-                                        SolvedForm& sf,
-                                        Node pv,
-                                        std::vector<TermProperties>& term_props,
-                                        std::vector<Node>& terms,
-                                        CegInstEffort effort)
-{
-  Node eq_lhs = terms[0];
-  Node eq_rhs = terms[1];
-  Node lhs_coeff = term_props[0].d_coeff;
-  Node rhs_coeff = term_props[1].d_coeff;
-  //make the same coefficient
-  if( rhs_coeff!=lhs_coeff ){
-    if( !rhs_coeff.isNull() ){
-      Trace("cegqi-arith-debug") << "...mult lhs by " << rhs_coeff << std::endl;
-      eq_lhs = NodeManager::currentNM()->mkNode( MULT, rhs_coeff, eq_lhs );
-      eq_lhs = Rewriter::rewrite( eq_lhs );
-    }
-    if( !lhs_coeff.isNull() ){
-      Trace("cegqi-arith-debug") << "...mult rhs by " << lhs_coeff << std::endl;
-      eq_rhs = NodeManager::currentNM()->mkNode( MULT, lhs_coeff, eq_rhs );
-      eq_rhs = Rewriter::rewrite( eq_rhs );
-    }
-  }
-  Node eq = eq_lhs.eqNode( eq_rhs );
-  eq = Rewriter::rewrite( eq );
-  Node val;
-  TermProperties pv_prop;
-  Node vts_coeff_inf;
-  Node vts_coeff_delta;
-  //isolate pv in the equality
-  int ires = solve_arith( ci, pv, eq, pv_prop.d_coeff, val, vts_coeff_inf, vts_coeff_delta );
-  if( ires!=0 ){
-    pv_prop.d_type = 0;
-    if (ci->constructInstantiationInc(pv, val, pv_prop, sf))
-    {
-      return true;
-    }
-  }
-
-  return false;
-}
-
-Node ArithInstantiator::hasProcessAssertion(CegInstantiator* ci,
-                                            SolvedForm& sf,
-                                            Node pv,
-                                            Node lit,
-                                            CegInstEffort effort)
-{
-  Node atom = lit.getKind()==NOT ? lit[0] : lit;
-  bool pol = lit.getKind()!=NOT;
-  //arithmetic inequalities and disequalities
-  if (atom.getKind() == GEQ ||
-      (atom.getKind() == EQUAL && !pol && atom[0].getType().isReal())) {
-    return lit;
-  } else {
-    return Node::null();
-  }
-}
-
-bool ArithInstantiator::processAssertion(CegInstantiator* ci,
-                                         SolvedForm& sf,
-                                         Node pv,
-                                         Node lit,
-                                         Node alit,
-                                         CegInstEffort effort)
-{
-  Node atom = lit.getKind()==NOT ? lit[0] : lit;
-  bool pol = lit.getKind()!=NOT;
-  //arithmetic inequalities and disequalities
-  Assert( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) );
-  // get model value for pv
-  Node pv_value = ci->getModelValue( pv );
-  //cannot contain infinity?
-  Node vts_coeff_inf;
-  Node vts_coeff_delta;
-  Node val;
-  TermProperties pv_prop;
-  //isolate pv in the inequality
-  int ires = solve_arith( ci, pv, atom, pv_prop.d_coeff, val, vts_coeff_inf, vts_coeff_delta );
-  if( ires!=0 ){
-    //disequalities are either strict upper or lower bounds
-    unsigned rmax = ( atom.getKind()==GEQ || options::cbqiModel() ) ? 1 : 2;
-    for( unsigned r=0; r<rmax; r++ ){
-      int uires = ires;
-      Node uval = val;
-      if( atom.getKind()==GEQ ){
-        //push negation downwards
-        if( !pol ){
-          uires = -ires;
-          if( d_type.isInteger() ){
-            uval = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkConst( Rational( uires ) ) );
-            uval = Rewriter::rewrite( uval );
-          }else{
-            Assert( d_type.isReal() );
-            //now is strict inequality
-            uires = uires*2;
-          }
-        }
-      }else{
-        bool is_upper;
-        if( options::cbqiModel() ){
-          // disequality is a disjunction : only consider the bound in the direction of the model
-          //first check if there is an infinity...
-          if( !vts_coeff_inf.isNull() ){
-            //coefficient or val won't make a difference, just compare with zero
-            Trace("cegqi-arith-debug") << "Disequality : check infinity polarity " << vts_coeff_inf << std::endl;
-            Assert( vts_coeff_inf.isConst() );
-            is_upper = ( vts_coeff_inf.getConst<Rational>().sgn()==1 );
-          }else{
-            Node rhs_value = ci->getModelValue( val );
-            Node lhs_value = pv_prop.getModifiedTerm( pv_value );
-            if( !pv_prop.isBasic() ){
-              lhs_value = pv_prop.getModifiedTerm( pv_value );
-              lhs_value = Rewriter::rewrite( lhs_value );
-            }
-            Trace("cegqi-arith-debug") << "Disequality : check model values " << lhs_value << " " << rhs_value << std::endl;
-            Assert( lhs_value!=rhs_value );
-            Node cmp = NodeManager::currentNM()->mkNode( GEQ, lhs_value, rhs_value );
-            cmp = Rewriter::rewrite( cmp );
-            Assert( cmp.isConst() );
-            is_upper = ( cmp!=ci->getQuantifiersEngine()->getTermUtil()->d_true );
-          }
-        }else{
-          is_upper = (r==0);
-        }
-        Assert( atom.getKind()==EQUAL && !pol );
-        if( d_type.isInteger() ){
-          uires = is_upper ? -1 : 1;
-          uval = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkConst( Rational( uires ) ) );
-          uval = Rewriter::rewrite( uval );
-        }else{
-          Assert( d_type.isReal() );
-          uires = is_upper ? -2 : 2;
-        }
-      }
-      if( Trace.isOn("cegqi-arith-bound-inf") ){
-        Node pvmod = pv_prop.getModifiedTerm( pv );
-        Trace("cegqi-arith-bound-inf") << "From " << lit << ", got : ";
-        Trace("cegqi-arith-bound-inf") << pvmod << " -> " << uval << ", styp = " << uires << std::endl;
-      }
-      //take into account delta
-      if( ci->useVtsDelta() && ( uires==2 || uires==-2 ) ){
-        if( options::cbqiModel() ){
-          Node delta_coeff = NodeManager::currentNM()->mkConst( Rational( uires > 0 ? 1 : -1 ) );
-          if( vts_coeff_delta.isNull() ){
-            vts_coeff_delta = delta_coeff;
-          }else{
-            vts_coeff_delta = NodeManager::currentNM()->mkNode( PLUS, vts_coeff_delta, delta_coeff );
-            vts_coeff_delta = Rewriter::rewrite( vts_coeff_delta );
-          }
-        }else{
-          Node delta = ci->getQuantifiersEngine()->getTermUtil()->getVtsDelta();
-          uval = NodeManager::currentNM()->mkNode( uires==2 ? PLUS : MINUS, uval, delta );
-          uval = Rewriter::rewrite( uval );
-        }
-      }
-      if( options::cbqiModel() ){
-        //just store bounds, will choose based on tighest bound
-        unsigned index = uires>0 ? 0 : 1;
-        d_mbp_bounds[index].push_back( uval );
-        d_mbp_coeff[index].push_back( pv_prop.d_coeff );
-        Trace("cegqi-arith-debug") << "Store bound " << index << " " << uval << " " << pv_prop.d_coeff << " " << vts_coeff_inf << " " << vts_coeff_delta << " " << lit << std::endl;
-        for( unsigned t=0; t<2; t++ ){
-          d_mbp_vts_coeff[index][t].push_back( t==0 ? vts_coeff_inf : vts_coeff_delta );
-        }
-        d_mbp_lit[index].push_back( lit );
-      }else{
-        //try this bound
-        pv_prop.d_type = uires>0 ? 1 : -1;
-        if (ci->constructInstantiationInc(pv, uval, pv_prop, sf))
-        {
-          return true;
-        }
-      }
-    }
-  }
-
-
-  return false;
-}
-
-bool ArithInstantiator::processAssertions(CegInstantiator* ci,
-                                          SolvedForm& sf,
-                                          Node pv,
-                                          CegInstEffort effort)
-{
-  if (options::cbqiModel()) {
-    bool use_inf = ci->useVtsInfinity() && ( d_type.isInteger() ? options::cbqiUseInfInt() : options::cbqiUseInfReal() );
-    bool upper_first = false;
-    if( options::cbqiMinBounds() ){
-      upper_first = d_mbp_bounds[1].size()<d_mbp_bounds[0].size();
-    }
-    int best_used[2];
-    std::vector< Node > t_values[3];
-    Node zero = ci->getQuantifiersEngine()->getTermUtil()->d_zero;
-    Node one = ci->getQuantifiersEngine()->getTermUtil()->d_one;
-    Node pv_value = ci->getModelValue( pv );
-    //try optimal bounds
-    for( unsigned r=0; r<2; r++ ){
-      int rr = upper_first ? (1-r) : r;
-      best_used[rr] = -1;
-      if( d_mbp_bounds[rr].empty() ){
-        if( use_inf ){
-          Trace("cegqi-arith-bound") << "No " << ( rr==0 ? "lower" : "upper" ) << " bounds for " << pv << " (type=" << d_type << ")" << std::endl;
-          //no bounds, we do +- infinity
-          Node val = ci->getQuantifiersEngine()->getTermUtil()->getVtsInfinity( d_type );
-          //TODO : rho value for infinity?
-          if( rr==0 ){
-            val = NodeManager::currentNM()->mkNode( UMINUS, val );
-            val = Rewriter::rewrite( val );
-          }
-          TermProperties pv_prop_no_bound;
-          if (ci->constructInstantiationInc(pv, val, pv_prop_no_bound, sf))
-          {
-            return true;
-          }
-        }
-      }else{
-        Trace("cegqi-arith-bound") << ( rr==0 ? "Lower" : "Upper" ) << " bounds for " << pv << " (type=" << d_type << ") : " << std::endl;
-        int best = -1;
-        Node best_bound_value[3];
-        for( unsigned j=0; j<d_mbp_bounds[rr].size(); j++ ){
-          Node value[3];
-          if( Trace.isOn("cegqi-arith-bound") ){
-            Assert( !d_mbp_bounds[rr][j].isNull() );
-            Trace("cegqi-arith-bound") << "  " << j << ": " << d_mbp_bounds[rr][j];
-            if( !d_mbp_vts_coeff[rr][0][j].isNull() ){
-              Trace("cegqi-arith-bound") << " (+ " << d_mbp_vts_coeff[rr][0][j] << " * INF)";
-            }
-            if( !d_mbp_vts_coeff[rr][1][j].isNull() ){
-              Trace("cegqi-arith-bound") << " (+ " << d_mbp_vts_coeff[rr][1][j] << " * DELTA)";
-            }
-            if( !d_mbp_coeff[rr][j].isNull() ){
-              Trace("cegqi-arith-bound") << " (div " << d_mbp_coeff[rr][j] << ")";
-            }
-            Trace("cegqi-arith-bound") << ", value = ";
-          }
-          t_values[rr].push_back( Node::null() );
-          //check if it is better than the current best bound : lexicographic order infinite/finite/infinitesimal parts
-          bool new_best = true;
-          for( unsigned t=0; t<3; t++ ){
-            //get the value
-            if( t==0 ){
-              value[0] = d_mbp_vts_coeff[rr][0][j];
-              if( !value[0].isNull() ){
-                Trace("cegqi-arith-bound") << "( " << value[0] << " * INF ) + ";
-              }else{
-                value[0] = zero;
-              }
-            }else if( t==1 ){
-              Node t_value = ci->getModelValue( d_mbp_bounds[rr][j] );
-              t_values[rr][j] = t_value;
-              value[1] = t_value;
-              Trace("cegqi-arith-bound") << value[1];
-            }else{
-              value[2] = d_mbp_vts_coeff[rr][1][j];
-              if( !value[2].isNull() ){
-                Trace("cegqi-arith-bound") << " + ( " << value[2] << " * DELTA )";
-              }else{
-                value[2] = zero;
-              }
-            }
-            //multiply by coefficient
-            if( value[t]!=zero && !d_mbp_coeff[rr][j].isNull() ){
-              Assert( d_mbp_coeff[rr][j].isConst() );
-              value[t] = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(1) / d_mbp_coeff[rr][j].getConst<Rational>() ), value[t] );
-              value[t] = Rewriter::rewrite( value[t] );
-            }
-            //check if new best
-            if( best!=-1 ){
-              Assert( !value[t].isNull() && !best_bound_value[t].isNull() );
-              if( value[t]!=best_bound_value[t] ){
-                Kind k = rr==0 ? GEQ : LEQ;
-                Node cmp_bound = NodeManager::currentNM()->mkNode( k, value[t], best_bound_value[t] );
-                cmp_bound = Rewriter::rewrite( cmp_bound );
-                if( cmp_bound!=ci->getQuantifiersEngine()->getTermUtil()->d_true ){
-                  new_best = false;
-                  break;
-                }
-              }
-            }
-          }
-          Trace("cegqi-arith-bound") << std::endl;
-          if( new_best ){
-            for( unsigned t=0; t<3; t++ ){
-              best_bound_value[t] = value[t];
-            }
-            best = j;
-          }
-        }
-        if( best!=-1 ){
-          Trace("cegqi-arith-bound") << "...best bound is " << best << " : ";
-          if( best_bound_value[0]!=zero ){
-            Trace("cegqi-arith-bound") << "( " << best_bound_value[0] << " * INF ) + ";
-          }
-          Trace("cegqi-arith-bound") << best_bound_value[1];
-          if( best_bound_value[2]!=zero ){
-            Trace("cegqi-arith-bound") << " + ( " << best_bound_value[2] << " * DELTA )";
-          }
-          Trace("cegqi-arith-bound") << std::endl;
-          best_used[rr] = best;
-          //if using cbqiMidpoint, only add the instance based on one bound if the bound is non-strict
-          if (!options::cbqiMidpoint() || d_type.isInteger()
-              || (ci->useVtsDelta() && d_mbp_vts_coeff[rr][1][best].isNull()))
-          {
-            Node val = d_mbp_bounds[rr][best];
-            val = getModelBasedProjectionValue( ci, pv, val, rr==0, d_mbp_coeff[rr][best], pv_value, t_values[rr][best], sf.getTheta(),
-                                                d_mbp_vts_coeff[rr][0][best], d_mbp_vts_coeff[rr][1][best] );
-            if( !val.isNull() ){
-              TermProperties pv_prop_bound;
-              pv_prop_bound.d_coeff = d_mbp_coeff[rr][best];
-              pv_prop_bound.d_type = rr==0 ? 1 : -1;
-              if (ci->constructInstantiationInc(pv, val, pv_prop_bound, sf))
-              {
-                return true;
-              }
-            }
-          }
-        }
-      }
-    }
-    //if not using infinity, use model value of zero
-    if( !use_inf && d_mbp_bounds[0].empty() && d_mbp_bounds[1].empty() ){
-      Node val = zero;
-      TermProperties pv_prop_zero;
-      Node theta = sf.getTheta();
-      val = getModelBasedProjectionValue( ci, pv, val, true, pv_prop_zero.d_coeff, pv_value, zero, sf.getTheta(), Node::null(), Node::null() );
-      if( !val.isNull() ){
-        if (ci->constructInstantiationInc(pv, val, pv_prop_zero, sf))
-        {
-          return true;
-        }
-      }
-    }
-    if( options::cbqiMidpoint() && !d_type.isInteger() ){
-      Node vals[2];
-      bool bothBounds = true;
-      Trace("cegqi-arith-bound") << "Try midpoint of bounds..." << std::endl;
-      for( unsigned rr=0; rr<2; rr++ ){
-        int best = best_used[rr];
-        if( best==-1 ){
-          bothBounds = false;
-        }else{
-          vals[rr] = d_mbp_bounds[rr][best];
-          vals[rr] = getModelBasedProjectionValue( ci, pv, vals[rr], rr==0, Node::null(), pv_value, t_values[rr][best], sf.getTheta(),
-                                                   d_mbp_vts_coeff[rr][0][best], Node::null() );
-        }
-        Trace("cegqi-arith-bound") << "Bound : " << vals[rr] << std::endl;
-      }
-      Node val;
-      if( bothBounds ){
-        Assert( !vals[0].isNull() && !vals[1].isNull() );
-        if( vals[0]==vals[1] ){
-          val = vals[0];
-        }else{
-          val = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkNode( PLUS, vals[0], vals[1] ),
-                                                        NodeManager::currentNM()->mkConst( Rational(1)/Rational(2) ) );
-          val = Rewriter::rewrite( val );
-        }
-      }else{
-        if( !vals[0].isNull() ){
-          val = NodeManager::currentNM()->mkNode( PLUS, vals[0], one );
-          val = Rewriter::rewrite( val );
-        }else if( !vals[1].isNull() ){
-          val = NodeManager::currentNM()->mkNode( MINUS, vals[1], one );
-          val = Rewriter::rewrite( val );
-        }
-      }
-      Trace("cegqi-arith-bound") << "Midpoint value : " << val << std::endl;
-      if( !val.isNull() ){
-        TermProperties pv_prop_midpoint;
-        if (ci->constructInstantiationInc(pv, val, pv_prop_midpoint, sf))
-        {
-          return true;
-        }
-      }
-    }
-    //generally should not make it to this point FIXME: write proper assertion
-    //Assert( ( ci->hasNestedQuantification() && !options::cbqiNestedQE() ) || options::cbqiAll() );
-
-    if( options::cbqiNopt() ){
-      //try non-optimal bounds (heuristic, may help when nested quantification) ?
-      Trace("cegqi-arith-bound") << "Try non-optimal bounds..." << std::endl;
-      for( unsigned r=0; r<2; r++ ){
-        int rr = upper_first ? (1-r) : r;
-        for( unsigned j=0; j<d_mbp_bounds[rr].size(); j++ ){
-          if( (int)j!=best_used[rr] && ( !options::cbqiMidpoint() || d_mbp_vts_coeff[rr][1][j].isNull() ) ){
-            Node val = getModelBasedProjectionValue( ci, pv, d_mbp_bounds[rr][j], rr==0, d_mbp_coeff[rr][j], pv_value, t_values[rr][j], sf.getTheta(),
-                                                     d_mbp_vts_coeff[rr][0][j], d_mbp_vts_coeff[rr][1][j] );
-            if( !val.isNull() ){
-              TermProperties pv_prop_nopt_bound;
-              pv_prop_nopt_bound.d_coeff = d_mbp_coeff[rr][j];
-              pv_prop_nopt_bound.d_type = rr==0 ? 1 : -1;
-              if (ci->constructInstantiationInc(
-                      pv, val, pv_prop_nopt_bound, sf))
-              {
-                return true;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-  return false;
-}
-
-bool ArithInstantiator::needsPostProcessInstantiationForVariable(
-    CegInstantiator* ci, SolvedForm& sf, Node pv, CegInstEffort effort)
-{
-  return std::find( sf.d_non_basic.begin(), sf.d_non_basic.end(), pv )!=sf.d_non_basic.end();
-}
-
-bool ArithInstantiator::postProcessInstantiationForVariable(
-    CegInstantiator* ci,
-    SolvedForm& sf,
-    Node pv,
-    CegInstEffort effort,
-    std::vector<Node>& lemmas)
-{
-  Assert( std::find( sf.d_non_basic.begin(), sf.d_non_basic.end(), pv )!=sf.d_non_basic.end() );
-  Assert( std::find( sf.d_vars.begin(), sf.d_vars.end(), pv )!=sf.d_vars.end() );
-  unsigned index = std::find( sf.d_vars.begin(), sf.d_vars.end(), pv )-sf.d_vars.begin();
-  Assert( !sf.d_props[index].isBasic() );
-  Node eq_lhs = sf.d_props[index].getModifiedTerm( sf.d_vars[index] );
-  if( Trace.isOn("cegqi-arith-debug") ){
-    Trace("cegqi-arith-debug") << "Normalize substitution for ";
-    Trace("cegqi-arith-debug") << eq_lhs << " = " << sf.d_subs[index] << std::endl;
-  }
-  Assert( sf.d_vars[index].getType().isInteger() );
-  //must ensure that divisibility constraints are met
-  //solve updated rewritten equality for vars[index], if coefficient is one, then we are successful
-  Node eq_rhs = sf.d_subs[index];
-  Node eq = eq_lhs.eqNode( eq_rhs );
-  eq = Rewriter::rewrite( eq );
-  Trace("cegqi-arith-debug") << "...equality is " << eq << std::endl;
-  std::map< Node, Node > msum;
-  if (ArithMSum::getMonomialSumLit(eq, msum))
-  {
-    Node veq;
-    if (ArithMSum::isolate(sf.d_vars[index], msum, veq, EQUAL, true) != 0)
-    {
-      Node veq_c;
-      if( veq[0]!=sf.d_vars[index] ){
-        Node veq_v;
-        if (ArithMSum::getMonomial(veq[0], veq_c, veq_v))
-        {
-          Assert( veq_v==sf.d_vars[index] );
-        }
-      }
-      sf.d_subs[index] = veq[1];
-      if( !veq_c.isNull() ){
-        sf.d_subs[index] = NodeManager::currentNM()->mkNode( INTS_DIVISION_TOTAL, veq[1], veq_c );
-        Trace("cegqi-arith-debug") << "...bound type is : " << sf.d_props[index].d_type << std::endl;
-        //intger division rounding up if from a lower bound
-        if( sf.d_props[index].d_type==1 && options::cbqiRoundUpLowerLia() ){
-          sf.d_subs[index] = NodeManager::currentNM()->mkNode( PLUS, sf.d_subs[index],
-            NodeManager::currentNM()->mkNode( ITE,
-              NodeManager::currentNM()->mkNode( EQUAL,
-                NodeManager::currentNM()->mkNode( INTS_MODULUS_TOTAL, veq[1], veq_c ),
-                ci->getQuantifiersEngine()->getTermUtil()->d_zero ),
-              ci->getQuantifiersEngine()->getTermUtil()->d_zero, ci->getQuantifiersEngine()->getTermUtil()->d_one )
-          );
-        }
-      }
-      Trace("cegqi-arith-debug") << "...normalize integers : " << sf.d_vars[index] << " -> " << sf.d_subs[index] << std::endl;
-    }else{
-      Trace("cegqi-arith-debug") << "...failed to isolate." << std::endl;
-      return false;
-    }
-  }else{
-    Trace("cegqi-arith-debug") << "...failed to get monomial sum." << std::endl;
-    return false;
-  }
-  return true;
-}
-
-void DtInstantiator::reset(CegInstantiator* ci,
-                           SolvedForm& sf,
-                           Node pv,
-                           CegInstEffort effort)
-{
-}
-
-Node DtInstantiator::solve_dt( Node v, Node a, Node b, Node sa, Node sb ) {
-  Trace("cegqi-arith-debug2") << "Solve dt : " << v << " " << a << " " << b << " " << sa << " " << sb << std::endl;
-  Node ret;
-  if( !a.isNull() && a==v ){
-    ret = sb;
-  }else if( !b.isNull() && b==v ){
-    ret = sa;
-  }else if( !a.isNull() && a.getKind()==APPLY_CONSTRUCTOR ){
-    if( !b.isNull() && b.getKind()==APPLY_CONSTRUCTOR ){
-      if( a.getOperator()==b.getOperator() ){
-        for( unsigned i=0; i<a.getNumChildren(); i++ ){
-          Node s = solve_dt( v, a[i], b[i], sa[i], sb[i] );
-          if( !s.isNull() ){
-            return s;
-          }
-        }
-      }
-    }else{
-      unsigned cindex = Datatype::indexOf( a.getOperator().toExpr() );
-      TypeNode tn = a.getType();
-      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-      for( unsigned i=0; i<a.getNumChildren(); i++ ){
-        Node nn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex].getSelectorInternal( tn.toType(), i ) ), sb );
-        Node s = solve_dt( v, a[i], Node::null(), sa[i], nn );
-        if( !s.isNull() ){
-          return s;
-        }
-      }
-    }
-  }else if( !b.isNull() && b.getKind()==APPLY_CONSTRUCTOR ){
-    return solve_dt( v, b, a, sb, sa );
-  }
-  if( !ret.isNull() ){
-    //ensure does not contain
-    if( TermUtil::containsTerm( ret, v ) ){
-      ret = Node::null();
-    }
-  }
-  return ret;
-}
-
-bool DtInstantiator::processEqualTerms(CegInstantiator* ci,
-                                       SolvedForm& sf,
-                                       Node pv,
-                                       std::vector<Node>& eqc,
-                                       CegInstEffort effort)
-{
-  Trace("cegqi-dt-debug") << "try based on constructors in equivalence class."
-                          << std::endl;
-  // look in equivalence class for a constructor
-  for( unsigned k=0; k<eqc.size(); k++ ){
-    Node n = eqc[k];
-    if( n.getKind()==APPLY_CONSTRUCTOR ){
-      Trace("cegqi-dt-debug") << "...try based on constructor term " << n << std::endl;
-      std::vector< Node > children;
-      children.push_back( n.getOperator() );
-      const Datatype& dt = ((DatatypeType)(d_type).toType()).getDatatype();
-      unsigned cindex = Datatype::indexOf( n.getOperator().toExpr() );
-      //now must solve for selectors applied to pv
-      for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){
-        Node c = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex].getSelectorInternal( d_type.toType(), j ) ), pv );
-        ci->pushStackVariable( c );
-        children.push_back( c );
-      }
-      Node val = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, children );
-      TermProperties pv_prop_dt;
-      if (ci->constructInstantiationInc(pv, val, pv_prop_dt, sf))
-      {
-        return true;
-      }else{
-        //cleanup
-        for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){
-          ci->popStackVariable();
-        }
-        break;
-      }
-    }
-  }
-  return false;
-}
-
-bool DtInstantiator::processEquality(CegInstantiator* ci,
-                                     SolvedForm& sf,
-                                     Node pv,
-                                     std::vector<TermProperties>& term_props,
-                                     std::vector<Node>& terms,
-                                     CegInstEffort effort)
-{
-  Node val = solve_dt( pv, terms[0], terms[1], terms[0], terms[1] );
-  if( !val.isNull() ){
-    TermProperties pv_prop;
-    if (ci->constructInstantiationInc(pv, val, pv_prop, sf))
-    {
-      return true;
-    }
-  }
-  return false;
-}
-
-void EprInstantiator::reset(CegInstantiator* ci,
-                            SolvedForm& sf,
-                            Node pv,
-                            CegInstEffort effort)
-{
-  d_equal_terms.clear();
-}
-
-bool EprInstantiator::processEqualTerm(CegInstantiator* ci,
-                                       SolvedForm& sf,
-                                       Node pv,
-                                       TermProperties& pv_prop,
-                                       Node n,
-                                       CegInstEffort effort)
-{
-  if( options::quantEprMatching() ){
-    Assert( pv_prop.isBasic() );
-    d_equal_terms.push_back( n );
-    return false;
-  }else{
-    pv_prop.d_type = 0;
-    return ci->constructInstantiationInc(pv, n, pv_prop, sf);
-  }
-}
-
-void EprInstantiator::computeMatchScore( CegInstantiator * ci, Node pv, Node catom, std::vector< Node >& arg_reps, TermArgTrie * tat, unsigned index, std::map< Node, int >& match_score ) {
-  if( index==catom.getNumChildren() ){
-    Assert( tat->hasNodeData() );
-    Node gcatom = tat->getNodeData();
-    Trace("cegqi-epr") << "Matched : " << catom << " and " << gcatom << std::endl;
-    for( unsigned i=0; i<catom.getNumChildren(); i++ ){
-      if( catom[i]==pv ){
-        Trace("cegqi-epr") << "...increment " << gcatom[i] << std::endl;
-        match_score[gcatom[i]]++;
-      }else{
-        //recursive matching
-        computeMatchScore( ci, pv, catom[i], gcatom[i], match_score );
-      }
-    }
-  }else{
-    std::map< TNode, TermArgTrie >::iterator it = tat->d_data.find( arg_reps[index] );
-    if( it!=tat->d_data.end() ){
-      computeMatchScore( ci, pv, catom, arg_reps, &it->second, index+1, match_score );
-    }
-  }
-}
-
-void EprInstantiator::computeMatchScore( CegInstantiator * ci, Node pv, Node catom, Node eqc, std::map< Node, int >& match_score ) {
-  if( inst::Trigger::isAtomicTrigger( catom ) && TermUtil::containsTerm( catom, pv ) ){
-    Trace("cegqi-epr") << "Find matches for " << catom << "..." << std::endl;
-    std::vector< Node > arg_reps;
-    for( unsigned j=0; j<catom.getNumChildren(); j++ ){
-      arg_reps.push_back( ci->getQuantifiersEngine()->getMasterEqualityEngine()->getRepresentative( catom[j] ) );
-    }
-    if( ci->getQuantifiersEngine()->getMasterEqualityEngine()->hasTerm( eqc ) ){
-      Node rep = ci->getQuantifiersEngine()->getMasterEqualityEngine()->getRepresentative( eqc );
-      Node op = ci->getQuantifiersEngine()->getTermDatabase()->getMatchOperator( catom );
-      TermArgTrie * tat = ci->getQuantifiersEngine()->getTermDatabase()->getTermArgTrie( rep, op );
-      Trace("cegqi-epr") << "EPR instantiation match term : " << catom << ", check ground terms=" << (tat!=NULL) << std::endl;
-      if( tat ){
-        computeMatchScore( ci, pv, catom, arg_reps, tat, 0, match_score );
-      }
-    }
-  }
-}
-
-struct sortEqTermsMatch {
-  std::map< Node, int > d_match_score;
-  bool operator() (Node i, Node j) {
-    int match_score_i = d_match_score[i];
-    int match_score_j = d_match_score[j];
-    return match_score_i>match_score_j || ( match_score_i==match_score_j && i<j );
-  }
-};
-
-bool EprInstantiator::processEqualTerms(CegInstantiator* ci,
-                                        SolvedForm& sf,
-                                        Node pv,
-                                        std::vector<Node>& eqc,
-                                        CegInstEffort effort)
-{
-  if( options::quantEprMatching() ){
-    //heuristic for best matching constant
-    sortEqTermsMatch setm;
-    for( unsigned i=0; i<ci->getNumCEAtoms(); i++ ){
-      Node catom = ci->getCEAtom( i );
-      computeMatchScore( ci, pv, catom, catom, setm.d_match_score );
-    }
-    //sort by match score
-    std::sort( d_equal_terms.begin(), d_equal_terms.end(), setm );
-    TermProperties pv_prop;
-    pv_prop.d_type = 0;
-    for( unsigned i=0; i<d_equal_terms.size(); i++ ){
-      if (ci->constructInstantiationInc(pv, d_equal_terms[i], pv_prop, sf))
-      {
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
-// this class can be used to query the model value through the CegInstaniator class
-class CegInstantiatorBvInverterQuery : public BvInverterQuery
-{
- public:
-  CegInstantiatorBvInverterQuery(CegInstantiator* ci)
-      : BvInverterQuery(), d_ci(ci)
-  {
-  }
-  ~CegInstantiatorBvInverterQuery() {}
-  /** return the model value of n */
-  Node getModelValue( Node n ) {
-    return d_ci->getModelValue( n );
-  }
-  /** get bound variable of type tn */
-  Node getBoundVariable(TypeNode tn) { return d_ci->getBoundVariable(tn); }
- protected:
-  // pointer to class that is able to query model values
-  CegInstantiator * d_ci;
-};
-
-BvInstantiator::BvInstantiator(QuantifiersEngine* qe, TypeNode tn)
-    : Instantiator(qe, tn), d_tried_assertion_inst(false)
-{
-  // get the global inverter utility
-  // this must be global since we need to:
-  // * process Skolem functions properly across multiple variables within the same quantifier
-  // * cache Skolem variables uniformly across multiple quantified formulas
-  d_inverter = qe->getBvInverter();
-}
-
-BvInstantiator::~BvInstantiator(){
-
-}
-void BvInstantiator::reset(CegInstantiator* ci,
-                           SolvedForm& sf,
-                           Node pv,
-                           CegInstEffort effort)
-{
-  d_inst_id_counter = 0;
-  d_var_to_inst_id.clear();
-  d_inst_id_to_term.clear();
-  d_inst_id_to_alit.clear();
-  d_var_to_curr_inst_id.clear();
-  d_alit_to_model_slack.clear();
-  d_tried_assertion_inst = false;
-}
-
-void BvInstantiator::processLiteral(CegInstantiator* ci,
-                                    SolvedForm& sf,
-                                    Node pv,
-                                    Node lit,
-                                    Node alit,
-                                    CegInstEffort effort)
-{
-  Assert(d_inverter != NULL);
-  // find path to pv
-  std::vector<unsigned> path;
-  Node sv = d_inverter->getSolveVariable(pv.getType());
-  Node pvs = ci->getModelValue(pv);
-  Trace("cegqi-bv") << "Get path to pv : " << lit << std::endl;
-  Node slit = d_inverter->getPathToPv(lit, pv, sv, pvs, path);
-  if (!slit.isNull())
-  {
-    CegInstantiatorBvInverterQuery m(ci);
-    unsigned iid = d_inst_id_counter;
-    Trace("cegqi-bv") << "Solve lit to bv inverter : " << slit << std::endl;
-    Node inst = d_inverter->solveBvLit(sv, slit, path, &m);
-    if (!inst.isNull())
-    {
-      inst = Rewriter::rewrite(inst);
-      if (inst.isConst() || !ci->hasNestedQuantification())
-      {
-        Trace("cegqi-bv") << "...solved form is " << inst << std::endl;
-        // store information for id and increment
-        d_var_to_inst_id[pv].push_back(iid);
-        d_inst_id_to_term[iid] = inst;
-        d_inst_id_to_alit[iid] = alit;
-        d_inst_id_counter++;
-      }
-    }
-    else
-    {
-      Trace("cegqi-bv") << "...failed to solve." << std::endl;
-    }
-  }
-}
-
-Node BvInstantiator::hasProcessAssertion(CegInstantiator* ci,
-                                         SolvedForm& sf,
-                                         Node pv,
-                                         Node lit,
-                                         CegInstEffort effort)
-{
-  if (effort == CEG_INST_EFFORT_FULL)
-  {
-    // always use model values at full effort
-    return Node::null();
-  }
-  Node atom = lit.getKind() == NOT ? lit[0] : lit;
-  bool pol = lit.getKind() != NOT;
-  Kind k = atom.getKind();
-  if (k != EQUAL && k != BITVECTOR_ULT && k != BITVECTOR_SLT)
-  {
-    // others are unhandled
-    return Node::null();
-  }
-  else if (!atom[0].getType().isBitVector())
-  {
-    return Node::null();
-  }
-  else if (options::cbqiBvIneqMode() == CBQI_BV_INEQ_KEEP
-           || (pol && k == EQUAL))
-  {
-    return lit;
-  }
-  NodeManager* nm = NodeManager::currentNM();
-  Node s = atom[0];
-  Node t = atom[1];
-
-  Node sm = ci->getModelValue(s);
-  Node tm = ci->getModelValue(t);
-  Assert(!sm.isNull() && sm.isConst());
-  Assert(!tm.isNull() && tm.isConst());
-  Trace("cegqi-bv") << "Model value: " << std::endl;
-  Trace("cegqi-bv") << "   " << s << " " << k << " " << t << " is "
-                    << std::endl;
-  Trace("cegqi-bv") << "   " << sm << " <> " << tm << std::endl;
-
-  Node ret;
-  if (options::cbqiBvIneqMode() == CBQI_BV_INEQ_EQ_SLACK)
-  {
-    // if using slack, we convert constraints to a positive equality based on
-    // the current model M, e.g.:
-    //   (not) s ~ t  --->  s = t + ( s^M - t^M )
-    if (sm != tm)
-    {
-      Node slack = Rewriter::rewrite(nm->mkNode(BITVECTOR_SUB, sm, tm));
-      Assert(slack.isConst());
-      // remember the slack value for the asserted literal
-      d_alit_to_model_slack[lit] = slack;
-      ret = nm->mkNode(EQUAL, s, nm->mkNode(BITVECTOR_PLUS, t, slack));
-      Trace("cegqi-bv") << "Slack is " << slack << std::endl;
-    }
-    else
-    {
-      ret = s.eqNode(t);
-    }
-  } else {
-    // turn disequality into an inequality
-    // e.g. s != t becomes s < t or t < s
-    if (k == EQUAL)
-    {
-      if (Random::getRandom().pickWithProb(0.5))
-      {
-        std::swap(s, t);
-      }
-      pol = true;
-    }
-    // otherwise, we optimistically solve for the boundary point of an
-    // inequality, for example:
-    //   for s < t, we solve s+1 = t
-    //   for ~( s < t ), we solve s = t
-    // notice that this equality does not necessarily hold in the model, and
-    // hence the corresponding instantiation strategy is not guaranteed to be
-    // monotonic.
-    if (!pol)
-    {
-      ret = s.eqNode(t);
-    } else {
-      Node bv_one = bv::utils::mkOne(bv::utils::getSize(s));
-      ret = nm->mkNode(BITVECTOR_PLUS, s, bv_one).eqNode(t);
-    }
-  }
-  Trace("cegqi-bv") << "Process " << lit << " as " << ret << std::endl;
-  return ret;
-}
-
-bool BvInstantiator::processAssertion(CegInstantiator* ci,
-                                      SolvedForm& sf,
-                                      Node pv,
-                                      Node lit,
-                                      Node alit,
-                                      CegInstEffort effort)
-{
-  // if option enabled, use approach for word-level inversion for BV instantiation
-  if( options::cbqiBv() ){
-    // get the best rewritten form of lit for solving for pv 
-    //   this should remove instances of non-invertible operators, and "linearize" lit with respect to pv as much as possible
-    Node rlit = rewriteAssertionForSolvePv(ci, pv, lit);
-    if( Trace.isOn("cegqi-bv") ){
-      Trace("cegqi-bv") << "BvInstantiator::processAssertion : solve " << pv << " in " << lit << std::endl;
-      if( lit!=rlit ){
-        Trace("cegqi-bv") << "...rewritten to " << rlit << std::endl;
-      }
-    }
-    if (!rlit.isNull())
-    {
-      processLiteral(ci, sf, pv, rlit, alit, effort);
-    }
-  }
-  return false;
-}
-
-bool BvInstantiator::useModelValue(CegInstantiator* ci,
-                                   SolvedForm& sf,
-                                   Node pv,
-                                   CegInstEffort effort)
-{
-  return !d_tried_assertion_inst
-         && (effort < CEG_INST_EFFORT_FULL || options::cbqiFullEffort());
-}
-
-bool BvInstantiator::processAssertions(CegInstantiator* ci,
-                                       SolvedForm& sf,
-                                       Node pv,
-                                       CegInstEffort effort)
-{
-  std::unordered_map< Node, std::vector< unsigned >, NodeHashFunction >::iterator iti = d_var_to_inst_id.find( pv );
-  if( iti!=d_var_to_inst_id.end() ){
-    Trace("cegqi-bv") << "BvInstantiator::processAssertions for " << pv << std::endl;
-    // if interleaving, do not do inversion half the time
-    if (!options::cbqiBvInterleaveValue() || Random::getRandom().pickWithProb(0.5))
-    {
-      bool firstVar = sf.empty();
-      // get inst id list
-      if (Trace.isOn("cegqi-bv"))
-      {
-        Trace("cegqi-bv") << "  " << iti->second.size()
-                          << " candidate instantiations for " << pv << " : "
-                          << std::endl;
-        if (firstVar)
-        {
-          Trace("cegqi-bv") << "  ...this is the first variable" << std::endl;
-        }
-      }
-      // until we have a model-preserving selection function for BV, this must
-      // be heuristic (we only pick one literal)
-      // hence we randomize the list
-      // this helps robustness, since picking the same literal every time may
-      // lead to a stream of value instantiations, whereas with randomization
-      // we may find an invertible literal that leads to a useful instantiation.
-      std::random_shuffle(iti->second.begin(), iti->second.end());
-
-      if (Trace.isOn("cegqi-bv"))
-      {
-        for (unsigned j = 0, size = iti->second.size(); j < size; j++)
-        {
-          unsigned inst_id = iti->second[j];
-          Assert(d_inst_id_to_term.find(inst_id) != d_inst_id_to_term.end());
-          Node inst_term = d_inst_id_to_term[inst_id];
-          Assert(d_inst_id_to_alit.find(inst_id) != d_inst_id_to_alit.end());
-          Node alit = d_inst_id_to_alit[inst_id];
-
-          // get the slack value introduced for the asserted literal
-          Node curr_slack_val;
-          std::unordered_map<Node, Node, NodeHashFunction>::iterator itms =
-              d_alit_to_model_slack.find(alit);
-          if (itms != d_alit_to_model_slack.end())
-          {
-            curr_slack_val = itms->second;
-          }
-
-          // debug printing
-          Trace("cegqi-bv") << "   [" << j << "] : ";
-          Trace("cegqi-bv") << inst_term << std::endl;
-          if (!curr_slack_val.isNull()) {
-            Trace("cegqi-bv") << "   ...with slack value : " << curr_slack_val
-                              << std::endl;
-          }
-          Trace("cegqi-bv-debug") << "   ...from : " << alit << std::endl;
-          Trace("cegqi-bv") << std::endl;
-        }
-      }
-
-      // Now, try all instantiation ids we want to try
-      // Typically we try only one, otherwise worst-case performance
-      // for constructing instantiations is exponential on the number of
-      // variables in this quantifier prefix.
-      bool ret = false;
-      bool tryMultipleInst = firstVar && options::cbqiMultiInst();
-      bool revertOnSuccess = tryMultipleInst;
-      for (unsigned j = 0, size = iti->second.size(); j < size; j++)
-      {
-        unsigned inst_id = iti->second[j];
-        Assert(d_inst_id_to_term.find(inst_id) != d_inst_id_to_term.end());
-        Node inst_term = d_inst_id_to_term[inst_id];
-        Node alit = d_inst_id_to_alit[inst_id];
-        // try instantiation pv -> inst_term
-        TermProperties pv_prop_bv;
-        Trace("cegqi-bv") << "*** try " << pv << " -> " << inst_term
-                          << std::endl;
-        d_var_to_curr_inst_id[pv] = inst_id;
-        d_tried_assertion_inst = true;
-        ci->markSolved(alit);
-        if (ci->constructInstantiationInc(
-                pv, inst_term, pv_prop_bv, sf, revertOnSuccess))
-        {
-          ret = true;
-        }
-        ci->markSolved(alit, false);
-        // we are done unless we try multiple instances
-        if (!tryMultipleInst)
-        {
-          break;
-        }
-      }
-      if (ret)
-      {
-        return true;
-      }
-      Trace("cegqi-bv") << "...failed to add instantiation for " << pv
-                        << std::endl;
-      d_var_to_curr_inst_id.erase(pv);
-    } else {
-      Trace("cegqi-bv") << "...do not do instantiation for " << pv
-                        << " (skip, based on heuristic)" << std::endl;
-    }
-  }
-
-  return false;
-}
-
-Node BvInstantiator::rewriteAssertionForSolvePv(CegInstantiator* ci,
-                                                Node pv,
-                                                Node lit)
-{
-  // result of rewriting the visited term
-  std::stack<std::unordered_map<TNode, Node, TNodeHashFunction> > visited;
-  visited.push(std::unordered_map<TNode, Node, TNodeHashFunction>());
-  // whether the visited term contains pv
-  std::unordered_map<TNode, bool, TNodeHashFunction> visited_contains_pv;
-  std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
-  std::unordered_map<TNode, Node, TNodeHashFunction> curr_subs;
-  std::stack<std::stack<TNode> > visit;
-  TNode cur;
-  visit.push(std::stack<TNode>());
-  visit.top().push(lit);
-  do {
-    cur = visit.top().top();
-    visit.top().pop();
-    it = visited.top().find(cur);
-
-    if (it == visited.top().end())
-    {
-      std::unordered_map<TNode, Node, TNodeHashFunction>::iterator itc =
-          curr_subs.find(cur);
-      if (itc != curr_subs.end())
-      {
-        visited.top()[cur] = itc->second;
-      }
-      else
-      {
-        if (cur.getKind() == CHOICE)
-        {
-          // must replace variables of choice functions
-          // with new variables to avoid variable
-          // capture when considering substitutions
-          // with multiple literals.
-          Node bv = ci->getBoundVariable(cur[0][0].getType());
-          // should not have captured variables
-          Assert(curr_subs.find(cur[0][0]) == curr_subs.end());
-          curr_subs[cur[0][0]] = bv;
-          // we cannot cache the results of subterms
-          // of this choice expression since we are
-          // now in the context { cur[0][0] -> bv },
-          // hence we push a context here
-          visited.push(std::unordered_map<TNode, Node, TNodeHashFunction>());
-          visit.push(std::stack<TNode>());
-        }
-        visited.top()[cur] = Node::null();
-        visit.top().push(cur);
-        for (unsigned i = 0; i < cur.getNumChildren(); i++)
-        {
-          visit.top().push(cur[i]);
-        }
-      }
-    } else if (it->second.isNull()) {
-      Node ret;
-      bool childChanged = false;
-      std::vector<Node> children;
-      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED) {
-        children.push_back(cur.getOperator());
-      }
-      bool contains_pv = ( cur==pv );
-      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
-        it = visited.top().find(cur[i]);
-        Assert(it != visited.top().end());
-        Assert(!it->second.isNull());
-        childChanged = childChanged || cur[i] != it->second;
-        children.push_back(it->second);
-        contains_pv = contains_pv || visited_contains_pv[cur[i]];
-      }
-      // careful that rewrites above do not affect whether this term contains pv
-      visited_contains_pv[cur] = contains_pv;
-
-      // rewrite the term
-      ret = rewriteTermForSolvePv(pv, cur, children, visited_contains_pv);
-
-      // return original if the above function does not produce a result
-      if (ret.isNull()) {
-        if (childChanged) {
-          ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
-        }else{
-          ret = cur;
-        }
-      }
-
-      /* We need to update contains_pv also for rewritten nodes, since
-       * the normalizePv* functions rely on the information if pv occurs in a
-       * rewritten node or not. */
-      if (ret != cur)
-      {
-        contains_pv = (ret == pv);
-        for (unsigned i = 0, size = ret.getNumChildren(); i < size; ++i)
-        {
-          contains_pv = contains_pv || visited_contains_pv[ret[i]];
-        }
-        visited_contains_pv[ret] = contains_pv;
-      }
-
-      // if was choice, pop context
-      if (cur.getKind() == CHOICE)
-      {
-        Assert(curr_subs.find(cur[0][0]) != curr_subs.end());
-        curr_subs.erase(cur[0][0]);
-        visited.pop();
-        visit.pop();
-        Assert(visited.size() == visit.size());
-        Assert(!visit.empty());
-      }
-
-      visited.top()[cur] = ret;
-    }
-  } while (!visit.top().empty());
-  Assert(visited.size() == 1);
-  Assert(visited.top().find(lit) != visited.top().end());
-  Assert(!visited.top().find(lit)->second.isNull());
-
-  Node result = visited.top()[lit];
-
-  if (Trace.isOn("cegqi-bv-nl"))
-  {
-    std::vector<TNode> trace_visit;
-    std::unordered_set<TNode, TNodeHashFunction> trace_visited;
-
-    trace_visit.push_back(result);
-    do
-    {
-      cur = trace_visit.back();
-      trace_visit.pop_back();
-
-      if (trace_visited.find(cur) == trace_visited.end())
-      {
-        trace_visited.insert(cur);
-        trace_visit.insert(trace_visit.end(), cur.begin(), cur.end());
-      }
-      else if (cur == pv)
-      {
-        Trace("cegqi-bv-nl")
-            << "NONLINEAR LITERAL for " << pv << " : " << lit << std::endl;
-      }
-    } while (!trace_visit.empty());
-  }
-
-  return result;
-}
-
-/**
- * Determine coefficient of pv in term n, where n has the form pv, -pv, pv * t,
- * or -pv * t. Extracting the coefficient of multiplications only succeeds if
- * the multiplication are normalized with normalizePvMult.
- *
- * If sucessful it returns
- *   1    if n ==  pv,
- *  -1    if n == -pv,
- *   t    if n ==  pv * t,
- *  -t    if n == -pv * t.
- * If n is not a linear term, a null node is returned.
- */
-static Node getPvCoeff(TNode pv, TNode n)
-{
-  bool neg = false;
-  Node coeff;
-
-  if (n.getKind() == BITVECTOR_NEG)
-  {
-    neg = true;
-    n = n[0];
-  }
-
-  if (n == pv)
-  {
-    coeff = bv::utils::mkOne(bv::utils::getSize(pv));
-  }
-  /* All multiplications are normalized to pv * (t1 * t2). */
-  else if (n.getKind() == BITVECTOR_MULT && n.getAttribute(BvLinearAttribute()))
-  {
-    Assert(n.getNumChildren() == 2);
-    Assert(n[0] == pv);
-    coeff = n[1];
-  }
-  else /* n is in no form to extract the coefficient for pv */
-  {
-    Trace("cegqi-bv-nl") << "Cannot extract coefficient for " << pv << " in "
-                         << n << std::endl;
-    return Node::null();
-  }
-  Assert(!coeff.isNull());
-
-  if (neg) return NodeManager::currentNM()->mkNode(BITVECTOR_NEG, coeff);
-  return coeff;
-}
-
-/**
- * Normalizes the children of a BITVECTOR_MULT w.r.t. pv. contains_pv marks
- * terms in which pv occurs.
- * For example,
- *
- *  a * -pv * b * c
- *
- * is rewritten to
- *
- *  pv * -(a * b * c)
- *
- * Returns the normalized node if the resulting term is linear w.r.t. pv and
- * a null node otherwise. If pv does not occur in children it returns a
- * multiplication over children.
- */
-static Node normalizePvMult(
-    TNode pv,
-    const std::vector<Node>& children,
-    std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv)
-{
-  bool neg, neg_coeff = false;
-  bool found_pv = false;
-  NodeManager* nm;
-  NodeBuilder<> nb(BITVECTOR_MULT);
-  BvLinearAttribute is_linear;
-
-  nm = NodeManager::currentNM();
-  for (TNode nc : children)
-  {
-    if (!contains_pv[nc])
-    {
-      nb << nc;
-      continue;
-    }
-
-    neg = false;
-    if (nc.getKind() == BITVECTOR_NEG)
-    {
-      neg = true;
-      nc = nc[0];
-    }
-
-    if (!found_pv && nc == pv)
-    {
-      found_pv = true;
-      neg_coeff = neg;
-      continue;
-    }
-    else if (!found_pv && nc.getKind() == BITVECTOR_MULT
-             && nc.getAttribute(is_linear))
-    {
-      Assert(nc.getNumChildren() == 2);
-      Assert(nc[0] == pv);
-      Assert(!contains_pv[nc[1]]);
-      found_pv = true;
-      neg_coeff = neg;
-      nb << nc[1];
-      continue;
-    }
-    return Node::null(); /* non-linear */
-  }
-  Assert(nb.getNumChildren() > 0);
-
-  Node coeff = (nb.getNumChildren() == 1) ? nb[0] : nb.constructNode();
-  if (neg_coeff)
-  {
-    coeff = nm->mkNode(BITVECTOR_NEG, coeff);
-  }
-  coeff = Rewriter::rewrite(coeff);
-  unsigned size_coeff = bv::utils::getSize(coeff);
-  Node zero = bv::utils::mkZero(size_coeff);
-  if (coeff == zero)
-  {
-    return zero;
-  }
-  Node result;
-  if (found_pv)
-  {
-    if (coeff == bv::utils::mkOne(size_coeff))
-    {
-      return pv;
-    }
-    result = nm->mkNode(BITVECTOR_MULT, pv, coeff);
-    contains_pv[result] = true;
-    result.setAttribute(is_linear, true);
-  }
-  else
-  {
-    result = coeff;
-  }
-  return result;
-}
-
-#ifdef CVC4_ASSERTIONS
-static bool isLinearPlus(
-    TNode n,
-    TNode pv,
-    std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv)
-{
-  Node coeff;
-  Assert(n.getAttribute(BvLinearAttribute()));
-  Assert(n.getNumChildren() == 2);
-  if (n[0] != pv)
-  {
-    Assert(n[0].getKind() == BITVECTOR_MULT);
-    Assert(n[0].getNumChildren() == 2);
-    Assert(n[0][0] == pv);
-    Assert(!contains_pv[n[0][1]]);
-  }
-  Assert(!contains_pv[n[1]]);
-  coeff = getPvCoeff(pv, n[0]);
-  Assert(!coeff.isNull());
-  Assert(!contains_pv[coeff]);
-  return true;
-}
-#endif
-
-/**
- * Normalizes the children of a BITVECTOR_PLUS w.r.t. pv. contains_pv marks
- * terms in which pv occurs.
- * For example,
- *
- *  a * pv + b + c * -pv
- *
- * is rewritten to
- *
- *  pv * (a - c) + b
- *
- * Returns the normalized node if the resulting term is linear w.r.t. pv and
- * a null node otherwise. If pv does not occur in children it returns an
- * addition over children.
- */
-static Node normalizePvPlus(
-    Node pv,
-    const std::vector<Node>& children,
-    std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv)
-{
-  NodeManager* nm;
-  NodeBuilder<> nb_c(BITVECTOR_PLUS);
-  NodeBuilder<> nb_l(BITVECTOR_PLUS);
-  BvLinearAttribute is_linear;
-  bool neg;
-
-  nm = NodeManager::currentNM();
-  for (TNode nc : children)
-  {
-    if (!contains_pv[nc])
-    {
-      nb_l << nc;
-      continue;
-    }
-
-    neg = false;
-    if (nc.getKind() == BITVECTOR_NEG)
-    {
-      neg = true;
-      nc = nc[0];
-    }
-
-    if (nc == pv
-        || (nc.getKind() == BITVECTOR_MULT && nc.getAttribute(is_linear)))
-    {
-      Node coeff = getPvCoeff(pv, nc);
-      Assert(!coeff.isNull());
-      if (neg)
-      {
-        coeff = nm->mkNode(BITVECTOR_NEG, coeff);
-      }
-      nb_c << coeff;
-      continue;
-    }
-    else if (nc.getKind() == BITVECTOR_PLUS && nc.getAttribute(is_linear))
-    {
-      Assert(isLinearPlus(nc, pv, contains_pv));
-      Node coeff = getPvCoeff(pv, nc[0]);
-      Assert(!coeff.isNull());
-      Node leaf = nc[1];
-      if (neg)
-      {
-        coeff = nm->mkNode(BITVECTOR_NEG, coeff);
-        leaf = nm->mkNode(BITVECTOR_NEG, leaf);
-      }
-      nb_c << coeff;
-      nb_l << leaf;
-      continue;
-    }
-    /* can't collect coefficients of 'pv' in 'cur' -> non-linear */
-    return Node::null();
-  }
-  Assert(nb_c.getNumChildren() > 0 || nb_l.getNumChildren() > 0);
-
-  Node pv_mult_coeffs, result;
-  if (nb_c.getNumChildren() > 0)
-  {
-    Node coeffs = (nb_c.getNumChildren() == 1) ? nb_c[0] : nb_c.constructNode();
-    coeffs = Rewriter::rewrite(coeffs);
-    result = pv_mult_coeffs = normalizePvMult(pv, {pv, coeffs}, contains_pv);
-  }
-
-  if (nb_l.getNumChildren() > 0)
-  {
-    Node leafs = (nb_l.getNumChildren() == 1) ? nb_l[0] : nb_l.constructNode();
-    leafs = Rewriter::rewrite(leafs);
-    Node zero = bv::utils::mkZero(bv::utils::getSize(pv));
-    /* pv * 0 + t --> t */
-    if (pv_mult_coeffs.isNull() || pv_mult_coeffs == zero)
-    {
-      result = leafs;
-    }
-    else
-    {
-      result = nm->mkNode(BITVECTOR_PLUS, pv_mult_coeffs, leafs);
-      contains_pv[result] = true;
-      result.setAttribute(is_linear, true);
-    }
-  }
-  Assert(!result.isNull());
-  return result;
-}
-
-/**
- * Linearize an equality w.r.t. pv such that pv only occurs once. contains_pv
- * marks terms in which pv occurs.
- * For example, equality
- *
- *   -pv * a + b = c + pv
- *
- * rewrites to
- *
- *   pv * (-a - 1) = c - b.
- */
-static Node normalizePvEqual(
-    Node pv,
-    const std::vector<Node>& children,
-    std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv)
-{
-  Assert(children.size() == 2);
-
-  NodeManager* nm = NodeManager::currentNM();
-  BvLinearAttribute is_linear;
-  Node coeffs[2], leafs[2];
-  bool neg;
-  TNode child;
-
-  for (unsigned i = 0; i < 2; ++i)
-  {
-    child = children[i];
-    neg = false;
-    if (child.getKind() == BITVECTOR_NEG)
-    {
-      neg = true;
-      child = child[0];
-    }
-    if (child.getAttribute(is_linear) || child == pv)
-    {
-      if (child.getKind() == BITVECTOR_PLUS)
-      {
-        Assert(isLinearPlus(child, pv, contains_pv));
-        coeffs[i] = getPvCoeff(pv, child[0]);
-        leafs[i] = child[1];
-      }
-      else
-      {
-        Assert(child.getKind() == BITVECTOR_MULT || child == pv);
-        coeffs[i] = getPvCoeff(pv, child);
-      }
-    }
-    if (neg)
-    {
-      if (!coeffs[i].isNull())
-      {
-        coeffs[i] = nm->mkNode(BITVECTOR_NEG, coeffs[i]);
-      }
-      if (!leafs[i].isNull())
-      {
-        leafs[i] = nm->mkNode(BITVECTOR_NEG, leafs[i]);
-      }
-    }
-  }
-
-  if (coeffs[0].isNull() || coeffs[1].isNull())
-  {
-    return Node::null();
-  }
-
-  Node coeff = nm->mkNode(BITVECTOR_SUB, coeffs[0], coeffs[1]);
-  coeff = Rewriter::rewrite(coeff);
-  std::vector<Node> mult_children = {pv, coeff};
-  Node lhs = normalizePvMult(pv, mult_children, contains_pv);
-
-  Node rhs;
-  if (!leafs[0].isNull() && !leafs[1].isNull())
-  {
-    rhs = nm->mkNode(BITVECTOR_SUB, leafs[1], leafs[0]);
-  }
-  else if (!leafs[0].isNull())
-  {
-    rhs = nm->mkNode(BITVECTOR_NEG, leafs[0]);
-  }
-  else if (!leafs[1].isNull())
-  {
-    rhs = leafs[1];
-  }
-  else
-  {
-    rhs = bv::utils::mkZero(bv::utils::getSize(pv));
-  }
-  rhs = Rewriter::rewrite(rhs);
-
-  if (lhs == rhs)
-  {
-    return bv::utils::mkTrue();
-  }
-
-  Node result = lhs.eqNode(rhs);
-  contains_pv[result] = true;
-  return result;
-}
-
-Node BvInstantiator::rewriteTermForSolvePv(
-    Node pv,
-    Node n,
-    std::vector<Node>& children,
-    std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv)
-{
-  NodeManager* nm = NodeManager::currentNM();
-
-  // [1] rewrite cases of non-invertible operators
-
-  if (n.getKind() == EQUAL)
-  {
-    TNode lhs = children[0];
-    TNode rhs = children[1];
-
-    /* rewrite: x * x = x -> x < 2 */
-    if ((lhs == pv && rhs.getKind() == BITVECTOR_MULT && rhs[0] == pv
-         && rhs[1] == pv)
-        || (rhs == pv && lhs.getKind() == BITVECTOR_MULT && lhs[0] == pv
-            && lhs[1] == pv))
-    {
-      return nm->mkNode(
-          BITVECTOR_ULT,
-          pv,
-          bv::utils::mkConst(BitVector(bv::utils::getSize(pv), Integer(2))));
-    }
-
-    if (options::cbqiBvLinearize() && contains_pv[lhs] && contains_pv[rhs])
-    {
-      Node result = normalizePvEqual(pv, children, contains_pv);
-      if (!result.isNull())
-      {
-        Trace("cegqi-bv-nl")
-            << "Normalize " << n << " to " << result << std::endl;
-      }
-      else
-      {
-        Trace("cegqi-bv-nl")
-            << "Nonlinear " << n.getKind() << " " << n << std::endl;
-      }
-      return result;
-    }
-  }
-  else if (n.getKind() == BITVECTOR_MULT || n.getKind() == BITVECTOR_PLUS)
-  {
-    if (options::cbqiBvLinearize() && contains_pv[n])
-    {
-      Node result;
-      if (n.getKind() == BITVECTOR_MULT)
-      {
-        result = normalizePvMult(pv, children, contains_pv);
-      }
-      else
-      {
-        result = normalizePvPlus(pv, children, contains_pv);
-      }
-      if (!result.isNull())
-      {
-        Trace("cegqi-bv-nl")
-            << "Normalize " << n << " to " << result << std::endl;
-        return result;
-      }
-      else
-      {
-        Trace("cegqi-bv-nl")
-            << "Nonlinear " << n.getKind() << " " << n << std::endl;
-      }
-    }
-  }
-
-  // [2] try to rewrite non-linear literals -> linear literals
-
-  return Node::null();
-}
-
-/** sort bv extract interval
- *
- * This sorts lists of bitvector extract terms where
- * ((_ extract i1 i2) t) < ((_ extract j1 j2) t)
- * if i1>j1 or i1=j1 and i2>j2.
- */
-struct SortBvExtractInterval
-{
-  bool operator()(Node i, Node j)
-  {
-    Assert(i.getKind() == BITVECTOR_EXTRACT);
-    Assert(j.getKind() == BITVECTOR_EXTRACT);
-    BitVectorExtract ie = i.getOperator().getConst<BitVectorExtract>();
-    BitVectorExtract je = j.getOperator().getConst<BitVectorExtract>();
-    if (ie.high > je.high)
-    {
-      return true;
-    }
-    else if (ie.high == je.high)
-    {
-      Assert(ie.low != je.low);
-      return ie.low > je.low;
-    }
-    return false;
-  }
-};
-
-void BvInstantiatorPreprocess::registerCounterexampleLemma(
-    std::vector<Node>& lems, std::vector<Node>& ce_vars)
-{
-  // new variables
-  std::vector<Node> vars;
-  // new lemmas
-  std::vector<Node> new_lems;
-
-  if (options::cbqiBvRmExtract())
-  {
-    NodeManager* nm = NodeManager::currentNM();
-    Trace("cegqi-bv-pp") << "-----remove extracts..." << std::endl;
-    // map from terms to bitvector extracts applied to that term
-    std::map<Node, std::vector<Node> > extract_map;
-    std::unordered_set<TNode, TNodeHashFunction> visited;
-    for (unsigned i = 0, size = lems.size(); i < size; i++)
-    {
-      Trace("cegqi-bv-pp-debug2") << "Register ce lemma # " << i << " : "
-                                  << lems[i] << std::endl;
-      collectExtracts(lems[i], extract_map, visited);
-    }
-    for (std::pair<const Node, std::vector<Node> >& es : extract_map)
-    {
-      // sort based on the extract start position
-      std::vector<Node>& curr_vec = es.second;
-
-      SortBvExtractInterval sbei;
-      std::sort(curr_vec.begin(), curr_vec.end(), sbei);
-
-      unsigned width = es.first.getType().getBitVectorSize();
-
-      // list of points b such that:
-      //   b>0 and we must start a segment at (b-1)  or  b==0
-      std::vector<unsigned> boundaries;
-      boundaries.push_back(width);
-      boundaries.push_back(0);
-
-      Trace("cegqi-bv-pp") << "For term " << es.first << " : " << std::endl;
-      for (unsigned i = 0, size = curr_vec.size(); i < size; i++)
-      {
-        Trace("cegqi-bv-pp") << "  " << i << " : " << curr_vec[i] << std::endl;
-        BitVectorExtract e =
-            curr_vec[i].getOperator().getConst<BitVectorExtract>();
-        if (std::find(boundaries.begin(), boundaries.end(), e.high + 1)
-            == boundaries.end())
-        {
-          boundaries.push_back(e.high + 1);
-        }
-        if (std::find(boundaries.begin(), boundaries.end(), e.low)
-            == boundaries.end())
-        {
-          boundaries.push_back(e.low);
-        }
-      }
-      std::sort(boundaries.rbegin(), boundaries.rend());
-
-      // make the extract variables
-      std::vector<Node> children;
-      for (unsigned i = 1; i < boundaries.size(); i++)
-      {
-        Assert(boundaries[i - 1] > 0);
-        Node ex = bv::utils::mkExtract(
-            es.first, boundaries[i - 1] - 1, boundaries[i]);
-        Node var =
-            nm->mkSkolem("ek",
-                         ex.getType(),
-                         "variable to represent disjoint extract region");
-        children.push_back(var);
-        vars.push_back(var);
-      }
-
-      Node conc = nm->mkNode(kind::BITVECTOR_CONCAT, children);
-      Assert(conc.getType() == es.first.getType());
-      Node eq_lem = conc.eqNode(es.first);
-      Trace("cegqi-bv-pp") << "Introduced : " << eq_lem << std::endl;
-      new_lems.push_back(eq_lem);
-      Trace("cegqi-bv-pp") << "...finished processing extracts for term "
-                            << es.first << std::endl;
-    }
-    Trace("cegqi-bv-pp") << "-----done remove extracts" << std::endl;
-  }
-
-  if (!vars.empty())
-  {
-    // could try applying subs -> vars here
-    // in practice, this led to worse performance
-
-    Trace("cegqi-bv-pp") << "Adding " << new_lems.size() << " lemmas..."
-                         << std::endl;
-    lems.insert(lems.end(), new_lems.begin(), new_lems.end());
-    Trace("cegqi-bv-pp") << "Adding " << vars.size() << " variables..."
-                         << std::endl;
-    ce_vars.insert(ce_vars.end(), vars.begin(), vars.end());
-  }
-}
-
-void BvInstantiatorPreprocess::collectExtracts(
-    Node lem,
-    std::map<Node, std::vector<Node> >& extract_map,
-    std::unordered_set<TNode, TNodeHashFunction>& visited)
-{
-  std::vector<TNode> visit;
-  TNode cur;
-  visit.push_back(lem);
-  do
-  {
-    cur = visit.back();
-    visit.pop_back();
-    if (visited.find(cur) == visited.end())
-    {
-      visited.insert(cur);
-      if (cur.getKind() != FORALL)
-      {
-        if (cur.getKind() == BITVECTOR_EXTRACT)
-        {
-          extract_map[cur[0]].push_back(cur);
-        }
-
-        for (const Node& nc : cur)
-        {
-          visit.push_back(nc);
-        }
-      }
-    }
-  } while (!visit.empty());
-}
-
-} /* CVC4::theory::quantifiers namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/ceg_t_instantiator.h b/src/theory/quantifiers/ceg_t_instantiator.h
deleted file mode 100644 (file)
index 95295d2..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-/*********************                                                        */
-/*! \file ceg_t_instantiator.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief theory-specific counterexample-guided quantifier instantiation
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__CEG_T_INSTANTIATOR_H
-#define __CVC4__CEG_T_INSTANTIATOR_H
-
-#include "theory/quantifiers/bv_inverter.h"
-#include "theory/quantifiers/ceg_instantiator.h"
-
-#include <unordered_set>
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-/** TODO (#1367) : document these classes, also move to separate files. */
-
-class ArithInstantiator : public Instantiator {
- public:
-  ArithInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){}
-  virtual ~ArithInstantiator(){}
-  virtual void reset(CegInstantiator* ci,
-                     SolvedForm& sf,
-                     Node pv,
-                     CegInstEffort effort) override;
-  virtual bool hasProcessEquality(CegInstantiator* ci,
-                                  SolvedForm& sf,
-                                  Node pv,
-                                  CegInstEffort effort) override
-  {
-    return true;
-  }
-  virtual bool processEquality(CegInstantiator* ci,
-                               SolvedForm& sf,
-                               Node pv,
-                               std::vector<TermProperties>& term_props,
-                               std::vector<Node>& terms,
-                               CegInstEffort effort) override;
-  virtual bool hasProcessAssertion(CegInstantiator* ci,
-                                   SolvedForm& sf,
-                                   Node pv,
-                                   CegInstEffort effort) override
-  {
-    return true;
-  }
-  virtual Node hasProcessAssertion(CegInstantiator* ci,
-                                   SolvedForm& sf,
-                                   Node pv,
-                                   Node lit,
-                                   CegInstEffort effort) override;
-  virtual bool processAssertion(CegInstantiator* ci,
-                                SolvedForm& sf,
-                                Node pv,
-                                Node lit,
-                                Node alit,
-                                CegInstEffort effort) override;
-  virtual bool processAssertions(CegInstantiator* ci,
-                                 SolvedForm& sf,
-                                 Node pv,
-                                 CegInstEffort effort) override;
-  virtual bool needsPostProcessInstantiationForVariable(
-      CegInstantiator* ci,
-      SolvedForm& sf,
-      Node pv,
-      CegInstEffort effort) override;
-  virtual bool postProcessInstantiationForVariable(
-      CegInstantiator* ci,
-      SolvedForm& sf,
-      Node pv,
-      CegInstEffort effort,
-      std::vector<Node>& lemmas) override;
-  virtual std::string identify() const override { return "Arith"; }
- private:
-  Node d_vts_sym[2];
-  std::vector<Node> d_mbp_bounds[2];
-  std::vector<Node> d_mbp_coeff[2];
-  std::vector<Node> d_mbp_vts_coeff[2][2];
-  std::vector<Node> d_mbp_lit[2];
-  int solve_arith(CegInstantiator* ci,
-                  Node v,
-                  Node atom,
-                  Node& veq_c,
-                  Node& val,
-                  Node& vts_coeff_inf,
-                  Node& vts_coeff_delta);
-  Node getModelBasedProjectionValue(CegInstantiator* ci,
-                                    Node e,
-                                    Node t,
-                                    bool isLower,
-                                    Node c,
-                                    Node me,
-                                    Node mt,
-                                    Node theta,
-                                    Node inf_coeff,
-                                    Node delta_coeff);
-};
-
-class DtInstantiator : public Instantiator {
-public:
-  DtInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){}
-  virtual ~DtInstantiator(){}
-  virtual void reset(CegInstantiator* ci,
-                     SolvedForm& sf,
-                     Node pv,
-                     CegInstEffort effort) override;
-  virtual bool processEqualTerms(CegInstantiator* ci,
-                                 SolvedForm& sf,
-                                 Node pv,
-                                 std::vector<Node>& eqc,
-                                 CegInstEffort effort) override;
-  virtual bool hasProcessEquality(CegInstantiator* ci,
-                                  SolvedForm& sf,
-                                  Node pv,
-                                  CegInstEffort effort) override
-  {
-    return true;
-  }
-  virtual bool processEquality(CegInstantiator* ci,
-                               SolvedForm& sf,
-                               Node pv,
-                               std::vector<TermProperties>& term_props,
-                               std::vector<Node>& terms,
-                               CegInstEffort effort) override;
-  virtual std::string identify() const override { return "Dt"; }
- private:
-  Node solve_dt(Node v, Node a, Node b, Node sa, Node sb);
-};
-
-class TermArgTrie;
-
-class EprInstantiator : public Instantiator {
- public:
-  EprInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){}
-  virtual ~EprInstantiator(){}
-  virtual void reset(CegInstantiator* ci,
-                     SolvedForm& sf,
-                     Node pv,
-                     CegInstEffort effort) override;
-  virtual bool processEqualTerm(CegInstantiator* ci,
-                                SolvedForm& sf,
-                                Node pv,
-                                TermProperties& pv_prop,
-                                Node n,
-                                CegInstEffort effort) override;
-  virtual bool processEqualTerms(CegInstantiator* ci,
-                                 SolvedForm& sf,
-                                 Node pv,
-                                 std::vector<Node>& eqc,
-                                 CegInstEffort effort) override;
-  virtual std::string identify() const override { return "Epr"; }
- private:
-  std::vector<Node> d_equal_terms;
-  void computeMatchScore(CegInstantiator* ci,
-                         Node pv,
-                         Node catom,
-                         std::vector<Node>& arg_reps,
-                         TermArgTrie* tat,
-                         unsigned index,
-                         std::map<Node, int>& match_score);
-  void computeMatchScore(CegInstantiator* ci,
-                         Node pv,
-                         Node catom,
-                         Node eqc,
-                         std::map<Node, int>& match_score);
-};
-
-/** Bitvector instantiator
- *
- * This implements an approach for counterexample-guided instantiation
- * for bit-vector variables based on word-level inversions.
- * It is enabled by --cbqi-bv.
- */
-class BvInstantiator : public Instantiator {
- public:
-  BvInstantiator(QuantifiersEngine* qe, TypeNode tn);
-  ~BvInstantiator() override;
-  void reset(CegInstantiator* ci,
-             SolvedForm& sf,
-             Node pv,
-             CegInstEffort effort) override;
-  bool hasProcessAssertion(CegInstantiator* ci,
-                           SolvedForm& sf,
-                           Node pv,
-                           CegInstEffort effort) override
-  {
-    return true;
-  }
-  Node hasProcessAssertion(CegInstantiator* ci,
-                           SolvedForm& sf,
-                           Node pv,
-                           Node lit,
-                           CegInstEffort effort) override;
-  bool processAssertion(CegInstantiator* ci,
-                        SolvedForm& sf,
-                        Node pv,
-                        Node lit,
-                        Node alit,
-                        CegInstEffort effort) override;
-  bool processAssertions(CegInstantiator* ci,
-                         SolvedForm& sf,
-                         Node pv,
-                         CegInstEffort effort) override;
-  /** use model value
-   *
-   * We allow model values if we have not already tried an assertion,
-   * and only at levels below full if cbqiFullEffort is false.
-   */
-  bool useModelValue(CegInstantiator* ci,
-                     SolvedForm& sf,
-                     Node pv,
-                     CegInstEffort effort) override;
-  std::string identify() const override { return "Bv"; }
-
- private:
-  // point to the bv inverter class
-  BvInverter * d_inverter;
-  unsigned d_inst_id_counter;
-  /** information about solved forms */
-  std::unordered_map< Node, std::vector< unsigned >, NodeHashFunction > d_var_to_inst_id;
-  std::unordered_map< unsigned, Node > d_inst_id_to_term;
-  std::unordered_map<unsigned, Node> d_inst_id_to_alit;
-  // variable to current id we are processing
-  std::unordered_map< Node, unsigned, NodeHashFunction > d_var_to_curr_inst_id;
-  /** the amount of slack we added for asserted literals */
-  std::unordered_map<Node, Node, NodeHashFunction> d_alit_to_model_slack;
-  /** whether we have tried an instantiation based on assertion in this round */
-  bool d_tried_assertion_inst;
-  /** rewrite assertion for solve pv
-  * returns a literal that is equivalent to lit that leads to best solved form for pv
-  */
-  Node rewriteAssertionForSolvePv(CegInstantiator* ci, Node pv, Node lit);
-  /** rewrite term for solve pv
-   * This is a helper function for rewriteAssertionForSolvePv.
-   * If this returns non-null value ret, then this indicates
-   * that n should be rewritten to ret. It is called as
-   * a "post-rewrite", that is, after the children of n
-   * have been rewritten and stored in the vector children.
-   *
-   * contains_pv stores whether certain nodes contain pv.
-   * where we guarantee that all subterms of terms in children
-   * appear in the domain of contains_pv.
-   */
-  Node rewriteTermForSolvePv(
-      Node pv,
-      Node n,
-      std::vector<Node>& children,
-      std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv);
-  /** process literal, called from processAssertion
-  * lit is the literal to solve for pv that has been rewritten according to
-  * internal rules here.
-  * alit is the asserted literal that lit is derived from.
-  */
-  void processLiteral(CegInstantiator* ci,
-                      SolvedForm& sf,
-                      Node pv,
-                      Node lit,
-                      Node alit,
-                      CegInstEffort effort);
-};
-
-/** Bitvector instantiator preprocess
- *
- * This class implements preprocess techniques that are helpful for
- * counterexample-guided instantiation, such as introducing variables
- * that refer to disjoint bit-vector extracts.
- */
-class BvInstantiatorPreprocess : public InstantiatorPreprocess
-{
- public:
-  BvInstantiatorPreprocess() {}
-  ~BvInstantiatorPreprocess() override {}
-  /** register counterexample lemma
-   *
-   * This method modifies the contents of lems based on the extract terms
-   * it contains when the option --cbqi-bv-rm-extract is enabled. It introduces
-   * a dummy equality so that segments of terms t under extracts can be solved
-   * independently.
-   *
-   * For example:
-   *   P[ ((extract 7 4) t), ((extract 3 0) t)]
-   *     becomes:
-   *   P[((extract 7 4) t), ((extract 3 0) t)] ^
-   *   t = concat( x74, x30 )
-   * where x74 and x30 are fresh variables of type BV_4.
-   *
-   * Another example:
-   *   P[ ((extract 7 3) t), ((extract 4 0) t)]
-   *     becomes:
-   *   P[((extract 7 4) t), ((extract 3 0) t)] ^
-   *   t = concat( x75, x44, x30 )
-   * where x75, x44 and x30 are fresh variables of type BV_3, BV_1, and BV_4
-   * respectively.
-   *
-   * Notice we leave the original conjecture alone. This is done for performance
-   * since the added equalities ensure we are able to construct the proper
-   * solved forms for variables in t and for the intermediate variables above.
-   */
-  void registerCounterexampleLemma(std::vector<Node>& lems,
-                                   std::vector<Node>& ce_vars) override;
-
- private:
-  /** collect extracts
-   *
-   * This method collects all extract terms in lem
-   * and stores them in d_extract_map.
-   * visited is the terms we've already visited.
-   */
-  void collectExtracts(Node lem,
-                       std::map<Node, std::vector<Node> >& extract_map,
-                       std::unordered_set<TNode, TNodeHashFunction>& visited);
-};
-
-} /* CVC4::theory::quantifiers namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
-
-#endif
diff --git a/src/theory/quantifiers/cegqi/ceg_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_instantiator.cpp
new file mode 100644 (file)
index 0000000..d7d46bb
--- /dev/null
@@ -0,0 +1,1337 @@
+/*********************                                                        */
+/*! \file ceg_instantiator.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of counterexample-guided quantifier instantiation
+ **/
+
+#include "theory/quantifiers/cegqi/ceg_instantiator.h"
+#include "theory/quantifiers/cegqi/ceg_t_instantiator.h"
+
+#include "options/quantifiers_options.h"
+#include "smt/term_formula_removal.h"
+#include "theory/arith/arith_msum.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/quantifiers_rewriter.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_enumeration.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers/ematching/trigger.h"
+#include "theory/theory_engine.h"
+
+using namespace std;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+std::ostream& operator<<(std::ostream& os, CegInstEffort e)
+{
+  switch (e)
+  {
+    case CEG_INST_EFFORT_NONE: os << "?"; break;
+    case CEG_INST_EFFORT_STANDARD: os << "STANDARD"; break;
+    case CEG_INST_EFFORT_STANDARD_MV: os << "STANDARD_MV"; break;
+    case CEG_INST_EFFORT_FULL: os << "FULL"; break;
+    default: Unreachable();
+  }
+  return os;
+}
+
+std::ostream& operator<<(std::ostream& os, CegInstPhase phase)
+{
+  switch (phase)
+  {
+    case CEG_INST_PHASE_NONE: os << "?"; break;
+    case CEG_INST_PHASE_EQC: os << "eqc"; break;
+    case CEG_INST_PHASE_EQUAL: os << "eq"; break;
+    case CEG_INST_PHASE_ASSERTION: os << "as"; break;
+    case CEG_INST_PHASE_MVALUE: os << "mv"; break;
+    default: Unreachable();
+  }
+  return os;
+}
+
+CegInstantiator::CegInstantiator(QuantifiersEngine* qe,
+                                 CegqiOutput* out,
+                                 bool use_vts_delta,
+                                 bool use_vts_inf)
+    : d_qe(qe),
+      d_out(out),
+      d_use_vts_delta(use_vts_delta),
+      d_use_vts_inf(use_vts_inf),
+      d_is_nested_quant(false),
+      d_effort(CEG_INST_EFFORT_NONE)
+{
+}
+
+CegInstantiator::~CegInstantiator() {
+  for (std::pair<Node, Instantiator*> inst : d_instantiator)
+  {
+    delete inst.second;
+  }
+  for (std::pair<TheoryId, InstantiatorPreprocess*> instp : d_tipp)
+  {
+    delete instp.second;
+  }
+}
+
+void CegInstantiator::computeProgVars( Node n ){
+  if( d_prog_var.find( n )==d_prog_var.end() ){
+    d_prog_var[n].clear();
+    if (n.getKind() == kind::CHOICE)
+    {
+      Assert(d_prog_var.find(n[0][0]) == d_prog_var.end());
+      d_prog_var[n[0][0]].clear();
+    }
+    if (d_vars_set.find(n) != d_vars_set.end())
+    {
+      d_prog_var[n].insert(n);
+    }else if( !d_out->isEligibleForInstantiation( n ) ){
+      d_inelig.insert(n);
+      return;
+    }
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      computeProgVars( n[i] );
+      if( d_inelig.find( n[i] )!=d_inelig.end() ){
+        d_inelig.insert(n);
+      }
+      // all variables in child are contained in this
+      d_prog_var[n].insert(d_prog_var[n[i]].begin(), d_prog_var[n[i]].end());
+    }
+    // selectors applied to program variables are also variables
+    if (n.getKind() == APPLY_SELECTOR_TOTAL
+        && d_prog_var[n].find(n[0]) != d_prog_var[n].end())
+    {
+      d_prog_var[n].insert(n);
+    }
+    if (n.getKind() == kind::CHOICE)
+    {
+      d_prog_var.erase(n[0][0]);
+    }
+  }
+}
+
+bool CegInstantiator::isEligible( Node n ) {
+  //compute d_subs_fv, which program variables are contained in n, and determines if eligible
+  computeProgVars( n );
+  return d_inelig.find( n )==d_inelig.end();
+}
+
+bool CegInstantiator::hasVariable( Node n, Node pv ) {
+  computeProgVars( n );
+  return d_prog_var[n].find( pv )!=d_prog_var[n].end();
+}
+
+void CegInstantiator::activateInstantiationVariable(Node v, unsigned index)
+{
+  if( d_instantiator.find( v )==d_instantiator.end() ){
+    TypeNode tn = v.getType();
+    Instantiator * vinst;
+    if( tn.isReal() ){
+      vinst = new ArithInstantiator( d_qe, tn );
+    }else if( tn.isSort() ){
+      Assert( options::quantEpr() );
+      vinst = new EprInstantiator( d_qe, tn );
+    }else if( tn.isDatatype() ){
+      vinst = new DtInstantiator( d_qe, tn );
+    }else if( tn.isBitVector() ){
+      vinst = new BvInstantiator( d_qe, tn );
+    }else if( tn.isBoolean() ){
+      vinst = new ModelValueInstantiator( d_qe, tn );
+    }else{
+      //default
+      vinst = new Instantiator( d_qe, tn );
+    }
+    d_instantiator[v] = vinst;
+  }
+  d_curr_subs_proc[v].clear();
+  d_curr_index[v] = index;
+  d_curr_iphase[v] = CEG_INST_PHASE_NONE;
+}
+
+void CegInstantiator::registerTheoryIds(TypeNode tn,
+                                        std::map<TypeNode, bool>& visited)
+{
+  if (visited.find(tn) == visited.end())
+  {
+    visited[tn] = true;
+    TheoryId tid = Theory::theoryOf(tn);
+    registerTheoryId(tid);
+    if (tn.isDatatype())
+    {
+      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+      for (unsigned i = 0; i < dt.getNumConstructors(); i++)
+      {
+        for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
+        {
+          registerTheoryIds(
+              TypeNode::fromType(
+                  ((SelectorType)dt[i][j].getType()).getRangeType()),
+              visited);
+        }
+      }
+    }
+  }
+}
+
+void CegInstantiator::registerTheoryId(TheoryId tid)
+{
+  if (std::find(d_tids.begin(), d_tids.end(), tid) == d_tids.end())
+  {
+    // setup any theory-specific preprocessors here
+    if (tid == THEORY_BV)
+    {
+      d_tipp[tid] = new BvInstantiatorPreprocess;
+    }
+    d_tids.push_back(tid);
+  }
+}
+
+void CegInstantiator::registerVariable(Node v, bool is_aux)
+{
+  Assert(std::find(d_vars.begin(), d_vars.end(), v) == d_vars.end());
+  Assert(std::find(d_aux_vars.begin(), d_aux_vars.end(), v)
+         == d_aux_vars.end());
+  if (!is_aux)
+  {
+    d_vars.push_back(v);
+    d_vars_set.insert(v);
+  }
+  else
+  {
+    d_aux_vars.push_back(v);
+  }
+  TypeNode vtn = v.getType();
+  Trace("cbqi-proc-debug") << "Collect theory ids from type " << vtn << " of "
+                           << v << std::endl;
+  // collect relevant theories for this variable
+  std::map<TypeNode, bool> visited;
+  registerTheoryIds(vtn, visited);
+}
+
+void CegInstantiator::deactivateInstantiationVariable(Node v)
+{
+  d_curr_subs_proc.erase( v );
+  d_curr_index.erase( v );
+  d_curr_iphase.erase(v);
+}
+
+bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i)
+{
+  if( i==d_vars.size() ){
+    //solved for all variables, now construct instantiation
+    bool needsPostprocess =
+        sf.d_vars.size() > d_input_vars.size() || !d_var_order_index.empty();
+    std::vector< Instantiator * > pp_inst;
+    std::map< Instantiator *, Node > pp_inst_to_var;
+    std::vector< Node > lemmas;
+    for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){
+      if (ita->second->needsPostProcessInstantiationForVariable(
+              this, sf, ita->first, d_effort))
+      {
+        needsPostprocess = true;
+        pp_inst_to_var[ ita->second ] = ita->first;
+      }
+    }
+    if( needsPostprocess ){
+      //must make copy so that backtracking reverts sf
+      SolvedForm sf_tmp = sf;
+      bool postProcessSuccess = true;
+      for( std::map< Instantiator *, Node >::iterator itp = pp_inst_to_var.begin(); itp != pp_inst_to_var.end(); ++itp ){
+        if (!itp->first->postProcessInstantiationForVariable(
+                this, sf_tmp, itp->second, d_effort, lemmas))
+        {
+          postProcessSuccess = false;
+          break;
+        }
+      }
+      if( postProcessSuccess ){
+        return doAddInstantiation( sf_tmp.d_vars, sf_tmp.d_subs, lemmas );
+      }else{
+        return false;
+      }
+    }else{
+      return doAddInstantiation( sf.d_vars, sf.d_subs, lemmas );
+    }
+  }else{
+    //Node v = d_single_inv_map_to_prog[d_single_inv[0][i]];
+    bool is_cv = false;
+    Node pv;
+    if( d_stack_vars.empty() ){
+      pv = d_vars[i];
+    }else{
+      pv = d_stack_vars.back();
+      is_cv = true;
+      d_stack_vars.pop_back();
+    }
+    activateInstantiationVariable(pv, i);
+
+    //get the instantiator object
+    Instantiator * vinst = NULL;
+    std::map< Node, Instantiator * >::iterator itin = d_instantiator.find( pv );
+    if( itin!=d_instantiator.end() ){
+      vinst = itin->second;
+    }
+    Assert( vinst!=NULL );
+    d_active_instantiators[pv] = vinst;
+    vinst->reset(this, sf, pv, d_effort);
+
+    TypeNode pvtn = pv.getType();
+    TypeNode pvtnb = pvtn.getBaseType();
+    Node pvr = pv;
+    if( d_qe->getMasterEqualityEngine()->hasTerm( pv ) ){
+      pvr = d_qe->getMasterEqualityEngine()->getRepresentative( pv );
+    }
+    Trace("cbqi-inst-debug") << "[Find instantiation for " << pv << "], rep=" << pvr << ", instantiator is " << vinst->identify() << std::endl;
+    Node pv_value;
+    if( options::cbqiModel() ){
+      pv_value = getModelValue( pv );
+      Trace("cbqi-bound2") << "...M( " << pv << " ) = " << pv_value << std::endl;
+    }
+
+    // if d_effort is full, we must choose at least one model value
+    if ((i + 1) < d_vars.size() || d_effort != CEG_INST_EFFORT_FULL)
+    {
+      //[1] easy case : pv is in the equivalence class as another term not containing pv
+      Trace("cbqi-inst-debug") << "[1] try based on equivalence class." << std::endl;
+      d_curr_iphase[pv] = CEG_INST_PHASE_EQC;
+      std::map< Node, std::vector< Node > >::iterator it_eqc = d_curr_eqc.find( pvr );
+      if( it_eqc!=d_curr_eqc.end() ){
+        //std::vector< Node > eq_candidates;
+        Trace("cbqi-inst-debug2") << "...eqc has size " << it_eqc->second.size() << std::endl;
+        for( unsigned k=0; k<it_eqc->second.size(); k++ ){
+          Node n = it_eqc->second[k];
+          if( n!=pv ){
+            Trace("cbqi-inst-debug") << "...try based on equal term " << n << std::endl;
+            //must be an eligible term
+            if( isEligible( n ) ){
+              Node ns;
+              TermProperties pv_prop;  //coefficient of pv in the equality we solve (null is 1)
+              bool proc = false;
+              if( !d_prog_var[n].empty() ){
+                ns = applySubstitution( pvtn, n, sf, pv_prop, false );
+                if( !ns.isNull() ){
+                  computeProgVars( ns );
+                  //substituted version must be new and cannot contain pv
+                  proc = d_prog_var[ns].find( pv )==d_prog_var[ns].end();
+                }
+              }else{
+                ns = n;
+                proc = true;
+              }
+              if( proc ){
+                if (vinst->processEqualTerm(
+                        this, sf, pv, pv_prop, ns, d_effort))
+                {
+                  return true;
+                }
+                // Do not consider more than one equal term,
+                // this helps non-monotonic strategies that may encounter
+                // duplicate instantiations.
+                break;
+              }
+            }
+          }
+        }
+        if (vinst->processEqualTerms(this, sf, pv, it_eqc->second, d_effort))
+        {
+          return true;
+        }
+      }else{
+        Trace("cbqi-inst-debug2") << "...eqc not found." << std::endl;
+      }
+
+      //[2] : we can solve an equality for pv
+      /// iterate over equivalence classes to find cases where we can solve for
+      /// the variable
+      if (vinst->hasProcessEquality(this, sf, pv, d_effort))
+      {
+        Trace("cbqi-inst-debug") << "[2] try based on solving equalities." << std::endl;
+        d_curr_iphase[pv] = CEG_INST_PHASE_EQUAL;
+        for( unsigned k=0; k<d_curr_type_eqc[pvtnb].size(); k++ ){
+          Node r = d_curr_type_eqc[pvtnb][k];
+          std::map< Node, std::vector< Node > >::iterator it_reqc = d_curr_eqc.find( r );
+          std::vector< Node > lhs;
+          std::vector< bool > lhs_v;
+          std::vector< TermProperties > lhs_prop;
+          Assert( it_reqc!=d_curr_eqc.end() );
+          for( unsigned kk=0; kk<it_reqc->second.size(); kk++ ){
+            Node n = it_reqc->second[kk];
+            Trace("cbqi-inst-debug2") << "...look at term " << n << std::endl;
+            //must be an eligible term
+            if( isEligible( n ) ){
+              Node ns;
+              TermProperties pv_prop;
+              if( !d_prog_var[n].empty() ){
+                ns = applySubstitution( pvtn, n, sf, pv_prop );
+                if( !ns.isNull() ){
+                  computeProgVars( ns );
+                }
+              }else{
+                ns = n;
+              }
+              if( !ns.isNull() ){
+                bool hasVar = d_prog_var[ns].find( pv )!=d_prog_var[ns].end();
+                Trace("cbqi-inst-debug2") << "... " << ns << " has var " << pv << " : " << hasVar << std::endl;
+                std::vector< TermProperties > term_props;
+                std::vector< Node > terms;
+                term_props.push_back( pv_prop );
+                terms.push_back( ns );
+                for( unsigned j=0; j<lhs.size(); j++ ){
+                  //if this term or the another has pv in it, try to solve for it
+                  if( hasVar || lhs_v[j] ){
+                    Trace("cbqi-inst-debug") << "... " << i << "...try based on equality " << lhs[j] << " = " << ns << std::endl;
+                    term_props.push_back( lhs_prop[j] );
+                    terms.push_back( lhs[j] );
+                    if (vinst->processEquality(
+                            this, sf, pv, term_props, terms, d_effort))
+                    {
+                      return true;
+                    }
+                    term_props.pop_back();
+                    terms.pop_back();
+                  }
+                }
+                lhs.push_back( ns );
+                lhs_v.push_back( hasVar );
+                lhs_prop.push_back( pv_prop );
+              }else{
+                Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible after substitution." << std::endl;
+              }
+            }else{
+              Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible." << std::endl;
+            }
+          }
+        }
+      }
+
+      //[3] directly look at assertions
+      if (vinst->hasProcessAssertion(this, sf, pv, d_effort))
+      {
+        Trace("cbqi-inst-debug") << "[3] try based on assertions." << std::endl;
+        d_curr_iphase[pv] = CEG_INST_PHASE_ASSERTION;
+        std::unordered_set< Node, NodeHashFunction > lits;
+        //unsigned rmax = Theory::theoryOf( pv )==Theory::theoryOf( pv.getType() ) ? 1 : 2;
+        for( unsigned r=0; r<2; r++ ){
+          TheoryId tid = r==0 ? Theory::theoryOf( pvtn ) : THEORY_UF;
+          Trace("cbqi-inst-debug2") << "  look at assertions of " << tid << std::endl;
+          std::map< TheoryId, std::vector< Node > >::iterator ita = d_curr_asserts.find( tid );
+          if( ita!=d_curr_asserts.end() ){
+            for (unsigned j = 0; j<ita->second.size(); j++) {
+              Node lit = ita->second[j];
+              if( lits.find(lit)==lits.end() ){
+                lits.insert(lit);
+                Node plit;
+                if (options::cbqiRepeatLit() || !isSolvedAssertion(lit))
+                {
+                  plit =
+                      vinst->hasProcessAssertion(this, sf, pv, lit, d_effort);
+                }
+                if (!plit.isNull()) {
+                  Trace("cbqi-inst-debug2") << "  look at " << lit;
+                  if (plit != lit) {
+                    Trace("cbqi-inst-debug2") << "...processed to : " << plit;
+                  }
+                  Trace("cbqi-inst-debug2") << std::endl;
+                  // apply substitutions
+                  Node slit = applySubstitutionToLiteral(plit, sf);
+                  if( !slit.isNull() ){
+                    // check if contains pv
+                    if( hasVariable( slit, pv ) ){
+                      Trace("cbqi-inst-debug") << "...try based on literal "
+                                               << slit << "," << std::endl;
+                      Trace("cbqi-inst-debug") << "...from " << lit
+                                               << std::endl;
+                      if (vinst->processAssertion(
+                              this, sf, pv, slit, lit, d_effort))
+                      {
+                        return true;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+        if (vinst->processAssertions(this, sf, pv, d_effort))
+        {
+          return true;
+        }
+      }
+    }
+
+    //[4] resort to using value in model. We do so if:
+    // - if the instantiator uses model values at this effort, or
+    // - if we are solving for a subfield of a datatype (is_cv).
+    if ((vinst->useModelValue(this, sf, pv, d_effort) || is_cv)
+        && vinst->allowModelValue(this, sf, pv, d_effort))
+    {
+#ifdef CVC4_ASSERTIONS
+      if( pvtn.isReal() && options::cbqiNestedQE() && !options::cbqiAll() ){
+        Trace("cbqi-warn") << "Had to resort to model value." << std::endl;
+        Assert( false );
+      }
+#endif
+      Node mv = getModelValue( pv );
+      TermProperties pv_prop_m;
+      Trace("cbqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl;
+      d_curr_iphase[pv] = CEG_INST_PHASE_MVALUE;
+      CegInstEffort prev = d_effort;
+      if (d_effort < CEG_INST_EFFORT_STANDARD_MV)
+      {
+        // update the effort level to indicate we have used a model value
+        d_effort = CEG_INST_EFFORT_STANDARD_MV;
+      }
+      if (constructInstantiationInc(pv, mv, pv_prop_m, sf))
+      {
+        return true;
+      }
+      d_effort = prev;
+    }
+    Trace("cbqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl;
+    if( is_cv ){
+      d_stack_vars.push_back( pv );
+    }
+    d_active_instantiators.erase( pv );
+    deactivateInstantiationVariable(pv);
+    return false;
+  }
+}
+
+void CegInstantiator::pushStackVariable( Node v ) {
+  d_stack_vars.push_back( v );
+}
+
+void CegInstantiator::popStackVariable() {
+  Assert( !d_stack_vars.empty() );
+  d_stack_vars.pop_back();
+}
+
+bool CegInstantiator::constructInstantiationInc(Node pv,
+                                                Node n,
+                                                TermProperties& pv_prop,
+                                                SolvedForm& sf,
+                                                bool revertOnSuccess)
+{
+  Node cnode = pv_prop.getCacheNode();
+  if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){
+    d_curr_subs_proc[pv][n][cnode] = true;
+    if( Trace.isOn("cbqi-inst-debug") ){
+      for( unsigned j=0; j<sf.d_subs.size(); j++ ){
+        Trace("cbqi-inst-debug") << " ";
+      }
+      Trace("cbqi-inst-debug") << sf.d_subs.size() << ": (" << d_curr_iphase[pv]
+                         << ") ";
+      Node mod_pv = pv_prop.getModifiedTerm( pv );
+      Trace("cbqi-inst-debug") << mod_pv << " -> " << n << std::endl;
+      Assert( n.getType().isSubtypeOf( pv.getType() ) );
+    }
+    //must ensure variables have been computed for n
+    computeProgVars( n );
+    Assert( d_inelig.find( n )==d_inelig.end() );
+
+    //substitute into previous substitutions, when applicable
+    std::vector< Node > a_var;
+    a_var.push_back( pv );
+    std::vector< Node > a_subs;
+    a_subs.push_back( n );
+    std::vector< TermProperties > a_prop;
+    a_prop.push_back( pv_prop );
+    std::vector< Node > a_non_basic;
+    if( !pv_prop.isBasic() ){
+      a_non_basic.push_back( pv );
+    }
+    bool success = true;
+    std::map< int, Node > prev_subs;
+    std::map< int, TermProperties > prev_prop;
+    std::map< int, Node > prev_sym_subs;
+    std::vector< Node > new_non_basic;
+    Trace("cbqi-inst-debug2") << "Applying substitutions to previous substitution terms..." << std::endl;
+    for( unsigned j=0; j<sf.d_subs.size(); j++ ){
+      Trace("cbqi-inst-debug2") << "  Apply for " << sf.d_subs[j]  << std::endl;
+      Assert( d_prog_var.find( sf.d_subs[j] )!=d_prog_var.end() );
+      if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){
+        prev_subs[j] = sf.d_subs[j];
+        TNode tv = pv;
+        TNode ts = n;
+        TermProperties a_pv_prop;
+        Node new_subs = applySubstitution( sf.d_vars[j].getType(), sf.d_subs[j], a_var, a_subs, a_prop, a_non_basic, a_pv_prop, true );
+        if( !new_subs.isNull() ){
+          sf.d_subs[j] = new_subs;
+          // the substitution apply to this term resulted in a non-basic substitution relationship
+          if( !a_pv_prop.isBasic() ){
+            // we are processing:
+            //    sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n } 
+          
+            // based on the above substitution, we have:
+            //   x = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n } 
+            // is equivalent to
+            //   a_pv_prop.getModifiedTerm( x ) = new_subs
+            
+            // thus we must compose substitutions:
+            //   a_pv_prop.getModifiedTerm( sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) ) = new_subs
+            
+            prev_prop[j] = sf.d_props[j];
+            bool prev_basic = sf.d_props[j].isBasic();
+            
+            // now compose the property
+            sf.d_props[j].composeProperty( a_pv_prop );
+            
+            // if previously was basic, becomes non-basic
+            if( prev_basic && !sf.d_props[j].isBasic() ){
+              Assert( std::find( sf.d_non_basic.begin(), sf.d_non_basic.end(), sf.d_vars[j] )==sf.d_non_basic.end() );
+              new_non_basic.push_back( sf.d_vars[j] );
+              sf.d_non_basic.push_back( sf.d_vars[j] );
+            }
+          }
+          if( sf.d_subs[j]!=prev_subs[j] ){
+            computeProgVars( sf.d_subs[j] );
+            Assert( d_inelig.find( sf.d_subs[j] )==d_inelig.end() );
+          }
+          Trace("cbqi-inst-debug2") << "Subs " << j << " " << sf.d_subs[j] << std::endl;
+        }else{
+          Trace("cbqi-inst-debug2") << "...failed to apply substitution to " << sf.d_subs[j] << std::endl;
+          success = false;
+          break;
+        }
+      }else{
+        Trace("cbqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl;
+      }
+    }
+    if( success ){
+      Trace("cbqi-inst-debug2") << "Adding to vectors..." << std::endl;
+      sf.push_back( pv, n, pv_prop );
+      Trace("cbqi-inst-debug2") << "Recurse..." << std::endl;
+      unsigned i = d_curr_index[pv];
+      success = constructInstantiation(sf, d_stack_vars.empty() ? i + 1 : i);
+      if (!success || revertOnSuccess)
+      {
+        Trace("cbqi-inst-debug2") << "Removing from vectors..." << std::endl;
+        sf.pop_back( pv, n, pv_prop );
+      }
+    }
+    if (success && !revertOnSuccess)
+    {
+      return true;
+    }else{
+      Trace("cbqi-inst-debug2") << "Revert substitutions..." << std::endl;
+      //revert substitution information
+      for( std::map< int, Node >::iterator it = prev_subs.begin(); it != prev_subs.end(); it++ ){
+        sf.d_subs[it->first] = it->second;
+      }
+      for( std::map< int, TermProperties >::iterator it = prev_prop.begin(); it != prev_prop.end(); it++ ){
+        sf.d_props[it->first] = it->second;
+      }
+      for( unsigned i=0; i<new_non_basic.size(); i++ ){
+        sf.d_non_basic.pop_back();
+      }
+      return success;
+    }
+  }else{
+    //already tried this substitution
+    return false;
+  }
+}
+
+bool CegInstantiator::doAddInstantiation( std::vector< Node >& vars, std::vector< Node >& subs, std::vector< Node >& lemmas ) {
+  if (vars.size() > d_input_vars.size() || !d_var_order_index.empty())
+  {
+    Trace("cbqi-inst-debug") << "Reconstructing instantiations...." << std::endl;
+    std::map< Node, Node > subs_map;
+    for( unsigned i=0; i<subs.size(); i++ ){
+      subs_map[vars[i]] = subs[i];
+    }
+    subs.clear();
+    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
+    {
+      std::map<Node, Node>::iterator it = subs_map.find(d_input_vars[i]);
+      Assert( it!=subs_map.end() );
+      Node n = it->second;
+      Trace("cbqi-inst-debug") << "  " << d_input_vars[i] << " -> " << n
+                               << std::endl;
+      Assert(n.getType().isSubtypeOf(d_input_vars[i].getType()));
+      subs.push_back( n );
+    }
+  }
+  if (Trace.isOn("cbqi-inst"))
+  {
+    Trace("cbqi-inst") << "Ceg Instantiator produced : " << std::endl;
+    for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
+    {
+      Node v = d_input_vars[i];
+      Trace("cbqi-inst") << i << " (" << d_curr_iphase[v] << ") : " 
+                         << v << " -> " << subs[i] << std::endl;
+      Assert(subs[i].getType().isSubtypeOf(v.getType()));
+    }
+  }
+  Trace("cbqi-inst-debug") << "Do the instantiation...." << std::endl;
+  bool ret = d_out->doAddInstantiation( subs );
+  for( unsigned i=0; i<lemmas.size(); i++ ){
+    d_out->addLemma( lemmas[i] );
+  }
+  return ret;
+}
+
+bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){
+  Assert( d_prog_var.find( n )!=d_prog_var.end() );
+  if( !non_basic.empty() ){
+    for (std::unordered_set<Node, NodeHashFunction>::iterator it =
+             d_prog_var[n].begin();
+         it != d_prog_var[n].end();
+         ++it)
+    {
+      if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end())
+      {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, 
+                                         std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff ) {
+  computeProgVars( n );
+  Assert( n==Rewriter::rewrite( n ) );
+  bool is_basic = canApplyBasicSubstitution( n, non_basic );
+  if( Trace.isOn("cegqi-si-apply-subs-debug") ){
+    Trace("cegqi-si-apply-subs-debug") << "is_basic = " << is_basic << "  " << tn << std::endl;
+    for( unsigned i=0; i<subs.size(); i++ ){
+      Trace("cegqi-si-apply-subs-debug") << "  " << vars[i] << " -> " << subs[i] << "   types : " << vars[i].getType() << " -> " << subs[i].getType() << std::endl;
+      Assert( subs[i].getType().isSubtypeOf( vars[i].getType() ) );
+    }
+  }
+  Node nret;
+  if( is_basic ){
+    nret = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+  }else{
+    if( !tn.isInteger() ){
+      //can do basic substitution instead with divisions
+      std::vector< Node > nvars;
+      std::vector< Node > nsubs;
+      for( unsigned i=0; i<vars.size(); i++ ){
+        if( !prop[i].d_coeff.isNull() ){
+          Assert( vars[i].getType().isInteger() );
+          Assert( prop[i].d_coeff.isConst() );
+          Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst<Rational>() ) );
+          nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn );
+          nn =  Rewriter::rewrite( nn );
+          nsubs.push_back( nn );
+        }else{
+          nsubs.push_back( subs[i] );
+        }
+      }
+      nret = n.substitute( vars.begin(), vars.end(), nsubs.begin(), nsubs.end() );
+    }else if( try_coeff ){
+      //must convert to monomial representation
+      std::map< Node, Node > msum;
+      if (ArithMSum::getMonomialSum(n, msum))
+      {
+        std::map< Node, Node > msum_coeff;
+        std::map< Node, Node > msum_term;
+        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+          //check if in substitution
+          std::vector< Node >::iterator its = std::find( vars.begin(), vars.end(), it->first );
+          if( its!=vars.end() ){
+            int index = its-vars.begin();
+            if( prop[index].d_coeff.isNull() ){
+              //apply substitution
+              msum_term[it->first] = subs[index];
+            }else{
+              //apply substitution, multiply to ensure no divisibility conflict
+              msum_term[it->first] = subs[index];
+              //relative coefficient
+              msum_coeff[it->first] = prop[index].d_coeff;
+              if( pv_prop.d_coeff.isNull() ){
+                pv_prop.d_coeff = prop[index].d_coeff;
+              }else{
+                pv_prop.d_coeff = NodeManager::currentNM()->mkNode( MULT, pv_prop.d_coeff, prop[index].d_coeff );
+              }
+            }
+          }else{
+            msum_term[it->first] = it->first;
+          }
+        }
+        //make sum with normalized coefficient
+        if( !pv_prop.d_coeff.isNull() ){
+          pv_prop.d_coeff = Rewriter::rewrite( pv_prop.d_coeff );
+          Trace("cegqi-si-apply-subs-debug") << "Combined coeff : " << pv_prop.d_coeff << std::endl;
+          std::vector< Node > children;
+          for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+            Node c_coeff;
+            if( !msum_coeff[it->first].isNull() ){
+              c_coeff = Rewriter::rewrite( NodeManager::currentNM()->mkConst( pv_prop.d_coeff.getConst<Rational>() / msum_coeff[it->first].getConst<Rational>() ) );
+            }else{
+              c_coeff = pv_prop.d_coeff;
+            }
+            if( !it->second.isNull() ){
+              c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second );
+            }
+            Assert( !c_coeff.isNull() );
+            Node c;
+            if( msum_term[it->first].isNull() ){
+              c = c_coeff;
+            }else{
+              c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] );
+            }
+            children.push_back( c );
+            Trace("cegqi-si-apply-subs-debug") << "Add child : " << c << std::endl;
+          }
+          Node nretc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children );
+          nretc = Rewriter::rewrite( nretc );
+          //ensure that nret does not contain vars
+          if( !TermUtil::containsTerms( nretc, vars ) ){
+            //result is ( nret / pv_prop.d_coeff )
+            nret = nretc;
+          }else{
+            Trace("cegqi-si-apply-subs-debug") << "Failed, since result " << nretc << " contains free variable." << std::endl;
+          }
+        }else{
+          //implies that we have a monomial that has a free variable
+          Trace("cegqi-si-apply-subs-debug") << "Failed to find coefficient during substitution, implies monomial with free variable." << std::endl;
+        }
+      }else{
+        Trace("cegqi-si-apply-subs-debug") << "Failed to find monomial sum " << n << std::endl;
+      }
+    }
+  }
+  if( n!=nret && !nret.isNull() ){
+    nret = Rewriter::rewrite( nret );
+  }
+  return nret;
+}
+
+Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs, 
+                                                  std::vector< TermProperties >& prop, std::vector< Node >& non_basic ) {
+  computeProgVars( lit );
+  bool is_basic = canApplyBasicSubstitution( lit, non_basic );
+  Node lret;
+  if( is_basic ){
+   lret = lit.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+  }else{
+    Node atom = lit.getKind()==NOT ? lit[0] : lit;
+    bool pol = lit.getKind()!=NOT;
+    //arithmetic inequalities and disequalities
+    if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){
+      Assert( atom.getKind()!=GEQ || atom[1].isConst() );
+      Node atom_lhs;
+      Node atom_rhs;
+      if( atom.getKind()==GEQ ){
+        atom_lhs = atom[0];
+        atom_rhs = atom[1];
+      }else{
+        atom_lhs = NodeManager::currentNM()->mkNode( MINUS, atom[0], atom[1] );
+        atom_lhs = Rewriter::rewrite( atom_lhs );
+        atom_rhs = getQuantifiersEngine()->getTermUtil()->d_zero;
+      }
+      //must be an eligible term
+      if( isEligible( atom_lhs ) ){
+        //apply substitution to LHS of atom
+        TermProperties atom_lhs_prop;
+        atom_lhs = applySubstitution( NodeManager::currentNM()->realType(), atom_lhs, vars, subs, prop, non_basic, atom_lhs_prop );
+        if( !atom_lhs.isNull() ){
+          if( !atom_lhs_prop.d_coeff.isNull() ){
+            atom_rhs = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, atom_lhs_prop.d_coeff, atom_rhs ) );
+          }
+          lret = NodeManager::currentNM()->mkNode( atom.getKind(), atom_lhs, atom_rhs );
+          if( !pol ){
+            lret = lret.negate();
+          }
+        }
+      }
+    }else{
+      // don't know how to apply substitution to literal
+    }
+  }
+  if( lit!=lret && !lret.isNull() ){
+    lret = Rewriter::rewrite( lret );
+  }
+  return lret;
+}
+  
+bool CegInstantiator::check() {
+  if( d_qe->getTheoryEngine()->needCheck() ){
+    Trace("cbqi-engine") << "  CEGQI instantiator : wait until all ground theories are finished." << std::endl;
+    return false;
+  }
+  processAssertions();
+  for( unsigned r=0; r<2; r++ ){
+    d_effort = r == 0 ? CEG_INST_EFFORT_STANDARD : CEG_INST_EFFORT_FULL;
+    SolvedForm sf;
+    d_stack_vars.clear();
+    d_bound_var_index.clear();
+    d_solved_asserts.clear();
+    //try to add an instantiation
+    if (constructInstantiation(sf, 0))
+    {
+      return true;
+    }
+  }
+  Trace("cbqi-engine") << "  WARNING : unable to find CEGQI single invocation instantiation." << std::endl;
+  return false;
+}
+
+void collectPresolveEqTerms( Node n, std::map< Node, std::vector< Node > >& teq ) {
+  if( n.getKind()==FORALL || n.getKind()==EXISTS ){
+    //do nothing
+  }else{
+    if( n.getKind()==EQUAL ){
+      for( unsigned i=0; i<2; i++ ){
+        std::map< Node, std::vector< Node > >::iterator it = teq.find( n[i] );
+        if( it!=teq.end() ){
+          Node nn = n[ i==0 ? 1 : 0 ];
+          if( std::find( it->second.begin(), it->second.end(), nn )==it->second.end() ){
+            it->second.push_back( nn );
+            Trace("cbqi-presolve") << "  - " << n[i] << " = " << nn << std::endl;
+          }
+        }
+      }
+    }
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      collectPresolveEqTerms( n[i], teq );
+    }
+  }
+}
+
+void getPresolveEqConjuncts( std::vector< Node >& vars, std::vector< Node >& terms,
+                             std::map< Node, std::vector< Node > >& teq, Node f, std::vector< Node >& conj ) {
+  if( conj.size()<1000 ){
+    if( terms.size()==f[0].getNumChildren() ){
+      Node c = f[1].substitute( vars.begin(), vars.end(), terms.begin(), terms.end() );
+      conj.push_back( c );
+    }else{
+      unsigned i = terms.size();
+      Node v = f[0][i];
+      terms.push_back( Node::null() );
+      for( unsigned j=0; j<teq[v].size(); j++ ){
+        terms[i] = teq[v][j];
+        getPresolveEqConjuncts( vars, terms, teq, f, conj );
+      }
+      terms.pop_back();
+    }
+  }
+}
+
+void CegInstantiator::presolve( Node q ) {
+  //at preregister time, add proxy of obvious instantiations up front, which helps learning during preprocessing
+  //only if no nested quantifiers
+  if( !QuantifiersRewriter::containsQuantifiers( q[1] ) ){
+    std::vector< Node > ps_vars;
+    std::map< Node, std::vector< Node > > teq;
+    for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+      ps_vars.push_back( q[0][i] );
+      teq[q[0][i]].clear();
+    }
+    collectPresolveEqTerms( q[1], teq );
+    std::vector< Node > terms;
+    std::vector< Node > conj;
+    getPresolveEqConjuncts( ps_vars, terms, teq, q, conj );
+
+    if( !conj.empty() ){
+      Node lem = conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj );
+      Node g = NodeManager::currentNM()->mkSkolem( "g", NodeManager::currentNM()->booleanType() );
+      lem = NodeManager::currentNM()->mkNode( OR, g, lem );
+      Trace("cbqi-presolve-debug") << "Presolve lemma : " << lem << std::endl;
+      d_qe->getOutputChannel().lemma( lem, false, true );
+    }
+  }
+}
+
+void CegInstantiator::processAssertions() {
+  Trace("cbqi-proc") << "--- Process assertions, #var = " << d_vars.size() << ", #aux-var = " << d_aux_vars.size() << std::endl;
+  d_curr_asserts.clear();
+  d_curr_eqc.clear();
+  d_curr_type_eqc.clear();
+
+  // must use master equality engine to avoid value instantiations
+  eq::EqualityEngine* ee = d_qe->getMasterEqualityEngine();
+  //to eliminate identified illegal terms
+  std::map< Node, Node > aux_subs;
+
+  //for each variable
+  for( unsigned i=0; i<d_vars.size(); i++ ){
+    Node pv = d_vars[i];
+    TypeNode pvtn = pv.getType();
+    Trace("cbqi-proc-debug") << "Collect theory ids from type " << pvtn << " of " << pv << std::endl;
+    //collect information about eqc
+    if( ee->hasTerm( pv ) ){
+      Node pvr = ee->getRepresentative( pv );
+      if( d_curr_eqc.find( pvr )==d_curr_eqc.end() ){
+        Trace("cbqi-proc") << "Collect equivalence class " << pvr << std::endl;
+        eq::EqClassIterator eqc_i = eq::EqClassIterator( pvr, ee );
+        while( !eqc_i.isFinished() ){
+          d_curr_eqc[pvr].push_back( *eqc_i );
+          ++eqc_i;
+        }
+      }
+    }
+  }
+  //collect assertions for relevant theories
+  for( unsigned i=0; i<d_tids.size(); i++ ){
+    TheoryId tid = d_tids[i];
+    Theory* theory = d_qe->getTheoryEngine()->theoryOf( tid );
+    if( theory && d_qe->getTheoryEngine()->isTheoryEnabled(tid) ){
+      Trace("cbqi-proc") << "Collect assertions from theory " << tid << std::endl;
+      d_curr_asserts[tid].clear();
+      //collect all assertions from theory
+      for( context::CDList<Assertion>::const_iterator it = theory->facts_begin(); it != theory->facts_end(); ++ it) {
+        Node lit = (*it).assertion;
+        Node atom = lit.getKind()==NOT ? lit[0] : lit;
+        if( d_is_nested_quant || std::find( d_ce_atoms.begin(), d_ce_atoms.end(), atom )!=d_ce_atoms.end() ){
+          d_curr_asserts[tid].push_back( lit );
+          Trace("cbqi-proc-debug") << "...add : " << lit << std::endl;
+        }else{
+          Trace("cbqi-proc") << "...do not consider literal " << tid << " : " << lit << " since it is not part of CE body." << std::endl;
+        }
+        if( lit.getKind()==EQUAL ){
+          std::map< Node, std::map< Node, Node > >::iterator itae = d_aux_eq.find( lit );
+          if( itae!=d_aux_eq.end() ){
+            for( std::map< Node, Node >::iterator itae2 = itae->second.begin(); itae2 != itae->second.end(); ++itae2 ){
+              aux_subs[ itae2->first ] = itae2->second;
+              Trace("cbqi-proc") << "......add substitution : " << itae2->first << " -> " << itae2->second << std::endl;
+            }
+          }
+        }else if( atom.getKind()==BOOLEAN_TERM_VARIABLE ){
+          if( std::find( d_aux_vars.begin(), d_aux_vars.end(), atom )!=d_aux_vars.end() ){
+            Node val = NodeManager::currentNM()->mkConst( lit.getKind()!=NOT );
+            aux_subs[ atom ] = val;
+            Trace("cbqi-proc") << "......add substitution : " << atom << " -> " << val << std::endl;
+          }
+        }
+      }
+    }
+  }
+  //collect equivalence classes that correspond to relevant theories
+  Trace("cbqi-proc-debug") << "...collect typed equivalence classes" << std::endl;
+  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
+  while( !eqcs_i.isFinished() ){
+    Node r = *eqcs_i;
+    TypeNode rtn = r.getType();
+    TheoryId tid = Theory::theoryOf( rtn );
+    //if we care about the theory of this eqc
+    if( std::find( d_tids.begin(), d_tids.end(), tid )!=d_tids.end() ){
+      if( rtn.isInteger() || rtn.isReal() ){
+        rtn = rtn.getBaseType();
+      }
+      Trace("cbqi-proc-debug") << "...type eqc: " << r << std::endl;
+      d_curr_type_eqc[rtn].push_back( r );
+      if( d_curr_eqc.find( r )==d_curr_eqc.end() ){
+        Trace("cbqi-proc") << "Collect equivalence class " << r << std::endl;
+        Trace("cbqi-proc-debug") << "  ";
+        eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
+        while( !eqc_i.isFinished() ){
+          Trace("cbqi-proc-debug") << *eqc_i << " ";
+          d_curr_eqc[r].push_back( *eqc_i );
+          ++eqc_i;
+        }
+        Trace("cbqi-proc-debug") << std::endl;
+      }
+    }
+    ++eqcs_i;
+  }
+  //construct substitution from auxiliary variable equalities (if e.g. ITE removal was applied to CE body of quantified formula)
+  std::vector< Node > subs_lhs;
+  std::vector< Node > subs_rhs;
+  for( unsigned i=0; i<d_aux_vars.size(); i++ ){
+    Node r = d_aux_vars[i];
+    std::map< Node, Node >::iterator it = aux_subs.find( r );
+    if( it!=aux_subs.end() ){
+      addToAuxVarSubstitution( subs_lhs, subs_rhs, r, it->second );
+    }else{
+      Trace("cbqi-proc") << "....no substitution found for auxiliary variable " << r << "!!! type is " << r.getType() << std::endl;
+      Assert( false );
+    }
+  }
+
+  //apply substitutions to everything, if necessary
+  if( !subs_lhs.empty() ){
+    Trace("cbqi-proc") << "Applying substitution : " << std::endl;
+    for( unsigned i=0; i<subs_lhs.size(); i++ ){
+      Trace("cbqi-proc") << "  " << subs_lhs[i] << " -> " << subs_rhs[i] << std::endl;
+    }
+    for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){
+      for( unsigned i=0; i<it->second.size(); i++ ){
+        Node lit = it->second[i];
+        lit = lit.substitute( subs_lhs.begin(), subs_lhs.end(), subs_rhs.begin(), subs_rhs.end() );
+        lit = Rewriter::rewrite( lit );
+        it->second[i] = lit;
+      }
+    }
+    for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){
+      for( unsigned i=0; i<it->second.size(); i++ ){
+        Node n = it->second[i];
+        n = n.substitute( subs_lhs.begin(), subs_lhs.end(), subs_rhs.begin(), subs_rhs.end() );
+        n = Rewriter::rewrite( n  );
+        it->second[i] = n;
+      }
+    }
+  }
+
+  //remove unecessary assertions
+  for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){
+    std::vector< Node > akeep;
+    for( unsigned i=0; i<it->second.size(); i++ ){
+      Node n = it->second[i];
+      //must be an eligible term
+      if( isEligible( n ) ){
+        //must contain at least one variable
+        if( !d_prog_var[n].empty() ){
+          Trace("cbqi-proc") << "...literal[" << it->first << "] : " << n << std::endl;
+          akeep.push_back( n );
+        }else{
+          Trace("cbqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains no relevant variables." << std::endl;
+        }
+      }else{
+        Trace("cbqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains ineligible terms." << std::endl;
+      }
+    }
+    it->second.clear();
+    it->second.insert( it->second.end(), akeep.begin(), akeep.end() );
+  }
+
+  //remove duplicate terms from eqc
+  for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){
+    std::vector< Node > new_eqc;
+    for( unsigned i=0; i<it->second.size(); i++ ){
+      if( std::find( new_eqc.begin(), new_eqc.end(), it->second[i] )==new_eqc.end() ){
+        new_eqc.push_back( it->second[i] );
+      }
+    }
+    it->second.clear();
+    it->second.insert( it->second.end(), new_eqc.begin(), new_eqc.end() );
+  }
+}
+
+void CegInstantiator::addToAuxVarSubstitution( std::vector< Node >& subs_lhs, std::vector< Node >& subs_rhs, Node l, Node r ) {
+  r = r.substitute( subs_lhs.begin(), subs_lhs.end(), subs_rhs.begin(), subs_rhs.end() );
+
+  std::vector< Node > cl;
+  cl.push_back( l );
+  std::vector< Node > cr;
+  cr.push_back( r );
+  for( unsigned i=0; i<subs_lhs.size(); i++ ){
+    Node nr = subs_rhs[i].substitute( cl.begin(), cl.end(), cr.begin(), cr.end() );
+    nr = Rewriter::rewrite( nr );
+    subs_rhs[i] = nr;
+  }
+
+  subs_lhs.push_back( l );
+  subs_rhs.push_back( r );
+}
+
+Node CegInstantiator::getModelValue( Node n ) {
+  return d_qe->getModel()->getValue( n );
+}
+
+Node CegInstantiator::getBoundVariable(TypeNode tn)
+{
+  unsigned index = 0;
+  std::unordered_map<TypeNode, unsigned, TypeNodeHashFunction>::iterator itb =
+      d_bound_var_index.find(tn);
+  if (itb != d_bound_var_index.end())
+  {
+    index = itb->second;
+  }
+  d_bound_var_index[tn] = index + 1;
+  while (index >= d_bound_var[tn].size())
+  {
+    std::stringstream ss;
+    ss << "x" << index;
+    Node x = NodeManager::currentNM()->mkBoundVar(ss.str(), tn);
+    d_bound_var[tn].push_back(x);
+  }
+  return d_bound_var[tn][index];
+}
+
+bool CegInstantiator::isSolvedAssertion(Node n) const
+{
+  return d_solved_asserts.find(n) != d_solved_asserts.end();
+}
+
+void CegInstantiator::markSolved(Node n, bool solved)
+{
+  if (solved)
+  {
+    d_solved_asserts.insert(n);
+  }
+  else if (isSolvedAssertion(n))
+  {
+    d_solved_asserts.erase(n);
+  }
+}
+
+void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) {
+  if( n.getKind()==FORALL ){
+    d_is_nested_quant = true;
+  }else if( visited.find( n )==visited.end() ){
+    visited[n] = true;
+    if( TermUtil::isBoolConnectiveTerm( n ) ){
+      for( unsigned i=0; i<n.getNumChildren(); i++ ){
+        collectCeAtoms( n[i], visited );
+      }
+    }else{
+      if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){
+        Trace("cbqi-ce-atoms") << "CE atoms : " << n << std::endl;
+        d_ce_atoms.push_back( n );
+      }
+    }
+  }
+}
+
+void CegInstantiator::registerCounterexampleLemma( std::vector< Node >& lems, std::vector< Node >& ce_vars ) {
+  Trace("cbqi-reg") << "Register counterexample lemma..." << std::endl;
+  d_input_vars.clear();
+  d_input_vars.insert(d_input_vars.end(), ce_vars.begin(), ce_vars.end());
+
+  //Assert( d_vars.empty() );
+  d_vars.clear();
+  registerTheoryId(THEORY_UF);
+  for (unsigned i = 0; i < ce_vars.size(); i++)
+  {
+    Trace("cbqi-reg") << "  register input variable : " << ce_vars[i] << std::endl;
+    registerVariable(ce_vars[i]);
+  }
+
+  // preprocess with all relevant instantiator preprocessors
+  Trace("cbqi-debug") << "Preprocess based on theory-specific methods..."
+                      << std::endl;
+  std::vector<Node> pvars;
+  pvars.insert(pvars.end(), d_vars.begin(), d_vars.end());
+  for (std::pair<const TheoryId, InstantiatorPreprocess*>& p : d_tipp)
+  {
+    p.second->registerCounterexampleLemma(lems, pvars);
+  }
+  // must register variables generated by preprocessors
+  Trace("cbqi-debug") << "Register variables from theory-specific methods "
+                      << d_input_vars.size() << " " << pvars.size() << " ..."
+                      << std::endl;
+  for (unsigned i = d_input_vars.size(), size = pvars.size(); i < size; ++i)
+  {
+    Trace("cbqi-reg") << "  register theory preprocess variable : " << pvars[i]
+                      << std::endl;
+    registerVariable(pvars[i]);
+  }
+
+  //remove ITEs
+  IteSkolemMap iteSkolemMap;
+  d_qe->getTheoryEngine()->getTermFormulaRemover()->run(lems, iteSkolemMap);
+  //Assert( d_aux_vars.empty() );
+  d_aux_vars.clear();
+  d_aux_eq.clear();
+  for(IteSkolemMap::iterator i = iteSkolemMap.begin(); i != iteSkolemMap.end(); ++i) {
+    Trace("cbqi-reg") << "  register aux variable : " << i->first << std::endl;
+    registerVariable(i->first, true);
+  }
+  for( unsigned i=0; i<lems.size(); i++ ){
+    Trace("cbqi-debug") << "Counterexample lemma (pre-rewrite)  " << i << " : " << lems[i] << std::endl;
+    Node rlem = lems[i];
+    rlem = Rewriter::rewrite( rlem );
+    Trace("cbqi-debug") << "Counterexample lemma (post-rewrite) " << i << " : " << rlem << std::endl;
+    //record the literals that imply auxiliary variables to be equal to terms
+    if( lems[i].getKind()==ITE && rlem.getKind()==ITE ){
+      if( lems[i][1].getKind()==EQUAL && lems[i][2].getKind()==EQUAL && lems[i][1][0]==lems[i][2][0] ){
+        if( std::find( d_aux_vars.begin(), d_aux_vars.end(), lems[i][1][0] )!=d_aux_vars.end() ){
+          Node v = lems[i][1][0];
+          for( unsigned r=1; r<=2; r++ ){
+            d_aux_eq[rlem[r]][v] = lems[i][r][1];
+            Trace("cbqi-debug") << "  " << rlem[r] << " implies " << v << " = " << lems[i][r][1] << std::endl;
+          }
+        }
+      }
+    }
+    /*else if( lems[i].getKind()==EQUAL && lems[i][0].getType().isBoolean() ){
+      //Boolean terms
+      if( std::find( d_aux_vars.begin(), d_aux_vars.end(), lems[i][0] )!=d_aux_vars.end() ){
+        Node v = lems[i][0];
+        d_aux_eq[rlem][v] = lems[i][1];
+         Trace("cbqi-debug") << "  " << rlem << " implies " << v << " = " << lems[i][1] << std::endl;
+      }
+    }*/
+    lems[i] = rlem;
+  }
+
+  // determine variable order: must do Reals before Ints
+  Trace("cbqi-debug") << "Determine variable order..." << std::endl;
+  if (!d_vars.empty())
+  {
+    std::map<Node, unsigned> voo;
+    bool doSort = false;
+    std::vector<Node> vars;
+    std::map<TypeNode, std::vector<Node> > tvars;
+    for (unsigned i = 0, size = d_vars.size(); i < size; i++)
+    {
+      voo[d_vars[i]] = i;
+      d_var_order_index.push_back(0);
+      TypeNode tn = d_vars[i].getType();
+      if (tn.isInteger())
+      {
+        doSort = true;
+        tvars[tn].push_back(d_vars[i]);
+      }
+      else
+      {
+        vars.push_back(d_vars[i]);
+      }
+    }
+    if (doSort)
+    {
+      Trace("cbqi-debug") << "Sort variables based on ordering." << std::endl;
+      for (std::pair<const TypeNode, std::vector<Node> >& vs : tvars)
+      {
+        vars.insert(vars.end(), vs.second.begin(), vs.second.end());
+      }
+
+      Trace("cbqi-debug") << "Consider variables in this order : " << std::endl;
+      for (unsigned i = 0; i < vars.size(); i++)
+      {
+        d_var_order_index[voo[vars[i]]] = i;
+        Trace("cbqi-debug") << "  " << vars[i] << " : " << vars[i].getType()
+                            << ", index was : " << voo[vars[i]] << std::endl;
+        d_vars[i] = vars[i];
+      }
+      Trace("cbqi-debug") << std::endl;
+    }
+    else
+    {
+      d_var_order_index.clear();
+    }
+  }
+
+  //collect atoms from all lemmas: we will only do bounds coming from original body
+  d_is_nested_quant = false;
+  std::map< Node, bool > visited;
+  for( unsigned i=0; i<lems.size(); i++ ){
+    collectCeAtoms( lems[i], visited );
+  }
+}
+
+
+Instantiator::Instantiator( QuantifiersEngine * qe, TypeNode tn ) : d_type( tn ){
+  d_closed_enum_type = qe->getTermEnumeration()->isClosedEnumerableType(tn);
+}
+
+bool Instantiator::processEqualTerm(CegInstantiator* ci,
+                                    SolvedForm& sf,
+                                    Node pv,
+                                    TermProperties& pv_prop,
+                                    Node n,
+                                    CegInstEffort effort)
+{
+  pv_prop.d_type = 0;
+  return ci->constructInstantiationInc(pv, n, pv_prop, sf);
+}
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/cegqi/ceg_instantiator.h b/src/theory/quantifiers/cegqi/ceg_instantiator.h
new file mode 100644 (file)
index 0000000..03983fe
--- /dev/null
@@ -0,0 +1,783 @@
+/*********************                                                        */
+/*! \file ceg_instantiator.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief counterexample-guided quantifier instantiation
+ **/
+
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__CEG_INSTANTIATOR_H
+#define __CVC4__THEORY__QUANTIFIERS__CEG_INSTANTIATOR_H
+
+#include "theory/quantifiers_engine.h"
+#include "util/statistics_registry.h"
+
+namespace CVC4 {
+namespace theory {
+
+namespace arith {
+  class TheoryArith;
+}
+
+namespace quantifiers {
+
+class CegqiOutput {
+public:
+  virtual ~CegqiOutput() {}
+  virtual bool doAddInstantiation( std::vector< Node >& subs ) = 0;
+  virtual bool isEligibleForInstantiation( Node n ) = 0;
+  virtual bool addLemma( Node lem ) = 0;
+};
+
+class Instantiator;
+class InstantiatorPreprocess;
+
+/** Term Properties
+ *
+ * Stores properties for a variable to solve for in counterexample-guided
+ * instantiation.
+ *
+ * For LIA, this includes the coefficient of the variable, and the bound type
+ * for the variable.
+ */
+class TermProperties {
+public:
+  TermProperties() : d_type(0) {}
+  virtual ~TermProperties() {}
+
+  // type of property for a term
+  //  for arithmetic this corresponds to bound type (0:equal, 1:upper bound, -1:lower bound)
+  int d_type;
+  // for arithmetic
+  Node d_coeff;
+  // get cache node
+  // we consider terms + TermProperties that are unique up to their cache node
+  // (see constructInstantiationInc)
+  virtual Node getCacheNode() const { return d_coeff; }
+  // is non-basic 
+  virtual bool isBasic() const { return d_coeff.isNull(); }
+  // get modified term 
+  virtual Node getModifiedTerm( Node pv ) const {
+    if( !d_coeff.isNull() ){
+      return NodeManager::currentNM()->mkNode( kind::MULT, d_coeff, pv );
+    }else{
+      return pv;
+    }
+  }
+  // compose property, should be such that: 
+  //   p.getModifiedTerm( this.getModifiedTerm( x ) ) = this_updated.getModifiedTerm( x )
+  virtual void composeProperty( TermProperties& p ){
+    if( !p.d_coeff.isNull() ){
+      if( d_coeff.isNull() ){
+        d_coeff = p.d_coeff;
+      }else{
+        d_coeff = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::MULT, d_coeff, p.d_coeff ) );
+      }
+    }
+  }
+};
+
+/** Solved form
+ *  This specifies a substitution:
+ *  { d_props[i].getModifiedTerm(d_vars[i]) -> d_subs[i] | i = 0...|d_vars| }
+ */
+class SolvedForm {
+public:
+  // list of variables
+  std::vector< Node > d_vars;
+  // list of terms that they are substituted to
+  std::vector< Node > d_subs;
+  // properties for each variable
+  std::vector< TermProperties > d_props;
+  // the variables that have non-basic information regarding how they are substituted
+  //   an example is for linear arithmetic, we store "substitution with coefficients".
+  std::vector<Node> d_non_basic;
+  // push the substitution pv_prop.getModifiedTerm(pv) -> n
+  void push_back( Node pv, Node n, TermProperties& pv_prop ){
+    d_vars.push_back( pv );
+    d_subs.push_back( n );
+    d_props.push_back( pv_prop );
+    if( !pv_prop.isBasic() ){
+      d_non_basic.push_back( pv );
+      // update theta value
+      Node new_theta = getTheta();
+      if( new_theta.isNull() ){
+        new_theta = pv_prop.d_coeff;
+      }else{
+        new_theta = NodeManager::currentNM()->mkNode( kind::MULT, new_theta, pv_prop.d_coeff );
+        new_theta = Rewriter::rewrite( new_theta );
+      }
+      d_theta.push_back( new_theta );
+    }
+  }
+  // pop the substitution pv_prop.getModifiedTerm(pv) -> n
+  void pop_back( Node pv, Node n, TermProperties& pv_prop ){
+    d_vars.pop_back();
+    d_subs.pop_back();
+    d_props.pop_back();
+    if( !pv_prop.isBasic() ){
+      d_non_basic.pop_back();
+      // update theta value
+      d_theta.pop_back();
+    }
+  }
+  // is this solved form empty?
+  bool empty() { return d_vars.empty(); }
+public:
+  // theta values (for LIA, see Section 4 of Reynolds/King/Kuncak FMSD 2017)
+  std::vector< Node > d_theta;
+  // get the current value for theta (for LIA, see Section 4 of Reynolds/King/Kuncak FMSD 2017)
+  Node getTheta() {
+    if( d_theta.empty() ){
+      return Node::null();
+    }else{
+      return d_theta[d_theta.size()-1];
+    }
+  }
+};
+
+/** instantiation effort levels
+ *
+ * This effort is used to stratify the construction of
+ * instantiations for some theories that may result to
+ * using model value instantiations.
+ */
+enum CegInstEffort
+{
+  // uninitialized
+  CEG_INST_EFFORT_NONE,
+  // standard effort level
+  CEG_INST_EFFORT_STANDARD,
+  // standard effort level, but we have used model values
+  CEG_INST_EFFORT_STANDARD_MV,
+  // full effort level
+  CEG_INST_EFFORT_FULL
+};
+
+std::ostream& operator<<(std::ostream& os, CegInstEffort e);
+
+/** instantiation phase for variables
+ *
+ * This indicates the phase in which we constructed
+ * a substitution for individual variables.
+ */
+enum CegInstPhase
+{
+  // uninitialized
+  CEG_INST_PHASE_NONE,
+  // instantiation constructed during traversal of equivalence classes
+  CEG_INST_PHASE_EQC,
+  // instantiation constructed during solving equalities
+  CEG_INST_PHASE_EQUAL,
+  // instantiation constructed by looking at theory assertions
+  CEG_INST_PHASE_ASSERTION,
+  // instantiation constructed by querying model value
+  CEG_INST_PHASE_MVALUE,
+};
+
+std::ostream& operator<<(std::ostream& os, CegInstPhase phase);
+
+/** Ceg instantiator
+ *
+ * This class manages counterexample-guided quantifier instantiation
+ * for a single quantified formula.
+ *
+ * For details on counterexample-guided quantifier instantiation
+ * (for linear arithmetic), see Reynolds/King/Kuncak FMSD 2017.
+ */
+class CegInstantiator {
+ public:
+  CegInstantiator(QuantifiersEngine* qe,
+                  CegqiOutput* out,
+                  bool use_vts_delta = true,
+                  bool use_vts_inf = true);
+  virtual ~CegInstantiator();
+  /** check
+   * This adds instantiations based on the state of d_vars in current context
+   * on the output channel d_out of this class.
+   */
+  bool check();
+  /** presolve for quantified formula
+   *
+   * This initializes formulas that help static learning of the quantifier-free
+   * solver. It is only called if the option --cbqi-prereg-inst is used.
+   */
+  void presolve(Node q);
+  /** Register the counterexample lemma
+   *
+   * lems : contains the conjuncts of the counterexample lemma of the
+   *        quantified formula we are processing. The counterexample
+   *        lemma is the formula { ~phi[e/x] } in Figure 1 of Reynolds
+   *        et al. FMSD 2017.
+   * ce_vars : contains the variables e. Notice these are variables of
+   *           INST_CONSTANT kind, since we do not permit bound
+   *           variables in assertions.
+   *
+   * This method may modify the set of lemmas lems based on:
+   * - ITE removal,
+   * - Theory-specific preprocessing of instantiation lemmas.
+   * It may also introduce new variables to ce_vars if necessary.
+   */
+  void registerCounterexampleLemma(std::vector<Node>& lems,
+                                   std::vector<Node>& ce_vars);
+  /** get the output channel of this class */
+  CegqiOutput* getOutput() { return d_out; }
+  //------------------------------interface for instantiators
+  /** get quantifiers engine */
+  QuantifiersEngine* getQuantifiersEngine() { return d_qe; }
+  /** push stack variable
+   * This adds a new variable to solve for in the stack
+   * of variables we are processing. This stack is only
+   * used for datatypes, where e.g. the DtInstantiator
+   * solving for a list x may push the stack "variables"
+   * head(x) and tail(x).
+   */
+  void pushStackVariable(Node v);
+  /** pop stack variable */
+  void popStackVariable();
+  /** construct instantiation increment
+   *
+   * Adds the substitution { pv_prop.getModifiedTerm(pv) -> n } to the current
+   * instantiation, specified by sf.
+   *
+   * This function returns true if a call to
+   * QuantifiersEngine::addInstantiation(...)
+   * was successfully made in a recursive call.
+   *
+   * The solved form sf is reverted to its original state if
+   *   this function returns false, or
+   *   revertOnSuccess is true and this function returns true.
+   */
+  bool constructInstantiationInc(Node pv,
+                                 Node n,
+                                 TermProperties& pv_prop,
+                                 SolvedForm& sf,
+                                 bool revertOnSuccess = false);
+  /** get the current model value of term n */
+  Node getModelValue(Node n);
+  /** get bound variable for type
+   *
+   * This gets the next (canonical) bound variable of
+   * type tn. This can be used for instance when
+   * constructing instantiations that involve choice expressions.
+   */
+  Node getBoundVariable(TypeNode tn);
+  /** has this assertion been marked as solved? */
+  bool isSolvedAssertion(Node n) const;
+  /** marked solved */
+  void markSolved(Node n, bool solved = true);
+  //------------------------------end interface for instantiators
+
+  /**
+   * Get the number of atoms in the counterexample lemma of the quantified
+   * formula we are processing with this class.
+   */
+  unsigned getNumCEAtoms() { return d_ce_atoms.size(); }
+  /**
+   * Get the i^th atom of the counterexample lemma of the quantified
+   * formula we are processing with this class.
+   */
+  Node getCEAtom(unsigned i) { return d_ce_atoms[i]; }
+  /** is n a term that is eligible for instantiation? */
+  bool isEligible(Node n);
+  /** does n have variable pv? */
+  bool hasVariable(Node n, Node pv);
+  /** are we using delta for LRA virtual term substitution? */
+  bool useVtsDelta() { return d_use_vts_delta; }
+  /** are we using infinity for LRA virtual term substitution? */
+  bool useVtsInfinity() { return d_use_vts_inf; }
+  /** are we processing a nested quantified formula? */
+  bool hasNestedQuantification() { return d_is_nested_quant; }
+ private:
+  /** quantified formula associated with this instantiator */
+  QuantifiersEngine* d_qe;
+  /** output channel of this instantiator */
+  CegqiOutput* d_out;
+  /** whether we are using delta for virtual term substitution
+    * (for quantified LRA).
+    */
+  bool d_use_vts_delta;
+  /** whether we are using infinity for virtual term substitution
+    * (for quantified LRA).
+    */
+  bool d_use_vts_inf;
+
+  //-------------------------------globally cached
+  /** cache from nodes to the set of variables it contains
+    * (from the quantified formula we are instantiating).
+    */
+  std::unordered_map<Node,
+                     std::unordered_set<Node, NodeHashFunction>,
+                     NodeHashFunction>
+      d_prog_var;
+  /** cache of the set of terms that we have established are
+   * ineligible for instantiation.
+    */
+  std::unordered_set<Node, NodeHashFunction> d_inelig;
+  /** ensures n is in d_prog_var and d_inelig. */
+  void computeProgVars(Node n);
+  //-------------------------------end globally cached
+
+  //-------------------------------cached per round
+  /** current assertions per theory */
+  std::map<TheoryId, std::vector<Node> > d_curr_asserts;
+  /** map from representatives to the terms in their equivalence class */
+  std::map<Node, std::vector<Node> > d_curr_eqc;
+  /** map from types to representatives of that type */
+  std::map<TypeNode, std::vector<Node> > d_curr_type_eqc;
+  /** solved asserts */
+  std::unordered_set<Node, NodeHashFunction> d_solved_asserts;
+  /** process assertions
+   * This is called once at the beginning of check to
+   * set up all necessary information for constructing instantiations,
+   * such as the above data structures.
+   */
+  void processAssertions();
+  /** add to auxiliary variable substitution
+   * This adds the substitution l -> r to the auxiliary
+   * variable substitution subs_lhs -> subs_rhs, and serializes
+   * it (applies it to existing substitutions).
+   */
+  void addToAuxVarSubstitution(std::vector<Node>& subs_lhs,
+                               std::vector<Node>& subs_rhs,
+                               Node l,
+                               Node r);
+  /** cache bound variables for type returned
+   * by getBoundVariable(...).
+   */
+  std::unordered_map<TypeNode, std::vector<Node>, TypeNodeHashFunction>
+      d_bound_var;
+  /** current index of bound variables for type.
+   * The next call to getBoundVariable(...) for
+   * type tn returns the d_bound_var_index[tn]^th
+   * element of d_bound_var[tn], or a fresh variable
+   * if not in bounds.
+   */
+  std::unordered_map<TypeNode, unsigned, TypeNodeHashFunction>
+      d_bound_var_index;
+  //-------------------------------end cached per round
+
+  //-------------------------------data per theory
+  /** relevant theory ids
+   * A list of theory ids that contain at least one
+   * constraint in the body of the quantified formula we
+   * are processing.
+   */
+  std::vector<TheoryId> d_tids;
+  /** map from theory ids to instantiator preprocessors */
+  std::map<TheoryId, InstantiatorPreprocess*> d_tipp;
+  /** registers all theory ids associated with type tn
+   *
+   * This recursively calls registerTheoryId for typeOf(tn') for
+   * all parameters and datatype subfields of type tn.
+   * visited stores the types we have already visited.
+   */
+  void registerTheoryIds(TypeNode tn, std::map<TypeNode, bool>& visited);
+  /** register theory id tid
+   *
+   * This is called when the quantified formula we are processing
+   * with this class involves theory tid. In this case, we will
+   * construct instantiations based on the assertion list of this theory.
+   */
+  void registerTheoryId(TheoryId tid);
+  //-------------------------------end data per theory
+
+  //-------------------------------the variables
+  /** the variables we are instantiating
+   *
+   * This is a superset of the variables for the instantiations we are
+   * generating and sending on the output channel of this class.
+   */
+  std::vector<Node> d_vars;
+  /** set form of d_vars */
+  std::unordered_set<Node, NodeHashFunction> d_vars_set;
+  /** index of variables reported in instantiation */
+  std::vector<unsigned> d_var_order_index;
+  /** number of input variables
+   *
+   * These are the variables, in order, for the instantiations we are generating
+   * and sending on the output channel of this class.
+   */
+  std::vector<Node> d_input_vars;
+  /** literals to equalities for aux vars
+   * This stores entries of the form
+   *   L -> ( k -> t )
+   * where
+   *   k is a variable in d_aux_vars,
+   *   L is a literal that if asserted implies that our
+   *    instantiation should map { k -> t }.
+   * For example, if a term of the form
+   *   ite( C, t1, t2 )
+   * was replaced by k, we get this (top-level) assertion:
+   *   ite( C, k=t1, k=t2 )
+   * The vector d_aux_eq contains the exact form of
+   * the literals in the above constraint that they would
+   * appear in assertions, meaning d_aux_eq may contain:
+   *   t1=k -> ( k -> t1 )
+   *   t2=k -> ( k -> t2 )
+   * where t1=k and t2=k are the rewritten form of
+   * k=t1 and k=t2 respectively.
+   */
+  std::map<Node, std::map<Node, Node> > d_aux_eq;
+  /** auxiliary variables
+   * These variables include the result of removing ITE
+   * terms from the quantified formula we are processing.
+   * These variables must be eliminated from constraints
+   * as a preprocess step to check().
+   */
+  std::vector<Node> d_aux_vars;
+  /** register variable */
+  void registerVariable(Node v, bool is_aux = false);
+  //-------------------------------the variables
+
+  //-------------------------------quantified formula info
+  /** are we processing a nested quantified formula? */
+  bool d_is_nested_quant;
+  /** the atoms of the CE lemma */
+  std::vector<Node> d_ce_atoms;
+  /** collect atoms */
+  void collectCeAtoms(Node n, std::map<Node, bool>& visited);
+  //-------------------------------end quantified formula info
+
+  //-------------------------------current state
+  /** the current effort level of the instantiator
+   * This indicates the effort Instantiator objects
+   * will put into the terms they return.
+   */
+  CegInstEffort d_effort;
+  /** for each variable, the instantiator used for that variable */
+  std::map<Node, Instantiator*> d_active_instantiators;
+  /** map from variables to the index in the prefix of the quantified
+   * formula we are processing.
+   */
+  std::map<Node, unsigned> d_curr_index;
+  /** map from variables to the phase in which we instantiated them */
+  std::map<Node, CegInstPhase> d_curr_iphase;
+  /** cache of current substitutions tried between activate/deactivate */
+  std::map<Node, std::map<Node, std::map<Node, bool> > > d_curr_subs_proc;
+  /** stack of temporary variables we are solving for,
+   * e.g. subfields of datatypes.
+   */
+  std::vector<Node> d_stack_vars;
+  /** activate instantiation variable v at index
+   *
+   * This is called when variable (inst constant) v is activated
+   * for the quantified formula we are processing.
+   * This method initializes the instantiator class for
+   * that variable if necessary, where this class is
+   * determined by the type of v. It also initializes
+   * the cache of values we have tried substituting for v
+   * (in d_curr_subs_proc), and stores its index.
+   */
+  void activateInstantiationVariable(Node v, unsigned index);
+  /** deactivate instantiation variable
+   *
+   * This is called when variable (inst constant) v is deactivated
+   * for the quantified formula we are processing.
+   */
+  void deactivateInstantiationVariable(Node v);
+  //-------------------------------end current state
+
+  //---------------------------------for applying substitutions
+  /** can use basic substitution */
+  bool canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic );
+  /** apply substitution
+  * We wish to process the substitution: 
+  *   ( pv = n * sf )
+  * where pv is a variable with type tn, and * denotes application of substitution.
+  * The return value "ret" and pv_prop is such that the above equality is equivalent to
+  *   ( pv_prop.getModifiedTerm(pv) = ret )
+  */
+  Node applySubstitution( TypeNode tn, Node n, SolvedForm& sf, TermProperties& pv_prop, bool try_coeff = true ) {
+    return applySubstitution( tn, n, sf.d_vars, sf.d_subs, sf.d_props, sf.d_non_basic, pv_prop, try_coeff );
+  }
+  /** apply substitution, with solved form expanded to subs/prop/non_basic/vars */
+  Node applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, 
+                          std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff = true );
+  /** apply substitution to literal lit 
+  * The return value is equivalent to ( lit * sf )
+  * where * denotes application of substitution.
+  */
+  Node applySubstitutionToLiteral( Node lit, SolvedForm& sf ) {
+    return applySubstitutionToLiteral( lit, sf.d_vars, sf.d_subs, sf.d_props, sf.d_non_basic );
+  }
+  /** apply substitution to literal lit, with solved form expanded to subs/prop/non_basic/vars */
+  Node applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, 
+                                   std::vector< Node >& non_basic );
+  //---------------------------------end for applying substitutions
+
+  /** map from variables to their instantiators */
+  std::map<Node, Instantiator*> d_instantiator;
+
+  /** construct instantiation
+   * This method constructs the current instantiation, where we
+   * are currently processing the i^th variable in d_vars.
+   * It returns true if a successful call to the output channel's
+   * doAddInstantiation was made.
+   */
+  bool constructInstantiation(SolvedForm& sf, unsigned i);
+  /** do add instantiation
+   * This method is called by the above function after we finalize the
+   * variables/substitution and auxiliary lemmas.
+   * It returns true if a successful call to the output channel's
+   * doAddInstantiation was made.
+   */
+  bool doAddInstantiation(std::vector<Node>& vars,
+                          std::vector<Node>& subs,
+                          std::vector<Node>& lemmas);
+};
+
+/** Instantiator class
+ *
+ * This is a virtual class that is used for methods for constructing
+ * substitutions for individual variables in counterexample-guided
+ * instantiation techniques.
+ *
+ * This class contains a set of interface functions below, which are called
+ * based on a fixed instantiation method implemented by CegInstantiator.
+ * In these calls, the Instantiator in turn makes calls to methods in
+ * CegInstanatior (primarily constructInstantiationInc).
+ */
+class Instantiator {
+public:
+  Instantiator( QuantifiersEngine * qe, TypeNode tn );
+  virtual ~Instantiator(){}
+  /** reset
+   * This is called once, prior to any of the below methods are called.
+   * This function sets up any initial information necessary for constructing
+   * instantiations for pv based on the current context.
+   */
+  virtual void reset(CegInstantiator* ci,
+                     SolvedForm& sf,
+                     Node pv,
+                     CegInstEffort effort)
+  {
+  }
+
+  /** process equal term
+   *
+   * This method is called when the entailment:
+   *   E |= pv_prop.getModifiedTerm(pv) = n
+   * holds in the current context E, and n is eligible for instantiation.
+   *
+   * Returns true if an instantiation was successfully added via a call to
+   * CegInstantiator::constructInstantiationInc.
+   */
+  virtual bool processEqualTerm(CegInstantiator* ci,
+                                SolvedForm& sf,
+                                Node pv,
+                                TermProperties& pv_prop,
+                                Node n,
+                                CegInstEffort effort);
+  /** process equal terms
+   *
+   * This method is called after process equal term, where eqc is the list of
+   * eligible terms in the equivalence class of pv.
+   *
+   * Returns true if an instantiation was successfully added via a call to
+   * CegInstantiator::constructInstantiationInc.
+   */
+  virtual bool processEqualTerms(CegInstantiator* ci,
+                                 SolvedForm& sf,
+                                 Node pv,
+                                 std::vector<Node>& eqc,
+                                 CegInstEffort effort)
+  {
+    return false;
+  }
+
+  /** whether the instantiator implements processEquality */
+  virtual bool hasProcessEquality(CegInstantiator* ci,
+                                  SolvedForm& sf,
+                                  Node pv,
+                                  CegInstEffort effort)
+  {
+    return false;
+  }
+  /** process equality
+   *  The input is such that term_props.size() = terms.size() = 2
+   *  This method is called when the entailment:
+   *    E ^ term_props[0].getModifiedTerm(x0) =
+   *    terms[0] ^ term_props[1].getModifiedTerm(x1) = terms[1] |= x0 = x1
+   *  holds in current context E for fresh variables xi, terms[i] are eligible,
+   *  and at least one terms[i] contains pv for i = 0,1.
+   *  Notice in the basic case, E |= terms[0] = terms[1].
+   *
+   *  Returns true if an instantiation was successfully added via a call to
+   *  CegInstantiator::constructInstantiationInc.
+   */
+  virtual bool processEquality(CegInstantiator* ci,
+                               SolvedForm& sf,
+                               Node pv,
+                               std::vector<TermProperties>& term_props,
+                               std::vector<Node>& terms,
+                               CegInstEffort effort)
+  {
+    return false;
+  }
+
+  /** whether the instantiator implements processAssertion for any literal */
+  virtual bool hasProcessAssertion(CegInstantiator* ci,
+                                   SolvedForm& sf,
+                                   Node pv,
+                                   CegInstEffort effort)
+  {
+    return false;
+  }
+  /** has process assertion
+  *
+  * This method is called when the entailment:
+  *   E |= lit
+  * holds in current context E. Typically, lit belongs to the list of current
+  * assertions.
+  *
+  * This method is used to determine whether the instantiator implements
+  * processAssertion for literal lit.
+  *   If this method returns null, then this intantiator does not handle the
+  *   literal lit. Otherwise, this method returns a literal lit' such that:
+  *   (1) lit' is true in the current model,
+  *   (2) lit' implies lit.
+  *   where typically lit' = lit.
+  */
+  virtual Node hasProcessAssertion(CegInstantiator* ci,
+                                   SolvedForm& sf,
+                                   Node pv,
+                                   Node lit,
+                                   CegInstEffort effort)
+  {
+    return Node::null();
+  }
+  /** process assertion
+   * This method processes the assertion slit for variable pv.
+   * lit : the substituted form (under sf) of a literal returned by
+   *       hasProcessAssertion
+   * alit : the asserted literal, given as input to hasProcessAssertion
+   *
+   *  Returns true if an instantiation was successfully added via a call to
+   *  CegInstantiator::constructInstantiationInc.
+   */
+  virtual bool processAssertion(CegInstantiator* ci,
+                                SolvedForm& sf,
+                                Node pv,
+                                Node lit,
+                                Node alit,
+                                CegInstEffort effort)
+  {
+    return false;
+  }
+  /** process assertions
+   *
+   * Called after processAssertion is called for each literal asserted to the
+   * instantiator.
+   *
+   * Returns true if an instantiation was successfully added via a call to
+   * CegInstantiator::constructInstantiationInc.
+   */
+  virtual bool processAssertions(CegInstantiator* ci,
+                                 SolvedForm& sf,
+                                 Node pv,
+                                 CegInstEffort effort)
+  {
+    return false;
+  }
+
+  /** do we use the model value as instantiation for pv?
+   * This method returns true if we use model value instantiations
+   * at the same effort level as those determined by this instantiator.
+   */
+  virtual bool useModelValue(CegInstantiator* ci,
+                             SolvedForm& sf,
+                             Node pv,
+                             CegInstEffort effort)
+  {
+    return effort > CEG_INST_EFFORT_STANDARD;
+  }
+  /** do we allow the model value as instantiation for pv? */
+  virtual bool allowModelValue(CegInstantiator* ci,
+                               SolvedForm& sf,
+                               Node pv,
+                               CegInstEffort effort)
+  {
+    return d_closed_enum_type;
+  }
+
+  /** do we need to postprocess the solved form for pv? */
+  virtual bool needsPostProcessInstantiationForVariable(CegInstantiator* ci,
+                                                        SolvedForm& sf,
+                                                        Node pv,
+                                                        CegInstEffort effort)
+  {
+    return false;
+  }
+  /** postprocess the solved form for pv
+   *
+   * This method returns true if we successfully postprocessed the solved form.
+   * lemmas is a set of lemmas we wish to return along with the instantiation.
+   */
+  virtual bool postProcessInstantiationForVariable(CegInstantiator* ci,
+                                                   SolvedForm& sf,
+                                                   Node pv,
+                                                   CegInstEffort effort,
+                                                   std::vector<Node>& lemmas)
+  {
+    return true;
+  }
+
+  /** Identify this module (for debugging) */
+  virtual std::string identify() const { return "Default"; }
+ protected:
+  /** the type of the variable we are instantiating */
+  TypeNode d_type;
+  /** whether d_type is a closed enumerable type */
+  bool d_closed_enum_type;
+};
+
+class ModelValueInstantiator : public Instantiator {
+public:
+  ModelValueInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){}
+  virtual ~ModelValueInstantiator(){}
+  bool useModelValue(CegInstantiator* ci,
+                     SolvedForm& sf,
+                     Node pv,
+                     CegInstEffort effort)
+  {
+    return true;
+  }
+  std::string identify() const { return "ModelValue"; }
+};
+
+/** instantiator preprocess
+ *
+ * This class implements techniques for preprocessing the counterexample lemma
+ * generated for counterexample-guided quantifier instantiation.
+ */
+class InstantiatorPreprocess
+{
+ public:
+  InstantiatorPreprocess() {}
+  virtual ~InstantiatorPreprocess() {}
+  /** register counterexample lemma
+   * This implements theory-specific preprocessing and registration
+   * of counterexample lemmas, with the same contract as
+   * CegInstantiation::registerCounterexampleLemma.
+   */
+  virtual void registerCounterexampleLemma(std::vector<Node>& lems,
+                                           std::vector<Node>& ce_vars)
+  {
+  }
+};
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
+
+#endif
diff --git a/src/theory/quantifiers/cegqi/ceg_t_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_t_instantiator.cpp
new file mode 100644 (file)
index 0000000..e6e6420
--- /dev/null
@@ -0,0 +1,1990 @@
+/*********************                                                        */
+/*! \file ceg_t_instantiator.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of theory-specific counterexample-guided quantifier instantiation
+ **/
+
+#include "theory/quantifiers/cegqi/ceg_t_instantiator.h"
+
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers/quantifiers_rewriter.h"
+#include "theory/quantifiers/ematching/trigger.h"
+
+#include "theory/arith/arith_msum.h"
+#include "theory/arith/partial_model.h"
+#include "theory/arith/theory_arith.h"
+#include "theory/arith/theory_arith_private.h"
+#include "theory/bv/theory_bv_utils.h"
+#include "util/bitvector.h"
+#include "util/random.h"
+
+#include <algorithm>
+#include <stack>
+
+using namespace std;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+struct BvLinearAttributeId {};
+using BvLinearAttribute = expr::Attribute<BvLinearAttributeId, bool>;
+
+Node ArithInstantiator::getModelBasedProjectionValue( CegInstantiator * ci, Node e, Node t, bool isLower, Node c, Node me, Node mt, Node theta, Node inf_coeff, Node delta_coeff ) {
+  Node val = t;
+  Trace("cegqi-arith-bound2") << "Value : " << val << std::endl;
+  Assert( !e.getType().isInteger() || t.getType().isInteger() );
+  Assert( !e.getType().isInteger() || mt.getType().isInteger() );
+  //add rho value
+  //get the value of c*e
+  Node ceValue = me;
+  Node new_theta = theta;
+  if( !c.isNull() ){
+    Assert( c.getType().isInteger() );
+    ceValue = NodeManager::currentNM()->mkNode( MULT, ceValue, c );
+    ceValue = Rewriter::rewrite( ceValue );
+    if( new_theta.isNull() ){
+      new_theta = c;
+    }else{
+      new_theta = NodeManager::currentNM()->mkNode( MULT, new_theta, c );
+      new_theta = Rewriter::rewrite( new_theta );
+    }
+    Trace("cegqi-arith-bound2") << "...c*e = " << ceValue << std::endl;
+    Trace("cegqi-arith-bound2") << "...theta = " << new_theta << std::endl;
+  }
+  if( !new_theta.isNull() && e.getType().isInteger() ){
+    Node rho;
+    //if( !mt.getType().isInteger() ){
+      //round up/down
+      //mt = NodeManager::currentNM()->mkNode(
+    //}
+    if( isLower ){
+      rho = NodeManager::currentNM()->mkNode( MINUS, ceValue, mt );
+    }else{
+      rho = NodeManager::currentNM()->mkNode( MINUS, mt, ceValue );
+    }
+    rho = Rewriter::rewrite( rho );
+    Trace("cegqi-arith-bound2") << "...rho = " << me << " - " << mt << " = " << rho << std::endl;
+    Trace("cegqi-arith-bound2") << "..." << rho << " mod " << new_theta << " = ";
+    rho = NodeManager::currentNM()->mkNode( INTS_MODULUS_TOTAL, rho, new_theta );
+    rho = Rewriter::rewrite( rho );
+    Trace("cegqi-arith-bound2") << rho << std::endl;
+    Kind rk = isLower ? PLUS : MINUS;
+    val = NodeManager::currentNM()->mkNode( rk, val, rho );
+    val = Rewriter::rewrite( val );
+    Trace("cegqi-arith-bound2") << "(after rho) : " << val << std::endl;
+  }
+  if( !inf_coeff.isNull() ){
+    Assert( !d_vts_sym[0].isNull() );
+    val = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkNode( MULT, inf_coeff, d_vts_sym[0] ) );
+    val = Rewriter::rewrite( val );
+  }
+  if( !delta_coeff.isNull() ){
+    //create delta here if necessary
+    val = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkNode( MULT, delta_coeff, ci->getQuantifiersEngine()->getTermUtil()->getVtsDelta() ) );
+    val = Rewriter::rewrite( val );
+  }
+  return val;
+}
+
+//this isolates the atom into solved form
+//     veq_c * pv <> val + vts_coeff_delta * delta + vts_coeff_inf * inf
+//  ensures val is Int if pv is Int, and val does not contain vts symbols
+int ArithInstantiator::solve_arith( CegInstantiator * ci, Node pv, Node atom, Node& veq_c, Node& val, Node& vts_coeff_inf, Node& vts_coeff_delta ) {
+  int ires = 0;
+  Trace("cegqi-arith-debug") << "isolate for " << pv << " in " << atom << std::endl;
+  std::map< Node, Node > msum;
+  if (ArithMSum::getMonomialSumLit(atom, msum))
+  {
+    Trace("cegqi-arith-debug") << "got monomial sum: " << std::endl;
+    if( Trace.isOn("cegqi-arith-debug") ){
+      ArithMSum::debugPrintMonomialSum(msum, "cegqi-arith-debug");
+    }
+    TypeNode pvtn = pv.getType();
+    //remove vts symbols from polynomial
+    Node vts_coeff[2];
+    for( unsigned t=0; t<2; t++ ){
+      if( !d_vts_sym[t].isNull() ){
+        std::map< Node, Node >::iterator itminf = msum.find( d_vts_sym[t] );
+        if( itminf!=msum.end() ){
+          vts_coeff[t] = itminf->second;
+          if( vts_coeff[t].isNull() ){
+            vts_coeff[t] = NodeManager::currentNM()->mkConst( Rational( 1 ) );
+          }
+          //negate if coefficient on variable is positive
+          std::map< Node, Node >::iterator itv = msum.find( pv );
+          if( itv!=msum.end() ){
+            //multiply by the coefficient we will isolate for
+            if( itv->second.isNull() ){
+              vts_coeff[t] = ArithMSum::negate(vts_coeff[t]);
+            }else{
+              if( !pvtn.isInteger() ){
+                vts_coeff[t] = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(-1) / itv->second.getConst<Rational>() ), vts_coeff[t] );
+                vts_coeff[t] = Rewriter::rewrite( vts_coeff[t] );
+              }else if( itv->second.getConst<Rational>().sgn()==1 ){
+                vts_coeff[t] = ArithMSum::negate(vts_coeff[t]);
+              }
+            }
+          }
+          Trace("cegqi-arith-debug") << "vts[" << t << "] coefficient is " << vts_coeff[t] << std::endl;
+          msum.erase( d_vts_sym[t] );
+        }
+      }
+    }
+
+    ires = ArithMSum::isolate(pv, msum, veq_c, val, atom.getKind());
+    if( ires!=0 ){
+      Node realPart;
+      if( Trace.isOn("cegqi-arith-debug") ){
+        Trace("cegqi-arith-debug") << "Isolate : ";
+        if( !veq_c.isNull() ){
+          Trace("cegqi-arith-debug") << veq_c << " * ";
+        }
+        Trace("cegqi-arith-debug") << pv << " " << atom.getKind() << " " << val << std::endl;
+      }
+      if( options::cbqiAll() ){
+        // when not pure LIA/LRA, we must check whether the lhs contains pv
+        if( TermUtil::containsTerm( val, pv ) ){
+          Trace("cegqi-arith-debug") << "fail : contains bad term" << std::endl;
+          return 0;
+        }
+      }
+      if( pvtn.isInteger() && ( ( !veq_c.isNull() && !veq_c.getType().isInteger() ) || !val.getType().isInteger() ) ){
+        //redo, split integer/non-integer parts
+        bool useCoeff = false;
+        Integer coeff = ci->getQuantifiersEngine()->getTermUtil()->d_one.getConst<Rational>().getNumerator();
+        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+          if( it->first.isNull() || it->first.getType().isInteger() ){
+            if( !it->second.isNull() ){
+              coeff = coeff.lcm( it->second.getConst<Rational>().getDenominator() );
+              useCoeff = true;
+            }
+          }
+        }
+        //multiply everything by this coefficient
+        Node rcoeff = NodeManager::currentNM()->mkConst( Rational( coeff ) );
+        std::vector< Node > real_part;
+        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+          if( useCoeff ){
+            if( it->second.isNull() ){
+              msum[it->first] = rcoeff;
+            }else{
+              msum[it->first] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, it->second, rcoeff ) );
+            }
+          }
+          if( !it->first.isNull() && !it->first.getType().isInteger() ){
+            real_part.push_back( msum[it->first].isNull() ? it->first : NodeManager::currentNM()->mkNode( MULT, msum[it->first], it->first ) );
+          }
+        }
+        //remove delta  TODO: check this
+        vts_coeff[1] = Node::null();
+        //multiply inf
+        if( !vts_coeff[0].isNull() ){
+          vts_coeff[0] = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, rcoeff, vts_coeff[0] ) );
+        }
+        realPart = real_part.empty() ? ci->getQuantifiersEngine()->getTermUtil()->d_zero : ( real_part.size()==1 ? real_part[0] : NodeManager::currentNM()->mkNode( PLUS, real_part ) );
+        Assert( ci->getOutput()->isEligibleForInstantiation( realPart ) );
+        //re-isolate
+        Trace("cegqi-arith-debug") << "Re-isolate..." << std::endl;
+        ires = ArithMSum::isolate(pv, msum, veq_c, val, atom.getKind());
+        Trace("cegqi-arith-debug") << "Isolate for mixed Int/Real : " << veq_c << " * " << pv << " " << atom.getKind() << " " << val << std::endl;
+        Trace("cegqi-arith-debug") << "                 real part : " << realPart << std::endl;
+        if( ires!=0 ){
+          int ires_use = ( msum[pv].isNull() || msum[pv].getConst<Rational>().sgn()==1 ) ? 1 : -1;
+          val = Rewriter::rewrite( NodeManager::currentNM()->mkNode( ires_use==-1 ? PLUS : MINUS,
+                                    NodeManager::currentNM()->mkNode( ires_use==-1 ? MINUS : PLUS, val, realPart ),
+                                    NodeManager::currentNM()->mkNode( TO_INTEGER, realPart ) ) );  //TODO: round up for upper bounds?
+          Trace("cegqi-arith-debug") << "result : " << val << std::endl;
+          Assert( val.getType().isInteger() );
+        }
+      }
+    }
+    vts_coeff_inf = vts_coeff[0];
+    vts_coeff_delta = vts_coeff[1];
+    Trace("cegqi-arith-debug") << "Return " << veq_c << " * " << pv << " " << atom.getKind() << " " << val << ", vts = (" << vts_coeff_inf << ", " << vts_coeff_delta << ")" << std::endl;
+  }else{
+    Trace("cegqi-arith-debug") << "fail : could not get monomial sum" << std::endl;
+  }
+  return ires;
+}
+
+void ArithInstantiator::reset(CegInstantiator* ci,
+                              SolvedForm& sf,
+                              Node pv,
+                              CegInstEffort effort)
+{
+  d_vts_sym[0] = ci->getQuantifiersEngine()->getTermUtil()->getVtsInfinity( d_type, false, false );
+  d_vts_sym[1] = ci->getQuantifiersEngine()->getTermUtil()->getVtsDelta( false, false );
+  for( unsigned i=0; i<2; i++ ){
+    d_mbp_bounds[i].clear();
+    d_mbp_coeff[i].clear();
+    for( unsigned j=0; j<2; j++ ){
+      d_mbp_vts_coeff[i][j].clear();
+    }
+    d_mbp_lit[i].clear();
+  }
+}
+
+bool ArithInstantiator::processEquality(CegInstantiator* ci,
+                                        SolvedForm& sf,
+                                        Node pv,
+                                        std::vector<TermProperties>& term_props,
+                                        std::vector<Node>& terms,
+                                        CegInstEffort effort)
+{
+  Node eq_lhs = terms[0];
+  Node eq_rhs = terms[1];
+  Node lhs_coeff = term_props[0].d_coeff;
+  Node rhs_coeff = term_props[1].d_coeff;
+  //make the same coefficient
+  if( rhs_coeff!=lhs_coeff ){
+    if( !rhs_coeff.isNull() ){
+      Trace("cegqi-arith-debug") << "...mult lhs by " << rhs_coeff << std::endl;
+      eq_lhs = NodeManager::currentNM()->mkNode( MULT, rhs_coeff, eq_lhs );
+      eq_lhs = Rewriter::rewrite( eq_lhs );
+    }
+    if( !lhs_coeff.isNull() ){
+      Trace("cegqi-arith-debug") << "...mult rhs by " << lhs_coeff << std::endl;
+      eq_rhs = NodeManager::currentNM()->mkNode( MULT, lhs_coeff, eq_rhs );
+      eq_rhs = Rewriter::rewrite( eq_rhs );
+    }
+  }
+  Node eq = eq_lhs.eqNode( eq_rhs );
+  eq = Rewriter::rewrite( eq );
+  Node val;
+  TermProperties pv_prop;
+  Node vts_coeff_inf;
+  Node vts_coeff_delta;
+  //isolate pv in the equality
+  int ires = solve_arith( ci, pv, eq, pv_prop.d_coeff, val, vts_coeff_inf, vts_coeff_delta );
+  if( ires!=0 ){
+    pv_prop.d_type = 0;
+    if (ci->constructInstantiationInc(pv, val, pv_prop, sf))
+    {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+Node ArithInstantiator::hasProcessAssertion(CegInstantiator* ci,
+                                            SolvedForm& sf,
+                                            Node pv,
+                                            Node lit,
+                                            CegInstEffort effort)
+{
+  Node atom = lit.getKind()==NOT ? lit[0] : lit;
+  bool pol = lit.getKind()!=NOT;
+  //arithmetic inequalities and disequalities
+  if (atom.getKind() == GEQ ||
+      (atom.getKind() == EQUAL && !pol && atom[0].getType().isReal())) {
+    return lit;
+  } else {
+    return Node::null();
+  }
+}
+
+bool ArithInstantiator::processAssertion(CegInstantiator* ci,
+                                         SolvedForm& sf,
+                                         Node pv,
+                                         Node lit,
+                                         Node alit,
+                                         CegInstEffort effort)
+{
+  Node atom = lit.getKind()==NOT ? lit[0] : lit;
+  bool pol = lit.getKind()!=NOT;
+  //arithmetic inequalities and disequalities
+  Assert( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) );
+  // get model value for pv
+  Node pv_value = ci->getModelValue( pv );
+  //cannot contain infinity?
+  Node vts_coeff_inf;
+  Node vts_coeff_delta;
+  Node val;
+  TermProperties pv_prop;
+  //isolate pv in the inequality
+  int ires = solve_arith( ci, pv, atom, pv_prop.d_coeff, val, vts_coeff_inf, vts_coeff_delta );
+  if( ires!=0 ){
+    //disequalities are either strict upper or lower bounds
+    unsigned rmax = ( atom.getKind()==GEQ || options::cbqiModel() ) ? 1 : 2;
+    for( unsigned r=0; r<rmax; r++ ){
+      int uires = ires;
+      Node uval = val;
+      if( atom.getKind()==GEQ ){
+        //push negation downwards
+        if( !pol ){
+          uires = -ires;
+          if( d_type.isInteger() ){
+            uval = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkConst( Rational( uires ) ) );
+            uval = Rewriter::rewrite( uval );
+          }else{
+            Assert( d_type.isReal() );
+            //now is strict inequality
+            uires = uires*2;
+          }
+        }
+      }else{
+        bool is_upper;
+        if( options::cbqiModel() ){
+          // disequality is a disjunction : only consider the bound in the direction of the model
+          //first check if there is an infinity...
+          if( !vts_coeff_inf.isNull() ){
+            //coefficient or val won't make a difference, just compare with zero
+            Trace("cegqi-arith-debug") << "Disequality : check infinity polarity " << vts_coeff_inf << std::endl;
+            Assert( vts_coeff_inf.isConst() );
+            is_upper = ( vts_coeff_inf.getConst<Rational>().sgn()==1 );
+          }else{
+            Node rhs_value = ci->getModelValue( val );
+            Node lhs_value = pv_prop.getModifiedTerm( pv_value );
+            if( !pv_prop.isBasic() ){
+              lhs_value = pv_prop.getModifiedTerm( pv_value );
+              lhs_value = Rewriter::rewrite( lhs_value );
+            }
+            Trace("cegqi-arith-debug") << "Disequality : check model values " << lhs_value << " " << rhs_value << std::endl;
+            Assert( lhs_value!=rhs_value );
+            Node cmp = NodeManager::currentNM()->mkNode( GEQ, lhs_value, rhs_value );
+            cmp = Rewriter::rewrite( cmp );
+            Assert( cmp.isConst() );
+            is_upper = ( cmp!=ci->getQuantifiersEngine()->getTermUtil()->d_true );
+          }
+        }else{
+          is_upper = (r==0);
+        }
+        Assert( atom.getKind()==EQUAL && !pol );
+        if( d_type.isInteger() ){
+          uires = is_upper ? -1 : 1;
+          uval = NodeManager::currentNM()->mkNode( PLUS, val, NodeManager::currentNM()->mkConst( Rational( uires ) ) );
+          uval = Rewriter::rewrite( uval );
+        }else{
+          Assert( d_type.isReal() );
+          uires = is_upper ? -2 : 2;
+        }
+      }
+      if( Trace.isOn("cegqi-arith-bound-inf") ){
+        Node pvmod = pv_prop.getModifiedTerm( pv );
+        Trace("cegqi-arith-bound-inf") << "From " << lit << ", got : ";
+        Trace("cegqi-arith-bound-inf") << pvmod << " -> " << uval << ", styp = " << uires << std::endl;
+      }
+      //take into account delta
+      if( ci->useVtsDelta() && ( uires==2 || uires==-2 ) ){
+        if( options::cbqiModel() ){
+          Node delta_coeff = NodeManager::currentNM()->mkConst( Rational( uires > 0 ? 1 : -1 ) );
+          if( vts_coeff_delta.isNull() ){
+            vts_coeff_delta = delta_coeff;
+          }else{
+            vts_coeff_delta = NodeManager::currentNM()->mkNode( PLUS, vts_coeff_delta, delta_coeff );
+            vts_coeff_delta = Rewriter::rewrite( vts_coeff_delta );
+          }
+        }else{
+          Node delta = ci->getQuantifiersEngine()->getTermUtil()->getVtsDelta();
+          uval = NodeManager::currentNM()->mkNode( uires==2 ? PLUS : MINUS, uval, delta );
+          uval = Rewriter::rewrite( uval );
+        }
+      }
+      if( options::cbqiModel() ){
+        //just store bounds, will choose based on tighest bound
+        unsigned index = uires>0 ? 0 : 1;
+        d_mbp_bounds[index].push_back( uval );
+        d_mbp_coeff[index].push_back( pv_prop.d_coeff );
+        Trace("cegqi-arith-debug") << "Store bound " << index << " " << uval << " " << pv_prop.d_coeff << " " << vts_coeff_inf << " " << vts_coeff_delta << " " << lit << std::endl;
+        for( unsigned t=0; t<2; t++ ){
+          d_mbp_vts_coeff[index][t].push_back( t==0 ? vts_coeff_inf : vts_coeff_delta );
+        }
+        d_mbp_lit[index].push_back( lit );
+      }else{
+        //try this bound
+        pv_prop.d_type = uires>0 ? 1 : -1;
+        if (ci->constructInstantiationInc(pv, uval, pv_prop, sf))
+        {
+          return true;
+        }
+      }
+    }
+  }
+
+
+  return false;
+}
+
+bool ArithInstantiator::processAssertions(CegInstantiator* ci,
+                                          SolvedForm& sf,
+                                          Node pv,
+                                          CegInstEffort effort)
+{
+  if (options::cbqiModel()) {
+    bool use_inf = ci->useVtsInfinity() && ( d_type.isInteger() ? options::cbqiUseInfInt() : options::cbqiUseInfReal() );
+    bool upper_first = false;
+    if( options::cbqiMinBounds() ){
+      upper_first = d_mbp_bounds[1].size()<d_mbp_bounds[0].size();
+    }
+    int best_used[2];
+    std::vector< Node > t_values[3];
+    Node zero = ci->getQuantifiersEngine()->getTermUtil()->d_zero;
+    Node one = ci->getQuantifiersEngine()->getTermUtil()->d_one;
+    Node pv_value = ci->getModelValue( pv );
+    //try optimal bounds
+    for( unsigned r=0; r<2; r++ ){
+      int rr = upper_first ? (1-r) : r;
+      best_used[rr] = -1;
+      if( d_mbp_bounds[rr].empty() ){
+        if( use_inf ){
+          Trace("cegqi-arith-bound") << "No " << ( rr==0 ? "lower" : "upper" ) << " bounds for " << pv << " (type=" << d_type << ")" << std::endl;
+          //no bounds, we do +- infinity
+          Node val = ci->getQuantifiersEngine()->getTermUtil()->getVtsInfinity( d_type );
+          //TODO : rho value for infinity?
+          if( rr==0 ){
+            val = NodeManager::currentNM()->mkNode( UMINUS, val );
+            val = Rewriter::rewrite( val );
+          }
+          TermProperties pv_prop_no_bound;
+          if (ci->constructInstantiationInc(pv, val, pv_prop_no_bound, sf))
+          {
+            return true;
+          }
+        }
+      }else{
+        Trace("cegqi-arith-bound") << ( rr==0 ? "Lower" : "Upper" ) << " bounds for " << pv << " (type=" << d_type << ") : " << std::endl;
+        int best = -1;
+        Node best_bound_value[3];
+        for( unsigned j=0; j<d_mbp_bounds[rr].size(); j++ ){
+          Node value[3];
+          if( Trace.isOn("cegqi-arith-bound") ){
+            Assert( !d_mbp_bounds[rr][j].isNull() );
+            Trace("cegqi-arith-bound") << "  " << j << ": " << d_mbp_bounds[rr][j];
+            if( !d_mbp_vts_coeff[rr][0][j].isNull() ){
+              Trace("cegqi-arith-bound") << " (+ " << d_mbp_vts_coeff[rr][0][j] << " * INF)";
+            }
+            if( !d_mbp_vts_coeff[rr][1][j].isNull() ){
+              Trace("cegqi-arith-bound") << " (+ " << d_mbp_vts_coeff[rr][1][j] << " * DELTA)";
+            }
+            if( !d_mbp_coeff[rr][j].isNull() ){
+              Trace("cegqi-arith-bound") << " (div " << d_mbp_coeff[rr][j] << ")";
+            }
+            Trace("cegqi-arith-bound") << ", value = ";
+          }
+          t_values[rr].push_back( Node::null() );
+          //check if it is better than the current best bound : lexicographic order infinite/finite/infinitesimal parts
+          bool new_best = true;
+          for( unsigned t=0; t<3; t++ ){
+            //get the value
+            if( t==0 ){
+              value[0] = d_mbp_vts_coeff[rr][0][j];
+              if( !value[0].isNull() ){
+                Trace("cegqi-arith-bound") << "( " << value[0] << " * INF ) + ";
+              }else{
+                value[0] = zero;
+              }
+            }else if( t==1 ){
+              Node t_value = ci->getModelValue( d_mbp_bounds[rr][j] );
+              t_values[rr][j] = t_value;
+              value[1] = t_value;
+              Trace("cegqi-arith-bound") << value[1];
+            }else{
+              value[2] = d_mbp_vts_coeff[rr][1][j];
+              if( !value[2].isNull() ){
+                Trace("cegqi-arith-bound") << " + ( " << value[2] << " * DELTA )";
+              }else{
+                value[2] = zero;
+              }
+            }
+            //multiply by coefficient
+            if( value[t]!=zero && !d_mbp_coeff[rr][j].isNull() ){
+              Assert( d_mbp_coeff[rr][j].isConst() );
+              value[t] = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(1) / d_mbp_coeff[rr][j].getConst<Rational>() ), value[t] );
+              value[t] = Rewriter::rewrite( value[t] );
+            }
+            //check if new best
+            if( best!=-1 ){
+              Assert( !value[t].isNull() && !best_bound_value[t].isNull() );
+              if( value[t]!=best_bound_value[t] ){
+                Kind k = rr==0 ? GEQ : LEQ;
+                Node cmp_bound = NodeManager::currentNM()->mkNode( k, value[t], best_bound_value[t] );
+                cmp_bound = Rewriter::rewrite( cmp_bound );
+                if( cmp_bound!=ci->getQuantifiersEngine()->getTermUtil()->d_true ){
+                  new_best = false;
+                  break;
+                }
+              }
+            }
+          }
+          Trace("cegqi-arith-bound") << std::endl;
+          if( new_best ){
+            for( unsigned t=0; t<3; t++ ){
+              best_bound_value[t] = value[t];
+            }
+            best = j;
+          }
+        }
+        if( best!=-1 ){
+          Trace("cegqi-arith-bound") << "...best bound is " << best << " : ";
+          if( best_bound_value[0]!=zero ){
+            Trace("cegqi-arith-bound") << "( " << best_bound_value[0] << " * INF ) + ";
+          }
+          Trace("cegqi-arith-bound") << best_bound_value[1];
+          if( best_bound_value[2]!=zero ){
+            Trace("cegqi-arith-bound") << " + ( " << best_bound_value[2] << " * DELTA )";
+          }
+          Trace("cegqi-arith-bound") << std::endl;
+          best_used[rr] = best;
+          //if using cbqiMidpoint, only add the instance based on one bound if the bound is non-strict
+          if (!options::cbqiMidpoint() || d_type.isInteger()
+              || (ci->useVtsDelta() && d_mbp_vts_coeff[rr][1][best].isNull()))
+          {
+            Node val = d_mbp_bounds[rr][best];
+            val = getModelBasedProjectionValue( ci, pv, val, rr==0, d_mbp_coeff[rr][best], pv_value, t_values[rr][best], sf.getTheta(),
+                                                d_mbp_vts_coeff[rr][0][best], d_mbp_vts_coeff[rr][1][best] );
+            if( !val.isNull() ){
+              TermProperties pv_prop_bound;
+              pv_prop_bound.d_coeff = d_mbp_coeff[rr][best];
+              pv_prop_bound.d_type = rr==0 ? 1 : -1;
+              if (ci->constructInstantiationInc(pv, val, pv_prop_bound, sf))
+              {
+                return true;
+              }
+            }
+          }
+        }
+      }
+    }
+    //if not using infinity, use model value of zero
+    if( !use_inf && d_mbp_bounds[0].empty() && d_mbp_bounds[1].empty() ){
+      Node val = zero;
+      TermProperties pv_prop_zero;
+      Node theta = sf.getTheta();
+      val = getModelBasedProjectionValue( ci, pv, val, true, pv_prop_zero.d_coeff, pv_value, zero, sf.getTheta(), Node::null(), Node::null() );
+      if( !val.isNull() ){
+        if (ci->constructInstantiationInc(pv, val, pv_prop_zero, sf))
+        {
+          return true;
+        }
+      }
+    }
+    if( options::cbqiMidpoint() && !d_type.isInteger() ){
+      Node vals[2];
+      bool bothBounds = true;
+      Trace("cegqi-arith-bound") << "Try midpoint of bounds..." << std::endl;
+      for( unsigned rr=0; rr<2; rr++ ){
+        int best = best_used[rr];
+        if( best==-1 ){
+          bothBounds = false;
+        }else{
+          vals[rr] = d_mbp_bounds[rr][best];
+          vals[rr] = getModelBasedProjectionValue( ci, pv, vals[rr], rr==0, Node::null(), pv_value, t_values[rr][best], sf.getTheta(),
+                                                   d_mbp_vts_coeff[rr][0][best], Node::null() );
+        }
+        Trace("cegqi-arith-bound") << "Bound : " << vals[rr] << std::endl;
+      }
+      Node val;
+      if( bothBounds ){
+        Assert( !vals[0].isNull() && !vals[1].isNull() );
+        if( vals[0]==vals[1] ){
+          val = vals[0];
+        }else{
+          val = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkNode( PLUS, vals[0], vals[1] ),
+                                                        NodeManager::currentNM()->mkConst( Rational(1)/Rational(2) ) );
+          val = Rewriter::rewrite( val );
+        }
+      }else{
+        if( !vals[0].isNull() ){
+          val = NodeManager::currentNM()->mkNode( PLUS, vals[0], one );
+          val = Rewriter::rewrite( val );
+        }else if( !vals[1].isNull() ){
+          val = NodeManager::currentNM()->mkNode( MINUS, vals[1], one );
+          val = Rewriter::rewrite( val );
+        }
+      }
+      Trace("cegqi-arith-bound") << "Midpoint value : " << val << std::endl;
+      if( !val.isNull() ){
+        TermProperties pv_prop_midpoint;
+        if (ci->constructInstantiationInc(pv, val, pv_prop_midpoint, sf))
+        {
+          return true;
+        }
+      }
+    }
+    //generally should not make it to this point FIXME: write proper assertion
+    //Assert( ( ci->hasNestedQuantification() && !options::cbqiNestedQE() ) || options::cbqiAll() );
+
+    if( options::cbqiNopt() ){
+      //try non-optimal bounds (heuristic, may help when nested quantification) ?
+      Trace("cegqi-arith-bound") << "Try non-optimal bounds..." << std::endl;
+      for( unsigned r=0; r<2; r++ ){
+        int rr = upper_first ? (1-r) : r;
+        for( unsigned j=0; j<d_mbp_bounds[rr].size(); j++ ){
+          if( (int)j!=best_used[rr] && ( !options::cbqiMidpoint() || d_mbp_vts_coeff[rr][1][j].isNull() ) ){
+            Node val = getModelBasedProjectionValue( ci, pv, d_mbp_bounds[rr][j], rr==0, d_mbp_coeff[rr][j], pv_value, t_values[rr][j], sf.getTheta(),
+                                                     d_mbp_vts_coeff[rr][0][j], d_mbp_vts_coeff[rr][1][j] );
+            if( !val.isNull() ){
+              TermProperties pv_prop_nopt_bound;
+              pv_prop_nopt_bound.d_coeff = d_mbp_coeff[rr][j];
+              pv_prop_nopt_bound.d_type = rr==0 ? 1 : -1;
+              if (ci->constructInstantiationInc(
+                      pv, val, pv_prop_nopt_bound, sf))
+              {
+                return true;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return false;
+}
+
+bool ArithInstantiator::needsPostProcessInstantiationForVariable(
+    CegInstantiator* ci, SolvedForm& sf, Node pv, CegInstEffort effort)
+{
+  return std::find( sf.d_non_basic.begin(), sf.d_non_basic.end(), pv )!=sf.d_non_basic.end();
+}
+
+bool ArithInstantiator::postProcessInstantiationForVariable(
+    CegInstantiator* ci,
+    SolvedForm& sf,
+    Node pv,
+    CegInstEffort effort,
+    std::vector<Node>& lemmas)
+{
+  Assert( std::find( sf.d_non_basic.begin(), sf.d_non_basic.end(), pv )!=sf.d_non_basic.end() );
+  Assert( std::find( sf.d_vars.begin(), sf.d_vars.end(), pv )!=sf.d_vars.end() );
+  unsigned index = std::find( sf.d_vars.begin(), sf.d_vars.end(), pv )-sf.d_vars.begin();
+  Assert( !sf.d_props[index].isBasic() );
+  Node eq_lhs = sf.d_props[index].getModifiedTerm( sf.d_vars[index] );
+  if( Trace.isOn("cegqi-arith-debug") ){
+    Trace("cegqi-arith-debug") << "Normalize substitution for ";
+    Trace("cegqi-arith-debug") << eq_lhs << " = " << sf.d_subs[index] << std::endl;
+  }
+  Assert( sf.d_vars[index].getType().isInteger() );
+  //must ensure that divisibility constraints are met
+  //solve updated rewritten equality for vars[index], if coefficient is one, then we are successful
+  Node eq_rhs = sf.d_subs[index];
+  Node eq = eq_lhs.eqNode( eq_rhs );
+  eq = Rewriter::rewrite( eq );
+  Trace("cegqi-arith-debug") << "...equality is " << eq << std::endl;
+  std::map< Node, Node > msum;
+  if (ArithMSum::getMonomialSumLit(eq, msum))
+  {
+    Node veq;
+    if (ArithMSum::isolate(sf.d_vars[index], msum, veq, EQUAL, true) != 0)
+    {
+      Node veq_c;
+      if( veq[0]!=sf.d_vars[index] ){
+        Node veq_v;
+        if (ArithMSum::getMonomial(veq[0], veq_c, veq_v))
+        {
+          Assert( veq_v==sf.d_vars[index] );
+        }
+      }
+      sf.d_subs[index] = veq[1];
+      if( !veq_c.isNull() ){
+        sf.d_subs[index] = NodeManager::currentNM()->mkNode( INTS_DIVISION_TOTAL, veq[1], veq_c );
+        Trace("cegqi-arith-debug") << "...bound type is : " << sf.d_props[index].d_type << std::endl;
+        //intger division rounding up if from a lower bound
+        if( sf.d_props[index].d_type==1 && options::cbqiRoundUpLowerLia() ){
+          sf.d_subs[index] = NodeManager::currentNM()->mkNode( PLUS, sf.d_subs[index],
+            NodeManager::currentNM()->mkNode( ITE,
+              NodeManager::currentNM()->mkNode( EQUAL,
+                NodeManager::currentNM()->mkNode( INTS_MODULUS_TOTAL, veq[1], veq_c ),
+                ci->getQuantifiersEngine()->getTermUtil()->d_zero ),
+              ci->getQuantifiersEngine()->getTermUtil()->d_zero, ci->getQuantifiersEngine()->getTermUtil()->d_one )
+          );
+        }
+      }
+      Trace("cegqi-arith-debug") << "...normalize integers : " << sf.d_vars[index] << " -> " << sf.d_subs[index] << std::endl;
+    }else{
+      Trace("cegqi-arith-debug") << "...failed to isolate." << std::endl;
+      return false;
+    }
+  }else{
+    Trace("cegqi-arith-debug") << "...failed to get monomial sum." << std::endl;
+    return false;
+  }
+  return true;
+}
+
+void DtInstantiator::reset(CegInstantiator* ci,
+                           SolvedForm& sf,
+                           Node pv,
+                           CegInstEffort effort)
+{
+}
+
+Node DtInstantiator::solve_dt( Node v, Node a, Node b, Node sa, Node sb ) {
+  Trace("cegqi-arith-debug2") << "Solve dt : " << v << " " << a << " " << b << " " << sa << " " << sb << std::endl;
+  Node ret;
+  if( !a.isNull() && a==v ){
+    ret = sb;
+  }else if( !b.isNull() && b==v ){
+    ret = sa;
+  }else if( !a.isNull() && a.getKind()==APPLY_CONSTRUCTOR ){
+    if( !b.isNull() && b.getKind()==APPLY_CONSTRUCTOR ){
+      if( a.getOperator()==b.getOperator() ){
+        for( unsigned i=0; i<a.getNumChildren(); i++ ){
+          Node s = solve_dt( v, a[i], b[i], sa[i], sb[i] );
+          if( !s.isNull() ){
+            return s;
+          }
+        }
+      }
+    }else{
+      unsigned cindex = Datatype::indexOf( a.getOperator().toExpr() );
+      TypeNode tn = a.getType();
+      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+      for( unsigned i=0; i<a.getNumChildren(); i++ ){
+        Node nn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex].getSelectorInternal( tn.toType(), i ) ), sb );
+        Node s = solve_dt( v, a[i], Node::null(), sa[i], nn );
+        if( !s.isNull() ){
+          return s;
+        }
+      }
+    }
+  }else if( !b.isNull() && b.getKind()==APPLY_CONSTRUCTOR ){
+    return solve_dt( v, b, a, sb, sa );
+  }
+  if( !ret.isNull() ){
+    //ensure does not contain
+    if( TermUtil::containsTerm( ret, v ) ){
+      ret = Node::null();
+    }
+  }
+  return ret;
+}
+
+bool DtInstantiator::processEqualTerms(CegInstantiator* ci,
+                                       SolvedForm& sf,
+                                       Node pv,
+                                       std::vector<Node>& eqc,
+                                       CegInstEffort effort)
+{
+  Trace("cegqi-dt-debug") << "try based on constructors in equivalence class."
+                          << std::endl;
+  // look in equivalence class for a constructor
+  for( unsigned k=0; k<eqc.size(); k++ ){
+    Node n = eqc[k];
+    if( n.getKind()==APPLY_CONSTRUCTOR ){
+      Trace("cegqi-dt-debug") << "...try based on constructor term " << n << std::endl;
+      std::vector< Node > children;
+      children.push_back( n.getOperator() );
+      const Datatype& dt = ((DatatypeType)(d_type).toType()).getDatatype();
+      unsigned cindex = Datatype::indexOf( n.getOperator().toExpr() );
+      //now must solve for selectors applied to pv
+      for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){
+        Node c = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex].getSelectorInternal( d_type.toType(), j ) ), pv );
+        ci->pushStackVariable( c );
+        children.push_back( c );
+      }
+      Node val = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, children );
+      TermProperties pv_prop_dt;
+      if (ci->constructInstantiationInc(pv, val, pv_prop_dt, sf))
+      {
+        return true;
+      }else{
+        //cleanup
+        for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){
+          ci->popStackVariable();
+        }
+        break;
+      }
+    }
+  }
+  return false;
+}
+
+bool DtInstantiator::processEquality(CegInstantiator* ci,
+                                     SolvedForm& sf,
+                                     Node pv,
+                                     std::vector<TermProperties>& term_props,
+                                     std::vector<Node>& terms,
+                                     CegInstEffort effort)
+{
+  Node val = solve_dt( pv, terms[0], terms[1], terms[0], terms[1] );
+  if( !val.isNull() ){
+    TermProperties pv_prop;
+    if (ci->constructInstantiationInc(pv, val, pv_prop, sf))
+    {
+      return true;
+    }
+  }
+  return false;
+}
+
+void EprInstantiator::reset(CegInstantiator* ci,
+                            SolvedForm& sf,
+                            Node pv,
+                            CegInstEffort effort)
+{
+  d_equal_terms.clear();
+}
+
+bool EprInstantiator::processEqualTerm(CegInstantiator* ci,
+                                       SolvedForm& sf,
+                                       Node pv,
+                                       TermProperties& pv_prop,
+                                       Node n,
+                                       CegInstEffort effort)
+{
+  if( options::quantEprMatching() ){
+    Assert( pv_prop.isBasic() );
+    d_equal_terms.push_back( n );
+    return false;
+  }else{
+    pv_prop.d_type = 0;
+    return ci->constructInstantiationInc(pv, n, pv_prop, sf);
+  }
+}
+
+void EprInstantiator::computeMatchScore( CegInstantiator * ci, Node pv, Node catom, std::vector< Node >& arg_reps, TermArgTrie * tat, unsigned index, std::map< Node, int >& match_score ) {
+  if( index==catom.getNumChildren() ){
+    Assert( tat->hasNodeData() );
+    Node gcatom = tat->getNodeData();
+    Trace("cegqi-epr") << "Matched : " << catom << " and " << gcatom << std::endl;
+    for( unsigned i=0; i<catom.getNumChildren(); i++ ){
+      if( catom[i]==pv ){
+        Trace("cegqi-epr") << "...increment " << gcatom[i] << std::endl;
+        match_score[gcatom[i]]++;
+      }else{
+        //recursive matching
+        computeMatchScore( ci, pv, catom[i], gcatom[i], match_score );
+      }
+    }
+  }else{
+    std::map< TNode, TermArgTrie >::iterator it = tat->d_data.find( arg_reps[index] );
+    if( it!=tat->d_data.end() ){
+      computeMatchScore( ci, pv, catom, arg_reps, &it->second, index+1, match_score );
+    }
+  }
+}
+
+void EprInstantiator::computeMatchScore( CegInstantiator * ci, Node pv, Node catom, Node eqc, std::map< Node, int >& match_score ) {
+  if( inst::Trigger::isAtomicTrigger( catom ) && TermUtil::containsTerm( catom, pv ) ){
+    Trace("cegqi-epr") << "Find matches for " << catom << "..." << std::endl;
+    std::vector< Node > arg_reps;
+    for( unsigned j=0; j<catom.getNumChildren(); j++ ){
+      arg_reps.push_back( ci->getQuantifiersEngine()->getMasterEqualityEngine()->getRepresentative( catom[j] ) );
+    }
+    if( ci->getQuantifiersEngine()->getMasterEqualityEngine()->hasTerm( eqc ) ){
+      Node rep = ci->getQuantifiersEngine()->getMasterEqualityEngine()->getRepresentative( eqc );
+      Node op = ci->getQuantifiersEngine()->getTermDatabase()->getMatchOperator( catom );
+      TermArgTrie * tat = ci->getQuantifiersEngine()->getTermDatabase()->getTermArgTrie( rep, op );
+      Trace("cegqi-epr") << "EPR instantiation match term : " << catom << ", check ground terms=" << (tat!=NULL) << std::endl;
+      if( tat ){
+        computeMatchScore( ci, pv, catom, arg_reps, tat, 0, match_score );
+      }
+    }
+  }
+}
+
+struct sortEqTermsMatch {
+  std::map< Node, int > d_match_score;
+  bool operator() (Node i, Node j) {
+    int match_score_i = d_match_score[i];
+    int match_score_j = d_match_score[j];
+    return match_score_i>match_score_j || ( match_score_i==match_score_j && i<j );
+  }
+};
+
+bool EprInstantiator::processEqualTerms(CegInstantiator* ci,
+                                        SolvedForm& sf,
+                                        Node pv,
+                                        std::vector<Node>& eqc,
+                                        CegInstEffort effort)
+{
+  if( options::quantEprMatching() ){
+    //heuristic for best matching constant
+    sortEqTermsMatch setm;
+    for( unsigned i=0; i<ci->getNumCEAtoms(); i++ ){
+      Node catom = ci->getCEAtom( i );
+      computeMatchScore( ci, pv, catom, catom, setm.d_match_score );
+    }
+    //sort by match score
+    std::sort( d_equal_terms.begin(), d_equal_terms.end(), setm );
+    TermProperties pv_prop;
+    pv_prop.d_type = 0;
+    for( unsigned i=0; i<d_equal_terms.size(); i++ ){
+      if (ci->constructInstantiationInc(pv, d_equal_terms[i], pv_prop, sf))
+      {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+// this class can be used to query the model value through the CegInstaniator class
+class CegInstantiatorBvInverterQuery : public BvInverterQuery
+{
+ public:
+  CegInstantiatorBvInverterQuery(CegInstantiator* ci)
+      : BvInverterQuery(), d_ci(ci)
+  {
+  }
+  ~CegInstantiatorBvInverterQuery() {}
+  /** return the model value of n */
+  Node getModelValue( Node n ) {
+    return d_ci->getModelValue( n );
+  }
+  /** get bound variable of type tn */
+  Node getBoundVariable(TypeNode tn) { return d_ci->getBoundVariable(tn); }
+ protected:
+  // pointer to class that is able to query model values
+  CegInstantiator * d_ci;
+};
+
+BvInstantiator::BvInstantiator(QuantifiersEngine* qe, TypeNode tn)
+    : Instantiator(qe, tn), d_tried_assertion_inst(false)
+{
+  // get the global inverter utility
+  // this must be global since we need to:
+  // * process Skolem functions properly across multiple variables within the same quantifier
+  // * cache Skolem variables uniformly across multiple quantified formulas
+  d_inverter = qe->getBvInverter();
+}
+
+BvInstantiator::~BvInstantiator(){
+
+}
+void BvInstantiator::reset(CegInstantiator* ci,
+                           SolvedForm& sf,
+                           Node pv,
+                           CegInstEffort effort)
+{
+  d_inst_id_counter = 0;
+  d_var_to_inst_id.clear();
+  d_inst_id_to_term.clear();
+  d_inst_id_to_alit.clear();
+  d_var_to_curr_inst_id.clear();
+  d_alit_to_model_slack.clear();
+  d_tried_assertion_inst = false;
+}
+
+void BvInstantiator::processLiteral(CegInstantiator* ci,
+                                    SolvedForm& sf,
+                                    Node pv,
+                                    Node lit,
+                                    Node alit,
+                                    CegInstEffort effort)
+{
+  Assert(d_inverter != NULL);
+  // find path to pv
+  std::vector<unsigned> path;
+  Node sv = d_inverter->getSolveVariable(pv.getType());
+  Node pvs = ci->getModelValue(pv);
+  Trace("cegqi-bv") << "Get path to pv : " << lit << std::endl;
+  Node slit = d_inverter->getPathToPv(lit, pv, sv, pvs, path);
+  if (!slit.isNull())
+  {
+    CegInstantiatorBvInverterQuery m(ci);
+    unsigned iid = d_inst_id_counter;
+    Trace("cegqi-bv") << "Solve lit to bv inverter : " << slit << std::endl;
+    Node inst = d_inverter->solveBvLit(sv, slit, path, &m);
+    if (!inst.isNull())
+    {
+      inst = Rewriter::rewrite(inst);
+      if (inst.isConst() || !ci->hasNestedQuantification())
+      {
+        Trace("cegqi-bv") << "...solved form is " << inst << std::endl;
+        // store information for id and increment
+        d_var_to_inst_id[pv].push_back(iid);
+        d_inst_id_to_term[iid] = inst;
+        d_inst_id_to_alit[iid] = alit;
+        d_inst_id_counter++;
+      }
+    }
+    else
+    {
+      Trace("cegqi-bv") << "...failed to solve." << std::endl;
+    }
+  }
+}
+
+Node BvInstantiator::hasProcessAssertion(CegInstantiator* ci,
+                                         SolvedForm& sf,
+                                         Node pv,
+                                         Node lit,
+                                         CegInstEffort effort)
+{
+  if (effort == CEG_INST_EFFORT_FULL)
+  {
+    // always use model values at full effort
+    return Node::null();
+  }
+  Node atom = lit.getKind() == NOT ? lit[0] : lit;
+  bool pol = lit.getKind() != NOT;
+  Kind k = atom.getKind();
+  if (k != EQUAL && k != BITVECTOR_ULT && k != BITVECTOR_SLT)
+  {
+    // others are unhandled
+    return Node::null();
+  }
+  else if (!atom[0].getType().isBitVector())
+  {
+    return Node::null();
+  }
+  else if (options::cbqiBvIneqMode() == CBQI_BV_INEQ_KEEP
+           || (pol && k == EQUAL))
+  {
+    return lit;
+  }
+  NodeManager* nm = NodeManager::currentNM();
+  Node s = atom[0];
+  Node t = atom[1];
+
+  Node sm = ci->getModelValue(s);
+  Node tm = ci->getModelValue(t);
+  Assert(!sm.isNull() && sm.isConst());
+  Assert(!tm.isNull() && tm.isConst());
+  Trace("cegqi-bv") << "Model value: " << std::endl;
+  Trace("cegqi-bv") << "   " << s << " " << k << " " << t << " is "
+                    << std::endl;
+  Trace("cegqi-bv") << "   " << sm << " <> " << tm << std::endl;
+
+  Node ret;
+  if (options::cbqiBvIneqMode() == CBQI_BV_INEQ_EQ_SLACK)
+  {
+    // if using slack, we convert constraints to a positive equality based on
+    // the current model M, e.g.:
+    //   (not) s ~ t  --->  s = t + ( s^M - t^M )
+    if (sm != tm)
+    {
+      Node slack = Rewriter::rewrite(nm->mkNode(BITVECTOR_SUB, sm, tm));
+      Assert(slack.isConst());
+      // remember the slack value for the asserted literal
+      d_alit_to_model_slack[lit] = slack;
+      ret = nm->mkNode(EQUAL, s, nm->mkNode(BITVECTOR_PLUS, t, slack));
+      Trace("cegqi-bv") << "Slack is " << slack << std::endl;
+    }
+    else
+    {
+      ret = s.eqNode(t);
+    }
+  } else {
+    // turn disequality into an inequality
+    // e.g. s != t becomes s < t or t < s
+    if (k == EQUAL)
+    {
+      if (Random::getRandom().pickWithProb(0.5))
+      {
+        std::swap(s, t);
+      }
+      pol = true;
+    }
+    // otherwise, we optimistically solve for the boundary point of an
+    // inequality, for example:
+    //   for s < t, we solve s+1 = t
+    //   for ~( s < t ), we solve s = t
+    // notice that this equality does not necessarily hold in the model, and
+    // hence the corresponding instantiation strategy is not guaranteed to be
+    // monotonic.
+    if (!pol)
+    {
+      ret = s.eqNode(t);
+    } else {
+      Node bv_one = bv::utils::mkOne(bv::utils::getSize(s));
+      ret = nm->mkNode(BITVECTOR_PLUS, s, bv_one).eqNode(t);
+    }
+  }
+  Trace("cegqi-bv") << "Process " << lit << " as " << ret << std::endl;
+  return ret;
+}
+
+bool BvInstantiator::processAssertion(CegInstantiator* ci,
+                                      SolvedForm& sf,
+                                      Node pv,
+                                      Node lit,
+                                      Node alit,
+                                      CegInstEffort effort)
+{
+  // if option enabled, use approach for word-level inversion for BV instantiation
+  if( options::cbqiBv() ){
+    // get the best rewritten form of lit for solving for pv 
+    //   this should remove instances of non-invertible operators, and "linearize" lit with respect to pv as much as possible
+    Node rlit = rewriteAssertionForSolvePv(ci, pv, lit);
+    if( Trace.isOn("cegqi-bv") ){
+      Trace("cegqi-bv") << "BvInstantiator::processAssertion : solve " << pv << " in " << lit << std::endl;
+      if( lit!=rlit ){
+        Trace("cegqi-bv") << "...rewritten to " << rlit << std::endl;
+      }
+    }
+    if (!rlit.isNull())
+    {
+      processLiteral(ci, sf, pv, rlit, alit, effort);
+    }
+  }
+  return false;
+}
+
+bool BvInstantiator::useModelValue(CegInstantiator* ci,
+                                   SolvedForm& sf,
+                                   Node pv,
+                                   CegInstEffort effort)
+{
+  return !d_tried_assertion_inst
+         && (effort < CEG_INST_EFFORT_FULL || options::cbqiFullEffort());
+}
+
+bool BvInstantiator::processAssertions(CegInstantiator* ci,
+                                       SolvedForm& sf,
+                                       Node pv,
+                                       CegInstEffort effort)
+{
+  std::unordered_map< Node, std::vector< unsigned >, NodeHashFunction >::iterator iti = d_var_to_inst_id.find( pv );
+  if( iti!=d_var_to_inst_id.end() ){
+    Trace("cegqi-bv") << "BvInstantiator::processAssertions for " << pv << std::endl;
+    // if interleaving, do not do inversion half the time
+    if (!options::cbqiBvInterleaveValue() || Random::getRandom().pickWithProb(0.5))
+    {
+      bool firstVar = sf.empty();
+      // get inst id list
+      if (Trace.isOn("cegqi-bv"))
+      {
+        Trace("cegqi-bv") << "  " << iti->second.size()
+                          << " candidate instantiations for " << pv << " : "
+                          << std::endl;
+        if (firstVar)
+        {
+          Trace("cegqi-bv") << "  ...this is the first variable" << std::endl;
+        }
+      }
+      // until we have a model-preserving selection function for BV, this must
+      // be heuristic (we only pick one literal)
+      // hence we randomize the list
+      // this helps robustness, since picking the same literal every time may
+      // lead to a stream of value instantiations, whereas with randomization
+      // we may find an invertible literal that leads to a useful instantiation.
+      std::random_shuffle(iti->second.begin(), iti->second.end());
+
+      if (Trace.isOn("cegqi-bv"))
+      {
+        for (unsigned j = 0, size = iti->second.size(); j < size; j++)
+        {
+          unsigned inst_id = iti->second[j];
+          Assert(d_inst_id_to_term.find(inst_id) != d_inst_id_to_term.end());
+          Node inst_term = d_inst_id_to_term[inst_id];
+          Assert(d_inst_id_to_alit.find(inst_id) != d_inst_id_to_alit.end());
+          Node alit = d_inst_id_to_alit[inst_id];
+
+          // get the slack value introduced for the asserted literal
+          Node curr_slack_val;
+          std::unordered_map<Node, Node, NodeHashFunction>::iterator itms =
+              d_alit_to_model_slack.find(alit);
+          if (itms != d_alit_to_model_slack.end())
+          {
+            curr_slack_val = itms->second;
+          }
+
+          // debug printing
+          Trace("cegqi-bv") << "   [" << j << "] : ";
+          Trace("cegqi-bv") << inst_term << std::endl;
+          if (!curr_slack_val.isNull()) {
+            Trace("cegqi-bv") << "   ...with slack value : " << curr_slack_val
+                              << std::endl;
+          }
+          Trace("cegqi-bv-debug") << "   ...from : " << alit << std::endl;
+          Trace("cegqi-bv") << std::endl;
+        }
+      }
+
+      // Now, try all instantiation ids we want to try
+      // Typically we try only one, otherwise worst-case performance
+      // for constructing instantiations is exponential on the number of
+      // variables in this quantifier prefix.
+      bool ret = false;
+      bool tryMultipleInst = firstVar && options::cbqiMultiInst();
+      bool revertOnSuccess = tryMultipleInst;
+      for (unsigned j = 0, size = iti->second.size(); j < size; j++)
+      {
+        unsigned inst_id = iti->second[j];
+        Assert(d_inst_id_to_term.find(inst_id) != d_inst_id_to_term.end());
+        Node inst_term = d_inst_id_to_term[inst_id];
+        Node alit = d_inst_id_to_alit[inst_id];
+        // try instantiation pv -> inst_term
+        TermProperties pv_prop_bv;
+        Trace("cegqi-bv") << "*** try " << pv << " -> " << inst_term
+                          << std::endl;
+        d_var_to_curr_inst_id[pv] = inst_id;
+        d_tried_assertion_inst = true;
+        ci->markSolved(alit);
+        if (ci->constructInstantiationInc(
+                pv, inst_term, pv_prop_bv, sf, revertOnSuccess))
+        {
+          ret = true;
+        }
+        ci->markSolved(alit, false);
+        // we are done unless we try multiple instances
+        if (!tryMultipleInst)
+        {
+          break;
+        }
+      }
+      if (ret)
+      {
+        return true;
+      }
+      Trace("cegqi-bv") << "...failed to add instantiation for " << pv
+                        << std::endl;
+      d_var_to_curr_inst_id.erase(pv);
+    } else {
+      Trace("cegqi-bv") << "...do not do instantiation for " << pv
+                        << " (skip, based on heuristic)" << std::endl;
+    }
+  }
+
+  return false;
+}
+
+Node BvInstantiator::rewriteAssertionForSolvePv(CegInstantiator* ci,
+                                                Node pv,
+                                                Node lit)
+{
+  // result of rewriting the visited term
+  std::stack<std::unordered_map<TNode, Node, TNodeHashFunction> > visited;
+  visited.push(std::unordered_map<TNode, Node, TNodeHashFunction>());
+  // whether the visited term contains pv
+  std::unordered_map<TNode, bool, TNodeHashFunction> visited_contains_pv;
+  std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
+  std::unordered_map<TNode, Node, TNodeHashFunction> curr_subs;
+  std::stack<std::stack<TNode> > visit;
+  TNode cur;
+  visit.push(std::stack<TNode>());
+  visit.top().push(lit);
+  do {
+    cur = visit.top().top();
+    visit.top().pop();
+    it = visited.top().find(cur);
+
+    if (it == visited.top().end())
+    {
+      std::unordered_map<TNode, Node, TNodeHashFunction>::iterator itc =
+          curr_subs.find(cur);
+      if (itc != curr_subs.end())
+      {
+        visited.top()[cur] = itc->second;
+      }
+      else
+      {
+        if (cur.getKind() == CHOICE)
+        {
+          // must replace variables of choice functions
+          // with new variables to avoid variable
+          // capture when considering substitutions
+          // with multiple literals.
+          Node bv = ci->getBoundVariable(cur[0][0].getType());
+          // should not have captured variables
+          Assert(curr_subs.find(cur[0][0]) == curr_subs.end());
+          curr_subs[cur[0][0]] = bv;
+          // we cannot cache the results of subterms
+          // of this choice expression since we are
+          // now in the context { cur[0][0] -> bv },
+          // hence we push a context here
+          visited.push(std::unordered_map<TNode, Node, TNodeHashFunction>());
+          visit.push(std::stack<TNode>());
+        }
+        visited.top()[cur] = Node::null();
+        visit.top().push(cur);
+        for (unsigned i = 0; i < cur.getNumChildren(); i++)
+        {
+          visit.top().push(cur[i]);
+        }
+      }
+    } else if (it->second.isNull()) {
+      Node ret;
+      bool childChanged = false;
+      std::vector<Node> children;
+      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED) {
+        children.push_back(cur.getOperator());
+      }
+      bool contains_pv = ( cur==pv );
+      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
+        it = visited.top().find(cur[i]);
+        Assert(it != visited.top().end());
+        Assert(!it->second.isNull());
+        childChanged = childChanged || cur[i] != it->second;
+        children.push_back(it->second);
+        contains_pv = contains_pv || visited_contains_pv[cur[i]];
+      }
+      // careful that rewrites above do not affect whether this term contains pv
+      visited_contains_pv[cur] = contains_pv;
+
+      // rewrite the term
+      ret = rewriteTermForSolvePv(pv, cur, children, visited_contains_pv);
+
+      // return original if the above function does not produce a result
+      if (ret.isNull()) {
+        if (childChanged) {
+          ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
+        }else{
+          ret = cur;
+        }
+      }
+
+      /* We need to update contains_pv also for rewritten nodes, since
+       * the normalizePv* functions rely on the information if pv occurs in a
+       * rewritten node or not. */
+      if (ret != cur)
+      {
+        contains_pv = (ret == pv);
+        for (unsigned i = 0, size = ret.getNumChildren(); i < size; ++i)
+        {
+          contains_pv = contains_pv || visited_contains_pv[ret[i]];
+        }
+        visited_contains_pv[ret] = contains_pv;
+      }
+
+      // if was choice, pop context
+      if (cur.getKind() == CHOICE)
+      {
+        Assert(curr_subs.find(cur[0][0]) != curr_subs.end());
+        curr_subs.erase(cur[0][0]);
+        visited.pop();
+        visit.pop();
+        Assert(visited.size() == visit.size());
+        Assert(!visit.empty());
+      }
+
+      visited.top()[cur] = ret;
+    }
+  } while (!visit.top().empty());
+  Assert(visited.size() == 1);
+  Assert(visited.top().find(lit) != visited.top().end());
+  Assert(!visited.top().find(lit)->second.isNull());
+
+  Node result = visited.top()[lit];
+
+  if (Trace.isOn("cegqi-bv-nl"))
+  {
+    std::vector<TNode> trace_visit;
+    std::unordered_set<TNode, TNodeHashFunction> trace_visited;
+
+    trace_visit.push_back(result);
+    do
+    {
+      cur = trace_visit.back();
+      trace_visit.pop_back();
+
+      if (trace_visited.find(cur) == trace_visited.end())
+      {
+        trace_visited.insert(cur);
+        trace_visit.insert(trace_visit.end(), cur.begin(), cur.end());
+      }
+      else if (cur == pv)
+      {
+        Trace("cegqi-bv-nl")
+            << "NONLINEAR LITERAL for " << pv << " : " << lit << std::endl;
+      }
+    } while (!trace_visit.empty());
+  }
+
+  return result;
+}
+
+/**
+ * Determine coefficient of pv in term n, where n has the form pv, -pv, pv * t,
+ * or -pv * t. Extracting the coefficient of multiplications only succeeds if
+ * the multiplication are normalized with normalizePvMult.
+ *
+ * If sucessful it returns
+ *   1    if n ==  pv,
+ *  -1    if n == -pv,
+ *   t    if n ==  pv * t,
+ *  -t    if n == -pv * t.
+ * If n is not a linear term, a null node is returned.
+ */
+static Node getPvCoeff(TNode pv, TNode n)
+{
+  bool neg = false;
+  Node coeff;
+
+  if (n.getKind() == BITVECTOR_NEG)
+  {
+    neg = true;
+    n = n[0];
+  }
+
+  if (n == pv)
+  {
+    coeff = bv::utils::mkOne(bv::utils::getSize(pv));
+  }
+  /* All multiplications are normalized to pv * (t1 * t2). */
+  else if (n.getKind() == BITVECTOR_MULT && n.getAttribute(BvLinearAttribute()))
+  {
+    Assert(n.getNumChildren() == 2);
+    Assert(n[0] == pv);
+    coeff = n[1];
+  }
+  else /* n is in no form to extract the coefficient for pv */
+  {
+    Trace("cegqi-bv-nl") << "Cannot extract coefficient for " << pv << " in "
+                         << n << std::endl;
+    return Node::null();
+  }
+  Assert(!coeff.isNull());
+
+  if (neg) return NodeManager::currentNM()->mkNode(BITVECTOR_NEG, coeff);
+  return coeff;
+}
+
+/**
+ * Normalizes the children of a BITVECTOR_MULT w.r.t. pv. contains_pv marks
+ * terms in which pv occurs.
+ * For example,
+ *
+ *  a * -pv * b * c
+ *
+ * is rewritten to
+ *
+ *  pv * -(a * b * c)
+ *
+ * Returns the normalized node if the resulting term is linear w.r.t. pv and
+ * a null node otherwise. If pv does not occur in children it returns a
+ * multiplication over children.
+ */
+static Node normalizePvMult(
+    TNode pv,
+    const std::vector<Node>& children,
+    std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv)
+{
+  bool neg, neg_coeff = false;
+  bool found_pv = false;
+  NodeManager* nm;
+  NodeBuilder<> nb(BITVECTOR_MULT);
+  BvLinearAttribute is_linear;
+
+  nm = NodeManager::currentNM();
+  for (TNode nc : children)
+  {
+    if (!contains_pv[nc])
+    {
+      nb << nc;
+      continue;
+    }
+
+    neg = false;
+    if (nc.getKind() == BITVECTOR_NEG)
+    {
+      neg = true;
+      nc = nc[0];
+    }
+
+    if (!found_pv && nc == pv)
+    {
+      found_pv = true;
+      neg_coeff = neg;
+      continue;
+    }
+    else if (!found_pv && nc.getKind() == BITVECTOR_MULT
+             && nc.getAttribute(is_linear))
+    {
+      Assert(nc.getNumChildren() == 2);
+      Assert(nc[0] == pv);
+      Assert(!contains_pv[nc[1]]);
+      found_pv = true;
+      neg_coeff = neg;
+      nb << nc[1];
+      continue;
+    }
+    return Node::null(); /* non-linear */
+  }
+  Assert(nb.getNumChildren() > 0);
+
+  Node coeff = (nb.getNumChildren() == 1) ? nb[0] : nb.constructNode();
+  if (neg_coeff)
+  {
+    coeff = nm->mkNode(BITVECTOR_NEG, coeff);
+  }
+  coeff = Rewriter::rewrite(coeff);
+  unsigned size_coeff = bv::utils::getSize(coeff);
+  Node zero = bv::utils::mkZero(size_coeff);
+  if (coeff == zero)
+  {
+    return zero;
+  }
+  Node result;
+  if (found_pv)
+  {
+    if (coeff == bv::utils::mkOne(size_coeff))
+    {
+      return pv;
+    }
+    result = nm->mkNode(BITVECTOR_MULT, pv, coeff);
+    contains_pv[result] = true;
+    result.setAttribute(is_linear, true);
+  }
+  else
+  {
+    result = coeff;
+  }
+  return result;
+}
+
+#ifdef CVC4_ASSERTIONS
+static bool isLinearPlus(
+    TNode n,
+    TNode pv,
+    std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv)
+{
+  Node coeff;
+  Assert(n.getAttribute(BvLinearAttribute()));
+  Assert(n.getNumChildren() == 2);
+  if (n[0] != pv)
+  {
+    Assert(n[0].getKind() == BITVECTOR_MULT);
+    Assert(n[0].getNumChildren() == 2);
+    Assert(n[0][0] == pv);
+    Assert(!contains_pv[n[0][1]]);
+  }
+  Assert(!contains_pv[n[1]]);
+  coeff = getPvCoeff(pv, n[0]);
+  Assert(!coeff.isNull());
+  Assert(!contains_pv[coeff]);
+  return true;
+}
+#endif
+
+/**
+ * Normalizes the children of a BITVECTOR_PLUS w.r.t. pv. contains_pv marks
+ * terms in which pv occurs.
+ * For example,
+ *
+ *  a * pv + b + c * -pv
+ *
+ * is rewritten to
+ *
+ *  pv * (a - c) + b
+ *
+ * Returns the normalized node if the resulting term is linear w.r.t. pv and
+ * a null node otherwise. If pv does not occur in children it returns an
+ * addition over children.
+ */
+static Node normalizePvPlus(
+    Node pv,
+    const std::vector<Node>& children,
+    std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv)
+{
+  NodeManager* nm;
+  NodeBuilder<> nb_c(BITVECTOR_PLUS);
+  NodeBuilder<> nb_l(BITVECTOR_PLUS);
+  BvLinearAttribute is_linear;
+  bool neg;
+
+  nm = NodeManager::currentNM();
+  for (TNode nc : children)
+  {
+    if (!contains_pv[nc])
+    {
+      nb_l << nc;
+      continue;
+    }
+
+    neg = false;
+    if (nc.getKind() == BITVECTOR_NEG)
+    {
+      neg = true;
+      nc = nc[0];
+    }
+
+    if (nc == pv
+        || (nc.getKind() == BITVECTOR_MULT && nc.getAttribute(is_linear)))
+    {
+      Node coeff = getPvCoeff(pv, nc);
+      Assert(!coeff.isNull());
+      if (neg)
+      {
+        coeff = nm->mkNode(BITVECTOR_NEG, coeff);
+      }
+      nb_c << coeff;
+      continue;
+    }
+    else if (nc.getKind() == BITVECTOR_PLUS && nc.getAttribute(is_linear))
+    {
+      Assert(isLinearPlus(nc, pv, contains_pv));
+      Node coeff = getPvCoeff(pv, nc[0]);
+      Assert(!coeff.isNull());
+      Node leaf = nc[1];
+      if (neg)
+      {
+        coeff = nm->mkNode(BITVECTOR_NEG, coeff);
+        leaf = nm->mkNode(BITVECTOR_NEG, leaf);
+      }
+      nb_c << coeff;
+      nb_l << leaf;
+      continue;
+    }
+    /* can't collect coefficients of 'pv' in 'cur' -> non-linear */
+    return Node::null();
+  }
+  Assert(nb_c.getNumChildren() > 0 || nb_l.getNumChildren() > 0);
+
+  Node pv_mult_coeffs, result;
+  if (nb_c.getNumChildren() > 0)
+  {
+    Node coeffs = (nb_c.getNumChildren() == 1) ? nb_c[0] : nb_c.constructNode();
+    coeffs = Rewriter::rewrite(coeffs);
+    result = pv_mult_coeffs = normalizePvMult(pv, {pv, coeffs}, contains_pv);
+  }
+
+  if (nb_l.getNumChildren() > 0)
+  {
+    Node leafs = (nb_l.getNumChildren() == 1) ? nb_l[0] : nb_l.constructNode();
+    leafs = Rewriter::rewrite(leafs);
+    Node zero = bv::utils::mkZero(bv::utils::getSize(pv));
+    /* pv * 0 + t --> t */
+    if (pv_mult_coeffs.isNull() || pv_mult_coeffs == zero)
+    {
+      result = leafs;
+    }
+    else
+    {
+      result = nm->mkNode(BITVECTOR_PLUS, pv_mult_coeffs, leafs);
+      contains_pv[result] = true;
+      result.setAttribute(is_linear, true);
+    }
+  }
+  Assert(!result.isNull());
+  return result;
+}
+
+/**
+ * Linearize an equality w.r.t. pv such that pv only occurs once. contains_pv
+ * marks terms in which pv occurs.
+ * For example, equality
+ *
+ *   -pv * a + b = c + pv
+ *
+ * rewrites to
+ *
+ *   pv * (-a - 1) = c - b.
+ */
+static Node normalizePvEqual(
+    Node pv,
+    const std::vector<Node>& children,
+    std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv)
+{
+  Assert(children.size() == 2);
+
+  NodeManager* nm = NodeManager::currentNM();
+  BvLinearAttribute is_linear;
+  Node coeffs[2], leafs[2];
+  bool neg;
+  TNode child;
+
+  for (unsigned i = 0; i < 2; ++i)
+  {
+    child = children[i];
+    neg = false;
+    if (child.getKind() == BITVECTOR_NEG)
+    {
+      neg = true;
+      child = child[0];
+    }
+    if (child.getAttribute(is_linear) || child == pv)
+    {
+      if (child.getKind() == BITVECTOR_PLUS)
+      {
+        Assert(isLinearPlus(child, pv, contains_pv));
+        coeffs[i] = getPvCoeff(pv, child[0]);
+        leafs[i] = child[1];
+      }
+      else
+      {
+        Assert(child.getKind() == BITVECTOR_MULT || child == pv);
+        coeffs[i] = getPvCoeff(pv, child);
+      }
+    }
+    if (neg)
+    {
+      if (!coeffs[i].isNull())
+      {
+        coeffs[i] = nm->mkNode(BITVECTOR_NEG, coeffs[i]);
+      }
+      if (!leafs[i].isNull())
+      {
+        leafs[i] = nm->mkNode(BITVECTOR_NEG, leafs[i]);
+      }
+    }
+  }
+
+  if (coeffs[0].isNull() || coeffs[1].isNull())
+  {
+    return Node::null();
+  }
+
+  Node coeff = nm->mkNode(BITVECTOR_SUB, coeffs[0], coeffs[1]);
+  coeff = Rewriter::rewrite(coeff);
+  std::vector<Node> mult_children = {pv, coeff};
+  Node lhs = normalizePvMult(pv, mult_children, contains_pv);
+
+  Node rhs;
+  if (!leafs[0].isNull() && !leafs[1].isNull())
+  {
+    rhs = nm->mkNode(BITVECTOR_SUB, leafs[1], leafs[0]);
+  }
+  else if (!leafs[0].isNull())
+  {
+    rhs = nm->mkNode(BITVECTOR_NEG, leafs[0]);
+  }
+  else if (!leafs[1].isNull())
+  {
+    rhs = leafs[1];
+  }
+  else
+  {
+    rhs = bv::utils::mkZero(bv::utils::getSize(pv));
+  }
+  rhs = Rewriter::rewrite(rhs);
+
+  if (lhs == rhs)
+  {
+    return bv::utils::mkTrue();
+  }
+
+  Node result = lhs.eqNode(rhs);
+  contains_pv[result] = true;
+  return result;
+}
+
+Node BvInstantiator::rewriteTermForSolvePv(
+    Node pv,
+    Node n,
+    std::vector<Node>& children,
+    std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv)
+{
+  NodeManager* nm = NodeManager::currentNM();
+
+  // [1] rewrite cases of non-invertible operators
+
+  if (n.getKind() == EQUAL)
+  {
+    TNode lhs = children[0];
+    TNode rhs = children[1];
+
+    /* rewrite: x * x = x -> x < 2 */
+    if ((lhs == pv && rhs.getKind() == BITVECTOR_MULT && rhs[0] == pv
+         && rhs[1] == pv)
+        || (rhs == pv && lhs.getKind() == BITVECTOR_MULT && lhs[0] == pv
+            && lhs[1] == pv))
+    {
+      return nm->mkNode(
+          BITVECTOR_ULT,
+          pv,
+          bv::utils::mkConst(BitVector(bv::utils::getSize(pv), Integer(2))));
+    }
+
+    if (options::cbqiBvLinearize() && contains_pv[lhs] && contains_pv[rhs])
+    {
+      Node result = normalizePvEqual(pv, children, contains_pv);
+      if (!result.isNull())
+      {
+        Trace("cegqi-bv-nl")
+            << "Normalize " << n << " to " << result << std::endl;
+      }
+      else
+      {
+        Trace("cegqi-bv-nl")
+            << "Nonlinear " << n.getKind() << " " << n << std::endl;
+      }
+      return result;
+    }
+  }
+  else if (n.getKind() == BITVECTOR_MULT || n.getKind() == BITVECTOR_PLUS)
+  {
+    if (options::cbqiBvLinearize() && contains_pv[n])
+    {
+      Node result;
+      if (n.getKind() == BITVECTOR_MULT)
+      {
+        result = normalizePvMult(pv, children, contains_pv);
+      }
+      else
+      {
+        result = normalizePvPlus(pv, children, contains_pv);
+      }
+      if (!result.isNull())
+      {
+        Trace("cegqi-bv-nl")
+            << "Normalize " << n << " to " << result << std::endl;
+        return result;
+      }
+      else
+      {
+        Trace("cegqi-bv-nl")
+            << "Nonlinear " << n.getKind() << " " << n << std::endl;
+      }
+    }
+  }
+
+  // [2] try to rewrite non-linear literals -> linear literals
+
+  return Node::null();
+}
+
+/** sort bv extract interval
+ *
+ * This sorts lists of bitvector extract terms where
+ * ((_ extract i1 i2) t) < ((_ extract j1 j2) t)
+ * if i1>j1 or i1=j1 and i2>j2.
+ */
+struct SortBvExtractInterval
+{
+  bool operator()(Node i, Node j)
+  {
+    Assert(i.getKind() == BITVECTOR_EXTRACT);
+    Assert(j.getKind() == BITVECTOR_EXTRACT);
+    BitVectorExtract ie = i.getOperator().getConst<BitVectorExtract>();
+    BitVectorExtract je = j.getOperator().getConst<BitVectorExtract>();
+    if (ie.high > je.high)
+    {
+      return true;
+    }
+    else if (ie.high == je.high)
+    {
+      Assert(ie.low != je.low);
+      return ie.low > je.low;
+    }
+    return false;
+  }
+};
+
+void BvInstantiatorPreprocess::registerCounterexampleLemma(
+    std::vector<Node>& lems, std::vector<Node>& ce_vars)
+{
+  // new variables
+  std::vector<Node> vars;
+  // new lemmas
+  std::vector<Node> new_lems;
+
+  if (options::cbqiBvRmExtract())
+  {
+    NodeManager* nm = NodeManager::currentNM();
+    Trace("cegqi-bv-pp") << "-----remove extracts..." << std::endl;
+    // map from terms to bitvector extracts applied to that term
+    std::map<Node, std::vector<Node> > extract_map;
+    std::unordered_set<TNode, TNodeHashFunction> visited;
+    for (unsigned i = 0, size = lems.size(); i < size; i++)
+    {
+      Trace("cegqi-bv-pp-debug2") << "Register ce lemma # " << i << " : "
+                                  << lems[i] << std::endl;
+      collectExtracts(lems[i], extract_map, visited);
+    }
+    for (std::pair<const Node, std::vector<Node> >& es : extract_map)
+    {
+      // sort based on the extract start position
+      std::vector<Node>& curr_vec = es.second;
+
+      SortBvExtractInterval sbei;
+      std::sort(curr_vec.begin(), curr_vec.end(), sbei);
+
+      unsigned width = es.first.getType().getBitVectorSize();
+
+      // list of points b such that:
+      //   b>0 and we must start a segment at (b-1)  or  b==0
+      std::vector<unsigned> boundaries;
+      boundaries.push_back(width);
+      boundaries.push_back(0);
+
+      Trace("cegqi-bv-pp") << "For term " << es.first << " : " << std::endl;
+      for (unsigned i = 0, size = curr_vec.size(); i < size; i++)
+      {
+        Trace("cegqi-bv-pp") << "  " << i << " : " << curr_vec[i] << std::endl;
+        BitVectorExtract e =
+            curr_vec[i].getOperator().getConst<BitVectorExtract>();
+        if (std::find(boundaries.begin(), boundaries.end(), e.high + 1)
+            == boundaries.end())
+        {
+          boundaries.push_back(e.high + 1);
+        }
+        if (std::find(boundaries.begin(), boundaries.end(), e.low)
+            == boundaries.end())
+        {
+          boundaries.push_back(e.low);
+        }
+      }
+      std::sort(boundaries.rbegin(), boundaries.rend());
+
+      // make the extract variables
+      std::vector<Node> children;
+      for (unsigned i = 1; i < boundaries.size(); i++)
+      {
+        Assert(boundaries[i - 1] > 0);
+        Node ex = bv::utils::mkExtract(
+            es.first, boundaries[i - 1] - 1, boundaries[i]);
+        Node var =
+            nm->mkSkolem("ek",
+                         ex.getType(),
+                         "variable to represent disjoint extract region");
+        children.push_back(var);
+        vars.push_back(var);
+      }
+
+      Node conc = nm->mkNode(kind::BITVECTOR_CONCAT, children);
+      Assert(conc.getType() == es.first.getType());
+      Node eq_lem = conc.eqNode(es.first);
+      Trace("cegqi-bv-pp") << "Introduced : " << eq_lem << std::endl;
+      new_lems.push_back(eq_lem);
+      Trace("cegqi-bv-pp") << "...finished processing extracts for term "
+                            << es.first << std::endl;
+    }
+    Trace("cegqi-bv-pp") << "-----done remove extracts" << std::endl;
+  }
+
+  if (!vars.empty())
+  {
+    // could try applying subs -> vars here
+    // in practice, this led to worse performance
+
+    Trace("cegqi-bv-pp") << "Adding " << new_lems.size() << " lemmas..."
+                         << std::endl;
+    lems.insert(lems.end(), new_lems.begin(), new_lems.end());
+    Trace("cegqi-bv-pp") << "Adding " << vars.size() << " variables..."
+                         << std::endl;
+    ce_vars.insert(ce_vars.end(), vars.begin(), vars.end());
+  }
+}
+
+void BvInstantiatorPreprocess::collectExtracts(
+    Node lem,
+    std::map<Node, std::vector<Node> >& extract_map,
+    std::unordered_set<TNode, TNodeHashFunction>& visited)
+{
+  std::vector<TNode> visit;
+  TNode cur;
+  visit.push_back(lem);
+  do
+  {
+    cur = visit.back();
+    visit.pop_back();
+    if (visited.find(cur) == visited.end())
+    {
+      visited.insert(cur);
+      if (cur.getKind() != FORALL)
+      {
+        if (cur.getKind() == BITVECTOR_EXTRACT)
+        {
+          extract_map[cur[0]].push_back(cur);
+        }
+
+        for (const Node& nc : cur)
+        {
+          visit.push_back(nc);
+        }
+      }
+    }
+  } while (!visit.empty());
+}
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/cegqi/ceg_t_instantiator.h b/src/theory/quantifiers/cegqi/ceg_t_instantiator.h
new file mode 100644 (file)
index 0000000..b9c7e20
--- /dev/null
@@ -0,0 +1,331 @@
+/*********************                                                        */
+/*! \file ceg_t_instantiator.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief theory-specific counterexample-guided quantifier instantiation
+ **/
+
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__CEG_T_INSTANTIATOR_H
+#define __CVC4__CEG_T_INSTANTIATOR_H
+
+#include "theory/quantifiers/bv_inverter.h"
+#include "theory/quantifiers/cegqi/ceg_instantiator.h"
+
+#include <unordered_set>
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+/** TODO (#1367) : document these classes, also move to separate files. */
+
+class ArithInstantiator : public Instantiator {
+ public:
+  ArithInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){}
+  virtual ~ArithInstantiator(){}
+  virtual void reset(CegInstantiator* ci,
+                     SolvedForm& sf,
+                     Node pv,
+                     CegInstEffort effort) override;
+  virtual bool hasProcessEquality(CegInstantiator* ci,
+                                  SolvedForm& sf,
+                                  Node pv,
+                                  CegInstEffort effort) override
+  {
+    return true;
+  }
+  virtual bool processEquality(CegInstantiator* ci,
+                               SolvedForm& sf,
+                               Node pv,
+                               std::vector<TermProperties>& term_props,
+                               std::vector<Node>& terms,
+                               CegInstEffort effort) override;
+  virtual bool hasProcessAssertion(CegInstantiator* ci,
+                                   SolvedForm& sf,
+                                   Node pv,
+                                   CegInstEffort effort) override
+  {
+    return true;
+  }
+  virtual Node hasProcessAssertion(CegInstantiator* ci,
+                                   SolvedForm& sf,
+                                   Node pv,
+                                   Node lit,
+                                   CegInstEffort effort) override;
+  virtual bool processAssertion(CegInstantiator* ci,
+                                SolvedForm& sf,
+                                Node pv,
+                                Node lit,
+                                Node alit,
+                                CegInstEffort effort) override;
+  virtual bool processAssertions(CegInstantiator* ci,
+                                 SolvedForm& sf,
+                                 Node pv,
+                                 CegInstEffort effort) override;
+  virtual bool needsPostProcessInstantiationForVariable(
+      CegInstantiator* ci,
+      SolvedForm& sf,
+      Node pv,
+      CegInstEffort effort) override;
+  virtual bool postProcessInstantiationForVariable(
+      CegInstantiator* ci,
+      SolvedForm& sf,
+      Node pv,
+      CegInstEffort effort,
+      std::vector<Node>& lemmas) override;
+  virtual std::string identify() const override { return "Arith"; }
+ private:
+  Node d_vts_sym[2];
+  std::vector<Node> d_mbp_bounds[2];
+  std::vector<Node> d_mbp_coeff[2];
+  std::vector<Node> d_mbp_vts_coeff[2][2];
+  std::vector<Node> d_mbp_lit[2];
+  int solve_arith(CegInstantiator* ci,
+                  Node v,
+                  Node atom,
+                  Node& veq_c,
+                  Node& val,
+                  Node& vts_coeff_inf,
+                  Node& vts_coeff_delta);
+  Node getModelBasedProjectionValue(CegInstantiator* ci,
+                                    Node e,
+                                    Node t,
+                                    bool isLower,
+                                    Node c,
+                                    Node me,
+                                    Node mt,
+                                    Node theta,
+                                    Node inf_coeff,
+                                    Node delta_coeff);
+};
+
+class DtInstantiator : public Instantiator {
+public:
+  DtInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){}
+  virtual ~DtInstantiator(){}
+  virtual void reset(CegInstantiator* ci,
+                     SolvedForm& sf,
+                     Node pv,
+                     CegInstEffort effort) override;
+  virtual bool processEqualTerms(CegInstantiator* ci,
+                                 SolvedForm& sf,
+                                 Node pv,
+                                 std::vector<Node>& eqc,
+                                 CegInstEffort effort) override;
+  virtual bool hasProcessEquality(CegInstantiator* ci,
+                                  SolvedForm& sf,
+                                  Node pv,
+                                  CegInstEffort effort) override
+  {
+    return true;
+  }
+  virtual bool processEquality(CegInstantiator* ci,
+                               SolvedForm& sf,
+                               Node pv,
+                               std::vector<TermProperties>& term_props,
+                               std::vector<Node>& terms,
+                               CegInstEffort effort) override;
+  virtual std::string identify() const override { return "Dt"; }
+ private:
+  Node solve_dt(Node v, Node a, Node b, Node sa, Node sb);
+};
+
+class TermArgTrie;
+
+class EprInstantiator : public Instantiator {
+ public:
+  EprInstantiator( QuantifiersEngine * qe, TypeNode tn ) : Instantiator( qe, tn ){}
+  virtual ~EprInstantiator(){}
+  virtual void reset(CegInstantiator* ci,
+                     SolvedForm& sf,
+                     Node pv,
+                     CegInstEffort effort) override;
+  virtual bool processEqualTerm(CegInstantiator* ci,
+                                SolvedForm& sf,
+                                Node pv,
+                                TermProperties& pv_prop,
+                                Node n,
+                                CegInstEffort effort) override;
+  virtual bool processEqualTerms(CegInstantiator* ci,
+                                 SolvedForm& sf,
+                                 Node pv,
+                                 std::vector<Node>& eqc,
+                                 CegInstEffort effort) override;
+  virtual std::string identify() const override { return "Epr"; }
+ private:
+  std::vector<Node> d_equal_terms;
+  void computeMatchScore(CegInstantiator* ci,
+                         Node pv,
+                         Node catom,
+                         std::vector<Node>& arg_reps,
+                         TermArgTrie* tat,
+                         unsigned index,
+                         std::map<Node, int>& match_score);
+  void computeMatchScore(CegInstantiator* ci,
+                         Node pv,
+                         Node catom,
+                         Node eqc,
+                         std::map<Node, int>& match_score);
+};
+
+/** Bitvector instantiator
+ *
+ * This implements an approach for counterexample-guided instantiation
+ * for bit-vector variables based on word-level inversions.
+ * It is enabled by --cbqi-bv.
+ */
+class BvInstantiator : public Instantiator {
+ public:
+  BvInstantiator(QuantifiersEngine* qe, TypeNode tn);
+  ~BvInstantiator() override;
+  void reset(CegInstantiator* ci,
+             SolvedForm& sf,
+             Node pv,
+             CegInstEffort effort) override;
+  bool hasProcessAssertion(CegInstantiator* ci,
+                           SolvedForm& sf,
+                           Node pv,
+                           CegInstEffort effort) override
+  {
+    return true;
+  }
+  Node hasProcessAssertion(CegInstantiator* ci,
+                           SolvedForm& sf,
+                           Node pv,
+                           Node lit,
+                           CegInstEffort effort) override;
+  bool processAssertion(CegInstantiator* ci,
+                        SolvedForm& sf,
+                        Node pv,
+                        Node lit,
+                        Node alit,
+                        CegInstEffort effort) override;
+  bool processAssertions(CegInstantiator* ci,
+                         SolvedForm& sf,
+                         Node pv,
+                         CegInstEffort effort) override;
+  /** use model value
+   *
+   * We allow model values if we have not already tried an assertion,
+   * and only at levels below full if cbqiFullEffort is false.
+   */
+  bool useModelValue(CegInstantiator* ci,
+                     SolvedForm& sf,
+                     Node pv,
+                     CegInstEffort effort) override;
+  std::string identify() const override { return "Bv"; }
+
+ private:
+  // point to the bv inverter class
+  BvInverter * d_inverter;
+  unsigned d_inst_id_counter;
+  /** information about solved forms */
+  std::unordered_map< Node, std::vector< unsigned >, NodeHashFunction > d_var_to_inst_id;
+  std::unordered_map< unsigned, Node > d_inst_id_to_term;
+  std::unordered_map<unsigned, Node> d_inst_id_to_alit;
+  // variable to current id we are processing
+  std::unordered_map< Node, unsigned, NodeHashFunction > d_var_to_curr_inst_id;
+  /** the amount of slack we added for asserted literals */
+  std::unordered_map<Node, Node, NodeHashFunction> d_alit_to_model_slack;
+  /** whether we have tried an instantiation based on assertion in this round */
+  bool d_tried_assertion_inst;
+  /** rewrite assertion for solve pv
+  * returns a literal that is equivalent to lit that leads to best solved form for pv
+  */
+  Node rewriteAssertionForSolvePv(CegInstantiator* ci, Node pv, Node lit);
+  /** rewrite term for solve pv
+   * This is a helper function for rewriteAssertionForSolvePv.
+   * If this returns non-null value ret, then this indicates
+   * that n should be rewritten to ret. It is called as
+   * a "post-rewrite", that is, after the children of n
+   * have been rewritten and stored in the vector children.
+   *
+   * contains_pv stores whether certain nodes contain pv.
+   * where we guarantee that all subterms of terms in children
+   * appear in the domain of contains_pv.
+   */
+  Node rewriteTermForSolvePv(
+      Node pv,
+      Node n,
+      std::vector<Node>& children,
+      std::unordered_map<TNode, bool, TNodeHashFunction>& contains_pv);
+  /** process literal, called from processAssertion
+  * lit is the literal to solve for pv that has been rewritten according to
+  * internal rules here.
+  * alit is the asserted literal that lit is derived from.
+  */
+  void processLiteral(CegInstantiator* ci,
+                      SolvedForm& sf,
+                      Node pv,
+                      Node lit,
+                      Node alit,
+                      CegInstEffort effort);
+};
+
+/** Bitvector instantiator preprocess
+ *
+ * This class implements preprocess techniques that are helpful for
+ * counterexample-guided instantiation, such as introducing variables
+ * that refer to disjoint bit-vector extracts.
+ */
+class BvInstantiatorPreprocess : public InstantiatorPreprocess
+{
+ public:
+  BvInstantiatorPreprocess() {}
+  ~BvInstantiatorPreprocess() override {}
+  /** register counterexample lemma
+   *
+   * This method modifies the contents of lems based on the extract terms
+   * it contains when the option --cbqi-bv-rm-extract is enabled. It introduces
+   * a dummy equality so that segments of terms t under extracts can be solved
+   * independently.
+   *
+   * For example:
+   *   P[ ((extract 7 4) t), ((extract 3 0) t)]
+   *     becomes:
+   *   P[((extract 7 4) t), ((extract 3 0) t)] ^
+   *   t = concat( x74, x30 )
+   * where x74 and x30 are fresh variables of type BV_4.
+   *
+   * Another example:
+   *   P[ ((extract 7 3) t), ((extract 4 0) t)]
+   *     becomes:
+   *   P[((extract 7 4) t), ((extract 3 0) t)] ^
+   *   t = concat( x75, x44, x30 )
+   * where x75, x44 and x30 are fresh variables of type BV_3, BV_1, and BV_4
+   * respectively.
+   *
+   * Notice we leave the original conjecture alone. This is done for performance
+   * since the added equalities ensure we are able to construct the proper
+   * solved forms for variables in t and for the intermediate variables above.
+   */
+  void registerCounterexampleLemma(std::vector<Node>& lems,
+                                   std::vector<Node>& ce_vars) override;
+
+ private:
+  /** collect extracts
+   *
+   * This method collects all extract terms in lem
+   * and stores them in d_extract_map.
+   * visited is the terms we've already visited.
+   */
+  void collectExtracts(Node lem,
+                       std::map<Node, std::vector<Node> >& extract_map,
+                       std::unordered_set<TNode, TNodeHashFunction>& visited);
+};
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
+
+#endif
diff --git a/src/theory/quantifiers/cegqi/inst_strategy_cbqi.cpp b/src/theory/quantifiers/cegqi/inst_strategy_cbqi.cpp
new file mode 100644 (file)
index 0000000..8de3dbf
--- /dev/null
@@ -0,0 +1,828 @@
+/*********************                                                        */
+/*! \file inst_strategy_cbqi.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Tim King, Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of counterexample-guided quantifier instantiation strategies
+ **/
+#include "theory/quantifiers/cegqi/inst_strategy_cbqi.h"
+
+#include "options/quantifiers_options.h"
+#include "smt/term_formula_removal.h"
+#include "theory/arith/partial_model.h"
+#include "theory/arith/theory_arith.h"
+#include "theory/arith/theory_arith_private.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/instantiate.h"
+#include "theory/quantifiers/quant_epr.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/quantifiers_rewriter.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers/ematching/trigger.h"
+#include "theory/theory_engine.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::theory::arith;
+
+#define ARITH_INSTANTIATOR_USE_MINUS_DELTA
+
+InstStrategyCbqi::InstStrategyCbqi( QuantifiersEngine * qe )
+  : QuantifiersModule( qe ), d_added_cbqi_lemma( qe->getUserContext() ), 
+d_elim_quants( qe->getSatContext() ),
+d_nested_qe_waitlist_size( qe->getUserContext() ),
+d_nested_qe_waitlist_proc( qe->getUserContext() )
+//, d_added_inst( qe->getUserContext() )
+{
+  d_qid_count = 0;
+}
+
+bool InstStrategyCbqi::needsCheck( Theory::Effort e ) {
+  return e>=Theory::EFFORT_LAST_CALL;
+}
+
+QuantifiersModule::QEffort InstStrategyCbqi::needsModel(Theory::Effort e)
+{
+  for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
+    Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
+    if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){
+      return QEFFORT_STANDARD;
+    }
+  }
+  return QEFFORT_NONE;
+}
+
+bool InstStrategyCbqi::registerCbqiLemma( Node q ) {
+  if( !hasAddedCbqiLemma( q ) ){
+    d_added_cbqi_lemma.insert( q );
+    Trace("cbqi-debug") << "Do cbqi for " << q << std::endl;
+    //add cbqi lemma
+    //get the counterexample literal
+    Node ceLit = d_quantEngine->getTermUtil()->getCounterexampleLiteral( q );
+    Node ceBody = d_quantEngine->getTermUtil()->getInstConstantBody( q );
+    if( !ceBody.isNull() ){
+      //add counterexample lemma
+      Node lem = NodeManager::currentNM()->mkNode( OR, ceLit.negate(), ceBody.negate() );
+      //require any decision on cel to be phase=true
+      d_quantEngine->addRequirePhase( ceLit, true );
+      Debug("cbqi-debug") << "Require phase " << ceLit << " = true." << std::endl;
+      //add counterexample lemma
+      lem = Rewriter::rewrite( lem );
+      Trace("cbqi-lemma") << "Counterexample lemma : " << lem << std::endl;
+      registerCounterexampleLemma( q, lem );
+      
+      //totality lemmas for EPR
+      QuantEPR * qepr = d_quantEngine->getQuantEPR();
+      if( qepr!=NULL ){   
+        for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+          TypeNode tn = q[0][i].getType();
+          if( tn.isSort() ){
+            if( qepr->isEPR( tn ) ){
+              //add totality lemma
+              std::map< TypeNode, std::vector< Node > >::iterator itc = qepr->d_consts.find( tn );
+              if( itc!=qepr->d_consts.end() ){
+                Assert( !itc->second.empty() );
+                Node ic = d_quantEngine->getTermUtil()->getInstantiationConstant( q, i );
+                std::vector< Node > disj;
+                for( unsigned j=0; j<itc->second.size(); j++ ){
+                  disj.push_back( ic.eqNode( itc->second[j] ) );
+                }
+                Node tlem = disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( kind::OR, disj );
+                Trace("cbqi-lemma") << "EPR totality lemma : " << tlem << std::endl;
+                d_quantEngine->getOutputChannel().lemma( tlem );
+              }else{
+                Assert( false );
+              }                  
+            }else{
+              Assert( !options::cbqiAll() );
+            }
+          }
+        }
+      }      
+      
+      //compute dependencies between quantified formulas
+      if( options::cbqiLitDepend() || options::cbqiInnermost() ){
+        std::vector< Node > ics;
+        TermUtil::computeVarContains( q, ics );
+        d_parent_quant[q].clear();
+        d_children_quant[q].clear();
+        std::vector< Node > dep;
+        for( unsigned i=0; i<ics.size(); i++ ){
+          Node qi = ics[i].getAttribute(InstConstantAttribute());
+          if( std::find( d_parent_quant[q].begin(), d_parent_quant[q].end(), qi )==d_parent_quant[q].end() ){
+            d_parent_quant[q].push_back( qi );
+            d_children_quant[qi].push_back( q );
+            Assert( hasAddedCbqiLemma( qi ) );
+            Node qicel = d_quantEngine->getTermUtil()->getCounterexampleLiteral( qi );
+            dep.push_back( qi );
+            dep.push_back( qicel );
+          }
+        }
+        if( !dep.empty() ){
+          Node dep_lemma = NodeManager::currentNM()->mkNode( kind::IMPLIES, ceLit, NodeManager::currentNM()->mkNode( kind::AND, dep ) );
+          Trace("cbqi-lemma") << "Counterexample dependency lemma : " << dep_lemma << std::endl;
+          d_quantEngine->getOutputChannel().lemma( dep_lemma );
+        }
+      }
+      
+      //must register all sub-quantifiers of counterexample lemma, register their lemmas
+      std::vector< Node > quants;
+      TermUtil::computeQuantContains( lem, quants );
+      for( unsigned i=0; i<quants.size(); i++ ){
+        if( doCbqi( quants[i] ) ){
+          registerCbqiLemma( quants[i] );
+        }
+        if( options::cbqiNestedQE() ){
+          //record these as counterexample quantifiers
+          QAttributes qa;
+          QuantAttributes::computeQuantAttributes( quants[i], qa );
+          if( !qa.d_qid_num.isNull() ){
+            d_id_to_ce_quant[ qa.d_qid_num ] = quants[i];
+            d_ce_quant_to_id[ quants[i] ] = qa.d_qid_num;
+            Trace("cbqi-nqe") << "CE quant id = " << qa.d_qid_num << " is " << quants[i] << std::endl;
+          }
+        }
+      }
+    }
+    return true;
+  }else{
+    return false;
+  }
+}
+
+void InstStrategyCbqi::reset_round( Theory::Effort effort ) {
+  d_cbqi_set_quant_inactive = false;
+  d_incomplete_check = false;
+  d_active_quant.clear();
+  //check if any cbqi lemma has not been added yet
+  for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
+    Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
+    //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine
+    if( doCbqi( q ) ){
+      Assert( hasAddedCbqiLemma( q ) );
+      if( d_quantEngine->getModel()->isQuantifierActive( q ) ){
+        d_active_quant[q] = true;
+        Debug("cbqi-debug") << "Check quantified formula " << q << "..." << std::endl;
+        Node cel = d_quantEngine->getTermUtil()->getCounterexampleLiteral( q );
+        bool value;
+        if( d_quantEngine->getValuation().hasSatValue( cel, value ) ){
+          Debug("cbqi-debug") << "...CE Literal has value " << value << std::endl;
+          if( !value ){
+            if( d_quantEngine->getValuation().isDecision( cel ) ){
+              Trace("cbqi-warn") << "CBQI WARNING: Bad decision on CE Literal." << std::endl;
+            }else{
+              Trace("cbqi") << "Inactive : " << q << std::endl;
+              d_quantEngine->getModel()->setQuantifierActive( q, false );
+              d_cbqi_set_quant_inactive = true;
+              d_active_quant.erase( q );
+              d_elim_quants.insert( q );
+              Trace("cbqi-nqe") << "Inactive, waitlist proc/size = " << d_nested_qe_waitlist_proc[q].get() << "/" << d_nested_qe_waitlist_size[q].get() << std::endl;
+              //process from waitlist
+              while( d_nested_qe_waitlist_proc[q]<d_nested_qe_waitlist_size[q] ){
+                int index = d_nested_qe_waitlist_proc[q];
+                Assert( index>=0 );
+                Assert( index<(int)d_nested_qe_waitlist[q].size() );
+                Node nq = d_nested_qe_waitlist[q][index];
+                Node nqeqn = doNestedQENode( d_nested_qe_info[nq].d_q, q, nq, d_nested_qe_info[nq].d_inst_terms, d_nested_qe_info[nq].d_doVts );
+                Node dqelem = nq.eqNode( nqeqn ); 
+                Trace("cbqi-lemma") << "Delayed nested quantifier elimination lemma : " << dqelem << std::endl;
+                d_quantEngine->getOutputChannel().lemma( dqelem );
+                d_nested_qe_waitlist_proc[q] = index + 1;
+              }
+            }
+          }
+        }else{
+          Debug("cbqi-debug") << "...CE Literal does not have value " << std::endl;
+        }
+      }
+    }
+  }
+
+  //refinement: only consider innermost active quantified formulas
+  if( options::cbqiInnermost() ){
+    if( !d_children_quant.empty() && !d_active_quant.empty() ){
+      Trace("cbqi-debug") << "Find non-innermost quantifiers..." << std::endl;
+      std::vector< Node > ninner;
+      for( std::map< Node, bool >::iterator it = d_active_quant.begin(); it != d_active_quant.end(); ++it ){
+        std::map< Node, std::vector< Node > >::iterator itc = d_children_quant.find( it->first );
+        if( itc!=d_children_quant.end() ){
+          for( unsigned j=0; j<itc->second.size(); j++ ){
+            if( d_active_quant.find( itc->second[j] )!=d_active_quant.end() ){
+              Trace("cbqi-debug") << "Do not consider " << it->first << " since it is not innermost (" << itc->second[j] << std::endl;
+              ninner.push_back( it->first );
+              break;
+            }
+          }
+        }
+      } 
+      Trace("cbqi-debug") << "Found " << ninner.size() << " non-innermost." << std::endl;
+      for( unsigned i=0; i<ninner.size(); i++ ){
+        Assert( d_active_quant.find( ninner[i] )!=d_active_quant.end() );
+        d_active_quant.erase( ninner[i] );
+      }
+      Assert( !d_active_quant.empty() );
+      Trace("cbqi-debug") << "...done removing." << std::endl;
+    }
+  }
+  
+  processResetInstantiationRound( effort );
+}
+
+void InstStrategyCbqi::check(Theory::Effort e, QEffort quant_e)
+{
+  if (quant_e == QEFFORT_STANDARD)
+  {
+    Assert( !d_quantEngine->inConflict() );
+    double clSet = 0;
+    if( Trace.isOn("cbqi-engine") ){
+      clSet = double(clock())/double(CLOCKS_PER_SEC);
+      Trace("cbqi-engine") << "---Cbqi Engine Round, effort = " << e << "---" << std::endl;
+    }
+    unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting();
+    for( int ee=0; ee<=1; ee++ ){
+      //for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
+      //  Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
+      //  if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){
+      for( std::map< Node, bool >::iterator it = d_active_quant.begin(); it != d_active_quant.end(); ++it ){
+        Node q = it->first;
+        Trace("cbqi") << "CBQI : Process quantifier " << q[0] << " at effort " << ee << std::endl;
+        if( d_nested_qe.find( q )==d_nested_qe.end() ){
+          process( q, e, ee );
+          if( d_quantEngine->inConflict() ){
+            break;
+          }
+        }else{
+          Trace("cbqi-warn") << "CBQI : Cannot process already eliminated quantified formula " << q << std::endl;
+          Assert( false );
+        }
+      }
+      if( d_quantEngine->inConflict() || d_quantEngine->getNumLemmasWaiting()>lastWaiting ){
+        break;
+      }
+    }
+    if( Trace.isOn("cbqi-engine") ){
+      if( d_quantEngine->getNumLemmasWaiting()>lastWaiting ){
+        Trace("cbqi-engine") << "Added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl;
+      }
+      double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+      Trace("cbqi-engine") << "Finished cbqi engine, time = " << (clSet2-clSet) << std::endl;
+    }
+  }
+}
+
+bool InstStrategyCbqi::checkComplete() {
+  if( ( !options::cbqiSat() && d_cbqi_set_quant_inactive ) || d_incomplete_check ){
+    return false;
+  }else{
+    return true;
+  }
+}
+
+bool InstStrategyCbqi::checkCompleteFor( Node q ) {
+  std::map< Node, int >::iterator it = d_do_cbqi.find( q );
+  if( it!=d_do_cbqi.end() ){
+    return it->second>0;
+  }else{
+    return false;
+  }
+}
+
+Node InstStrategyCbqi::getIdMarkedQuantNode( Node n, std::map< Node, Node >& visited ){
+  std::map< Node, Node >::iterator it = visited.find( n );
+  if( it==visited.end() ){
+    Node ret = n;
+    if( n.getKind()==FORALL ){
+      QAttributes qa;
+      QuantAttributes::computeQuantAttributes( n, qa );
+      if( qa.d_qid_num.isNull() ){
+        std::vector< Node > rc;
+        rc.push_back( n[0] );
+        rc.push_back( getIdMarkedQuantNode( n[1], visited ) );
+        Node avar = NodeManager::currentNM()->mkSkolem( "id", NodeManager::currentNM()->booleanType() );
+        QuantIdNumAttribute ida;
+        avar.setAttribute(ida,d_qid_count);
+        d_qid_count++;
+        std::vector< Node > iplc;
+        iplc.push_back( NodeManager::currentNM()->mkNode( INST_ATTRIBUTE, avar ) );
+        if( n.getNumChildren()==3 ){
+          for( unsigned i=0; i<n[2].getNumChildren(); i++ ){
+            iplc.push_back( n[2][i] );
+          }
+        }
+        rc.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, iplc ) );
+        ret = NodeManager::currentNM()->mkNode( FORALL, rc );
+      }
+    }else if( n.getNumChildren()>0 ){
+      std::vector< Node > children;
+      if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+        children.push_back( n.getOperator() );
+      }
+      bool childChanged = false;
+      for( unsigned i=0; i<n.getNumChildren(); i++ ){
+        Node nc = getIdMarkedQuantNode( n[i], visited );
+        childChanged = childChanged || nc!=n[i];
+        children.push_back( nc );
+      }
+      if( childChanged ){
+        ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
+      }
+    }
+    visited[n] = ret;
+    return ret;
+  }else{
+    return it->second;
+  }
+}
+
+void InstStrategyCbqi::preRegisterQuantifier( Node q ) {
+  if( d_quantEngine->getOwner( q )==NULL && doCbqi( q ) ){
+    if( d_do_cbqi[q]==2 ){
+      //take full ownership of the quantified formula
+      d_quantEngine->setOwner( q, this );
+      
+      //mark all nested quantifiers with id
+      if( options::cbqiNestedQE() ){
+        std::map< Node, Node > visited;
+        Node mq = getIdMarkedQuantNode( q[1], visited );
+        if( mq!=q[1] ){
+          //do not do cbqi
+          d_do_cbqi[q] = false;
+          //instead do reduction
+          std::vector< Node > qqc;
+          qqc.push_back( q[0] );
+          qqc.push_back( mq );
+          if( q.getNumChildren()==3 ){
+            qqc.push_back( q[2] );
+          }
+          Node qq = NodeManager::currentNM()->mkNode( FORALL, qqc );
+          Node mlem = NodeManager::currentNM()->mkNode( IMPLIES, q, qq );
+          Trace("cbqi-lemma") << "Mark quant id lemma : " << mlem << std::endl;
+          d_quantEngine->getOutputChannel().lemma( mlem );
+        }
+      }
+    }
+  }
+}
+
+void InstStrategyCbqi::registerQuantifier( Node q ) {
+  if( doCbqi( q ) ){
+    if( registerCbqiLemma( q ) ){
+      Trace("cbqi") << "Registered cbqi lemma for quantifier : " << q << std::endl;
+    }
+  }
+}
+
+Node InstStrategyCbqi::doNestedQENode( Node q, Node ceq, Node n, std::vector< Node >& inst_terms, bool doVts ) {
+  // there is a nested quantified formula (forall y. nq[y,x]) such that 
+  //    q is (forall y. nq[y,t]) for ground terms t,
+  //    ceq is (forall y. nq[y,e]) for CE variables e.
+  // we call this function when we know (forall y. nq[y,e]) is equivalent to quantifier-free formula C[e].
+  // in this case, q is equivalent to the quantifier-free formula C[t].
+  if( d_nested_qe.find( ceq )==d_nested_qe.end() ){
+    d_nested_qe[ceq] = d_quantEngine->getInstantiatedConjunction( ceq );
+    Trace("cbqi-nqe") << "CE quantifier elimination : " << std::endl;
+    Trace("cbqi-nqe") << "  " << ceq << std::endl; 
+    Trace("cbqi-nqe") << "  " << d_nested_qe[ceq] << std::endl;
+    //should not contain quantifiers
+    Assert( !QuantifiersRewriter::containsQuantifiers( d_nested_qe[ceq] ) );
+  }
+  Assert( d_quantEngine->getTermUtil()->d_inst_constants[q].size()==inst_terms.size() );
+  //replace inst constants with instantiation
+  Node ret = d_nested_qe[ceq].substitute( d_quantEngine->getTermUtil()->d_inst_constants[q].begin(),
+                                          d_quantEngine->getTermUtil()->d_inst_constants[q].end(),
+                                          inst_terms.begin(), inst_terms.end() );
+  if( doVts ){
+    //do virtual term substitution
+    ret = Rewriter::rewrite( ret );
+    ret = d_quantEngine->getTermUtil()->rewriteVtsSymbols( ret );
+  }
+  Trace("cbqi-nqe") << "Nested quantifier elimination: " << std::endl;
+  Trace("cbqi-nqe") << "  " << n << std::endl; 
+  Trace("cbqi-nqe") << "  " << ret << std::endl;
+  return ret;
+}
+
+Node InstStrategyCbqi::doNestedQERec( Node q, Node n, std::map< Node, Node >& visited, std::vector< Node >& inst_terms, bool doVts ) {
+  if( visited.find( n )==visited.end() ){
+    Node ret = n;
+    if( n.getKind()==FORALL ){
+      QAttributes qa;
+      QuantAttributes::computeQuantAttributes( n, qa );
+      if( !qa.d_qid_num.isNull() ){
+        //if it has an id, check whether we have done quantifier elimination for this id
+        std::map< Node, Node >::iterator it = d_id_to_ce_quant.find( qa.d_qid_num );
+        if( it!=d_id_to_ce_quant.end() ){
+          Node ceq = it->second;
+          bool doNestedQe = d_elim_quants.contains( ceq );
+          if( doNestedQe ){
+            ret = doNestedQENode( q, ceq, n, inst_terms, doVts );
+          }else{
+            Trace("cbqi-nqe") << "Add to nested qe waitlist : " << std::endl;
+            Node nr = Rewriter::rewrite( n );
+            Trace("cbqi-nqe") << "  " << ceq << std::endl;
+            Trace("cbqi-nqe") << "  " << nr << std::endl;
+            int wlsize = d_nested_qe_waitlist_size[ceq] + 1;
+            d_nested_qe_waitlist_size[ceq] = wlsize;
+            if( wlsize<(int)d_nested_qe_waitlist[ceq].size() ){
+              d_nested_qe_waitlist[ceq][wlsize] = nr;
+            }else{
+              d_nested_qe_waitlist[ceq].push_back( nr );
+            }
+            d_nested_qe_info[nr].d_q = q;
+            d_nested_qe_info[nr].d_inst_terms.clear();
+            d_nested_qe_info[nr].d_inst_terms.insert( d_nested_qe_info[nr].d_inst_terms.end(), inst_terms.begin(), inst_terms.end() );
+            d_nested_qe_info[nr].d_doVts = doVts;
+            //TODO: ensure this holds by restricting prenex when cbqiNestedQe is true.
+            Assert( !options::cbqiInnermost() );
+          }
+        } 
+      } 
+    }else if( n.getNumChildren()>0 ){
+      std::vector< Node > children;
+      if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+        children.push_back( n.getOperator() );
+      }
+      bool childChanged = false;
+      for( unsigned i=0; i<n.getNumChildren(); i++ ){
+        Node nc = doNestedQERec( q, n[i], visited, inst_terms, doVts );
+        childChanged = childChanged || nc!=n[i];
+        children.push_back( nc );
+      }
+      if( childChanged ){
+        ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
+      }
+    }
+    visited[n] = ret;
+    return ret;
+  }else{
+    return n;
+  }  
+}
+
+Node InstStrategyCbqi::doNestedQE( Node q, std::vector< Node >& inst_terms, Node lem, bool doVts ) {
+  std::map< Node, Node > visited;
+  return doNestedQERec( q, lem, visited, inst_terms, doVts );
+}
+
+void InstStrategyCbqi::registerCounterexampleLemma( Node q, Node lem ){
+  Trace("cbqi-debug") << "Counterexample lemma  : " << lem << std::endl;
+  d_quantEngine->addLemma( lem, false );
+}
+
+bool InstStrategyCbqi::hasNonCbqiOperator( Node n, std::map< Node, bool >& visited ){
+  if( visited.find( n )==visited.end() ){
+    visited[n] = true;
+    if( n.getKind()!=BOUND_VARIABLE && TermUtil::hasBoundVarAttr( n ) ){
+      if( !inst::Trigger::isCbqiKind( n.getKind() ) ){
+        Trace("cbqi-debug2") << "Non-cbqi kind : " << n.getKind() << " in " << n  << std::endl;
+        return true;
+      }else if( n.getKind()==MULT && ( n.getNumChildren()!=2 || !n[0].isConst() ) ){
+        Trace("cbqi-debug2") << "Non-linear arithmetic : " << n << std::endl;
+        return true;
+      }else if( n.getKind()==FORALL ){
+        return hasNonCbqiOperator( n[1], visited );
+      }else{
+        for( unsigned i=0; i<n.getNumChildren(); i++ ){
+          if( hasNonCbqiOperator( n[i], visited ) ){
+            return true;
+          }
+        }
+      }
+    }
+  }
+  return false;
+}
+
+// -1 : not cbqi sort, 0 : cbqi sort, 1 : cbqi sort regardless of quantifier body
+int InstStrategyCbqi::isCbqiSort( TypeNode tn, std::map< TypeNode, int >& visited ) {
+  std::map< TypeNode, int >::iterator itv = visited.find( tn );
+  if( itv==visited.end() ){
+    visited[tn] = 0;
+    int ret = -1;
+    if( tn.isInteger() || tn.isReal() || tn.isBoolean() || tn.isBitVector() ){
+      ret = 0;
+    }else if( tn.isDatatype() ){
+      ret = 1;
+      const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
+      for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+        for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
+          TypeNode crange = TypeNode::fromType( ((SelectorType)dt[i][j].getType()).getRangeType() );
+          int cret = isCbqiSort( crange, visited );
+          if( cret==-1 ){
+            visited[tn] = -1;
+            return -1;
+          }else if( cret<ret ){
+            ret = cret;
+          }
+        }
+      }
+    }else if( tn.isSort() ){
+      QuantEPR * qepr = d_quantEngine->getQuantEPR();
+      if( qepr!=NULL ){
+        ret = qepr->isEPR( tn ) ? 1 : -1;
+      }
+    }
+    visited[tn] = ret;
+    return ret;
+  }else{
+    return itv->second;
+  }
+}
+
+int InstStrategyCbqi::hasNonCbqiVariable( Node q ){
+  int hmin = 1;
+  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+    TypeNode tn = q[0][i].getType();
+    std::map< TypeNode, int > visited;
+    int handled = isCbqiSort( tn, visited );
+    if( handled==-1 ){
+      return -1;
+    }else if( handled<hmin ){
+      hmin = handled;
+    }
+  }
+  return hmin;
+}
+
+bool InstStrategyCbqi::doCbqi( Node q ){
+  std::map< Node, int >::iterator it = d_do_cbqi.find( q );
+  if( it==d_do_cbqi.end() ){
+    int ret = 2;
+    if( !d_quantEngine->getQuantAttributes()->isQuantElim( q ) ){
+      Assert( !d_quantEngine->getQuantAttributes()->isQuantElimPartial( q ) );
+      //if has an instantiation pattern, don't do it
+      if( q.getNumChildren()==3 && options::eMatching() && options::userPatternsQuant()!=USER_PAT_MODE_IGNORE ){
+        for( unsigned i=0; i<q[2].getNumChildren(); i++ ){
+          if( q[2][i].getKind()==INST_PATTERN ){
+            ret = 0;
+          }
+        }
+      }
+      if( d_quantEngine->getQuantAttributes()->isSygus( q ) ){
+        ret = 0;
+      }
+      if( ret!=0 ){
+        //if quantifier has a non-handled variable, then do not use cbqi
+        //if quantifier has an APPLY_UF term, then do not use cbqi unless EPR
+        int ncbqiv = hasNonCbqiVariable( q );
+        if( ncbqiv==0 || ncbqiv==1 ){
+          std::map< Node, bool > visited;
+          if( hasNonCbqiOperator( q[1], visited ) ){
+            if( ncbqiv==1 ){
+              //all variables are fully handled, this implies this will be handlable regardless of body (e.g. for EPR)
+              //  so, try but not exclusively
+              ret = 1;
+            }else{
+              //cannot be handled
+              ret = 0;
+            }
+          }
+        }else{
+          // unhandled variable type
+          ret = 0;
+        }
+        if( ret==0 && options::cbqiAll() ){
+          //try but not exclusively
+          ret = 1;
+        }
+      }
+    }
+    Trace("cbqi-quant") << "doCbqi " << q << " returned " << ret << std::endl;
+    d_do_cbqi[q] = ret;
+    return ret!=0;
+  }else{
+    return it->second!=0;
+  }
+}
+
+Node InstStrategyCbqi::getNextDecisionRequestProc( Node q, std::map< Node, bool >& proc ) {
+  if( proc.find( q )==proc.end() ){
+    proc[q] = true;
+    //first check children
+    std::map< Node, std::vector< Node > >::iterator itc = d_children_quant.find( q );
+    if( itc!=d_children_quant.end() ){
+      for( unsigned j=0; j<itc->second.size(); j++ ){
+        Node d = getNextDecisionRequestProc( itc->second[j], proc );
+        if( !d.isNull() ){
+          return d;
+        }
+      }
+    }
+    //then check self
+    if( hasAddedCbqiLemma( q ) ){
+      Node cel = d_quantEngine->getTermUtil()->getCounterexampleLiteral( q );
+      bool value;
+      if( !d_quantEngine->getValuation().hasSatValue( cel, value ) ){
+        Trace("cbqi-dec") << "CBQI: get next decision " << cel << std::endl;
+        return cel;
+      }
+    }    
+  }
+  return Node::null(); 
+}
+
+Node InstStrategyCbqi::getNextDecisionRequest( unsigned& priority ){
+  std::map< Node, bool > proc;
+  //for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
+  //  Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
+  for( NodeSet::const_iterator it = d_added_cbqi_lemma.begin(); it != d_added_cbqi_lemma.end(); ++it ){
+    Node q = *it;
+    Node d = getNextDecisionRequestProc( q, proc );
+    if( !d.isNull() ){
+      priority = 0;
+      return d;
+    }
+  }
+  return Node::null();
+}
+
+
+
+//new implementation
+
+bool CegqiOutputInstStrategy::doAddInstantiation( std::vector< Node >& subs ) {
+  return d_out->doAddInstantiation( subs );
+}
+
+bool CegqiOutputInstStrategy::isEligibleForInstantiation( Node n ) {
+  return d_out->isEligibleForInstantiation( n );
+}
+
+bool CegqiOutputInstStrategy::addLemma( Node lem ) {
+  return d_out->addLemma( lem );
+}
+
+
+InstStrategyCegqi::InstStrategyCegqi( QuantifiersEngine * qe )
+  : InstStrategyCbqi( qe ) {
+  d_out = new CegqiOutputInstStrategy( this );
+  d_small_const = NodeManager::currentNM()->mkConst( Rational(1)/Rational(1000000) );
+  d_check_vts_lemma_lc = false;
+}
+
+InstStrategyCegqi::~InstStrategyCegqi()
+{
+  delete d_out;
+
+  for(std::map< Node, CegInstantiator * >::iterator i = d_cinst.begin(),
+          iend = d_cinst.end(); i != iend; ++i) {
+    CegInstantiator * instantiator = (*i).second;
+    delete instantiator;
+  }
+  d_cinst.clear();
+}
+
+void InstStrategyCegqi::processResetInstantiationRound( Theory::Effort effort ) {
+  d_check_vts_lemma_lc = false;
+}
+
+void InstStrategyCegqi::process( Node q, Theory::Effort effort, int e ) {
+  if( e==0 ){
+    CegInstantiator * cinst = getInstantiator( q );
+    Trace("inst-alg") << "-> Run cegqi for " << q << std::endl;
+    d_curr_quant = q;
+    if( !cinst->check() ){
+      d_incomplete_check = true;
+      d_check_vts_lemma_lc = true;
+    }
+    d_curr_quant = Node::null();
+  }else if( e==1 ){
+    //minimize the free delta heuristically on demand
+    if( d_check_vts_lemma_lc ){
+      Trace("inst-alg") << "-> Minimize delta heuristic, for " << q << std::endl;
+      d_check_vts_lemma_lc = false;
+      d_small_const = NodeManager::currentNM()->mkNode( MULT, d_small_const, d_small_const );
+      d_small_const = Rewriter::rewrite( d_small_const );
+      //heuristic for now, until we know how to do nested quantification
+      Node delta = d_quantEngine->getTermUtil()->getVtsDelta( true, false );
+      if( !delta.isNull() ){
+        Trace("quant-vts-debug") << "Delta lemma for " << d_small_const << std::endl;
+        Node delta_lem_ub = NodeManager::currentNM()->mkNode( LT, delta, d_small_const );
+        d_quantEngine->getOutputChannel().lemma( delta_lem_ub );
+      }
+      std::vector< Node > inf;
+      d_quantEngine->getTermUtil()->getVtsTerms( inf, true, false, false );
+      for( unsigned i=0; i<inf.size(); i++ ){
+        Trace("quant-vts-debug") << "Infinity lemma for " << inf[i] << " " << d_small_const << std::endl;
+        Node inf_lem_lb = NodeManager::currentNM()->mkNode( GT, inf[i], NodeManager::currentNM()->mkConst( Rational(1)/d_small_const.getConst<Rational>() ) );
+        d_quantEngine->getOutputChannel().lemma( inf_lem_lb );
+      }
+    }
+  }
+}
+
+bool InstStrategyCegqi::doAddInstantiation( std::vector< Node >& subs ) {
+  Assert( !d_curr_quant.isNull() );
+  //if doing partial quantifier elimination, record the instantiation and set the incomplete flag instead of sending instantiation lemma
+  if( d_quantEngine->getQuantAttributes()->isQuantElimPartial( d_curr_quant ) ){
+    d_cbqi_set_quant_inactive = true;
+    d_incomplete_check = true;
+    d_quantEngine->getInstantiate()->recordInstantiation(
+        d_curr_quant, subs, false, false);
+    return true;
+  }else{
+    //check if we need virtual term substitution (if used delta or infinity)
+    bool used_vts = d_quantEngine->getTermUtil()->containsVtsTerm( subs, false );
+    if (d_quantEngine->getInstantiate()->addInstantiation(
+            d_curr_quant, subs, false, false, used_vts))
+    {
+      ++(d_quantEngine->d_statistics.d_instantiations_cbqi);
+      //d_added_inst.insert( d_curr_quant );
+      return true;
+    }else{
+      //this should never happen for monotonic selection strategies
+      Trace("cbqi-warn") << "WARNING: Existing instantiation" << std::endl;
+      return false;
+    }
+  }
+}
+
+bool InstStrategyCegqi::addLemma( Node lem ) {
+  return d_quantEngine->addLemma( lem );
+}
+
+bool InstStrategyCegqi::isEligibleForInstantiation( Node n ) {
+  if( n.getKind()==INST_CONSTANT || n.getKind()==SKOLEM ){
+    if( n.getAttribute(VirtualTermSkolemAttribute()) ){
+      // virtual terms are allowed
+      return true;
+    }else{
+      TypeNode tn = n.getType();
+      if( tn.isSort() ){
+        QuantEPR * qepr = d_quantEngine->getQuantEPR();
+        if( qepr!=NULL ){
+          //legal if in the finite set of constants of type tn
+          if( qepr->isEPRConstant( tn, n ) ){
+            return true;
+          }
+        }
+      }
+      //only legal if current quantified formula contains n
+      return TermUtil::containsTerm( d_curr_quant, n );
+    }
+  }else{
+    return true;
+  }
+}
+
+CegInstantiator * InstStrategyCegqi::getInstantiator( Node q ) {
+  std::map< Node, CegInstantiator * >::iterator it = d_cinst.find( q );
+  if( it==d_cinst.end() ){
+    CegInstantiator * cinst = new CegInstantiator( d_quantEngine, d_out, true, true );
+    d_cinst[q] = cinst;
+    return cinst;
+  }else{
+   return it->second;
+  }
+}
+
+void InstStrategyCegqi::registerQuantifier( Node q ) {
+  if( doCbqi( q ) ){
+    // get the instantiator  
+    if( options::cbqiPreRegInst() ){
+      getInstantiator( q );
+    }
+    // register the cbqi lemma
+    if( registerCbqiLemma( q ) ){
+      Trace("cbqi") << "Registered cbqi lemma for quantifier : " << q << std::endl;
+    }
+  }
+}
+
+void InstStrategyCegqi::registerCounterexampleLemma( Node q, Node lem ) {
+  //must register with the instantiator
+  //must explicitly remove ITEs so that we record dependencies
+  std::vector< Node > ce_vars;
+  for( unsigned i=0; i<d_quantEngine->getTermUtil()->getNumInstantiationConstants( q ); i++ ){
+    ce_vars.push_back( d_quantEngine->getTermUtil()->getInstantiationConstant( q, i ) );
+  }
+  std::vector< Node > lems;
+  lems.push_back( lem );
+  CegInstantiator * cinst = getInstantiator( q );
+  cinst->registerCounterexampleLemma( lems, ce_vars );
+  for( unsigned i=0; i<lems.size(); i++ ){
+    Trace("cbqi-debug") << "Counterexample lemma " << i << " : " << lems[i] << std::endl;
+    d_quantEngine->addLemma( lems[i], false );
+  }
+}
+
+void InstStrategyCegqi::presolve() {
+  if( options::cbqiPreRegInst() ){
+    for( std::map< Node, CegInstantiator * >::iterator it = d_cinst.begin(); it != d_cinst.end(); ++it ){
+      Trace("cbqi-presolve") << "Presolve " << it->first << std::endl;
+      it->second->presolve( it->first );
+    }
+  }
+}
+
diff --git a/src/theory/quantifiers/cegqi/inst_strategy_cbqi.h b/src/theory/quantifiers/cegqi/inst_strategy_cbqi.h
new file mode 100644 (file)
index 0000000..3443d2c
--- /dev/null
@@ -0,0 +1,166 @@
+/*********************                                                        */
+/*! \file inst_strategy_cbqi.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Morgan Deters, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief counterexample-guided quantifier instantiation
+ **/
+
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__INST_STRATEGY_CBQI_H
+#define __CVC4__INST_STRATEGY_CBQI_H
+
+#include "theory/arith/arithvar.h"
+#include "theory/quantifiers/cegqi/ceg_instantiator.h"
+#include "theory/quantifiers/ematching/instantiation_engine.h"
+#include "util/statistics_registry.h"
+
+namespace CVC4 {
+namespace theory {
+
+namespace arith {
+  class TheoryArith;
+}
+
+namespace quantifiers {
+
+class InstStrategyCbqi : public QuantifiersModule {
+  typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
+  typedef context::CDHashMap< Node, int, NodeHashFunction> NodeIntMap;
+
+ protected:
+  bool d_cbqi_set_quant_inactive;
+  bool d_incomplete_check;
+  /** whether we have added cbqi lemma */
+  NodeSet d_added_cbqi_lemma;
+  /** whether we have added cbqi lemma */
+  NodeSet d_elim_quants;
+  /** parent guards */
+  std::map< Node, std::vector< Node > > d_parent_quant;
+  std::map< Node, std::vector< Node > > d_children_quant;
+  std::map< Node, bool > d_active_quant;
+  /** whether we have instantiated quantified formulas */
+  //NodeSet d_added_inst;
+  /** whether to do cbqi for this quantified formula 0 : no, 2 : yes, 1 : yes but not exclusively, -1 : heuristically */
+  std::map< Node, int > d_do_cbqi;
+  /** register ce lemma */
+  bool registerCbqiLemma( Node q );
+  virtual void registerCounterexampleLemma( Node q, Node lem );
+  /** has added cbqi lemma */
+  bool hasAddedCbqiLemma( Node q ) { return d_added_cbqi_lemma.find( q )!=d_added_cbqi_lemma.end(); }
+  /** helper functions */
+  int hasNonCbqiVariable( Node q );
+  bool hasNonCbqiOperator( Node n, std::map< Node, bool >& visited );
+  int isCbqiSort( TypeNode tn, std::map< TypeNode, int >& visited );
+  /** get next decision request with dependency checking */
+  Node getNextDecisionRequestProc( Node q, std::map< Node, bool >& proc );  
+  /** process functions */
+  virtual void processResetInstantiationRound( Theory::Effort effort ) = 0;
+  virtual void process( Node q, Theory::Effort effort, int e ) = 0;
+
+ protected:
+  //for identification
+  uint64_t d_qid_count;
+  //nested qe map
+  std::map< Node, Node > d_nested_qe;
+  //mark ids on quantifiers 
+  Node getIdMarkedQuantNode( Node n, std::map< Node, Node >& visited );
+  // id to ce quant
+  std::map< Node, Node > d_id_to_ce_quant;
+  std::map< Node, Node > d_ce_quant_to_id;
+  //do nested quantifier elimination recursive
+  Node doNestedQENode( Node q, Node ceq, Node n, std::vector< Node >& inst_terms, bool doVts );
+  Node doNestedQERec( Node q, Node n, std::map< Node, Node >& visited, std::vector< Node >& inst_terms, bool doVts );
+  //elimination information (for delayed elimination)
+  class NestedQEInfo {
+  public:
+    NestedQEInfo() : d_doVts(false){}
+    ~NestedQEInfo(){}
+    Node d_q;
+    std::vector< Node > d_inst_terms;
+    bool d_doVts;
+  };
+  std::map< Node, NestedQEInfo > d_nested_qe_info;
+  NodeIntMap d_nested_qe_waitlist_size;
+  NodeIntMap d_nested_qe_waitlist_proc;
+  std::map< Node, std::vector< Node > > d_nested_qe_waitlist;
+
+ public:
+  //do nested quantifier elimination
+  Node doNestedQE( Node q, std::vector< Node >& inst_terms, Node lem, bool doVts );
+
+ public:
+  InstStrategyCbqi( QuantifiersEngine * qe );
+
+  /** whether to do CBQI for quantifier q */
+  bool doCbqi( Node q );
+  /** process functions */
+  bool needsCheck( Theory::Effort e );
+  QEffort needsModel(Theory::Effort e);
+  void reset_round( Theory::Effort e );
+  void check(Theory::Effort e, QEffort quant_e);
+  bool checkComplete();
+  bool checkCompleteFor( Node q );
+  void preRegisterQuantifier( Node q );
+  void registerQuantifier( Node q );
+  /** get next decision request */
+  Node getNextDecisionRequest( unsigned& priority );
+};
+
+//generalized counterexample guided quantifier instantiation
+
+class InstStrategyCegqi;
+
+class CegqiOutputInstStrategy : public CegqiOutput {
+public:
+  CegqiOutputInstStrategy( InstStrategyCegqi * out ) : d_out( out ){}
+  InstStrategyCegqi * d_out;
+  bool doAddInstantiation( std::vector< Node >& subs );
+  bool isEligibleForInstantiation( Node n );
+  bool addLemma( Node lem );
+};
+
+class InstStrategyCegqi : public InstStrategyCbqi {
+ protected:
+  CegqiOutputInstStrategy * d_out;
+  std::map< Node, CegInstantiator * > d_cinst;
+  Node d_small_const;
+  Node d_curr_quant;
+  bool d_check_vts_lemma_lc;
+  /** process functions */
+  void processResetInstantiationRound(Theory::Effort effort) override;
+  void process(Node f, Theory::Effort effort, int e) override;
+  /** register ce lemma */
+  void registerCounterexampleLemma(Node q, Node lem) override;
+
+ public:
+  InstStrategyCegqi( QuantifiersEngine * qe );
+  ~InstStrategyCegqi() override;
+
+  bool doAddInstantiation( std::vector< Node >& subs );
+  bool isEligibleForInstantiation( Node n );
+  bool addLemma( Node lem );
+  /** identify */
+  std::string identify() const override { return std::string("Cegqi"); }
+
+  //get instantiator for quantifier
+  CegInstantiator * getInstantiator( Node q );
+  //register quantifier
+  void registerQuantifier(Node q) override;
+  //presolve
+  void presolve() override;
+};
+
+}
+}
+}
+
+#endif
index b7d1fe404dbad563a6bdc6dfe8a67fa4aa6d149f..142f9beaef3749e774e71547527a57038d1a6627 100644 (file)
@@ -20,7 +20,7 @@
 #include "theory/quantifiers/term_database.h"
 #include "theory/quantifiers/term_enumeration.h"
 #include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/ematching/trigger.h"
 #include "theory/theory_engine.h"
 
 using namespace CVC4;
diff --git a/src/theory/quantifiers/ematching/ho_trigger.cpp b/src/theory/quantifiers/ematching/ho_trigger.cpp
new file mode 100644 (file)
index 0000000..0e09551
--- /dev/null
@@ -0,0 +1,475 @@
+/*********************                                                        */
+/*! \file ho_trigger.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of higher-order trigger class
+ **/
+
+#include <stack>
+
+#include "theory/quantifiers/ematching/ho_trigger.h"
+#include "theory/quantifiers/instantiate.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/theory_engine.h"
+#include "theory/uf/equality_engine.h"
+#include "theory/uf/theory_uf_rewriter.h"
+#include "util/hash.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace inst {
+
+HigherOrderTrigger::HigherOrderTrigger(
+    QuantifiersEngine* qe,
+    Node q,
+    std::vector<Node>& nodes,
+    std::map<Node, std::vector<Node> >& ho_apps)
+    : Trigger(qe, q, nodes), d_ho_var_apps(ho_apps)
+{
+  NodeManager* nm = NodeManager::currentNM();
+  // process the higher-order variable applications
+  for (std::pair<const Node, std::vector<Node> >& as : d_ho_var_apps)
+  {
+    Node n = as.first;
+    d_ho_var_list.push_back(n);
+    TypeNode tn = n.getType();
+    Assert(tn.isFunction());
+    if (Trace.isOn("ho-quant-trigger"))
+    {
+      Trace("ho-quant-trigger") << "  have " << as.second.size();
+      Trace("ho-quant-trigger") << " patterns with variable operator " << n
+                                << ":" << std::endl;
+      for (unsigned j = 0; j < as.second.size(); j++)
+      {
+        Trace("ho-quant-trigger") << "  " << as.second[j] << std::endl;
+      }
+    }
+    if (d_ho_var_types.find(tn) == d_ho_var_types.end())
+    {
+      Trace("ho-quant-trigger") << "  type " << tn
+                                << " needs higher-order matching." << std::endl;
+      d_ho_var_types.insert(tn);
+    }
+    // make the bound variable lists
+    d_ho_var_bvl[n] = nm->getBoundVarListForFunctionType(tn);
+    for (const Node& nc : d_ho_var_bvl[n])
+    {
+      d_ho_var_bvs[n].push_back(nc);
+    }
+  }
+}
+
+HigherOrderTrigger::~HigherOrderTrigger() {}
+void HigherOrderTrigger::collectHoVarApplyTerms(
+    Node q, Node& n, std::map<Node, std::vector<Node> >& apps)
+{
+  std::vector<Node> ns;
+  ns.push_back(n);
+  collectHoVarApplyTerms(q, ns, apps);
+  Assert(ns.size() == 1);
+  n = ns[0];
+}
+
+void HigherOrderTrigger::collectHoVarApplyTerms(
+    Node q, std::vector<Node>& ns, std::map<Node, std::vector<Node> >& apps)
+{
+  std::unordered_map<TNode, Node, TNodeHashFunction> visited;
+  std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
+  // whether the visited node is a child of a HO_APPLY chain
+  std::unordered_map<TNode, bool, TNodeHashFunction> withinApply;
+  std::vector<TNode> visit;
+  TNode cur;
+  for (unsigned i = 0, size = ns.size(); i < size; i++)
+  {
+    visit.push_back(ns[i]);
+    withinApply[ns[i]] = false;
+    do
+    {
+      cur = visit.back();
+      visit.pop_back();
+
+      it = visited.find(cur);
+      if (it == visited.end())
+      {
+        // do not look in nested quantifiers
+        if (cur.getKind() == FORALL)
+        {
+          visited[cur] = cur;
+        }
+        else
+        {
+          bool curWithinApply = withinApply[cur];
+          visited[cur] = Node::null();
+          visit.push_back(cur);
+          for (unsigned j = 0, size = cur.getNumChildren(); j < size; j++)
+          {
+            withinApply[cur[j]] = curWithinApply && j == 0;
+            visit.push_back(cur[j]);
+          }
+        }
+      }
+      else if (it->second.isNull())
+      {
+        // carry the conversion
+        Node ret = cur;
+        bool childChanged = false;
+        std::vector<Node> children;
+        if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
+        {
+          children.push_back(cur.getOperator());
+        }
+        for (const Node& nc : cur)
+        {
+          it = visited.find(nc);
+          Assert(it != visited.end());
+          Assert(!it->second.isNull());
+          childChanged = childChanged || nc != it->second;
+          children.push_back(it->second);
+        }
+        if (childChanged)
+        {
+          ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
+        }
+        // now, convert and store the application
+        if (!withinApply[cur])
+        {
+          TNode op;
+          if (ret.getKind() == kind::APPLY_UF)
+          {
+            // could be a fully applied function variable
+            op = ret.getOperator();
+          }
+          else if (ret.getKind() == kind::HO_APPLY)
+          {
+            op = ret;
+            while (op.getKind() == kind::HO_APPLY)
+            {
+              op = op[0];
+            }
+          }
+          if (!op.isNull())
+          {
+            if (op.getKind() == kind::INST_CONSTANT)
+            {
+              Assert(quantifiers::TermUtil::getInstConstAttr(ret) == q);
+              Trace("ho-quant-trigger-debug")
+                  << "Ho variable apply term : " << ret << " with head " << op
+                  << std::endl;
+              if (ret.getKind() == kind::APPLY_UF)
+              {
+                Node prev = ret;
+                // for consistency, convert to HO_APPLY if fully applied
+                ret = uf::TheoryUfRewriter::getHoApplyForApplyUf(ret);
+              }
+              apps[op].push_back(ret);
+            }
+          }
+        }
+        visited[cur] = ret;
+      }
+    } while (!visit.empty());
+
+    // store the conversion
+    Assert(visited.find(ns[i]) != visited.end());
+    ns[i] = visited[ns[i]];
+  }
+}
+
+int HigherOrderTrigger::addInstantiations()
+{
+  // call the base class implementation
+  int addedFoLemmas = Trigger::addInstantiations();
+  // also adds predicate lemms to force app completion
+  int addedHoLemmas = addHoTypeMatchPredicateLemmas();
+  return addedHoLemmas + addedFoLemmas;
+}
+
+bool HigherOrderTrigger::sendInstantiation(InstMatch& m)
+{
+  if (options::hoMatching())
+  {
+    // get substitution corresponding to m
+    std::vector<TNode> vars;
+    std::vector<TNode> subs;
+    quantifiers::TermUtil* tutil = d_quantEngine->getTermUtil();
+    for (unsigned i = 0, size = d_quant[0].getNumChildren(); i < size; i++)
+    {
+      subs.push_back(m.d_vals[i]);
+      vars.push_back(tutil->getInstantiationConstant(d_quant, i));
+    }
+
+    Trace("ho-unif-debug") << "Run higher-order unification..." << std::endl;
+
+    // get the substituted form of all variable-operator ho application terms
+    std::map<TNode, std::vector<Node> > ho_var_apps_subs;
+    for (std::pair<const Node, std::vector<Node> >& ha : d_ho_var_apps)
+    {
+      TNode var = ha.first;
+      for (unsigned j = 0, size = ha.second.size(); j < size; j++)
+      {
+        TNode app = ha.second[j];
+        Node sapp =
+            app.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
+        ho_var_apps_subs[var].push_back(sapp);
+        Trace("ho-unif-debug") << "  app[" << var << "] : " << app << " -> "
+                               << sapp << std::endl;
+      }
+    }
+
+    // compute argument vectors for each variable
+    d_lchildren.clear();
+    d_arg_to_arg_rep.clear();
+    d_arg_vector.clear();
+    EqualityQuery* eq = d_quantEngine->getEqualityQuery();
+    for (std::pair<const TNode, std::vector<Node> >& ha : ho_var_apps_subs)
+    {
+      TNode var = ha.first;
+      unsigned vnum = var.getAttribute(InstVarNumAttribute());
+      Node value = m.d_vals[vnum];
+      Trace("ho-unif-debug") << "  val[" << var << "] = " << value << std::endl;
+
+      Trace("ho-unif-debug2") << "initialize lambda information..."
+                              << std::endl;
+      // initialize the lambda children
+      d_lchildren[vnum].push_back(value);
+      std::map<TNode, std::vector<Node> >::iterator ithb =
+          d_ho_var_bvs.find(var);
+      Assert(ithb != d_ho_var_bvs.end());
+      d_lchildren[vnum].insert(
+          d_lchildren[vnum].end(), ithb->second.begin(), ithb->second.end());
+
+      Trace("ho-unif-debug2") << "compute fixed arguments..." << std::endl;
+      // compute for each argument if it is only applied to a fixed value modulo
+      // equality
+      std::map<unsigned, Node> fixed_vals;
+      for (unsigned i = 0; i < ha.second.size(); i++)
+      {
+        std::vector<TNode> args;
+        Node f = uf::TheoryUfRewriter::decomposeHoApply(ha.second[i], args);
+        // Assert( f==value );
+        for (unsigned k = 0, size = args.size(); k < size; k++)
+        {
+          Node val = args[k];
+          std::map<unsigned, Node>::iterator itf = fixed_vals.find(k);
+          if (itf == fixed_vals.end())
+          {
+            fixed_vals[k] = val;
+          }
+          else if (!itf->second.isNull())
+          {
+            if (!eq->areEqual(itf->second, args[k]))
+            {
+              if (!d_quantEngine->getTermDatabase()->isEntailed(
+                      itf->second.eqNode(args[k]), true, eq))
+              {
+                fixed_vals[k] = Node::null();
+              }
+            }
+          }
+        }
+      }
+      if (Trace.isOn("ho-unif-debug"))
+      {
+        for (std::map<unsigned, Node>::iterator itf = fixed_vals.begin();
+             itf != fixed_vals.end();
+             ++itf)
+        {
+          Trace("ho-unif-debug") << "  arg[" << var << "][" << itf->first
+                                 << "] : " << itf->second << std::endl;
+        }
+      }
+
+      // now construct argument vectors
+      Trace("ho-unif-debug2") << "compute argument vectors..." << std::endl;
+      std::map<Node, unsigned> arg_to_rep;
+      for (unsigned index = 0, size = ithb->second.size(); index < size;
+           index++)
+      {
+        Node bv_at_index = ithb->second[index];
+        std::map<unsigned, Node>::iterator itf = fixed_vals.find(index);
+        Trace("ho-unif-debug") << "  * arg[" << var << "][" << index << "]";
+        if (itf != fixed_vals.end())
+        {
+          if (!itf->second.isNull())
+          {
+            Node r = eq->getRepresentative(itf->second);
+            std::map<Node, unsigned>::iterator itfr = arg_to_rep.find(r);
+            if (itfr != arg_to_rep.end())
+            {
+              d_arg_to_arg_rep[vnum][index] = itfr->second;
+              // function applied to equivalent values at multiple arguments,
+              // can permute variables
+              d_arg_vector[vnum][itfr->second].push_back(bv_at_index);
+              Trace("ho-unif-debug") << " = { self } ++ arg[" << var << "]["
+                                     << itfr->second << "]" << std::endl;
+            }
+            else
+            {
+              arg_to_rep[r] = index;
+              // function applied to single value, can either use variable or
+              // value at this argument position
+              d_arg_vector[vnum][index].push_back(bv_at_index);
+              d_arg_vector[vnum][index].push_back(itf->second);
+              if (!options::hoMatchingVarArgPriority())
+              {
+                std::reverse(d_arg_vector[vnum][index].begin(),
+                             d_arg_vector[vnum][index].end());
+              }
+              Trace("ho-unif-debug") << " = { self, " << itf->second << " } "
+                                     << std::endl;
+            }
+          }
+          else
+          {
+            // function is applied to disequal values, can only use variable at
+            // this argument position
+            d_arg_vector[vnum][index].push_back(bv_at_index);
+            Trace("ho-unif-debug") << " = { self } (disequal)" << std::endl;
+          }
+        }
+        else
+        {
+          // argument is irrelevant to matching, assume identity variable
+          d_arg_vector[vnum][index].push_back(bv_at_index);
+          Trace("ho-unif-debug") << " = { self } (irrelevant)" << std::endl;
+        }
+      }
+      Trace("ho-unif-debug2") << "finished." << std::endl;
+    }
+
+    return sendInstantiation(m, 0);
+  }
+  else
+  {
+    // do not run higher-order matching
+    return d_quantEngine->getInstantiate()->addInstantiation(d_quant, m);
+  }
+}
+
+// recursion depth limited by number of arguments of higher order variables
+// occurring as pattern operators (very small)
+bool HigherOrderTrigger::sendInstantiation(InstMatch& m, unsigned var_index)
+{
+  if (var_index == d_ho_var_list.size())
+  {
+    // we now have an instantiation to try
+    return d_quantEngine->getInstantiate()->addInstantiation(d_quant, m);
+  }
+  else
+  {
+    Node var = d_ho_var_list[var_index];
+    unsigned vnum = var.getAttribute(InstVarNumAttribute());
+    Assert(vnum < m.d_vals.size());
+    Node value = m.d_vals[vnum];
+    Assert(d_lchildren[vnum][0] == value);
+    Assert(d_ho_var_bvl.find(var) != d_ho_var_bvl.end());
+
+    // now, recurse on arguments to enumerate equivalent matching lambda
+    // expressions
+    bool ret =
+        sendInstantiationArg(m, var_index, vnum, 0, d_ho_var_bvl[var], false);
+
+    // reset the value
+    m.d_vals[vnum] = value;
+
+    return ret;
+  }
+}
+
+bool HigherOrderTrigger::sendInstantiationArg(InstMatch& m,
+                                              unsigned var_index,
+                                              unsigned vnum,
+                                              unsigned arg_index,
+                                              Node lbvl,
+                                              bool arg_changed)
+{
+  if (arg_index == lbvl.getNumChildren())
+  {
+    // construct the lambda
+    if (arg_changed)
+    {
+      Node body =
+          NodeManager::currentNM()->mkNode(kind::APPLY_UF, d_lchildren[vnum]);
+      Node lam = NodeManager::currentNM()->mkNode(kind::LAMBDA, lbvl, body);
+      m.d_vals[vnum] = lam;
+      Trace("ho-unif-debug2") << "  try " << vnum << " -> " << lam << std::endl;
+    }
+    return sendInstantiation(m, var_index + 1);
+  }
+  else
+  {
+    std::map<unsigned, unsigned>::iterator itr =
+        d_arg_to_arg_rep[vnum].find(arg_index);
+    unsigned rindex =
+        itr != d_arg_to_arg_rep[vnum].end() ? itr->second : arg_index;
+    std::map<unsigned, std::vector<Node> >::iterator itv =
+        d_arg_vector[vnum].find(rindex);
+    Assert(itv != d_arg_vector[vnum].end());
+    Node prev = lbvl[arg_index];
+    bool ret = false;
+    // try each argument in the vector
+    for (unsigned i = 0, size = itv->second.size(); i < size; i++)
+    {
+      bool new_arg_changed = arg_changed || prev != itv->second[i];
+      d_lchildren[vnum][arg_index + 1] = itv->second[i];
+      if (sendInstantiationArg(
+              m, var_index, vnum, arg_index + 1, lbvl, new_arg_changed))
+      {
+        ret = true;
+        break;
+      }
+    }
+    // clean up
+    d_lchildren[vnum][arg_index + 1] = prev;
+    return ret;
+  }
+}
+
+int HigherOrderTrigger::addHoTypeMatchPredicateLemmas()
+{
+  unsigned numLemmas = 0;
+  if (!d_ho_var_types.empty())
+  {
+    // this forces expansion of APPLY_UF terms to curried HO_APPLY chains
+    unsigned size = d_quantEngine->getTermDatabase()->getNumOperators();
+    for (unsigned j = 0; j < size; j++)
+    {
+      Node f = d_quantEngine->getTermDatabase()->getOperator(j);
+      if (f.isVar())
+      {
+        TypeNode tn = f.getType();
+        if (d_ho_var_types.find(tn) != d_ho_var_types.end())
+        {
+          Node u = d_quantEngine->getTermUtil()->getHoTypeMatchPredicate(tn);
+          Node au = NodeManager::currentNM()->mkNode(kind::APPLY_UF, u, f);
+          if (d_quantEngine->addLemma(au))
+          {
+            // this forces f to be a first-class member of the quantifier-free
+            // equality engine,
+            //  which in turn forces the quantifier-free theory solver to expand
+            //  it to HO_APPLY
+            Trace("ho-quant") << "Added ho match predicate lemma : " << au
+                              << std::endl;
+            numLemmas++;
+          }
+        }
+      }
+    }
+  }
+  return numLemmas;
+}
+
+} /* CVC4::theory::inst namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/ematching/ho_trigger.h b/src/theory/quantifiers/ematching/ho_trigger.h
new file mode 100644 (file)
index 0000000..41fec5e
--- /dev/null
@@ -0,0 +1,278 @@
+/*********************                                                        */
+/*! \file ho_trigger.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief higher-order trigger class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__HO_TRIGGER_H
+#define __CVC4__THEORY__QUANTIFIERS__HO_TRIGGER_H
+
+#include <map>
+#include <unordered_set>
+
+#include "expr/node.h"
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/inst_match.h"
+#include "theory/quantifiers/ematching/trigger.h"
+
+namespace CVC4 {
+namespace theory {
+namespace inst {
+
+class Trigger;
+
+/** HigherOrder trigger
+ *
+ * This extends the trigger class with techniques that post-process
+ * instantiations, specified by InstMatch objects, according to a variant of
+ * Huet's algorithm. For details, see Chapter 16 of the Handbook of Automated
+ * Reasoning (vol. 2), by Gilles Dowek.
+ *
+ * The main difference between HigherOrderTrigger and Trigger is the function
+ * sendInstantiation(...). Recall that this function is called when its
+ * underlying IMGenerator generates an InstMatch m using E-matching technique.
+ * We enumerate additional instantiations based on m, when the domain of m
+ * contains variables of function type.
+ *
+ * Examples below (f, x, y are universal variables):
+ *
+ * (EX1): (f x y) matches (k 0 1) in standard E-matching with:
+ *
+ * f -> k, x -> 0, y -> 1
+ *
+ * This match is extended to four possible solutions by this class:
+ *
+ * f -> \ xy. (k x y), x -> 0, y -> 1
+ * f -> \ xy. (k 0 y), x -> 0, y -> 1
+ * f -> \ xy. (k x 1), x -> 0, y -> 1
+ * f -> \ xy. (k 0 1), x -> 0, y -> 1
+ *
+ *
+ * (EX2): Similarly, (f x y) matches (k 0 0) with possible solutions:
+ *
+ * f -> \ xy. (k x x), x -> 0, y -> 0
+ * f -> \ xy. (k y x), x -> 0, y -> 0
+ * f -> \ xy. (k 0 x), x -> 0, y -> 0
+ * f -> \ xy. (k x y), x -> 0, y -> 0
+ * f -> \ xy. (k y y), x -> 0, y -> 0
+ * f -> \ xy. (k 0 y), x -> 0, y -> 0
+ * f -> \ xy. (k x 0), x -> 0, y -> 0
+ * f -> \ xy. (k y 0), x -> 0, y -> 0
+ * f -> \ xy. (k 0 0), x -> 0, y -> 0
+ *
+ *
+ * (EX3): (f x y), (f x z) simultaneously match (k 0 1), (k 0 2) with possible
+ * solutions:
+ *
+ * f -> \ xy. (k x y), x -> 0, y -> 1, z -> 2
+ * f -> \ xy. (k 0 y), x -> 0, y -> 1, z -> 2
+ *
+ *
+ * This class enumerates the lists above until one instantiation of that form is
+ * successfully added via a call to Instantiate::addInstantiation(...)
+ *
+ *
+ * It also implements a way of forcing APPLY_UF to expand to curried HO_APPLY to
+ * handle a corner case where there are no matchable ground terms
+ * (addHoTypeMatchPredicateLemmas).
+ *
+ */
+class HigherOrderTrigger : public Trigger
+{
+  friend class Trigger;
+
+ private:
+  HigherOrderTrigger(QuantifiersEngine* qe,
+                     Node q,
+                     std::vector<Node>& nodes,
+                     std::map<Node, std::vector<Node> >& ho_apps);
+  virtual ~HigherOrderTrigger();
+
+ public:
+  /** Collect higher order var apply terms
+   *
+   * Collect all top-level HO_APPLY terms in n whose head is a variable x in
+   * quantified formula q. Append all such terms in apps[x].
+   * This method may modify n so that it is in the expected form required for
+   * higher-order matching, in particular, APPLY_UF terms with variable
+   * operators are converted to curried applications of HO_APPLY.
+   */
+  static void collectHoVarApplyTerms(Node q,
+                                     Node& n,
+                                     std::map<Node, std::vector<Node> >& apps);
+  /** Collect higher order var apply terms
+   *
+   * Same as above, but with multiple terms ns.
+   */
+  static void collectHoVarApplyTerms(Node q,
+                                     std::vector<Node>& ns,
+                                     std::map<Node, std::vector<Node> >& apps);
+  /** add all available instantiations, based on the current context
+   *
+   * Extends Trigger::addInstantiations to also send
+   * lemmas based on addHoTypeMatchPredicateLemmas.
+   */
+  virtual int addInstantiations() override;
+
+ protected:
+  /**
+   * Map from function-typed variables to their applications in the quantified
+   * formula d_f (member of Trigger).
+   */
+  std::map<Node, std::vector<Node> > d_ho_var_apps;
+  /**
+   * List of all function-typed variables that occur as the head of function
+   * applications in d_f.
+   */
+  std::vector<Node> d_ho_var_list;
+  /**
+   * Cached bound variables and bound variable list for each variable of
+   * function type. These are used for constructing lambda terms in
+   * instantiations.
+   */
+  std::map<TNode, std::vector<Node> > d_ho_var_bvs;
+  std::map<TNode, Node> d_ho_var_bvl;
+  /** the set of types of ho variables */
+  std::unordered_set<TypeNode, TypeNodeHashFunction> d_ho_var_types;
+  /** add higher-order type predicate lemmas
+   *
+   * Adds lemmas of the form P( f ), where P is the predicate
+   * returned by TermUtil::getHoTypeMatchPredicate( f.getType() ).
+   * These lemmas force certain functions f of type tn to appear as
+   * first-class terms in the quantifier-free UF solver, where recall a
+   * first-class term is one that occurs as an (external) term in its equality
+   * engine. These functions f are all operators that have at least one
+   * term f(t1...tn) indexed by TermDabatase and are such that
+   * f's type is the same as a function-typed variable we
+   * are considering in this class (in d_ho_var_apps).
+   *
+   * TODO: we may eliminate this based on how github issue #1115 is resolved.
+   */
+  int addHoTypeMatchPredicateLemmas();
+  /** send instantiation
+   *
+  * Sends an instantiation that is equivalent to m via
+  * Instantiate::addInstantiation(...). This method may modify m based on
+  * imitations and projections (Huet's algorithm), if m was generated by
+  * matching ground terms to function applications with variable heads.
+  * See examples (EX1)-(EX3) above.
+  */
+  bool sendInstantiation(InstMatch& m) override;
+
+ private:
+  //-------------------- current information about the match
+  /**
+   * Map from variable position to the arguments of the lambda we generated
+   * for that variable.
+   *
+   * For example (EX4), take a quantified formula:
+   *   forall x f1 y f2. (...)
+   * Say we generated the match:
+   *   x -> 0
+   *   f1 -> k1
+   *   y -> 1
+   *   f2 -> k2
+   *   z -> 0
+   * where we matched
+   *   (f1 x y) with (k1 0 1) and
+   *   (f2 x z)  with (k2 0 0)
+   * Then the algorithm implemented by this class may modify the match to:
+   *   x -> 0
+   *   f1 -> (\ x1 x2. (k1 x1 1))
+   *   y -> 1
+   *   f2 -> (\ x1 x2. (k2 0 x1))
+   *   z -> 0
+   *
+   * In the above (modified) match, the contents of d_lchildren are:
+   *   1 -> { k1, x1, 1 }
+   *   3 -> { k2, 0, x1 }
+   */
+  std::map<unsigned, std::vector<Node> > d_lchildren;
+  /** map from variable position to the representative variable position.
+  * Used when two argument positions of a match are mapped to equal terms.
+  *
+  * In the above example (EX4), the first and second arguments of
+  * the match for f2 are equal.  Thus, in the above example,
+  * we have that d_arg_to_arg_rep is:
+  *   1 -> { 0 -> 0, 1 -> 1 }
+  *   3 -> { 0 -> 0, 1 -> 0 }
+  * In other words, the first argument
+  */
+  std::map<unsigned, std::map<unsigned, unsigned> > d_arg_to_arg_rep;
+  /** map from representative argument positions to the equivalence class
+   * of argument positions. In the above example (EX4), d_arg_vector is:
+   *   1 -> { 0 -> { 0 }, 1 -> { 1 } }
+   *   3 -> { 0 -> { 0, 1 } }
+   */
+  std::map<unsigned, std::map<unsigned, std::vector<Node> > > d_arg_vector;
+  //-------------------- end current information about the match
+
+  /** higher-order pattern unification algorithm
+   *
+  * Sends an instantiation that is equivalent to m via
+  * d_quantEngine->addInstantiation(...),
+  * based on Huet's algorithm.
+  *
+  * This is a helper function of sendInstantiation( m ) above.
+  *
+  * var_index is the index of the variable in m that we are currently processing
+  *   i.e. we are processing the var_index^{th} higher-order variable.
+  *
+  * For example, say we are processing the match from (EX4) above.
+  *   when var_index = 0,1, we are processing possibilities for
+  *    instantiation of f1,f2 respectively.
+  */
+  bool sendInstantiation(InstMatch& m, unsigned var_index);
+  /** higher-order pattern unification algorithm
+   * Sends an instantiation that is equivalent to m via
+   * d_quantEngine->addInstantiation(...).
+   * This is a helper function of sendInstantiation( m, var_index ) above.
+   *
+   * var_index is the index of the variable in m that we are currently
+   * processing
+   *   i.e. we are processing the var_index^{th} higher-order variable.
+   * vnum maps var_index to the actual variable number in m
+   * arg_index is the argument of the lambda term we are currently considering
+   * lbvl is the bound variable list associated with the term in m we are
+   * currently modifying
+   * arg_changed is whether we have modified m.
+   *
+   * For example, say we have modified our match from (EX4) to:
+   *   x -> 0
+   *   f1 -> (\ x1 x2. (k1 x1 1))
+   *   y -> 1
+   *   f2 -> (\ x1 x2. (k2 0 ?))
+   *   z -> 0
+   * That is, we are currently considering possibilities for the second
+   * argument of the body for f2.
+   * Then:
+   *   var_index = 1,
+   *   vnum = 3 (f2 is the 3^rd variable of our quantified formula)
+   *   arg_index = 1,
+   *   lbvl is d_ho_var_bvl[f2], and
+   *   arg_changed is true, since we modified at least one previous
+   *     argument of f1 or f2.
+   */
+  bool sendInstantiationArg(InstMatch& m,
+                            unsigned var_index,
+                            unsigned vnum,
+                            unsigned arg_index,
+                            Node lbvl,
+                            bool arg_changed);
+};
+
+} /* CVC4::theory::inst namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__HO_TRIGGER_H */
diff --git a/src/theory/quantifiers/ematching/inst_match_generator.cpp b/src/theory/quantifiers/ematching/inst_match_generator.cpp
new file mode 100644 (file)
index 0000000..c36597e
--- /dev/null
@@ -0,0 +1,1138 @@
+/*********************                                                        */
+/*! \file inst_match_generator.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Morgan Deters, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+#include "theory/quantifiers/ematching/inst_match_generator.h"
+
+#include "expr/datatype.h"
+#include "options/datatypes_options.h"
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/candidate_generator.h"
+#include "theory/quantifiers/instantiate.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers/ematching/trigger.h"
+#include "theory/quantifiers_engine.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+
+namespace CVC4 {
+namespace theory {
+namespace inst {
+
+bool IMGenerator::sendInstantiation(Trigger* tparent, InstMatch& m)
+{
+  return tparent->sendInstantiation(m);
+}
+
+InstMatchGenerator::InstMatchGenerator( Node pat ){
+  d_cg = NULL;
+  d_needsReset = true;
+  d_active_add = true;
+  Assert( quantifiers::TermUtil::hasInstConstAttr(pat) );
+  d_pattern = pat;
+  d_match_pattern = pat;
+  d_match_pattern_type = pat.getType();
+  d_next = NULL;
+  d_independent_gen = false;
+}
+
+InstMatchGenerator::InstMatchGenerator() {
+  d_cg = NULL;
+  d_needsReset = true;
+  d_active_add = true;
+  d_next = NULL;
+  d_independent_gen = false;
+}
+
+InstMatchGenerator::~InstMatchGenerator()
+{
+  for( unsigned i=0; i<d_children.size(); i++ ){
+    delete d_children[i];
+  }
+  delete d_cg;
+}
+
+void InstMatchGenerator::setActiveAdd(bool val){
+  d_active_add = val;
+  if( d_next!=NULL ){
+    d_next->setActiveAdd(val);
+  }
+}
+
+int InstMatchGenerator::getActiveScore( QuantifiersEngine * qe ) {
+  if( d_match_pattern.isNull() ){
+    return -1;
+  }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){
+    Node f = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
+    unsigned ngt = qe->getTermDatabase()->getNumGroundTerms( f );
+    Trace("trigger-active-sel-debug") << "Number of ground terms for " << f << " is " << ngt << std::endl;
+    return ngt;
+  }else if( d_match_pattern.getKind()==INST_CONSTANT ){
+    TypeNode tn = d_match_pattern.getType();
+    unsigned ngtt = qe->getTermDatabase()->getNumTypeGroundTerms( tn );
+    Trace("trigger-active-sel-debug") << "Number of ground terms for " << tn << " is " << ngtt << std::endl;
+    return ngtt;
+//  }else if( d_match_pattern_getKind()==EQUAL ){
+    
+  }else{
+    return -1;
+  }
+}
+
+void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector< InstMatchGenerator * > & gens ){
+  if( !d_pattern.isNull() ){
+    Trace("inst-match-gen") << "Initialize, pattern term is " << d_pattern << std::endl;
+    if( d_match_pattern.getKind()==NOT ){
+      //we want to add the children of the NOT
+      d_match_pattern = d_pattern[0];
+    }
+    if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==GEQ ){
+      //make sure the matching portion of the equality is on the LHS of d_pattern
+      //  and record what d_match_pattern is
+      for( unsigned i=0; i<2; i++ ){
+        if( !quantifiers::TermUtil::hasInstConstAttr(d_match_pattern[i]) || d_match_pattern[i].getKind()==INST_CONSTANT ){
+          Node mp = d_match_pattern[1-i];
+          Node mpo = d_match_pattern[i];
+          if( mp.getKind()!=INST_CONSTANT ){
+            if( i==0 ){
+              if( d_match_pattern.getKind()==GEQ ){
+                d_pattern = NodeManager::currentNM()->mkNode( kind::GT, mp, mpo );
+                d_pattern = d_pattern.negate();
+              }else{
+                d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), mp, mpo );
+              }
+            }
+            d_eq_class_rel = mpo;
+            d_match_pattern = mp;
+          }
+          break;
+        }
+      }
+    }else if( d_match_pattern.getKind()==APPLY_SELECTOR_TOTAL && d_match_pattern[0].getKind()==INST_CONSTANT && 
+              options::purifyDtTriggers() && !options::dtSharedSelectors() ){
+      d_match_pattern = d_match_pattern[0];
+    }
+    d_match_pattern_type = d_match_pattern.getType();
+    Trace("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl;
+    d_match_pattern_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
+
+    //now, collect children of d_match_pattern
+    if (d_match_pattern.getKind() == INST_CONSTANT)
+    {
+      d_children_types.push_back(
+          d_match_pattern.getAttribute(InstVarNumAttribute()));
+    }
+    else
+    {
+      for (unsigned i = 0, size = d_match_pattern.getNumChildren(); i < size;
+           i++)
+      {
+        Node qa = quantifiers::TermUtil::getInstConstAttr(d_match_pattern[i]);
+        if (!qa.isNull())
+        {
+          InstMatchGenerator* cimg =
+              getInstMatchGenerator(q, d_match_pattern[i]);
+          if (cimg)
+          {
+            d_children.push_back(cimg);
+            d_children_index.push_back(i);
+            d_children_types.push_back(-2);
+          }else{
+            if (d_match_pattern[i].getKind() == INST_CONSTANT && qa == q)
+            {
+              d_children_types.push_back(
+                  d_match_pattern[i].getAttribute(InstVarNumAttribute()));
+            }
+            else
+            {
+              d_children_types.push_back(-1);
+            }
+          }
+        }
+        else
+        {
+          d_children_types.push_back(-1);
+        }
+      }
+    }
+
+    //create candidate generator
+    if( Trigger::isAtomicTrigger( d_match_pattern ) ){
+      //we will be scanning lists trying to find d_match_pattern.getOperator()
+      d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern );
+      //if matching on disequality, inform the candidate generator not to match on eqc
+      if( d_pattern.getKind()==NOT && d_pattern[0].getKind()==EQUAL ){
+        ((inst::CandidateGeneratorQE*)d_cg)->excludeEqc( d_eq_class_rel );
+        d_eq_class_rel = Node::null();
+      }
+    }else if( d_match_pattern.getKind()==INST_CONSTANT ){
+      if( d_pattern.getKind()==APPLY_SELECTOR_TOTAL ){
+        Expr selectorExpr = qe->getTermDatabase()->getMatchOperator( d_pattern ).toExpr();
+        size_t selectorIndex = Datatype::cindexOf(selectorExpr);
+        const Datatype& dt = Datatype::datatypeOf(selectorExpr);
+        const DatatypeConstructor& c = dt[selectorIndex];
+        Node cOp = Node::fromExpr(c.getConstructor());
+        Trace("inst-match-gen") << "Purify dt trigger " << d_pattern << ", will match terms of op " << cOp << std::endl;
+        d_cg = new inst::CandidateGeneratorQE( qe, cOp );
+      }else{
+        d_cg = new CandidateGeneratorQEAll( qe, d_match_pattern );
+      }
+    }else if( d_match_pattern.getKind()==EQUAL &&
+              d_match_pattern[0].getKind()==INST_CONSTANT && d_match_pattern[1].getKind()==INST_CONSTANT ){
+      //we will be producing candidates via literal matching heuristics
+      if( d_pattern.getKind()!=NOT ){
+        //candidates will be all equalities
+        d_cg = new inst::CandidateGeneratorQELitEq( qe, d_match_pattern );
+      }else{
+        //candidates will be all disequalities
+        d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern );
+      }
+    }else{
+      Trace("inst-match-gen-warn") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
+    }
+  }
+  gens.insert( gens.end(), d_children.begin(), d_children.end() );
+}
+
+/** get match (not modulo equality) */
+int InstMatchGenerator::getMatch(
+    Node f, Node t, InstMatch& m, QuantifiersEngine* qe, Trigger* tparent)
+{
+  Trace("matching") << "Matching " << t << " against pattern " << d_match_pattern << " ("
+                    << m << ")" << ", " << d_children.size() << ", pattern is " << d_pattern << std::endl;
+  Assert( !d_match_pattern.isNull() );
+  if (d_cg == nullptr)
+  {
+    Trace("matching-fail") << "Internal error for match generator." << std::endl;
+    return -2;
+  }else{
+    EqualityQuery* q = qe->getEqualityQuery();
+    bool success = true;
+    //save previous match
+    //InstMatch prev( &m );
+    std::vector< int > prev;
+    //if t is null
+    Assert( !t.isNull() );
+    Assert( !quantifiers::TermUtil::hasInstConstAttr(t) );
+    Assert( d_match_pattern.getKind()==INST_CONSTANT || t.getKind()==d_match_pattern.getKind() );
+    Assert( !Trigger::isAtomicTrigger( d_match_pattern ) || t.getOperator()==d_match_pattern.getOperator() );
+    //first, check if ground arguments are not equal, or a match is in conflict
+    Trace("matching-debug2") << "Setting immediate matches..." << std::endl;
+    for (unsigned i = 0, size = d_match_pattern.getNumChildren(); i < size; i++)
+    {
+      int ct = d_children_types[i];
+      if (ct >= 0)
+      {
+        Trace("matching-debug2") << "Setting " << ct << " to " << t[i] << "..."
+                                 << std::endl;
+        bool addToPrev = m.get(ct).isNull();
+        if (!m.set(q, ct, t[i]))
+        {
+          //match is in conflict
+          Trace("matching-fail") << "Match fail: " << m.get(ct) << " and "
+                                 << t[i] << std::endl;
+          success = false;
+          break;
+        }else if( addToPrev ){
+          Trace("matching-debug2") << "Success." << std::endl;
+          prev.push_back(ct);
+        }
+      }
+      else if (ct == -1)
+      {
+        if( !q->areEqual( d_match_pattern[i], t[i] ) ){
+          Trace("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl;
+          //ground arguments are not equal
+          success = false;
+          break;
+        }
+      }
+    }
+    Trace("matching-debug2") << "Done setting immediate matches, success = " << success << "." << std::endl;
+    //for variable matching
+    if( d_match_pattern.getKind()==INST_CONSTANT ){
+      bool addToPrev = m.get(d_children_types[0]).isNull();
+      if (!m.set(q, d_children_types[0], t))
+      {
+        success = false;
+      }else{
+        if( addToPrev ){
+          prev.push_back(d_children_types[0]);
+        }
+      }
+    //for relational matching
+    }else if( !d_eq_class_rel.isNull() && d_eq_class_rel.getKind()==INST_CONSTANT ){
+      int v = d_eq_class_rel.getAttribute(InstVarNumAttribute());
+      //also must fit match to equivalence class
+      bool pol = d_pattern.getKind()!=NOT;
+      Node pat = d_pattern.getKind()==NOT ? d_pattern[0] : d_pattern;
+      Node t_match;
+      if( pol ){
+        if( pat.getKind()==GT ){
+          t_match = NodeManager::currentNM()->mkNode(MINUS, t, qe->getTermUtil()->d_one);
+        }else{
+          t_match = t;
+        }
+      }else{
+        if( pat.getKind()==EQUAL ){
+          if( t.getType().isBoolean() ){
+            t_match = NodeManager::currentNM()->mkConst( !q->areEqual( qe->getTermUtil()->d_true, t ) );
+          }else{
+            Assert( t.getType().isReal() );
+            t_match = NodeManager::currentNM()->mkNode(PLUS, t, qe->getTermUtil()->d_one);
+          }
+        }else if( pat.getKind()==GEQ ){
+          t_match = NodeManager::currentNM()->mkNode(PLUS, t, qe->getTermUtil()->d_one);
+        }else if( pat.getKind()==GT ){
+          t_match = t;
+        }
+      }
+      if( !t_match.isNull() ){
+        bool addToPrev = m.get( v ).isNull();
+        if (!m.set(q, v, t_match))
+        {
+          success = false;
+        }else if( addToPrev ){
+          prev.push_back( v );
+        }
+      }
+    }
+    int ret_val = -1;
+    if( success ){
+      Trace("matching-debug2") << "Reset children..." << std::endl;
+      //now, fit children into match
+      //we will be requesting candidates for matching terms for each child
+      for (unsigned i = 0, size = d_children.size(); i < size; i++)
+      {
+        if( !d_children[i]->reset( t[ d_children_index[i] ], qe ) ){
+          success = false;
+          break;
+        }
+      }
+      if( success ){
+        Trace("matching-debug2") << "Continue next " << d_next << std::endl;
+        ret_val = continueNextMatch(f, m, qe, tparent);
+      }
+    }
+    if( ret_val<0 ){
+      for (int& pv : prev)
+      {
+        m.d_vals[pv] = Node::null();
+      }
+    }
+    return ret_val;
+  }
+}
+
+int InstMatchGenerator::continueNextMatch(Node f,
+                                          InstMatch& m,
+                                          QuantifiersEngine* qe,
+                                          Trigger* tparent)
+{
+  if( d_next!=NULL ){
+    return d_next->getNextMatch(f, m, qe, tparent);
+  }else{
+    if( d_active_add ){
+      return sendInstantiation(tparent, m) ? 1 : -1;
+    }else{
+      return 1;
+    }
+  }
+}
+
+/** reset instantiation round */
+void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){
+  if( !d_match_pattern.isNull() ){
+    Trace("matching-debug2") << this << " reset instantiation round." << std::endl;
+    d_needsReset = true;
+    if( d_cg ){
+      d_cg->resetInstantiationRound();
+    }
+  }
+  if( d_next ){
+    d_next->resetInstantiationRound( qe );
+  }
+  d_curr_exclude_match.clear();
+}
+
+bool InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){
+  eqc = qe->getEqualityQuery()->getRepresentative( eqc );
+  Trace("matching-debug2") << this << " reset " << eqc << "." << std::endl;
+  if( !d_eq_class_rel.isNull() && d_eq_class_rel.getKind()!=INST_CONSTANT ){
+    d_eq_class = d_eq_class_rel;
+  }else if( !eqc.isNull() ){
+    d_eq_class = eqc;
+  }
+  //we have a specific equivalence class in mind
+  //we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term
+  //just look in equivalence class of the RHS
+  d_cg->reset( d_eq_class );
+  d_needsReset = false;
+  
+  //generate the first candidate preemptively
+  d_curr_first_candidate = Node::null();
+  Node t;
+  do {
+    t = d_cg->getNextCandidate();
+    if( d_curr_exclude_match.find( t )==d_curr_exclude_match.end() ){
+      d_curr_first_candidate = t;
+    }
+  }while( !t.isNull() && d_curr_first_candidate.isNull() );
+  Trace("matching-summary") << "Reset " << d_match_pattern << " in " << eqc << " returns " << !d_curr_first_candidate.isNull() << "." << std::endl;
+
+  return !d_curr_first_candidate.isNull();
+}
+
+int InstMatchGenerator::getNextMatch(Node f,
+                                     InstMatch& m,
+                                     QuantifiersEngine* qe,
+                                     Trigger* tparent)
+{
+  if( d_needsReset ){
+    Trace("matching") << "Reset not done yet, must do the reset..." << std::endl;
+    reset( d_eq_class, qe );
+  }
+  d_curr_matched = Node::null();
+  Trace("matching") << this << " " << d_match_pattern << " get next match " << m << " in eq class " << d_eq_class << std::endl;
+  int success = -1;
+  Node t = d_curr_first_candidate;
+  do{
+    Trace("matching-debug2") << "Matching candidate : " << t << std::endl;
+    //if t not null, try to fit it into match m
+    if( !t.isNull() ){
+      if( d_curr_exclude_match.find( t )==d_curr_exclude_match.end() ){
+        Assert( t.getType().isComparableTo( d_match_pattern_type ) );
+        Trace("matching-summary") << "Try " << d_match_pattern << " : " << t << std::endl;
+        success = getMatch(f, t, m, qe, tparent);
+        if( d_independent_gen && success<0 ){
+          Assert( d_eq_class.isNull() );
+          d_curr_exclude_match[t] = true;
+        }
+      }
+      //get the next candidate term t
+      if( success<0 ){
+        t = d_cg->getNextCandidate();
+      }else{
+        d_curr_first_candidate = d_cg->getNextCandidate();
+      }
+    }
+  }while( success<0 && !t.isNull() );
+  d_curr_matched = t;
+  if( success<0 ){
+    Trace("matching-summary") << "..." << d_match_pattern << " failed, reset." << std::endl;
+    Trace("matching") << this << " failed, reset " << d_eq_class << std::endl;
+    //we failed, must reset
+    reset( d_eq_class, qe );
+  }else{
+    Trace("matching-summary") << "..." << d_match_pattern << " success." << std::endl;
+  }
+  return success;
+}
+
+int InstMatchGenerator::addInstantiations(Node f,
+                                          QuantifiersEngine* qe,
+                                          Trigger* tparent)
+{
+  //try to add instantiation for each match produced
+  int addedLemmas = 0;
+  InstMatch m( f );
+  while (getNextMatch(f, m, qe, tparent) > 0)
+  {
+    if( !d_active_add ){
+      if (sendInstantiation(tparent, m))
+      {
+        addedLemmas++;
+        if( qe->inConflict() ){
+          break;
+        }
+      }
+    }else{
+      addedLemmas++;
+      if( qe->inConflict() ){
+        break;
+      }
+    }
+    m.clear();
+  }
+  //return number of lemmas added
+  return addedLemmas;
+}
+
+
+InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( Node q, Node pat, QuantifiersEngine* qe ) {
+  std::vector< Node > pats;
+  pats.push_back( pat );
+  std::map< Node, InstMatchGenerator * > pat_map_init;
+  return mkInstMatchGenerator( q, pats, qe, pat_map_init );
+}
+
+InstMatchGenerator* InstMatchGenerator::mkInstMatchGeneratorMulti( Node q, std::vector< Node >& pats, QuantifiersEngine* qe ) {
+  Assert( pats.size()>1 );
+  InstMatchGeneratorMultiLinear * imgm = new InstMatchGeneratorMultiLinear( q, pats, qe );
+  std::vector< InstMatchGenerator* > gens;
+  imgm->initialize(q, qe, gens);
+  Assert( gens.size()==pats.size() );
+  std::vector< Node > patsn;
+  std::map< Node, InstMatchGenerator * > pat_map_init;
+  for( unsigned i=0; i<gens.size(); i++ ){
+    Node pn = gens[i]->d_match_pattern;
+    patsn.push_back( pn );
+    pat_map_init[pn] = gens[i];
+  }
+  //return mkInstMatchGenerator( q, patsn, qe, pat_map_init );
+  imgm->d_next = mkInstMatchGenerator( q, patsn, qe, pat_map_init );
+  return imgm;
+}
+
+InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( Node q, std::vector< Node >& pats, QuantifiersEngine* qe, 
+                                                              std::map< Node, InstMatchGenerator * >& pat_map_init ) {
+  size_t pCounter = 0;
+  InstMatchGenerator* prev = NULL;
+  InstMatchGenerator* oinit = NULL;
+  while( pCounter<pats.size() ){
+    size_t counter = 0;
+    std::vector< InstMatchGenerator* > gens;
+    InstMatchGenerator* init;
+    std::map< Node, InstMatchGenerator * >::iterator iti = pat_map_init.find( pats[pCounter] );
+    if( iti==pat_map_init.end() ){
+      init = new InstMatchGenerator(pats[pCounter]);
+    }else{
+      init = iti->second;
+    }
+    if(pCounter==0){
+      oinit = init;
+    }
+    gens.push_back(init);
+    //chain the resulting match generators together
+    while (counter<gens.size()) {
+      InstMatchGenerator* curr = gens[counter];
+      if( prev ){
+        prev->d_next = curr;
+      }
+      curr->initialize(q, qe, gens);
+      prev = curr;
+      counter++;
+    }
+    pCounter++;
+  }
+  return oinit;
+}
+
+InstMatchGenerator* InstMatchGenerator::getInstMatchGenerator(Node q, Node n)
+{
+  if (n.getKind() == INST_CONSTANT)
+  {
+    return NULL;
+  }
+  Trace("var-trigger-debug") << "Is " << n << " a variable trigger?"
+                             << std::endl;
+  if (Trigger::isBooleanTermTrigger(n))
+  {
+    VarMatchGeneratorBooleanTerm* vmg =
+        new VarMatchGeneratorBooleanTerm(n[0], n[1]);
+    Trace("var-trigger") << "Boolean term trigger : " << n << ", var = " << n[0]
+                         << std::endl;
+    return vmg;
+  }
+  Node x;
+  if (options::purifyTriggers())
+  {
+    x = Trigger::getInversionVariable(n);
+  }
+  if (!x.isNull())
+  {
+    Node s = Trigger::getInversion(n, x);
+    VarMatchGeneratorTermSubs* vmg = new VarMatchGeneratorTermSubs(x, s);
+    Trace("var-trigger") << "Term substitution trigger : " << n
+                         << ", var = " << x << ", subs = " << s << std::endl;
+    return vmg;
+  }
+  return new InstMatchGenerator(n);
+}
+
+VarMatchGeneratorBooleanTerm::VarMatchGeneratorBooleanTerm( Node var, Node comp ) :
+  InstMatchGenerator(), d_comp( comp ), d_rm_prev( false ) {
+  d_children_types.push_back(var.getAttribute(InstVarNumAttribute()));
+}
+
+int VarMatchGeneratorBooleanTerm::getNextMatch(Node q,
+                                               InstMatch& m,
+                                               QuantifiersEngine* qe,
+                                               Trigger* tparent)
+{
+  int ret_val = -1;
+  if( !d_eq_class.isNull() ){
+    Node s = NodeManager::currentNM()->mkConst(qe->getEqualityQuery()->areEqual( d_eq_class, d_pattern ));
+    d_eq_class = Node::null();
+    d_rm_prev = m.get(d_children_types[0]).isNull();
+    if (!m.set(qe->getEqualityQuery(), d_children_types[0], s))
+    {
+      return -1;
+    }else{
+      ret_val = continueNextMatch(q, m, qe, tparent);
+      if( ret_val>0 ){
+        return ret_val;
+      }
+    }
+  }
+  if( d_rm_prev ){
+    m.d_vals[d_children_types[0]] = Node::null();
+    d_rm_prev = false;
+  }
+  return ret_val;
+}
+
+VarMatchGeneratorTermSubs::VarMatchGeneratorTermSubs( Node var, Node subs ) :
+  InstMatchGenerator(), d_var( var ), d_subs( subs ), d_rm_prev( false ){
+  d_children_types.push_back(d_var.getAttribute(InstVarNumAttribute()));
+  d_var_type = d_var.getType();
+}
+
+int VarMatchGeneratorTermSubs::getNextMatch(Node q,
+                                            InstMatch& m,
+                                            QuantifiersEngine* qe,
+                                            Trigger* tparent)
+{
+  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 );
+    s = Rewriter::rewrite( s );
+    Trace("var-trigger-matching") << "...got " << s << ", " << s.getKind() << std::endl;
+    d_eq_class = Node::null();
+    //if( s.getType().isSubtypeOf( d_var_type ) ){
+    d_rm_prev = m.get(d_children_types[0]).isNull();
+    if (!m.set(qe->getEqualityQuery(), d_children_types[0], s))
+    {
+      return -1;
+    }else{
+      ret_val = continueNextMatch(q, m, qe, tparent);
+      if( ret_val>0 ){
+        return ret_val;
+      }
+    }
+  }
+  if( d_rm_prev ){
+    m.d_vals[d_children_types[0]] = Node::null();
+    d_rm_prev = false;
+  }
+  return -1;
+}
+
+InstMatchGeneratorMultiLinear::InstMatchGeneratorMultiLinear( Node q, std::vector< Node >& pats, QuantifiersEngine* qe ) {
+  //order patterns to maximize eager matching failures
+  std::map< Node, std::vector< Node > > var_contains;
+  qe->getTermUtil()->getVarContains( q, pats, var_contains );
+  std::map< Node, std::vector< Node > > var_to_node;
+  for( std::map< Node, std::vector< Node > >::iterator it = var_contains.begin(); it != var_contains.end(); ++it ){
+    for( unsigned i=0; i<it->second.size(); i++ ){
+      var_to_node[ it->second[i] ].push_back( it->first );
+    }
+  }
+  std::vector< Node > pats_ordered;
+  std::vector< bool > pats_ordered_independent;
+  std::map< Node, bool > var_bound;
+  while( pats_ordered.size()<pats.size() ){
+    // score is lexographic ( bound vars, shared vars )
+    int score_max_1 = -1;
+    int score_max_2 = -1;
+    int score_index = -1;
+    for( unsigned i=0; i<pats.size(); i++ ){
+      Node p = pats[i];
+      if( std::find( pats_ordered.begin(), pats_ordered.end(), p )==pats_ordered.end() ){
+        int score_1 = 0;
+        int score_2 = 0;
+        for( unsigned j=0; j<var_contains[p].size(); j++ ){
+          Node v = var_contains[p][j];
+          if( var_bound.find( v )!=var_bound.end() ){
+            score_1++;
+          }else if( var_to_node[v].size()>1 ){
+            score_2++;
+          }
+        }
+        if( score_index==-1 || score_1>score_max_1 || ( score_1==score_max_1 && score_2>score_max_2 ) ){
+          score_index = i;
+          score_max_1 = score_1;
+          score_max_2 = score_2;
+        }
+      }
+    }
+    //update the variable bounds
+    Node mp = pats[score_index];
+    for( unsigned i=0; i<var_contains[mp].size(); i++ ){
+      var_bound[var_contains[mp][i]] = true;
+    }
+    pats_ordered.push_back( mp );
+    pats_ordered_independent.push_back( score_max_1==0 );
+  }
+  
+  Trace("multi-trigger-linear") << "Make children for linear multi trigger." << std::endl;
+  for( unsigned i=0; i<pats_ordered.size(); i++ ){
+    Trace("multi-trigger-linear") << "...make for " << pats_ordered[i] << std::endl;
+    InstMatchGenerator* cimg = getInstMatchGenerator(q, pats_ordered[i]);
+    Assert( cimg!=NULL );
+    d_children.push_back( cimg );
+    if( i==0 ){  //TODO : improve
+      cimg->setIndependent();
+    }
+  }
+}
+
+int InstMatchGeneratorMultiLinear::resetChildren( QuantifiersEngine* qe ){
+  for( unsigned i=0; i<d_children.size(); i++ ){
+    if( !d_children[i]->reset( Node::null(), qe ) ){
+      return -2;
+    }
+  }
+  return 1;
+}
+
+bool InstMatchGeneratorMultiLinear::reset( Node eqc, QuantifiersEngine* qe ) {
+  Assert( eqc.isNull() );
+  if( options::multiTriggerLinear() ){
+    return true;
+  }else{
+    return resetChildren( qe )>0;
+  }
+}
+
+int InstMatchGeneratorMultiLinear::getNextMatch(Node q,
+                                                InstMatch& m,
+                                                QuantifiersEngine* qe,
+                                                Trigger* tparent)
+{
+  Trace("multi-trigger-linear-debug") << "InstMatchGeneratorMultiLinear::getNextMatch : reset " << std::endl;
+  if( options::multiTriggerLinear() ){
+    //reset everyone
+    int rc_ret = resetChildren( qe );
+    if( rc_ret<0 ){
+      return rc_ret;
+    }
+  }
+  Trace("multi-trigger-linear-debug") << "InstMatchGeneratorMultiLinear::getNextMatch : continue match " << std::endl;
+  Assert( d_next!=NULL );
+  int ret_val = continueNextMatch(q, m, qe, tparent);
+  if( ret_val>0 ){
+    Trace("multi-trigger-linear") << "Successful multi-trigger instantiation." << std::endl;
+    if( options::multiTriggerLinear() ){
+      // now, restrict everyone
+      for( unsigned i=0; i<d_children.size(); i++ ){
+        Node mi = d_children[i]->getCurrentMatch();
+        Trace("multi-trigger-linear") << "   child " << i << " match : " << mi << std::endl;
+        d_children[i]->excludeMatch( mi );
+      }
+    }
+  }
+  return ret_val;
+}
+
+
+/** constructors */
+InstMatchGeneratorMulti::InstMatchGeneratorMulti(Node q,
+                                                 std::vector<Node>& pats,
+                                                 QuantifiersEngine* qe)
+    : d_quant(q)
+{
+  Trace("multi-trigger-cache") << "Making smart multi-trigger for " << q << std::endl;
+  std::map< Node, std::vector< Node > > var_contains;
+  qe->getTermUtil()->getVarContains( q, pats, var_contains );
+  //convert to indicies
+  for( std::map< Node, std::vector< Node > >::iterator it = var_contains.begin(); it != var_contains.end(); ++it ){
+    Trace("multi-trigger-cache") << "Pattern " << it->first << " contains: ";
+    for( int i=0; i<(int)it->second.size(); i++ ){
+      Trace("multi-trigger-cache") << it->second[i] << " ";
+      int index = it->second[i].getAttribute(InstVarNumAttribute());
+      d_var_contains[ it->first ].push_back( index );
+      d_var_to_node[ index ].push_back( it->first );
+    }
+    Trace("multi-trigger-cache") << std::endl;
+  }
+  for( unsigned i=0; i<pats.size(); i++ ){
+    Node n = pats[i];
+    //make the match generator
+    InstMatchGenerator* img =
+        InstMatchGenerator::mkInstMatchGenerator(q, n, qe);
+    img->setActiveAdd(false);
+    d_children.push_back(img);
+    //compute unique/shared variables
+    std::vector< int > unique_vars;
+    std::map< int, bool > shared_vars;
+    int numSharedVars = 0;
+    for( unsigned j=0; j<d_var_contains[n].size(); j++ ){
+      if( d_var_to_node[ d_var_contains[n][j] ].size()==1 ){
+        Trace("multi-trigger-cache") << "Var " << d_var_contains[n][j] << " is unique to " << pats[i] << std::endl;
+        unique_vars.push_back( d_var_contains[n][j] );
+      }else{
+        shared_vars[ d_var_contains[n][j] ] = true;
+        numSharedVars++;
+      }
+    }
+    //we use the latest shared variables, then unique variables
+    std::vector< int > vars;
+    unsigned index = i==0 ? pats.size()-1 : (i-1);
+    while( numSharedVars>0 && index!=i ){
+      for( std::map< int, bool >::iterator it = shared_vars.begin(); it != shared_vars.end(); ++it ){
+        if( it->second ){
+          if( std::find( d_var_contains[ pats[index] ].begin(), d_var_contains[ pats[index] ].end(), it->first )!=
+              d_var_contains[ pats[index] ].end() ){
+            vars.push_back( it->first );
+            shared_vars[ it->first ] = false;
+            numSharedVars--;
+          }
+        }
+      }
+      index = index==0 ? (int)(pats.size()-1) : (index-1);
+    }
+    vars.insert( vars.end(), unique_vars.begin(), unique_vars.end() );
+    Trace("multi-trigger-cache") << "   Index[" << i << "]: ";
+    for( unsigned j=0; j<vars.size(); j++ ){
+      Trace("multi-trigger-cache") << vars[j] << " ";
+    }
+    Trace("multi-trigger-cache") << std::endl;
+    //make ordered inst match trie
+    d_imtio[i] = new InstMatchTrie::ImtIndexOrder;
+    d_imtio[i]->d_order.insert( d_imtio[i]->d_order.begin(), vars.begin(), vars.end() );
+    d_children_trie.push_back( InstMatchTrieOrdered( d_imtio[i] ) );
+  }
+}
+
+InstMatchGeneratorMulti::~InstMatchGeneratorMulti()
+{
+  for( unsigned i=0; i<d_children.size(); i++ ){
+    delete d_children[i];
+  }
+  for( std::map< unsigned, InstMatchTrie::ImtIndexOrder* >::iterator it = d_imtio.begin(); it != d_imtio.end(); ++it ){
+    delete it->second;
+  }
+}
+
+/** reset instantiation round (call this whenever equivalence classes have changed) */
+void InstMatchGeneratorMulti::resetInstantiationRound( QuantifiersEngine* qe ){
+  for( unsigned i=0; i<d_children.size(); i++ ){
+    d_children[i]->resetInstantiationRound( qe );
+  }
+}
+
+/** reset, eqc is the equivalence class to search in (any if eqc=null) */
+bool InstMatchGeneratorMulti::reset( Node eqc, QuantifiersEngine* qe ){
+  for( unsigned i=0; i<d_children.size(); i++ ){
+    if( !d_children[i]->reset( eqc, qe ) ){
+      //return false;
+    }
+  }
+  return true;
+}
+
+int InstMatchGeneratorMulti::addInstantiations(Node q,
+                                               QuantifiersEngine* qe,
+                                               Trigger* tparent)
+{
+  int addedLemmas = 0;
+  Trace("multi-trigger-cache") << "Process smart multi trigger" << std::endl;
+  for( unsigned i=0; i<d_children.size(); i++ ){
+    Trace("multi-trigger-cache") << "Calculate matches " << i << std::endl;
+    std::vector< InstMatch > newMatches;
+    InstMatch m( q );
+    while (d_children[i]->getNextMatch(q, m, qe, tparent) > 0)
+    {
+      //m.makeRepresentative( qe );
+      newMatches.push_back( InstMatch( &m ) );
+      m.clear();
+    }
+    Trace("multi-trigger-cache") << "Made " << newMatches.size() << " new matches for index " << i << std::endl;
+    for( unsigned j=0; j<newMatches.size(); j++ ){
+      Trace("multi-trigger-cache2") << "...processing " << j << " / " << newMatches.size() << ", #lemmas = " << addedLemmas << std::endl;
+      processNewMatch(qe, tparent, newMatches[j], i, addedLemmas);
+      if( qe->inConflict() ){
+        return addedLemmas;
+      }
+    }
+  }
+  return addedLemmas;
+}
+
+void InstMatchGeneratorMulti::processNewMatch(QuantifiersEngine* qe,
+                                              Trigger* tparent,
+                                              InstMatch& m,
+                                              int fromChildIndex,
+                                              int& addedLemmas)
+{
+  //see if these produce new matches
+  d_children_trie[fromChildIndex].addInstMatch(qe, d_quant, m);
+  //possibly only do the following if we know that new matches will be produced?
+  //the issue is that instantiations are filtered in quantifiers engine, and so there is no guarentee that
+  // we can safely skip the following lines, even when we have already produced this match.
+  Trace("multi-trigger-cache-debug") << "Child " << fromChildIndex << " produced match " << m << std::endl;
+  //process new instantiations
+  int childIndex = (fromChildIndex+1)%(int)d_children.size();
+  processNewInstantiations(qe,
+                           tparent,
+                           m,
+                           addedLemmas,
+                           d_children_trie[childIndex].getTrie(),
+                           0,
+                           childIndex,
+                           fromChildIndex,
+                           true);
+}
+
+void InstMatchGeneratorMulti::processNewInstantiations(QuantifiersEngine* qe,
+                                                       Trigger* tparent,
+                                                       InstMatch& m,
+                                                       int& addedLemmas,
+                                                       InstMatchTrie* tr,
+                                                       int trieIndex,
+                                                       int childIndex,
+                                                       int endChildIndex,
+                                                       bool modEq)
+{
+  Assert( !qe->inConflict() );
+  if( childIndex==endChildIndex ){
+    // m is an instantiation
+    if (sendInstantiation(tparent, m))
+    {
+      addedLemmas++;
+      Trace("multi-trigger-cache-debug") << "-> Produced instantiation " << m
+                                         << std::endl;
+    }
+  }else if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){
+    int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex];
+    // Node curr_ic = qe->getTermUtil()->getInstantiationConstant( d_quant,
+    // curr_index );
+    Node n = m.get( curr_index );
+    if( n.isNull() ){
+      // add to InstMatch
+      for (std::pair<const Node, InstMatchTrie>& d : tr->d_data)
+      {
+        InstMatch mn(&m);
+        mn.setValue(curr_index, d.first);
+        processNewInstantiations(qe,
+                                 tparent,
+                                 mn,
+                                 addedLemmas,
+                                 &(d.second),
+                                 trieIndex + 1,
+                                 childIndex,
+                                 endChildIndex,
+                                 modEq);
+        if (qe->inConflict())
+        {
+          break;
+        }
+      }
+    }
+    // shared and set variable, try to merge
+    std::map<Node, InstMatchTrie>::iterator it = tr->d_data.find(n);
+    if (it != tr->d_data.end())
+    {
+      processNewInstantiations(qe,
+                               tparent,
+                               m,
+                               addedLemmas,
+                               &(it->second),
+                               trieIndex + 1,
+                               childIndex,
+                               endChildIndex,
+                               modEq);
+    }
+    if (modEq)
+    {
+      // check modulo equality for other possible instantiations
+      if (qe->getEqualityQuery()->getEngine()->hasTerm(n))
+      {
+        eq::EqClassIterator eqc(
+            qe->getEqualityQuery()->getEngine()->getRepresentative(n),
+            qe->getEqualityQuery()->getEngine());
+        while (!eqc.isFinished())
+        {
+          Node en = (*eqc);
+          if (en != n)
+          {
+            std::map<Node, InstMatchTrie>::iterator itc = tr->d_data.find(en);
+            if (itc != tr->d_data.end())
+            {
+              processNewInstantiations(qe,
+                                       tparent,
+                                       m,
+                                       addedLemmas,
+                                       &(itc->second),
+                                       trieIndex + 1,
+                                       childIndex,
+                                       endChildIndex,
+                                       modEq);
+              if (qe->inConflict())
+              {
+                break;
+              }
+            }
+          }
+          ++eqc;
+        }
+      }
+    }
+  }else{
+    int newChildIndex = (childIndex+1)%(int)d_children.size();
+    processNewInstantiations(qe,
+                             tparent,
+                             m,
+                             addedLemmas,
+                             d_children_trie[newChildIndex].getTrie(),
+                             0,
+                             newChildIndex,
+                             endChildIndex,
+                             modEq);
+  }
+}
+
+InstMatchGeneratorSimple::InstMatchGeneratorSimple(Node q,
+                                                   Node pat,
+                                                   QuantifiersEngine* qe)
+    : d_quant(q), d_match_pattern(pat)
+{
+  if( d_match_pattern.getKind()==NOT ){
+    d_match_pattern = d_match_pattern[0];
+    d_pol = false;
+  }else{
+    d_pol = true;
+  }
+  if( d_match_pattern.getKind()==EQUAL ){
+    d_eqc = d_match_pattern[1];
+    d_match_pattern = d_match_pattern[0];
+    Assert( !quantifiers::TermUtil::hasInstConstAttr( d_eqc ) );
+  }
+  Assert( Trigger::isSimpleTrigger( d_match_pattern ) );
+  for( unsigned i=0; i<d_match_pattern.getNumChildren(); i++ ){
+    if( d_match_pattern[i].getKind()==INST_CONSTANT ){
+      if( !options::cbqi() || quantifiers::TermUtil::getInstConstAttr(d_match_pattern[i])==q ){
+        d_var_num[i] = d_match_pattern[i].getAttribute(InstVarNumAttribute());
+      }else{
+        d_var_num[i] = -1;
+      }
+    }
+    d_match_pattern_arg_types.push_back( d_match_pattern[i].getType() );
+  }
+  d_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
+}
+
+void InstMatchGeneratorSimple::resetInstantiationRound( QuantifiersEngine* qe ) {
+  
+}
+int InstMatchGeneratorSimple::addInstantiations(Node q,
+                                                QuantifiersEngine* qe,
+                                                Trigger* tparent)
+{
+  int addedLemmas = 0;
+  quantifiers::TermArgTrie* tat;
+  if( d_eqc.isNull() ){
+    tat = qe->getTermDatabase()->getTermArgTrie( d_op );
+  }else{
+    if( d_pol ){
+      tat = qe->getTermDatabase()->getTermArgTrie( d_eqc, d_op );
+    }else{
+      Node r = qe->getEqualityQuery()->getRepresentative( d_eqc );
+      //iterate over all classes except r
+      tat = qe->getTermDatabase()->getTermArgTrie( Node::null(), d_op );
+      if( tat ){
+        for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){
+          if( it->first!=r ){
+            InstMatch m( q );
+            addInstantiations( m, qe, addedLemmas, 0, &(it->second) );
+            if( qe->inConflict() ){
+              break;
+            }
+          }
+        }
+        tat = NULL;
+      }
+    }
+  }
+  Debug("simple-trigger-debug") << "Adding instantiations based on " << tat << " from " << d_op << " " << d_eqc << std::endl;
+  if( tat ){
+    InstMatch m( q );
+    addInstantiations( m, qe, addedLemmas, 0, tat );
+  }
+  return addedLemmas;
+}
+
+void InstMatchGeneratorSimple::addInstantiations(InstMatch& m,
+                                                 QuantifiersEngine* qe,
+                                                 int& addedLemmas,
+                                                 unsigned argIndex,
+                                                 quantifiers::TermArgTrie* tat)
+{
+  Debug("simple-trigger-debug") << "Add inst " << argIndex << " " << d_match_pattern << std::endl;
+  if (argIndex == d_match_pattern.getNumChildren())
+  {
+    Assert( !tat->d_data.empty() );
+    TNode t = tat->getNodeData();
+    Debug("simple-trigger") << "Actual term is " << t << std::endl;
+    //convert to actual used terms
+    for( std::map< int, int >::iterator it = d_var_num.begin(); it != d_var_num.end(); ++it ){
+      if( it->second>=0 ){
+        Debug("simple-trigger") << "...set " << it->second << " " << t[it->first] << std::endl;
+        m.setValue( it->second, t[it->first] );
+      }
+    }
+    // we do not need the trigger parent for simple triggers (no post-processing
+    // required)
+    if (qe->getInstantiate()->addInstantiation(d_quant, m))
+    {
+      addedLemmas++;
+      Debug("simple-trigger") << "-> Produced instantiation " << m << std::endl;
+    }
+  }else{
+    if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){
+      int v = d_var_num[argIndex];
+      if( v!=-1 ){
+        for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){
+          Node t = it->first;
+          Node prev = m.get( v );
+          //using representatives, just check if equal
+          Assert( t.getType().isComparableTo( d_match_pattern_arg_types[argIndex] ) );
+          if( prev.isNull() || prev==t ){
+            m.setValue( v, t);
+            addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) );
+            m.setValue( v, prev);
+            if( qe->inConflict() ){
+              break;
+            }
+          }
+        }
+        return;
+      }
+      //inst constant from another quantified formula, treat as ground term  TODO: remove this?
+    }
+    Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] );
+    std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r );
+    if( it!=tat->d_data.end() ){
+      addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) );
+    }
+  }
+}
+
+int InstMatchGeneratorSimple::getActiveScore( QuantifiersEngine * qe ) {
+  Node f = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
+  unsigned ngt = qe->getTermDatabase()->getNumGroundTerms( f );
+  Trace("trigger-active-sel-debug") << "Number of ground terms for (simple) " << f << " is " << ngt << std::endl;
+  return ngt;   
+}
+
+
+}/* CVC4::theory::inst namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/ematching/inst_match_generator.h b/src/theory/quantifiers/ematching/inst_match_generator.h
new file mode 100644 (file)
index 0000000..6c38db1
--- /dev/null
@@ -0,0 +1,694 @@
+/*********************                                                        */
+/*! \file inst_match_generator.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Morgan Deters, Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief inst match generator class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H
+#define __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H
+
+#include <map>
+#include "theory/quantifiers/inst_match_trie.h"
+
+namespace CVC4 {
+namespace theory {
+
+class QuantifiersEngine;
+namespace quantifiers{
+  class TermArgTrie;
+}
+
+namespace inst {
+
+class Trigger;
+
+/** IMGenerator class
+*
+* Virtual base class for generating InstMatch objects, which correspond to
+* quantifier instantiations. The main use of this class is as a backend utility
+* to Trigger (see theory/quantifiers/ematching/trigger.h).
+*
+* Some functions below take as argument a pointer to the current quantifiers
+* engine, which is used for making various queries about what terms and
+* equalities exist in the current context.
+*
+* Some functions below take a pointer to a parent Trigger object, which is used
+* to post-process and finalize the instantiations through
+* sendInstantiation(...), where the parent trigger will make calls to
+* qe->getInstantiate()->addInstantiation(...). The latter function is the entry
+* point in which instantiate lemmas are enqueued to be sent on the output
+* channel.
+*/
+class IMGenerator {
+public:
+  virtual ~IMGenerator() {}
+  /** Reset instantiation round.
+  *
+  * Called once at beginning of an instantiation round.
+  */
+  virtual void resetInstantiationRound(QuantifiersEngine* qe) {}
+  /** Reset.
+  *
+  * eqc is the equivalence class to search in (any if eqc=null).
+  * Returns true if this generator can produce instantiations, and false
+  * otherwise. An example of when it returns false is if it can be determined
+  * that no appropriate matchable terms occur based on eqc.
+  */
+  virtual bool reset(Node eqc, QuantifiersEngine* qe) { return true; }
+  /** Get the next match.
+  *
+  * Must call reset( eqc ) before this function. This constructs an
+  * instantiation, which it populates in data structure m,
+  * based on the current context using the implemented matching algorithm.
+  *
+  * q is the quantified formula we are adding instantiations for
+  * m is the InstMatch object we are generating
+  *
+  * Returns a value >0 if an instantiation was successfully generated
+  */
+  virtual int getNextMatch(Node q,
+                           InstMatch& m,
+                           QuantifiersEngine* qe,
+                           Trigger* tparent)
+  {
+    return 0;
+  }
+  /** add instantiations
+  *
+  * This add all available instantiations for q based on the current context
+  * using the implemented matching algorithm. It typically is implemented as a
+  * fixed point of getNextMatch above.
+  *
+  * It returns the number of instantiations added using calls to calls to
+  * Instantiate::addInstantiation(...).
+  */
+  virtual int addInstantiations(Node q,
+                                QuantifiersEngine* qe,
+                                Trigger* tparent)
+  {
+    return 0;
+  }
+  /** get active score
+  *
+  * A heuristic value indicating how active this generator is.
+  */
+  virtual int getActiveScore( QuantifiersEngine * qe ) { return 0; }
+ protected:
+  /** send instantiation
+   *
+   * This method sends instantiation, specified by m, to the parent trigger
+   * object, which will in turn make a call to
+   * Instantiate::addInstantiation(...). This method returns true if a
+   * call to Instantiate::addInstantiation(...) was successfully made,
+   * indicating that an instantiation was enqueued in the quantifier engine's
+   * lemma cache.
+   */
+  bool sendInstantiation(Trigger* tparent, InstMatch& m);
+};/* class IMGenerator */
+
+class CandidateGenerator;
+
+/** InstMatchGenerator class
+*
+* This is the default generator class for non-simple single triggers, that is,
+* triggers composed of a single term with nested term applications.
+* For example, { f( y, f( x, a ) ) } and { f( g( x ), a ) } are non-simple
+* triggers.
+*
+* Handling non-simple triggers is done by constructing a linked list of
+* InstMatchGenerator classes (see mkInstMatchGenerator), where each
+* InstMatchGenerator has a "d_next" pointer.  If d_next is NULL,
+* then this is the end of the InstMatchGenerator and the last
+* InstMatchGenerator is responsible for finalizing the instantiation.
+*
+* For (EX1), for the trigger f( y, f( x, a ) ), we construct the linked list:
+*
+* [ f( y, f( x, a ) ) ] -> [ f( x, a ) ] -> NULL
+*
+* In a call to getNextMatch,
+* if we match against a ground term f( b, c ), then the first InstMatchGenerator
+* in this list binds y to b, and tells the InstMatchGenerator [ f( x, a ) ] to
+* match f-applications in the equivalence class of c.
+*
+* CVC4 employs techniques that ensure that the number of instantiations
+* is worst-case polynomial wrt the number of ground terms.
+* Consider the axiom/pattern/context (EX2) :
+*
+*          axiom : forall x1 x2 x3 x4. F[ x1...x4 ]
+*
+*        trigger : P( f( x1 ), f( x2 ), f( x3 ), f( x4 ) )
+*
+* ground context : ~P( a, a, a, a ), a = f( c_1 ) = ... = f( c_100 )
+*
+* If E-matching were applied exhaustively, then x1, x2, x3, x4 would be
+* instantiated with all combinations of c_1, ... c_100, giving 100^4
+* instantiations.
+*
+* Instead, we enforce that at most 1 instantiation is produced for a
+* ( pattern, ground term ) pair per round. Meaning, only one instantiation is
+* generated when matching P( a, a, a, a ) against the generator
+* [P( f( x1 ), f( x2 ), f( x3 ), f( x4 ) )]. For details, see Section 3 of
+* Reynolds, Vampire 2016.
+*
+* To enforce these policies, we use a flag "d_active_add" which dictates the
+* behavior of the last element in the linked list. If d_active_add is
+*   true -> a call to getNextMatch(...) returns 1 only if adding the
+*           instantiation via a call to IMGenerator::sendInstantiation(...)
+*           successfully enqueues a lemma via a call to
+*           Instantiate::addInstantiation(...). This call may fail e.g. if we
+*           have already added the instantiation, or the instantiation is
+*           entailed.
+*   false -> a call to getNextMatch(...) returns 1 whenever an m is
+*            constructed, where typically the caller would use m.
+* This is important since a return value >0 signals that the current matched
+* terms should be flushed. Consider the above example (EX1), where
+* [ f(y,f(x,a)) ] is being matched against f(b,c),
+* [ f(x,a) ] is being matched against f(d,a) where c=f(d,a)
+* A successfully added instantiation { x->d, y->b } here signals we should
+* not produce further instantiations that match f(y,f(x,a)) with f(b,c).
+*
+* A number of special cases of triggers are covered by this generator (see
+* implementation of initialize), including :
+*   Literal triggers, e.g. x >= a, ~x = y
+*   Selector triggers, e.g. head( x )
+*   Triggers with invertible subterms, e.g. f( x+1 )
+*   Variable triggers, e.g. x
+*
+* All triggers above can be in the context of an equality, e.g.
+* { f( y, f( x, a ) ) = b } is a trigger that matches f( y, f( x, a ) ) to
+* ground terms in the equivalence class of b.
+* { ~f( y, f( x, a ) ) = b } is a trigger that matches f( y, f( x, a ) ) to any
+* ground terms not in the equivalence class of b.
+*/
+class InstMatchGenerator : public IMGenerator {
+ public:
+  /** destructor */
+  ~InstMatchGenerator() override;
+
+  /** Reset instantiation round. */
+  void resetInstantiationRound(QuantifiersEngine* qe) override;
+  /** Reset. */
+  bool reset(Node eqc, QuantifiersEngine* qe) override;
+  /** Get the next match. */
+  int getNextMatch(Node q,
+                   InstMatch& m,
+                   QuantifiersEngine* qe,
+                   Trigger* tparent) override;
+  /** Add instantiations. */
+  int addInstantiations(Node q,
+                        QuantifiersEngine* qe,
+                        Trigger* tparent) override;
+
+  /** set active add flag (true by default)
+   *
+  * If active add is true, we call sendInstantiation in calls to getNextMatch,
+  * instead of returning the match. This is necessary so that we can ensure
+  * policies that are dependent upon knowing when instantiations are
+  * successfully added to the output channel through
+  * Instantiate::addInstantiation(...).
+  */
+  void setActiveAdd(bool val);
+  /** Get active score for this inst match generator
+   *
+   * See Trigger::getActiveScore for details.
+   */
+  int getActiveScore(QuantifiersEngine* qe) override;
+  /** exclude match
+   *
+   * Exclude matching d_match_pattern with Node n on subsequent calls to
+   * getNextMatch.
+   */
+  void excludeMatch(Node n) { d_curr_exclude_match[n] = true; }
+  /** Get current match.
+   * Returns the term we are currently matching.
+   */
+  Node getCurrentMatch() { return d_curr_matched; }
+  /** set that this match generator is independent
+   *
+  * A match generator is indepndent when this generator fails to produce a
+  * match in a call to getNextMatch, the overall matching fails.
+  */
+  void setIndependent() { d_independent_gen = true; }
+  //-------------------------------construction of inst match generators
+  /** mkInstMatchGenerator for single triggers, calls the method below */
+  static InstMatchGenerator* mkInstMatchGenerator(Node q,
+                                                  Node pat,
+                                                  QuantifiersEngine* qe);
+  /** mkInstMatchGenerator for the multi trigger case
+  *
+  * This linked list of InstMatchGenerator classes with one
+  * InstMatchGeneratorMultiLinear at the head and a list of trailing
+  * InstMatchGenerators corresponding to each unique subterm of pats with
+  * free variables.
+  */
+  static InstMatchGenerator* mkInstMatchGeneratorMulti(Node q,
+                                                       std::vector<Node>& pats,
+                                                       QuantifiersEngine* qe);
+  /** mkInstMatchGenerator
+  *
+  * This generates a linked list of InstMatchGenerators for each unique
+  * subterm of pats with free variables.
+  *
+  * q is the quantified formula associated with the generator we are making
+  * pats is a set of terms we are making InstMatchGenerator nodes for
+  * qe is a pointer to the quantifiers engine (used for querying necessary
+  * information during initialization) pat_map_init maps from terms to
+  * generators we have already made for them.
+  *
+  * It calls initialize(...) for all InstMatchGenerators generated by this call.
+  */
+  static InstMatchGenerator* mkInstMatchGenerator(
+      Node q,
+      std::vector<Node>& pats,
+      QuantifiersEngine* qe,
+      std::map<Node, InstMatchGenerator*>& pat_map_init);
+  //-------------------------------end construction of inst match generators
+
+ protected:
+  /** constructors
+   *
+  * These are intentionally private, and are called during linked list
+  * construction in mkInstMatchGenerator.
+  */
+  InstMatchGenerator(Node pat);
+  InstMatchGenerator();
+  /** The pattern we are producing matches for.
+   *
+  * This term and d_match_pattern can be different since this
+  * term may involve  information regarding phase and (dis)equality entailment,
+  * or other special cases of Triggers.
+  *
+  * For example, for the trigger for P( x ) = false, which matches P( x ) with
+  * P( t ) in the equivalence class of false,
+  *   P( x ) = false is d_pattern
+  *   P( x ) is d_match_pattern
+  * Another example, for pure theory triggers like head( x ), we have
+  *   head( x ) is d_pattern
+  *   x is d_match_pattern
+  * since head( x ) can match any (List) datatype term x.
+  *
+  * If null, this is a multi trigger that is merging matches from d_children,
+  * which is used in InstMatchGeneratorMulti.
+  */
+  Node d_pattern;
+  /** The match pattern
+   * This is the term that is matched against ground terms,
+   * see examples above.
+   */
+  Node d_match_pattern;
+  /** The current term we are matching. */
+  Node d_curr_matched;
+  /** do we need to call reset on this generator? */
+  bool d_needsReset;
+  /** candidate generator
+   * This is the back-end utility for InstMatchGenerator.
+   * It generates a stream of candidate terms to match against d_match_pattern
+   * below, dependending upon what kind of term we are matching
+   * (e.g. a matchable term, a variable, a relation, etc.).
+   */
+  CandidateGenerator* d_cg;
+  /** children generators
+   * These match generators correspond to the children of the term
+   * we are matching with this generator.
+   * For example [ f( x, a ) ] is a child of [ f( y, f( x, a ) ) ]
+   * in the example (EX1) above.
+   */
+  std::vector<InstMatchGenerator*> d_children;
+  /** for each child, the index in the term
+   * For example [ f( x, a ) ] has index 1 in [ f( y, f( x, a ) ) ]
+   * in the example (EX1) above, indicating it is the 2nd child
+   * of the term.
+   */
+  std::vector<int> d_children_index;
+  /** children types
+   *
+   * If d_match_pattern is an instantiation constant, then this is a singleton
+   * vector containing the variable number of the d_match_pattern itself.
+   * If d_match_patterm is a term of the form f( t1, ..., tn ), then for each
+   * index i, d_children[i] stores the type of node ti is, where:
+   *   >= 0 : variable (indicates its number),
+   *   -1 : ground term,
+   *   -2 : child term.
+   */
+  std::vector<int> d_children_types;
+  /** The next generator in the linked list
+   * that this generator is a part of.
+   */
+  InstMatchGenerator* d_next;
+  /** The equivalence class we are currently matching in. */
+  Node d_eq_class;
+  /** If non-null, then this is a relational trigger of the form x ~
+   * d_eq_class_rel. */
+  Node d_eq_class_rel;
+  /** Excluded matches
+  * Stores the terms we are not allowed to match.
+  * These can for instance be specified by the smt2
+  * extended syntax (! ... :no-pattern).
+  */
+  std::map<Node, bool> d_curr_exclude_match;
+  /** Current first candidate
+  * Used in a key fail-quickly optimization which generates
+  * the first candidate term to match during reset().
+  */
+  Node d_curr_first_candidate;
+  /** Indepdendent generate
+  * If this flag is true, failures to match should be cached.
+  */
+  bool d_independent_gen;
+  /** active add flag, described above. */
+  bool d_active_add;
+  /** cached value of d_match_pattern.getType() */
+  TypeNode d_match_pattern_type;
+  /** the match operator for d_match_pattern
+   *
+   * See TermDatabase::getMatchOperator for details on match operators.
+   */
+  Node d_match_pattern_op;
+  /** get the match against ground term or formula t.
+   *
+   * d_match_pattern and t should have the same shape, that is,
+   * their match operator (see TermDatabase::getMatchOperator) is the same.
+   * only valid for use where !d_match_pattern.isNull().
+   */
+  int getMatch(
+      Node q, Node t, InstMatch& m, QuantifiersEngine* qe, Trigger* tparent);
+  /** Initialize this generator.
+   *
+   * q is the quantified formula associated with this generator.
+   *
+   * This constructs the appropriate information about what
+   * patterns we are matching and children generators.
+   *
+   * It may construct new (child) generators needed to implement
+   * the matching algorithm for this term. For each new generator
+   * constructed in this way, it adds them to gens.
+   */
+  void initialize(Node q,
+                  QuantifiersEngine* qe,
+                  std::vector<InstMatchGenerator*>& gens);
+  /** Continue next match
+   *
+  * This is called during getNextMatch when the current generator in the linked
+  * list succesfully satisfies its matching constraint. This function either
+  * calls getNextMatch of the next element in the linked list, or finalizes the
+  * match (calling sendInstantiation(...) if active add is true, or returning a
+  * value >0 if active add is false).  Its return value has the same semantics
+  * as getNextMatch.
+  */
+  int continueNextMatch(Node q,
+                        InstMatch& m,
+                        QuantifiersEngine* qe,
+                        Trigger* tparent);
+  /** Get inst match generator
+   *
+   * Gets the InstMatchGenerator that implements the
+   * appropriate matching algorithm for n within q
+   * within a linked list of InstMatchGenerators.
+   */
+  static InstMatchGenerator* getInstMatchGenerator(Node q, Node n);
+};/* class InstMatchGenerator */
+
+/** match generator for Boolean term ITEs
+* This handles the special case of triggers that look like ite( x, BV1, BV0 ).
+*/
+class VarMatchGeneratorBooleanTerm : public InstMatchGenerator {
+public:
+  VarMatchGeneratorBooleanTerm( Node var, Node comp );
+
+  /** Reset */
+  bool reset(Node eqc, QuantifiersEngine* qe) override
+  {
+    d_eq_class = eqc; 
+    return true;
+  }
+  /** Get the next match. */
+  int getNextMatch(Node q,
+                   InstMatch& m,
+                   QuantifiersEngine* qe,
+                   Trigger* tparent) override;
+
+ private:
+  /** stores the true branch of the Boolean ITE */
+  Node d_comp;
+  /** stores whether we have written a value for var in the current match. */
+  bool d_rm_prev;
+};
+
+/** match generator for purified terms
+* This handles the special case of invertible terms like x+1 (see
+* Trigger::getTermInversionVariable).
+*/
+class VarMatchGeneratorTermSubs : public InstMatchGenerator {
+public:
+  VarMatchGeneratorTermSubs( Node var, Node subs );
+
+  /** Reset */
+  bool reset(Node eqc, QuantifiersEngine* qe) override
+  {
+    d_eq_class = eqc;
+    return true;
+  }
+  /** Get the next match. */
+  int getNextMatch(Node q,
+                   InstMatch& m,
+                   QuantifiersEngine* qe,
+                   Trigger* tparent) override;
+
+ private:
+  /** variable we are matching (x in the example x+1). */
+  TNode d_var;
+  /** cache of d_var.getType() */
+  TypeNode d_var_type;
+  /** The substitution for what we match (x-1 in the example x+1). */
+  Node d_subs;
+  /** stores whether we have written a value for d_var in the current match. */
+  bool d_rm_prev;
+};
+
+/** InstMatchGeneratorMultiLinear class
+*
+* This is the default implementation of multi-triggers.
+*
+* Handling multi-triggers using this class is done by constructing a linked
+* list of InstMatchGenerator classes (see mkInstMatchGeneratorMulti), with one
+* InstMatchGeneratorMultiLinear at the head and a list of trailing
+* InstMatchGenerators.
+*
+* CVC4 employs techniques that ensure that the number of instantiations
+* is worst-case polynomial wrt the number of ground terms, where this class
+* lifts this policy to multi-triggers. In particular consider
+*
+*  multi-trigger : { f( x1 ), f( x2 ), f( x3 ), f( x4 ) }
+*
+* For this multi-trigger, we insist that for each i=1...4, and each ground term
+* t, there is at most 1 instantiation added as a result of matching
+*    ( f( x1 ), f( x2 ), f( x3 ), f( x4 ) )
+* against ground terms of the form
+*    ( s_1, s_2, s_3, s_4 ) where t = s_i for i=1,...,4.
+* Meaning we add instantiations for the multi-trigger
+* ( f( x1 ), f( x2 ), f( x3 ), f( x4 ) ) based on matching pairwise against:
+*   ( f( c_i11 ), f( c_i21 ), f( c_i31 ), f( c_i41 ) )
+*   ( f( c_i12 ), f( c_i22 ), f( c_i32 ), f( c_i42 ) )
+*   ( f( c_i13 ), f( c_i23 ), f( c_i33 ), f( c_i43 ) )
+* Where we require c_i{jk} != c_i{jl} for each i=1...4, k != l.
+*
+* For example, we disallow adding instantiations based on matching against both
+* ( f( c_1 ), f( c_2 ), f( c_4 ), f( c_6 ) ) and
+* ( f( c_1 ), f( c_3 ), f( c_5 ), f( c_7 ) )
+* against ( f( x1 ), f( x2 ), f( x3 ), f( x4 ) ), since f( c_1 ) is matched
+* against f( x1 ) twice.
+*
+* This policy can be disabled by --no-multi-trigger-linear.
+*
+*/
+class InstMatchGeneratorMultiLinear : public InstMatchGenerator {
+  friend class InstMatchGenerator;
+
+ public:
+  /** Reset. */
+  bool reset(Node eqc, QuantifiersEngine* qe) override;
+  /** Get the next match. */
+  int getNextMatch(Node q,
+                   InstMatch& m,
+                   QuantifiersEngine* qe,
+                   Trigger* tparent) override;
+
+ protected:
+  /** reset the children of this generator */
+  int resetChildren(QuantifiersEngine* qe);
+  /** constructor */
+  InstMatchGeneratorMultiLinear(Node q,
+                                std::vector<Node>& pats,
+                                QuantifiersEngine* qe);
+};/* class InstMatchGeneratorMulti */
+
+/** InstMatchGeneratorMulti
+*
+* This is an earlier implementation of multi-triggers
+* that is enabled by --multi-trigger-cache.
+* This generator takes the product of instantiations
+* found by single trigger matching, and does
+* not have the guarantee that the number of
+* instantiations is polynomial wrt the number of
+* ground terms.
+*/
+class InstMatchGeneratorMulti : public IMGenerator {
+ public:
+  /** constructors */
+  InstMatchGeneratorMulti(Node q,
+                          std::vector<Node>& pats,
+                          QuantifiersEngine* qe);
+  /** destructor */
+  ~InstMatchGeneratorMulti() override;
+
+  /** Reset instantiation round. */
+  void resetInstantiationRound(QuantifiersEngine* qe) override;
+  /** Reset. */
+  bool reset(Node eqc, QuantifiersEngine* qe) override;
+  /** Add instantiations. */
+  int addInstantiations(Node q,
+                        QuantifiersEngine* qe,
+                        Trigger* tparent) override;
+
+ private:
+  /** indexed trie */
+  typedef std::pair< std::pair< int, int >, InstMatchTrie* > IndexedTrie;
+  /** process new match
+   *
+   * Called during addInstantiations(...).
+   * Indicates we produced a match m for child fromChildIndex
+   * addedLemmas is how many instantiations we succesfully send
+   * via IMGenerator::sendInstantiation(...) calls.
+   */
+  void processNewMatch(QuantifiersEngine* qe,
+                       Trigger* tparent,
+                       InstMatch& m,
+                       int fromChildIndex,
+                       int& addedLemmas);
+  /** helper for process new match
+   * tr is the inst match trie (term index) we are currently traversing.
+   * trieIndex is depth we are in trie tr.
+   * childIndex is the index of the term in the multi trigger we are currently
+   *               processing.
+   * endChildIndex is the index of the term in the multi trigger that generated
+   *                  a new term, and hence we will end when the product
+   *                  computed by this function returns to.
+   * modEq is whether we are matching modulo equality.
+   */
+  void processNewInstantiations(QuantifiersEngine* qe,
+                                Trigger* tparent,
+                                InstMatch& m,
+                                int& addedLemmas,
+                                InstMatchTrie* tr,
+                                int trieIndex,
+                                int childIndex,
+                                int endChildIndex,
+                                bool modEq);
+  /** Map from pattern nodes to indices of variables they contain. */
+  std::map< Node, std::vector< int > > d_var_contains;
+  /** Map from variable indices to pattern nodes that contain them. */
+  std::map< int, std::vector< Node > > d_var_to_node;
+  /** quantified formula we are producing matches for */
+  Node d_quant;
+  /** children generators
+   * These are inst match generators for each term in the multi trigger.
+   */
+  std::vector< InstMatchGenerator* > d_children;
+  /** variable orderings
+   * Stores a heuristically determined variable ordering (unique
+   * variables first) for each term in the multi trigger.
+   */
+  std::map< unsigned, InstMatchTrie::ImtIndexOrder* > d_imtio;
+  /** inst match tries for each child node
+   * This data structure stores all InstMatch objects generated
+   * by matching for each term in the multi trigger.
+   */
+  std::vector< InstMatchTrieOrdered > d_children_trie;
+};/* class InstMatchGeneratorMulti */
+
+/** InstMatchGeneratorSimple class
+*
+* This is the default generator class for simple single triggers.
+* For example, { f( x, a ) }, { f( x, x ) } and { f( x, y ) } are simple single
+* triggers. In practice, around 70-90% of triggers are simple single triggers.
+*
+* Notice that simple triggers also can have an attached polarity.
+* For example, { P( x ) = false }, { f( x, y ) = a } and { ~f( a, x ) = b } are
+* simple single triggers.
+*
+* The implementation traverses the term indices in TermDatabase for adding
+* instantiations, which is more efficient than the techniques required for
+* handling non-simple single triggers.
+*
+* In contrast to other instantiation generators, it does not call
+* IMGenerator::sendInstantiation and for performance reasons instead calls
+* qe->getInstantiate()->addInstantiation(...) directly.
+*/
+class InstMatchGeneratorSimple : public IMGenerator {
+ public:
+  /** constructors */
+  InstMatchGeneratorSimple(Node q, Node pat, QuantifiersEngine* qe);
+
+  /** Reset instantiation round. */
+  void resetInstantiationRound(QuantifiersEngine* qe) override;
+  /** Add instantiations. */
+  int addInstantiations(Node q,
+                        QuantifiersEngine* qe,
+                        Trigger* tparent) override;
+  /** Get active score. */
+  int getActiveScore(QuantifiersEngine* qe) override;
+
+ private:
+  /** quantified formula for the trigger term */
+  Node d_quant;
+  /** the trigger term */
+  Node d_match_pattern;
+  /** equivalence class polarity information
+   *
+  * This stores the required polarity/equivalence class with this trigger.
+  * If d_eqc is non-null, we only produce matches { x->t } such that
+  * our context does not entail
+  *   ( d_match_pattern*{ x->t } = d_eqc) if d_pol = true, or
+  *   ( d_match_pattern*{ x->t } != d_eqc) if d_pol = false.
+  * where * denotes application of substitution.
+  */
+  bool d_pol;
+  Node d_eqc;
+  /** Match pattern arg types.
+   * Cached values of d_match_pattern[i].getType().
+   */
+  std::vector< TypeNode > d_match_pattern_arg_types;
+  /** The match operator d_match_pattern (see TermDb::getMatchOperator). */
+  Node d_op;
+  /** Map from child number to variable index. */
+  std::map< int, int > d_var_num;
+  /** add instantiations, helper function.
+   *
+   * m is the current match we are building,
+   * addedLemmas is the number of lemmas we have added via calls to
+   *                qe->getInstantiate()->aaddInstantiation(...),
+   * argIndex is the argument index in d_match_pattern we are currently
+   *              matching,
+   * tat is the term index we are currently traversing.
+   */
+  void addInstantiations(InstMatch& m,
+                         QuantifiersEngine* qe,
+                         int& addedLemmas,
+                         unsigned argIndex,
+                         quantifiers::TermArgTrie* tat);
+};/* class InstMatchGeneratorSimple */
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp b/src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp
new file mode 100644 (file)
index 0000000..c2c1425
--- /dev/null
@@ -0,0 +1,613 @@
+/*********************                                                        */
+/*! \file inst_strategy_e_matching.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Morgan Deters, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of e matching instantiation strategies
+ **/
+
+#include "theory/quantifiers/ematching/inst_strategy_e_matching.h"
+#include "theory/quantifiers/ematching/inst_match_generator.h"
+#include "theory/quantifiers/quant_relevance.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/theory_engine.h"
+
+using namespace std;
+
+namespace CVC4 {
+
+using namespace kind;
+using namespace context;
+
+namespace theory {
+
+using namespace inst;
+
+namespace quantifiers {
+
+//priority levels :
+//1 : user patterns (when user-pat!={resort,ignore}), auto-gen patterns (for non-user pattern quantifiers, or when user-pat={resort,ignore})
+//2 : user patterns (when user-pat=resort), auto gen patterns (for user pattern quantifiers when user-pat=use)
+
+// user-pat=interleave alternates between use and resort
+
+struct sortQuantifiersForSymbol {
+  QuantifiersEngine* d_qe;
+  std::map< Node, Node > d_op_map;
+  bool operator() (Node i, Node j) {
+    int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_op_map[i] );
+    int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_op_map[j] );
+    if( nqfsi<nqfsj ){
+      return true;
+    }else if( nqfsi>nqfsj ){
+      return false;
+    }else{
+      return false;
+    }
+  }
+};
+
+struct sortTriggers {
+  bool operator() (Node i, Node j) {
+    int wi = Trigger::getTriggerWeight( i );
+    int wj = Trigger::getTriggerWeight( j );
+    if( wi==wj ){
+      return i<j;
+    }else{
+      return wi<wj;
+    }
+  }
+};
+
+void InstStrategyUserPatterns::processResetInstantiationRound( Theory::Effort effort ){
+  Trace("inst-alg-debug") << "reset user triggers" << std::endl;
+  //reset triggers
+  for( std::map< Node, std::vector< Trigger* > >::iterator it = d_user_gen.begin(); it != d_user_gen.end(); ++it ){
+    for( unsigned i=0; i<it->second.size(); i++ ){
+      it->second[i]->resetInstantiationRound();
+      it->second[i]->reset( Node::null() );
+    }
+  }
+  Trace("inst-alg-debug") << "done reset user triggers" << std::endl;
+}
+
+int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){
+  if( e==0 ){
+    return STATUS_UNFINISHED;
+  }else{
+    int peffort = d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ? 2 : 1;
+    if( e<peffort ){
+      return STATUS_UNFINISHED;
+    }else if( e==peffort ){
+      d_counter[f]++;
+
+      Trace("inst-alg") << "-> User-provided instantiate " << f << "..." << std::endl;
+      if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT  ){
+        for( unsigned i=0; i<d_user_gen_wait[f].size(); i++ ){
+          Trigger * t = Trigger::mkTrigger( d_quantEngine, f, d_user_gen_wait[f][i], true, Trigger::TR_RETURN_NULL );
+          if( t ){
+            d_user_gen[f].push_back( t );
+          }
+        }
+        d_user_gen_wait[f].clear();
+      }
+
+      for( unsigned i=0; i<d_user_gen[f].size(); i++ ){
+        bool processTrigger = true;
+        if( processTrigger ){
+          Trace("process-trigger") << "  Process (user) ";
+          d_user_gen[f][i]->debugPrint("process-trigger");
+          Trace("process-trigger") << "..." << std::endl;
+          int numInst = d_user_gen[f][i]->addInstantiations();
+          Trace("process-trigger") << "  Done, numInst = " << numInst << "." << std::endl;
+          d_quantEngine->d_statistics.d_instantiations_user_patterns += numInst;
+          if( d_user_gen[f][i]->isMultiTrigger() ){
+            d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst;
+          }
+          if( d_quantEngine->inConflict() ){
+            break;
+          }
+        }
+      }
+    }
+  }
+  return STATUS_UNKNOWN;
+}
+
+void InstStrategyUserPatterns::addUserPattern( Node q, Node pat ){
+  Assert( pat.getKind()==INST_PATTERN );
+  //add to generators
+  bool usable = true;
+  std::vector< Node > nodes;
+  for( unsigned i=0; i<pat.getNumChildren(); i++ ){
+    Node pat_use = Trigger::getIsUsableTrigger( pat[i], q );
+    if( pat_use.isNull() ){
+      Trace("trigger-warn") << "User-provided trigger is not usable : " << pat << " because of " << pat[i] << std::endl;
+      usable = false;
+      break;
+    }else{
+      nodes.push_back( pat_use );
+    }
+  }
+  if( usable ){
+    Trace("user-pat") << "Add user pattern: " << pat << " for " << q << std::endl;
+    //check match option
+    if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ){
+      d_user_gen_wait[q].push_back( nodes );
+    }else{
+      Trigger * t = Trigger::mkTrigger( d_quantEngine, q, nodes, true, Trigger::TR_MAKE_NEW );
+      if( t ){
+        d_user_gen[q].push_back( t );
+      }else{
+        Trace("trigger-warn") << "Failed to construct trigger : " << pat << " due to variable mismatch" << std::endl;
+      }
+    }
+  }
+}
+
+InstStrategyAutoGenTriggers::InstStrategyAutoGenTriggers( QuantifiersEngine* qe ) : InstStrategy( qe ){
+  //how to select trigger terms
+  d_tr_strategy = options::triggerSelMode();
+  //whether to select new triggers during the search
+  if( options::incrementTriggers() ){
+    d_regenerate_frequency = 3;
+    d_regenerate = true;
+  }else{
+    d_regenerate_frequency = 1;
+    d_regenerate = false;
+  }
+}
+
+void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){
+  Trace("inst-alg-debug") << "reset auto-gen triggers" << std::endl;
+  //reset triggers
+  for( unsigned r=0; r<2; r++ ){
+    for( std::map< Node, std::map< Trigger*, bool > >::iterator it = d_auto_gen_trigger[r].begin(); it != d_auto_gen_trigger[r].end(); ++it ){
+      for( std::map< Trigger*, bool >::iterator itt = it->second.begin(); itt != it->second.end(); ++itt ){
+        itt->first->resetInstantiationRound();
+        itt->first->reset( Node::null() );
+      }
+    }
+  }
+  d_processed_trigger.clear();
+  Trace("inst-alg-debug") << "done reset auto-gen triggers" << std::endl;
+}
+
+int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ){
+  UserPatMode upMode = d_quantEngine->getInstUserPatMode();
+  if( hasUserPatterns( f ) && upMode==USER_PAT_MODE_TRUST ){
+    return STATUS_UNKNOWN;
+  }else{
+    int peffort = ( hasUserPatterns( f ) && upMode!=USER_PAT_MODE_IGNORE && upMode!=USER_PAT_MODE_RESORT ) ? 2 : 1;
+    if( e<peffort ){
+      return STATUS_UNFINISHED;
+    }else{
+      Trace("inst-alg") << "-> Auto-gen instantiate " << f << "..." << std::endl;
+      bool gen = false;
+      if( e==peffort ){
+        if( d_counter.find( f )==d_counter.end() ){
+          d_counter[f] = 0;
+          gen = true;
+        }else{
+          d_counter[f]++;
+          gen = d_regenerate && d_counter[f]%d_regenerate_frequency==0;
+        }
+      }else{
+        gen = true;
+      }
+      if( gen ){
+        generateTriggers( f );
+        if( d_counter[f]==0 && d_auto_gen_trigger[0][f].empty() && d_auto_gen_trigger[1][f].empty() && f.getNumChildren()==2 ){
+          Trace("trigger-warn") << "Could not find trigger for " << f << std::endl;
+        }
+      }
+
+      //if( e==4 ){
+      //  d_processed_trigger.clear();
+      //  d_quantEngine->getEqualityQuery()->setLiberal( true );
+      //}
+      if( options::triggerActiveSelMode()!=TRIGGER_ACTIVE_SEL_ALL ){
+        int max_score = -1;
+        Trigger * max_trigger = NULL;
+        for( std::map< Trigger*, bool >::iterator itt = d_auto_gen_trigger[0][f].begin(); itt != d_auto_gen_trigger[0][f].end(); ++itt ){
+          int score = itt->first->getActiveScore();
+          if( options::triggerActiveSelMode()==TRIGGER_ACTIVE_SEL_MIN ){
+            if( score>=0 && ( score<max_score || max_score<0 ) ){
+              max_score = score;
+              max_trigger = itt->first;
+            } 
+          }else{
+            if( score>max_score ){
+              max_score = score;
+              max_trigger = itt->first;
+            }
+          }
+          d_auto_gen_trigger[0][f][itt->first] = false;
+        }
+        if( max_trigger!=NULL ){
+          d_auto_gen_trigger[0][f][max_trigger] = true;
+        }
+      }
+      
+      bool hasInst = false;
+      for( unsigned r=0; r<2; r++ ){
+        for( std::map< Trigger*, bool >::iterator itt = d_auto_gen_trigger[r][f].begin(); itt != d_auto_gen_trigger[r][f].end(); ++itt ){
+          Trigger* tr = itt->first;
+          if( tr ){
+            bool processTrigger = itt->second;
+            if( processTrigger && d_processed_trigger[f].find( tr )==d_processed_trigger[f].end() ){
+              d_processed_trigger[f][tr] = true;
+              Trace("process-trigger") << "  Process ";
+              tr->debugPrint("process-trigger");
+              Trace("process-trigger") << "..." << std::endl;
+              int numInst = tr->addInstantiations();
+              hasInst = numInst>0 || hasInst;
+              Trace("process-trigger") << "  Done, numInst = " << numInst << "." << std::endl;
+              d_quantEngine->d_statistics.d_instantiations_auto_gen += numInst;
+              if( r==1 ){
+                d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst;
+              }
+              if( d_quantEngine->inConflict() ){
+                break;
+              }
+            }
+          }
+        }
+        if( d_quantEngine->inConflict() || ( hasInst && options::multiTriggerPriority() ) ){
+          break;
+        }
+      }
+      //if( e==4 ){
+      //  d_quantEngine->getEqualityQuery()->setLiberal( false );
+      //}
+      return STATUS_UNKNOWN;
+    }
+  }
+}
+
+void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
+  Trace("auto-gen-trigger-debug") << "Generate triggers for " << f << ", #var=" << f[0].getNumChildren() << "..." << std::endl;
+  if( d_patTerms[0].find( f )==d_patTerms[0].end() ){
+    //determine all possible pattern terms based on trigger term selection strategy d_tr_strategy
+    d_patTerms[0][f].clear();
+    d_patTerms[1][f].clear();
+    bool ntrivTriggers = options::relationalTriggers();
+    std::vector< Node > patTermsF;
+    std::map< Node, inst::TriggerTermInfo > tinfo;
+    //well-defined function: can assume LHS is only trigger
+    if( options::quantFunWellDefined() ){
+      Node hd = QuantAttributes::getFunDefHead( f );
+      if( !hd.isNull() ){
+        hd = d_quantEngine->getTermUtil()
+                 ->substituteBoundVariablesToInstConstants(hd, f);
+        patTermsF.push_back( hd );
+        tinfo[hd].init( f, hd );
+      }
+    }
+    //otherwise, use algorithm for collecting pattern terms
+    if( patTermsF.empty() ){
+      Node bd = d_quantEngine->getTermUtil()->getInstConstantBody( f );
+      Trigger::collectPatTerms( f, bd, patTermsF, d_tr_strategy, d_user_no_gen[f], tinfo, true );
+      if( ntrivTriggers ){
+        sortTriggers st;
+        std::sort( patTermsF.begin(), patTermsF.end(), st );
+      }
+      if( Trace.isOn("auto-gen-trigger-debug") ){
+        Trace("auto-gen-trigger-debug") << "Collected pat terms for " << bd << ", no-patterns : " << d_user_no_gen[f].size() << std::endl;
+        for( unsigned i=0; i<patTermsF.size(); i++ ){
+          Assert( tinfo.find( patTermsF[i] )!=tinfo.end() );
+          Trace("auto-gen-trigger-debug") << "   " << patTermsF[i] << std::endl;
+          Trace("auto-gen-trigger-debug2") << "     info = [" << tinfo[patTermsF[i]].d_reqPol << ", " << tinfo[patTermsF[i]].d_reqPolEq << ", " << tinfo[patTermsF[i]].d_fv.size() << "]" << std::endl;
+        }
+        Trace("auto-gen-trigger-debug") << std::endl;
+      }
+    }
+    //sort into single/multi triggers, calculate which terms should not be considered
+    std::map< Node, bool > vcMap;
+    std::map< Node, bool > rmPatTermsF;
+    int last_weight = -1;
+    for( unsigned i=0; i<patTermsF.size(); i++ ){
+      Assert( patTermsF[i].getKind()!=NOT );
+      bool newVar = false;
+      for( unsigned j=0; j<tinfo[ patTermsF[i] ].d_fv.size(); j++ ){
+        if( vcMap.find( tinfo[ patTermsF[i] ].d_fv[j] )==vcMap.end() ){
+          vcMap[tinfo[ patTermsF[i] ].d_fv[j]] = true;
+          newVar = true;
+        }
+      }
+      int curr_w = Trigger::getTriggerWeight( patTermsF[i] );
+      if( ntrivTriggers && !newVar && last_weight!=-1 && curr_w>last_weight ){
+        Trace("auto-gen-trigger-debug") << "...exclude expendible non-trivial trigger : " << patTermsF[i] << std::endl;
+        rmPatTermsF[patTermsF[i]] = true;
+      }else{
+        last_weight = curr_w;
+      }
+    }
+    d_num_trigger_vars[f] = vcMap.size();
+    if( d_num_trigger_vars[f]>0 && d_num_trigger_vars[f]<f[0].getNumChildren() ){
+      Trace("auto-gen-trigger-partial") << "Quantified formula : " << f << std::endl;
+      Trace("auto-gen-trigger-partial") << "...does not contain all variables in triggers!!!" << std::endl;
+      if( options::partialTriggers() ){
+        std::vector< Node > vcs[2];
+        for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
+          Node ic = d_quantEngine->getTermUtil()->getInstantiationConstant( f, i );
+          vcs[ vcMap.find( ic )==vcMap.end() ? 0 : 1 ].push_back( f[0][i] );
+        }
+        for( unsigned i=0; i<2; i++ ){
+          d_vc_partition[i][f] = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, vcs[i] );
+        }
+      }else{
+        return;
+      }
+    }
+    for( unsigned i=0; i<patTermsF.size(); i++ ){
+      Node pat = patTermsF[i];
+      if( rmPatTermsF.find( pat )==rmPatTermsF.end() ){
+        Trace("auto-gen-trigger-debug") << "...processing pattern " << pat << std::endl;
+        Node mpat = pat;
+        //process the pattern: if it has a required polarity, consider it
+        Assert( tinfo.find( pat )!=tinfo.end() );
+        int rpol = tinfo[pat].d_reqPol;
+        Node rpoleq = tinfo[pat].d_reqPolEq;
+        unsigned num_fv = tinfo[pat].d_fv.size();
+        Trace("auto-gen-trigger-debug") << "...required polarity for " << pat << " is " << rpol << ", eq=" << rpoleq << std::endl;
+        if( rpol!=0 ){
+          Assert( rpol==1 || rpol==-1 );
+          if( Trigger::isRelationalTrigger( pat ) ){
+            pat = rpol==-1 ? pat.negate() : pat;
+          }else{
+            Assert( Trigger::isAtomicTrigger( pat ) );
+            if( pat.getType().isBoolean() && rpoleq.isNull() ){
+              if( options::literalMatchMode()==LITERAL_MATCH_USE ){
+                pat = NodeManager::currentNM()->mkNode( EQUAL, pat, NodeManager::currentNM()->mkConst( rpol==-1 ) ).negate();
+              }else if( options::literalMatchMode()!=LITERAL_MATCH_NONE ){
+                pat = NodeManager::currentNM()->mkNode( EQUAL, pat, NodeManager::currentNM()->mkConst( rpol==1 ) );
+              }
+            }else{
+              Assert( !rpoleq.isNull() );
+              if( rpol==-1 ){
+                if( options::literalMatchMode()!=LITERAL_MATCH_NONE ){
+                  //all equivalence classes except rpoleq
+                  pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq ).negate();
+                }
+              }else if( rpol==1 ){
+                if( options::literalMatchMode()==LITERAL_MATCH_AGG ){
+                  //only equivalence class rpoleq
+                  pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq );
+                }
+                //all equivalence classes that are not disequal to rpoleq TODO?
+              }
+            }
+          }
+          Trace("auto-gen-trigger-debug") << "...got : " << pat << std::endl;
+        }else{
+          if( Trigger::isRelationalTrigger( pat ) ){
+            //consider both polarities
+            addPatternToPool( f, pat.negate(), num_fv, mpat );
+          }
+        }
+        addPatternToPool( f, pat, num_fv, mpat );
+      }
+    }
+    //tinfo not used below this point
+    d_made_multi_trigger[f] = false;
+    Trace("auto-gen-trigger") << "Single trigger pool for " << f << " : " << std::endl;
+    for( unsigned i=0; i<d_patTerms[0][f].size(); i++ ){
+      Trace("auto-gen-trigger") << "   " << d_patTerms[0][f][i] << std::endl;
+    }
+    if( !d_patTerms[1][f].empty() ){
+      Trace("auto-gen-trigger") << "Multi-trigger term pool for " << f << " : " << std::endl;
+      for( unsigned i=0; i<d_patTerms[1][f].size(); i++ ){
+        Trace("auto-gen-trigger") << "   " << d_patTerms[1][f][i] << std::endl;
+      }
+    }
+  }
+
+  unsigned rmin = d_patTerms[0][f].empty() ? 1 : 0;
+  unsigned rmax = options::multiTriggerWhenSingle() ? 1 : rmin;
+  for( unsigned r=rmin; r<=rmax; r++ ){
+    std::vector< Node > patTerms;
+    for( int i=0; i<(int)d_patTerms[r][f].size(); i++ ){
+      if( r==1 || d_single_trigger_gen.find( d_patTerms[r][f][i] )==d_single_trigger_gen.end() ){
+        patTerms.push_back( d_patTerms[r][f][i] );
+      }
+    }
+    if( !patTerms.empty() ){
+      Trace("auto-gen-trigger") << "Generate trigger for " << f << std::endl;
+      //sort terms based on relevance
+      if( options::relevantTriggers() ){
+        sortQuantifiersForSymbol sqfs;
+        sqfs.d_qe = d_quantEngine;
+        for( unsigned i=0; i<patTerms.size(); i++ ){
+          Assert( d_pat_to_mpat.find( patTerms[i] )!=d_pat_to_mpat.end() );
+          Assert( d_pat_to_mpat[patTerms[i]].hasOperator() );
+          sqfs.d_op_map[ patTerms[i] ] = d_pat_to_mpat[patTerms[i]].getOperator();
+        }        
+        //sort based on # occurrences (this will cause Trigger to select rarer symbols)
+        std::sort( patTerms.begin(), patTerms.end(), sqfs );
+        Debug("relevant-trigger") << "Terms based on relevance: " << std::endl;
+        for( unsigned i=0; i<patTerms.size(); i++ ){
+          Debug("relevant-trigger") << "   " << patTerms[i] << " from " << d_pat_to_mpat[patTerms[i]] << " (";
+          Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_pat_to_mpat[patTerms[i]].getOperator() ) << ")" << std::endl;
+        }
+      }
+      //now, generate the trigger...
+      Trigger* tr = NULL;
+      if( d_is_single_trigger[ patTerms[0] ] ){
+        tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], false, Trigger::TR_RETURN_NULL, d_num_trigger_vars[f] );
+        d_single_trigger_gen[ patTerms[0] ] = true;
+      }else{
+        //only generate multi trigger if option set, or if no single triggers exist
+        if( !d_patTerms[0][f].empty() ){
+          if( options::multiTriggerWhenSingle() ){
+            Trace("multi-trigger-debug") << "Resort to choosing multi-triggers..." << std::endl;
+          }else{
+            return;
+          }
+        }
+        //if we are re-generating triggers, shuffle based on some method
+        if( d_made_multi_trigger[f] ){
+          std::random_shuffle( patTerms.begin(), patTerms.end() ); //shuffle randomly
+        }else{
+          d_made_multi_trigger[f] = true;
+        }
+        //will possibly want to get an old trigger
+        tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, false, Trigger::TR_GET_OLD, d_num_trigger_vars[f] );
+      }
+      if( tr ){
+        addTrigger( tr, f );
+        //if we are generating additional triggers...
+        if( !tr->isMultiTrigger() ){
+          unsigned index = 0;
+          if( index<patTerms.size() ){
+            //Notice() << "check add additional" << std::endl;
+            //check if similar patterns exist, and if so, add them additionally
+            unsigned nqfs_curr = 0;
+            if( options::relevantTriggers() ){
+              nqfs_curr = d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[0].getOperator() );
+            }
+            index++;
+            bool success = true;
+            while( success && index<patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){
+              success = false;
+              if( !options::relevantTriggers() ||
+                  d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[index].getOperator() )<=nqfs_curr ){
+                d_single_trigger_gen[ patTerms[index] ] = true;
+                Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], false, Trigger::TR_RETURN_NULL, d_num_trigger_vars[f] );
+                addTrigger( tr2, f );
+                success = true;
+              }
+              index++;
+            }
+            //Notice() << "done check add additional" << std::endl;
+          }
+        }
+      }
+    }
+  }
+}
+
+void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat ) {
+  d_pat_to_mpat[pat] = mpat;
+  unsigned num_vars = options::partialTriggers() ? d_num_trigger_vars[q] : q[0].getNumChildren();
+  if( num_fv==num_vars && ( options::pureThTriggers() || !Trigger::isPureTheoryTrigger( pat ) ) ){
+    d_patTerms[0][q].push_back( pat );
+    d_is_single_trigger[ pat ] = true;
+  }else{
+    d_patTerms[1][q].push_back( pat );
+    d_is_single_trigger[ pat ] = false;
+  }
+}
+
+
+void InstStrategyAutoGenTriggers::addTrigger( inst::Trigger * tr, Node q ) {
+  if( tr ){
+    if( d_num_trigger_vars[q]<q[0].getNumChildren() ){
+      //partial trigger : generate implication to mark user pattern
+      Node pat =
+          d_quantEngine->getTermUtil()->substituteInstConstantsToBoundVariables(
+              tr->getInstPattern(), q);
+      Node ipl = NodeManager::currentNM()->mkNode(INST_PATTERN_LIST, pat);
+      Node qq = NodeManager::currentNM()->mkNode( FORALL, d_vc_partition[1][q], NodeManager::currentNM()->mkNode( FORALL, d_vc_partition[0][q], q[1] ), ipl );
+      Trace("auto-gen-trigger-partial") << "Make partially specified user pattern: " << std::endl;
+      Trace("auto-gen-trigger-partial") << "  " << qq << std::endl;
+      Node lem = NodeManager::currentNM()->mkNode( OR, q.negate(), qq );
+      d_quantEngine->addLemma( lem );
+    }else{
+      unsigned tindex;
+      if( tr->isMultiTrigger() ){
+        //disable all other multi triggers
+        for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[1][q].begin(); it != d_auto_gen_trigger[1][q].end(); ++it ){
+          d_auto_gen_trigger[1][q][ it->first ] = false;
+        }
+        tindex = 1;
+      }else{
+        tindex = 0;
+      }
+      //making it during an instantiation round, so must reset
+      if( d_auto_gen_trigger[tindex][q].find( tr )==d_auto_gen_trigger[tindex][q].end() ){
+        tr->resetInstantiationRound();
+        tr->reset( Node::null() );
+      }
+      d_auto_gen_trigger[tindex][q][tr] = true;
+    }
+  }
+}
+
+bool InstStrategyAutoGenTriggers::hasUserPatterns( Node q ) {
+  if( q.getNumChildren()==3 ){
+    std::map< Node, bool >::iterator it = d_hasUserPatterns.find( q );
+    if( it==d_hasUserPatterns.end() ){
+      bool hasPat = false;
+      for( unsigned i=0; i<q[2].getNumChildren(); i++ ){
+        if( q[2][i].getKind()==INST_PATTERN ){
+          hasPat = true;
+          break;
+        }
+      }
+      d_hasUserPatterns[q] = hasPat;
+      return hasPat;
+    }else{
+      return it->second;
+    }
+  }else{
+    return false;
+  }
+}
+
+void InstStrategyAutoGenTriggers::addUserNoPattern( Node q, Node pat ) {
+  Assert( pat.getKind()==INST_NO_PATTERN && pat.getNumChildren()==1 );
+  if( std::find( d_user_no_gen[q].begin(), d_user_no_gen[q].end(), pat[0] )==d_user_no_gen[q].end() ){
+    Trace("user-pat") << "Add user no-pattern: " << pat[0] << " for " << q << std::endl;
+    d_user_no_gen[q].push_back( pat[0] );
+  }
+}
+
+/*  TODO?
+bool InstStrategyLocalTheoryExt::isLocalTheoryExt( Node f ) {
+  std::map< Node, bool >::iterator itq = d_quant.find( f );
+  if( itq==d_quant.end() ){
+    //generate triggers
+    Node bd = d_quantEngine->getTermUtil()->getInstConstantBody( f );
+    std::vector< Node > vars;
+    std::vector< Node > patTerms;
+    bool ret = Trigger::isLocalTheoryExt( bd, vars, patTerms );
+    if( ret ){
+      d_quant[f] = ret;
+      //add all variables to trigger that don't already occur
+      for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
+        Node x = d_quantEngine->getTermUtil()->getInstantiationConstant( f, i );
+        if( std::find( vars.begin(), vars.end(), x )==vars.end() ){
+          patTerms.push_back( x );
+        }
+      }
+      Trace("local-t-ext") << "Local theory extensions trigger for " << f << " : " << std::endl;
+      for( unsigned i=0; i<patTerms.size(); i++ ){
+        Trace("local-t-ext") << "  " << patTerms[i] << std::endl;
+      }
+      Trace("local-t-ext") << std::endl;
+      Trigger * tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, true, Trigger::TR_GET_OLD );
+      d_lte_trigger[f] = tr;
+    }else{
+      Trace("local-t-ext") << "No local theory extensions trigger for " << f << "." << std::endl;
+      Trace("local-t-ext-warn") << "WARNING: not local theory extensions : " << f << std::endl;
+    }
+    d_quant[f] = ret;
+    return ret;
+  }else{
+    return itq->second;
+  }
+}
+*/
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/ematching/inst_strategy_e_matching.h b/src/theory/quantifiers/ematching/inst_strategy_e_matching.h
new file mode 100644 (file)
index 0000000..8f11dfe
--- /dev/null
@@ -0,0 +1,119 @@
+/*********************                                                        */
+/*! \file inst_strategy_e_matching.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Morgan Deters, Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief E matching instantiation strategies
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__INST_STRATEGY_E_MATCHING_H
+#define __CVC4__INST_STRATEGY_E_MATCHING_H
+
+#include "context/context.h"
+#include "context/context_mm.h"
+#include "theory/quantifiers/ematching/instantiation_engine.h"
+#include "theory/quantifiers/ematching/trigger.h"
+#include "theory/quantifiers_engine.h"
+#include "util/statistics_registry.h"
+#include "options/quantifiers_options.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+//instantiation strategies
+
+class InstStrategyUserPatterns : public InstStrategy{
+private:
+  /** explicitly provided patterns */
+  std::map< Node, std::vector< inst::Trigger* > > d_user_gen;
+  /** waiting to be generated patterns */
+  std::map< Node, std::vector< std::vector< Node > > > d_user_gen_wait;
+  /** counter for quantifiers */
+  std::map< Node, int > d_counter;
+  /** process functions */
+  void processResetInstantiationRound( Theory::Effort effort );
+  int process( Node f, Theory::Effort effort, int e );
+public:
+  InstStrategyUserPatterns( QuantifiersEngine* ie ) :
+      InstStrategy( ie ){}
+  ~InstStrategyUserPatterns(){}
+public:
+  /** add pattern */
+  void addUserPattern( Node q, Node pat );
+  /** get num patterns */
+  int getNumUserGenerators( Node q ) { return (int)d_user_gen[q].size(); }
+  /** get user pattern */
+  inst::Trigger* getUserGenerator( Node q, int i ) { return d_user_gen[q][ i ]; }
+  /** identify */
+  std::string identify() const { return std::string("UserPatterns"); }
+};/* class InstStrategyUserPatterns */
+
+class InstStrategyAutoGenTriggers : public InstStrategy {
+public:
+  enum {
+    RELEVANCE_NONE,
+    RELEVANCE_DEFAULT,
+  };
+private:
+  /** trigger generation strategy */
+  TriggerSelMode d_tr_strategy;
+  /** regeneration */
+  bool d_regenerate;
+  int d_regenerate_frequency;
+  /** (single,multi) triggers for each quantifier */
+  std::map< Node, std::map< inst::Trigger*, bool > > d_auto_gen_trigger[2];
+  std::map< Node, int > d_counter;
+  /** single, multi triggers for each quantifier */
+  std::map< Node, std::vector< Node > > d_patTerms[2];
+  std::map< Node, std::map< Node, bool > > d_patReqPol;
+  /** information about triggers */
+  std::map< Node, bool > d_is_single_trigger;
+  std::map< Node, bool > d_single_trigger_gen;
+  std::map< Node, bool > d_made_multi_trigger;
+  //processed trigger this round
+  std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger;
+  //instantiation no patterns
+  std::map< Node, std::vector< Node > > d_user_no_gen;
+  // number of trigger variables per quantifier
+  std::map< Node, unsigned > d_num_trigger_vars;
+  std::map< Node, Node > d_vc_partition[2];
+  std::map< Node, Node > d_pat_to_mpat;
+private:
+  /** process functions */
+  void processResetInstantiationRound( Theory::Effort effort );
+  int process( Node q, Theory::Effort effort, int e );
+  /** generate triggers */
+  void generateTriggers( Node q );
+  void addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat );
+  void addTrigger( inst::Trigger * tr, Node f );
+  /** has user patterns */
+  bool hasUserPatterns( Node q );
+  /** has user patterns */
+  std::map< Node, bool > d_hasUserPatterns;
+public:
+  InstStrategyAutoGenTriggers( QuantifiersEngine* qe );
+  ~InstStrategyAutoGenTriggers(){}
+public:
+  /** get auto-generated trigger */
+  inst::Trigger* getAutoGenTrigger( Node q );
+  /** identify */
+  std::string identify() const { return std::string("AutoGenTriggers"); }
+  /** add pattern */
+  void addUserNoPattern( Node q, Node pat );
+};/* class InstStrategyAutoGenTriggers */
+
+
+}
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif
diff --git a/src/theory/quantifiers/ematching/instantiation_engine.cpp b/src/theory/quantifiers/ematching/instantiation_engine.cpp
new file mode 100644 (file)
index 0000000..184add8
--- /dev/null
@@ -0,0 +1,209 @@
+/*********************                                                        */
+/*! \file instantiation_engine.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Morgan Deters, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of instantiation engine class
+ **/
+
+#include "theory/quantifiers/ematching/instantiation_engine.h"
+
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/ematching/inst_strategy_e_matching.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers/ematching/trigger.h"
+#include "theory/theory_engine.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::theory::inst;
+
+InstantiationEngine::InstantiationEngine(QuantifiersEngine* qe)
+    : QuantifiersModule(qe),
+      d_instStrategies(),
+      d_isup(),
+      d_i_ag(),
+      d_quants() {
+  if (options::eMatching()) {
+    // these are the instantiation strategies for E-matching
+    // user-provided patterns
+    if (options::userPatternsQuant() != USER_PAT_MODE_IGNORE) {
+      d_isup.reset(new InstStrategyUserPatterns(d_quantEngine));
+      d_instStrategies.push_back(d_isup.get());
+    }
+
+    // auto-generated patterns
+    d_i_ag.reset(new InstStrategyAutoGenTriggers(d_quantEngine));
+    d_instStrategies.push_back(d_i_ag.get());
+  }
+}
+
+InstantiationEngine::~InstantiationEngine() {}
+
+void InstantiationEngine::presolve() {
+  for( unsigned i=0; i<d_instStrategies.size(); ++i ){
+    d_instStrategies[i]->presolve();
+  }
+}
+
+void InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
+  unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting();
+  //iterate over an internal effort level e
+  int e = 0;
+  int eLimit = effort==Theory::EFFORT_LAST_CALL ? 10 : 2;
+  bool finished = false;
+  //while unfinished, try effort level=0,1,2....
+  while( !finished && e<=eLimit ){
+    Debug("inst-engine") << "IE: Prepare instantiation (" << e << ")." << std::endl;
+    finished = true;
+    //instantiate each quantifier
+    for( unsigned i=0; i<d_quants.size(); i++ ){
+      Node q = d_quants[i];
+      Debug("inst-engine-debug") << "IE: Instantiate " << q << "..." << std::endl;
+      //int e_use = d_quantEngine->getRelevance( q )==-1 ? e - 1 : e;
+      int e_use = e;
+      if( e_use>=0 ){
+        Trace("inst-engine-debug") << "inst-engine : " << q << std::endl;
+        //check each instantiation strategy
+        for( unsigned j=0; j<d_instStrategies.size(); j++ ){
+          InstStrategy* is = d_instStrategies[j];
+          Trace("inst-engine-debug") << "Do " << is->identify() << " " << e_use << std::endl;
+          int quantStatus = is->process( q, effort, e_use );
+          Trace("inst-engine-debug") << " -> status is " << quantStatus << ", conflict=" << d_quantEngine->inConflict() << std::endl;
+          if( d_quantEngine->inConflict() ){
+            return;
+          }else if( quantStatus==InstStrategy::STATUS_UNFINISHED ){
+            finished = false;
+          }
+        }
+      }
+    }
+    //do not consider another level if already added lemma at this level
+    if( d_quantEngine->getNumLemmasWaiting()>lastWaiting ){
+      finished = true;
+    }
+    e++;
+  }
+}
+
+bool InstantiationEngine::needsCheck( Theory::Effort e ){
+  return d_quantEngine->getInstWhenNeedsCheck( e );
+}
+
+void InstantiationEngine::reset_round( Theory::Effort e ){
+  //if not, proceed to instantiation round
+  //reset the instantiation strategies
+  for( unsigned i=0; i<d_instStrategies.size(); ++i ){
+    InstStrategy* is = d_instStrategies[i];
+    is->processResetInstantiationRound( e );
+  }
+}
+
+void InstantiationEngine::check(Theory::Effort e, QEffort quant_e)
+{
+  CodeTimer codeTimer(d_quantEngine->d_statistics.d_ematching_time);
+  if (quant_e == QEFFORT_STANDARD)
+  {
+    double clSet = 0;
+    if( Trace.isOn("inst-engine") ){
+      clSet = double(clock())/double(CLOCKS_PER_SEC);
+      Trace("inst-engine") << "---Instantiation Engine Round, effort = " << e << "---" << std::endl;
+    }
+    //collect all active quantified formulas belonging to this
+    bool quantActive = false;
+    d_quants.clear();
+    for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
+      Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true );
+      if( d_quantEngine->hasOwnership( q, this ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){
+        quantActive = true;
+        d_quants.push_back( q );
+      }
+    }
+    Trace("inst-engine-debug") << "InstEngine: check: # asserted quantifiers " << d_quants.size() << "/";
+    Trace("inst-engine-debug") << d_quantEngine->getModel()->getNumAssertedQuantifiers() << " " << quantActive << std::endl;
+    if( quantActive ){
+      unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting();
+      doInstantiationRound( e );
+      if( d_quantEngine->inConflict() ){
+        Assert( d_quantEngine->getNumLemmasWaiting()>lastWaiting );
+        Trace("inst-engine") << "Conflict, added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl;
+      }else if( d_quantEngine->hasAddedLemma() ){
+        Trace("inst-engine") << "Added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting)  << std::endl;
+      }
+    }else{
+      d_quants.clear();
+    }
+    if( Trace.isOn("inst-engine") ){
+      double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+      Trace("inst-engine") << "Finished instantiation engine, time = " << (clSet2-clSet) << std::endl;
+    }
+  }
+}
+
+bool InstantiationEngine::checkCompleteFor( Node q ) {
+  //TODO?
+  return false;
+}
+
+void InstantiationEngine::preRegisterQuantifier( Node q ) {
+  if( options::strictTriggers() && q.getNumChildren()==3 ){
+    //if strict triggers, take ownership of this quantified formula
+    bool hasPat = false;
+    for( unsigned i=0; i<q[2].getNumChildren(); i++ ){
+      if( q[2][i].getKind()==INST_PATTERN || q[2][i].getKind()==INST_NO_PATTERN  ){
+        hasPat = true;
+        break;
+      }
+    }
+    if( hasPat ){
+      d_quantEngine->setOwner( q, this, 1 );
+    }
+  }
+}
+
+void InstantiationEngine::registerQuantifier( Node f ){
+  if( d_quantEngine->hasOwnership( f, this ) ){
+    //for( unsigned i=0; i<d_instStrategies.size(); ++i ){
+    //  d_instStrategies[i]->registerQuantifier( f );
+    //}
+    //take into account user patterns
+    if( f.getNumChildren()==3 ){
+      Node subsPat =
+          d_quantEngine->getTermUtil()->substituteBoundVariablesToInstConstants(
+              f[2], f);
+      //add patterns
+      for( int i=0; i<(int)subsPat.getNumChildren(); i++ ){
+        //Notice() << "Add pattern " << subsPat[i] << " for " << f << std::endl;
+        if( subsPat[i].getKind()==INST_PATTERN ){
+          addUserPattern( f, subsPat[i] );
+        }else if( subsPat[i].getKind()==INST_NO_PATTERN ){
+          addUserNoPattern( f, subsPat[i] );
+        }
+      }
+    }
+  }
+}
+
+void InstantiationEngine::addUserPattern(Node q, Node pat) {
+  if (d_isup) {
+    d_isup->addUserPattern(q, pat);
+  }
+}
+
+void InstantiationEngine::addUserNoPattern(Node q, Node pat) {
+  if (d_i_ag) {
+    d_i_ag->addUserNoPattern(q, pat);
+  }
+}
diff --git a/src/theory/quantifiers/ematching/instantiation_engine.h b/src/theory/quantifiers/ematching/instantiation_engine.h
new file mode 100644 (file)
index 0000000..18b5ea1
--- /dev/null
@@ -0,0 +1,98 @@
+/*********************                                                        */
+/*! \file instantiation_engine.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Morgan Deters, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Instantiation Engine classes
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__INSTANTIATION_ENGINE_H
+#define __CVC4__THEORY__QUANTIFIERS__INSTANTIATION_ENGINE_H
+
+#include <memory>
+
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/theory_quantifiers.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class InstStrategyUserPatterns;
+class InstStrategyAutoGenTriggers;
+class InstStrategyFreeVariable;
+
+/** instantiation strategy class */
+class InstStrategy {
+public:
+  enum Status {
+    STATUS_UNFINISHED,
+    STATUS_UNKNOWN,
+  };/* enum Status */
+protected:
+  /** reference to the instantiation engine */
+  QuantifiersEngine* d_quantEngine;
+public:
+  InstStrategy( QuantifiersEngine* qe ) : d_quantEngine( qe ){}
+  virtual ~InstStrategy(){}
+  /** presolve */
+  virtual void presolve() {}
+  /** reset instantiation */
+  virtual void processResetInstantiationRound( Theory::Effort effort ) = 0;
+  /** process method, returns a status */
+  virtual int process( Node f, Theory::Effort effort, int e ) = 0;
+  /** identify */
+  virtual std::string identify() const { return std::string("Unknown"); }
+  /** register quantifier */
+  //virtual void registerQuantifier( Node q ) {}
+};/* class InstStrategy */
+
+class InstantiationEngine : public QuantifiersModule {
+ private:
+  /** instantiation strategies */
+  std::vector<InstStrategy*> d_instStrategies;
+  /** user-pattern instantiation strategy */
+  std::unique_ptr<InstStrategyUserPatterns> d_isup;
+  /** auto gen triggers; only kept for destructor cleanup */
+  std::unique_ptr<InstStrategyAutoGenTriggers> d_i_ag;
+
+  typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
+  /** current processing quantified formulas */
+  std::vector<Node> d_quants;
+
+  /** is the engine incomplete for this quantifier */
+  bool isIncomplete(Node q);
+  /** do instantiation round */
+  void doInstantiationRound(Theory::Effort effort);
+
+ public:
+  InstantiationEngine(QuantifiersEngine* qe);
+  ~InstantiationEngine();
+  void presolve();
+  bool needsCheck(Theory::Effort e);
+  void reset_round(Theory::Effort e);
+  void check(Theory::Effort e, QEffort quant_e);
+  bool checkCompleteFor(Node q);
+  void preRegisterQuantifier(Node q);
+  void registerQuantifier(Node q);
+  Node explain(TNode n) { return Node::null(); }
+  /** add user pattern */
+  void addUserPattern(Node q, Node pat);
+  void addUserNoPattern(Node q, Node pat);
+  /** Identify this module */
+  std::string identify() const { return "InstEngine"; }
+}; /* class InstantiationEngine */
+
+}/* CVC4::theory::quantifiers namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__INSTANTIATION_ENGINE_H */
diff --git a/src/theory/quantifiers/ematching/trigger.cpp b/src/theory/quantifiers/ematching/trigger.cpp
new file mode 100644 (file)
index 0000000..b73c336
--- /dev/null
@@ -0,0 +1,969 @@
+/*********************                                                        */
+/*! \file trigger.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Morgan Deters, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of trigger class
+ **/
+
+#include "theory/quantifiers/ematching/trigger.h"
+
+#include "theory/arith/arith_msum.h"
+#include "theory/quantifiers/candidate_generator.h"
+#include "theory/quantifiers/ematching/ho_trigger.h"
+#include "theory/quantifiers/ematching/inst_match_generator.h"
+#include "theory/quantifiers/instantiate.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/theory_engine.h"
+#include "theory/uf/equality_engine.h"
+#include "util/hash.h"
+
+using namespace std;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+
+namespace CVC4 {
+namespace theory {
+namespace inst {
+
+void TriggerTermInfo::init( Node q, Node n, int reqPol, Node reqPolEq ){
+  if( d_fv.empty() ){
+    quantifiers::TermUtil::getVarContainsNode( q, n, d_fv );
+  }
+  if( d_reqPol==0 ){
+    d_reqPol = reqPol;
+    d_reqPolEq = reqPolEq;
+  }else{
+    //determined a ground (dis)equality must hold or else q is a tautology?
+  }
+  d_weight = Trigger::getTriggerWeight(n);
+}
+
+/** trigger class constructor */
+Trigger::Trigger(QuantifiersEngine* qe, Node q, std::vector<Node>& nodes)
+    : d_quantEngine(qe), d_quant(q)
+{
+  d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() );
+  Trace("trigger") << "Trigger for " << q << ": " << std::endl;
+  for( unsigned i=0; i<d_nodes.size(); i++ ){
+    Trace("trigger") << "   " << d_nodes[i] << std::endl;
+  }
+  if( d_nodes.size()==1 ){
+    if( isSimpleTrigger( d_nodes[0] ) ){
+      d_mg = new InstMatchGeneratorSimple(q, d_nodes[0], qe);
+    }else{
+      d_mg = InstMatchGenerator::mkInstMatchGenerator(q, d_nodes[0], qe);
+    }
+  }else{
+    if( options::multiTriggerCache() ){
+      d_mg = new InstMatchGeneratorMulti(q, d_nodes, qe);
+    }else{
+      d_mg = InstMatchGenerator::mkInstMatchGeneratorMulti(q, d_nodes, qe);
+    }
+  }
+  if( d_nodes.size()==1 ){
+    if( isSimpleTrigger( d_nodes[0] ) ){
+      ++(qe->d_statistics.d_triggers);
+    }else{
+      ++(qe->d_statistics.d_simple_triggers);
+    }
+  }else{
+    Trace("multi-trigger") << "Trigger for " << q << ": " << std::endl;
+    for( unsigned i=0; i<d_nodes.size(); i++ ){
+      Trace("multi-trigger") << "   " << d_nodes[i] << std::endl;
+    }
+    ++(qe->d_statistics.d_multi_triggers);
+  }
+
+  // Notice() << "Trigger : " << (*this) << "  for " << q << std::endl;
+  Trace("trigger-debug") << "Finished making trigger." << std::endl;
+}
+
+Trigger::~Trigger() {
+  delete d_mg;
+}
+
+void Trigger::resetInstantiationRound(){
+  d_mg->resetInstantiationRound( d_quantEngine );
+}
+
+void Trigger::reset( Node eqc ){
+  d_mg->reset( eqc, d_quantEngine );
+}
+
+Node Trigger::getInstPattern(){
+  return NodeManager::currentNM()->mkNode( INST_PATTERN, d_nodes );
+}
+
+int Trigger::addInstantiations()
+{
+  int addedLemmas = d_mg->addInstantiations(d_quant, d_quantEngine, this);
+  if( addedLemmas>0 ){
+    if (Debug.isOn("inst-trigger"))
+    {
+      Debug("inst-trigger") << "Added " << addedLemmas
+                            << " lemmas, trigger was ";
+      for (unsigned i = 0; i < d_nodes.size(); i++)
+      {
+        Debug("inst-trigger") << d_nodes[i] << " ";
+      }
+      Debug("inst-trigger") << std::endl;
+    }
+  }
+  return addedLemmas;
+}
+
+bool Trigger::sendInstantiation(InstMatch& m)
+{
+  return d_quantEngine->getInstantiate()->addInstantiation(d_quant, m);
+}
+
+bool Trigger::mkTriggerTerms( Node q, std::vector< Node >& nodes, unsigned n_vars, std::vector< Node >& trNodes ) {
+  //only take nodes that contribute variables to the trigger when added
+  std::vector< Node > temp;
+  temp.insert( temp.begin(), nodes.begin(), nodes.end() );
+  std::map< Node, bool > vars;
+  std::map< Node, std::vector< Node > > patterns;
+  size_t varCount = 0;
+  std::map< Node, std::vector< Node > > varContains;
+  quantifiers::TermUtil::getVarContains( q, temp, varContains );
+  for( unsigned i=0; i<temp.size(); i++ ){
+    bool foundVar = false;
+    for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){
+      Node v = varContains[ temp[i] ][j];
+      Assert( quantifiers::TermUtil::getInstConstAttr(v)==q );
+      if( vars.find( v )==vars.end() ){
+        varCount++;
+        vars[ v ] = true;
+        foundVar = true;
+      }
+    }
+    if( foundVar ){
+      trNodes.push_back( temp[i] );
+      for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){
+        Node v = varContains[ temp[i] ][j];
+        patterns[ v ].push_back( temp[i] );
+      }
+    }
+    if( varCount==n_vars ){
+      break;
+    }
+  }
+  if( varCount<n_vars ){
+    Trace("trigger-debug") << "Don't consider trigger since it does not contain specified number of variables." << std::endl;
+    for( unsigned i=0; i<nodes.size(); i++) {
+      Trace("trigger-debug") << nodes[i] << " ";
+    }
+    Trace("trigger-debug") << std::endl;
+
+    //do not generate multi-trigger if it does not contain all variables
+    return false;
+  }else{
+    //now, minimize the trigger
+    for( unsigned i=0; i<trNodes.size(); i++ ){
+      bool keepPattern = false;
+      Node n = trNodes[i];
+      for( unsigned j=0; j<varContains[ n ].size(); j++ ){
+        Node v = varContains[ n ][j];
+        if( patterns[v].size()==1 ){
+          keepPattern = true;
+          break;
+        }
+      }
+      if( !keepPattern ){
+        //remove from pattern vector
+        for( unsigned j=0; j<varContains[ n ].size(); j++ ){
+          Node v = varContains[ n ][j];
+          for( unsigned k=0; k<patterns[v].size(); k++ ){
+            if( patterns[v][k]==n ){
+              patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 );
+              break;
+            }
+          }
+        }
+        //remove from trigger nodes
+        trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 );
+        i--;
+      }
+    }
+  }
+  return true;
+}
+
+Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, bool keepAll, int trOption, unsigned use_n_vars ){
+  std::vector< Node > trNodes;
+  if( !keepAll ){
+    unsigned n_vars = use_n_vars==0 ? f[0].getNumChildren() : use_n_vars;
+    if( !mkTriggerTerms( f, nodes, n_vars, trNodes ) ){
+      return NULL;
+    }
+  }else{
+    trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() );
+  }
+
+  //check for duplicate?
+  if( trOption!=TR_MAKE_NEW ){
+    Trigger* t = qe->getTriggerDatabase()->getTrigger( trNodes );
+    if( t ){
+      if( trOption==TR_GET_OLD ){
+        //just return old trigger
+        return t;
+      }else{
+        return NULL;
+      }
+    }
+  }
+
+  // check if higher-order
+  Trace("trigger-debug") << "Collect higher-order variable triggers..."
+                         << std::endl;
+  std::map<Node, std::vector<Node> > ho_apps;
+  HigherOrderTrigger::collectHoVarApplyTerms(f, trNodes, ho_apps);
+  Trace("trigger") << "...got " << ho_apps.size()
+                   << " higher-order applications." << std::endl;
+  Trigger* t;
+  if (!ho_apps.empty())
+  {
+    t = new HigherOrderTrigger(qe, f, trNodes, ho_apps);
+  }
+  else
+  {
+    t = new Trigger(qe, f, trNodes);
+  }
+
+  qe->getTriggerDatabase()->addTrigger( trNodes, t );
+  return t;
+}
+
+Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, bool keepAll, int trOption, unsigned use_n_vars ){
+  std::vector< Node > nodes;
+  nodes.push_back( n );
+  return mkTrigger( qe, f, nodes, keepAll, trOption, use_n_vars );
+}
+
+bool Trigger::isUsable( Node n, Node q ){
+  if( quantifiers::TermUtil::getInstConstAttr(n)==q ){
+    if( isAtomicTrigger( n ) ){
+      for( unsigned i=0; i<n.getNumChildren(); i++ ){
+        if( !isUsable( n[i], q ) ){
+          return false;
+        }
+      }
+      return true;
+    }else if( n.getKind()==INST_CONSTANT ){
+      return true;
+    }else{
+      std::map< Node, Node > coeffs;
+      if( isBooleanTermTrigger( n ) ){
+        return true;
+      }else if( options::purifyTriggers() ){
+        Node x = getInversionVariable( n );
+        if( !x.isNull() ){
+          return true;
+        }
+      }
+    }
+    return false;
+  }else{
+    return true;
+  }
+}
+
+Node Trigger::getIsUsableEq( Node q, Node n ) {
+  Assert( isRelationalTrigger( n ) );
+  for( unsigned i=0; i<2; i++) {
+    if( isUsableEqTerms( q, n[i], n[1-i] ) ){
+      if( i==1 && n.getKind()==EQUAL && !quantifiers::TermUtil::hasInstConstAttr(n[0]) ){
+        return NodeManager::currentNM()->mkNode( n.getKind(), n[1], n[0] );  
+      }else{
+        return n;
+      }
+    }
+  }
+  return Node::null();
+}
+
+bool Trigger::isUsableEqTerms( Node q, Node n1, Node n2 ) {
+  if( n1.getKind()==INST_CONSTANT ){
+    if( options::relationalTriggers() ){
+      if( !quantifiers::TermUtil::hasInstConstAttr(n2) ){
+        return true;
+      }else if( n2.getKind()==INST_CONSTANT ){
+        return true;
+      }
+    }
+  }else if( isUsableAtomicTrigger( n1, q ) ){
+    if( options::relationalTriggers() && n2.getKind()==INST_CONSTANT && !quantifiers::TermUtil::containsTerm( n1, n2 ) ){
+      return true;
+    }else if( !quantifiers::TermUtil::hasInstConstAttr(n2) ){
+      return true;
+    }
+  }
+  return false;
+}
+
+Node Trigger::getIsUsableTrigger( Node n, Node q ) {
+  bool pol = true;
+  Trace("trigger-debug") << "Is " << n << " a usable trigger?" << std::endl;
+  if( n.getKind()==NOT ){
+    pol = !pol;
+    n = n[0];
+  }
+  if( n.getKind()==INST_CONSTANT ){
+    return pol ? n : NodeManager::currentNM()->mkNode( EQUAL, n, NodeManager::currentNM()->mkConst( true ) ).notNode();
+  }else if( isRelationalTrigger( n ) ){
+    Node rtr = getIsUsableEq( q, n );
+    if( rtr.isNull() && n[0].getType().isReal() ){
+      //try to solve relation
+      std::map< Node, Node > m;
+      if (ArithMSum::getMonomialSumLit(n, m))
+      {
+        for( std::map< Node, Node >::iterator it = m.begin(); it!=m.end(); ++it ){
+          bool trySolve = false;
+          if( !it->first.isNull() ){
+            if( it->first.getKind()==INST_CONSTANT ){
+              trySolve = options::relationalTriggers();
+            }else if( isUsableTrigger( it->first, q ) ){
+              trySolve = true;
+            }
+          }
+          if( trySolve ){
+            Trace("trigger-debug") << "Try to solve for " << it->first << std::endl;
+            Node veq;
+            if (ArithMSum::isolate(it->first, m, veq, n.getKind()) != 0)
+            {
+              rtr = getIsUsableEq( q, veq );
+            }
+            //either all solves will succeed or all solves will fail
+            break;
+          }
+        }
+      }
+    }
+    if( !rtr.isNull() ){
+      Trace("relational-trigger") << "Relational trigger : " << std::endl;
+      Trace("relational-trigger") << "    " << rtr << " (from " << n << ")" << std::endl;
+      Trace("relational-trigger") << "    in quantifier " << q << std::endl;
+      Node rtr2 = pol ? rtr : rtr.negate();
+      Trace("relational-trigger") << "    return : " << rtr2 << std::endl;
+      return rtr2;
+    }
+  }else{
+    Trace("trigger-debug") << n << " usable : " << ( quantifiers::TermUtil::getInstConstAttr(n)==q ) << " " << isAtomicTrigger( n ) << " " << isUsable( n, q ) << std::endl;
+    if( isUsableAtomicTrigger( n, q ) ){
+      return pol ? n : NodeManager::currentNM()->mkNode( EQUAL, n, NodeManager::currentNM()->mkConst( true ) ).notNode();
+    }
+  }
+  return Node::null();
+}
+
+bool Trigger::isUsableAtomicTrigger( Node n, Node q ) {
+  return quantifiers::TermUtil::getInstConstAttr( n )==q && isAtomicTrigger( n ) && isUsable( n, q );
+}
+
+bool Trigger::isUsableTrigger( Node n, Node q ){
+  Node nu = getIsUsableTrigger( n, q );
+  return !nu.isNull();
+}
+
+bool Trigger::isAtomicTrigger( Node n ){
+  return isAtomicTriggerKind( n.getKind() );
+}
+
+bool Trigger::isAtomicTriggerKind( Kind k ) {
+  return k == APPLY_UF || k == SELECT || k == STORE || k == APPLY_CONSTRUCTOR
+         || k == APPLY_SELECTOR_TOTAL || k == APPLY_TESTER || k == UNION
+         || k == INTERSECTION || k == SUBSET || k == SETMINUS || k == MEMBER
+         || k == SINGLETON || k == SEP_PTO || k == BITVECTOR_TO_NAT
+         || k == INT_TO_BITVECTOR || k == HO_APPLY;
+}
+
+bool Trigger::isRelationalTrigger( Node n ) {
+  return isRelationalTriggerKind( n.getKind() );
+}
+
+bool Trigger::isRelationalTriggerKind( Kind k ) {
+  return k==EQUAL || k==GEQ;
+}
+  
+bool Trigger::isCbqiKind( Kind k ) {
+  if( quantifiers::TermUtil::isBoolConnective( k ) || k==PLUS || k==GEQ || k==EQUAL || k==MULT ){
+    return true;
+  }else{
+    //CBQI typically works for satisfaction-complete theories
+    TheoryId t = kindToTheoryId( k );
+    return t == THEORY_BV || t == THEORY_DATATYPES || t == THEORY_BOOL;
+  }
+}
+
+bool Trigger::isSimpleTrigger( Node n ){
+  Node t = n.getKind()==NOT ? n[0] : n;
+  if( t.getKind()==EQUAL ){
+    if( !quantifiers::TermUtil::hasInstConstAttr( t[1] ) ){
+      t = t[0];
+    }
+  }
+  if( isAtomicTrigger( t ) ){
+    for( unsigned i=0; i<t.getNumChildren(); i++ ){
+      if( t[i].getKind()!=INST_CONSTANT && quantifiers::TermUtil::hasInstConstAttr(t[i]) ){
+        return false;
+      }
+    }
+    if( options::purifyDtTriggers() && t.getKind()==APPLY_SELECTOR_TOTAL ){
+      return false;
+    }
+    if (t.getKind() == HO_APPLY && t[0].getKind() == INST_CONSTANT)
+    {
+      return false;
+    }
+    return true;
+  }else{
+    return false;
+  }
+}
+
+//store triggers in reqPol, indicating their polarity (if any) they must appear to falsify the quantified formula
+void Trigger::collectPatTerms2( Node q, Node n, std::map< Node, std::vector< Node > >& visited, std::map< Node, TriggerTermInfo >& tinfo, 
+                                quantifiers::TriggerSelMode tstrt, std::vector< Node >& exclude, std::vector< Node >& added,
+                                bool pol, bool hasPol, bool epol, bool hasEPol, bool knowIsUsable ){
+  std::map< Node, std::vector< Node > >::iterator itv = visited.find( n );
+  if( itv==visited.end() ){
+    visited[ n ].clear();
+    Trace("auto-gen-trigger-debug2") << "Collect pat terms " << n << " " << pol << " " << hasPol << " " << epol << " " << hasEPol << std::endl;
+    if( n.getKind()!=FORALL && n.getKind()!=INST_CONSTANT ){
+      Node nu;
+      bool nu_single = false;
+      if( knowIsUsable ){
+        nu = n;
+      }else if( n.getKind()!=NOT && std::find( exclude.begin(), exclude.end(), n )==exclude.end() ){
+        nu = getIsUsableTrigger( n, q );
+        if( !nu.isNull() && nu!=n ){
+          collectPatTerms2( q, nu, visited, tinfo, tstrt, exclude, added, pol, hasPol, epol, hasEPol, true );
+          // copy to n
+          visited[n].insert( visited[n].end(), added.begin(), added.end() );
+          return;
+        }
+      }
+      if( !nu.isNull() ){
+        Assert( nu==n );
+        Assert( nu.getKind()!=NOT );
+        Trace("auto-gen-trigger-debug2") << "...found usable trigger : " << nu << std::endl;
+        Node reqEq;
+        if( nu.getKind()==EQUAL ){
+          if( isAtomicTrigger( nu[0] ) && !quantifiers::TermUtil::hasInstConstAttr(nu[1]) ){
+            if( hasPol ){
+              reqEq = nu[1];
+            }
+            nu = nu[0];
+          }
+        }
+        Assert( reqEq.isNull() || !quantifiers::TermUtil::hasInstConstAttr( reqEq ) );
+        Assert( isUsableTrigger( nu, q ) );
+        //tinfo.find( nu )==tinfo.end()
+        Trace("auto-gen-trigger-debug2") << "...add usable trigger : " << nu << std::endl;
+        tinfo[ nu ].init( q, nu, hasEPol ? ( epol ? 1 : -1 ) : 0, reqEq );
+        nu_single = tinfo[ nu ].d_fv.size()==q[0].getNumChildren();
+      }
+      Node nrec = nu.isNull() ? n : nu;
+      std::vector< Node > added2;
+      for( unsigned i=0; i<nrec.getNumChildren(); i++ ){
+        bool newHasPol, newPol;
+        bool newHasEPol, newEPol;
+        QuantPhaseReq::getPolarity( nrec, i, hasPol, pol, newHasPol, newPol );
+        QuantPhaseReq::getEntailPolarity( nrec, i, hasEPol, epol, newHasEPol, newEPol );
+        collectPatTerms2( q, nrec[i], visited, tinfo, tstrt, exclude, added2, newPol, newHasPol, newEPol, newHasEPol );
+      }
+      // if this is not a usable trigger, don't worry about caching the results, since triggers do not contain non-usable subterms
+      if( !nu.isNull() ){
+        bool rm_nu = false;
+        for( unsigned i=0; i<added2.size(); i++ ){
+          Trace("auto-gen-trigger-debug2") << "..." << nu << " added child " << i << " : " << added2[i] << std::endl;
+          Assert( added2[i]!=nu );
+          // if child was not already removed
+          if( tinfo.find( added2[i] )!=tinfo.end() ){
+            if( tstrt==quantifiers::TRIGGER_SEL_MAX || ( tstrt==quantifiers::TRIGGER_SEL_MIN_SINGLE_MAX && !nu_single ) ){
+              //discard all subterms
+              Trace("auto-gen-trigger-debug2") << "......remove it." << std::endl;
+              visited[ added2[i] ].clear();
+              tinfo.erase( added2[i] );
+            }else{
+              if( tinfo[ nu ].d_fv.size()==tinfo[ added2[i] ].d_fv.size() ){
+                if (tinfo[nu].d_weight >= tinfo[added2[i]].d_weight)
+                {
+                  // discard if we added a subterm as a trigger with all
+                  // variables that nu has
+                  Trace("auto-gen-trigger-debug2")
+                      << "......subsumes parent " << tinfo[nu].d_weight << " "
+                      << tinfo[added2[i]].d_weight << "." << std::endl;
+                  rm_nu = true;
+                }
+              }
+              if( std::find( added.begin(), added.end(), added2[i] )==added.end() ){
+                added.push_back( added2[i] );
+              }
+            }
+          }
+        }
+        if( rm_nu && ( tstrt==quantifiers::TRIGGER_SEL_MIN || ( tstrt==quantifiers::TRIGGER_SEL_MIN_SINGLE_ALL && nu_single ) ) ){
+          tinfo.erase( nu );
+        }else{
+          if( std::find( added.begin(), added.end(), nu )==added.end() ){
+            added.push_back( nu );
+          }
+        }
+        visited[n].insert( visited[n].end(), added.begin(), added.end() );
+      }
+    }
+  }else{
+    for( unsigned i=0; i<itv->second.size(); ++i ){
+      Node t = itv->second[i];
+      if( std::find( added.begin(), added.end(), t )==added.end() ){
+        added.push_back( t );
+      }
+    }
+  }
+}
+
+bool Trigger::isBooleanTermTrigger( Node n ) {
+  if( n.getKind()==ITE ){
+    //check for boolean term converted to ITE
+    if( n[0].getKind()==INST_CONSTANT &&
+        n[1].getKind()==CONST_BITVECTOR &&
+        n[2].getKind()==CONST_BITVECTOR ){
+      if( ((BitVectorType)n[1].getType().toType()).getSize()==1 &&
+          n[1].getConst<BitVector>().toInteger()==1 &&
+          n[2].getConst<BitVector>().toInteger()==0 ){
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool Trigger::isPureTheoryTrigger( Node n ) {
+  if( n.getKind()==APPLY_UF || n.getKind()==VARIABLE || n.getKind()==SKOLEM ){  //|| !quantifiers::TermUtil::hasInstConstAttr( n ) ){
+    return false;
+  }else{
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      if( !isPureTheoryTrigger( n[i] ) ){
+        return false;
+      }
+    }
+    return true;
+  }
+}
+
+int Trigger::getTriggerWeight( Node n ) {
+  if (n.getKind() == APPLY_UF)
+  {
+    return 0;
+  }
+  else if (isAtomicTrigger(n))
+  {
+    return 1;
+  }else{
+    if( options::relationalTriggers() ){
+      if( isRelationalTrigger( n ) ){
+        for( unsigned i=0; i<2; i++ ){
+          if( n[i].getKind()==INST_CONSTANT && !quantifiers::TermUtil::hasInstConstAttr( n[1-i] ) ){
+            return 0;
+          }
+        }
+      }
+    }
+    return 2;
+  }
+}
+
+bool Trigger::isLocalTheoryExt( Node n, std::vector< Node >& vars, std::vector< Node >& patTerms ) {
+  if( !n.getType().isBoolean() && n.getKind()==APPLY_UF ){
+    if( std::find( patTerms.begin(), patTerms.end(), n )==patTerms.end() ){
+      bool hasVar = false;
+      for( unsigned i=0; i<n.getNumChildren(); i++ ){
+        if( n[i].getKind()==INST_CONSTANT ){
+          hasVar = true;
+          if( std::find( vars.begin(), vars.end(), n[i] )==vars.end() ){
+            vars.push_back( n[i] );
+          }else{
+            //do not allow duplicate variables
+            return false;
+          }
+        }else{
+          //do not allow nested function applications
+          return false;
+        }
+      }
+      if( hasVar ){
+        patTerms.push_back( n );
+      }
+    }
+  }else{
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      if( !isLocalTheoryExt( n[i], vars, patTerms ) ){
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+void Trigger::collectPatTerms( Node q, Node n, std::vector< Node >& patTerms, quantifiers::TriggerSelMode tstrt, std::vector< Node >& exclude, 
+                               std::map< Node, TriggerTermInfo >& tinfo, bool filterInst ){
+  std::map< Node, std::vector< Node > > visited;
+  if( filterInst ){
+    //immediately do not consider any term t for which another term is an instance of t
+    std::vector< Node > patTerms2;
+    std::map< Node, TriggerTermInfo > tinfo2;
+    collectPatTerms( q, n, patTerms2, quantifiers::TRIGGER_SEL_ALL, exclude, tinfo2, false );
+    std::vector< Node > temp;
+    temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() );
+    filterTriggerInstances(temp);
+    if (Trace.isOn("trigger-filter-instance"))
+    {
+      if (temp.size() != patTerms2.size())
+      {
+        Trace("trigger-filter-instance") << "Filtered an instance: "
+                                         << std::endl;
+        Trace("trigger-filter-instance") << "Old: ";
+        for (unsigned i = 0; i < patTerms2.size(); i++)
+        {
+          Trace("trigger-filter-instance") << patTerms2[i] << " ";
+        }
+        Trace("trigger-filter-instance") << std::endl << "New: ";
+        for (unsigned i = 0; i < temp.size(); i++)
+        {
+          Trace("trigger-filter-instance") << temp[i] << " ";
+        }
+        Trace("trigger-filter-instance") << std::endl;
+      }
+    }
+    if( tstrt==quantifiers::TRIGGER_SEL_ALL ){
+      for( unsigned i=0; i<temp.size(); i++ ){
+        //copy information
+        tinfo[temp[i]].d_fv.insert( tinfo[temp[i]].d_fv.end(), tinfo2[temp[i]].d_fv.begin(), tinfo2[temp[i]].d_fv.end() );
+        tinfo[temp[i]].d_reqPol = tinfo2[temp[i]].d_reqPol;
+        tinfo[temp[i]].d_reqPolEq = tinfo2[temp[i]].d_reqPolEq;
+        patTerms.push_back( temp[i] );
+      }
+      return;
+    }else{
+      //do not consider terms that have instances
+      for( unsigned i=0; i<patTerms2.size(); i++ ){
+        if( std::find( temp.begin(), temp.end(), patTerms2[i] )==temp.end() ){
+          visited[ patTerms2[i] ].clear();
+        }
+      }
+    }
+  }
+  std::vector< Node > added;
+  collectPatTerms2( q, n, visited, tinfo, tstrt, exclude, added, true, true, false, true );
+  for( std::map< Node, TriggerTermInfo >::iterator it = tinfo.begin(); it != tinfo.end(); ++it ){
+    patTerms.push_back( it->first );
+  }
+}
+
+int Trigger::isTriggerInstanceOf(Node n1,
+                                 Node n2,
+                                 std::vector<Node>& fv1,
+                                 std::vector<Node>& fv2)
+{
+  Assert(n1 != n2);
+  int status = 0;
+  std::unordered_set<TNode, TNodeHashFunction> subs_vars;
+  std::unordered_set<std::pair<TNode, TNode>,
+                     PairHashFunction<TNode,
+                                      TNode,
+                                      TNodeHashFunction,
+                                      TNodeHashFunction> >
+      visited;
+  std::vector<std::pair<TNode, TNode> > visit;
+  std::pair<TNode, TNode> cur;
+  TNode cur1;
+  TNode cur2;
+  visit.push_back(std::pair<TNode, TNode>(n1, n2));
+  do
+  {
+    cur = visit.back();
+    visit.pop_back();
+    if (visited.find(cur) == visited.end())
+    {
+      visited.insert(cur);
+      cur1 = cur.first;
+      cur2 = cur.second;
+      Assert(cur1 != cur2);
+      // recurse if they have the same operator
+      if (cur1.hasOperator() && cur2.hasOperator()
+          && cur1.getNumChildren() == cur2.getNumChildren()
+          && cur1.getOperator() == cur2.getOperator()
+          && cur1.getOperator().getKind()!=INST_CONSTANT)
+      {
+        visit.push_back(std::pair<TNode, TNode>(cur1, cur2));
+        for (unsigned i = 0, size = cur1.getNumChildren(); i < size; i++)
+        {
+          if (cur1[i] != cur2[i])
+          {
+            visit.push_back(std::pair<TNode, TNode>(cur1[i], cur2[i]));
+          }
+          else if (cur1[i].getKind() == INST_CONSTANT)
+          {
+            if (subs_vars.find(cur1[i]) != subs_vars.end())
+            {
+              return 0;
+            }
+            // the variable must map to itself in the substitution
+            subs_vars.insert(cur1[i]);
+          }
+        }
+      }
+      else
+      {
+        bool success = false;
+        // check if we are in a unifiable instance case
+        // must be only this case
+        for (unsigned r = 0; r < 2; r++)
+        {
+          if (status == 0 || ((status == 1) == (r == 0)))
+          {
+            TNode curi = r == 0 ? cur1 : cur2;
+            if (curi.getKind() == INST_CONSTANT
+                && subs_vars.find(curi) == subs_vars.end())
+            {
+              TNode curj = r == 0 ? cur2 : cur1;
+              // RHS must be a simple trigger
+              if (getTriggerWeight(curj) == 0)
+              {
+                // must occur in the free variables in the other
+                std::vector<Node>& free_vars = r == 0 ? fv2 : fv1;
+                if (std::find(free_vars.begin(), free_vars.end(), curi)
+                    != free_vars.end())
+                {
+                  status = r == 0 ? 1 : -1;
+                  subs_vars.insert(curi);
+                  success = true;
+                  break;
+                }
+              }
+            }
+          }
+        }
+        if (!success)
+        {
+          return 0;
+        }
+      }
+    }
+  } while (!visit.empty());
+  return status;
+}
+
+void Trigger::filterTriggerInstances(std::vector<Node>& nodes)
+{
+  std::map<unsigned, std::vector<Node> > fvs;
+  for (unsigned i = 0, size = nodes.size(); i < size; i++)
+  {
+    quantifiers::TermUtil::computeVarContains(nodes[i], fvs[i]);
+  }
+  std::vector<bool> active;
+  active.resize(nodes.size(), true);
+  for (unsigned i = 0, size = nodes.size(); i < size; i++)
+  {
+    std::vector<Node>& fvsi = fvs[i];
+    if (active[i])
+    {
+      for (unsigned j = i + 1, size2 = nodes.size(); j < size2; j++)
+      {
+        if (active[j])
+        {
+          int result = isTriggerInstanceOf(nodes[i], nodes[j], fvsi, fvs[j]);
+          if (result == 1)
+          {
+            Trace("filter-instances") << nodes[j] << " is an instance of "
+                                      << nodes[i] << std::endl;
+            active[i] = false;
+            break;
+          }
+          else if (result == -1)
+          {
+            Trace("filter-instances") << nodes[i] << " is an instance of "
+                                      << nodes[j] << std::endl;
+            active[j] = false;
+          }
+        }
+      }
+    }
+  }
+  std::vector<Node> temp;
+  for (unsigned i = 0; i < nodes.size(); i++)
+  {
+    if (active[i])
+    {
+      temp.push_back(nodes[i]);
+    }
+  }
+  nodes.clear();
+  nodes.insert(nodes.begin(), temp.begin(), temp.end());
+}
+
+Node Trigger::getInversionVariable( Node n ) {
+  if( n.getKind()==INST_CONSTANT ){
+    return n;
+  }else if( n.getKind()==PLUS || n.getKind()==MULT ){
+    Node ret;
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      if( quantifiers::TermUtil::hasInstConstAttr(n[i]) ){
+        if( ret.isNull() ){
+          ret = getInversionVariable( n[i] );
+          if( ret.isNull() ){
+            Trace("var-trigger-debug") << "No : multiple variables " << n << std::endl;
+            return Node::null();
+          }
+        }else{
+          return Node::null();
+        }
+      }else if( n.getKind()==MULT ){
+        if( !n[i].isConst() ){
+          Trace("var-trigger-debug") << "No : non-linear coefficient " << n << std::endl;
+          return Node::null();
+        }
+        /*
+        else if( n.getType().isInteger() ){
+          Rational r = n[i].getConst<Rational>();
+          if( r!=Rational(-1) && r!=Rational(1) ){
+            Trace("var-trigger-debug") << "No : not integer coefficient " << n << std::endl;
+            return Node::null();
+          }
+        }
+        */
+      }
+    }
+    return ret;
+  }else{
+    Trace("var-trigger-debug") << "No : unsupported operator " << n << "." << std::endl;
+  }
+  return Node::null();
+}
+
+Node Trigger::getInversion( Node n, Node x ) {
+  if( n.getKind()==INST_CONSTANT ){
+    return x;
+  }else if( n.getKind()==PLUS || n.getKind()==MULT ){
+    int cindex = -1;
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      if( !quantifiers::TermUtil::hasInstConstAttr(n[i]) ){
+        if( n.getKind()==PLUS ){
+          x = NodeManager::currentNM()->mkNode( MINUS, x, n[i] );
+        }else if( n.getKind()==MULT ){
+          Assert( n[i].isConst() );
+          if( x.getType().isInteger() ){
+            Node coeff = NodeManager::currentNM()->mkConst( n[i].getConst<Rational>().abs() );
+            if( !n[i].getConst<Rational>().abs().isOne() ){
+              x = NodeManager::currentNM()->mkNode( INTS_DIVISION_TOTAL, x, coeff );
+            }
+            if( n[i].getConst<Rational>().sgn()<0 ){
+              x = NodeManager::currentNM()->mkNode( UMINUS, x );
+            }
+          }else{
+            Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / n[i].getConst<Rational>() );
+            x = NodeManager::currentNM()->mkNode( MULT, x, coeff );
+          }
+        }
+        x = Rewriter::rewrite( x );
+      }else{
+        Assert( cindex==-1 );
+        cindex = i;
+      }
+    }
+    Assert( cindex!=-1 );
+    return getInversion( n[cindex], x );
+  }
+  return Node::null();
+}
+
+void Trigger::getTriggerVariables(Node n, Node q, std::vector<Node>& t_vars)
+{
+  std::vector< Node > patTerms;
+  std::map< Node, TriggerTermInfo > tinfo;
+  // collect all patterns from n
+  std::vector< Node > exclude;
+  collectPatTerms(q, n, patTerms, quantifiers::TRIGGER_SEL_ALL, exclude, tinfo);
+  //collect all variables from all patterns in patTerms, add to t_vars
+  for( unsigned i=0; i<patTerms.size(); i++ ){
+    quantifiers::TermUtil::getVarContainsNode( q, patTerms[i], t_vars );
+  }
+}
+
+int Trigger::getActiveScore() {
+  return d_mg->getActiveScore( d_quantEngine );
+}
+
+TriggerTrie::TriggerTrie()
+{}
+
+TriggerTrie::~TriggerTrie() {
+  for(std::map< TNode, TriggerTrie* >::iterator i = d_children.begin(), iend = d_children.end();
+      i != iend; ++i) {
+    TriggerTrie* current = (*i).second;
+    delete current;
+  }
+  d_children.clear();
+
+  for( unsigned i=0; i<d_tr.size(); i++ ){
+    delete d_tr[i];
+  }
+}
+
+inst::Trigger* TriggerTrie::getTrigger(std::vector<Node>& nodes)
+{
+  std::vector<Node> temp;
+  temp.insert(temp.begin(), nodes.begin(), nodes.end());
+  std::sort(temp.begin(), temp.end());
+  TriggerTrie* tt = this;
+  for (const Node& n : temp)
+  {
+    std::map<TNode, TriggerTrie*>::iterator itt = tt->d_children.find(n);
+    if (itt == tt->d_children.end())
+    {
+      return NULL;
+    }
+    else
+    {
+      tt = itt->second;
+    }
+  }
+  return tt->d_tr.empty() ? NULL : tt->d_tr[0];
+}
+
+void TriggerTrie::addTrigger(std::vector<Node>& nodes, inst::Trigger* t)
+{
+  std::vector<Node> temp;
+  temp.insert(temp.begin(), nodes.begin(), nodes.end());
+  std::sort(temp.begin(), temp.end());
+  TriggerTrie* tt = this;
+  for (const Node& n : temp)
+  {
+    std::map<TNode, TriggerTrie*>::iterator itt = tt->d_children.find(n);
+    if (itt == tt->d_children.end())
+    {
+      TriggerTrie* ttn = new TriggerTrie;
+      tt->d_children[n] = ttn;
+      tt = ttn;
+    }
+    else
+    {
+      tt = itt->second;
+    }
+  }
+  tt->d_tr.push_back(t);
+}
+
+}/* CVC4::theory::inst namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/ematching/trigger.h b/src/theory/quantifiers/ematching/trigger.h
new file mode 100644 (file)
index 0000000..e91a87e
--- /dev/null
@@ -0,0 +1,476 @@
+/*********************                                                        */
+/*! \file trigger.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Tim King, Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief trigger class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__TRIGGER_H
+#define __CVC4__THEORY__QUANTIFIERS__TRIGGER_H
+
+#include <map>
+
+#include "expr/node.h"
+#include "theory/quantifiers/inst_match.h"
+#include "options/quantifiers_options.h"
+
+namespace CVC4 {
+namespace theory {
+
+class QuantifiersEngine;
+
+namespace inst {
+
+class IMGenerator;
+class InstMatchGenerator;
+
+/** Information about a node used in a trigger.
+*
+* This information includes:
+* 1. the free variables of the node, and
+* 2. information about which terms are useful for matching.
+*
+* As an example, consider the trigger
+*   { f( x ), g( y ), P( y, z ) }
+* for quantified formula
+*   forall xy. ( f( x ) != b => ( P( x, g( y ) ) V P( y, z ) ) )
+*
+* Notice that it is only useful to match f( x ) to f-applications not in the
+* equivalence class of b, and P( y, z ) to P-applications not in the equivalence
+* class of true, as such instances will always be entailed by the ground
+* equalities and disequalities the current context. Entailed instances are
+* typically not helpful, and are discarded in Instantiate::addInstantiation(...)
+* unless the option --no-inst-no-entail is enabled. For more details, see page
+* 10 of "Congruence Closure with Free Variables", Barbosa et al., TACAS 2017.
+*
+* This example is referenced for each of the functions below.
+*/
+class TriggerTermInfo {
+ public:
+  TriggerTermInfo() : d_reqPol(0), d_weight(0) {}
+  ~TriggerTermInfo() {}
+  /** The free variables in the node
+  *
+  * In the trigger term info for f( x ) in the above example, d_fv = { x }
+  * In the trigger term info for g( y ) in the above example, d_fv = { y }
+  * In the trigger term info for P( y, z ) in the above example, d_fv = { y, z }
+  */
+  std::vector<Node> d_fv;
+  /** Required polarity:  1 for equality, -1 for disequality, 0 for none
+  *
+  * In the trigger term info for f( x ) in the above example, d_reqPol = -1
+  * In the trigger term info for g( y ) in the above example, d_reqPol = 0
+  * In the trigger term info for P( y, z ) in the above example,  d_reqPol = 1
+  */
+  int d_reqPol;
+  /** Required polarity equal term
+  *
+  * If d_reqPolEq is not null,
+  *   if d_reqPol = 1, then this trigger term must be matched to terms in the
+  *                    equivalence class of d_reqPolEq,
+  *   if d_reqPol = -1, then this trigger term must be matched to terms *not* in
+  *                     the equivalence class of d_reqPolEq.
+  *
+  * This information is typically chosen by analyzing the entailed equalities
+  * and disequalities of quantified formulas.
+  * In the trigger term info for f( x ) in the above example, d_reqPolEq = b
+  * In the trigger term info for g( y ) in the above example,
+  *   d_reqPolEq = Node::null()
+  * In the trigger term info for P( y, z ) in the above example,
+  *   d_reqPolEq = false
+  */
+  Node d_reqPolEq;
+  /** the weight of the trigger (see Trigger::getTriggerWeight). */
+  int d_weight;
+  /** Initialize this information class (can be called more than once).
+  * q is the quantified formula that n is a trigger term for
+  * n is the trigger term
+  * reqPol/reqPolEq are described above
+  */
+  void init(Node q, Node n, int reqPol = 0, Node reqPolEq = Node::null());
+};
+
+/** A collection of nodes representing a trigger.
+*
+* This class encapsulates all implementations of E-matching in CVC4.
+* Its primary use is as a utility of the quantifiers module InstantiationEngine
+* (see theory/quantifiers/ematching/instantiation_engine.h) which uses Trigger to make
+* appropriate calls to Instantiate::addInstantiation(...)
+* (see theory/instantiate.h) for the instantiate utility of the quantifiers
+* engine (d_quantEngine) associated with this trigger.  These calls
+* queue instantiation lemmas to the output channel of TheoryQuantifiers during
+* a full effort check.
+*
+* Concretely, a Trigger* t is used in the following way during a full effort
+* check. Assume that t is associated with quantified formula q (see field d_f).
+* We call :
+*
+* // setup initial information
+* t->resetInstantiationRound();
+* // will produce instantiations based on matching with all terms
+* t->reset( Node::null() );
+* // add all instantiations based on E-matching with this trigger and the
+* // current context
+* t->addInstantiations();
+*
+* This will result in (a set of) calls to
+* Instantiate::addInstantiation(q, m1)...Instantiate::addInstantiation(q, mn),
+* where m1...mn are InstMatch objects. These calls add the corresponding
+* instantiation lemma for (q,mi) on the output channel associated with
+* d_quantEngine.
+*
+* The Trigger class is wrapper around an underlying IMGenerator class, which
+* implements various forms of E-matching for its set of nodes (d_nodes), which
+* is refered to in the literature as a "trigger". A trigger is a set of terms
+* whose free variables are the bound variables of a quantified formula q,
+* and that is used to guide instantiations for q (for example, see "Efficient
+* E-Matching for SMT Solvers" by de Moura et al).
+*
+* For example of an instantiation lemma produced by E-matching :
+*
+* quantified formula : forall x. P( x )
+*            trigger : P( x )
+*     ground context : ~P( a )
+*
+* Then E-matching matches P( x ) and P( a ), resulting in the match { x -> a }
+* which is used to generate the instantiation lemma :
+*   (forall x. P( x )) => P( a )
+*
+* Terms that are provided as input to a Trigger class via mkTrigger
+* should be in "instantiation constant form", see TermUtil::getInstConstantNode.
+* Say we have quantified formula q whose AST is the Node
+*   (FORALL
+*     (BOUND_VAR_LIST x)
+*     (NOT (P x))
+*     (INST_PATTERN_LIST (INST_PATTERN (P x))))
+* then TermUtil::getInstConstantNode( q, (P x) ) = (P IC) where
+* IC = TermUtil::getInstantiationConstant( q, i ).
+* Trigger expects as input (P IC) to represent the Trigger (P x). This form
+* ensures that references to bound variables are unique to quantified formulas,
+* which is required to ensure the correctness of instantiation lemmas we
+* generate.
+*
+*/
+class Trigger {
+  friend class IMGenerator;
+
+ public:
+  virtual ~Trigger();
+  /** get the generator associated with this trigger */
+  IMGenerator* getGenerator() { return d_mg; }
+  /** Reset instantiation round.
+   *
+  * Called once at beginning of an instantiation round.
+  */
+  void resetInstantiationRound();
+  /** Reset the trigger.
+   *
+  * eqc is the equivalence class from which to match ground terms. If eqc is
+  * Node::null(), then we match ground terms from all equivalence classes.
+  */
+  void reset( Node eqc );
+  /** add all available instantiations, based on the current context
+  *
+  * This function makes the appropriate calls to d_qe->addInstantiation(...)
+  * based on the current ground terms and equalities in the current context,
+  * via queries to functions in d_qe. This calls the addInstantiations function
+  * of the underlying match generator. It can be extended to
+  * produce instantiations beyond what is produced by the match generator
+  * (for example, see theory/quantifiers/ematching/ho_trigger.h).
+  */
+  virtual int addInstantiations();
+  /** Return whether this is a multi-trigger. */
+  bool isMultiTrigger() { return d_nodes.size()>1; }
+  /** Get instantiation pattern list associated with this trigger.
+   *
+  * An instantiation pattern list is the node representation of a trigger, in
+  * particular, it is the third argument of quantified formulas which have user
+  * (! ... :pattern) attributes.
+  */
+  Node getInstPattern();
+  /* A heuristic value indicating how active this generator is.
+   *
+  * This returns the number of ground terms for the match operators in terms
+  * from d_nodes. This score is only used with the experimental option
+  *   --trigger-active-sel.
+  */
+  int getActiveScore();
+  /** print debug information for the trigger */
+  void debugPrint(const char* c)
+  {
+    Trace(c) << "TRIGGER( ";
+    for (int i = 0; i < (int)d_nodes.size(); i++)
+    {
+      if (i > 0)
+      {
+        Trace(c) << ", ";
+      }
+      Trace(c) << d_nodes[i];
+    }
+    Trace(c) << " )";
+  }
+  /** mkTrigger method
+   *
+   * This makes an instance of a trigger object.
+   *  qe     : pointer to the quantifier engine;
+   *  q      : the quantified formula we are making a trigger for
+   *  nodes  : the nodes comprising the (multi-)trigger
+   *  keepAll: don't remove unneeded patterns;
+   *  trOption : policy for dealing with triggers that already exist
+   *             (see below)
+   *  use_n_vars : number of variables that should be bound by the trigger
+   *               typically, the number of quantified variables in q.
+   */
+  enum{
+    TR_MAKE_NEW,    //make new trigger even if it already may exist
+    TR_GET_OLD,     //return a previous trigger if it had already been created
+    TR_RETURN_NULL  //return null if a duplicate is found
+  };
+  static Trigger* mkTrigger(QuantifiersEngine* qe,
+                            Node q,
+                            std::vector<Node>& nodes,
+                            bool keepAll = true,
+                            int trOption = TR_MAKE_NEW,
+                            unsigned use_n_vars = 0);
+  /** single trigger version that calls the above function */
+  static Trigger* mkTrigger(QuantifiersEngine* qe,
+                            Node q,
+                            Node n,
+                            bool keepAll = true,
+                            int trOption = TR_MAKE_NEW,
+                            unsigned use_n_vars = 0);
+  /** make trigger terms
+   *
+   * This takes a set of eligible trigger terms and stores a subset of them in
+   * trNodes, such that :
+   *   (1) the terms in trNodes contain at least n_vars of the quantified
+   *       variables in quantified formula q, and
+   *   (2) the set trNodes is minimal, i.e. removing one term from trNodes
+   *       always violates (1).
+   */
+  static bool mkTriggerTerms(Node q,
+                             std::vector<Node>& nodes,
+                             unsigned n_vars,
+                             std::vector<Node>& trNodes);
+  /** collect pattern terms
+   *
+   * This collects all terms that are eligible for triggers for quantified
+   * formula q in term n and adds them to patTerms.
+   *   tstrt : the selection strategy (see options/quantifiers_mode.h),
+   *   exclude :  a set of terms that *cannot* be selected as triggers,
+   *   tinfo : stores the result of the collection, mapping terms to the
+   *           information they are associated with,
+   *   filterInst : flag that when true, we discard terms that have instances
+   *     in the vector we are returning, e.g. we do not return f( x ) if we are
+   *     also returning f( f( x ) ). TODO: revisit this (issue #1211)
+   */
+  static void collectPatTerms( Node q, Node n, std::vector< Node >& patTerms, quantifiers::TriggerSelMode tstrt,
+                               std::vector< Node >& exclude, std::map< Node, TriggerTermInfo >& tinfo,
+                               bool filterInst = false );
+
+  /** Is n a usable trigger in quantified formula q?
+   *
+   * A usable trigger is one that is matchable and contains free variables only
+   * from q.
+   */
+  static bool isUsableTrigger( Node n, Node q );
+  /** get is usable trigger
+   *
+   * Return the associated node of n that is a usable trigger in quantified
+   * formula q. This may be different than n in several cases :
+   * (1) Polarity information is explicitly converted to equalities, e.g.
+   *      getIsUsableTrigger( (not (P x )), q ) may return (= (P x) false)
+   * (2) Relational triggers are put into solved form, e.g.
+   *      getIsUsableTrigger( (= (+ x a) 5), q ) may return (= x (- 5 a)).
+   */
+  static Node getIsUsableTrigger( Node n, Node q );
+  /** Is n a usable atomic trigger?
+   *
+   * A usable atomic trigger is a term that is both a useable trigger and an
+   * atomic trigger.
+   */
+  static bool isUsableAtomicTrigger( Node n, Node q );
+  /** is n an atomic trigger?
+  *
+  * An atomic trigger is one whose kind is an atomic trigger kind.
+  */
+  static bool isAtomicTrigger( Node n );
+  /** Is k an atomic trigger kind?
+   *
+  * An atomic trigger kind is one for which term indexing/matching is possible.
+  */
+  static bool isAtomicTriggerKind( Kind k );
+  /** is n a relational trigger, e.g. like x >= a ? */
+  static bool isRelationalTrigger( Node n );
+  /** Is k a relational trigger kind? */
+  static bool isRelationalTriggerKind( Kind k );
+  /** Is k a kind for which counterexample-guided instantiation is possible?
+   *
+  * This typically corresponds to kinds that correspond to operators that
+  * have total interpretations and are a part of the signature of
+  * satisfaction complete theories (see Reynolds et al., CAV 2015).
+  */
+  static bool isCbqiKind( Kind k );
+  /** is n a simple trigger (see inst_match_generator.h)? */
+  static bool isSimpleTrigger( Node n );
+  /** is n a Boolean term trigger, e.g. ite( x, BV1, BV0 )? */
+  static bool isBooleanTermTrigger( Node n );
+  /** is n a pure theory trigger, e.g. head( x )? */
+  static bool isPureTheoryTrigger( Node n );
+  /** get trigger weight
+   *
+   * Returns 0 for triggers that are easy to process and 1 otherwise.
+   * A trigger is easy to process if it is an atomic trigger, or a relational
+   * trigger of the form x ~ g for ~ \in { =, >=, > }.
+   */
+  static int getTriggerWeight( Node n );
+  /** Returns whether n is a trigger term with a local theory extension
+  * property from Bansal et al., CAV 2015.
+  */
+  static bool isLocalTheoryExt( Node n, std::vector< Node >& vars,
+                                std::vector< Node >& patTerms );
+  /** get the variable associated with an inversion for n
+   *
+   * A term n with an inversion variable x has the following property :
+   *   There exists a closed function f such that for all terms t
+   *   |= (n = t) <=> (x = f(t))
+   * For example, getInversionVariable( x+1 ) returns x since for all terms t,
+   *   |= x+1 = t <=> x = (\y. y-1)(t)
+   * We call f the inversion function for n.
+   */
+  static Node getInversionVariable( Node n );
+  /** Get the body of the inversion function for n whose argument is y.
+   * e.g. getInversion( x+1, y ) returns y-1
+   */
+  static Node getInversion(Node n, Node y);
+  /** get all variables that E-matching can instantiate from a subterm n.
+   *
+   * This returns the union of all free variables in usable triggers that are
+   * subterms of n.
+   */
+  static void getTriggerVariables(Node n, Node f, std::vector<Node>& t_vars);
+
+ protected:
+  /** trigger constructor, intentionally protected (use Trigger::mkTrigger). */
+  Trigger(QuantifiersEngine* ie, Node q, std::vector<Node>& nodes);
+  /** is subterm of trigger usable (helper function for isUsableTrigger) */
+  static bool isUsable( Node n, Node q );
+  /** returns an equality that is equivalent to the equality eq and
+  * is a usable trigger for q if one exists, otherwise returns Node::null().
+  */
+  static Node getIsUsableEq( Node q, Node eq );
+  /** returns whether n1 == n2 is a usable (relational) trigger for q. */
+  static bool isUsableEqTerms( Node q, Node n1, Node n2 );
+  /** recursive helper function for collectPatTerms
+   *
+   * This collects the usable trigger terms in the subterm n of the body of
+   * quantified formula q.
+   *   visited : cache of the trigger terms collected for each visited node,
+   *   tinfo : cache of trigger term info for each visited node,
+   *   tstrat : the selection strategy (see options/quantifiers_mode.h)
+   *   exclude :  a set of terms that *cannot* be selected as triggers
+   *   pol/hasPol : the polarity of node n in q
+   *                (see QuantPhaseReq theory/quantifiers/quant_util.h)
+   *   epol/hasEPol : the entailed polarity of node n in q
+   *                  (see QuantPhaseReq theory/quantifiers/quant_util.h)
+   *   knowIsUsable : whether we know that n is a usable trigger.
+   *
+   * We add the triggers we collected recursively in n into added.
+   */
+  static void collectPatTerms2( Node q, Node n, std::map< Node, std::vector< Node > >& visited, std::map< Node, TriggerTermInfo >& tinfo, 
+                                quantifiers::TriggerSelMode tstrt, std::vector< Node >& exclude, std::vector< Node >& added,
+                                bool pol, bool hasPol, bool epol, bool hasEPol, bool knowIsUsable = false );
+
+  /** filter all nodes that have trigger instances
+   *
+   * This is used during collectModelInfo to filter certain trigger terms,
+   * stored in nodes. This updates nodes so that no pairs of distinct nodes
+   * (i,j) is such that i is a trigger instance of j or vice versa (see below).
+   */
+  static void filterTriggerInstances(std::vector<Node>& nodes);
+
+  /** is instance of
+   *
+   * We say a term t is an trigger instance of term s if
+   * (1) t = s * { x1 -> t1 ... xn -> tn }
+   * (2) { x1, ..., xn } are a subset of FV( t ).
+   * For example, f( g( h( x, x ) ) ) and f( g( x ) ) are instances of f( x ),
+   * but f( g( y ) ) and g( x ) are not instances of f( x ).
+   *
+   * When this method returns -1, n1 is an instance of n2,
+   * When this method returns 1, n1 is an instance of n2.
+   *
+   * The motivation for this method is to discard triggers s that are less
+   * restrictive (criteria (1)) and serve to bind the same variables (criteria
+   * (2)) as another trigger t. This often helps avoiding matching loops.
+   */
+  static int isTriggerInstanceOf(Node n1,
+                                 Node n2,
+                                 std::vector<Node>& fv1,
+                                 std::vector<Node>& fv2);
+
+  /** add an instantiation (called by InstMatchGenerator)
+   *
+   * This calls Instantiate::addInstantiation(...) for instantiations
+   * associated with m. Typically, m is associated with a single instantiation,
+   * but in some cases (e.g. higher-order) we may modify m before calling
+   * Instantiate::addInstantiation(...).
+   */
+  virtual bool sendInstantiation(InstMatch& m);
+  /** The nodes comprising this trigger. */
+  std::vector< Node > d_nodes;
+  /** The quantifiers engine associated with this trigger. */
+  QuantifiersEngine* d_quantEngine;
+  /** The quantified formula this trigger is for. */
+  Node d_quant;
+  /** match generator
+   *
+  * This is the back-end utility that implements the underlying matching
+  * algorithm associated with this trigger.
+  */
+  IMGenerator* d_mg;
+}; /* class Trigger */
+
+/** A trie of triggers.
+*
+* This class is used to cache all Trigger objects that are generated in the
+* current context. We index Triggers in this data structure based on the
+* value of Trigger::d_nodes. When a Trigger is added to this data structure,
+* this Trie assumes responsibility for deleting it.
+*/
+class TriggerTrie {
+public:
+  TriggerTrie();
+  ~TriggerTrie();
+  /** get trigger
+  * This returns a Trigger t that is indexed by nodes,
+  * or NULL otherwise.
+  */
+  Trigger* getTrigger(std::vector<Node>& nodes);
+  /** add trigger
+  * This adds t to the trie, indexed by nodes.
+  * In typical use cases, nodes is t->d_nodes.
+  */
+  void addTrigger(std::vector<Node>& nodes, Trigger* t);
+
+ private:
+  /** The trigger at this node in the trie. */
+  std::vector<Trigger*> d_tr;
+  /** The children of this node in the trie. */
+  std::map< TNode, TriggerTrie* > d_children;
+};/* class inst::Trigger::TriggerTrie */
+
+}/* CVC4::theory::inst namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__TRIGGER_H */
index e7070b469310af914e8dd37f4d0be153a5b81692..e608b25b36b86c0b0e968bafc6425182e9a8e337 100644 (file)
 #include "theory/quantifiers/first_order_model.h"
 #include "options/base_options.h"
 #include "options/quantifiers_options.h"
-#include "theory/quantifiers/ambqi_builder.h"
-#include "theory/quantifiers/bounded_integers.h"
-#include "theory/quantifiers/full_model_check.h"
-#include "theory/quantifiers/model_engine.h"
+#include "theory/quantifiers/fmf/ambqi_builder.h"
+#include "theory/quantifiers/fmf/bounded_integers.h"
+#include "theory/quantifiers/fmf/full_model_check.h"
+#include "theory/quantifiers/fmf/model_engine.h"
 #include "theory/quantifiers/quantifiers_attributes.h"
 #include "theory/quantifiers/term_database.h"
 #include "theory/quantifiers/term_enumeration.h"
diff --git a/src/theory/quantifiers/fmf/ambqi_builder.cpp b/src/theory/quantifiers/fmf/ambqi_builder.cpp
new file mode 100644 (file)
index 0000000..6bb73f8
--- /dev/null
@@ -0,0 +1,968 @@
+/*********************                                                        */
+/*! \file ambqi_builder.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Morgan Deters, Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of abstract MBQI builder
+ **/
+
+#include "theory/quantifiers/fmf/ambqi_builder.h"
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/instantiate.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+
+using namespace std;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+
+void AbsDef::construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth ) {
+  d_def.clear();
+  Assert( !fapps.empty() );
+  if( depth==fapps[0].getNumChildren() ){
+    //if( fapps.size()>1 ){
+    //  for( unsigned i=0; i<fapps.size(); i++ ){
+    //    std::cout << "...." << fapps[i] << " -> " << m->getRepresentativeId( fapps[i] ) << std::endl;
+    //  }
+    //}
+    //get representative in model for this term
+    d_value = m->getRepresentativeId( fapps[0] );
+    Assert( d_value!=val_none );
+  }else{
+    TypeNode tn = fapps[0][depth].getType();
+    std::map< unsigned, std::vector< TNode > > fapp_child;
+
+    //partition based on evaluations of fapps[1][depth]....fapps[n][depth]
+    for( unsigned i=0; i<fapps.size(); i++ ){
+      unsigned r = m->getRepresentativeId( fapps[i][depth] );
+      Assert( r < 32 );
+      fapp_child[r].push_back( fapps[i] );
+    }
+
+    //do completion
+    std::map< unsigned, unsigned > fapp_child_index;
+    unsigned def = m->d_domain[ tn ];
+    unsigned minSize = fapp_child.begin()->second.size();
+    unsigned minSizeIndex = fapp_child.begin()->first;
+    for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){
+      fapp_child_index[it->first] = ( 1 << it->first );
+      def = def & ~( 1 << it->first );
+      if( it->second.size()<minSize ){
+        minSize = it->second.size();
+        minSizeIndex = it->first;
+      }
+    }
+    fapp_child_index[minSizeIndex] |= def;
+    d_default = fapp_child_index[minSizeIndex];
+
+    //construct children
+    for( std::map< unsigned, std::vector< TNode > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){
+      Trace("abs-model-debug") << "Construct " << it->first << " : " << fapp_child_index[it->first] << " : ";
+      const RepSet* rs = m->getRepSet();
+      debugPrintUInt("abs-model-debug",
+                     rs->getNumRepresentatives(tn),
+                     fapp_child_index[it->first]);
+      Trace("abs-model-debug") << " : " << it->second.size() << " terms." << std::endl;
+      d_def[fapp_child_index[it->first]].construct_func( m, it->second, depth+1 );
+    }
+  }
+}
+
+void AbsDef::simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth ) {
+  if( d_value==val_none && !d_def.empty() ){
+    //process the default
+    std::map< unsigned, AbsDef >::iterator defd = d_def.find( d_default );
+    Assert( defd!=d_def.end() );
+    unsigned newDef = d_default;
+    std::vector< unsigned > to_erase;
+    defd->second.simplify( m, q, n, depth+1 );
+    int defVal = defd->second.d_value;
+    bool isConstant = ( defVal!=val_none );
+    //process each child
+    for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
+      if( it->first!=d_default ){
+        it->second.simplify( m, q, n, depth+1 );
+        if( it->second.d_value==defVal && it->second.d_value!=val_none ){
+          newDef = newDef | it->first;
+          to_erase.push_back( it->first );
+        }else{
+          isConstant = false;
+        }
+      }
+    }
+    if( !to_erase.empty() ){
+      //erase old default
+      int defVal = defd->second.d_value;
+      d_def.erase( d_default );
+      //set new default
+      d_default = newDef;
+      d_def[d_default].construct_def_entry( m, q, n, defVal, depth+1 );
+      //erase redundant entries
+      for( unsigned i=0; i<to_erase.size(); i++ ){
+        d_def.erase( to_erase[i] );
+      }
+    }
+    //if constant, propagate the value upwards
+    if( isConstant ){
+      d_value = defVal;
+    }else{
+      d_value = val_none;
+    }
+  }
+}
+
+void AbsDef::debugPrintUInt( const char * c, unsigned dSize, unsigned u ) const{
+  for( unsigned i=0; i<dSize; i++ ){
+    Trace(c) << ( ( u & ( 1 << i ) )!=0 ? "1" : "0");
+  }
+  //Trace(c) << "(";
+  //for( unsigned i=0; i<32; i++ ){
+  //  Trace(c) << ( ( u & ( 1 << i ) )!=0 ? "1" : "0");
+  //}
+  //Trace(c) << ")";
+}
+
+void AbsDef::debugPrint( const char * c, FirstOrderModelAbs * m, TNode f, unsigned depth ) const{
+  if( Trace.isOn(c) ){
+    if( depth==f.getNumChildren() ){
+      for( unsigned i=0; i<depth; i++ ){ Trace(c) << "  ";}
+      Trace(c) << "V[" << d_value << "]" << std::endl;
+    }else{
+      TypeNode tn = f[depth].getType();
+      const RepSet* rs = m->getRepSet();
+      unsigned dSize = rs->getNumRepresentatives(tn);
+      Assert( dSize<32 );
+      for( std::map< unsigned, AbsDef >::const_iterator it = d_def.begin(); it != d_def.end(); ++it ){
+        for( unsigned i=0; i<depth; i++ ){ Trace(c) << "  ";}
+        debugPrintUInt( c, dSize, it->first );
+        if( it->first==d_default ){
+          Trace(c) << "*";
+        }
+        if( it->second.d_value!=val_none ){
+          Trace(c) << " -> V[" << it->second.d_value << "]";
+        }
+        Trace(c) << std::endl;
+        it->second.debugPrint( c, m, f, depth+1 );
+      }
+    }
+  }
+}
+
+bool AbsDef::addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth ) {
+  if( inst==0 || !options::fmfOneInstPerRound() ){
+    if( d_value==1 ){
+      //instantiations are all true : ignore this
+      return true;
+    }else{
+      if( depth==q[0].getNumChildren() ){
+        if (qe->getInstantiate()->addInstantiation(q, terms, true))
+        {
+          Trace("ambqi-inst-debug") << "-> Added instantiation." << std::endl;
+          inst++;
+          return true;
+        }else{
+          Trace("ambqi-inst-debug") << "-> Failed to add instantiation." << std::endl;
+          //we are incomplete
+          return false;
+        }
+      }else{
+        bool osuccess = true;
+        TypeNode tn = m->getVariable( q, depth ).getType();
+        for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
+          //get witness term
+          unsigned index = 0;
+          bool success;
+          do {
+            success = false;
+            index = getId( it->first, index );
+            if( index<32 ){
+              const RepSet* rs = m->getRepSet();
+              Assert(index < rs->getNumRepresentatives(tn));
+              terms[m->d_var_order[q][depth]] =
+                  rs->getRepresentative(tn, index);
+              if( !it->second.addInstantiations( m, qe, q, terms, inst, depth+1 ) && inst==0 ){
+                //if we are incomplete, and have not yet added an instantiation, keep trying
+                index++;
+                Trace("ambqi-inst-debug") << "At depth " << depth << ", failed branch, no instantiations and incomplete, increment index : " << index << std::endl;
+              }else{
+                success = true;
+              }
+            }
+          }while( !qe->inConflict() && !success && index<32 );
+          //mark if we are incomplete
+          osuccess = osuccess && success;
+        }
+        return osuccess;
+      }
+    }
+  }else{
+    return true;
+  }
+}
+
+void AbsDef::construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth ) {
+  if( depth==entry.size() ){
+    d_value = v;
+  }else{
+    d_def[entry[depth]].construct_entry( entry, entry_def, v, depth+1 );
+    if( entry_def[depth] ){
+      d_default = entry[depth];
+    }
+  }
+}
+
+void AbsDef::get_defs( unsigned u, std::vector< AbsDef * >& defs ) {
+  for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
+    if( ( u & it->first )!=0 ){
+      Assert( (u & it->first)==u );
+      defs.push_back( &it->second );
+    }
+  }
+}
+
+void AbsDef::construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth ) {
+  if( depth==q[0].getNumChildren() ){
+    Assert( defs.size()==1 );
+    d_value = defs[0]->d_value;
+  }else{
+    TypeNode tn = m->getVariable( q, depth ).getType();
+    unsigned def = m->d_domain[tn];
+    for( unsigned i=0; i<defs.size(); i++ ){
+      //process each simple child
+      for( std::map< unsigned, AbsDef >::iterator itd = defs[i]->d_def.begin(); itd != defs[i]->d_def.end(); ++itd ){
+        if( isSimple( itd->first ) && ( def & itd->first )!=0 ){
+          def &= ~( itd->first );
+          //process this value
+          std::vector< AbsDef * > cdefs;
+          for( unsigned j=0; j<defs.size(); j++ ){
+            defs[j]->get_defs( itd->first, cdefs );
+          }
+          d_def[itd->first].construct_normalize( m, q, cdefs, depth+1 );
+          if( def==0 ){
+            d_default = itd->first;
+            break;
+          }
+        }
+      }
+      if( def==0 ){
+        break;
+      }
+    }
+    if( def!=0 ){
+      d_default = def;
+      //process the default
+      std::vector< AbsDef * > cdefs;
+      for( unsigned j=0; j<defs.size(); j++ ){
+        defs[j]->get_defs( d_default, cdefs );
+      }
+      d_def[d_default].construct_normalize( m, q, cdefs, depth+1 );
+    }
+  }
+}
+
+void AbsDef::construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth ) {
+  d_value = v;
+  if( depth<n.getNumChildren() ){
+    TypeNode tn = q.isNull() ? n[depth].getType() : m->getVariable( q, depth ).getType();
+    unsigned dom = m->d_domain[tn] ;
+    d_def[dom].construct_def_entry( m, q, n, v, depth+1 );
+    d_default = dom;
+  }
+}
+
+void AbsDef::apply_ucompose( FirstOrderModelAbs * m, TNode q,
+                             std::vector< unsigned >& entry, std::vector< bool >& entry_def,
+                             std::vector< int >& terms, std::map< unsigned, int >& vchildren,
+                             AbsDef * a, unsigned depth ) {
+  if( depth==terms.size() ){
+    if( Trace.isOn("ambqi-check-debug2") ){
+      Trace("ambqi-check-debug2") << "Add entry ( ";
+      const RepSet* rs = m->getRepSet();
+      for( unsigned i=0; i<entry.size(); i++ ){
+        unsigned dSize =
+            rs->getNumRepresentatives(m->getVariable(q, i).getType());
+        debugPrintUInt( "ambqi-check-debug2", dSize, entry[i] );
+        Trace("ambqi-check-debug2") << " ";
+      }
+      Trace("ambqi-check-debug2") << ")" << std::endl;
+    }
+    a->construct_entry( entry, entry_def, d_value );
+  }else{
+    unsigned id;
+    if( terms[depth]==val_none ){
+      //a variable
+      std::map< unsigned, int >::iterator itv = vchildren.find( depth );
+      Assert( itv!=vchildren.end() );
+      unsigned prev_v = entry[itv->second];
+      bool prev_vd = entry_def[itv->second];
+      for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
+        entry[itv->second] = it->first & prev_v;
+        entry_def[itv->second] = ( it->first==d_default ) && prev_vd;
+        if( entry[itv->second]!=0 ){
+          it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
+        }
+      }
+      entry[itv->second] = prev_v;
+      entry_def[itv->second] = prev_vd;
+    }else{
+      id = (unsigned)terms[depth];
+      Assert( id<32 );
+      unsigned fid = 1 << id;
+      std::map< unsigned, AbsDef >::iterator it = d_def.find( fid );
+      if( it!=d_def.end() ){
+        it->second.apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
+      }else{
+        d_def[d_default].apply_ucompose( m, q, entry, entry_def, terms, vchildren, a, depth+1 );
+      }
+    }
+  }
+}
+
+void AbsDef::construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth ) {
+  if( depth==q[0].getNumChildren() ){
+    Assert( currv!=val_none );
+    d_value = currv;
+  }else{
+    TypeNode tn = m->getVariable( q, depth ).getType();
+    unsigned dom = m->d_domain[tn];
+    int vindex = depth==v1 ? 0 : ( depth==v2 ? 1 : val_none );
+    if( vindex==val_none ){
+      d_def[dom].construct_var_eq( m, q, v1, v2, curr, currv, depth+1 );
+      d_default = dom;
+    }else{
+      Assert( currv==val_none );
+      if( curr==val_none ){
+        unsigned numReps = m->getRepSet()->getNumRepresentatives(tn);
+        Assert( numReps < 32 );
+        for( unsigned i=0; i<numReps; i++ ){
+          curr = 1 << i;
+          d_def[curr].construct_var_eq( m, q, v1, v2, curr, currv, depth+1 );
+        }
+        d_default = curr;
+      }else{
+        d_def[curr].construct_var_eq( m, q, v1, v2, curr, 1, depth+1 );
+        dom = dom & ~curr;
+        d_def[dom].construct_var_eq( m, q, v1, v2, curr, 0, depth+1 );
+        d_default = dom;
+      }
+    }
+  }
+}
+
+void AbsDef::construct_var( FirstOrderModelAbs * m, TNode q, unsigned v, int currv, unsigned depth ) {
+  if( depth==q[0].getNumChildren() ){
+    Assert( currv!=val_none );
+    d_value = currv;
+  }else{
+    TypeNode tn = m->getVariable( q, depth ).getType();
+    if( v==depth ){
+      unsigned numReps = m->getRepSet()->getNumRepresentatives(tn);
+      Assert( numReps>0 && numReps < 32 );
+      for( unsigned i=0; i<numReps; i++ ){
+        d_def[ 1 << i ].construct_var( m, q, v, i, depth+1 );
+      }
+      d_default = 1 << (numReps - 1);
+    }else{
+      unsigned dom = m->d_domain[tn];
+      d_def[dom].construct_var( m, q, v, currv, depth+1 );
+      d_default = dom;
+    }
+  }
+}
+
+void AbsDef::construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
+                                std::map< unsigned, AbsDef * >& children,
+                                std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
+                                std::vector< unsigned >& entry, std::vector< bool >& entry_def ) {
+  const RepSet* rs = m->getRepSet();
+  if( n.getKind()==OR || n.getKind()==AND ){
+    // short circuiting
+    for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
+      if( ( it->second->d_value==0 && n.getKind()==AND ) ||
+          ( it->second->d_value==1 && n.getKind()==OR ) ){
+        //std::cout << "Short circuit " << it->second->d_value << " " << entry.size() << "/" << q[0].getNumChildren() << std::endl;
+        unsigned count = q[0].getNumChildren() - entry.size();
+        for( unsigned i=0; i<count; i++ ){
+          entry.push_back( m->d_domain[m->getVariable( q, entry.size() ).getType()] );
+          entry_def.push_back( true );
+        }
+        construct_entry( entry, entry_def, it->second->d_value );
+        for( unsigned i=0; i<count; i++ ){
+          entry.pop_back();
+          entry_def.pop_back();
+        }
+        return;
+      }
+    }
+  }
+  if( entry.size()==q[0].getNumChildren() ){
+    if( f ){
+      if( Trace.isOn("ambqi-check-debug2") ){
+        for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
+        Trace("ambqi-check-debug2") << "Evaluate uninterpreted function entry..." << std::endl;
+      }
+      //we are composing with an uninterpreted function
+      std::vector< int > values;
+      values.resize( n.getNumChildren(), val_none );
+      for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
+        values[it->first] = it->second->d_value;
+      }
+      for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){
+        values[it->first] = it->second;
+      }
+      //look up value(s)
+      f->apply_ucompose( m, q, entry, entry_def, values, vchildren, this );
+    }else{
+      bool incomplete = false;
+      //we are composing with an interpreted function
+      std::vector< TNode > values;
+      values.resize( n.getNumChildren(), TNode::null() );
+      for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
+        Trace("ambqi-check-debug2") << "composite : " << it->first << " : " << it->second->d_value;
+        if( it->second->d_value>=0 ){
+          if (it->second->d_value
+              >= (int)rs->getNumRepresentatives(n[it->first].getType()))
+          {
+            std::cout << it->second->d_value << " " << n[it->first] << " "
+                      << n[it->first].getType() << " "
+                      << rs->getNumRepresentatives(n[it->first].getType())
+                      << std::endl;
+          }
+          Assert(it->second->d_value
+                 < (int)rs->getNumRepresentatives(n[it->first].getType()));
+          values[it->first] = rs->getRepresentative(n[it->first].getType(),
+                                                    it->second->d_value);
+        }else{
+          incomplete = true;
+        }
+        Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl;
+      }
+      for( std::map< unsigned, int >::iterator it = bchildren.begin(); it != bchildren.end(); ++it ){
+        Trace("ambqi-check-debug2") << "   basic :  " << it->first << " : " << it->second;
+        if( it->second>=0 ){
+          Assert(it->second
+                 < (int)rs->getNumRepresentatives(n[it->first].getType()));
+          values[it->first] =
+              rs->getRepresentative(n[it->first].getType(), it->second);
+        }else{
+          incomplete = true;
+        }
+        Trace("ambqi-check-debug2") << " ->> " << values[it->first] << std::endl;
+      }
+      Assert( vchildren.empty() );
+      if( incomplete ){
+        Trace("ambqi-check-debug2") << "Construct incomplete entry." << std::endl;
+
+        //if a child is unknown, we must return unknown
+        construct_entry( entry, entry_def, val_unk );
+      }else{
+        if( Trace.isOn("ambqi-check-debug2") ){
+          for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
+          Trace("ambqi-check-debug2") << "Evaluate interpreted function entry ( ";
+          for( unsigned i=0; i<values.size(); i++ ){
+            Assert( !values[i].isNull() );
+            Trace("ambqi-check-debug2") << values[i] << " ";
+          }
+          Trace("ambqi-check-debug2") << ")..." << std::endl;
+        }
+        //evaluate
+        Node vv = NodeManager::currentNM()->mkNode( n.getKind(), values );
+        vv = Rewriter::rewrite( vv );
+        int v = m->getRepresentativeId( vv );
+        construct_entry( entry, entry_def, v );
+      }
+    }
+  }else{
+    //take product of arguments
+    TypeNode tn = m->getVariable( q, entry.size() ).getType();
+    Assert( m->isValidType( tn ) );
+    unsigned def = m->d_domain[tn];
+    if( Trace.isOn("ambqi-check-debug2") ){
+      for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
+      Trace("ambqi-check-debug2") << "Take product of arguments" << std::endl;
+    }
+    for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
+      Assert( it->second!=NULL );
+      //process each child
+      for( std::map< unsigned, AbsDef >::iterator itd = it->second->d_def.begin(); itd != it->second->d_def.end(); ++itd ){
+        if( itd->first!=it->second->d_default && ( def & itd->first )!=0 ){
+          def &= ~( itd->first );
+          //process this value
+          std::map< unsigned, AbsDef * > cchildren;
+          for( std::map< unsigned, AbsDef * >::iterator it2 = children.begin(); it2 != children.end(); ++it2 ){
+            Assert( it2->second!=NULL );
+            std::map< unsigned, AbsDef >::iterator itdf = it2->second->d_def.find( itd->first );
+            if( itdf!=it2->second->d_def.end() ){
+              cchildren[it2->first] = &itdf->second;
+            }else{
+              Assert( it2->second->getDefault()!=NULL );
+              cchildren[it2->first] = it2->second->getDefault();
+            }
+          }
+          if( Trace.isOn("ambqi-check-debug2") ){
+            for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
+            Trace("ambqi-check-debug2") << "...process : ";
+            debugPrintUInt("ambqi-check-debug2",
+                           rs->getNumRepresentatives(tn),
+                           itd->first);
+            Trace("ambqi-check-debug2") << " " << children.size() << " " << cchildren.size() << std::endl;
+          }
+          entry.push_back( itd->first );
+          entry_def.push_back( def==0 );
+          construct_compose( m, q, n, f, cchildren, bchildren, vchildren, entry, entry_def );
+          entry_def.pop_back();
+          entry.pop_back();
+          if( def==0 ){
+            break;
+          }
+        }
+      }
+      if( def==0 ){
+        break;
+      }
+    }
+    if( def!=0 ){
+      if( Trace.isOn("ambqi-check-debug2") ){
+        for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
+        Trace("ambqi-check-debug2") << "Make default argument" << std::endl;
+      }
+      std::map< unsigned, AbsDef * > cdchildren;
+      for( std::map< unsigned, AbsDef * >::iterator it = children.begin(); it != children.end(); ++it ){
+        Assert( it->second->getDefault()!=NULL );
+        cdchildren[it->first] = it->second->getDefault();
+      }
+      if( Trace.isOn("ambqi-check-debug2") ){
+        for( unsigned i=0; i<entry.size(); i++ ){ Trace("ambqi-check-debug2") << "  "; }
+        Trace("ambqi-check-debug2") << "...process default : ";
+        debugPrintUInt(
+            "ambqi-check-debug2", rs->getNumRepresentatives(tn), def);
+        Trace("ambqi-check-debug2") << " " << children.size() << " " << cdchildren.size() << std::endl;
+      }
+      entry.push_back( def );
+      entry_def.push_back( true );
+      construct_compose( m, q, n, f, cdchildren, bchildren, vchildren, entry, entry_def );
+      entry_def.pop_back();
+      entry.pop_back();
+    }
+  }
+}
+
+bool AbsDef::construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
+                        std::map< unsigned, AbsDef * >& children,
+                        std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
+                        int varChCount ) {
+  if( Trace.isOn("ambqi-check-debug3") ){
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      Trace("ambqi-check-debug3") << i << " : ";
+      Trace("ambqi-check-debug3") << ((children.find( i )!=children.end()) ? "X" : ".");
+      if( bchildren.find( i )!=bchildren.end() ){
+        Trace("ambqi-check-debug3") << bchildren[i];
+      }else{
+        Trace("ambqi-check-debug3") << ".";
+      }
+      if( vchildren.find( i )!=vchildren.end() ){
+        Trace("ambqi-check-debug3") << vchildren[i];
+      }else{
+        Trace("ambqi-check-debug3") << ".";
+      }
+      Trace("ambqi-check-debug3") << std::endl;
+    }
+    Trace("ambqi-check-debug3") << "varChCount : " << varChCount << std::endl;
+  }
+  if( varChCount==0 || f ){
+    //short-circuit
+    if( n.getKind()==AND || n.getKind()==OR ){
+      for( std::map< unsigned, int >::iterator it = bchildren.begin(); it !=bchildren.end(); ++it ){
+        if( ( it->second==0 && n.getKind()==AND ) ||
+            ( it->second==1 && n.getKind()==OR ) ){
+          construct_def_entry( m, q, q[0], it->second );
+          return true;
+        }
+      }
+    }
+    Trace("ambqi-check-debug2") << "Construct compose..." << std::endl;
+    std::vector< unsigned > entry;
+    std::vector< bool > entry_def;
+    if( f && varChCount>0 ){
+      AbsDef unorm;
+      unorm.construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
+      //normalize
+      std::vector< AbsDef* > defs;
+      defs.push_back( &unorm );
+      construct_normalize( m, q, defs );
+    }else{
+      construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
+    }
+    Assert( is_normalized() );
+    //if( !is_normalized() ){
+    //  std::cout << "NON NORMALIZED DEFINITION" << std::endl;
+    //  exit( 10 );
+    //}
+    return true;
+  }else if( varChCount==1 && ( n.getKind()==EQUAL && !n[0].getType().isBoolean() ) ){
+    Trace("ambqi-check-debug2") << "Expand variable child..." << std::endl;
+    //expand the variable based on its finite domain
+    AbsDef a;
+    a.construct_var( m, q, vchildren.begin()->second, val_none );
+    children[vchildren.begin()->first] = &a;
+    vchildren.clear();
+    std::vector< unsigned > entry;
+    std::vector< bool > entry_def;
+    Trace("ambqi-check-debug2") << "Construct compose with variable..." << std::endl;
+    construct_compose( m, q, n, f, children, bchildren, vchildren, entry, entry_def );
+    return true;
+  }else if( varChCount==2 && ( n.getKind()==EQUAL && !n[0].getType().isBoolean() ) ){
+    Trace("ambqi-check-debug2") << "Construct variable equality..." << std::endl;
+    //efficient expansion of the equality
+    construct_var_eq( m, q, vchildren[0], vchildren[1], val_none, val_none );
+    return true;
+  }else{
+    return false;
+  }
+}
+
+void AbsDef::negate() {
+  for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
+    it->second.negate();
+  }
+  if( d_value==0 ){
+    d_value = 1;
+  }else if( d_value==1 ){
+    d_value = 0;
+  }
+}
+
+Node AbsDef::getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth ) {
+  const RepSet* rs = m->getRepSet();
+  if( depth==vars.size() ){
+    TypeNode tn = op.getType();
+    if( tn.getNumChildren()>0 ){
+      tn = tn[tn.getNumChildren() - 1];
+    }
+    if( d_value>=0 ){
+      Assert(d_value < (int)rs->getNumRepresentatives(tn));
+      if( tn.isBoolean() ){
+        return NodeManager::currentNM()->mkConst( d_value==1 );
+      }else{
+        return rs->getRepresentative(tn, d_value);
+      }
+    }else{
+      return Node::null();
+    }
+  }else{
+    TypeNode tn = vars[depth].getType();
+    Node curr;
+    curr = d_def[d_default].getFunctionValue( m, op, vars, depth+1 );
+    for( std::map< unsigned, AbsDef >::iterator it = d_def.begin(); it != d_def.end(); ++it ){
+      if( it->first!=d_default ){
+        unsigned id = getId( it->first );
+        Assert(id < rs->getNumRepresentatives(tn));
+        TNode n = rs->getRepresentative(tn, id);
+        Node fv = it->second.getFunctionValue( m, op, vars, depth+1 );
+        if( !curr.isNull() && !fv.isNull() ){
+          curr = NodeManager::currentNM()->mkNode( ITE, vars[depth].eqNode( n ), fv, curr );
+        }else{
+          curr = Node::null();
+        }
+      }
+    }
+    return curr;
+  }
+}
+
+bool AbsDef::isSimple( unsigned n ) {
+  return (n & (n - 1))==0;
+}
+
+unsigned AbsDef::getId( unsigned n, unsigned start, unsigned end ) {
+  Assert( n!=0 );
+  while( (n & ( 1 << start )) == 0 ){
+    start++;
+    if( start==end ){
+      return start;
+    }
+  }
+  return start;
+}
+
+Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< Node >& args ) {
+  std::vector< unsigned > iargs;
+  for( unsigned i=0; i<args.size(); i++ ){
+    unsigned v = 1 << m->getRepresentativeId( args[i] );
+    iargs.push_back( v );
+  }
+  return evaluate( m, retTyp, iargs, 0 );
+}
+
+Node AbsDef::evaluate( FirstOrderModelAbs * m, TypeNode retTyp, std::vector< unsigned >& iargs, unsigned depth ) {
+  if( d_value!=val_none ){
+    if( d_value==val_unk ){
+      return Node::null();
+    }else{
+      const RepSet* rs = m->getRepSet();
+      Assert(d_value >= 0 && d_value < (int)rs->getNumRepresentatives(retTyp));
+      return rs->getRepresentative(retTyp, d_value);
+    }
+  }else{
+    std::map< unsigned, AbsDef >::iterator it = d_def.find( iargs[depth] );
+    if( it==d_def.end() ){
+      return d_def[d_default].evaluate( m, retTyp, iargs, depth+1 );
+    }else{
+      return it->second.evaluate( m, retTyp, iargs, depth+1 );
+    }
+  }
+}
+
+bool AbsDef::is_normalized() {
+  for( std::map< unsigned, AbsDef >::iterator it1 = d_def.begin(); it1 != d_def.end(); ++it1 ){
+    if( !it1->second.is_normalized() ){
+      return false;
+    }
+    for( std::map< unsigned, AbsDef >::iterator it2 = d_def.begin(); it2 != d_def.end(); ++it2 ){
+      if( it1->first!=it2->first && (( it1->first & it2->first )!=0) ){
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+AbsMbqiBuilder::AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe ) :
+QModelBuilder( c, qe ){
+  d_true = NodeManager::currentNM()->mkConst( true );
+  d_false = NodeManager::currentNM()->mkConst( false );
+}
+
+
+//------------------------model construction----------------------------
+
+bool AbsMbqiBuilder::processBuildModel(TheoryModel* m) {
+  Trace("ambqi-debug") << "process build model " << std::endl;
+  FirstOrderModel* f = (FirstOrderModel*)m;
+  FirstOrderModelAbs* fm = f->asFirstOrderModelAbs();
+  RepSet* rs = m->getRepSetPtr();
+  fm->initialize();
+  //process representatives
+  fm->d_rep_id.clear();
+  fm->d_domain.clear();
+
+  //initialize boolean sort
+  TypeNode b = d_true.getType();
+  rs->d_type_reps[b].clear();
+  rs->d_type_reps[b].push_back(d_false);
+  rs->d_type_reps[b].push_back(d_true);
+  fm->d_rep_id[d_false] = 0;
+  fm->d_rep_id[d_true] = 1;
+
+  //initialize unintpreted sorts
+  Trace("ambqi-model") << std::endl << "Making representatives..." << std::endl;
+  for (std::map<TypeNode, std::vector<Node> >::iterator it =
+           rs->d_type_reps.begin();
+       it != rs->d_type_reps.end();
+       ++it)
+  {
+    if( it->first.isSort() ){
+      Assert( !it->second.empty() );
+      //set the domain
+      fm->d_domain[it->first] = 0;
+      Trace("ambqi-model") << "Representatives for " << it->first << " : " << std::endl;
+      for( unsigned i=0; i<it->second.size(); i++ ){
+        if( i<32 ){
+          fm->d_domain[it->first] |= ( 1 << i );
+        }
+        Trace("ambqi-model") << i << " : " << it->second[i] << std::endl;
+        fm->d_rep_id[it->second[i]] = i;
+      }
+      if( it->second.size()>=32 ){
+        fm->d_domain.erase( it->first );
+      }
+    }
+  }
+
+  Trace("ambqi-model") << std::endl << "Making function definitions..." << std::endl;
+  //construct the models for functions
+  for( std::map<Node, AbsDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+    Node f = it->first;
+    Trace("ambqi-model-debug") << "Building Model for " << f << std::endl;
+    //reset the model
+    it->second->clear();
+    //get all (non-redundant) f-applications
+    std::vector< TNode > fapps;
+    Trace("ambqi-model-debug") << "Initial terms: " << std::endl;
+    std::map< Node, std::vector< Node > >::iterator itut = fm->d_uf_terms.find( f );
+    if( itut!=fm->d_uf_terms.end() ){
+      for( size_t i=0; i<itut->second.size(); i++ ){
+        Node n = itut->second[i];
+        // only consider unique up to congruence (in model equality engine)?
+        Trace("ambqi-model-debug") << "  " << n << " -> " << fm->getRepresentativeId( n ) << std::endl;
+        fapps.push_back( n );
+      }
+    }
+    if( fapps.empty() ){
+      //choose arbitrary value
+      Node mbt = fm->getModelBasisOpTerm(f);
+      Trace("ambqi-model-debug") << "Initial terms empty, add " << mbt << std::endl;
+      fapps.push_back( mbt );
+    }
+    bool fValid = true;
+    for( unsigned i=0; i<fapps[0].getNumChildren(); i++ ){
+      if( fm->d_domain.find( fapps[0][i].getType() )==fm->d_domain.end() ){
+        Trace("ambqi-model") << "Interpretation of " << f << " is not valid.";
+        Trace("ambqi-model") << " (domain for " << fapps[0][i].getType() << " is too large)." << std::endl;
+        fValid = false;
+        break;
+      }
+    }
+    fm->d_models_valid[f] = fValid;
+    if( fValid ){
+      //construct the ambqi model
+      it->second->construct_func( fm, fapps );
+      Trace("ambqi-model-debug") << "Interpretation of " << f << " : " << std::endl;
+      it->second->debugPrint("ambqi-model-debug", fm, fapps[0] );
+      Trace("ambqi-model-debug") << "Simplifying " << f << "..." << std::endl;
+      it->second->simplify( fm, TNode::null(), fapps[0] );
+      Trace("ambqi-model") << "(Simplified) interpretation of " << f << " : " << std::endl;
+      it->second->debugPrint("ambqi-model", fm, fapps[0] );
+
+/*
+      if( Debug.isOn("ambqi-model-debug") ){
+        for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
+          Node e = it->second->evaluate_n( fm, fm->d_uf_terms[f][i] );
+          Debug("ambqi-model-debug") << fm->d_uf_terms[f][i] << " evaluates to " << e << std::endl;
+          Assert( fm->areEqual( e, fm->d_uf_terms[f][i] ) );
+        }
+      }
+*/
+    }
+  }
+  Trace("ambqi-model") << "Construct model representation..." << std::endl;
+  //make function values
+  for( std::map<Node, AbsDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+    if( it->first.getType().getNumChildren()>1 ){
+      Trace("ambqi-model") << "Construct for " << it->first << "..." << std::endl;
+      Node f_def = fm->getFunctionValue( it->first, "$x" );
+      m->assignFunctionDefinition( it->first, f_def );
+    }
+  }
+  Assert( d_addedLemmas==0 );
+  return TheoryEngineModelBuilder::processBuildModel( m );
+}
+
+
+//--------------------model checking---------------------------------------
+
+//do exhaustive instantiation
+int AbsMbqiBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) {
+  Trace("ambqi-check") << "Exhaustive instantiation " << q << " " << effort << std::endl;
+  if (effort==0) {
+    FirstOrderModelAbs * fma = fm->asFirstOrderModelAbs();
+    bool quantValid = true;
+    for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+      if( !fma->isValidType( q[0][i].getType() ) ){
+        quantValid = false;
+        Trace("ambqi-inst") << "Interpretation of " << q << " is not valid because of type " << q[0][i].getType() << std::endl;
+        break;
+      }
+    }
+    if( quantValid ){
+      Trace("ambqi-check") << "Compute interpretation..." << std::endl;
+      AbsDef ad;
+      doCheck( fma, q, ad, q[1] );
+      //now process entries
+      Trace("ambqi-inst-debug") << "...Current : " << d_addedLemmas << std::endl;
+      Trace("ambqi-inst") << "Interpretation of " << q << " is : " << std::endl;
+      ad.debugPrint( "ambqi-inst", fma, q[0] );
+      Trace("ambqi-inst") << std::endl;
+      Trace("ambqi-check") << "Add instantiations..." << std::endl;
+      int lem = 0;
+      quantValid = ad.addInstantiations( fma, d_qe, q, lem );
+      Trace("ambqi-inst") << "...Added " << lem << " lemmas." << std::endl;
+      if( lem>0 ){
+        //if we were incomplete but added at least one lemma, we are ok
+        quantValid = true;
+      }
+      d_addedLemmas += lem;
+      Trace("ambqi-inst-debug") << "...Total : " << d_addedLemmas << std::endl;
+    }
+    return quantValid ? 1 : 0;
+  }else{
+    return 1;
+  }
+}
+
+bool AbsMbqiBuilder::doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n ) {
+  Assert( n.getKind()!=FORALL );
+  if( n.getKind()==NOT && n[0].getKind()!=FORALL ){
+    doCheck( m, q, ad, n[0] );
+    ad.negate();
+    return true;
+  }else{
+    std::map< unsigned, AbsDef > children;
+    std::map< unsigned, int > bchildren;
+    std::map< unsigned, int > vchildren;
+    int varChCount = 0;
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      if( n[i].getKind()==FORALL ){
+        bchildren[i] = AbsDef::val_unk;
+      }else if( n[i].getKind() == BOUND_VARIABLE ){
+        varChCount++;
+        vchildren[i] = m->d_var_index[q][ m->getVariableId( q, n[i] ) ];
+        //vchildren[i] = m->getVariableId( q, n[i] );
+      }else if( m->hasTerm( n[i] ) ){
+        bchildren[i] = m->getRepresentativeId( n[i] );
+      }else{
+        if( !doCheck( m, q, children[i], n[i] ) ){
+          bchildren[i] = AbsDef::val_unk;
+          children.erase( i );
+        }
+      }
+    }
+    //convert to pointers
+    std::map< unsigned, AbsDef * > pchildren;
+    for( std::map< unsigned, AbsDef >::iterator it = children.begin(); it != children.end(); ++it ){
+      pchildren[it->first] = &it->second;
+    }
+    //construct the interpretation
+    Trace("ambqi-check-debug") << "Compute Interpretation of " << n << " " << n.getKind() << std::endl;
+    if( n.getKind() == APPLY_UF || n.getKind() == VARIABLE || n.getKind() == SKOLEM ){
+      Node op;
+      if( n.getKind() == APPLY_UF ){
+        op = n.getOperator();
+      }else{
+        op = n;
+      }
+      //uninterpreted compose
+      if( m->d_models_valid[op] ){
+        ad.construct( m, q, n, m->d_models[op], pchildren, bchildren, vchildren, varChCount );
+      }else{
+        Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (no function model)" << std::endl;
+        return false;
+      }
+    }else if( !ad.construct( m, q, n, NULL, pchildren, bchildren, vchildren, varChCount ) ){
+      Trace("ambqi-check-debug") << "** Cannot produce interpretation for " << n << " (variables are children of interpreted symbol)" << std::endl;
+      return false;
+    }
+    Trace("ambqi-check-try") << "Interpretation for " << n << " is : " << std::endl;
+    ad.debugPrint("ambqi-check-try", m, q[0] );
+    ad.simplify( m, q, q[0] );
+    Trace("ambqi-check-debug") << "(Simplified) Interpretation for " << n << " is : " << std::endl;
+    ad.debugPrint("ambqi-check-debug", m, q[0] );
+    Trace("ambqi-check-debug") << std::endl;
+    return true;
+  }
+}
+
+}/* namespace CVC4::theory::quantifiers */
+}/* namespace CVC4::theory */
+}/* namespace CVC4 */
diff --git a/src/theory/quantifiers/fmf/ambqi_builder.h b/src/theory/quantifiers/fmf/ambqi_builder.h
new file mode 100644 (file)
index 0000000..914da14
--- /dev/null
@@ -0,0 +1,105 @@
+/*********************                                                        */
+/*! \file ambqi_builder.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Morgan Deters, Tim King, Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Abstract MBQI model builder class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef ABSTRACT_MBQI_BUILDER
+#define ABSTRACT_MBQI_BUILDER
+
+#include "theory/quantifiers/fmf/model_builder.h"
+#include "theory/quantifiers/first_order_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class FirstOrderModelAbs;
+
+//representiation of function and term interpretations
+class AbsDef
+{
+private:
+  bool addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, TNode q, std::vector< Node >& terms, int& inst, unsigned depth );
+  void construct_compose( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
+                          std::map< unsigned, AbsDef * >& children,
+                          std::map< unsigned, int >& bchildren, std::map< unsigned, int >& vchildren,
+                          std::vector< unsigned >& entry, std::vector< bool >& entry_def );
+  void construct_entry( std::vector< unsigned >& entry, std::vector< bool >& entry_def, int v, unsigned depth = 0 );
+  void construct_def_entry( FirstOrderModelAbs * m, TNode q, TNode n, int v, unsigned depth = 0 );
+  void apply_ucompose( FirstOrderModelAbs * m, TNode q,
+                       std::vector< unsigned >& entry, std::vector< bool >& entry_def, std::vector< int >& terms,
+                       std::map< unsigned, int >& vchildren, AbsDef * a, unsigned depth = 0 );
+  void construct_var_eq( FirstOrderModelAbs * m, TNode q, unsigned v1, unsigned v2, int curr, int currv, unsigned depth = 0 );
+  void construct_var( FirstOrderModelAbs * m, TNode q, unsigned v, int currv, unsigned depth = 0 );
+  void get_defs( unsigned u, std::vector< AbsDef * >& defs );
+  void construct_normalize( FirstOrderModelAbs * m, TNode q, std::vector< AbsDef * >& defs, unsigned depth = 0 );
+public:
+  enum {
+    val_none = -1,
+    val_unk = -2,
+  };
+  AbsDef() : d_default( 0 ), d_value( -1 ){}
+  std::map< unsigned, AbsDef > d_def;
+  unsigned d_default;
+  int d_value;
+
+  void clear() { d_def.clear(); d_default = 0; d_value = -1; }
+  AbsDef * getDefault() { return &d_def[d_default]; }
+  void construct_func( FirstOrderModelAbs * m, std::vector< TNode >& fapps, unsigned depth = 0 );
+  void debugPrintUInt( const char * c, unsigned dSize, unsigned u ) const;
+  void debugPrint( const char * c, FirstOrderModelAbs * m, TNode f, unsigned depth = 0 ) const;
+  void simplify( FirstOrderModelAbs * m, TNode q, TNode n, unsigned depth = 0 );
+  int addInstantiations( FirstOrderModelAbs * m, QuantifiersEngine * qe, Node q, int& inst ){
+    std::vector< Node > terms;
+    terms.resize( q[0].getNumChildren() );
+    return addInstantiations( m, qe, q, terms, inst, 0 );
+  }
+  bool construct( FirstOrderModelAbs * m, TNode q, TNode n, AbsDef * f,
+                  std::map< unsigned, AbsDef * >& children,
+                  std::map< unsigned, int >& bchildren,
+                  std::map< unsigned, int >& vchildren,
+                  int varChCount );
+  void negate();
+  Node getFunctionValue( FirstOrderModelAbs * m, TNode op, std::vector< Node >& vars, unsigned depth = 0 );
+  static bool isSimple( unsigned n );
+  static unsigned getId( unsigned n, unsigned start=0, unsigned end=32 );
+  Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< Node >& args );
+  Node evaluate( FirstOrderModelAbs * m, TypeNode retType, std::vector< unsigned >& iargs, unsigned depth = 0 );
+  //for debugging
+  bool is_normalized();
+};
+
+class AbsMbqiBuilder : public QModelBuilder
+{
+  friend class AbsDef;
+private:
+  Node d_true;
+  Node d_false;
+  bool doCheck( FirstOrderModelAbs * m, TNode q, AbsDef & ad, TNode n );
+public:
+  AbsMbqiBuilder( context::Context* c, QuantifiersEngine* qe );
+
+  //process build model
+  bool processBuildModel(TheoryModel* m) override;
+  //do exhaustive instantiation
+  int doExhaustiveInstantiation(FirstOrderModel* fm,
+                                Node q,
+                                int effort) override;
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/fmf/bounded_integers.cpp b/src/theory/quantifiers/fmf/bounded_integers.cpp
new file mode 100644 (file)
index 0000000..b1e9c2a
--- /dev/null
@@ -0,0 +1,893 @@
+/*********************                                                        */
+/*! \file bounded_integers.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Morgan Deters, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Bounded integers module
+ **
+ ** This class manages integer bounds for quantifiers
+ **/
+
+#include "theory/quantifiers/fmf/bounded_integers.h"
+#include "options/quantifiers_options.h"
+#include "theory/arith/arith_msum.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/fmf/model_engine.h"
+#include "theory/quantifiers/term_enumeration.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/theory_engine.h"
+
+using namespace CVC4;
+using namespace std;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::kind;
+
+
+BoundedIntegers::IntRangeModel::IntRangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy) : d_bi(bi),
+      d_range(r), d_curr_max(-1), d_lit_to_range(u), d_range_assertions(c), d_has_range(c,false), d_curr_range(c,-1), d_ranges_proxied(u) { 
+  if( options::fmfBoundLazy() ){
+    d_proxy_range = isProxy ? r : NodeManager::currentNM()->mkSkolem( "pbir", r.getType() );
+  }else{
+    d_proxy_range = r;
+  }
+  if( !isProxy ){
+    Trace("bound-int") << "Introduce proxy " << d_proxy_range << " for " << d_range << std::endl;
+  }
+}
+
+void BoundedIntegers::IntRangeModel::initialize() {
+  //add initial split lemma
+  Node ltr = NodeManager::currentNM()->mkNode( LT, d_proxy_range, NodeManager::currentNM()->mkConst( Rational(0) ) );
+  ltr = Rewriter::rewrite( ltr );
+  Trace("bound-int-lemma") << " *** bound int: initial split on " << ltr << std::endl;
+  d_bi->getQuantifiersEngine()->getOutputChannel().split( ltr );
+  Node ltr_lit = ltr.getKind()==NOT ? ltr[0] : ltr;
+  d_range_literal[-1] = ltr_lit;
+  d_lit_to_range[ltr_lit] = -1;
+  d_lit_to_pol[ltr_lit] = ltr.getKind()!=NOT;
+  //register with bounded integers
+  Trace("bound-int-debug") << "Literal " << ltr_lit << " is literal for " << d_range << std::endl;
+  d_bi->addLiteralFromRange(ltr_lit, d_range);
+}
+
+void BoundedIntegers::IntRangeModel::assertNode(Node n) {
+  bool pol = n.getKind()!=NOT;
+  Node nlit = n.getKind()==NOT ? n[0] : n;
+  if( d_lit_to_range.find( nlit )!=d_lit_to_range.end() ){
+    int vrange = d_lit_to_range[nlit];
+    Trace("bound-int-assert") << "With polarity = " << pol << " (req "<< d_lit_to_pol[nlit] << ")";
+    Trace("bound-int-assert") << ", found literal " << nlit;
+    Trace("bound-int-assert") << ", it is bound literal " << vrange << " for " << d_range << std::endl;
+    d_range_assertions[nlit] = (pol==d_lit_to_pol[nlit]);
+    if( pol!=d_lit_to_pol[nlit] ){
+      //check if we need a new split?
+      if( !d_has_range ){
+        bool needsRange = true;
+        for( NodeIntMap::iterator it = d_lit_to_range.begin(); it != d_lit_to_range.end(); ++it ){
+          if( d_range_assertions.find( (*it).first )==d_range_assertions.end() ){
+            Trace("bound-int-debug") << "Does not need range because of " << (*it).first << std::endl;
+            needsRange = false;
+            break;
+          }
+        }
+        if( needsRange ){
+          allocateRange();
+        }
+      }
+    }else{
+      if (!d_has_range || vrange<d_curr_range ){
+        Trace("bound-int-bound") << "Successfully bound " << d_range << " to " << vrange << std::endl;
+        d_curr_range = vrange;
+      }
+      //set the range
+      d_has_range = true;
+    }
+  }else{
+    Message() << "Could not find literal " << nlit << " for range " << d_range << std::endl;
+    exit(0);
+  }
+}
+
+void BoundedIntegers::IntRangeModel::allocateRange() {
+  d_curr_max++;
+  int newBound = d_curr_max;
+  Trace("bound-int-proc") << "Allocate range bound " << newBound << " for " << d_range << std::endl;
+  //TODO: newBound should be chosen in a smarter way
+  Node ltr = NodeManager::currentNM()->mkNode( LEQ, d_proxy_range, NodeManager::currentNM()->mkConst( Rational(newBound) ) );
+  ltr = Rewriter::rewrite( ltr );
+  Trace("bound-int-lemma") << " *** bound int: split on " << ltr << std::endl;
+  d_bi->getQuantifiersEngine()->getOutputChannel().split( ltr );
+  Node ltr_lit = ltr.getKind()==NOT ? ltr[0] : ltr;
+  d_range_literal[newBound] = ltr_lit;
+  d_lit_to_range[ltr_lit] = newBound;
+  d_lit_to_pol[ltr_lit] = ltr.getKind()!=NOT;
+  //register with bounded integers
+  d_bi->addLiteralFromRange(ltr_lit, d_range);
+}
+
+Node BoundedIntegers::IntRangeModel::getNextDecisionRequest() {
+  //request the current cardinality as a decision literal, if not already asserted
+  for( NodeIntMap::iterator it = d_lit_to_range.begin(); it != d_lit_to_range.end(); ++it ){
+    int i = (*it).second;
+    if( !d_has_range || i<d_curr_range ){
+      Node rn = (*it).first;
+      Assert( !rn.isNull() );
+      if( d_range_assertions.find( rn )==d_range_assertions.end() ){
+        if (!d_lit_to_pol[rn]) {
+          rn = rn.negate();
+        }
+        Trace("bound-int-dec-debug") << "For " << d_range << ", make decision " << rn << " to make range " << i << std::endl;
+        return rn;
+      }
+    }
+  }
+  return Node::null();
+}
+
+bool BoundedIntegers::IntRangeModel::proxyCurrentRange() {
+  //Trace("model-engine") << "Range(" << d_range << ") currently is " << d_curr_max.get() << std::endl;
+  if( d_range!=d_proxy_range ){
+    //int curr = d_curr_range.get();
+    int curr = d_curr_max;
+    if( d_ranges_proxied.find( curr )==d_ranges_proxied.end() ){
+      d_ranges_proxied[curr] = true;
+      Assert( d_range_literal.find( curr )!=d_range_literal.end() );
+      Node lem = NodeManager::currentNM()->mkNode( EQUAL, d_range_literal[curr].negate(),
+                   NodeManager::currentNM()->mkNode( LEQ, d_range, NodeManager::currentNM()->mkConst( Rational(curr) ) ) );
+      Trace("bound-int-lemma") << "*** bound int : proxy lemma : " << lem << std::endl;
+      d_bi->getQuantifiersEngine()->addLemma( lem );
+      return true;
+    }
+  }
+  return false;
+}
+
+
+
+
+
+BoundedIntegers::BoundedIntegers(context::Context* c, QuantifiersEngine* qe) :
+QuantifiersModule(qe), d_assertions(c){
+
+}
+
+BoundedIntegers::~BoundedIntegers() { 
+  for( std::map< Node, RangeModel * >::iterator it = d_rms.begin(); it != d_rms.end(); ++it ){
+    delete it->second;
+  }
+}
+
+void BoundedIntegers::presolve() {
+  d_bnd_it.clear();
+}
+
+bool BoundedIntegers::isBound( Node f, Node v ) {
+  return std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end();
+}
+
+bool BoundedIntegers::hasNonBoundVar( Node f, Node b, std::map< Node, bool >& visited ) {
+  if( visited.find( b )==visited.end() ){
+    visited[b] = true;
+    if( b.getKind()==BOUND_VARIABLE ){
+      if( !isBound( f, b ) ){
+        return true;
+      }
+    }else{
+      for( unsigned i=0; i<b.getNumChildren(); i++ ){
+        if( hasNonBoundVar( f, b[i], visited ) ){
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+bool BoundedIntegers::hasNonBoundVar( Node f, Node b ) {
+  std::map< Node, bool > visited;
+  return hasNonBoundVar( f, b, visited );
+}
+
+bool BoundedIntegers::processEqDisjunct( Node q, Node n, Node& v, std::vector< Node >& v_cases ) {
+  if( n.getKind()==EQUAL ){
+    for( unsigned i=0; i<2; i++ ){
+      Node t = n[i];
+      if( !hasNonBoundVar( q, n[1-i] ) ){
+        if( t==v ){
+          v_cases.push_back( n[1-i] );
+          return true;
+        }else if( v.isNull() && t.getKind()==BOUND_VARIABLE ){
+          v = t;
+          v_cases.push_back( n[1-i] );
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+void BoundedIntegers::processMatchBoundVars( Node q, Node n, std::vector< Node >& bvs, std::map< Node, bool >& visited ){
+  if( visited.find( n )==visited.end() ){
+    visited[n] = true;
+    if( n.getKind()==BOUND_VARIABLE && !isBound( q, n ) ){
+      bvs.push_back( n );
+    //injective operators
+    }else if( n.getKind()==kind::APPLY_CONSTRUCTOR ){
+      for( unsigned i=0; i<n.getNumChildren(); i++ ){
+        processMatchBoundVars( q, n[i], bvs, visited );
+      }
+    }    
+  }
+}
+
+void BoundedIntegers::process( Node q, Node n, bool pol,
+                               std::map< Node, unsigned >& bound_lit_type_map,
+                               std::map< int, std::map< Node, Node > >& bound_lit_map,
+                               std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
+                               std::map< int, std::map< Node, Node > >& bound_int_range_term,
+                               std::map< Node, std::vector< Node > >& bound_fixed_set ){
+  if( n.getKind()==OR || n.getKind()==AND ){
+    if( (n.getKind()==OR)==pol ){
+      for( unsigned i=0; i<n.getNumChildren(); i++) {
+        process( q, n[i], pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set );
+      }
+    }else{
+      //if we are ( x != t1 ^ ...^ x != tn ), then x can be bound to { t1...tn }
+      Node conj = n;
+      if( !pol ){
+        conj = TermUtil::simpleNegate( conj );
+      }
+      Trace("bound-int-debug") << "Process possible finite disequality conjunction : " << conj << std::endl;
+      Assert( conj.getKind()==AND );
+      Node v;
+      std::vector< Node > v_cases;
+      bool success = true;
+      for( unsigned i=0; i<conj.getNumChildren(); i++ ){
+        if( conj[i].getKind()==NOT && processEqDisjunct( q, conj[i][0], v, v_cases ) ){
+          //continue
+        }else{
+          Trace("bound-int-debug") << "...failed due to " << conj[i] << std::endl;
+          success = false;
+          break;
+        }
+      }
+      if( success && !isBound( q, v ) ){
+        Trace("bound-int-debug") << "Success with variable " << v << std::endl;
+        bound_lit_type_map[v] = BOUND_FIXED_SET;
+        bound_lit_map[3][v] = n;
+        bound_lit_pol_map[3][v] = pol;
+        bound_fixed_set[v].clear();
+        bound_fixed_set[v].insert( bound_fixed_set[v].end(), v_cases.begin(), v_cases.end() );
+      }
+    }
+  }else if( n.getKind()==EQUAL ){
+    if( !pol ){
+      // non-applied DER on x != t, x can be bound to { t }
+      Node v;
+      std::vector< Node > v_cases;
+      if( processEqDisjunct( q, n, v, v_cases ) ){
+        if( !isBound( q, v ) ){
+          bound_lit_type_map[v] = BOUND_FIXED_SET;
+          bound_lit_map[3][v] = n;
+          bound_lit_pol_map[3][v] = pol;
+          Assert( v_cases.size()==1 );
+          bound_fixed_set[v].clear();
+          bound_fixed_set[v].push_back( v_cases[0] );
+        }
+      }
+    }  
+  }else if( n.getKind()==NOT ){
+    process( q, n[0], !pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set );
+  }else if( n.getKind()==GEQ ){
+    if( n[0].getType().isInteger() ){
+      std::map< Node, Node > msum;
+      if (ArithMSum::getMonomialSumLit(n, msum))
+      {
+        Trace("bound-int-debug") << "literal (polarity = " << pol << ") " << n << " is monomial sum : " << std::endl;
+        ArithMSum::debugPrintMonomialSum(msum, "bound-int-debug");
+        for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){
+          if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( q, it->first ) ){
+            //if not bound in another way
+            if( bound_lit_type_map.find( it->first )==bound_lit_type_map.end() || bound_lit_type_map[it->first] == BOUND_INT_RANGE ){
+              Node veq;
+              if (ArithMSum::isolate(it->first, msum, veq, GEQ) != 0)
+              {
+                Node n1 = veq[0];
+                Node n2 = veq[1];
+                if(pol){
+                  //flip
+                  n1 = veq[1];
+                  n2 = veq[0];
+                  if( n1.getKind()==BOUND_VARIABLE ){
+                    n2 = ArithMSum::offset(n2, 1);
+                  }else{
+                    n1 = ArithMSum::offset(n1, -1);
+                  }
+                  veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 );
+                }
+                Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl;
+                Node t = n1==it->first ? n2 : n1;
+                if( !hasNonBoundVar( q, t ) ) {
+                  Trace("bound-int-debug") << "The bound is relevant." << std::endl;
+                  int loru = n1==it->first ? 0 : 1;
+                  bound_lit_type_map[it->first] = BOUND_INT_RANGE;
+                  bound_int_range_term[loru][it->first] = t;
+                  bound_lit_map[loru][it->first] = n;
+                  bound_lit_pol_map[loru][it->first] = pol;
+                }else{
+                  Trace("bound-int-debug") << "The term " << t << " has non-bound variable." << std::endl;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }else if( n.getKind()==MEMBER ){
+    if( !pol && !hasNonBoundVar( q, n[1] ) ){
+      std::vector< Node > bound_vars;
+      std::map< Node, bool > visited;
+      processMatchBoundVars( q, n[0], bound_vars, visited );
+      for( unsigned i=0; i<bound_vars.size(); i++ ){
+        Node v = bound_vars[i];
+        Trace("bound-int-debug") << "literal (polarity = " << pol << ") " << n << " is membership." << std::endl;
+        bound_lit_type_map[v] = BOUND_SET_MEMBER;
+        bound_lit_map[2][v] = n;
+        bound_lit_pol_map[2][v] = pol;
+      }
+    }
+  }else{
+    Assert( n.getKind()!=LEQ && n.getKind()!=LT && n.getKind()!=GT );
+  }
+}
+
+bool BoundedIntegers::needsCheck( Theory::Effort e ) {
+  return e==Theory::EFFORT_LAST_CALL;
+}
+
+void BoundedIntegers::check(Theory::Effort e, QEffort quant_e)
+{
+  if (quant_e == QEFFORT_STANDARD)
+  {
+    Trace("bint-engine") << "---Bounded Integers---" << std::endl;
+    bool addedLemma = false;
+    //make sure proxies are up-to-date with range
+    for( unsigned i=0; i<d_ranges.size(); i++) {
+      if( d_rms[d_ranges[i]]->proxyCurrentRange() ){
+        addedLemma = true;
+      }
+    }
+    Trace("bint-engine") << "   addedLemma = " << addedLemma << std::endl;
+  }
+}
+
+
+void BoundedIntegers::addLiteralFromRange( Node lit, Node r ) {
+  d_lit_to_ranges[lit].push_back(r);
+  //check if it is already asserted?
+  if(d_assertions.find(lit)!=d_assertions.end()){
+    d_rms[r]->assertNode( d_assertions[lit] ? lit : lit.negate() );
+  }
+}
+
+void BoundedIntegers::setBoundedVar( Node q, Node v, unsigned bound_type ) {
+  d_bound_type[q][v] = bound_type;
+  d_set_nums[q][v] = d_set[q].size();
+  d_set[q].push_back( v );
+  Trace("bound-int-var") << "Bound variable #" << d_set_nums[q][v] << " : " << v << std::endl; 
+}
+
+void BoundedIntegers::preRegisterQuantifier( Node f ) {
+  //this needs to be done at preregister since it affects e.g. QuantDSplit's preregister
+  Trace("bound-int") << "preRegister quantifier " << f << std::endl;
+  
+  bool success;
+  do{
+    std::map< Node, unsigned > bound_lit_type_map;
+    std::map< int, std::map< Node, Node > > bound_lit_map;
+    std::map< int, std::map< Node, bool > > bound_lit_pol_map;
+    std::map< int, std::map< Node, Node > > bound_int_range_term;
+    std::map< Node, std::vector< Node > > bound_fixed_set;
+    success = false;
+    process( f, f[1], true, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term, bound_fixed_set );
+    //for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){
+    for( std::map< Node, unsigned >::iterator it = bound_lit_type_map.begin(); it != bound_lit_type_map.end(); ++it ){
+      Node v = it->first;
+      if( !isBound( f, v ) ){
+        bool setBoundVar = false;
+        if( it->second==BOUND_INT_RANGE ){
+          //must have both
+          if( bound_lit_map[0].find( v )!=bound_lit_map[0].end() && bound_lit_map[1].find( v )!=bound_lit_map[1].end() ){
+            setBoundedVar( f, v, BOUND_INT_RANGE );
+            setBoundVar = true;
+            for( unsigned b=0; b<2; b++ ){
+              //set the bounds
+              Assert( bound_int_range_term[b].find( v )!=bound_int_range_term[b].end() );
+              d_bounds[b][f][v] = bound_int_range_term[b][v];
+            }
+            if( options::fmfBoundMinMode()==FMF_BOUND_MIN_ALL || options::fmfBoundMinMode()==FMF_BOUND_MIN_INT_RANGE ){
+              Node r = NodeManager::currentNM()->mkNode( MINUS, d_bounds[1][f][v], d_bounds[0][f][v] );
+              d_range[f][v] = Rewriter::rewrite( r );
+            }
+            Trace("bound-int") << "Variable " << v << " is bound because of int range literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl;
+          }
+        }else if( it->second==BOUND_SET_MEMBER ){
+          setBoundedVar( f, v, BOUND_SET_MEMBER );
+          setBoundVar = true;
+          d_setm_range[f][v] = bound_lit_map[2][v][1];
+          d_setm_range_lit[f][v] = bound_lit_map[2][v];
+          if( options::fmfBoundMinMode()==FMF_BOUND_MIN_ALL || options::fmfBoundMinMode()==FMF_BOUND_MIN_SET_CARD ){
+            d_range[f][v] = NodeManager::currentNM()->mkNode( CARD, d_setm_range[f][v] );
+          }
+          Trace("bound-int") << "Variable " << v << " is bound because of set membership literal " << bound_lit_map[2][v] << std::endl;
+        }else if( it->second==BOUND_FIXED_SET ){
+          setBoundedVar( f, v, BOUND_FIXED_SET );
+          setBoundVar = true;
+          for( unsigned i=0; i<bound_fixed_set[v].size(); i++ ){
+            Node t = bound_fixed_set[v][i];
+            if( t.hasBoundVar() ){
+              d_fixed_set_ngr_range[f][v].push_back( t ); 
+            }else{
+              d_fixed_set_gr_range[f][v].push_back( t ); 
+            }
+          } 
+          Trace("bound-int") << "Variable " << v << " is bound because of disequality conjunction " << bound_lit_map[3][v] << std::endl;
+        }
+        if( setBoundVar ){
+          success = true;
+          //set Attributes on literals
+          for( unsigned b=0; b<2; b++ ){
+            if( bound_lit_map[b].find( v )!=bound_lit_map[b].end() ){
+              Assert( bound_lit_pol_map[b].find( v )!=bound_lit_pol_map[b].end() );
+              BoundIntLitAttribute bila;
+              bound_lit_map[b][v].setAttribute( bila, bound_lit_pol_map[b][v] ? 1 : 0 );
+            }else{
+              Assert( it->second!=BOUND_INT_RANGE );
+            }
+          }
+        }
+      }
+    }
+    if( !success ){
+      //resort to setting a finite bound on a variable
+      for( unsigned i=0; i<f[0].getNumChildren(); i++) {
+        if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){
+          TypeNode tn = f[0][i].getType();
+          if (tn.isSort()
+              || d_quantEngine->getTermEnumeration()->mayComplete(tn))
+          {
+            success = true;
+            setBoundedVar( f, f[0][i], BOUND_FINITE );
+            break;
+          }
+        }
+      }
+    }
+  }while( success );
+  
+  if( Trace.isOn("bound-int") ){
+    Trace("bound-int") << "Bounds are : " << std::endl;
+    for( unsigned i=0; i<f[0].getNumChildren(); i++) {
+      Node v = f[0][i];
+      if( std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end() ){
+        Assert( d_bound_type[f].find( v )!=d_bound_type[f].end() );
+        if( d_bound_type[f][v]==BOUND_INT_RANGE ){
+          Trace("bound-int") << "  " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl;
+        }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){
+          if( d_setm_range_lit[f][v][0]==v ){
+            Trace("bound-int") << "  " << v << " in " << d_setm_range[f][v] << std::endl;
+          }else{
+            Trace("bound-int") << "  " << v << " unifiable in " << d_setm_range_lit[f][v] << std::endl;
+          }
+        }else if( d_bound_type[f][v]==BOUND_FIXED_SET ){
+          Trace("bound-int") << "  " << v << " in { ";
+          for( unsigned i=0; i<d_fixed_set_ngr_range[f][v].size(); i++ ){ 
+            Trace("bound-int") << d_fixed_set_ngr_range[f][v][i] << " ";
+          }
+          for( unsigned i=0; i<d_fixed_set_gr_range[f][v].size(); i++ ){ 
+            Trace("bound-int") << d_fixed_set_gr_range[f][v][i] << " ";
+          }
+          Trace("bound-int") << "}" << std::endl;
+        }else if( d_bound_type[f][v]==BOUND_FINITE ){
+          Trace("bound-int") << "  " << v << " has small finite type." << std::endl;
+        }else{
+          Trace("bound-int") << "  " << v << " has unknown bound." << std::endl;
+          Assert( false );
+        }
+      }else{
+        Trace("bound-int") << "  " << "*** " << v << " is unbounded." << std::endl;
+      }
+    }
+  }
+  
+  bool bound_success = true;
+  for( unsigned i=0; i<f[0].getNumChildren(); i++) {
+    if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){
+      Trace("bound-int-warn") << "Warning : Bounded Integers : Due to quantification on " << f[0][i] << ", could not find bounds for " << f << std::endl;
+      bound_success = false;
+      break;
+    }
+  }
+  
+  if( bound_success ){
+    d_bound_quants.push_back( f );
+    for( unsigned i=0; i<d_set[f].size(); i++) {
+      Node v = d_set[f][i];
+      std::map< Node, Node >::iterator itr = d_range[f].find( v );
+      if( itr != d_range[f].end() ){
+        Node r = itr->second;
+        Assert( !r.isNull() );
+        bool isProxy = false;
+        if( r.hasBoundVar() ){
+          //introduce a new bound
+          Node new_range = NodeManager::currentNM()->mkSkolem( "bir", r.getType(), "bound for term" );
+          d_nground_range[f][v] = r;
+          d_range[f][v] = new_range;
+          r = new_range;
+          isProxy = true;
+        }
+        if( !r.isConst() ){
+          if( std::find(d_ranges.begin(), d_ranges.end(), r)==d_ranges.end() ){
+            Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << std::endl;
+            d_ranges.push_back( r );
+            d_rms[r] = new IntRangeModel( this, r, d_quantEngine->getSatContext(), d_quantEngine->getUserContext(), isProxy );
+            d_rms[r]->initialize();
+          }
+        }
+      }
+    }
+  }
+}
+
+void BoundedIntegers::registerQuantifier( Node q ) {
+
+}
+
+void BoundedIntegers::assertNode( Node n ) {
+  Trace("bound-int-assert") << "Assert " << n << std::endl;
+  Node nlit = n.getKind()==NOT ? n[0] : n;
+  if( d_lit_to_ranges.find(nlit)!=d_lit_to_ranges.end() ){
+    Trace("bound-int-assert") << "This is the bounding literal for " << d_lit_to_ranges[nlit].size() << " ranges." << std::endl;
+    for( unsigned i=0; i<d_lit_to_ranges[nlit].size(); i++) {
+      Node r = d_lit_to_ranges[nlit][i];
+      Trace("bound-int-assert") << "  ...this is a bounding literal for " << r << std::endl;
+      d_rms[r]->assertNode( n );
+    }
+  }
+  d_assertions[nlit] = n.getKind()!=NOT;
+}
+
+Node BoundedIntegers::getNextDecisionRequest( unsigned& priority ) {
+  Trace("bound-int-dec-debug") << "bi: Get next decision request?" << std::endl;
+  for( unsigned i=0; i<d_ranges.size(); i++) {
+    Node d = d_rms[d_ranges[i]]->getNextDecisionRequest();
+    if (!d.isNull()) {
+      bool polLit = d.getKind()!=NOT;
+      Node lit = d.getKind()==NOT ? d[0] : d;
+      bool value;
+      if( d_quantEngine->getValuation().hasSatValue( lit, value ) ) {
+        if( value==polLit ){
+          Trace("bound-int-dec-debug") << "...already asserted properly." << std::endl;
+          //already true, we're already fine
+        }else{
+          Trace("bound-int-dec-debug") << "...already asserted with wrong polarity, re-assert." << std::endl;
+          assertNode( d.negate() );
+          i--;
+        }
+      }else{
+        priority = 1;
+        Trace("bound-int-dec") << "Bounded Integers : Decide " << d << std::endl;
+        return d;
+      }
+    }
+  }
+  Trace("bound-int-dec-debug") << "No decision request." << std::endl;
+  return Node::null();
+}
+
+unsigned BoundedIntegers::getBoundVarType( Node q, Node v ) {
+  std::map< Node, unsigned >::iterator it = d_bound_type[q].find( v );
+  if( it==d_bound_type[q].end() ){
+    return BOUND_NONE;
+  }else{
+    return it->second;
+  }
+}
+
+void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
+  l = d_bounds[0][f][v];
+  u = d_bounds[1][f][v];
+  if( d_nground_range[f].find(v)!=d_nground_range[f].end() ){
+    //get the substitution
+    std::vector< Node > vars;
+    std::vector< Node > subs;
+    if( getRsiSubsitution( f, v, vars, subs, rsi ) ){
+      u = u.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+      l = l.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+    }else{
+      u = Node::null();
+      l = Node::null();
+    }
+  }
+}
+
+void BoundedIntegers::getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) {
+  getBounds( f, v, rsi, l, u );
+  Trace("bound-int-rsi") << "Get value in model for..." << l << " and " << u << std::endl;
+  if( !l.isNull() ){
+    l = d_quantEngine->getModel()->getValue( l );
+  }
+  if( !u.isNull() ){
+    u = d_quantEngine->getModel()->getValue( u );
+  }
+  Trace("bound-int-rsi") << "Value is " << l << " ... " << u << std::endl;
+  return;
+}
+
+bool BoundedIntegers::isGroundRange( Node q, Node v ) {
+  if( isBoundVar(q,v) ){
+    if( d_bound_type[q][v]==BOUND_INT_RANGE ){
+      return !getLowerBound(q,v).hasBoundVar() && !getUpperBound(q,v).hasBoundVar();
+    }else if( d_bound_type[q][v]==BOUND_SET_MEMBER ){
+      return !d_setm_range[q][v].hasBoundVar();
+    }else if( d_bound_type[q][v]==BOUND_FIXED_SET ){
+      return !d_fixed_set_ngr_range[q][v].empty();
+    }
+  }
+  return false;
+}
+
+Node BoundedIntegers::getSetRange( Node q, Node v, RepSetIterator * rsi ) {
+  Node sr = d_setm_range[q][v];
+  if( d_nground_range[q].find(v)!=d_nground_range[q].end() ){
+    //get the substitution
+    std::vector< Node > vars;
+    std::vector< Node > subs;
+    if( getRsiSubsitution( q, v, vars, subs, rsi ) ){
+      sr = sr.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+    }else{
+      sr = Node::null();
+    }
+  }
+  return sr;
+}
+
+Node BoundedIntegers::getSetRangeValue( Node q, Node v, RepSetIterator * rsi ) {
+  Node sr = getSetRange( q, v, rsi );
+  if( !sr.isNull() ){
+    Trace("bound-int-rsi") << "Get value in model for..." << sr << std::endl;
+    sr = d_quantEngine->getModel()->getValue( sr );
+    //if non-constant, then sr does not occur in the model, we fail
+    if( !sr.isConst() ){
+      return Node::null();
+    }
+    Trace("bound-int-rsi") << "Value is " << sr << std::endl;
+    //as heuristic, map to term model
+    if( sr.getKind()!=EMPTYSET ){
+      std::map< Node, Node > val_to_term;
+      while( sr.getKind()==UNION ){
+        Assert( sr[1].getKind()==kind::SINGLETON );
+        val_to_term[ sr[1][0] ] = sr[1][0];
+        sr = sr[0];
+      }
+      Assert( sr.getKind()==kind::SINGLETON );
+      val_to_term[ sr[0] ] = sr[0];
+      //must look back at assertions, not term database (theory of sets introduces extraneous terms internally)
+      Theory* theory = d_quantEngine->getTheoryEngine()->theoryOf( THEORY_SETS );
+      if( theory ){
+        context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end();
+        for( unsigned i = 0; it != it_end; ++ it, ++i ){
+          Node lit = (*it).assertion;
+          if( lit.getKind()==kind::MEMBER ){
+            Node vr = d_quantEngine->getModel()->getValue( lit[0] );
+            Trace("bound-int-rsi-debug") << "....membership for " << lit << " ==> " << vr << std::endl;
+            Trace("bound-int-rsi-debug") << "  " << (val_to_term.find( vr )!=val_to_term.end()) << " " << d_quantEngine->getEqualityQuery()->areEqual( d_setm_range_lit[q][v][1], lit[1] ) << std::endl;
+            if( val_to_term.find( vr )!=val_to_term.end() ){
+              if( d_quantEngine->getEqualityQuery()->areEqual( d_setm_range_lit[q][v][1], lit[1] ) ){
+                Trace("bound-int-rsi") << "  Map value to term : " << vr << " -> " << lit[0] << std::endl;
+                val_to_term[ vr ] = lit[0];
+              }
+            }
+          }
+        }
+      }
+      //rebuild value
+      Node nsr;
+      for( std::map< Node, Node >::iterator it = val_to_term.begin(); it != val_to_term.end(); ++it ){
+        Node nv = NodeManager::currentNM()->mkNode( kind::SINGLETON, it->second );
+        if( nsr.isNull() ){
+          nsr = nv;
+        }else{
+          nsr = NodeManager::currentNM()->mkNode( kind::UNION, nsr, nv );
+        }
+      }
+      Trace("bound-int-rsi") << "...reconstructed " << nsr << std::endl;
+      return nsr;
+      
+      /*
+      Node lit = d_setm_range_lit[q][v];
+      Trace("bound-int-rsi-debug") << "Bounded from lit " << lit << std::endl;
+      Node f = d_quantEngine->getTermDatabase()->getMatchOperator( lit );
+      TermArgTrie * ta = d_quantEngine->getTermDatabase()->getTermArgTrie( f );
+      if( ta ){
+        Trace("bound-int-rsi-debug") << "Got term index for " << f << std::endl;
+        for( std::map< TNode, TermArgTrie >::iterator it = ta->d_data.begin(); it != ta->d_data.end(); ++it ){
+
+        }
+
+      }
+      */
+    }
+    
+  }
+  return sr;
+}
+
+bool BoundedIntegers::getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi ) {
+
+  Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl;
+  Assert( d_set_nums[q].find( v )!=d_set_nums[q].end() );
+  int vindex = d_set_nums[q][v];
+  Assert( d_set_nums[q][v]==vindex );
+  Trace("bound-int-rsi-debug") << "  index order is " << vindex << std::endl;
+  //must take substitution for all variables that are iterating at higher level
+  for( int i=0; i<vindex; i++) {
+    Assert( d_set_nums[q][d_set[q][i]]==i );
+    Trace("bound-int-rsi") << "Look up the value for " << d_set[q][i] << " " << i << std::endl;
+    int v = rsi->getVariableOrder( i );
+    Assert( q[0][v]==d_set[q][i] );
+    Node t = rsi->getCurrentTerm(v, true);
+    Trace("bound-int-rsi") << "term : " << t << std::endl;
+    vars.push_back( d_set[q][i] );
+    subs.push_back( t );
+  }
+  
+  //check if it has been instantiated
+  if( !vars.empty() && !d_bnd_it[q][v].hasInstantiated(subs) ){
+    if( d_bound_type[q][v]==BOUND_INT_RANGE || d_bound_type[q][v]==BOUND_SET_MEMBER ){
+      //must add the lemma
+      Node nn = d_nground_range[q][v];
+      nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+      Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[q][v] );
+      Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl;
+      d_quantEngine->getOutputChannel().lemma(lem, false, true);
+    }
+    return false;
+  }else{
+    return true;
+  }
+}
+
+Node BoundedIntegers::matchBoundVar( Node v, Node t, Node e ){
+  if( t==v ){
+    return e;
+  }else if( t.getKind()==kind::APPLY_CONSTRUCTOR ){
+    if( e.getKind()==kind::APPLY_CONSTRUCTOR ){
+      if( t.getOperator() != e.getOperator() ) {
+        return Node::null();
+      }
+    }
+    const Datatype& dt = Datatype::datatypeOf( t.getOperator().toExpr() );
+    unsigned index = Datatype::indexOf( t.getOperator().toExpr() );
+    for( unsigned i=0; i<t.getNumChildren(); i++ ){
+      Node u;
+      if( e.getKind()==kind::APPLY_CONSTRUCTOR ){
+        u = matchBoundVar( v, t[i], e[i] );
+      }else{
+        Node se = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[index].getSelectorInternal( e.getType().toType(), i ) ), e );
+        u = matchBoundVar( v, t[i], se );
+      }
+      if( !u.isNull() ){
+        return u;
+      }
+    }
+  }
+  return Node::null();
+}
+
+bool BoundedIntegers::getBoundElements( RepSetIterator * rsi, bool initial, Node q, Node v, std::vector< Node >& elements ) {
+  if( initial || !isGroundRange( q, v ) ){
+    elements.clear();
+    unsigned bvt = getBoundVarType( q, v );
+    if( bvt==BOUND_INT_RANGE ){
+      Node l, u;
+      getBoundValues( q, v, rsi, l, u );
+      if( l.isNull() || u.isNull() ){
+        Trace("bound-int-warn") << "WARNING: Could not find integer bounds in model for " << v << " in " << q << std::endl;
+        //failed, abort the iterator
+        return false;
+      }else{
+        Trace("bound-int-rsi") << "Can limit bounds of " << v << " to " << l << "..." << u << std::endl;
+        Node range = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MINUS, u, l ) );
+        Node ra = Rewriter::rewrite( NodeManager::currentNM()->mkNode( LEQ, range, NodeManager::currentNM()->mkConst( Rational( 9999 ) ) ) );
+        Node tl = l;
+        Node tu = u;
+        getBounds( q, v, rsi, tl, tu );
+        Assert( !tl.isNull() && !tu.isNull() );
+        if( ra==d_quantEngine->getTermUtil()->d_true ){
+          long rr = range.getConst<Rational>().getNumerator().getLong()+1;
+          Trace("bound-int-rsi")  << "Actual bound range is " << rr << std::endl;
+          for( unsigned k=0; k<rr; k++ ){
+            Node t = NodeManager::currentNM()->mkNode(PLUS, tl, NodeManager::currentNM()->mkConst( Rational(k) ) );
+            t = Rewriter::rewrite( t );
+            elements.push_back( t );
+          }
+          return true;
+        }else{
+          Trace("fmf-incomplete") << "Incomplete because of integer quantification, bounds are too big for " << v << "." << std::endl;
+          return false;
+        }
+      }
+    }else if( bvt==BOUND_SET_MEMBER  ){ 
+      Node srv = getSetRangeValue( q, v, rsi );
+      if( srv.isNull() ){
+        Trace("bound-int-warn") << "WARNING: Could not find set bound in model for " << v << " in " << q << std::endl;
+        return false;
+      }else{
+        Trace("bound-int-rsi") << "Bounded by set membership : " << srv << std::endl;
+        if( srv.getKind()!=EMPTYSET ){
+          //collect the elements
+          while( srv.getKind()==UNION ){
+            Assert( srv[1].getKind()==kind::SINGLETON );
+            elements.push_back( srv[1][0] );
+            srv = srv[0];
+          }
+          Assert( srv.getKind()==kind::SINGLETON );
+          elements.push_back( srv[0] );
+          //check if we need to do matching, for literals like ( tuple( v ) in S )
+          Node t = d_setm_range_lit[q][v][0];
+          if( t!=v ){
+            std::vector< Node > elements_tmp;
+            elements_tmp.insert( elements_tmp.end(), elements.begin(), elements.end() );
+            elements.clear();
+            for( unsigned i=0; i<elements_tmp.size(); i++ ){
+              //do matching to determine v -> u
+              Node u = matchBoundVar( v, t, elements_tmp[i] );
+              Trace("bound-int-rsi-debug") << "  unification : " << elements_tmp[i] << " = " << t << " yields " << v << " -> " << u << std::endl;
+              if( !u.isNull() ){
+                elements.push_back( u );
+              }
+            }
+          }
+        }
+        return true;
+      }
+    }else if( bvt==BOUND_FIXED_SET ){
+      std::map< Node, std::vector< Node > >::iterator it = d_fixed_set_gr_range[q].find( v );
+      if( it!=d_fixed_set_gr_range[q].end() ){
+        for( unsigned i=0; i<it->second.size(); i++ ){
+          elements.push_back( it->second[i] );
+        }
+      }
+      it = d_fixed_set_ngr_range[q].find( v );
+      if( it!=d_fixed_set_ngr_range[q].end() ){
+        std::vector< Node > vars;
+        std::vector< Node > subs;
+        if( getRsiSubsitution( q, v, vars, subs, rsi ) ){
+          for( unsigned i=0; i<it->second.size(); i++ ){
+            Node t = it->second[i].substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+            elements.push_back( t );
+          }
+          return true;
+        }else{
+          return false;
+        }
+      }else{
+        return true;
+      }
+    }else{
+      return false;
+    }
+  }else{
+    //no change required
+    return true;
+  }
+}
+
diff --git a/src/theory/quantifiers/fmf/bounded_integers.h b/src/theory/quantifiers/fmf/bounded_integers.h
new file mode 100644 (file)
index 0000000..99d77a8
--- /dev/null
@@ -0,0 +1,181 @@
+/*********************                                                        */
+/*! \file bounded_integers.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Morgan Deters, Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+**/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__BOUNDED_INTEGERS_H
+#define __CVC4__BOUNDED_INTEGERS_H
+
+
+#include "theory/quantifiers_engine.h"
+
+#include "context/context.h"
+#include "context/context_mm.h"
+
+namespace CVC4 {
+namespace theory {
+
+class RepSetIterator;
+
+namespace quantifiers {
+
+
+class BoundedIntegers : public QuantifiersModule
+{
+  typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+  typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
+  typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
+  typedef context::CDHashMap<int, bool> IntBoolMap;
+public:
+  enum {
+    BOUND_FINITE,
+    BOUND_INT_RANGE,
+    BOUND_SET_MEMBER,
+    BOUND_FIXED_SET,
+    BOUND_NONE
+  };
+private:
+  //for determining bounds
+  bool isBound( Node f, Node v );
+  bool hasNonBoundVar( Node f, Node b, std::map< Node, bool >& visited );
+  bool hasNonBoundVar( Node f, Node b );
+  //bound type
+  std::map< Node, std::map< Node, unsigned > > d_bound_type;
+  std::map< Node, std::vector< Node > > d_set;
+  std::map< Node, std::map< Node, int > > d_set_nums;
+  std::map< Node, std::map< Node, Node > > d_range;
+  std::map< Node, std::map< Node, Node > > d_nground_range;
+  //integer lower/upper bounds
+  std::map< Node, std::map< Node, Node > > d_bounds[2];
+  //set membership range
+  std::map< Node, std::map< Node, Node > > d_setm_range;
+  std::map< Node, std::map< Node, Node > > d_setm_range_lit;
+  //fixed finite set range
+  std::map< Node, std::map< Node, std::vector< Node > > > d_fixed_set_gr_range;
+  std::map< Node, std::map< Node, std::vector< Node > > > d_fixed_set_ngr_range;
+  void hasFreeVar( Node f, Node n );
+  void process( Node q, Node n, bool pol,
+                std::map< Node, unsigned >& bound_lit_type_map,
+                std::map< int, std::map< Node, Node > >& bound_lit_map,
+                std::map< int, std::map< Node, bool > >& bound_lit_pol_map,
+                std::map< int, std::map< Node, Node > >& bound_int_range_term,
+                std::map< Node, std::vector< Node > >& bound_fixed_set );
+  bool processEqDisjunct( Node q, Node n, Node& v, std::vector< Node >& v_cases );
+  void processMatchBoundVars( Node q, Node n, std::vector< Node >& bvs, std::map< Node, bool >& visited );
+  std::vector< Node > d_bound_quants;
+private:
+  class RangeModel {
+  public:
+    RangeModel(){}
+    virtual ~RangeModel(){}
+    virtual void initialize() = 0;
+    virtual void assertNode(Node n) = 0;
+    virtual Node getNextDecisionRequest() = 0;
+    virtual bool proxyCurrentRange() = 0;
+  };
+  class IntRangeModel : public RangeModel {
+  private:
+    BoundedIntegers * d_bi;
+    void allocateRange();
+    Node d_proxy_range;
+  public:
+    IntRangeModel( BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy);
+    virtual ~IntRangeModel(){}
+    Node d_range;
+    int d_curr_max;
+    std::map< int, Node > d_range_literal;
+    std::map< Node, bool > d_lit_to_pol;
+    NodeIntMap d_lit_to_range;
+    NodeBoolMap d_range_assertions;
+    context::CDO< bool > d_has_range;
+    context::CDO< int > d_curr_range;
+    IntBoolMap d_ranges_proxied;
+    void initialize();
+    void assertNode(Node n);
+    Node getNextDecisionRequest();
+    bool proxyCurrentRange();
+  };
+private:
+  //information for minimizing ranges
+  std::vector< Node > d_ranges;
+  //map to range model objects
+  std::map< Node, RangeModel * > d_rms;
+  //literal to range
+  std::map< Node, std::vector< Node > > d_lit_to_ranges;
+  //list of currently asserted arithmetic literals
+  NodeBoolMap d_assertions;
+private:
+  //class to store whether bounding lemmas have been added
+  class BoundInstTrie
+  {
+  public:
+    std::map< Node, BoundInstTrie > d_children;
+    bool hasInstantiated( std::vector< Node > & vals, int index = 0, bool madeNew = false ){
+      if( index>=(int)vals.size() ){
+        return !madeNew;
+      }else{
+        Node n = vals[index];
+        if( d_children.find(n)==d_children.end() ){
+          madeNew = true;
+        }
+        return d_children[n].hasInstantiated(vals,index+1,madeNew);
+      }
+    }
+  };
+  std::map< Node, std::map< Node, BoundInstTrie > > d_bnd_it;
+private:
+  void addLiteralFromRange( Node lit, Node r );
+  
+  void setBoundedVar( Node f, Node v, unsigned bound_type );
+public:
+  BoundedIntegers( context::Context* c, QuantifiersEngine* qe );
+  virtual ~BoundedIntegers();
+  
+  void presolve();
+  bool needsCheck( Theory::Effort e );
+  void check(Theory::Effort e, QEffort quant_e);
+  void registerQuantifier( Node q );
+  void preRegisterQuantifier( Node q );
+  void assertNode( Node n );
+  Node getNextDecisionRequest( unsigned& priority );
+  bool isBoundVar( Node q, Node v ) { return std::find( d_set[q].begin(), d_set[q].end(), v )!=d_set[q].end(); }
+  unsigned getBoundVarType( Node q, Node v );
+  unsigned getNumBoundVars( Node q ) { return d_set[q].size(); }
+  Node getBoundVar( Node q, int i ) { return d_set[q][i]; }
+private:
+  //for integer range
+  Node getLowerBound( Node q, Node v ){ return d_bounds[0][q][v]; }
+  Node getUpperBound( Node q, Node v ){ return d_bounds[1][q][v]; }
+  void getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u );
+  void getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u );
+  bool isGroundRange(Node f, Node v);
+  //for set range
+  Node getSetRange( Node q, Node v, RepSetIterator * rsi );
+  Node getSetRangeValue( Node q, Node v, RepSetIterator * rsi );
+  Node matchBoundVar( Node v, Node t, Node e );
+  
+  bool getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi );
+public:
+  bool getBoundElements( RepSetIterator * rsi, bool initial, Node q, Node v, std::vector< Node >& elements );
+
+  /** Identify this module */
+  std::string identify() const { return "BoundedIntegers"; }
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/fmf/full_model_check.cpp b/src/theory/quantifiers/fmf/full_model_check.cpp
new file mode 100644 (file)
index 0000000..d6957b2
--- /dev/null
@@ -0,0 +1,1518 @@
+/*********************                                                        */
+/*! \file full_model_check.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Morgan Deters, Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of full model check class
+ **/
+
+#include "theory/quantifiers/fmf/full_model_check.h"
+#include "options/quantifiers_options.h"
+#include "options/uf_options.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/instantiate.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::theory::inst;
+using namespace CVC4::theory::quantifiers::fmcheck;
+
+struct ModelBasisArgSort
+{
+  std::vector< Node > d_terms;
+  // number of arguments that are model-basis terms
+  std::unordered_map<Node, unsigned, NodeHashFunction> d_mba_count;
+  bool operator() (int i,int j) {
+    return (d_mba_count[d_terms[i]] < d_mba_count[d_terms[j]]);
+  }
+};
+
+
+struct ConstRationalSort
+{
+  std::vector< Node > d_terms;
+  bool operator() (int i, int j) {
+    return (d_terms[i].getConst<Rational>() < d_terms[j].getConst<Rational>() );
+  }
+};
+
+
+bool EntryTrie::hasGeneralization( FirstOrderModelFmc * m, Node c, int index ) {
+  if (index==(int)c.getNumChildren()) {
+    return d_data!=-1;
+  }else{
+    TypeNode tn = c[index].getType();
+    Node st = m->getStar(tn);
+    if(d_child.find(st)!=d_child.end()) {
+      if( d_child[st].hasGeneralization(m, c, index+1) ){
+        return true;
+      }
+    }
+    if( c[index]!=st && d_child.find( c[index] )!=d_child.end() ){
+      if( d_child[ c[index] ].hasGeneralization(m, c, index+1) ){
+        return true;
+      }
+    }
+    if( c[index].getType().isSort() ){
+      //for star: check if all children are defined and have generalizations
+      if( c[index]==st ){     ///options::fmfFmcCoverSimplify()
+        //check if all children exist and are complete
+        unsigned num_child_def =
+            d_child.size() - (d_child.find(st) != d_child.end() ? 1 : 0);
+        if (num_child_def == m->getRepSet()->getNumRepresentatives(tn))
+        {
+          bool complete = true;
+          for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+            if( !m->isStar(it->first) ){
+              if( !it->second.hasGeneralization(m, c, index+1) ){
+                complete = false;
+                break;
+              }
+            }
+          }
+          if( complete ){
+            return true;
+          }
+        }
+      }
+    }
+
+    return false;
+  }
+}
+
+int EntryTrie::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node> & inst, int index ) {
+  Debug("fmc-entry-trie") << "Get generalization index " << inst.size() << " " << index << std::endl;
+  if (index==(int)inst.size()) {
+    return d_data;
+  }else{
+    int minIndex = -1;
+    if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && inst[index].getType().isInteger() ){
+      for( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+        //if( !m->isInterval( it->first ) ){
+        //  std::cout << "Not an interval during getGenIndex " << it->first << std::endl;
+        //  exit( 11 );
+        //}
+        //check if it is in the range
+        if( m->isInRange(inst[index], it->first )  ){
+          int gindex = it->second.getGeneralizationIndex(m, inst, index+1);
+          if( minIndex==-1 || (gindex!=-1 && gindex<minIndex) ){
+            minIndex = gindex;
+          }
+        }
+      }
+    }else{
+      Node st = m->getStar(inst[index].getType());
+      if(d_child.find(st)!=d_child.end()) {
+        minIndex = d_child[st].getGeneralizationIndex(m, inst, index+1);
+      }
+      Node cc = inst[index];
+      if( cc!=st && d_child.find( cc )!=d_child.end() ){
+        int gindex = d_child[ cc ].getGeneralizationIndex(m, inst, index+1);
+        if (minIndex==-1 || (gindex!=-1 && gindex<minIndex) ){
+          minIndex = gindex;
+        }
+      }
+    }
+    return minIndex;
+  }
+}
+
+void EntryTrie::addEntry( FirstOrderModelFmc * m, Node c, Node v, int data, int index ) {
+  if (index==(int)c.getNumChildren()) {
+    if(d_data==-1) {
+      d_data = data;
+    }
+  }
+  else {
+    d_child[ c[index] ].addEntry(m,c,v,data,index+1);
+    if( d_complete==0 ){
+      d_complete = -1;
+    }
+  }
+}
+
+void EntryTrie::getEntries( FirstOrderModelFmc * m, Node c, std::vector<int> & compat, std::vector<int> & gen, int index, bool is_gen ) {
+  if (index==(int)c.getNumChildren()) {
+    if( d_data!=-1) {
+      if( is_gen ){
+        gen.push_back(d_data);
+      }
+      compat.push_back(d_data);
+    }
+  }else{
+    if (m->isStar(c[index])) {
+      for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+        it->second.getEntries(m, c, compat, gen, index+1, is_gen );
+      }
+    }else{
+      Node st = m->getStar(c[index].getType());
+      if(d_child.find(st)!=d_child.end()) {
+        d_child[st].getEntries(m, c, compat, gen, index+1, false);
+      }
+      if( d_child.find( c[index] )!=d_child.end() ){
+        d_child[ c[index] ].getEntries(m, c, compat, gen, index+1, is_gen);
+      }
+    }
+
+  }
+}
+
+void EntryTrie::collectIndices(Node c, int index, std::vector< int >& indices ) {
+  if (index==(int)c.getNumChildren()) {
+    if( d_data!=-1 ){
+      indices.push_back( d_data );
+    }
+  }else{
+    for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
+      it->second.collectIndices(c, index+1, indices );
+    }
+  }
+}
+
+bool EntryTrie::isComplete(FirstOrderModelFmc * m, Node c, int index) {
+  if( d_complete==-1 ){
+    d_complete = 1;
+    if (index<(int)c.getNumChildren()) {
+      Node st = m->getStar(c[index].getType());
+      if(d_child.find(st)!=d_child.end()) {
+        if (!d_child[st].isComplete(m, c, index+1)) {
+          d_complete = 0;
+        }
+      }else{
+        d_complete = 0;
+      }
+    }
+  }
+  return d_complete==1;
+}
+
+bool Def::addEntry( FirstOrderModelFmc * m, Node c, Node v) {
+  if (d_et.hasGeneralization(m, c)) {
+    Trace("fmc-debug") << "Already has generalization, skip." << std::endl;
+    return false;
+  }
+  int newIndex = (int)d_cond.size();
+  if (!d_has_simplified) {
+    std::vector<int> compat;
+    std::vector<int> gen;
+    d_et.getEntries(m, c, compat, gen);
+    for( unsigned i=0; i<compat.size(); i++) {
+      if( d_status[compat[i]]==status_unk ){
+        if( d_value[compat[i]]!=v ){
+          d_status[compat[i]] = status_non_redundant;
+        }
+      }
+    }
+    for( unsigned i=0; i<gen.size(); i++) {
+      if( d_status[gen[i]]==status_unk ){
+        if( d_value[gen[i]]==v ){
+          d_status[gen[i]] = status_redundant;
+        }
+      }
+    }
+    d_status.push_back( status_unk );
+  }
+  d_et.addEntry(m, c, v, newIndex);
+  d_cond.push_back(c);
+  d_value.push_back(v);
+  return true;
+}
+
+Node Def::evaluate( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
+  int gindex = d_et.getGeneralizationIndex(m, inst);
+  if (gindex!=-1) {
+    return d_value[gindex];
+  }else{
+    Trace("fmc-warn") << "Warning : evaluation came up null!" << std::endl;
+    return Node::null();
+  }
+}
+
+int Def::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
+  return d_et.getGeneralizationIndex(m, inst);
+}
+
+void Def::basic_simplify( FirstOrderModelFmc * m ) {
+  d_has_simplified = true;
+  std::vector< Node > cond;
+  cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
+  d_cond.clear();
+  std::vector< Node > value;
+  value.insert( value.end(), d_value.begin(), d_value.end() );
+  d_value.clear();
+  d_et.reset();
+  for (unsigned i=0; i<d_status.size(); i++) {
+    if( d_status[i]!=status_redundant ){
+      addEntry(m, cond[i], value[i]);
+    }
+  }
+  d_status.clear();
+}
+
+void Def::simplify(FullModelChecker * mc, FirstOrderModelFmc * m) {
+  Trace("fmc-simplify") << "Simplify definition, #cond = " << d_cond.size() << std::endl;
+  basic_simplify( m );
+  Trace("fmc-simplify") << "post-basic simplify, #cond = " << d_cond.size() << std::endl;
+
+  //check if the last entry is not all star, if so, we can make the last entry all stars
+  if( !d_cond.empty() ){
+    bool last_all_stars = true;
+    Node cc = d_cond[d_cond.size()-1];
+    for( unsigned i=0; i<cc.getNumChildren(); i++ ){
+      if( !m->isInterval(cc[i]) && !m->isStar(cc[i]) ){
+        last_all_stars = false;
+        break;
+      }
+    }
+    if( !last_all_stars ){
+      Trace("fmc-cover-simplify") << "Need to modify last entry to be all stars." << std::endl;
+      Trace("fmc-cover-simplify") << "Before: " << std::endl;
+      debugPrint("fmc-cover-simplify",Node::null(), mc);
+      Trace("fmc-cover-simplify") << std::endl;
+      std::vector< Node > cond;
+      cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
+      d_cond.clear();
+      std::vector< Node > value;
+      value.insert( value.end(), d_value.begin(), d_value.end() );
+      d_value.clear();
+      d_et.reset();
+      d_has_simplified = false;
+      //change the last to all star
+      std::vector< Node > nc;
+      nc.push_back( cc.getOperator() );
+      for( unsigned j=0; j< cc.getNumChildren(); j++){
+        nc.push_back(m->getStarElement(cc[j].getType()));
+      }
+      cond[cond.size()-1] = NodeManager::currentNM()->mkNode( APPLY_UF, nc );
+      //re-add the entries
+      for (unsigned i=0; i<cond.size(); i++) {
+        addEntry(m, cond[i], value[i]);
+      }
+      Trace("fmc-cover-simplify") << "Finished re-adding entries." << std::endl;
+      basic_simplify( m );
+      Trace("fmc-cover-simplify") << "After: " << std::endl;
+      debugPrint("fmc-cover-simplify",Node::null(), mc);
+      Trace("fmc-cover-simplify") << std::endl;
+    }
+  }
+  Trace("fmc-simplify") << "finish simplify, #cond = " << d_cond.size() << std::endl;
+}
+
+void Def::debugPrint(const char * tr, Node op, FullModelChecker * m) {
+  if (!op.isNull()) {
+    Trace(tr) << "Model for " << op << " : " << std::endl;
+  }
+  for( unsigned i=0; i<d_cond.size(); i++) {
+    //print the condition
+    if (!op.isNull()) {
+      Trace(tr) << op;
+    }
+    m->debugPrintCond(tr, d_cond[i], true);
+    Trace(tr) << " -> ";
+    m->debugPrint(tr, d_value[i]);
+    Trace(tr) << std::endl;
+  }
+}
+
+
+FullModelChecker::FullModelChecker(context::Context* c, QuantifiersEngine* qe) :
+QModelBuilder( c, qe ){
+  d_true = NodeManager::currentNM()->mkConst(true);
+  d_false = NodeManager::currentNM()->mkConst(false);
+}
+
+bool FullModelChecker::preProcessBuildModel(TheoryModel* m) {
+  //standard pre-process
+  if( !preProcessBuildModelStd( m ) ){
+    return false;
+  }
+  
+  FirstOrderModelFmc * fm = ((FirstOrderModelFmc*)m)->asFirstOrderModelFmc();
+  Trace("fmc") << "---Full Model Check preprocess() " << std::endl;
+  d_preinitialized_types.clear();
+  //traverse equality engine
+  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( fm->d_equalityEngine );
+  while( !eqcs_i.isFinished() ){
+    TypeNode tr = (*eqcs_i).getType();
+    d_preinitialized_types[tr] = true;
+    ++eqcs_i;
+  }
+
+  //must ensure model basis terms exists in model for each relevant type
+  fm->initialize();
+  for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+    Node op = it->first;
+    TypeNode tno = op.getType();
+    for( unsigned i=0; i<tno.getNumChildren(); i++) {
+      preInitializeType( fm, tno[i] );
+    }
+  }
+  //do not have to introduce terms for sorts of domains of quantified formulas if we are allowed to assume empty sorts
+  if( !options::fmfEmptySorts() ){
+    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+      Node q = fm->getAssertedQuantifier( i );
+      //make sure all types are set
+      for( unsigned j=0; j<q[0].getNumChildren(); j++ ){
+        preInitializeType( fm, q[0][j].getType() );
+      }
+    }
+  }
+  return true;
+}
+
+bool FullModelChecker::processBuildModel(TheoryModel* m){
+  FirstOrderModelFmc * fm = ((FirstOrderModelFmc*)m)->asFirstOrderModelFmc();
+  Trace("fmc") << "---Full Model Check reset() " << std::endl;
+  d_quant_models.clear();
+  d_rep_ids.clear();
+  d_star_insts.clear();
+  //process representatives
+  RepSet* rs = fm->getRepSetPtr();
+  for (std::map<TypeNode, std::vector<Node> >::iterator it =
+           rs->d_type_reps.begin();
+       it != rs->d_type_reps.end();
+       ++it)
+  {
+    if( it->first.isSort() ){
+      Trace("fmc") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
+      for( size_t a=0; a<it->second.size(); a++ ){
+        Node r = fm->getRepresentative( it->second[a] );
+        if( Trace.isOn("fmc-model-debug") ){
+          std::vector< Node > eqc;
+          d_qe->getEqualityQuery()->getEquivalenceClass( r, eqc );
+          Trace("fmc-model-debug") << "   " << (it->second[a]==r);
+          Trace("fmc-model-debug") << " : " << it->second[a] << " : " << r << " : ";
+          //Trace("fmc-model-debug") << r2 << " : " << ir << " : ";
+          Trace("fmc-model-debug") << " {";
+          for( size_t i=0; i<eqc.size(); i++ ){
+            Trace("fmc-model-debug") << eqc[i] << ", ";
+          }
+          Trace("fmc-model-debug") << "}" << std::endl;
+        }
+        d_rep_ids[it->first][r] = (int)a;
+      }
+      Trace("fmc-model-debug") << std::endl;
+    }
+  }
+
+  //now, make models
+  for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+    Node op = it->first;
+    //reset the model
+    fm->d_models[op]->reset();
+
+    std::vector< Node > add_conds;
+    std::vector< Node > add_values;      
+    bool needsDefault = true;
+    std::map< Node, std::vector< Node > >::iterator itut = fm->d_uf_terms.find( op );
+    if( itut!=fm->d_uf_terms.end() ){
+      Trace("fmc-model-debug") << itut->second.size() << " model values for " << op << " ... " << std::endl;
+      for( size_t i=0; i<itut->second.size(); i++ ){
+        Node n = itut->second[i];
+        // only consider unique up to congruence (in model equality engine)?
+        add_conds.push_back( n );
+        add_values.push_back( n );
+        Node r = fm->getRepresentative(n);
+        Trace("fmc-model-debug") << n << " -> " << r << std::endl;
+        //AlwaysAssert( fm->areEqual( itut->second[i], r ) );
+      }
+    }else{
+      Trace("fmc-model-debug") << "No model values for " << op << " ... " << std::endl;
+    }
+    Trace("fmc-model-debug") << std::endl;
+    //possibly get default
+    if( needsDefault ){
+      Node nmb = fm->getModelBasisOpTerm(op);
+      //add default value if necessary
+      if( fm->hasTerm( nmb ) ){
+        Trace("fmc-model-debug") << "Add default " << nmb << std::endl;
+        add_conds.push_back( nmb );
+        add_values.push_back( nmb );
+      }else{
+        Node vmb = getSomeDomainElement(fm, nmb.getType());
+        Trace("fmc-model-debug") << "Add default to default representative " << nmb << " ";
+        Trace("fmc-model-debug")
+            << fm->getRepSet()->getNumRepresentatives(nmb.getType())
+            << std::endl;
+        add_conds.push_back( nmb );
+        add_values.push_back( vmb );
+      }
+    }
+
+    std::vector< Node > conds;
+    std::vector< Node > values;
+    std::vector< Node > entry_conds;
+    //get the entries for the model
+    for( size_t i=0; i<add_conds.size(); i++ ){
+      Node c = add_conds[i];
+      Node v = add_values[i];
+      std::vector< Node > children;
+      std::vector< Node > entry_children;
+      children.push_back(op);
+      entry_children.push_back(op);
+      bool hasNonStar = false;
+      for( unsigned i=0; i<c.getNumChildren(); i++) {
+        Node ri = fm->getRepresentative( c[i] );
+        children.push_back(ri);
+        bool isStar = false;
+        if( options::mbqiMode()!=quantifiers::MBQI_FMC_INTERVAL || !ri.getType().isInteger() ){
+          if (fm->isModelBasisTerm(ri) ) {
+            ri = fm->getStar( ri.getType() );
+            isStar = true;
+          }else{
+            hasNonStar = true;
+          }
+        }
+        if( !isStar && !ri.isConst() ){
+          Trace("fmc-warn") << "Warning : model for " << op << " has non-constant argument in model " << ri << " (from " << c[i] << ")" << std::endl;
+          Assert( false );
+        }
+        entry_children.push_back(ri);
+      }
+      Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+      Node nv = fm->getRepresentative( v );
+      if( !nv.isConst() ){
+        Trace("fmc-warn") << "Warning : model for " << op << " has non-constant value in model " << nv << std::endl;
+        Assert( false );
+      }
+      Node en = (useSimpleModels() && hasNonStar) ? n : NodeManager::currentNM()->mkNode( APPLY_UF, entry_children );
+      if( std::find(conds.begin(), conds.end(), n )==conds.end() ){
+        Trace("fmc-model-debug") << "- add " << n << " -> " << nv << " (entry is " << en << ")" << std::endl;
+        conds.push_back(n);
+        values.push_back(nv);
+        entry_conds.push_back(en);
+      }
+      else {
+        Trace("fmc-model-debug") << "Already have entry for : " << n << " -> " << nv << " (entry is " << en << ")" << std::endl;
+      }
+    }
+
+
+    //sort based on # default arguments
+    std::vector< int > indices;
+    ModelBasisArgSort mbas;
+    for (int i=0; i<(int)conds.size(); i++) {
+      mbas.d_terms.push_back(conds[i]);
+      mbas.d_mba_count[conds[i]] = fm->getModelBasisArg(conds[i]);
+      indices.push_back(i);
+    }
+    std::sort( indices.begin(), indices.end(), mbas );
+
+    for (int i=0; i<(int)indices.size(); i++) {
+      fm->d_models[op]->addEntry(fm, entry_conds[indices[i]], values[indices[i]]);
+    }
+
+
+    if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL ){
+      convertIntervalModel( fm, op );
+    }
+
+    Trace("fmc-model-simplify") << "Before simplification : " << std::endl;
+    fm->d_models[op]->debugPrint("fmc-model-simplify", op, this);
+    Trace("fmc-model-simplify") << std::endl;
+
+    Trace("fmc-model-simplify") << "Simplifying " << op << "..." << std::endl;
+    fm->d_models[op]->simplify( this, fm );
+
+    fm->d_models[op]->debugPrint("fmc-model", op, this);
+    Trace("fmc-model") << std::endl;
+
+    //for debugging
+    /*
+    for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
+      std::vector< Node > inst;
+      for( unsigned j=0; j<fm->d_uf_terms[op][i].getNumChildren(); j++ ){
+        Node r = fm->getRepresentative( fm->d_uf_terms[op][i][j] );
+        inst.push_back( r );
+      }
+      Node ev = fm->d_models[op]->evaluate( fm, inst );
+      Trace("fmc-model-debug") << ".....Checking eval( " << fm->d_uf_terms[op][i] << " ) = " << ev << std::endl;
+      AlwaysAssert( fm->areEqual( ev, fm->d_uf_terms[op][i] ) );
+    }
+    */
+  }
+  Assert( d_addedLemmas==0 );
+  
+  //make function values
+  for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ){
+    Node f_def = getFunctionValue( fm, it->first, "$x" );
+    m->assignFunctionDefinition( it->first, f_def );
+  }
+  return TheoryEngineModelBuilder::processBuildModel( m );
+}
+
+void FullModelChecker::preInitializeType( FirstOrderModelFmc * fm, TypeNode tn ){
+  if( d_preinitialized_types.find( tn )==d_preinitialized_types.end() ){
+    d_preinitialized_types[tn] = true;
+    if (!tn.isFunction() || options::ufHo())
+    {
+      Node mb = fm->getModelBasisTerm(tn);
+      if (!mb.isConst())
+      {
+        Trace("fmc") << "...add model basis term to EE of model " << mb << " "
+                     << tn << std::endl;
+        fm->d_equalityEngine->addTerm(mb);
+      }
+    }
+  }
+}
+
+void FullModelChecker::debugPrintCond(const char * tr, Node n, bool dispStar) {
+  Trace(tr) << "(";
+  for( unsigned j=0; j<n.getNumChildren(); j++) {
+    if( j>0 ) Trace(tr) << ", ";
+    debugPrint(tr, n[j], dispStar);
+  }
+  Trace(tr) << ")";
+}
+
+void FullModelChecker::debugPrint(const char * tr, Node n, bool dispStar) {
+  FirstOrderModelFmc * fm = (FirstOrderModelFmc *)d_qe->getModel();
+  if( n.isNull() ){
+    Trace(tr) << "null";
+  }
+  else if(fm->isStar(n) && dispStar) {
+    Trace(tr) << "*";
+  }
+  else if(fm->isInterval(n)) {
+    debugPrint(tr, n[0], dispStar );
+    Trace(tr) << "...";
+    debugPrint(tr, n[1], dispStar );
+  }else{
+    TypeNode tn = n.getType();
+    if( tn.isSort() && d_rep_ids.find(tn)!=d_rep_ids.end() ){
+      if (d_rep_ids[tn].find(n)!=d_rep_ids[tn].end()) {
+        Trace(tr) << d_rep_ids[tn][n];
+      }else{
+        Trace(tr) << n;
+      }
+    }else{
+      Trace(tr) << n;
+    }
+  }
+}
+
+
+int FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
+  Trace("fmc") << "Full model check " << f << ", effort = " << effort << "..." << std::endl;
+  Assert( !d_qe->inConflict() );
+  if( optUseModel() ){
+    FirstOrderModelFmc * fmfmc = fm->asFirstOrderModelFmc();
+    if (effort==0) {
+      //register the quantifier
+      if (d_quant_cond.find(f)==d_quant_cond.end()) {
+        std::vector< TypeNode > types;
+        for(unsigned i=0; i<f[0].getNumChildren(); i++){
+          types.push_back(f[0][i].getType());
+        }
+        TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->booleanType() );
+        Node op = NodeManager::currentNM()->mkSkolem( "qfmc", typ, "op created for full-model checking" );
+        d_quant_cond[f] = op;
+      }
+
+      if( options::mbqiMode()==MBQI_NONE ){
+        //just exhaustive instantiate
+        Node c = mkCondDefault( fmfmc, f );
+        d_quant_models[f].addEntry( fmfmc, c, d_false );
+        return exhaustiveInstantiate( fmfmc, f, c, -1);
+      }else{
+        //model check the quantifier
+        doCheck(fmfmc, f, d_quant_models[f], f[1]);
+        Trace("fmc") << "Definition for quantifier " << f << " is : " << std::endl;
+        Assert( !d_quant_models[f].d_cond.empty() );
+        d_quant_models[f].debugPrint("fmc", Node::null(), this);
+        Trace("fmc") << std::endl;
+
+        //consider all entries going to non-true
+        for (unsigned i=0; i<d_quant_models[f].d_cond.size(); i++) {
+          if( d_quant_models[f].d_value[i]!=d_true ) {
+            Trace("fmc-inst") << "Instantiate based on " << d_quant_models[f].d_cond[i] << "..." << std::endl;
+            bool hasStar = false;
+            std::vector< Node > inst;
+            for (unsigned j=0; j<d_quant_models[f].d_cond[i].getNumChildren(); j++) {
+              if (fmfmc->isStar(d_quant_models[f].d_cond[i][j])) {
+                hasStar = true;
+                inst.push_back(fmfmc->getModelBasisTerm(d_quant_models[f].d_cond[i][j].getType()));
+              }else if( fmfmc->isInterval(d_quant_models[f].d_cond[i][j])){
+                hasStar = true;
+                //if interval, find a sample point
+                if( fmfmc->isStar(d_quant_models[f].d_cond[i][j][0]) ){
+                  if( fmfmc->isStar(d_quant_models[f].d_cond[i][j][1]) ){
+                    inst.push_back(fmfmc->getModelBasisTerm(d_quant_models[f].d_cond[i][j][1].getType()));
+                  }else{
+                    Node nn = NodeManager::currentNM()->mkNode( MINUS, d_quant_models[f].d_cond[i][j][1],
+                                                                NodeManager::currentNM()->mkConst( Rational(1) ) );
+                    nn = Rewriter::rewrite( nn );
+                    inst.push_back( nn );
+                  }
+                }else{
+                  inst.push_back(d_quant_models[f].d_cond[i][j][0]);
+                }
+              }else{
+                inst.push_back(d_quant_models[f].d_cond[i][j]);
+              }
+            }
+            bool addInst = true;
+            if( hasStar ){
+              //try obvious (specified by inst)
+              Node ev = d_quant_models[f].evaluate(fmfmc, inst);
+              if (ev==d_true) {
+                addInst = false;
+                Trace("fmc-debug") << "...do not instantiate, evaluation was " << ev << std::endl;
+              }
+            }else{
+              //for debugging
+              if (Trace.isOn("fmc-test-inst")) {
+                Node ev = d_quant_models[f].evaluate(fmfmc, inst);
+                if( ev==d_true ){
+                  std::cout << "WARNING: instantiation was true! " << f << " " << d_quant_models[f].d_cond[i] << std::endl;
+                  exit(0);
+                }else{
+                  Trace("fmc-test-inst") << "...instantiation evaluated to false." << std::endl;
+                }
+              }
+            }
+            if( addInst ){
+              if( options::fmfBound() ){
+                std::vector< Node > cond;
+                cond.push_back(d_quant_cond[f]);
+                cond.insert( cond.end(), inst.begin(), inst.end() );
+                //need to do exhaustive instantiate algorithm to set things properly (should only add one instance)
+                Node c = mkCond( cond );
+                unsigned prevInst = d_addedLemmas;
+                exhaustiveInstantiate( fmfmc, f, c, -1 );
+                if( d_addedLemmas==prevInst ){
+                  d_star_insts[f].push_back(i);
+                }
+              }else{
+                //just add the instance
+                d_triedLemmas++;
+                if (d_qe->getInstantiate()->addInstantiation(f, inst, true))
+                {
+                  Trace("fmc-debug-inst") << "** Added instantiation." << std::endl;
+                  d_addedLemmas++;
+                  if( d_qe->inConflict() || options::fmfOneInstPerRound() ){
+                    break;
+                  }
+                }else{
+                  Trace("fmc-debug-inst") << "** Instantiation was duplicate." << std::endl;
+                  //this can happen if evaluation is unknown, or if we are generalizing a star that already has a value
+                  //if( !hasStar && d_quant_models[f].d_value[i]==d_false ){
+                  //  Trace("fmc-warn") << "**** FMC warning: inconsistent duplicate instantiation." << std::endl;
+                  //}
+                  //this assertion can happen if two instantiations from this round are identical
+                  // (0,1)->false (1,0)->false   for   forall xy. f( x, y ) = f( y, x )
+                  //Assert( hasStar || d_quant_models[f].d_value[i]!=d_false );
+                  //might try it next effort level
+                  d_star_insts[f].push_back(i);
+                }
+              }
+            }else{
+              Trace("fmc-debug-inst") << "** Instantiation was already true." << std::endl;
+              //might try it next effort level
+              d_star_insts[f].push_back(i);
+            }
+          }
+        }
+      }
+    }else{
+      if (!d_star_insts[f].empty()) {
+        Trace("fmc-exh") << "Exhaustive instantiate " << f << std::endl;
+        Trace("fmc-exh") << "Definition was : " << std::endl;
+        d_quant_models[f].debugPrint("fmc-exh", Node::null(), this);
+        Trace("fmc-exh") << std::endl;
+        Def temp;
+        //simplify the exceptions?
+        for( int i=(d_star_insts[f].size()-1); i>=0; i--) {
+          //get witness for d_star_insts[f][i]
+          int j = d_star_insts[f][i];
+          if( temp.addEntry(fmfmc, d_quant_models[f].d_cond[j], d_quant_models[f].d_value[j] ) ){
+            if( !exhaustiveInstantiate(fmfmc, f, d_quant_models[f].d_cond[j], j ) ){
+              //something went wrong, resort to exhaustive instantiation
+              return 0;
+            }
+          }
+        }
+      }
+    }
+    return 1;
+  }else{
+    return 0;
+  }
+}
+
+/** Representative bound fmc entry
+ *
+ * This bound information corresponds to one
+ * entry in a term definition (see terminology in
+ * Chapter 5 of Finite Model Finding for
+ * Satisfiability Modulo Theories thesis).
+ * For example, a term definition for the body
+ * of a quantified formula:
+ *   forall xyz. P( x, y, z )
+ * may be:
+ *   ( 0, 0, 0 ) -> false
+ *   ( *, 1, 2 ) -> false
+ *   ( *, *, * ) -> true
+ * Indicating that the quantified formula evaluates
+ * to false in the current model for x=0, y=0, z=0,
+ * or y=1, z=2 for any x, and evaluates to true
+ * otherwise.
+ * This class is used if we wish
+ * to iterate over all values corresponding to one
+ * of these entries. For example, for the second entry:
+ *   (*, 1, 2 )
+ * we iterate over all values of x, but only {1}
+ * for y and {2} for z.
+ */
+class RepBoundFmcEntry : public QRepBoundExt
+{
+ public:
+  RepBoundFmcEntry(QuantifiersEngine* qe, Node e, FirstOrderModelFmc* f)
+      : QRepBoundExt(qe), d_entry(e), d_fm(f)
+  {
+  }
+  ~RepBoundFmcEntry() {}
+  /** set bound */
+  virtual RepSetIterator::RsiEnumType setBound(
+      Node owner, unsigned i, std::vector<Node>& elements) override
+  {
+    if (d_fm->isInterval(d_entry[i]))
+    {
+      // explicitly add the interval?
+    }
+    else if (d_fm->isStar(d_entry[i]))
+    {
+      // must add the full range
+    }
+    else
+    {
+      // only need to consider the single point
+      elements.push_back(d_entry[i]);
+      return RepSetIterator::ENUM_DEFAULT;
+    }
+    return QRepBoundExt::setBound(owner, i, elements);
+  }
+
+ private:
+  /** the entry for this bound */
+  Node d_entry;
+  /** the model builder associated with this bound */
+  FirstOrderModelFmc* d_fm;
+};
+
+bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, Node c, int c_index) {
+  Trace("fmc-exh") << "----Exhaustive instantiate based on index " << c_index << " : " << c << " ";
+  debugPrintCond("fmc-exh", c, true);
+  Trace("fmc-exh")<< std::endl;
+  RepBoundFmcEntry rbfe(d_qe, c, fm);
+  RepSetIterator riter(d_qe->getModel()->getRepSet(), &rbfe);
+  Trace("fmc-exh-debug") << "Set quantifier..." << std::endl;
+  //initialize
+  if (riter.setQuantifier(f))
+  {
+    Trace("fmc-exh-debug") << "Set element domains..." << std::endl;
+    int addedLemmas = 0;
+    //now do full iteration
+    while( !riter.isFinished() ){
+      d_triedLemmas++;
+      Trace("fmc-exh-debug") << "Inst : ";
+      std::vector< Node > ev_inst;
+      std::vector< Node > inst;
+      for (unsigned i = 0; i < riter.getNumTerms(); i++)
+      {
+        Node rr = riter.getCurrentTerm( i );
+        Node r = rr;
+        //if( r.getType().isSort() ){
+        r = fm->getRepresentative( r );
+        //}else{
+        //  r = fm->getCurrentModelValue( r );
+        //}
+        debugPrint("fmc-exh-debug", r);
+        Trace("fmc-exh-debug") << " (term : " << rr << ")";
+        ev_inst.push_back( r );
+        inst.push_back( rr );
+      }
+      int ev_index = d_quant_models[f].getGeneralizationIndex(fm, ev_inst);
+      Trace("fmc-exh-debug") << ", index = " << ev_index << " / " << d_quant_models[f].d_value.size();
+      Node ev = ev_index==-1 ? Node::null() : d_quant_models[f].d_value[ev_index];
+      if (ev!=d_true) {
+        Trace("fmc-exh-debug") << ", add!";
+        //add as instantiation
+        if (d_qe->getInstantiate()->addInstantiation(f, inst, true))
+        {
+          Trace("fmc-exh-debug")  << " ...success.";
+          addedLemmas++;
+          if( d_qe->inConflict() || options::fmfOneInstPerRound() ){
+            break;
+          }
+        }else{
+          Trace("fmc-exh-debug") << ", failed.";
+        }
+      }else{
+        Trace("fmc-exh-debug") << ", already true";
+      }
+      Trace("fmc-exh-debug") << std::endl;
+      int index = riter.increment();
+      Trace("fmc-exh-debug") << "Incremented index " << index << std::endl;
+      if( !riter.isFinished() ){
+        if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_BOUND_INT ) {
+          Trace("fmc-exh-debug") << "Since this is a range enumeration, skip to the next..." << std::endl;
+          riter.incrementAtIndex(index - 1);
+        }
+      }
+    }
+    d_addedLemmas += addedLemmas;
+    Trace("fmc-exh") << "----Finished Exhaustive instantiate, lemmas = " << addedLemmas << ", incomplete=" << riter.isIncomplete() << std::endl;
+    return addedLemmas>0 || !riter.isIncomplete();
+  }else{
+    Trace("fmc-exh") << "----Finished Exhaustive instantiate, failed." << std::endl;
+    return !riter.isIncomplete();
+  }
+}
+
+void FullModelChecker::doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n ) {
+  Trace("fmc-debug") << "Check " << n << " " << n.getKind() << std::endl;
+  //first check if it is a bounding literal
+  if( n.hasAttribute(BoundIntLitAttribute()) ){
+    Trace("fmc-debug") << "It is a bounding literal, polarity = " << n.getAttribute(BoundIntLitAttribute()) << std::endl;
+    d.addEntry(fm, mkCondDefault(fm, f), n.getAttribute(BoundIntLitAttribute())==1 ? d_false : d_true );
+  }else if( n.getKind() == kind::BOUND_VARIABLE ){
+    Trace("fmc-debug") << "Add default entry..." << std::endl;
+    d.addEntry(fm, mkCondDefault(fm, f), n);
+  }
+  else if( n.getKind() == kind::NOT ){
+    //just do directly
+    doCheck( fm, f, d, n[0] );
+    doNegate( d );
+  }
+  else if( n.getKind() == kind::FORALL ){
+    d.addEntry(fm, mkCondDefault(fm, f), Node::null());
+  }
+  else if( n.getType().isArray() ){
+    //Trace("fmc-warn") << "WARNING : ARRAYS : Can't process base array " << r << std::endl;
+    //Trace("fmc-warn") << "          Default value was : " << odefaultValue << std::endl;
+    //Trace("fmc-debug") << "Can't process base array " << r << std::endl;
+    //can't process this array
+    d.reset();
+    d.addEntry(fm, mkCondDefault(fm, f), Node::null());
+  }
+  else if( n.getNumChildren()==0 ){
+    Node r = n;
+    if( !n.isConst() ){
+      if( !fm->hasTerm(n) ){
+        r = getSomeDomainElement(fm, n.getType() );
+      }
+      r = fm->getRepresentative( r );
+    }
+    Trace("fmc-debug") << "Add constant entry..." << std::endl;
+    d.addEntry(fm, mkCondDefault(fm, f), r);
+  }
+  else{
+    std::vector< int > var_ch;
+    std::vector< Def > children;
+    for( int i=0; i<(int)n.getNumChildren(); i++) {
+      Def dc;
+      doCheck(fm, f, dc, n[i]);
+      children.push_back(dc);
+      if( n[i].getKind() == kind::BOUND_VARIABLE ){
+        var_ch.push_back(i);
+      }
+    }
+
+    if( n.getKind()==APPLY_UF ){
+      Trace("fmc-debug") << "Do uninterpreted compose " << n << std::endl;
+      //uninterpreted compose
+      doUninterpretedCompose( fm, f, d, n.getOperator(), children );
+      /*
+    } else if( n.getKind()==SELECT ){
+      Trace("fmc-debug") << "Do select compose " << n << std::endl;
+      std::vector< Def > children2;
+      children2.push_back( children[1] );
+      std::vector< Node > cond;
+      mkCondDefaultVec(fm, f, cond);
+      std::vector< Node > val;
+      doUninterpretedCompose(fm, f, d, children[0], children2, 0, cond, val );
+      */
+    } else {
+      if( !var_ch.empty() ){
+        if( n.getKind()==EQUAL && !n[0].getType().isBoolean() ){
+          if( var_ch.size()==2 ){
+            Trace("fmc-debug") << "Do variable equality " << n << std::endl;
+            doVariableEquality( fm, f, d, n );
+          }else{
+            Trace("fmc-debug") << "Do variable relation " << n << std::endl;
+            doVariableRelation( fm, f, d, var_ch[0]==0 ? children[1] : children[0], var_ch[0]==0 ? n[0] : n[1] );
+          }
+        }else{
+          Trace("fmc-warn") << "Don't know how to check " << n << std::endl;
+          d.addEntry(fm, mkCondDefault(fm, f), Node::null());
+        }
+      }else{
+        Trace("fmc-debug") << "Do interpreted compose " << n << std::endl;
+        std::vector< Node > cond;
+        mkCondDefaultVec(fm, f, cond);
+        std::vector< Node > val;
+        //interpreted compose
+        doInterpretedCompose( fm, f, d, n, children, 0, cond, val );
+      }
+    }
+    Trace("fmc-debug") << "Simplify the definition..." << std::endl;
+    d.debugPrint("fmc-debug", Node::null(), this);
+    d.simplify(this, fm);
+    Trace("fmc-debug") << "Done simplifying" << std::endl;
+  }
+  Trace("fmc-debug") << "Definition for " << n << " is : " << std::endl;
+  d.debugPrint("fmc-debug", Node::null(), this);
+  Trace("fmc-debug") << std::endl;
+}
+
+void FullModelChecker::doNegate( Def & dc ) {
+  for (unsigned i=0; i<dc.d_cond.size(); i++) {
+    if (!dc.d_value[i].isNull()) {
+      dc.d_value[i] = dc.d_value[i]==d_true ? d_false : ( dc.d_value[i]==d_false ? d_true : dc.d_value[i] );
+    }
+  }
+}
+
+void FullModelChecker::doVariableEquality( FirstOrderModelFmc * fm, Node f, Def & d, Node eq ) {
+  std::vector<Node> cond;
+  mkCondDefaultVec(fm, f, cond);
+  if (eq[0]==eq[1]){
+    d.addEntry(fm, mkCond(cond), d_true);
+  }else{
+    TypeNode tn = eq[0].getType();
+    if( tn.isSort() ){
+      int j = fm->getVariableId(f, eq[0]);
+      int k = fm->getVariableId(f, eq[1]);
+      const RepSet* rs = fm->getRepSet();
+      if (!rs->hasType(tn))
+      {
+        getSomeDomainElement( fm, tn );  //to verify the type is initialized
+      }
+      unsigned nreps = rs->getNumRepresentatives(tn);
+      for (unsigned i = 0; i < nreps; i++)
+      {
+        Node r = fm->getRepresentative(rs->getRepresentative(tn, i));
+        cond[j+1] = r;
+        cond[k+1] = r;
+        d.addEntry( fm, mkCond(cond), d_true);
+      }
+      d.addEntry( fm, mkCondDefault(fm, f), d_false);
+    }else{
+      d.addEntry( fm, mkCondDefault(fm, f), Node::null());
+    }
+  }
+}
+
+void FullModelChecker::doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v) {
+  int j = fm->getVariableId(f, v);
+  for (unsigned i=0; i<dc.d_cond.size(); i++) {
+    Node val = dc.d_value[i];
+    if( val.isNull() ){
+      d.addEntry( fm, dc.d_cond[i], val);
+    }else{
+      if( dc.d_cond[i][j]!=val ){
+        if (fm->isStar(dc.d_cond[i][j])) {
+          std::vector<Node> cond;
+          mkCondVec(dc.d_cond[i],cond);
+          cond[j+1] = val;
+          d.addEntry(fm, mkCond(cond), d_true);
+          cond[j+1] = fm->getStar(val.getType());
+          d.addEntry(fm, mkCond(cond), d_false);
+        }else{
+          d.addEntry( fm, dc.d_cond[i], d_false);
+        }
+      }else{
+        d.addEntry( fm, dc.d_cond[i], d_true);
+      }
+    }
+  }
+}
+
+void FullModelChecker::doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node op, std::vector< Def > & dc ) {
+  Trace("fmc-uf-debug") << "Definition : " << std::endl;
+  fm->d_models[op]->debugPrint("fmc-uf-debug", op, this);
+  Trace("fmc-uf-debug") << std::endl;
+
+  std::vector< Node > cond;
+  mkCondDefaultVec(fm, f, cond);
+  std::vector< Node > val;
+  doUninterpretedCompose( fm, f, d, *fm->d_models[op], dc, 0, cond, val);
+}
+
+void FullModelChecker::doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d,
+                                               Def & df, std::vector< Def > & dc, int index,
+                                               std::vector< Node > & cond, std::vector<Node> & val ) {
+  Trace("fmc-uf-process") << "process at " << index << std::endl;
+  for( unsigned i=1; i<cond.size(); i++) {
+    debugPrint("fmc-uf-process", cond[i], true);
+    Trace("fmc-uf-process") << " ";
+  }
+  Trace("fmc-uf-process") << std::endl;
+  if (index==(int)dc.size()) {
+    //we have an entry, now do actual compose
+    std::map< int, Node > entries;
+    doUninterpretedCompose2( fm, f, entries, 0, cond, val, df.d_et);
+    if( entries.empty() ){
+      d.addEntry(fm, mkCond(cond), Node::null());
+    }else{
+      //add them to the definition
+      for( unsigned e=0; e<df.d_cond.size(); e++ ){
+        if ( entries.find(e)!=entries.end() ){
+          Trace("fmf-uf-process-debug") << "Add entry..." << std::endl;
+          d.addEntry(fm, entries[e], df.d_value[e] );
+          Trace("fmf-uf-process-debug") << "Done add entry." << std::endl;
+        }
+      }
+    }
+  }else{
+    for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
+      if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
+        std::vector< Node > new_cond;
+        new_cond.insert(new_cond.end(), cond.begin(), cond.end());
+        if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
+          Trace("fmc-uf-process") << "index " << i << " succeeded meet." << std::endl;
+          val.push_back(dc[index].d_value[i]);
+          doUninterpretedCompose(fm, f, d, df, dc, index+1, new_cond, val);
+          val.pop_back();
+        }else{
+          Trace("fmc-uf-process") << "index " << i << " failed meet." << std::endl;
+        }
+      }
+    }
+  }
+}
+
+void FullModelChecker::doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
+                                                std::map< int, Node > & entries, int index,
+                                                std::vector< Node > & cond, std::vector< Node > & val,
+                                                EntryTrie & curr ) {
+  Trace("fmc-uf-process") << "compose " << index << " / " << val.size() << std::endl;
+  for( unsigned i=1; i<cond.size(); i++) {
+    debugPrint("fmc-uf-process", cond[i], true);
+    Trace("fmc-uf-process") << " ";
+  }
+  Trace("fmc-uf-process") << std::endl;
+  if (index==(int)val.size()) {
+    Node c = mkCond(cond);
+    Trace("fmc-uf-entry") << "Entry : " << c << " -> index[" << curr.d_data << "]" << std::endl;
+    entries[curr.d_data] = c;
+  }else{
+    Node v = val[index];
+    Trace("fmc-uf-process") << "Process " << v << std::endl;
+    bool bind_var = false;
+    if( !v.isNull() && v.getKind()==kind::BOUND_VARIABLE ){
+      int j = fm->getVariableId(f, v);
+      Trace("fmc-uf-process") << v << " is variable #" << j << std::endl;
+      if (!fm->isStar(cond[j+1]) && !fm->isInterval(cond[j+1])) {
+        v = cond[j+1];
+      }else{
+        bind_var = true;
+      }
+    }
+    if (bind_var) {
+      Trace("fmc-uf-process") << "bind variable..." << std::endl;
+      int j = fm->getVariableId(f, v);
+      if( fm->isStar(cond[j+1]) ){
+        for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
+          cond[j+1] = it->first;
+          doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
+        }
+        cond[j+1] = fm->getStar(v.getType());
+      }else{
+        Node orig = cond[j+1];
+        for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
+          Node nw = doIntervalMeet( fm, it->first, orig );
+          if( !nw.isNull() ){
+            cond[j+1] = nw;
+            doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
+          }
+        }
+        cond[j+1] = orig;
+      }
+    }else{
+      if( !v.isNull() ){
+        if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && v.getType().isInteger() ){
+          for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
+            if( fm->isInRange( v, it->first ) ){
+              doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
+            }
+          }
+        }else{
+          if (curr.d_child.find(v)!=curr.d_child.end()) {
+            Trace("fmc-uf-process") << "follow value..." << std::endl;
+            doUninterpretedCompose2(fm, f, entries, index+1, cond, val, curr.d_child[v]);
+          }
+          Node st = fm->getStarElement(v.getType());
+          if (curr.d_child.find(st)!=curr.d_child.end()) {
+            Trace("fmc-uf-process") << "follow star..." << std::endl;
+            doUninterpretedCompose2(fm, f, entries, index+1, cond, val, curr.d_child[st]);
+          }
+        }
+      }
+    }
+  }
+}
+
+void FullModelChecker::doInterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n,
+                                             std::vector< Def > & dc, int index,
+                                             std::vector< Node > & cond, std::vector<Node> & val ) {
+  Trace("fmc-if-process") << "int compose " << index << " / " << dc.size() << std::endl;
+  for( unsigned i=1; i<cond.size(); i++) {
+    debugPrint("fmc-if-process", cond[i], true);
+    Trace("fmc-if-process") << " ";
+  }
+  Trace("fmc-if-process") << std::endl;
+  if ( index==(int)dc.size() ){
+    Node c = mkCond(cond);
+    Node v = evaluateInterpreted(n, val);
+    d.addEntry(fm, c, v);
+  }
+  else {
+    TypeNode vtn = n.getType();
+    for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
+      if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
+        std::vector< Node > new_cond;
+        new_cond.insert(new_cond.end(), cond.begin(), cond.end());
+        if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
+          bool process = true;
+          if (vtn.isBoolean()) {
+            //short circuit
+            if( (n.getKind()==OR && dc[index].d_value[i]==d_true) ||
+                (n.getKind()==AND && dc[index].d_value[i]==d_false) ){
+              Node c = mkCond(new_cond);
+              d.addEntry(fm, c, dc[index].d_value[i]);
+              process = false;
+            }
+          }
+          if (process) {
+            val.push_back(dc[index].d_value[i]);
+            doInterpretedCompose(fm, f, d, n, dc, index+1, new_cond, val);
+            val.pop_back();
+          }
+        }
+      }
+    }
+  }
+}
+
+int FullModelChecker::isCompat( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
+  Trace("fmc-debug3") << "isCompat " << c << std::endl;
+  Assert(cond.size()==c.getNumChildren()+1);
+  for (unsigned i=1; i<cond.size(); i++) {
+    if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && cond[i].getType().isInteger() ){
+      Node iv = doIntervalMeet( fm, cond[i], c[i-1], false );
+      if( iv.isNull() ){
+        return 0;
+      }
+    }else{
+      if( cond[i]!=c[i-1] && !fm->isStar(cond[i]) && !fm->isStar(c[i-1]) ) {
+        return 0;
+      }
+    }
+  }
+  return 1;
+}
+
+bool FullModelChecker::doMeet( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
+  Trace("fmc-debug3") << "doMeet " << c << std::endl;
+  Assert(cond.size()==c.getNumChildren()+1);
+  for (unsigned i=1; i<cond.size(); i++) {
+    if( cond[i]!=c[i-1] ) {
+      if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && cond[i].getType().isInteger() ){
+        Node iv = doIntervalMeet( fm, cond[i], c[i-1] );
+        if( !iv.isNull() ){
+          cond[i] = iv;
+        }else{
+          return false;
+        }
+      }else{
+        if( fm->isStar(cond[i]) ){
+          cond[i] = c[i-1];
+        }else if( !fm->isStar(c[i-1]) ){
+          return false;
+        }
+      }
+    }
+  }
+  return true;
+}
+
+Node FullModelChecker::doIntervalMeet( FirstOrderModelFmc * fm, Node i1, Node i2, bool mk ) {
+  Trace("fmc-debug2") << "Interval meet : " << i1 << " " << i2 << " " << mk << std::endl;
+  if( fm->isStar( i1 ) ){
+    return i2;
+  }else if( fm->isStar( i2 ) ){
+    return i1;
+  }else if( !fm->isInterval( i1 ) && fm->isInterval( i2 ) ){
+    return doIntervalMeet( fm, i2, i1, mk );
+  }else if( !fm->isInterval( i2 ) ){
+    if( fm->isInterval( i1 ) ){
+      if( fm->isInRange( i2, i1 ) ){
+        return i2;
+      }
+    }else if( i1==i2 ){
+      return i1;
+    }
+    return Node::null();
+  }else{
+    Node b[2];
+    for( unsigned j=0; j<2; j++ ){
+      Node b1 = i1[j];
+      Node b2 = i2[j];
+      if( fm->isStar( b1 ) ){
+        b[j] = b2;
+      }else if( fm->isStar( b2 ) ){
+        b[j] = b1;
+      }else if( b1.getConst<Rational>() < b2.getConst<Rational>() ){
+        b[j] = j==0 ? b2 : b1;
+      }else{
+        b[j] = j==0 ? b1 : b2;
+      }
+    }
+    if( fm->isStar( b[0] ) || fm->isStar( b[1] ) || b[0].getConst<Rational>() < b[1].getConst<Rational>() ){
+      return mk ? fm->getInterval( b[0], b[1] ) : i1;
+    }else{
+      return Node::null();
+    }
+  }
+}
+
+Node FullModelChecker::mkCond( std::vector< Node > & cond ) {
+  return NodeManager::currentNM()->mkNode(APPLY_UF, cond);
+}
+
+Node FullModelChecker::mkCondDefault( FirstOrderModelFmc * fm, Node f) {
+  std::vector< Node > cond;
+  mkCondDefaultVec(fm, f, cond);
+  return mkCond(cond);
+}
+
+void FullModelChecker::mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond ) {
+  Trace("fmc-debug") << "Make default vec, intervals = " << (options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL) << std::endl;
+  //get function symbol for f
+  cond.push_back(d_quant_cond[f]);
+  for (unsigned i=0; i<f[0].getNumChildren(); i++) {
+    Node ts = fm->getStarElement( f[0][i].getType() );
+    Assert( ts.getType()==f[0][i].getType() );
+    cond.push_back(ts);
+  }
+}
+
+void FullModelChecker::mkCondVec( Node n, std::vector< Node > & cond ) {
+  cond.push_back(n.getOperator());
+  for( unsigned i=0; i<n.getNumChildren(); i++ ){
+    cond.push_back( n[i] );
+  }
+}
+
+Node FullModelChecker::mkArrayCond( Node a ) {
+  if( d_array_term_cond.find(a)==d_array_term_cond.end() ){
+    if( d_array_cond.find(a.getType())==d_array_cond.end() ){
+      TypeNode typ = NodeManager::currentNM()->mkFunctionType( a.getType(), NodeManager::currentNM()->booleanType() );
+      Node op = NodeManager::currentNM()->mkSkolem( "fmc", typ, "op created for full-model checking" );
+      d_array_cond[a.getType()] = op;
+    }
+    std::vector< Node > cond;
+    cond.push_back(d_array_cond[a.getType()]);
+    cond.push_back(a);
+    d_array_term_cond[a] = NodeManager::currentNM()->mkNode(APPLY_UF, cond );
+  }
+  return d_array_term_cond[a];
+}
+
+Node FullModelChecker::evaluateInterpreted( Node n, std::vector< Node > & vals ) {
+  if( n.getKind()==EQUAL && !n[0].getType().isBoolean() ){
+    if (!vals[0].isNull() && !vals[1].isNull()) {
+      return vals[0]==vals[1] ? d_true : d_false;
+    }else{
+      return Node::null();
+    }
+  }else if( n.getKind()==ITE ){
+    if( vals[0]==d_true ){
+      return vals[1];
+    }else if( vals[0]==d_false ){
+      return vals[2];
+    }else{
+      return vals[1]==vals[2] ? vals[1] : Node::null();
+    }
+  }else if( n.getKind()==AND || n.getKind()==OR ){
+    bool isNull = false;
+    for (unsigned i=0; i<vals.size(); i++) {
+      if((vals[i]==d_true && n.getKind()==OR) || (vals[i]==d_false && n.getKind()==AND)) {
+        return vals[i];
+      }else if( vals[i].isNull() ){
+        isNull = true;
+      }
+    }
+    return isNull ? Node::null() : vals[0];
+  }else{
+    std::vector<Node> children;
+    if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+      children.push_back( n.getOperator() );
+    }
+    for (unsigned i=0; i<vals.size(); i++) {
+      if( vals[i].isNull() ){
+        return Node::null();
+      }else{
+        children.push_back( vals[i] );
+      }
+    }
+    Node nc = NodeManager::currentNM()->mkNode(n.getKind(), children);
+    Trace("fmc-eval") << "Evaluate " << nc << " to ";
+    nc = Rewriter::rewrite(nc);
+    Trace("fmc-eval") << nc << std::endl;
+    return nc;
+  }
+}
+
+Node FullModelChecker::getSomeDomainElement( FirstOrderModelFmc * fm, TypeNode tn ) {
+  bool addRepId = !fm->getRepSet()->hasType(tn);
+  Node de = fm->getSomeDomainElement(tn);
+  if( addRepId ){
+    d_rep_ids[tn][de] = 0;
+  }
+  return de;
+}
+
+Node FullModelChecker::getFunctionValue(FirstOrderModelFmc * fm, Node op, const char* argPrefix ) {
+  return fm->getFunctionValue(op, argPrefix);
+}
+
+
+bool FullModelChecker::useSimpleModels() {
+  return options::fmfFmcSimple();
+}
+
+void FullModelChecker::convertIntervalModel( FirstOrderModelFmc * fm, Node op ){
+  Trace("fmc-interval-model") << "Changing to interval model, Before : " << std::endl;
+  fm->d_models[op]->debugPrint("fmc-interval-model", op, this);
+  Trace("fmc-interval-model") << std::endl;
+  std::vector< int > indices;
+  for( int i=0; i<(int)fm->d_models[op]->d_cond.size(); i++ ){
+    indices.push_back( i );
+  }
+  std::map< int, std::map< int, Node > > changed_vals;
+  makeIntervalModel( fm, op, indices, 0, changed_vals );
+
+  std::vector< Node > conds;
+  std::vector< Node > values;
+  for( unsigned i=0; i<fm->d_models[op]->d_cond.size(); i++ ){
+    if( changed_vals.find(i)==changed_vals.end() ){
+      conds.push_back( fm->d_models[op]->d_cond[i] );
+    }else{
+      std::vector< Node > children;
+      children.push_back( op );
+      for( unsigned j=0; j<fm->d_models[op]->d_cond[i].getNumChildren(); j++ ){
+        if( changed_vals[i].find(j)==changed_vals[i].end() ){
+          children.push_back( fm->d_models[op]->d_cond[i][j] );
+        }else{
+          children.push_back( changed_vals[i][j] );
+        }
+      }
+      Node nc = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+      conds.push_back( nc );
+      Trace("fmc-interval-model") << "Interval : Entry #" << i << " changed to ";
+      debugPrintCond("fmc-interval-model", nc, true );
+      Trace("fmc-interval-model") << std::endl;
+    }
+    values.push_back( fm->d_models[op]->d_value[i] );
+  }
+  fm->d_models[op]->reset();
+  for( unsigned i=0; i<conds.size(); i++ ){
+    fm->d_models[op]->addEntry(fm, conds[i], values[i] );
+  }
+}
+
+void FullModelChecker::makeIntervalModel( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+                                          std::map< int, std::map< int, Node > >& changed_vals ) {
+  if( index==(int)fm->d_models[op]->d_cond[0].getNumChildren() ){
+    makeIntervalModel2( fm, op, indices, 0, changed_vals );
+  }else{
+    TypeNode tn = fm->d_models[op]->d_cond[0][index].getType();
+    if( tn.isInteger() ){
+      makeIntervalModel(fm,op,indices,index+1, changed_vals );
+    }else{
+      std::map< Node, std::vector< int > > new_indices;
+      for( unsigned i=0; i<indices.size(); i++ ){
+        Node v = fm->d_models[op]->d_cond[indices[i]][index];
+        new_indices[v].push_back( indices[i] );
+      }
+
+      for( std::map< Node, std::vector< int > >::iterator it = new_indices.begin(); it != new_indices.end(); ++it ){
+        makeIntervalModel( fm, op, it->second, index+1, changed_vals );
+      }
+    }
+  }
+}
+
+void FullModelChecker::makeIntervalModel2( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+                                          std::map< int, std::map< int, Node > >& changed_vals ) {
+  Debug("fmc-interval-model-debug") << "Process " << index << " with indicies : ";
+  for( unsigned i=0; i<indices.size(); i++ ){
+    Debug("fmc-interval-model-debug") << indices[i] << " ";
+  }
+  Debug("fmc-interval-model-debug") << std::endl;
+
+  if( index<(int)fm->d_models[op]->d_cond[0].getNumChildren() ){
+    TypeNode tn = fm->d_models[op]->d_cond[0][index].getType();
+    if( tn.isInteger() ){
+      std::map< Node, std::vector< int > > new_indices;
+      for( unsigned i=0; i<indices.size(); i++ ){
+        Node v = fm->d_models[op]->d_cond[indices[i]][index];
+        new_indices[v].push_back( indices[i] );
+        if( !v.isConst() ){
+          Trace("fmc-warn") << "WARNING: for interval, model has non-constant : " << v << std::endl;
+          Trace("fmc-warn") << "From condition : " << fm->d_models[op]->d_cond[indices[i]] << std::endl;
+        }
+      }
+
+      std::vector< Node > values;
+      for( std::map< Node, std::vector< int > >::iterator it = new_indices.begin(); it != new_indices.end(); ++it ){
+        makeIntervalModel2( fm, op, it->second, index+1, changed_vals );
+        values.push_back( it->first );
+      }
+
+      if( tn.isInteger() ){
+        //sort values by size
+        ConstRationalSort crs;
+        std::vector< int > sindices;
+        for( unsigned i=0; i<values.size(); i++ ){
+          sindices.push_back( (int)i );
+          crs.d_terms.push_back( values[i] );
+        }
+        std::sort( sindices.begin(), sindices.end(), crs );
+
+        Node ub = fm->getStar( tn );
+        for( int i=(int)(sindices.size()-1); i>=0; i-- ){
+          Node lb = fm->getStar( tn );
+          if( i>0 ){
+            lb = values[sindices[i]];
+          }
+          Node interval = fm->getInterval( lb, ub );
+          for( unsigned j=0; j<new_indices[values[sindices[i]]].size(); j++ ){
+            Debug("fmc-interval-model-debug") << "Change " << new_indices[values[sindices[i]]][j] << ", " << index << " to " << interval << std::endl;
+            changed_vals[new_indices[values[sindices[i]]][j]][index] = interval;
+          }
+          ub = lb;
+        }
+      }
+    }else{
+      makeIntervalModel2( fm, op, indices, index+1, changed_vals );
+    }
+  }
+}
diff --git a/src/theory/quantifiers/fmf/full_model_check.h b/src/theory/quantifiers/fmf/full_model_check.h
new file mode 100644 (file)
index 0000000..732f8be
--- /dev/null
@@ -0,0 +1,157 @@
+/*********************                                                        */
+/*! \file full_model_check.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Morgan Deters, Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Full model check class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__FULL_MODEL_CHECK_H
+#define __CVC4__THEORY__QUANTIFIERS__FULL_MODEL_CHECK_H
+
+#include "theory/quantifiers/fmf/model_builder.h"
+#include "theory/quantifiers/first_order_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+namespace fmcheck {
+
+
+class FirstOrderModelFmc;
+class FullModelChecker;
+
+class EntryTrie
+{
+private:
+  int d_complete;
+public:
+  EntryTrie() : d_complete(-1), d_data(-1){}
+  std::map<Node,EntryTrie> d_child;
+  int d_data;
+  void reset() { d_data = -1; d_child.clear(); d_complete = -1; }
+  void addEntry( FirstOrderModelFmc * m, Node c, Node v, int data, int index = 0 );
+  bool hasGeneralization( FirstOrderModelFmc * m, Node c, int index = 0 );
+  int getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node> & inst, int index = 0 );
+  void getEntries( FirstOrderModelFmc * m, Node c, std::vector<int> & compat, std::vector<int> & gen, int index = 0, bool is_gen = true );
+
+  void collectIndices(Node c, int index, std::vector< int >& indices );
+  bool isComplete(FirstOrderModelFmc * m, Node c, int index);
+};/* class EntryTrie */
+
+
+class Def
+{
+public:
+  EntryTrie d_et;
+  //cond is APPLY_UF whose arguments are returned by FullModelChecker::getRepresentative
+  std::vector< Node > d_cond;
+  //value is returned by FullModelChecker::getRepresentative
+  std::vector< Node > d_value;
+  void basic_simplify( FirstOrderModelFmc * m );
+private:
+  enum {
+    status_unk,
+    status_redundant,
+    status_non_redundant
+  };
+  std::vector< int > d_status;
+  bool d_has_simplified;
+public:
+  Def() : d_has_simplified(false){}
+  void reset() {
+    d_et.reset();
+    d_cond.clear();
+    d_value.clear();
+    d_status.clear();
+    d_has_simplified = false;
+  }
+  bool addEntry( FirstOrderModelFmc * m, Node c, Node v);
+  Node evaluate( FirstOrderModelFmc * m, std::vector<Node>& inst );
+  int getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>& inst );
+  void simplify( FullModelChecker * mc, FirstOrderModelFmc * m );
+  void debugPrint(const char * tr, Node op, FullModelChecker * m);
+};/* class Def */
+
+
+class FullModelChecker : public QModelBuilder
+{
+protected:
+  Node d_true;
+  Node d_false;
+  std::map<TypeNode, std::map< Node, int > > d_rep_ids;
+  std::map<Node, Def > d_quant_models;
+  std::map<Node, Node > d_quant_cond;
+  std::map< TypeNode, Node > d_array_cond;
+  std::map< Node, Node > d_array_term_cond;
+  std::map< Node, std::vector< int > > d_star_insts;
+  std::map< TypeNode, bool > d_preinitialized_types;
+  void preInitializeType( FirstOrderModelFmc * fm, TypeNode tn );
+  Node normalizeArgReps(FirstOrderModelFmc * fm, Node op, Node n);
+  bool exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, Node c, int c_index);
+protected:
+  void makeIntervalModel2( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+                          std::map< int, std::map< int, Node > >& changed_vals );
+  void makeIntervalModel( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
+                          std::map< int, std::map< int, Node > >& changed_vals );
+  void convertIntervalModel( FirstOrderModelFmc * fm, Node op );
+private:
+  void doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n );
+
+  void doNegate( Def & dc );
+  void doVariableEquality( FirstOrderModelFmc * fm, Node f, Def & d, Node eq );
+  void doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v);
+  void doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n, std::vector< Def > & dc );
+
+  void doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d,
+                               Def & df, std::vector< Def > & dc, int index,
+                               std::vector< Node > & cond, std::vector<Node> & val );
+  void doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
+                                std::map< int, Node > & entries, int index,
+                                std::vector< Node > & cond, std::vector< Node > & val,
+                                EntryTrie & curr);
+
+  void doInterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n,
+                             std::vector< Def > & dc, int index,
+                             std::vector< Node > & cond, std::vector<Node> & val );
+  int isCompat( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c );
+  Node doIntervalMeet( FirstOrderModelFmc * fm, Node i1, Node i2, bool mk = true );
+  bool doMeet( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c );
+  Node mkCond( std::vector< Node > & cond );
+  Node mkCondDefault( FirstOrderModelFmc * fm, Node f );
+  void mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond );
+  void mkCondVec( Node n, std::vector< Node > & cond );
+  Node mkArrayCond( Node a );
+  Node evaluateInterpreted( Node n, std::vector< Node > & vals );
+  Node getSomeDomainElement( FirstOrderModelFmc * fm, TypeNode tn );
+public:
+  FullModelChecker( context::Context* c, QuantifiersEngine* qe );
+
+  void debugPrintCond(const char * tr, Node n, bool dispStar = false);
+  void debugPrint(const char * tr, Node n, bool dispStar = false);
+
+  int doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort );
+
+  Node getFunctionValue(FirstOrderModelFmc * fm, Node op, const char* argPrefix );
+
+  /** process build model */  
+  bool preProcessBuildModel(TheoryModel* m); 
+  bool processBuildModel(TheoryModel* m);
+
+  bool useSimpleModels();
+};/* class FullModelChecker */
+
+}/* CVC4::theory::quantifiers::fmcheck namespace */
+}/* CVC4::theory::quantifiers namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__FULL_MODEL_CHECK_H */
diff --git a/src/theory/quantifiers/fmf/model_builder.cpp b/src/theory/quantifiers/fmf/model_builder.cpp
new file mode 100644 (file)
index 0000000..9e79611
--- /dev/null
@@ -0,0 +1,808 @@
+/*********************                                                        */
+/*! \file model_builder.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of model builder class
+ **/
+
+#include "theory/quantifiers/fmf/model_builder.h"
+
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/instantiate.h"
+#include "theory/quantifiers/fmf/model_engine.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers/ematching/trigger.h"
+#include "theory/theory_engine.h"
+#include "theory/uf/equality_engine.h"
+#include "theory/uf/theory_uf.h"
+#include "theory/uf/theory_uf_model.h"
+#include "theory/uf/theory_uf_strong_solver.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+
+QModelBuilder::QModelBuilder(context::Context* c, QuantifiersEngine* qe)
+    : TheoryEngineModelBuilder(qe->getTheoryEngine()),
+      d_qe(qe),
+      d_addedLemmas(0),
+      d_triedLemmas(0) {}
+
+bool QModelBuilder::optUseModel() {
+  return options::mbqiMode()!=MBQI_NONE || options::fmfBound();
+}
+
+bool QModelBuilder::preProcessBuildModel(TheoryModel* m) {
+  return preProcessBuildModelStd( m );
+}
+
+bool QModelBuilder::preProcessBuildModelStd(TheoryModel* m) {
+  d_addedLemmas = 0;
+  d_triedLemmas = 0;
+  if( options::fmfEmptySorts() || options::fmfFunWellDefinedRelevant() ){
+    FirstOrderModel * fm = (FirstOrderModel*)m;
+    //traverse equality engine
+    std::map< TypeNode, bool > eqc_usort;
+    eq::EqClassesIterator eqcs_i =
+        eq::EqClassesIterator(fm->getEqualityEngine());
+    while( !eqcs_i.isFinished() ){
+      TypeNode tr = (*eqcs_i).getType();
+      eqc_usort[tr] = true;
+      ++eqcs_i;
+    }
+    //look at quantified formulas
+    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+      Node q = fm->getAssertedQuantifier( i, true );
+      if( fm->isQuantifierActive( q ) ){
+        //check if any of these quantified formulas can be set inactive
+        if( options::fmfEmptySorts() ){
+          for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+            TypeNode tn = q[0][i].getType();
+            //we are allowed to assume the type is empty
+            if( tn.isSort() && eqc_usort.find( tn )==eqc_usort.end() ){
+              Trace("model-engine-debug") << "Empty domain quantified formula : " << q << std::endl;
+              fm->setQuantifierActive( q, false );
+            }
+          }
+        }else if( options::fmfFunWellDefinedRelevant() ){
+          if( q[0].getNumChildren()==1 ){
+            TypeNode tn = q[0][0].getType();
+            if( tn.getAttribute(AbsTypeFunDefAttribute()) ){
+              //Trace("model-engine-debug2") << "...possible irrelevant function def : " << q << ", #rr = " << d_quantEngine->getModel()->d_rep_set.getNumRelevantGroundReps( tn ) << std::endl;
+              //we are allowed to assume the introduced type is empty
+              if( eqc_usort.find( tn )==eqc_usort.end() ){
+                Trace("model-engine-debug") << "Irrelevant function definition : " << q << std::endl;
+                fm->setQuantifierActive( q, false );
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  return true;
+}
+
+void QModelBuilder::debugModel( TheoryModel* m ){
+  //debug the model: cycle through all instantiations for all quantifiers, report ones that are not true
+  if( Trace.isOn("quant-check-model") ){
+    FirstOrderModel* fm = (FirstOrderModel*)m;
+    Trace("quant-check-model") << "Testing quantifier instantiations..." << std::endl;
+    int tests = 0;
+    int bad = 0;
+    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+      Node f = fm->getAssertedQuantifier( i );
+      std::vector< Node > vars;
+      for( unsigned j=0; j<f[0].getNumChildren(); j++ ){
+        vars.push_back( f[0][j] );
+      }
+      QRepBoundExt qrbe(d_qe);
+      RepSetIterator riter(d_qe->getModel()->getRepSet(), &qrbe);
+      if( riter.setQuantifier( f ) ){
+        while( !riter.isFinished() ){
+          tests++;
+          std::vector< Node > terms;
+          for (unsigned k = 0; k < riter.getNumTerms(); k++)
+          {
+            terms.push_back( riter.getCurrentTerm( k ) );
+          }
+          Node n = d_qe->getInstantiate()->getInstantiation(f, vars, terms);
+          Node val = fm->getValue( n );
+          if (val != d_qe->getTermUtil()->d_true)
+          {
+            Trace("quant-check-model") << "*******  Instantiation " << n << " for " << std::endl;
+            Trace("quant-check-model") << "         " << f << std::endl;
+            Trace("quant-check-model") << "         Evaluates to " << val << std::endl;
+            bad++;
+          }
+          riter.increment();
+        }
+        Trace("quant-check-model") << "Tested " << tests << " instantiations";
+        if( bad>0 ){
+          Trace("quant-check-model") << ", " << bad << " failed" << std::endl;
+        }
+        Trace("quant-check-model") << "." << std::endl;
+      }else{
+        if( riter.isIncomplete() ){
+          Trace("quant-check-model") << "Warning: Could not test quantifier " << f << std::endl;
+        }
+      }
+    }
+  }
+}
+
+bool TermArgBasisTrie::addTerm(FirstOrderModel* fm, Node n, unsigned argIndex)
+{
+  if (argIndex < n.getNumChildren())
+  {
+    Node r;
+    if( n[ argIndex ].getAttribute(ModelBasisAttribute()) ){
+      r = n[ argIndex ];
+    }else{
+      r = fm->getRepresentative( n[ argIndex ] );
+    }
+    std::map< Node, TermArgBasisTrie >::iterator it = d_data.find( r );
+    if( it==d_data.end() ){
+      d_data[r].addTerm(fm, n, argIndex + 1);
+      return true;
+    }else{
+      return it->second.addTerm(fm, n, argIndex + 1);
+    }
+  }else{
+    return false;
+  }
+}
+
+QModelBuilderIG::QModelBuilderIG(context::Context* c, QuantifiersEngine* qe)
+    : QModelBuilder(c, qe),
+      d_basisNoMatch(c),
+      d_didInstGen(false),
+      d_numQuantSat(0),
+      d_numQuantInstGen(0),
+      d_numQuantNoInstGen(0),
+      d_numQuantNoSelForm(0),
+      d_instGenMatches(0) {}
+
+/*
+Node QModelBuilderIG::getCurrentUfModelValue( FirstOrderModel* fm, Node n, std::vector< Node > & args, bool partial ) {
+  return n;
+}
+*/
+
+bool QModelBuilderIG::processBuildModel( TheoryModel* m ) {
+  FirstOrderModel* f = (FirstOrderModel*)m;
+  FirstOrderModelIG* fm = f->asFirstOrderModelIG();
+  Trace("model-engine-debug") << "Process build model " << optUseModel() << std::endl;
+  d_didInstGen = false;
+  //reset the internal information
+  reset( fm );
+  //only construct first order model if optUseModel() is true
+  if( optUseModel() ){
+    Trace("model-engine-debug") << "Initializing " << fm->getNumAssertedQuantifiers() << " quantifiers..." << std::endl;
+    //check if any quantifiers are un-initialized
+    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+      Node q = fm->getAssertedQuantifier( i );
+      if( d_qe->getModel()->isQuantifierActive( q ) ){
+        int lems = initializeQuantifier(q, q, f);
+        d_statistics.d_init_inst_gen_lemmas += lems;
+        d_addedLemmas += lems;
+        if( d_qe->inConflict() ){
+          break;
+        }
+      }
+    }
+    if( d_addedLemmas>0 ){
+      Trace("model-engine") << "Initialize, Added Lemmas = " << d_addedLemmas << std::endl;
+      return false;
+    }else{
+      Assert( !d_qe->inConflict() );
+      //initialize model
+      fm->initialize();
+      //analyze the functions
+      Trace("model-engine-debug") << "Analyzing model..." << std::endl;
+      analyzeModel( fm );
+      //analyze the quantifiers
+      Trace("model-engine-debug") << "Analyzing quantifiers..." << std::endl;
+      d_uf_prefs.clear();
+      for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+        Node q = fm->getAssertedQuantifier( i );
+        analyzeQuantifier( fm, q );
+      }
+
+      //if applicable, find exceptions to model via inst-gen
+      if( options::fmfInstGen() ){
+        d_didInstGen = true;
+        d_instGenMatches = 0;
+        d_numQuantSat = 0;
+        d_numQuantInstGen = 0;
+        d_numQuantNoInstGen = 0;
+        d_numQuantNoSelForm = 0;
+        //now, see if we know that any exceptions via InstGen exist
+        Trace("model-engine-debug") << "Perform InstGen techniques for quantifiers..." << std::endl;
+        for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+          Node f = fm->getAssertedQuantifier( i );
+          if( d_qe->getModel()->isQuantifierActive( f ) ){
+            int lems = doInstGen( fm, f );
+            d_statistics.d_inst_gen_lemmas += lems;
+            d_addedLemmas += lems;
+            //temporary
+            if( lems>0 ){
+              d_numQuantInstGen++;
+            }else if( hasInstGen( f ) ){
+              d_numQuantNoInstGen++;
+            }else{
+              d_numQuantNoSelForm++;
+            }
+            if( d_qe->inConflict() || ( options::fmfInstGenOneQuantPerRound() && lems>0 ) ){
+              break;
+            }
+          }else{
+            d_numQuantSat++;
+          }
+        }
+        Trace("model-engine-debug") << "Quantifiers sat/ig/n-ig/null " << d_numQuantSat << " / " << d_numQuantInstGen << " / ";
+        Trace("model-engine-debug") << d_numQuantNoInstGen << " / " << d_numQuantNoSelForm << std::endl;
+        Trace("model-engine-debug") << "Inst-gen # matches examined = " << d_instGenMatches << std::endl;
+        if( Trace.isOn("model-engine") ){
+          if( d_addedLemmas>0 ){
+            Trace("model-engine") << "InstGen, added lemmas = " << d_addedLemmas << std::endl;
+          }else{
+            Trace("model-engine") << "No InstGen lemmas..." << std::endl;
+          }
+        }
+      }
+      //construct the model if necessary
+      if( d_addedLemmas==0 ){
+        //if no immediate exceptions, build the model
+        //  this model will be an approximation that will need to be tested via exhaustive instantiation
+        Trace("model-engine-debug") << "Building model..." << std::endl;
+        //build model for UF
+        for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
+          Trace("model-engine-debug-uf") << "Building model for " << it->first << "..." << std::endl;
+          constructModelUf( fm, it->first );
+        }
+        Trace("model-engine-debug") << "Done building models." << std::endl;
+      }else{
+        return false;
+      }
+    }
+  }
+  //update models
+  for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
+    it->second.update( fm );
+    Trace("model-func") << "QModelBuilder: Make function value from tree " << it->first << std::endl;
+    //construct function values
+    Node f_def = it->second.getFunctionValue( "$x" );
+    fm->assignFunctionDefinition( it->first, f_def );
+  }
+  Assert( d_addedLemmas==0 );
+  return TheoryEngineModelBuilder::processBuildModel( m );
+}
+
+int QModelBuilderIG::initializeQuantifier(Node f, Node fp, FirstOrderModel* fm)
+{
+  if( d_quant_basis_match_added.find( f )==d_quant_basis_match_added.end() ){
+    //create the basis match if necessary
+    if( d_quant_basis_match.find( f )==d_quant_basis_match.end() ){
+      Trace("inst-fmf-init") << "Initialize " << f << std::endl;
+      //add the model basis instantiation
+      // This will help produce the necessary information for model completion.
+      // We do this by extending distinguish ground assertions (those
+      //   containing terms with "model basis" attribute) to hold for all cases.
+
+      ////first, check if any variables are required to be equal
+      //for( std::map< Node, bool >::iterator it = d_quantEngine->d_phase_reqs[f].begin();
+      //    it != d_quantEngine->d_phase_reqs[f].end(); ++it ){
+      //  Node n = it->first;
+      //  if( n.getKind()==EQUAL && n[0].getKind()==INST_CONSTANT && n[1].getKind()==INST_CONSTANT ){
+      //    Notice() << "Unhandled phase req: " << n << std::endl;
+      //  }
+      //}
+      d_quant_basis_match[f] = InstMatch( f );
+      for (unsigned j = 0; j < f[0].getNumChildren(); j++)
+      {
+        Node t = fm->getModelBasisTerm(f[0][j].getType());
+        //calculate the basis match for f
+        d_quant_basis_match[f].setValue( j, t );
+      }
+      ++(d_statistics.d_num_quants_init);
+    }
+    //try to add it
+    Trace("inst-fmf-init") << "Init: try to add match " << d_quant_basis_match[f] << std::endl;
+    //add model basis instantiation
+    if (d_qe->getInstantiate()->addInstantiation(fp, d_quant_basis_match[f]))
+    {
+      d_quant_basis_match_added[f] = true;
+      return 1;
+    }else{
+      //shouldn't happen usually, but will occur if x != y is a required literal for f.
+      //Notice() << "No model basis for " << f << std::endl;
+      d_quant_basis_match_added[f] = false;
+    }
+  }
+  return 0;
+}
+
+void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){
+  FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
+  d_uf_model_constructed.clear();
+  //determine if any functions are constant
+  for( std::map< Node, uf::UfModelTree >::iterator it = fmig->d_uf_model_tree.begin(); it != fmig->d_uf_model_tree.end(); ++it ){
+    Node op = it->first;
+    TermArgBasisTrie tabt;
+    std::map< Node, std::vector< Node > >::iterator itut = fmig->d_uf_terms.find( op );
+    if( itut!=fmig->d_uf_terms.end() ){
+      for( size_t i=0; i<itut->second.size(); i++ ){
+        Node n = fmig->d_uf_terms[op][i];
+        //for calculating if op is constant
+        Node v = fmig->getRepresentative( n );
+        if( i==0 ){
+          d_uf_prefs[op].d_const_val = v;
+        }else if( v!=d_uf_prefs[op].d_const_val ){
+          d_uf_prefs[op].d_const_val = Node::null();
+          break;
+        }
+        //for calculating terms that we don't need to consider
+        //if( d_qe->getTermDatabase()->isTermActive( n ) || n.getAttribute(ModelBasisArgAttribute())!=0 ){
+        if( d_basisNoMatch.find( n )==d_basisNoMatch.end() ){
+          //need to consider if it is not congruent modulo model basis
+          if( !tabt.addTerm( fmig, n ) ){
+            d_basisNoMatch[n] = true;
+          }
+        }
+      }
+    }
+    if( !d_uf_prefs[op].d_const_val.isNull() ){
+      fmig->d_uf_model_gen[op].setDefaultValue( d_uf_prefs[op].d_const_val );
+      fmig->d_uf_model_gen[op].makeModel( fmig, it->second );
+      Debug("fmf-model-cons") << "Function " << op << " is the constant function ";
+      fmig->printRepresentativeDebug( "fmf-model-cons", d_uf_prefs[op].d_const_val );
+      Debug("fmf-model-cons") << std::endl;
+      d_uf_model_constructed[op] = true;
+    }else{
+      d_uf_model_constructed[op] = false;
+    }
+  }
+}
+
+bool QModelBuilderIG::hasConstantDefinition( Node n ){
+  Node lit = n.getKind()==NOT ? n[0] : n;
+  if( lit.getKind()==APPLY_UF ){
+    Node op = lit.getOperator();
+    if( !d_uf_prefs[op].d_const_val.isNull() ){
+      return true;
+    }
+  }
+  return false;
+}
+
+QModelBuilderIG::Statistics::Statistics():
+  d_num_quants_init("QModelBuilderIG::Number_Quantifiers", 0),
+  d_num_partial_quants_init("QModelBuilderIG::Number_Partial_Quantifiers", 0),
+  d_init_inst_gen_lemmas("QModelBuilderIG::Initialize_Inst_Gen_Lemmas", 0 ),
+  d_inst_gen_lemmas("QModelBuilderIG::Inst_Gen_Lemmas", 0 ),
+  d_eval_formulas("QModelBuilderIG::Eval_Formulas", 0 ),
+  d_eval_uf_terms("QModelBuilderIG::Eval_Uf_Terms", 0 ),
+  d_eval_lits("QModelBuilderIG::Eval_Lits", 0 ),
+  d_eval_lits_unknown("QModelBuilderIG::Eval_Lits_Unknown", 0 )
+{
+  smtStatisticsRegistry()->registerStat(&d_num_quants_init);
+  smtStatisticsRegistry()->registerStat(&d_num_partial_quants_init);
+  smtStatisticsRegistry()->registerStat(&d_init_inst_gen_lemmas);
+  smtStatisticsRegistry()->registerStat(&d_inst_gen_lemmas);
+  smtStatisticsRegistry()->registerStat(&d_eval_formulas);
+  smtStatisticsRegistry()->registerStat(&d_eval_uf_terms);
+  smtStatisticsRegistry()->registerStat(&d_eval_lits);
+  smtStatisticsRegistry()->registerStat(&d_eval_lits_unknown);
+}
+
+QModelBuilderIG::Statistics::~Statistics(){
+  smtStatisticsRegistry()->unregisterStat(&d_num_quants_init);
+  smtStatisticsRegistry()->unregisterStat(&d_num_partial_quants_init);
+  smtStatisticsRegistry()->unregisterStat(&d_init_inst_gen_lemmas);
+  smtStatisticsRegistry()->unregisterStat(&d_inst_gen_lemmas);
+  smtStatisticsRegistry()->unregisterStat(&d_eval_formulas);
+  smtStatisticsRegistry()->unregisterStat(&d_eval_uf_terms);
+  smtStatisticsRegistry()->unregisterStat(&d_eval_lits);
+  smtStatisticsRegistry()->unregisterStat(&d_eval_lits_unknown);
+}
+
+//do exhaustive instantiation
+int QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
+  if( optUseModel() ){
+    QRepBoundExt qrbe(d_qe);
+    RepSetIterator riter(d_qe->getModel()->getRepSet(), &qrbe);
+    if( riter.setQuantifier( f ) ){
+      FirstOrderModelIG * fmig = (FirstOrderModelIG*)d_qe->getModel();
+      Debug("inst-fmf-ei") << "Reset evaluate..." << std::endl;
+      fmig->resetEvaluate();
+      Debug("inst-fmf-ei") << "Begin instantiation..." << std::endl;
+      EqualityQuery* qy = d_qe->getEqualityQuery();
+      Instantiate* inst = d_qe->getInstantiate();
+      TermUtil* util = d_qe->getTermUtil();
+      while( !riter.isFinished() && ( d_addedLemmas==0 || !options::fmfOneInstPerRound() ) ){
+        d_triedLemmas++;
+        if( Debug.isOn("inst-fmf-ei-debug") ){
+          for( int i=0; i<(int)riter.d_index.size(); i++ ){
+            Debug("inst-fmf-ei-debug") << i << " : " << riter.d_index[i] << " : " << riter.getCurrentTerm( i ) << std::endl;
+          }
+        }
+        int eval = 0;
+        int depIndex;
+        //see if instantiation is already true in current model
+        if( Debug.isOn("fmf-model-eval") ){
+          Debug("fmf-model-eval") << "Evaluating ";
+          riter.debugPrintSmall("fmf-model-eval");
+          Debug("fmf-model-eval") << "Done calculating terms." << std::endl;
+        }
+        //if evaluate(...)==1, then the instantiation is already true in the model
+        //  depIndex is the index of the least significant variable that this evaluation relies upon
+        depIndex = riter.getNumTerms()-1;
+        Debug("fmf-model-eval") << "We will evaluate "
+                                << util->getInstConstantBody(f) << std::endl;
+        eval = fmig->evaluate(util->getInstConstantBody(f), depIndex, &riter);
+        if( eval==1 ){
+          Debug("fmf-model-eval") << "  Returned success with depIndex = " << depIndex << std::endl;
+        }else{
+          Debug("fmf-model-eval") << "  Returned " << (eval==-1 ? "failure" : "unknown") << ", depIndex = " << depIndex << std::endl;
+        }
+        if( eval==1 ){
+          //instantiation is already true -> skip
+          riter.incrementAtIndex(depIndex);
+        }else{
+          //instantiation was not shown to be true, construct the match
+          InstMatch m( f );
+          for (unsigned i = 0; i < riter.getNumTerms(); i++)
+          {
+            m.set(qy, i, riter.getCurrentTerm(i));
+          }
+          Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
+          //add as instantiation
+          if (inst->addInstantiation(f, m, true))
+          {
+            d_addedLemmas++;
+            if( d_qe->inConflict() ){
+              break;
+            }
+            //if the instantiation is show to be false, and we wish to skip multiple instantiations at once
+            if( eval==-1 ){
+              riter.incrementAtIndex(depIndex);
+            }else{
+              riter.increment();
+            }
+          }else{
+            Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl;
+            riter.increment();
+          }
+        }
+      }
+      //print debugging information
+      if( fmig ){
+        d_statistics.d_eval_formulas += fmig->d_eval_formulas;
+        d_statistics.d_eval_uf_terms += fmig->d_eval_uf_terms;
+        d_statistics.d_eval_lits += fmig->d_eval_lits;
+        d_statistics.d_eval_lits_unknown += fmig->d_eval_lits_unknown;
+      }
+      Trace("inst-fmf-ei") << "For " << f << ", finished: " << std::endl;
+      Trace("inst-fmf-ei") << "   Inst Tried: " << d_triedLemmas << std::endl;
+      Trace("inst-fmf-ei") << "   Inst Added: " << d_addedLemmas << std::endl;
+      if( d_addedLemmas>1000 ){
+        Trace("model-engine-warn") << "WARNING: many instantiations produced for " << f << ": " << std::endl;
+        Trace("model-engine-warn") << "   Inst Tried: " << d_triedLemmas << std::endl;
+        Trace("model-engine-warn") << "   Inst Added: " << d_addedLemmas << std::endl;
+        Trace("model-engine-warn") << std::endl;
+      }
+    }
+    //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
+    return riter.isIncomplete() ? -1 : 1;
+  }else{
+    return 0;
+  }
+}
+
+
+
+void QModelBuilderDefault::reset( FirstOrderModel* fm ){
+  d_quant_selection_lit.clear();
+  d_quant_selection_lit_candidates.clear();
+  d_quant_selection_lit_terms.clear();
+  d_term_selection_lit.clear();
+  d_op_selection_terms.clear();
+}
+
+
+int QModelBuilderDefault::getSelectionScore( std::vector< Node >& uf_terms ) {
+  /*
+  size_t maxChildren = 0;
+  for( size_t i=0; i<uf_terms.size(); i++ ){
+    if( uf_terms[i].getNumChildren()>maxChildren ){
+      maxChildren = uf_terms[i].getNumChildren();
+    }
+  }
+  //TODO: look at how many entries they have?
+  return (int)maxChildren;
+  */
+  return 0;
+}
+
+void QModelBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f ){
+  if( d_qe->getModel()->isQuantifierActive( f ) ){
+    FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
+    Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl;
+    //the pro/con preferences for this quantifier
+    std::vector< Node > pro_con[2];
+    //the terms in the selection literal we choose
+    std::vector< Node > selectionLitTerms;
+    Trace("inst-gen-debug-quant") << "Inst-gen analyze " << f << std::endl;
+    //for each asserted quantifier f,
+    // - determine selection literals
+    // - check which function/predicates have good and bad definitions for satisfying f
+    if( d_phase_reqs.find( f )==d_phase_reqs.end() ){
+      d_phase_reqs[f].initialize( d_qe->getTermUtil()->getInstConstantBody( f ), true );
+    }
+    int selectLitScore = -1;
+    for( std::map< Node, bool >::iterator it = d_phase_reqs[f].d_phase_reqs.begin(); it != d_phase_reqs[f].d_phase_reqs.end(); ++it ){
+      //the literal n is phase-required for quantifier f
+      Node n = it->first;
+      Node gn = fm->getModelBasis(f, n);
+      Debug("fmf-model-req") << "   Req: " << n << " -> " << it->second << std::endl;
+      bool value;
+      //if the corresponding ground abstraction literal has a SAT value
+      if( d_qe->getValuation().hasSatValue( gn, value ) ){
+        //collect the non-ground uf terms that this literal contains
+        //  and compute if all of the symbols in this literal have
+        //  constant definitions.
+        bool isConst = true;
+        std::vector< Node > uf_terms;
+        if( TermUtil::hasInstConstAttr(n) ){
+          isConst = false;
+          if( gn.getKind()==APPLY_UF ){
+            uf_terms.push_back( gn );
+            isConst = hasConstantDefinition( gn );
+          }else if( gn.getKind()==EQUAL ){
+            isConst = true;
+            for( int j=0; j<2; j++ ){
+              if( TermUtil::hasInstConstAttr(n[j]) ){
+                if( n[j].getKind()==APPLY_UF &&
+                    fmig->d_uf_model_tree.find( gn[j].getOperator() )!=fmig->d_uf_model_tree.end() ){
+                  uf_terms.push_back( gn[j] );
+                  isConst = isConst && hasConstantDefinition( gn[j] );
+                }else{
+                  isConst = false;
+                }
+              }
+            }
+          }
+        }
+        //check if the value in the SAT solver matches the preference according to the quantifier
+        int pref = 0;
+        if( value!=it->second ){
+          //we have a possible selection literal
+          bool selectLit = d_quant_selection_lit[f].isNull();
+          bool selectLitConstraints = true;
+          //it is a constantly defined selection literal : the quantifier is sat
+          if( isConst ){
+            selectLit = selectLit || d_qe->getModel()->isQuantifierActive( f );
+            d_qe->getModel()->setQuantifierActive( f, false );
+            //check if choosing this literal would add any additional constraints to default definitions
+            selectLitConstraints = false;
+            for( int j=0; j<(int)uf_terms.size(); j++ ){
+              Node op = uf_terms[j].getOperator();
+              if( d_uf_prefs[op].d_reconsiderModel ){
+                selectLitConstraints = true;
+              }
+            }
+            if( !selectLitConstraints ){
+              selectLit = true;
+            }
+          }
+          //also check if it is naturally a better literal
+          if( !selectLit ){
+            int score = getSelectionScore( uf_terms );
+            //Trace("inst-gen-debug") << "Check " << score << " < " << selectLitScore << std::endl;
+            selectLit = score<selectLitScore;
+          }
+          //see if we wish to choose this as a selection literal
+          d_quant_selection_lit_candidates[f].push_back( value ? n : n.notNode() );
+          if( selectLit ){
+            selectLitScore = getSelectionScore( uf_terms );
+            Trace("inst-gen-debug") << "Choose selection literal " << gn << std::endl;
+            Trace("inst-gen-debug") << "  flags: " << isConst << " " << selectLitConstraints << " " << selectLitScore << std::endl;
+            d_quant_selection_lit[f] = value ? n : n.notNode();
+            selectionLitTerms.clear();
+            selectionLitTerms.insert( selectionLitTerms.begin(), uf_terms.begin(), uf_terms.end() );
+            if( !selectLitConstraints ){
+              break;
+            }
+          }
+          pref = 1;
+        }else{
+          pref = -1;
+        }
+        //if we are not yet SAT, so we will add to preferences
+        if( d_qe->getModel()->isQuantifierActive( f ) ){
+          Debug("fmf-model-prefs") << "  It is " << ( pref==1 ? "pro" : "con" );
+          Debug("fmf-model-prefs") << " the definition of " << n << std::endl;
+          for( int j=0; j<(int)uf_terms.size(); j++ ){
+            pro_con[ pref==1 ? 0 : 1 ].push_back( uf_terms[j] );
+          }
+        }
+      }
+    }
+    //process information about selection literal for f
+    if( !d_quant_selection_lit[f].isNull() ){
+      d_quant_selection_lit_terms[f].insert( d_quant_selection_lit_terms[f].begin(), selectionLitTerms.begin(), selectionLitTerms.end() );
+      for( int i=0; i<(int)selectionLitTerms.size(); i++ ){
+        d_term_selection_lit[ selectionLitTerms[i] ] = d_quant_selection_lit[f];
+        d_op_selection_terms[ selectionLitTerms[i].getOperator() ].push_back( selectionLitTerms[i] );
+      }
+    }else{
+      Trace("inst-gen-warn") << "WARNING: " << f << " has no selection literals" << std::endl;
+    }
+    //process information about requirements and preferences of quantifier f
+    if( !d_qe->getModel()->isQuantifierActive( f ) ){
+      Debug("fmf-model-prefs") << "  * Constant SAT due to definition of ops: ";
+      for( int i=0; i<(int)selectionLitTerms.size(); i++ ){
+        Debug("fmf-model-prefs") << selectionLitTerms[i] << " ";
+        d_uf_prefs[ selectionLitTerms[i].getOperator() ].d_reconsiderModel = false;
+      }
+      Debug("fmf-model-prefs") << std::endl;
+    }else{
+      //note quantifier's value preferences to models
+      for( int k=0; k<2; k++ ){
+        for( int j=0; j<(int)pro_con[k].size(); j++ ){
+          Node op = pro_con[k][j].getOperator();
+          Node r = fmig->getRepresentative( pro_con[k][j] );
+          d_uf_prefs[op].setValuePreference( f, pro_con[k][j], r, k==0 );
+        }
+      }
+    }
+  }
+}
+
+int QModelBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
+  int addedLemmas = 0;
+  //we wish to add all known exceptions to our selection literal for f. this will help to refine our current model.
+  //This step is advantageous over exhaustive instantiation, since we are adding instantiations that involve model basis terms,
+  //  effectively acting as partial instantiations instead of pointwise instantiations.
+  if( !d_quant_selection_lit[f].isNull() ){
+    Trace("inst-gen") << "Do Inst-Gen for " << f << std::endl;
+    for( size_t i=0; i<d_quant_selection_lit_candidates[f].size(); i++ ){
+      bool phase = d_quant_selection_lit_candidates[f][i].getKind()!=NOT;
+      Node lit = d_quant_selection_lit_candidates[f][i].getKind()==NOT ? d_quant_selection_lit_candidates[f][i][0] : d_quant_selection_lit_candidates[f][i];
+      Assert( TermUtil::hasInstConstAttr(lit) );
+      std::vector< Node > tr_terms;
+      if( lit.getKind()==APPLY_UF ){
+        //only match predicates that are contrary to this one, use literal matching
+        Node eq = NodeManager::currentNM()->mkNode(
+            EQUAL, lit, NodeManager::currentNM()->mkConst(!phase));
+        tr_terms.push_back( eq );
+      }else if( lit.getKind()==EQUAL ){
+        //collect trigger terms
+        for( int j=0; j<2; j++ ){
+          if( TermUtil::hasInstConstAttr(lit[j]) ){
+            if( lit[j].getKind()==APPLY_UF ){
+              tr_terms.push_back( lit[j] );
+            }else{
+              tr_terms.clear();
+              break;
+            }
+          }
+        }
+        if( tr_terms.size()==1 && !phase ){
+          //equality between a function and a ground term, use literal matching
+          tr_terms.clear();
+          tr_terms.push_back( lit );
+        }
+      }
+      //if applicable, try to add exceptions here
+      if( !tr_terms.empty() ){
+        //make a trigger for these terms, add instantiations
+        inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, true, inst::Trigger::TR_MAKE_NEW );
+        //Notice() << "Trigger = " << (*tr) << std::endl;
+        tr->resetInstantiationRound();
+        tr->reset( Node::null() );
+        //d_qe->d_optInstMakeRepresentative = false;
+        //d_qe->d_optMatchIgnoreModelBasis = true;
+        addedLemmas += tr->addInstantiations();
+      }
+    }
+  }
+  return addedLemmas;
+}
+
+void QModelBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op ){
+  FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
+  if( optReconsiderFuncConstants() ){
+    //reconsider constant functions that weren't necessary
+    if( d_uf_model_constructed[op] ){
+      if( d_uf_prefs[op].d_reconsiderModel ){
+        //if we are allowed to reconsider default value, then see if the default value can be improved
+        Node v = d_uf_prefs[op].d_const_val;
+        if( d_uf_prefs[op].d_value_pro_con[0][v].empty() ){
+          Debug("fmf-model-cons-debug") << "Consider changing the default value for " << op << std::endl;
+          fmig->d_uf_model_tree[op].clear();
+          fmig->d_uf_model_gen[op].clear();
+          d_uf_model_constructed[op] = false;
+        }
+      }
+    }
+  }
+  if( !d_uf_model_constructed[op] ){
+    //construct the model for the uninterpretted function/predicate
+    bool setDefaultVal = true;
+    Node defaultTerm = fmig->getModelBasisOpTerm(op);
+    Trace("fmf-model-cons") << "Construct model for " << op << "..." << std::endl;
+    //set the values in the model
+    std::map< Node, std::vector< Node > >::iterator itut = fmig->d_uf_terms.find( op );
+    if( itut!=fmig->d_uf_terms.end() ){
+      for( size_t i=0; i<itut->second.size(); i++ ){
+        Node n = itut->second[i];
+        // only consider unique up to congruence (in model equality engine)?
+        Node v = fmig->getRepresentative( n );
+        Trace("fmf-model-cons") << "Set term " << n << " : "
+                                << fmig->getRepSet()->getIndexFor(v) << " " << v
+                                << std::endl;
+        //if this assertion did not help the model, just consider it ground
+        //set n = v in the model tree
+        //set it as ground value
+        fmig->d_uf_model_gen[op].setValue( fm, n, v );
+        if( fmig->d_uf_model_gen[op].optUsePartialDefaults() ){
+          //also set as default value if necessary
+          if( n.hasAttribute(ModelBasisArgAttribute()) && n.getAttribute(ModelBasisArgAttribute())!=0 ){
+            Trace("fmf-model-cons") << "  Set as default." << std::endl;
+            fmig->d_uf_model_gen[op].setValue( fm, n, v, false );
+            if( n==defaultTerm ){
+              //incidentally already set, we will not need to find a default value
+              setDefaultVal = false;
+            }
+          }
+        }else{
+          if( n==defaultTerm ){
+            fmig->d_uf_model_gen[op].setValue( fm, n, v, false );
+            //incidentally already set, we will not need to find a default value
+            setDefaultVal = false;
+          }
+        }
+      }
+    }
+    //set the overall default value if not set already  (is this necessary??)
+    if( setDefaultVal ){
+      Trace("fmf-model-cons") << "  Choose default value..." << std::endl;
+      //chose defaultVal based on heuristic, currently the best ratio of "pro" responses
+      Node defaultVal = d_uf_prefs[op].getBestDefaultValue( defaultTerm, fm );
+      if( defaultVal.isNull() ){
+        if (!fmig->getRepSet()->hasType(defaultTerm.getType()))
+        {
+          Node mbt = fmig->getModelBasisTerm(defaultTerm.getType());
+          fmig->getRepSetPtr()->d_type_reps[defaultTerm.getType()].push_back(
+              mbt);
+        }
+        defaultVal =
+            fmig->getRepSet()->getRepresentative(defaultTerm.getType(), 0);
+      }
+      Assert( !defaultVal.isNull() );
+      Trace("fmf-model-cons")
+          << "Set default term : " << fmig->getRepSet()->getIndexFor(defaultVal)
+          << std::endl;
+      fmig->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
+    }
+    Debug("fmf-model-cons") << "  Making model...";
+    fmig->d_uf_model_gen[op].makeModel( fm, fmig->d_uf_model_tree[op] );
+    d_uf_model_constructed[op] = true;
+    Debug("fmf-model-cons") << "  Finished constructing model for " << op << "." << std::endl;
+  }
+}
diff --git a/src/theory/quantifiers/fmf/model_builder.h b/src/theory/quantifiers/fmf/model_builder.h
new file mode 100644 (file)
index 0000000..4eb592b
--- /dev/null
@@ -0,0 +1,202 @@
+/*********************                                                        */
+/*! \file model_builder.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Morgan Deters, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Model Builder class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__MODEL_BUILDER_H
+#define __CVC4__THEORY__QUANTIFIERS__MODEL_BUILDER_H
+
+#include "theory/quantifiers_engine.h"
+#include "theory/theory_model_builder.h"
+#include "theory/uf/theory_uf_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+
+class QModelBuilder : public TheoryEngineModelBuilder
+{
+protected:
+  //quantifiers engine
+  QuantifiersEngine* d_qe;
+  bool preProcessBuildModel(TheoryModel* m); //must call preProcessBuildModelStd
+  bool preProcessBuildModelStd(TheoryModel* m);
+  /** number of lemmas generated while building model */
+  unsigned d_addedLemmas;
+  unsigned d_triedLemmas;
+public:
+  QModelBuilder( context::Context* c, QuantifiersEngine* qe );
+
+  //do exhaustive instantiation  
+  // 0 :  failed, but resorting to true exhaustive instantiation may work
+  // >0 : success
+  // <0 : failed
+  virtual int doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { return false; }
+  //whether to construct model
+  virtual bool optUseModel();
+  /** exist instantiation ? */
+  virtual bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false ) { return false; }
+  //debug model
+  virtual void debugModel( TheoryModel* m );
+  //statistics 
+  unsigned getNumAddedLemmas() { return d_addedLemmas; }
+  unsigned getNumTriedLemmas() { return d_triedLemmas; }
+};
+
+
+
+
+
+class TermArgBasisTrie {
+public:
+  /** the data */
+  std::map< Node, TermArgBasisTrie > d_data;
+  /** add term to the trie */
+  bool addTerm(FirstOrderModel* fm, Node n, unsigned argIndex = 0);
+};/* class TermArgBasisTrie */
+
+/** model builder class
+  *  This class is capable of building candidate models based on the current quantified formulas
+  *  that are asserted.  Use:
+  *  (1) call QModelBuilder::buildModel( m, false );, where m is a FirstOrderModel
+  *  (2) if candidate model is determined to be a real model,
+           then call QModelBuilder::buildModel( m, true );
+  */
+class QModelBuilderIG : public QModelBuilder
+{
+  typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
+
+ protected:
+  BoolMap d_basisNoMatch;
+  //map from operators to model preference data
+  std::map< Node, uf::UfModelPreferenceData > d_uf_prefs;
+  //built model uf
+  std::map< Node, bool > d_uf_model_constructed;
+  //whether inst gen was done
+  bool d_didInstGen;
+  /** process build model */
+  virtual bool processBuildModel( TheoryModel* m );
+
+ protected:
+  //reset
+  virtual void reset( FirstOrderModel* fm ) = 0;
+  //initialize quantifiers, return number of lemmas produced
+  virtual int initializeQuantifier(Node f, Node fp, FirstOrderModel* fm);
+  //analyze model
+  virtual void analyzeModel( FirstOrderModel* fm );
+  //analyze quantifiers
+  virtual void analyzeQuantifier( FirstOrderModel* fm, Node f ) = 0;
+  //do InstGen techniques for quantifier, return number of lemmas produced
+  virtual int doInstGen( FirstOrderModel* fm, Node f ) = 0;
+  //theory-specific build models
+  virtual void constructModelUf( FirstOrderModel* fm, Node op ) = 0;
+
+ protected:
+  //map from quantifiers to if are SAT
+  //std::map< Node, bool > d_quant_sat;
+  //which quantifiers have been initialized
+  std::map< Node, bool > d_quant_basis_match_added;
+  //map from quantifiers to model basis match
+  std::map< Node, InstMatch > d_quant_basis_match;
+
+ protected:  // helper functions
+  /** term has constant definition */
+  bool hasConstantDefinition( Node n );
+
+ public:
+  QModelBuilderIG( context::Context* c, QuantifiersEngine* qe );
+
+ public:
+  /** statistics class */
+  class Statistics {
+  public:
+    IntStat d_num_quants_init;
+    IntStat d_num_partial_quants_init;
+    IntStat d_init_inst_gen_lemmas;
+    IntStat d_inst_gen_lemmas;
+    IntStat d_eval_formulas;
+    IntStat d_eval_uf_terms;
+    IntStat d_eval_lits;
+    IntStat d_eval_lits_unknown;
+    Statistics();
+    ~Statistics();
+  };
+  Statistics d_statistics;
+  // is term selected
+  virtual bool isTermSelected( Node n ) { return false; }
+  /** quantifier has inst-gen definition */
+  virtual bool hasInstGen( Node f ) = 0;
+  /** did inst gen this round? */
+  bool didInstGen() { return d_didInstGen; }
+  // is quantifier active?
+  bool isQuantifierActive( Node f );
+  //do exhaustive instantiation
+  int doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort );
+
+  //temporary stats
+  int d_numQuantSat;
+  int d_numQuantInstGen;
+  int d_numQuantNoInstGen;
+  int d_numQuantNoSelForm;
+  //temporary stat
+  int d_instGenMatches;
+};/* class QModelBuilder */
+
+
+class QModelBuilderDefault : public QModelBuilderIG
+{
+ private:  /// information for (old) InstGen
+  // map from quantifiers to their selection literals
+  std::map< Node, Node > d_quant_selection_lit;
+  std::map< Node, std::vector< Node > > d_quant_selection_lit_candidates;
+  //map from quantifiers to their selection literal terms
+  std::map< Node, std::vector< Node > > d_quant_selection_lit_terms;
+  //map from terms to the selection literals they exist in
+  std::map< Node, Node > d_term_selection_lit;
+  //map from operators to terms that appear in selection literals
+  std::map< Node, std::vector< Node > > d_op_selection_terms;
+  //get selection score
+  int getSelectionScore( std::vector< Node >& uf_terms );
+
+ protected:
+  //reset
+  void reset(FirstOrderModel* fm) override;
+  //analyze quantifier
+  void analyzeQuantifier(FirstOrderModel* fm, Node f) override;
+  //do InstGen techniques for quantifier, return number of lemmas produced
+  int doInstGen(FirstOrderModel* fm, Node f) override;
+  //theory-specific build models
+  void constructModelUf(FirstOrderModel* fm, Node op) override;
+
+ protected:
+  std::map< Node, QuantPhaseReq > d_phase_reqs;
+
+ public:
+  QModelBuilderDefault( context::Context* c, QuantifiersEngine* qe ) : QModelBuilderIG( c, qe ){}
+
+  //options
+  bool optReconsiderFuncConstants() { return true; }
+  //has inst gen
+  bool hasInstGen(Node f) override
+  {
+    return !d_quant_selection_lit[f].isNull();
+  }
+};
+
+}/* CVC4::theory::quantifiers namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__MODEL_BUILDER_H */
diff --git a/src/theory/quantifiers/fmf/model_engine.cpp b/src/theory/quantifiers/fmf/model_engine.cpp
new file mode 100644 (file)
index 0000000..3f3c219
--- /dev/null
@@ -0,0 +1,342 @@
+/*********************                                                        */
+/*! \file model_engine.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Morgan Deters, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of model engine class
+ **/
+
+#include "theory/quantifiers/fmf/model_engine.h"
+
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/fmf/ambqi_builder.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/fmf/full_model_check.h"
+#include "theory/quantifiers/instantiate.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/theory_engine.h"
+#include "theory/uf/equality_engine.h"
+#include "theory/uf/theory_uf.h"
+#include "theory/uf/theory_uf_strong_solver.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::theory::inst;
+
+//Model Engine constructor
+ModelEngine::ModelEngine( context::Context* c, QuantifiersEngine* qe ) :
+QuantifiersModule( qe ),
+d_incomplete_check(true),
+d_addedLemmas(0),
+d_triedLemmas(0),
+d_totalLemmas(0)
+{
+
+}
+
+ModelEngine::~ModelEngine() {
+
+}
+
+bool ModelEngine::needsCheck( Theory::Effort e ) {
+  return e==Theory::EFFORT_LAST_CALL;
+}
+
+QuantifiersModule::QEffort ModelEngine::needsModel(Theory::Effort e)
+{
+  if( options::mbqiInterleave() ){
+    return QEFFORT_STANDARD;
+  }else{
+    return QEFFORT_MODEL;
+  }
+}
+
+void ModelEngine::reset_round( Theory::Effort e ) {
+  d_incomplete_check = true;
+}
+void ModelEngine::check(Theory::Effort e, QEffort quant_e)
+{
+  bool doCheck = false;
+  if( options::mbqiInterleave() ){
+    doCheck = quant_e == QEFFORT_STANDARD && d_quantEngine->hasAddedLemma();
+  }
+  if( !doCheck ){
+    doCheck = quant_e == QEFFORT_MODEL;
+  }
+  if( doCheck ){
+    Assert( !d_quantEngine->inConflict() );
+    int addedLemmas = 0;
+    FirstOrderModel* fm = d_quantEngine->getModel();
+
+    //the following will test that the model satisfies all asserted universal quantifiers by
+    // (model-based) exhaustive instantiation.
+    double clSet = 0;
+    if( Trace.isOn("model-engine") ){
+      Trace("model-engine") << "---Model Engine Round---" << std::endl;
+      clSet = double(clock())/double(CLOCKS_PER_SEC);
+    }
+
+    Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl;
+    //let the strong solver verify that the model is minimal
+    //for debugging, this will if there are terms in the model that the strong solver was not notified of
+    uf::StrongSolverTheoryUF * ufss = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver();
+    if( !ufss || ufss->debugModel( fm ) ){
+      Trace("model-engine-debug") << "Check model..." << std::endl;
+      d_incomplete_check = false;
+      //print debug
+      if( Trace.isOn("fmf-model-complete") ){
+        Trace("fmf-model-complete") << std::endl;
+        debugPrint("fmf-model-complete");
+      }
+      //successfully built an acceptable model, now check it
+      addedLemmas += checkModel();
+    }else{
+      addedLemmas++;
+    }
+
+    if( Trace.isOn("model-engine") ){
+      double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+      Trace("model-engine") << "Finished model engine, time = " << (clSet2-clSet) << std::endl;
+    }
+
+    if( addedLemmas==0 ){
+      Trace("model-engine-debug") << "No lemmas added, incomplete = " << ( d_incomplete_check || !d_incomplete_quants.empty() ) << std::endl;
+      //CVC4 will answer SAT or unknown
+      if( Trace.isOn("fmf-consistent") ){
+        Trace("fmf-consistent") << std::endl;
+        debugPrint("fmf-consistent");
+      }
+    }
+  }
+}
+
+bool ModelEngine::checkComplete() {
+  return !d_incomplete_check;
+}
+
+bool ModelEngine::checkCompleteFor( Node q ) {
+  return std::find( d_incomplete_quants.begin(), d_incomplete_quants.end(), q )==d_incomplete_quants.end();
+}
+
+void ModelEngine::registerQuantifier( Node f ){
+  if( Trace.isOn("fmf-warn") ){
+    bool canHandle = true;
+    for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
+      TypeNode tn = f[0][i].getType();
+      if( !tn.isSort() ){
+        if( !tn.getCardinality().isFinite() ){
+          if( tn.isInteger() ){
+            if( !options::fmfBound() ){
+              canHandle = false;
+            }
+          }else{
+            canHandle = false;
+          }
+        }
+      }
+    }
+    if( !canHandle ){
+      Trace("fmf-warn") << "Warning : Model Engine : may not be able to answer SAT because of formula : " << f << std::endl;
+    }
+  }
+}
+
+void ModelEngine::assertNode( Node f ){
+
+}
+
+bool ModelEngine::optOneQuantPerRound(){
+  return options::fmfOneQuantPerRound();
+}
+
+
+int ModelEngine::checkModel(){
+  FirstOrderModel* fm = d_quantEngine->getModel();
+
+  //flatten the representatives
+  //Trace("model-engine-debug") << "Flattening representatives...." << std::endl;
+  // d_quantEngine->getEqualityQuery()->flattenRepresentatives(
+  // fm->getRepSet()->d_type_reps );
+
+  //for debugging, setup
+  for (std::map<TypeNode, std::vector<Node> >::iterator it =
+           fm->getRepSetPtr()->d_type_reps.begin();
+       it != fm->getRepSetPtr()->d_type_reps.end();
+       ++it)
+  {
+    if( it->first.isSort() ){
+      Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
+      Trace("model-engine-debug") << "        Reps : ";
+      for( size_t i=0; i<it->second.size(); i++ ){
+        Trace("model-engine-debug") << it->second[i] << "  ";
+      }
+      Trace("model-engine-debug") << std::endl;
+      Trace("model-engine-debug") << "   Term reps : ";
+      for( size_t i=0; i<it->second.size(); i++ ){
+        Node r = d_quantEngine->getInternalRepresentative( it->second[i], Node::null(), 0 );
+        Trace("model-engine-debug") << r << " ";
+      }
+      Trace("model-engine-debug") << std::endl;
+      Node mbt = fm->getModelBasisTerm(it->first);
+      Trace("model-engine-debug") << "  Basis term : " << mbt << std::endl;
+    }
+  }
+
+  d_triedLemmas = 0;
+  d_addedLemmas = 0;
+  d_totalLemmas = 0;
+  //for statistics
+  if( Trace.isOn("model-engine") ){
+    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+      Node f = fm->getAssertedQuantifier( i );
+      if( d_quantEngine->getModel()->isQuantifierActive( f ) && d_quantEngine->hasOwnership( f, this ) ){
+        int totalInst = 1;
+        for( unsigned j=0; j<f[0].getNumChildren(); j++ ){
+          TypeNode tn = f[0][j].getType();
+          if (fm->getRepSet()->hasType(tn))
+          {
+            totalInst =
+                totalInst * (int)fm->getRepSet()->getNumRepresentatives(tn);
+          }
+        }
+        d_totalLemmas += totalInst;
+      }
+    }
+  }
+
+  Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl;
+  // FMC uses two sub-effort levels
+  int e_max = options::mbqiMode()==MBQI_FMC || options::mbqiMode()==MBQI_FMC_INTERVAL ? 2 : ( options::mbqiMode()==MBQI_TRUST ? 0 : 1 );
+  for( int e=0; e<e_max; e++) {
+    d_incomplete_quants.clear();
+    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+      Node q = fm->getAssertedQuantifier( i, true );
+      Trace("fmf-exh-inst") << "-> Exhaustive instantiate " << q << ", effort = " << e << "..." << std::endl;
+      //determine if we should check this quantifier
+      if( d_quantEngine->getModel()->isQuantifierActive( q ) && d_quantEngine->hasOwnership( q, this ) ){
+        exhaustiveInstantiate( q, e );
+        if( d_quantEngine->inConflict() || ( optOneQuantPerRound() && d_addedLemmas>0 ) ){
+          break;
+        }
+      }else{
+        Trace("fmf-exh-inst") << "-> Inactive : " << q << std::endl;
+      }
+    }
+    if( d_addedLemmas>0 ){
+      break;
+    }else{
+      Assert( !d_quantEngine->inConflict() );
+    }
+  }
+
+  //print debug information
+  if( d_quantEngine->inConflict() ){
+    Trace("model-engine") << "Conflict, added lemmas = ";
+  }else{
+    Trace("model-engine") << "Added Lemmas = ";
+  } 
+  Trace("model-engine") << d_addedLemmas << " / " << d_triedLemmas << " / ";
+  Trace("model-engine") << d_totalLemmas << std::endl;
+  return d_addedLemmas;
+}
+
+
+
+void ModelEngine::exhaustiveInstantiate( Node f, int effort ){
+  //first check if the builder can do the exhaustive instantiation
+  quantifiers::QModelBuilder * mb = d_quantEngine->getModelBuilder();
+  unsigned prev_alem = mb->getNumAddedLemmas();
+  unsigned prev_tlem = mb->getNumTriedLemmas();
+  int retEi = mb->doExhaustiveInstantiation( d_quantEngine->getModel(), f, effort );
+  if( retEi!=0 ){
+    if( retEi<0 ){
+      Trace("fmf-exh-inst") << "-> Builder determined complete instantiation was impossible." << std::endl;
+      d_incomplete_quants.push_back( f );
+    }else{
+      Trace("fmf-exh-inst") << "-> Builder determined instantiation(s)." << std::endl;
+    }
+    d_triedLemmas += mb->getNumTriedLemmas()-prev_tlem;
+    d_addedLemmas += mb->getNumAddedLemmas()-prev_alem;
+    d_quantEngine->d_statistics.d_instantiations_fmf_mbqi += mb->getNumAddedLemmas();
+  }else{
+    if( Trace.isOn("fmf-exh-inst-debug") ){
+      Trace("fmf-exh-inst-debug") << "   Instantiation Constants: ";
+      for( size_t i=0; i<f[0].getNumChildren(); i++ ){
+        Trace("fmf-exh-inst-debug") << d_quantEngine->getTermUtil()->getInstantiationConstant( f, i ) << " ";
+      }
+      Trace("fmf-exh-inst-debug") << std::endl;
+    }
+    //create a rep set iterator and iterate over the (relevant) domain of the quantifier
+    QRepBoundExt qrbe(d_quantEngine);
+    RepSetIterator riter(d_quantEngine->getModel()->getRepSet(), &qrbe);
+    if( riter.setQuantifier( f ) ){
+      Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter.isIncomplete() << "..." << std::endl;
+      if( !riter.isIncomplete() ){
+        int triedLemmas = 0;
+        int addedLemmas = 0;
+        EqualityQuery* qy = d_quantEngine->getEqualityQuery();
+        Instantiate* inst = d_quantEngine->getInstantiate();
+        while( !riter.isFinished() && ( addedLemmas==0 || !options::fmfOneInstPerRound() ) ){
+          //instantiation was not shown to be true, construct the match
+          InstMatch m( f );
+          for (unsigned i = 0; i < riter.getNumTerms(); i++)
+          {
+            m.set(qy, i, riter.getCurrentTerm(i));
+          }
+          Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
+          triedLemmas++;
+          //add as instantiation
+          if (inst->addInstantiation(f, m, true))
+          {
+            addedLemmas++;
+            if( d_quantEngine->inConflict() ){
+              break;
+            }
+          }else{
+            Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl;
+          }
+          riter.increment();
+        }
+        d_addedLemmas += addedLemmas;
+        d_triedLemmas += triedLemmas;
+        d_quantEngine->d_statistics.d_instantiations_fmf_exh += addedLemmas;
+      }
+    }else{
+      Trace("fmf-exh-inst") << "...exhaustive instantiation did set, incomplete=" << riter.isIncomplete() << "..." << std::endl;
+    }
+    //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
+    if( riter.isIncomplete() ){
+      d_incomplete_quants.push_back( f );
+    }
+  }
+}
+
+void ModelEngine::debugPrint( const char* c ){
+  Trace( c ) << "Quantifiers: " << std::endl;
+  for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
+    Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
+    if( d_quantEngine->hasOwnership( q, this ) ){
+      Trace( c ) << "   ";
+      if( !d_quantEngine->getModel()->isQuantifierActive( q ) ){
+        Trace( c ) << "*Inactive* ";
+      }else{
+        Trace( c ) << "           ";
+      }
+      Trace( c ) << q << std::endl;
+    }
+  }
+  //d_quantEngine->getModel()->debugPrint( c );
+}
+
diff --git a/src/theory/quantifiers/fmf/model_engine.h b/src/theory/quantifiers/fmf/model_engine.h
new file mode 100644 (file)
index 0000000..0903747
--- /dev/null
@@ -0,0 +1,70 @@
+/*********************                                                        */
+/*! \file model_engine.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Morgan Deters, Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Model Engine class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__MODEL_ENGINE_H
+#define __CVC4__THEORY__QUANTIFIERS__MODEL_ENGINE_H
+
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/fmf/model_builder.h"
+#include "theory/theory_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class ModelEngine : public QuantifiersModule
+{
+  friend class RepSetIterator;
+private:
+  //options
+  bool optOneQuantPerRound();
+private:
+  //check model
+  int checkModel();
+  //exhaustively instantiate quantifier (possibly using mbqi)
+  void exhaustiveInstantiate( Node f, int effort = 0 );
+private:
+  //temporary statistics
+  //is the exhaustive instantiation incomplete?
+  bool d_incomplete_check;
+  // set of quantified formulas for which check was incomplete
+  std::vector< Node > d_incomplete_quants;
+  int d_addedLemmas;
+  int d_triedLemmas;
+  int d_totalLemmas;
+public:
+  ModelEngine( context::Context* c, QuantifiersEngine* qe );
+  virtual ~ModelEngine();
+public:
+  bool needsCheck( Theory::Effort e );
+  QEffort needsModel(Theory::Effort e);
+  void reset_round( Theory::Effort e );
+  void check(Theory::Effort e, QEffort quant_e);
+  bool checkComplete();
+  bool checkCompleteFor( Node q );
+  void registerQuantifier( Node f );
+  void assertNode( Node f );
+  Node explain(TNode n){ return Node::null(); }
+  void debugPrint( const char* c );
+  /** Identify this module */
+  std::string identify() const { return "ModelEngine"; }
+};/* class ModelEngine */
+
+}/* CVC4::theory::quantifiers namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__MODEL_ENGINE_H */
diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp
deleted file mode 100644 (file)
index 4da23ea..0000000
+++ /dev/null
@@ -1,1518 +0,0 @@
-/*********************                                                        */
-/*! \file full_model_check.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Morgan Deters, Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of full model check class
- **/
-
-#include "theory/quantifiers/full_model_check.h"
-#include "options/quantifiers_options.h"
-#include "options/uf_options.h"
-#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace CVC4::theory::inst;
-using namespace CVC4::theory::quantifiers::fmcheck;
-
-struct ModelBasisArgSort
-{
-  std::vector< Node > d_terms;
-  // number of arguments that are model-basis terms
-  std::unordered_map<Node, unsigned, NodeHashFunction> d_mba_count;
-  bool operator() (int i,int j) {
-    return (d_mba_count[d_terms[i]] < d_mba_count[d_terms[j]]);
-  }
-};
-
-
-struct ConstRationalSort
-{
-  std::vector< Node > d_terms;
-  bool operator() (int i, int j) {
-    return (d_terms[i].getConst<Rational>() < d_terms[j].getConst<Rational>() );
-  }
-};
-
-
-bool EntryTrie::hasGeneralization( FirstOrderModelFmc * m, Node c, int index ) {
-  if (index==(int)c.getNumChildren()) {
-    return d_data!=-1;
-  }else{
-    TypeNode tn = c[index].getType();
-    Node st = m->getStar(tn);
-    if(d_child.find(st)!=d_child.end()) {
-      if( d_child[st].hasGeneralization(m, c, index+1) ){
-        return true;
-      }
-    }
-    if( c[index]!=st && d_child.find( c[index] )!=d_child.end() ){
-      if( d_child[ c[index] ].hasGeneralization(m, c, index+1) ){
-        return true;
-      }
-    }
-    if( c[index].getType().isSort() ){
-      //for star: check if all children are defined and have generalizations
-      if( c[index]==st ){     ///options::fmfFmcCoverSimplify()
-        //check if all children exist and are complete
-        unsigned num_child_def =
-            d_child.size() - (d_child.find(st) != d_child.end() ? 1 : 0);
-        if (num_child_def == m->getRepSet()->getNumRepresentatives(tn))
-        {
-          bool complete = true;
-          for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
-            if( !m->isStar(it->first) ){
-              if( !it->second.hasGeneralization(m, c, index+1) ){
-                complete = false;
-                break;
-              }
-            }
-          }
-          if( complete ){
-            return true;
-          }
-        }
-      }
-    }
-
-    return false;
-  }
-}
-
-int EntryTrie::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node> & inst, int index ) {
-  Debug("fmc-entry-trie") << "Get generalization index " << inst.size() << " " << index << std::endl;
-  if (index==(int)inst.size()) {
-    return d_data;
-  }else{
-    int minIndex = -1;
-    if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && inst[index].getType().isInteger() ){
-      for( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
-        //if( !m->isInterval( it->first ) ){
-        //  std::cout << "Not an interval during getGenIndex " << it->first << std::endl;
-        //  exit( 11 );
-        //}
-        //check if it is in the range
-        if( m->isInRange(inst[index], it->first )  ){
-          int gindex = it->second.getGeneralizationIndex(m, inst, index+1);
-          if( minIndex==-1 || (gindex!=-1 && gindex<minIndex) ){
-            minIndex = gindex;
-          }
-        }
-      }
-    }else{
-      Node st = m->getStar(inst[index].getType());
-      if(d_child.find(st)!=d_child.end()) {
-        minIndex = d_child[st].getGeneralizationIndex(m, inst, index+1);
-      }
-      Node cc = inst[index];
-      if( cc!=st && d_child.find( cc )!=d_child.end() ){
-        int gindex = d_child[ cc ].getGeneralizationIndex(m, inst, index+1);
-        if (minIndex==-1 || (gindex!=-1 && gindex<minIndex) ){
-          minIndex = gindex;
-        }
-      }
-    }
-    return minIndex;
-  }
-}
-
-void EntryTrie::addEntry( FirstOrderModelFmc * m, Node c, Node v, int data, int index ) {
-  if (index==(int)c.getNumChildren()) {
-    if(d_data==-1) {
-      d_data = data;
-    }
-  }
-  else {
-    d_child[ c[index] ].addEntry(m,c,v,data,index+1);
-    if( d_complete==0 ){
-      d_complete = -1;
-    }
-  }
-}
-
-void EntryTrie::getEntries( FirstOrderModelFmc * m, Node c, std::vector<int> & compat, std::vector<int> & gen, int index, bool is_gen ) {
-  if (index==(int)c.getNumChildren()) {
-    if( d_data!=-1) {
-      if( is_gen ){
-        gen.push_back(d_data);
-      }
-      compat.push_back(d_data);
-    }
-  }else{
-    if (m->isStar(c[index])) {
-      for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
-        it->second.getEntries(m, c, compat, gen, index+1, is_gen );
-      }
-    }else{
-      Node st = m->getStar(c[index].getType());
-      if(d_child.find(st)!=d_child.end()) {
-        d_child[st].getEntries(m, c, compat, gen, index+1, false);
-      }
-      if( d_child.find( c[index] )!=d_child.end() ){
-        d_child[ c[index] ].getEntries(m, c, compat, gen, index+1, is_gen);
-      }
-    }
-
-  }
-}
-
-void EntryTrie::collectIndices(Node c, int index, std::vector< int >& indices ) {
-  if (index==(int)c.getNumChildren()) {
-    if( d_data!=-1 ){
-      indices.push_back( d_data );
-    }
-  }else{
-    for ( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
-      it->second.collectIndices(c, index+1, indices );
-    }
-  }
-}
-
-bool EntryTrie::isComplete(FirstOrderModelFmc * m, Node c, int index) {
-  if( d_complete==-1 ){
-    d_complete = 1;
-    if (index<(int)c.getNumChildren()) {
-      Node st = m->getStar(c[index].getType());
-      if(d_child.find(st)!=d_child.end()) {
-        if (!d_child[st].isComplete(m, c, index+1)) {
-          d_complete = 0;
-        }
-      }else{
-        d_complete = 0;
-      }
-    }
-  }
-  return d_complete==1;
-}
-
-bool Def::addEntry( FirstOrderModelFmc * m, Node c, Node v) {
-  if (d_et.hasGeneralization(m, c)) {
-    Trace("fmc-debug") << "Already has generalization, skip." << std::endl;
-    return false;
-  }
-  int newIndex = (int)d_cond.size();
-  if (!d_has_simplified) {
-    std::vector<int> compat;
-    std::vector<int> gen;
-    d_et.getEntries(m, c, compat, gen);
-    for( unsigned i=0; i<compat.size(); i++) {
-      if( d_status[compat[i]]==status_unk ){
-        if( d_value[compat[i]]!=v ){
-          d_status[compat[i]] = status_non_redundant;
-        }
-      }
-    }
-    for( unsigned i=0; i<gen.size(); i++) {
-      if( d_status[gen[i]]==status_unk ){
-        if( d_value[gen[i]]==v ){
-          d_status[gen[i]] = status_redundant;
-        }
-      }
-    }
-    d_status.push_back( status_unk );
-  }
-  d_et.addEntry(m, c, v, newIndex);
-  d_cond.push_back(c);
-  d_value.push_back(v);
-  return true;
-}
-
-Node Def::evaluate( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
-  int gindex = d_et.getGeneralizationIndex(m, inst);
-  if (gindex!=-1) {
-    return d_value[gindex];
-  }else{
-    Trace("fmc-warn") << "Warning : evaluation came up null!" << std::endl;
-    return Node::null();
-  }
-}
-
-int Def::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>& inst ) {
-  return d_et.getGeneralizationIndex(m, inst);
-}
-
-void Def::basic_simplify( FirstOrderModelFmc * m ) {
-  d_has_simplified = true;
-  std::vector< Node > cond;
-  cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
-  d_cond.clear();
-  std::vector< Node > value;
-  value.insert( value.end(), d_value.begin(), d_value.end() );
-  d_value.clear();
-  d_et.reset();
-  for (unsigned i=0; i<d_status.size(); i++) {
-    if( d_status[i]!=status_redundant ){
-      addEntry(m, cond[i], value[i]);
-    }
-  }
-  d_status.clear();
-}
-
-void Def::simplify(FullModelChecker * mc, FirstOrderModelFmc * m) {
-  Trace("fmc-simplify") << "Simplify definition, #cond = " << d_cond.size() << std::endl;
-  basic_simplify( m );
-  Trace("fmc-simplify") << "post-basic simplify, #cond = " << d_cond.size() << std::endl;
-
-  //check if the last entry is not all star, if so, we can make the last entry all stars
-  if( !d_cond.empty() ){
-    bool last_all_stars = true;
-    Node cc = d_cond[d_cond.size()-1];
-    for( unsigned i=0; i<cc.getNumChildren(); i++ ){
-      if( !m->isInterval(cc[i]) && !m->isStar(cc[i]) ){
-        last_all_stars = false;
-        break;
-      }
-    }
-    if( !last_all_stars ){
-      Trace("fmc-cover-simplify") << "Need to modify last entry to be all stars." << std::endl;
-      Trace("fmc-cover-simplify") << "Before: " << std::endl;
-      debugPrint("fmc-cover-simplify",Node::null(), mc);
-      Trace("fmc-cover-simplify") << std::endl;
-      std::vector< Node > cond;
-      cond.insert( cond.end(), d_cond.begin(), d_cond.end() );
-      d_cond.clear();
-      std::vector< Node > value;
-      value.insert( value.end(), d_value.begin(), d_value.end() );
-      d_value.clear();
-      d_et.reset();
-      d_has_simplified = false;
-      //change the last to all star
-      std::vector< Node > nc;
-      nc.push_back( cc.getOperator() );
-      for( unsigned j=0; j< cc.getNumChildren(); j++){
-        nc.push_back(m->getStarElement(cc[j].getType()));
-      }
-      cond[cond.size()-1] = NodeManager::currentNM()->mkNode( APPLY_UF, nc );
-      //re-add the entries
-      for (unsigned i=0; i<cond.size(); i++) {
-        addEntry(m, cond[i], value[i]);
-      }
-      Trace("fmc-cover-simplify") << "Finished re-adding entries." << std::endl;
-      basic_simplify( m );
-      Trace("fmc-cover-simplify") << "After: " << std::endl;
-      debugPrint("fmc-cover-simplify",Node::null(), mc);
-      Trace("fmc-cover-simplify") << std::endl;
-    }
-  }
-  Trace("fmc-simplify") << "finish simplify, #cond = " << d_cond.size() << std::endl;
-}
-
-void Def::debugPrint(const char * tr, Node op, FullModelChecker * m) {
-  if (!op.isNull()) {
-    Trace(tr) << "Model for " << op << " : " << std::endl;
-  }
-  for( unsigned i=0; i<d_cond.size(); i++) {
-    //print the condition
-    if (!op.isNull()) {
-      Trace(tr) << op;
-    }
-    m->debugPrintCond(tr, d_cond[i], true);
-    Trace(tr) << " -> ";
-    m->debugPrint(tr, d_value[i]);
-    Trace(tr) << std::endl;
-  }
-}
-
-
-FullModelChecker::FullModelChecker(context::Context* c, QuantifiersEngine* qe) :
-QModelBuilder( c, qe ){
-  d_true = NodeManager::currentNM()->mkConst(true);
-  d_false = NodeManager::currentNM()->mkConst(false);
-}
-
-bool FullModelChecker::preProcessBuildModel(TheoryModel* m) {
-  //standard pre-process
-  if( !preProcessBuildModelStd( m ) ){
-    return false;
-  }
-  
-  FirstOrderModelFmc * fm = ((FirstOrderModelFmc*)m)->asFirstOrderModelFmc();
-  Trace("fmc") << "---Full Model Check preprocess() " << std::endl;
-  d_preinitialized_types.clear();
-  //traverse equality engine
-  eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( fm->d_equalityEngine );
-  while( !eqcs_i.isFinished() ){
-    TypeNode tr = (*eqcs_i).getType();
-    d_preinitialized_types[tr] = true;
-    ++eqcs_i;
-  }
-
-  //must ensure model basis terms exists in model for each relevant type
-  fm->initialize();
-  for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
-    Node op = it->first;
-    TypeNode tno = op.getType();
-    for( unsigned i=0; i<tno.getNumChildren(); i++) {
-      preInitializeType( fm, tno[i] );
-    }
-  }
-  //do not have to introduce terms for sorts of domains of quantified formulas if we are allowed to assume empty sorts
-  if( !options::fmfEmptySorts() ){
-    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
-      Node q = fm->getAssertedQuantifier( i );
-      //make sure all types are set
-      for( unsigned j=0; j<q[0].getNumChildren(); j++ ){
-        preInitializeType( fm, q[0][j].getType() );
-      }
-    }
-  }
-  return true;
-}
-
-bool FullModelChecker::processBuildModel(TheoryModel* m){
-  FirstOrderModelFmc * fm = ((FirstOrderModelFmc*)m)->asFirstOrderModelFmc();
-  Trace("fmc") << "---Full Model Check reset() " << std::endl;
-  d_quant_models.clear();
-  d_rep_ids.clear();
-  d_star_insts.clear();
-  //process representatives
-  RepSet* rs = fm->getRepSetPtr();
-  for (std::map<TypeNode, std::vector<Node> >::iterator it =
-           rs->d_type_reps.begin();
-       it != rs->d_type_reps.end();
-       ++it)
-  {
-    if( it->first.isSort() ){
-      Trace("fmc") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
-      for( size_t a=0; a<it->second.size(); a++ ){
-        Node r = fm->getRepresentative( it->second[a] );
-        if( Trace.isOn("fmc-model-debug") ){
-          std::vector< Node > eqc;
-          d_qe->getEqualityQuery()->getEquivalenceClass( r, eqc );
-          Trace("fmc-model-debug") << "   " << (it->second[a]==r);
-          Trace("fmc-model-debug") << " : " << it->second[a] << " : " << r << " : ";
-          //Trace("fmc-model-debug") << r2 << " : " << ir << " : ";
-          Trace("fmc-model-debug") << " {";
-          for( size_t i=0; i<eqc.size(); i++ ){
-            Trace("fmc-model-debug") << eqc[i] << ", ";
-          }
-          Trace("fmc-model-debug") << "}" << std::endl;
-        }
-        d_rep_ids[it->first][r] = (int)a;
-      }
-      Trace("fmc-model-debug") << std::endl;
-    }
-  }
-
-  //now, make models
-  for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
-    Node op = it->first;
-    //reset the model
-    fm->d_models[op]->reset();
-
-    std::vector< Node > add_conds;
-    std::vector< Node > add_values;      
-    bool needsDefault = true;
-    std::map< Node, std::vector< Node > >::iterator itut = fm->d_uf_terms.find( op );
-    if( itut!=fm->d_uf_terms.end() ){
-      Trace("fmc-model-debug") << itut->second.size() << " model values for " << op << " ... " << std::endl;
-      for( size_t i=0; i<itut->second.size(); i++ ){
-        Node n = itut->second[i];
-        // only consider unique up to congruence (in model equality engine)?
-        add_conds.push_back( n );
-        add_values.push_back( n );
-        Node r = fm->getRepresentative(n);
-        Trace("fmc-model-debug") << n << " -> " << r << std::endl;
-        //AlwaysAssert( fm->areEqual( itut->second[i], r ) );
-      }
-    }else{
-      Trace("fmc-model-debug") << "No model values for " << op << " ... " << std::endl;
-    }
-    Trace("fmc-model-debug") << std::endl;
-    //possibly get default
-    if( needsDefault ){
-      Node nmb = fm->getModelBasisOpTerm(op);
-      //add default value if necessary
-      if( fm->hasTerm( nmb ) ){
-        Trace("fmc-model-debug") << "Add default " << nmb << std::endl;
-        add_conds.push_back( nmb );
-        add_values.push_back( nmb );
-      }else{
-        Node vmb = getSomeDomainElement(fm, nmb.getType());
-        Trace("fmc-model-debug") << "Add default to default representative " << nmb << " ";
-        Trace("fmc-model-debug")
-            << fm->getRepSet()->getNumRepresentatives(nmb.getType())
-            << std::endl;
-        add_conds.push_back( nmb );
-        add_values.push_back( vmb );
-      }
-    }
-
-    std::vector< Node > conds;
-    std::vector< Node > values;
-    std::vector< Node > entry_conds;
-    //get the entries for the model
-    for( size_t i=0; i<add_conds.size(); i++ ){
-      Node c = add_conds[i];
-      Node v = add_values[i];
-      std::vector< Node > children;
-      std::vector< Node > entry_children;
-      children.push_back(op);
-      entry_children.push_back(op);
-      bool hasNonStar = false;
-      for( unsigned i=0; i<c.getNumChildren(); i++) {
-        Node ri = fm->getRepresentative( c[i] );
-        children.push_back(ri);
-        bool isStar = false;
-        if( options::mbqiMode()!=quantifiers::MBQI_FMC_INTERVAL || !ri.getType().isInteger() ){
-          if (fm->isModelBasisTerm(ri) ) {
-            ri = fm->getStar( ri.getType() );
-            isStar = true;
-          }else{
-            hasNonStar = true;
-          }
-        }
-        if( !isStar && !ri.isConst() ){
-          Trace("fmc-warn") << "Warning : model for " << op << " has non-constant argument in model " << ri << " (from " << c[i] << ")" << std::endl;
-          Assert( false );
-        }
-        entry_children.push_back(ri);
-      }
-      Node n = NodeManager::currentNM()->mkNode( APPLY_UF, children );
-      Node nv = fm->getRepresentative( v );
-      if( !nv.isConst() ){
-        Trace("fmc-warn") << "Warning : model for " << op << " has non-constant value in model " << nv << std::endl;
-        Assert( false );
-      }
-      Node en = (useSimpleModels() && hasNonStar) ? n : NodeManager::currentNM()->mkNode( APPLY_UF, entry_children );
-      if( std::find(conds.begin(), conds.end(), n )==conds.end() ){
-        Trace("fmc-model-debug") << "- add " << n << " -> " << nv << " (entry is " << en << ")" << std::endl;
-        conds.push_back(n);
-        values.push_back(nv);
-        entry_conds.push_back(en);
-      }
-      else {
-        Trace("fmc-model-debug") << "Already have entry for : " << n << " -> " << nv << " (entry is " << en << ")" << std::endl;
-      }
-    }
-
-
-    //sort based on # default arguments
-    std::vector< int > indices;
-    ModelBasisArgSort mbas;
-    for (int i=0; i<(int)conds.size(); i++) {
-      mbas.d_terms.push_back(conds[i]);
-      mbas.d_mba_count[conds[i]] = fm->getModelBasisArg(conds[i]);
-      indices.push_back(i);
-    }
-    std::sort( indices.begin(), indices.end(), mbas );
-
-    for (int i=0; i<(int)indices.size(); i++) {
-      fm->d_models[op]->addEntry(fm, entry_conds[indices[i]], values[indices[i]]);
-    }
-
-
-    if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL ){
-      convertIntervalModel( fm, op );
-    }
-
-    Trace("fmc-model-simplify") << "Before simplification : " << std::endl;
-    fm->d_models[op]->debugPrint("fmc-model-simplify", op, this);
-    Trace("fmc-model-simplify") << std::endl;
-
-    Trace("fmc-model-simplify") << "Simplifying " << op << "..." << std::endl;
-    fm->d_models[op]->simplify( this, fm );
-
-    fm->d_models[op]->debugPrint("fmc-model", op, this);
-    Trace("fmc-model") << std::endl;
-
-    //for debugging
-    /*
-    for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
-      std::vector< Node > inst;
-      for( unsigned j=0; j<fm->d_uf_terms[op][i].getNumChildren(); j++ ){
-        Node r = fm->getRepresentative( fm->d_uf_terms[op][i][j] );
-        inst.push_back( r );
-      }
-      Node ev = fm->d_models[op]->evaluate( fm, inst );
-      Trace("fmc-model-debug") << ".....Checking eval( " << fm->d_uf_terms[op][i] << " ) = " << ev << std::endl;
-      AlwaysAssert( fm->areEqual( ev, fm->d_uf_terms[op][i] ) );
-    }
-    */
-  }
-  Assert( d_addedLemmas==0 );
-  
-  //make function values
-  for( std::map<Node, Def * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ){
-    Node f_def = getFunctionValue( fm, it->first, "$x" );
-    m->assignFunctionDefinition( it->first, f_def );
-  }
-  return TheoryEngineModelBuilder::processBuildModel( m );
-}
-
-void FullModelChecker::preInitializeType( FirstOrderModelFmc * fm, TypeNode tn ){
-  if( d_preinitialized_types.find( tn )==d_preinitialized_types.end() ){
-    d_preinitialized_types[tn] = true;
-    if (!tn.isFunction() || options::ufHo())
-    {
-      Node mb = fm->getModelBasisTerm(tn);
-      if (!mb.isConst())
-      {
-        Trace("fmc") << "...add model basis term to EE of model " << mb << " "
-                     << tn << std::endl;
-        fm->d_equalityEngine->addTerm(mb);
-      }
-    }
-  }
-}
-
-void FullModelChecker::debugPrintCond(const char * tr, Node n, bool dispStar) {
-  Trace(tr) << "(";
-  for( unsigned j=0; j<n.getNumChildren(); j++) {
-    if( j>0 ) Trace(tr) << ", ";
-    debugPrint(tr, n[j], dispStar);
-  }
-  Trace(tr) << ")";
-}
-
-void FullModelChecker::debugPrint(const char * tr, Node n, bool dispStar) {
-  FirstOrderModelFmc * fm = (FirstOrderModelFmc *)d_qe->getModel();
-  if( n.isNull() ){
-    Trace(tr) << "null";
-  }
-  else if(fm->isStar(n) && dispStar) {
-    Trace(tr) << "*";
-  }
-  else if(fm->isInterval(n)) {
-    debugPrint(tr, n[0], dispStar );
-    Trace(tr) << "...";
-    debugPrint(tr, n[1], dispStar );
-  }else{
-    TypeNode tn = n.getType();
-    if( tn.isSort() && d_rep_ids.find(tn)!=d_rep_ids.end() ){
-      if (d_rep_ids[tn].find(n)!=d_rep_ids[tn].end()) {
-        Trace(tr) << d_rep_ids[tn][n];
-      }else{
-        Trace(tr) << n;
-      }
-    }else{
-      Trace(tr) << n;
-    }
-  }
-}
-
-
-int FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
-  Trace("fmc") << "Full model check " << f << ", effort = " << effort << "..." << std::endl;
-  Assert( !d_qe->inConflict() );
-  if( optUseModel() ){
-    FirstOrderModelFmc * fmfmc = fm->asFirstOrderModelFmc();
-    if (effort==0) {
-      //register the quantifier
-      if (d_quant_cond.find(f)==d_quant_cond.end()) {
-        std::vector< TypeNode > types;
-        for(unsigned i=0; i<f[0].getNumChildren(); i++){
-          types.push_back(f[0][i].getType());
-        }
-        TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->booleanType() );
-        Node op = NodeManager::currentNM()->mkSkolem( "qfmc", typ, "op created for full-model checking" );
-        d_quant_cond[f] = op;
-      }
-
-      if( options::mbqiMode()==MBQI_NONE ){
-        //just exhaustive instantiate
-        Node c = mkCondDefault( fmfmc, f );
-        d_quant_models[f].addEntry( fmfmc, c, d_false );
-        return exhaustiveInstantiate( fmfmc, f, c, -1);
-      }else{
-        //model check the quantifier
-        doCheck(fmfmc, f, d_quant_models[f], f[1]);
-        Trace("fmc") << "Definition for quantifier " << f << " is : " << std::endl;
-        Assert( !d_quant_models[f].d_cond.empty() );
-        d_quant_models[f].debugPrint("fmc", Node::null(), this);
-        Trace("fmc") << std::endl;
-
-        //consider all entries going to non-true
-        for (unsigned i=0; i<d_quant_models[f].d_cond.size(); i++) {
-          if( d_quant_models[f].d_value[i]!=d_true ) {
-            Trace("fmc-inst") << "Instantiate based on " << d_quant_models[f].d_cond[i] << "..." << std::endl;
-            bool hasStar = false;
-            std::vector< Node > inst;
-            for (unsigned j=0; j<d_quant_models[f].d_cond[i].getNumChildren(); j++) {
-              if (fmfmc->isStar(d_quant_models[f].d_cond[i][j])) {
-                hasStar = true;
-                inst.push_back(fmfmc->getModelBasisTerm(d_quant_models[f].d_cond[i][j].getType()));
-              }else if( fmfmc->isInterval(d_quant_models[f].d_cond[i][j])){
-                hasStar = true;
-                //if interval, find a sample point
-                if( fmfmc->isStar(d_quant_models[f].d_cond[i][j][0]) ){
-                  if( fmfmc->isStar(d_quant_models[f].d_cond[i][j][1]) ){
-                    inst.push_back(fmfmc->getModelBasisTerm(d_quant_models[f].d_cond[i][j][1].getType()));
-                  }else{
-                    Node nn = NodeManager::currentNM()->mkNode( MINUS, d_quant_models[f].d_cond[i][j][1],
-                                                                NodeManager::currentNM()->mkConst( Rational(1) ) );
-                    nn = Rewriter::rewrite( nn );
-                    inst.push_back( nn );
-                  }
-                }else{
-                  inst.push_back(d_quant_models[f].d_cond[i][j][0]);
-                }
-              }else{
-                inst.push_back(d_quant_models[f].d_cond[i][j]);
-              }
-            }
-            bool addInst = true;
-            if( hasStar ){
-              //try obvious (specified by inst)
-              Node ev = d_quant_models[f].evaluate(fmfmc, inst);
-              if (ev==d_true) {
-                addInst = false;
-                Trace("fmc-debug") << "...do not instantiate, evaluation was " << ev << std::endl;
-              }
-            }else{
-              //for debugging
-              if (Trace.isOn("fmc-test-inst")) {
-                Node ev = d_quant_models[f].evaluate(fmfmc, inst);
-                if( ev==d_true ){
-                  std::cout << "WARNING: instantiation was true! " << f << " " << d_quant_models[f].d_cond[i] << std::endl;
-                  exit(0);
-                }else{
-                  Trace("fmc-test-inst") << "...instantiation evaluated to false." << std::endl;
-                }
-              }
-            }
-            if( addInst ){
-              if( options::fmfBound() ){
-                std::vector< Node > cond;
-                cond.push_back(d_quant_cond[f]);
-                cond.insert( cond.end(), inst.begin(), inst.end() );
-                //need to do exhaustive instantiate algorithm to set things properly (should only add one instance)
-                Node c = mkCond( cond );
-                unsigned prevInst = d_addedLemmas;
-                exhaustiveInstantiate( fmfmc, f, c, -1 );
-                if( d_addedLemmas==prevInst ){
-                  d_star_insts[f].push_back(i);
-                }
-              }else{
-                //just add the instance
-                d_triedLemmas++;
-                if (d_qe->getInstantiate()->addInstantiation(f, inst, true))
-                {
-                  Trace("fmc-debug-inst") << "** Added instantiation." << std::endl;
-                  d_addedLemmas++;
-                  if( d_qe->inConflict() || options::fmfOneInstPerRound() ){
-                    break;
-                  }
-                }else{
-                  Trace("fmc-debug-inst") << "** Instantiation was duplicate." << std::endl;
-                  //this can happen if evaluation is unknown, or if we are generalizing a star that already has a value
-                  //if( !hasStar && d_quant_models[f].d_value[i]==d_false ){
-                  //  Trace("fmc-warn") << "**** FMC warning: inconsistent duplicate instantiation." << std::endl;
-                  //}
-                  //this assertion can happen if two instantiations from this round are identical
-                  // (0,1)->false (1,0)->false   for   forall xy. f( x, y ) = f( y, x )
-                  //Assert( hasStar || d_quant_models[f].d_value[i]!=d_false );
-                  //might try it next effort level
-                  d_star_insts[f].push_back(i);
-                }
-              }
-            }else{
-              Trace("fmc-debug-inst") << "** Instantiation was already true." << std::endl;
-              //might try it next effort level
-              d_star_insts[f].push_back(i);
-            }
-          }
-        }
-      }
-    }else{
-      if (!d_star_insts[f].empty()) {
-        Trace("fmc-exh") << "Exhaustive instantiate " << f << std::endl;
-        Trace("fmc-exh") << "Definition was : " << std::endl;
-        d_quant_models[f].debugPrint("fmc-exh", Node::null(), this);
-        Trace("fmc-exh") << std::endl;
-        Def temp;
-        //simplify the exceptions?
-        for( int i=(d_star_insts[f].size()-1); i>=0; i--) {
-          //get witness for d_star_insts[f][i]
-          int j = d_star_insts[f][i];
-          if( temp.addEntry(fmfmc, d_quant_models[f].d_cond[j], d_quant_models[f].d_value[j] ) ){
-            if( !exhaustiveInstantiate(fmfmc, f, d_quant_models[f].d_cond[j], j ) ){
-              //something went wrong, resort to exhaustive instantiation
-              return 0;
-            }
-          }
-        }
-      }
-    }
-    return 1;
-  }else{
-    return 0;
-  }
-}
-
-/** Representative bound fmc entry
- *
- * This bound information corresponds to one
- * entry in a term definition (see terminology in
- * Chapter 5 of Finite Model Finding for
- * Satisfiability Modulo Theories thesis).
- * For example, a term definition for the body
- * of a quantified formula:
- *   forall xyz. P( x, y, z )
- * may be:
- *   ( 0, 0, 0 ) -> false
- *   ( *, 1, 2 ) -> false
- *   ( *, *, * ) -> true
- * Indicating that the quantified formula evaluates
- * to false in the current model for x=0, y=0, z=0,
- * or y=1, z=2 for any x, and evaluates to true
- * otherwise.
- * This class is used if we wish
- * to iterate over all values corresponding to one
- * of these entries. For example, for the second entry:
- *   (*, 1, 2 )
- * we iterate over all values of x, but only {1}
- * for y and {2} for z.
- */
-class RepBoundFmcEntry : public QRepBoundExt
-{
- public:
-  RepBoundFmcEntry(QuantifiersEngine* qe, Node e, FirstOrderModelFmc* f)
-      : QRepBoundExt(qe), d_entry(e), d_fm(f)
-  {
-  }
-  ~RepBoundFmcEntry() {}
-  /** set bound */
-  virtual RepSetIterator::RsiEnumType setBound(
-      Node owner, unsigned i, std::vector<Node>& elements) override
-  {
-    if (d_fm->isInterval(d_entry[i]))
-    {
-      // explicitly add the interval?
-    }
-    else if (d_fm->isStar(d_entry[i]))
-    {
-      // must add the full range
-    }
-    else
-    {
-      // only need to consider the single point
-      elements.push_back(d_entry[i]);
-      return RepSetIterator::ENUM_DEFAULT;
-    }
-    return QRepBoundExt::setBound(owner, i, elements);
-  }
-
- private:
-  /** the entry for this bound */
-  Node d_entry;
-  /** the model builder associated with this bound */
-  FirstOrderModelFmc* d_fm;
-};
-
-bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, Node c, int c_index) {
-  Trace("fmc-exh") << "----Exhaustive instantiate based on index " << c_index << " : " << c << " ";
-  debugPrintCond("fmc-exh", c, true);
-  Trace("fmc-exh")<< std::endl;
-  RepBoundFmcEntry rbfe(d_qe, c, fm);
-  RepSetIterator riter(d_qe->getModel()->getRepSet(), &rbfe);
-  Trace("fmc-exh-debug") << "Set quantifier..." << std::endl;
-  //initialize
-  if (riter.setQuantifier(f))
-  {
-    Trace("fmc-exh-debug") << "Set element domains..." << std::endl;
-    int addedLemmas = 0;
-    //now do full iteration
-    while( !riter.isFinished() ){
-      d_triedLemmas++;
-      Trace("fmc-exh-debug") << "Inst : ";
-      std::vector< Node > ev_inst;
-      std::vector< Node > inst;
-      for (unsigned i = 0; i < riter.getNumTerms(); i++)
-      {
-        Node rr = riter.getCurrentTerm( i );
-        Node r = rr;
-        //if( r.getType().isSort() ){
-        r = fm->getRepresentative( r );
-        //}else{
-        //  r = fm->getCurrentModelValue( r );
-        //}
-        debugPrint("fmc-exh-debug", r);
-        Trace("fmc-exh-debug") << " (term : " << rr << ")";
-        ev_inst.push_back( r );
-        inst.push_back( rr );
-      }
-      int ev_index = d_quant_models[f].getGeneralizationIndex(fm, ev_inst);
-      Trace("fmc-exh-debug") << ", index = " << ev_index << " / " << d_quant_models[f].d_value.size();
-      Node ev = ev_index==-1 ? Node::null() : d_quant_models[f].d_value[ev_index];
-      if (ev!=d_true) {
-        Trace("fmc-exh-debug") << ", add!";
-        //add as instantiation
-        if (d_qe->getInstantiate()->addInstantiation(f, inst, true))
-        {
-          Trace("fmc-exh-debug")  << " ...success.";
-          addedLemmas++;
-          if( d_qe->inConflict() || options::fmfOneInstPerRound() ){
-            break;
-          }
-        }else{
-          Trace("fmc-exh-debug") << ", failed.";
-        }
-      }else{
-        Trace("fmc-exh-debug") << ", already true";
-      }
-      Trace("fmc-exh-debug") << std::endl;
-      int index = riter.increment();
-      Trace("fmc-exh-debug") << "Incremented index " << index << std::endl;
-      if( !riter.isFinished() ){
-        if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_BOUND_INT ) {
-          Trace("fmc-exh-debug") << "Since this is a range enumeration, skip to the next..." << std::endl;
-          riter.incrementAtIndex(index - 1);
-        }
-      }
-    }
-    d_addedLemmas += addedLemmas;
-    Trace("fmc-exh") << "----Finished Exhaustive instantiate, lemmas = " << addedLemmas << ", incomplete=" << riter.isIncomplete() << std::endl;
-    return addedLemmas>0 || !riter.isIncomplete();
-  }else{
-    Trace("fmc-exh") << "----Finished Exhaustive instantiate, failed." << std::endl;
-    return !riter.isIncomplete();
-  }
-}
-
-void FullModelChecker::doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n ) {
-  Trace("fmc-debug") << "Check " << n << " " << n.getKind() << std::endl;
-  //first check if it is a bounding literal
-  if( n.hasAttribute(BoundIntLitAttribute()) ){
-    Trace("fmc-debug") << "It is a bounding literal, polarity = " << n.getAttribute(BoundIntLitAttribute()) << std::endl;
-    d.addEntry(fm, mkCondDefault(fm, f), n.getAttribute(BoundIntLitAttribute())==1 ? d_false : d_true );
-  }else if( n.getKind() == kind::BOUND_VARIABLE ){
-    Trace("fmc-debug") << "Add default entry..." << std::endl;
-    d.addEntry(fm, mkCondDefault(fm, f), n);
-  }
-  else if( n.getKind() == kind::NOT ){
-    //just do directly
-    doCheck( fm, f, d, n[0] );
-    doNegate( d );
-  }
-  else if( n.getKind() == kind::FORALL ){
-    d.addEntry(fm, mkCondDefault(fm, f), Node::null());
-  }
-  else if( n.getType().isArray() ){
-    //Trace("fmc-warn") << "WARNING : ARRAYS : Can't process base array " << r << std::endl;
-    //Trace("fmc-warn") << "          Default value was : " << odefaultValue << std::endl;
-    //Trace("fmc-debug") << "Can't process base array " << r << std::endl;
-    //can't process this array
-    d.reset();
-    d.addEntry(fm, mkCondDefault(fm, f), Node::null());
-  }
-  else if( n.getNumChildren()==0 ){
-    Node r = n;
-    if( !n.isConst() ){
-      if( !fm->hasTerm(n) ){
-        r = getSomeDomainElement(fm, n.getType() );
-      }
-      r = fm->getRepresentative( r );
-    }
-    Trace("fmc-debug") << "Add constant entry..." << std::endl;
-    d.addEntry(fm, mkCondDefault(fm, f), r);
-  }
-  else{
-    std::vector< int > var_ch;
-    std::vector< Def > children;
-    for( int i=0; i<(int)n.getNumChildren(); i++) {
-      Def dc;
-      doCheck(fm, f, dc, n[i]);
-      children.push_back(dc);
-      if( n[i].getKind() == kind::BOUND_VARIABLE ){
-        var_ch.push_back(i);
-      }
-    }
-
-    if( n.getKind()==APPLY_UF ){
-      Trace("fmc-debug") << "Do uninterpreted compose " << n << std::endl;
-      //uninterpreted compose
-      doUninterpretedCompose( fm, f, d, n.getOperator(), children );
-      /*
-    } else if( n.getKind()==SELECT ){
-      Trace("fmc-debug") << "Do select compose " << n << std::endl;
-      std::vector< Def > children2;
-      children2.push_back( children[1] );
-      std::vector< Node > cond;
-      mkCondDefaultVec(fm, f, cond);
-      std::vector< Node > val;
-      doUninterpretedCompose(fm, f, d, children[0], children2, 0, cond, val );
-      */
-    } else {
-      if( !var_ch.empty() ){
-        if( n.getKind()==EQUAL && !n[0].getType().isBoolean() ){
-          if( var_ch.size()==2 ){
-            Trace("fmc-debug") << "Do variable equality " << n << std::endl;
-            doVariableEquality( fm, f, d, n );
-          }else{
-            Trace("fmc-debug") << "Do variable relation " << n << std::endl;
-            doVariableRelation( fm, f, d, var_ch[0]==0 ? children[1] : children[0], var_ch[0]==0 ? n[0] : n[1] );
-          }
-        }else{
-          Trace("fmc-warn") << "Don't know how to check " << n << std::endl;
-          d.addEntry(fm, mkCondDefault(fm, f), Node::null());
-        }
-      }else{
-        Trace("fmc-debug") << "Do interpreted compose " << n << std::endl;
-        std::vector< Node > cond;
-        mkCondDefaultVec(fm, f, cond);
-        std::vector< Node > val;
-        //interpreted compose
-        doInterpretedCompose( fm, f, d, n, children, 0, cond, val );
-      }
-    }
-    Trace("fmc-debug") << "Simplify the definition..." << std::endl;
-    d.debugPrint("fmc-debug", Node::null(), this);
-    d.simplify(this, fm);
-    Trace("fmc-debug") << "Done simplifying" << std::endl;
-  }
-  Trace("fmc-debug") << "Definition for " << n << " is : " << std::endl;
-  d.debugPrint("fmc-debug", Node::null(), this);
-  Trace("fmc-debug") << std::endl;
-}
-
-void FullModelChecker::doNegate( Def & dc ) {
-  for (unsigned i=0; i<dc.d_cond.size(); i++) {
-    if (!dc.d_value[i].isNull()) {
-      dc.d_value[i] = dc.d_value[i]==d_true ? d_false : ( dc.d_value[i]==d_false ? d_true : dc.d_value[i] );
-    }
-  }
-}
-
-void FullModelChecker::doVariableEquality( FirstOrderModelFmc * fm, Node f, Def & d, Node eq ) {
-  std::vector<Node> cond;
-  mkCondDefaultVec(fm, f, cond);
-  if (eq[0]==eq[1]){
-    d.addEntry(fm, mkCond(cond), d_true);
-  }else{
-    TypeNode tn = eq[0].getType();
-    if( tn.isSort() ){
-      int j = fm->getVariableId(f, eq[0]);
-      int k = fm->getVariableId(f, eq[1]);
-      const RepSet* rs = fm->getRepSet();
-      if (!rs->hasType(tn))
-      {
-        getSomeDomainElement( fm, tn );  //to verify the type is initialized
-      }
-      unsigned nreps = rs->getNumRepresentatives(tn);
-      for (unsigned i = 0; i < nreps; i++)
-      {
-        Node r = fm->getRepresentative(rs->getRepresentative(tn, i));
-        cond[j+1] = r;
-        cond[k+1] = r;
-        d.addEntry( fm, mkCond(cond), d_true);
-      }
-      d.addEntry( fm, mkCondDefault(fm, f), d_false);
-    }else{
-      d.addEntry( fm, mkCondDefault(fm, f), Node::null());
-    }
-  }
-}
-
-void FullModelChecker::doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v) {
-  int j = fm->getVariableId(f, v);
-  for (unsigned i=0; i<dc.d_cond.size(); i++) {
-    Node val = dc.d_value[i];
-    if( val.isNull() ){
-      d.addEntry( fm, dc.d_cond[i], val);
-    }else{
-      if( dc.d_cond[i][j]!=val ){
-        if (fm->isStar(dc.d_cond[i][j])) {
-          std::vector<Node> cond;
-          mkCondVec(dc.d_cond[i],cond);
-          cond[j+1] = val;
-          d.addEntry(fm, mkCond(cond), d_true);
-          cond[j+1] = fm->getStar(val.getType());
-          d.addEntry(fm, mkCond(cond), d_false);
-        }else{
-          d.addEntry( fm, dc.d_cond[i], d_false);
-        }
-      }else{
-        d.addEntry( fm, dc.d_cond[i], d_true);
-      }
-    }
-  }
-}
-
-void FullModelChecker::doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node op, std::vector< Def > & dc ) {
-  Trace("fmc-uf-debug") << "Definition : " << std::endl;
-  fm->d_models[op]->debugPrint("fmc-uf-debug", op, this);
-  Trace("fmc-uf-debug") << std::endl;
-
-  std::vector< Node > cond;
-  mkCondDefaultVec(fm, f, cond);
-  std::vector< Node > val;
-  doUninterpretedCompose( fm, f, d, *fm->d_models[op], dc, 0, cond, val);
-}
-
-void FullModelChecker::doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d,
-                                               Def & df, std::vector< Def > & dc, int index,
-                                               std::vector< Node > & cond, std::vector<Node> & val ) {
-  Trace("fmc-uf-process") << "process at " << index << std::endl;
-  for( unsigned i=1; i<cond.size(); i++) {
-    debugPrint("fmc-uf-process", cond[i], true);
-    Trace("fmc-uf-process") << " ";
-  }
-  Trace("fmc-uf-process") << std::endl;
-  if (index==(int)dc.size()) {
-    //we have an entry, now do actual compose
-    std::map< int, Node > entries;
-    doUninterpretedCompose2( fm, f, entries, 0, cond, val, df.d_et);
-    if( entries.empty() ){
-      d.addEntry(fm, mkCond(cond), Node::null());
-    }else{
-      //add them to the definition
-      for( unsigned e=0; e<df.d_cond.size(); e++ ){
-        if ( entries.find(e)!=entries.end() ){
-          Trace("fmf-uf-process-debug") << "Add entry..." << std::endl;
-          d.addEntry(fm, entries[e], df.d_value[e] );
-          Trace("fmf-uf-process-debug") << "Done add entry." << std::endl;
-        }
-      }
-    }
-  }else{
-    for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
-      if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
-        std::vector< Node > new_cond;
-        new_cond.insert(new_cond.end(), cond.begin(), cond.end());
-        if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
-          Trace("fmc-uf-process") << "index " << i << " succeeded meet." << std::endl;
-          val.push_back(dc[index].d_value[i]);
-          doUninterpretedCompose(fm, f, d, df, dc, index+1, new_cond, val);
-          val.pop_back();
-        }else{
-          Trace("fmc-uf-process") << "index " << i << " failed meet." << std::endl;
-        }
-      }
-    }
-  }
-}
-
-void FullModelChecker::doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
-                                                std::map< int, Node > & entries, int index,
-                                                std::vector< Node > & cond, std::vector< Node > & val,
-                                                EntryTrie & curr ) {
-  Trace("fmc-uf-process") << "compose " << index << " / " << val.size() << std::endl;
-  for( unsigned i=1; i<cond.size(); i++) {
-    debugPrint("fmc-uf-process", cond[i], true);
-    Trace("fmc-uf-process") << " ";
-  }
-  Trace("fmc-uf-process") << std::endl;
-  if (index==(int)val.size()) {
-    Node c = mkCond(cond);
-    Trace("fmc-uf-entry") << "Entry : " << c << " -> index[" << curr.d_data << "]" << std::endl;
-    entries[curr.d_data] = c;
-  }else{
-    Node v = val[index];
-    Trace("fmc-uf-process") << "Process " << v << std::endl;
-    bool bind_var = false;
-    if( !v.isNull() && v.getKind()==kind::BOUND_VARIABLE ){
-      int j = fm->getVariableId(f, v);
-      Trace("fmc-uf-process") << v << " is variable #" << j << std::endl;
-      if (!fm->isStar(cond[j+1]) && !fm->isInterval(cond[j+1])) {
-        v = cond[j+1];
-      }else{
-        bind_var = true;
-      }
-    }
-    if (bind_var) {
-      Trace("fmc-uf-process") << "bind variable..." << std::endl;
-      int j = fm->getVariableId(f, v);
-      if( fm->isStar(cond[j+1]) ){
-        for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
-          cond[j+1] = it->first;
-          doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
-        }
-        cond[j+1] = fm->getStar(v.getType());
-      }else{
-        Node orig = cond[j+1];
-        for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
-          Node nw = doIntervalMeet( fm, it->first, orig );
-          if( !nw.isNull() ){
-            cond[j+1] = nw;
-            doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
-          }
-        }
-        cond[j+1] = orig;
-      }
-    }else{
-      if( !v.isNull() ){
-        if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && v.getType().isInteger() ){
-          for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
-            if( fm->isInRange( v, it->first ) ){
-              doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
-            }
-          }
-        }else{
-          if (curr.d_child.find(v)!=curr.d_child.end()) {
-            Trace("fmc-uf-process") << "follow value..." << std::endl;
-            doUninterpretedCompose2(fm, f, entries, index+1, cond, val, curr.d_child[v]);
-          }
-          Node st = fm->getStarElement(v.getType());
-          if (curr.d_child.find(st)!=curr.d_child.end()) {
-            Trace("fmc-uf-process") << "follow star..." << std::endl;
-            doUninterpretedCompose2(fm, f, entries, index+1, cond, val, curr.d_child[st]);
-          }
-        }
-      }
-    }
-  }
-}
-
-void FullModelChecker::doInterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n,
-                                             std::vector< Def > & dc, int index,
-                                             std::vector< Node > & cond, std::vector<Node> & val ) {
-  Trace("fmc-if-process") << "int compose " << index << " / " << dc.size() << std::endl;
-  for( unsigned i=1; i<cond.size(); i++) {
-    debugPrint("fmc-if-process", cond[i], true);
-    Trace("fmc-if-process") << " ";
-  }
-  Trace("fmc-if-process") << std::endl;
-  if ( index==(int)dc.size() ){
-    Node c = mkCond(cond);
-    Node v = evaluateInterpreted(n, val);
-    d.addEntry(fm, c, v);
-  }
-  else {
-    TypeNode vtn = n.getType();
-    for (unsigned i=0; i<dc[index].d_cond.size(); i++) {
-      if (isCompat(fm, cond, dc[index].d_cond[i])!=0) {
-        std::vector< Node > new_cond;
-        new_cond.insert(new_cond.end(), cond.begin(), cond.end());
-        if( doMeet(fm, new_cond, dc[index].d_cond[i]) ){
-          bool process = true;
-          if (vtn.isBoolean()) {
-            //short circuit
-            if( (n.getKind()==OR && dc[index].d_value[i]==d_true) ||
-                (n.getKind()==AND && dc[index].d_value[i]==d_false) ){
-              Node c = mkCond(new_cond);
-              d.addEntry(fm, c, dc[index].d_value[i]);
-              process = false;
-            }
-          }
-          if (process) {
-            val.push_back(dc[index].d_value[i]);
-            doInterpretedCompose(fm, f, d, n, dc, index+1, new_cond, val);
-            val.pop_back();
-          }
-        }
-      }
-    }
-  }
-}
-
-int FullModelChecker::isCompat( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
-  Trace("fmc-debug3") << "isCompat " << c << std::endl;
-  Assert(cond.size()==c.getNumChildren()+1);
-  for (unsigned i=1; i<cond.size(); i++) {
-    if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && cond[i].getType().isInteger() ){
-      Node iv = doIntervalMeet( fm, cond[i], c[i-1], false );
-      if( iv.isNull() ){
-        return 0;
-      }
-    }else{
-      if( cond[i]!=c[i-1] && !fm->isStar(cond[i]) && !fm->isStar(c[i-1]) ) {
-        return 0;
-      }
-    }
-  }
-  return 1;
-}
-
-bool FullModelChecker::doMeet( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c ) {
-  Trace("fmc-debug3") << "doMeet " << c << std::endl;
-  Assert(cond.size()==c.getNumChildren()+1);
-  for (unsigned i=1; i<cond.size(); i++) {
-    if( cond[i]!=c[i-1] ) {
-      if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && cond[i].getType().isInteger() ){
-        Node iv = doIntervalMeet( fm, cond[i], c[i-1] );
-        if( !iv.isNull() ){
-          cond[i] = iv;
-        }else{
-          return false;
-        }
-      }else{
-        if( fm->isStar(cond[i]) ){
-          cond[i] = c[i-1];
-        }else if( !fm->isStar(c[i-1]) ){
-          return false;
-        }
-      }
-    }
-  }
-  return true;
-}
-
-Node FullModelChecker::doIntervalMeet( FirstOrderModelFmc * fm, Node i1, Node i2, bool mk ) {
-  Trace("fmc-debug2") << "Interval meet : " << i1 << " " << i2 << " " << mk << std::endl;
-  if( fm->isStar( i1 ) ){
-    return i2;
-  }else if( fm->isStar( i2 ) ){
-    return i1;
-  }else if( !fm->isInterval( i1 ) && fm->isInterval( i2 ) ){
-    return doIntervalMeet( fm, i2, i1, mk );
-  }else if( !fm->isInterval( i2 ) ){
-    if( fm->isInterval( i1 ) ){
-      if( fm->isInRange( i2, i1 ) ){
-        return i2;
-      }
-    }else if( i1==i2 ){
-      return i1;
-    }
-    return Node::null();
-  }else{
-    Node b[2];
-    for( unsigned j=0; j<2; j++ ){
-      Node b1 = i1[j];
-      Node b2 = i2[j];
-      if( fm->isStar( b1 ) ){
-        b[j] = b2;
-      }else if( fm->isStar( b2 ) ){
-        b[j] = b1;
-      }else if( b1.getConst<Rational>() < b2.getConst<Rational>() ){
-        b[j] = j==0 ? b2 : b1;
-      }else{
-        b[j] = j==0 ? b1 : b2;
-      }
-    }
-    if( fm->isStar( b[0] ) || fm->isStar( b[1] ) || b[0].getConst<Rational>() < b[1].getConst<Rational>() ){
-      return mk ? fm->getInterval( b[0], b[1] ) : i1;
-    }else{
-      return Node::null();
-    }
-  }
-}
-
-Node FullModelChecker::mkCond( std::vector< Node > & cond ) {
-  return NodeManager::currentNM()->mkNode(APPLY_UF, cond);
-}
-
-Node FullModelChecker::mkCondDefault( FirstOrderModelFmc * fm, Node f) {
-  std::vector< Node > cond;
-  mkCondDefaultVec(fm, f, cond);
-  return mkCond(cond);
-}
-
-void FullModelChecker::mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond ) {
-  Trace("fmc-debug") << "Make default vec, intervals = " << (options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL) << std::endl;
-  //get function symbol for f
-  cond.push_back(d_quant_cond[f]);
-  for (unsigned i=0; i<f[0].getNumChildren(); i++) {
-    Node ts = fm->getStarElement( f[0][i].getType() );
-    Assert( ts.getType()==f[0][i].getType() );
-    cond.push_back(ts);
-  }
-}
-
-void FullModelChecker::mkCondVec( Node n, std::vector< Node > & cond ) {
-  cond.push_back(n.getOperator());
-  for( unsigned i=0; i<n.getNumChildren(); i++ ){
-    cond.push_back( n[i] );
-  }
-}
-
-Node FullModelChecker::mkArrayCond( Node a ) {
-  if( d_array_term_cond.find(a)==d_array_term_cond.end() ){
-    if( d_array_cond.find(a.getType())==d_array_cond.end() ){
-      TypeNode typ = NodeManager::currentNM()->mkFunctionType( a.getType(), NodeManager::currentNM()->booleanType() );
-      Node op = NodeManager::currentNM()->mkSkolem( "fmc", typ, "op created for full-model checking" );
-      d_array_cond[a.getType()] = op;
-    }
-    std::vector< Node > cond;
-    cond.push_back(d_array_cond[a.getType()]);
-    cond.push_back(a);
-    d_array_term_cond[a] = NodeManager::currentNM()->mkNode(APPLY_UF, cond );
-  }
-  return d_array_term_cond[a];
-}
-
-Node FullModelChecker::evaluateInterpreted( Node n, std::vector< Node > & vals ) {
-  if( n.getKind()==EQUAL && !n[0].getType().isBoolean() ){
-    if (!vals[0].isNull() && !vals[1].isNull()) {
-      return vals[0]==vals[1] ? d_true : d_false;
-    }else{
-      return Node::null();
-    }
-  }else if( n.getKind()==ITE ){
-    if( vals[0]==d_true ){
-      return vals[1];
-    }else if( vals[0]==d_false ){
-      return vals[2];
-    }else{
-      return vals[1]==vals[2] ? vals[1] : Node::null();
-    }
-  }else if( n.getKind()==AND || n.getKind()==OR ){
-    bool isNull = false;
-    for (unsigned i=0; i<vals.size(); i++) {
-      if((vals[i]==d_true && n.getKind()==OR) || (vals[i]==d_false && n.getKind()==AND)) {
-        return vals[i];
-      }else if( vals[i].isNull() ){
-        isNull = true;
-      }
-    }
-    return isNull ? Node::null() : vals[0];
-  }else{
-    std::vector<Node> children;
-    if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
-      children.push_back( n.getOperator() );
-    }
-    for (unsigned i=0; i<vals.size(); i++) {
-      if( vals[i].isNull() ){
-        return Node::null();
-      }else{
-        children.push_back( vals[i] );
-      }
-    }
-    Node nc = NodeManager::currentNM()->mkNode(n.getKind(), children);
-    Trace("fmc-eval") << "Evaluate " << nc << " to ";
-    nc = Rewriter::rewrite(nc);
-    Trace("fmc-eval") << nc << std::endl;
-    return nc;
-  }
-}
-
-Node FullModelChecker::getSomeDomainElement( FirstOrderModelFmc * fm, TypeNode tn ) {
-  bool addRepId = !fm->getRepSet()->hasType(tn);
-  Node de = fm->getSomeDomainElement(tn);
-  if( addRepId ){
-    d_rep_ids[tn][de] = 0;
-  }
-  return de;
-}
-
-Node FullModelChecker::getFunctionValue(FirstOrderModelFmc * fm, Node op, const char* argPrefix ) {
-  return fm->getFunctionValue(op, argPrefix);
-}
-
-
-bool FullModelChecker::useSimpleModels() {
-  return options::fmfFmcSimple();
-}
-
-void FullModelChecker::convertIntervalModel( FirstOrderModelFmc * fm, Node op ){
-  Trace("fmc-interval-model") << "Changing to interval model, Before : " << std::endl;
-  fm->d_models[op]->debugPrint("fmc-interval-model", op, this);
-  Trace("fmc-interval-model") << std::endl;
-  std::vector< int > indices;
-  for( int i=0; i<(int)fm->d_models[op]->d_cond.size(); i++ ){
-    indices.push_back( i );
-  }
-  std::map< int, std::map< int, Node > > changed_vals;
-  makeIntervalModel( fm, op, indices, 0, changed_vals );
-
-  std::vector< Node > conds;
-  std::vector< Node > values;
-  for( unsigned i=0; i<fm->d_models[op]->d_cond.size(); i++ ){
-    if( changed_vals.find(i)==changed_vals.end() ){
-      conds.push_back( fm->d_models[op]->d_cond[i] );
-    }else{
-      std::vector< Node > children;
-      children.push_back( op );
-      for( unsigned j=0; j<fm->d_models[op]->d_cond[i].getNumChildren(); j++ ){
-        if( changed_vals[i].find(j)==changed_vals[i].end() ){
-          children.push_back( fm->d_models[op]->d_cond[i][j] );
-        }else{
-          children.push_back( changed_vals[i][j] );
-        }
-      }
-      Node nc = NodeManager::currentNM()->mkNode( APPLY_UF, children );
-      conds.push_back( nc );
-      Trace("fmc-interval-model") << "Interval : Entry #" << i << " changed to ";
-      debugPrintCond("fmc-interval-model", nc, true );
-      Trace("fmc-interval-model") << std::endl;
-    }
-    values.push_back( fm->d_models[op]->d_value[i] );
-  }
-  fm->d_models[op]->reset();
-  for( unsigned i=0; i<conds.size(); i++ ){
-    fm->d_models[op]->addEntry(fm, conds[i], values[i] );
-  }
-}
-
-void FullModelChecker::makeIntervalModel( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
-                                          std::map< int, std::map< int, Node > >& changed_vals ) {
-  if( index==(int)fm->d_models[op]->d_cond[0].getNumChildren() ){
-    makeIntervalModel2( fm, op, indices, 0, changed_vals );
-  }else{
-    TypeNode tn = fm->d_models[op]->d_cond[0][index].getType();
-    if( tn.isInteger() ){
-      makeIntervalModel(fm,op,indices,index+1, changed_vals );
-    }else{
-      std::map< Node, std::vector< int > > new_indices;
-      for( unsigned i=0; i<indices.size(); i++ ){
-        Node v = fm->d_models[op]->d_cond[indices[i]][index];
-        new_indices[v].push_back( indices[i] );
-      }
-
-      for( std::map< Node, std::vector< int > >::iterator it = new_indices.begin(); it != new_indices.end(); ++it ){
-        makeIntervalModel( fm, op, it->second, index+1, changed_vals );
-      }
-    }
-  }
-}
-
-void FullModelChecker::makeIntervalModel2( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
-                                          std::map< int, std::map< int, Node > >& changed_vals ) {
-  Debug("fmc-interval-model-debug") << "Process " << index << " with indicies : ";
-  for( unsigned i=0; i<indices.size(); i++ ){
-    Debug("fmc-interval-model-debug") << indices[i] << " ";
-  }
-  Debug("fmc-interval-model-debug") << std::endl;
-
-  if( index<(int)fm->d_models[op]->d_cond[0].getNumChildren() ){
-    TypeNode tn = fm->d_models[op]->d_cond[0][index].getType();
-    if( tn.isInteger() ){
-      std::map< Node, std::vector< int > > new_indices;
-      for( unsigned i=0; i<indices.size(); i++ ){
-        Node v = fm->d_models[op]->d_cond[indices[i]][index];
-        new_indices[v].push_back( indices[i] );
-        if( !v.isConst() ){
-          Trace("fmc-warn") << "WARNING: for interval, model has non-constant : " << v << std::endl;
-          Trace("fmc-warn") << "From condition : " << fm->d_models[op]->d_cond[indices[i]] << std::endl;
-        }
-      }
-
-      std::vector< Node > values;
-      for( std::map< Node, std::vector< int > >::iterator it = new_indices.begin(); it != new_indices.end(); ++it ){
-        makeIntervalModel2( fm, op, it->second, index+1, changed_vals );
-        values.push_back( it->first );
-      }
-
-      if( tn.isInteger() ){
-        //sort values by size
-        ConstRationalSort crs;
-        std::vector< int > sindices;
-        for( unsigned i=0; i<values.size(); i++ ){
-          sindices.push_back( (int)i );
-          crs.d_terms.push_back( values[i] );
-        }
-        std::sort( sindices.begin(), sindices.end(), crs );
-
-        Node ub = fm->getStar( tn );
-        for( int i=(int)(sindices.size()-1); i>=0; i-- ){
-          Node lb = fm->getStar( tn );
-          if( i>0 ){
-            lb = values[sindices[i]];
-          }
-          Node interval = fm->getInterval( lb, ub );
-          for( unsigned j=0; j<new_indices[values[sindices[i]]].size(); j++ ){
-            Debug("fmc-interval-model-debug") << "Change " << new_indices[values[sindices[i]]][j] << ", " << index << " to " << interval << std::endl;
-            changed_vals[new_indices[values[sindices[i]]][j]][index] = interval;
-          }
-          ub = lb;
-        }
-      }
-    }else{
-      makeIntervalModel2( fm, op, indices, index+1, changed_vals );
-    }
-  }
-}
diff --git a/src/theory/quantifiers/full_model_check.h b/src/theory/quantifiers/full_model_check.h
deleted file mode 100644 (file)
index f6d16dc..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/*********************                                                        */
-/*! \file full_model_check.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Morgan Deters, Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Full model check class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__FULL_MODEL_CHECK_H
-#define __CVC4__THEORY__QUANTIFIERS__FULL_MODEL_CHECK_H
-
-#include "theory/quantifiers/model_builder.h"
-#include "theory/quantifiers/first_order_model.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-namespace fmcheck {
-
-
-class FirstOrderModelFmc;
-class FullModelChecker;
-
-class EntryTrie
-{
-private:
-  int d_complete;
-public:
-  EntryTrie() : d_complete(-1), d_data(-1){}
-  std::map<Node,EntryTrie> d_child;
-  int d_data;
-  void reset() { d_data = -1; d_child.clear(); d_complete = -1; }
-  void addEntry( FirstOrderModelFmc * m, Node c, Node v, int data, int index = 0 );
-  bool hasGeneralization( FirstOrderModelFmc * m, Node c, int index = 0 );
-  int getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node> & inst, int index = 0 );
-  void getEntries( FirstOrderModelFmc * m, Node c, std::vector<int> & compat, std::vector<int> & gen, int index = 0, bool is_gen = true );
-
-  void collectIndices(Node c, int index, std::vector< int >& indices );
-  bool isComplete(FirstOrderModelFmc * m, Node c, int index);
-};/* class EntryTrie */
-
-
-class Def
-{
-public:
-  EntryTrie d_et;
-  //cond is APPLY_UF whose arguments are returned by FullModelChecker::getRepresentative
-  std::vector< Node > d_cond;
-  //value is returned by FullModelChecker::getRepresentative
-  std::vector< Node > d_value;
-  void basic_simplify( FirstOrderModelFmc * m );
-private:
-  enum {
-    status_unk,
-    status_redundant,
-    status_non_redundant
-  };
-  std::vector< int > d_status;
-  bool d_has_simplified;
-public:
-  Def() : d_has_simplified(false){}
-  void reset() {
-    d_et.reset();
-    d_cond.clear();
-    d_value.clear();
-    d_status.clear();
-    d_has_simplified = false;
-  }
-  bool addEntry( FirstOrderModelFmc * m, Node c, Node v);
-  Node evaluate( FirstOrderModelFmc * m, std::vector<Node>& inst );
-  int getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>& inst );
-  void simplify( FullModelChecker * mc, FirstOrderModelFmc * m );
-  void debugPrint(const char * tr, Node op, FullModelChecker * m);
-};/* class Def */
-
-
-class FullModelChecker : public QModelBuilder
-{
-protected:
-  Node d_true;
-  Node d_false;
-  std::map<TypeNode, std::map< Node, int > > d_rep_ids;
-  std::map<Node, Def > d_quant_models;
-  std::map<Node, Node > d_quant_cond;
-  std::map< TypeNode, Node > d_array_cond;
-  std::map< Node, Node > d_array_term_cond;
-  std::map< Node, std::vector< int > > d_star_insts;
-  std::map< TypeNode, bool > d_preinitialized_types;
-  void preInitializeType( FirstOrderModelFmc * fm, TypeNode tn );
-  Node normalizeArgReps(FirstOrderModelFmc * fm, Node op, Node n);
-  bool exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, Node c, int c_index);
-protected:
-  void makeIntervalModel2( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
-                          std::map< int, std::map< int, Node > >& changed_vals );
-  void makeIntervalModel( FirstOrderModelFmc * fm, Node op, std::vector< int > & indices, int index,
-                          std::map< int, std::map< int, Node > >& changed_vals );
-  void convertIntervalModel( FirstOrderModelFmc * fm, Node op );
-private:
-  void doCheck(FirstOrderModelFmc * fm, Node f, Def & d, Node n );
-
-  void doNegate( Def & dc );
-  void doVariableEquality( FirstOrderModelFmc * fm, Node f, Def & d, Node eq );
-  void doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v);
-  void doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n, std::vector< Def > & dc );
-
-  void doUninterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d,
-                               Def & df, std::vector< Def > & dc, int index,
-                               std::vector< Node > & cond, std::vector<Node> & val );
-  void doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
-                                std::map< int, Node > & entries, int index,
-                                std::vector< Node > & cond, std::vector< Node > & val,
-                                EntryTrie & curr);
-
-  void doInterpretedCompose( FirstOrderModelFmc * fm, Node f, Def & d, Node n,
-                             std::vector< Def > & dc, int index,
-                             std::vector< Node > & cond, std::vector<Node> & val );
-  int isCompat( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c );
-  Node doIntervalMeet( FirstOrderModelFmc * fm, Node i1, Node i2, bool mk = true );
-  bool doMeet( FirstOrderModelFmc * fm, std::vector< Node > & cond, Node c );
-  Node mkCond( std::vector< Node > & cond );
-  Node mkCondDefault( FirstOrderModelFmc * fm, Node f );
-  void mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond );
-  void mkCondVec( Node n, std::vector< Node > & cond );
-  Node mkArrayCond( Node a );
-  Node evaluateInterpreted( Node n, std::vector< Node > & vals );
-  Node getSomeDomainElement( FirstOrderModelFmc * fm, TypeNode tn );
-public:
-  FullModelChecker( context::Context* c, QuantifiersEngine* qe );
-
-  void debugPrintCond(const char * tr, Node n, bool dispStar = false);
-  void debugPrint(const char * tr, Node n, bool dispStar = false);
-
-  int doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort );
-
-  Node getFunctionValue(FirstOrderModelFmc * fm, Node op, const char* argPrefix );
-
-  /** process build model */  
-  bool preProcessBuildModel(TheoryModel* m); 
-  bool processBuildModel(TheoryModel* m);
-
-  bool useSimpleModels();
-};/* class FullModelChecker */
-
-}/* CVC4::theory::quantifiers::fmcheck namespace */
-}/* CVC4::theory::quantifiers namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__FULL_MODEL_CHECK_H */
diff --git a/src/theory/quantifiers/ho_trigger.cpp b/src/theory/quantifiers/ho_trigger.cpp
deleted file mode 100644 (file)
index 6456fb2..0000000
+++ /dev/null
@@ -1,475 +0,0 @@
-/*********************                                                        */
-/*! \file ho_trigger.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of higher-order trigger class
- **/
-
-#include <stack>
-
-#include "theory/quantifiers/ho_trigger.h"
-#include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers_engine.h"
-#include "theory/theory_engine.h"
-#include "theory/uf/equality_engine.h"
-#include "theory/uf/theory_uf_rewriter.h"
-#include "util/hash.h"
-
-using namespace CVC4::kind;
-
-namespace CVC4 {
-namespace theory {
-namespace inst {
-
-HigherOrderTrigger::HigherOrderTrigger(
-    QuantifiersEngine* qe,
-    Node q,
-    std::vector<Node>& nodes,
-    std::map<Node, std::vector<Node> >& ho_apps)
-    : Trigger(qe, q, nodes), d_ho_var_apps(ho_apps)
-{
-  NodeManager* nm = NodeManager::currentNM();
-  // process the higher-order variable applications
-  for (std::pair<const Node, std::vector<Node> >& as : d_ho_var_apps)
-  {
-    Node n = as.first;
-    d_ho_var_list.push_back(n);
-    TypeNode tn = n.getType();
-    Assert(tn.isFunction());
-    if (Trace.isOn("ho-quant-trigger"))
-    {
-      Trace("ho-quant-trigger") << "  have " << as.second.size();
-      Trace("ho-quant-trigger") << " patterns with variable operator " << n
-                                << ":" << std::endl;
-      for (unsigned j = 0; j < as.second.size(); j++)
-      {
-        Trace("ho-quant-trigger") << "  " << as.second[j] << std::endl;
-      }
-    }
-    if (d_ho_var_types.find(tn) == d_ho_var_types.end())
-    {
-      Trace("ho-quant-trigger") << "  type " << tn
-                                << " needs higher-order matching." << std::endl;
-      d_ho_var_types.insert(tn);
-    }
-    // make the bound variable lists
-    d_ho_var_bvl[n] = nm->getBoundVarListForFunctionType(tn);
-    for (const Node& nc : d_ho_var_bvl[n])
-    {
-      d_ho_var_bvs[n].push_back(nc);
-    }
-  }
-}
-
-HigherOrderTrigger::~HigherOrderTrigger() {}
-void HigherOrderTrigger::collectHoVarApplyTerms(
-    Node q, Node& n, std::map<Node, std::vector<Node> >& apps)
-{
-  std::vector<Node> ns;
-  ns.push_back(n);
-  collectHoVarApplyTerms(q, ns, apps);
-  Assert(ns.size() == 1);
-  n = ns[0];
-}
-
-void HigherOrderTrigger::collectHoVarApplyTerms(
-    Node q, std::vector<Node>& ns, std::map<Node, std::vector<Node> >& apps)
-{
-  std::unordered_map<TNode, Node, TNodeHashFunction> visited;
-  std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
-  // whether the visited node is a child of a HO_APPLY chain
-  std::unordered_map<TNode, bool, TNodeHashFunction> withinApply;
-  std::vector<TNode> visit;
-  TNode cur;
-  for (unsigned i = 0, size = ns.size(); i < size; i++)
-  {
-    visit.push_back(ns[i]);
-    withinApply[ns[i]] = false;
-    do
-    {
-      cur = visit.back();
-      visit.pop_back();
-
-      it = visited.find(cur);
-      if (it == visited.end())
-      {
-        // do not look in nested quantifiers
-        if (cur.getKind() == FORALL)
-        {
-          visited[cur] = cur;
-        }
-        else
-        {
-          bool curWithinApply = withinApply[cur];
-          visited[cur] = Node::null();
-          visit.push_back(cur);
-          for (unsigned j = 0, size = cur.getNumChildren(); j < size; j++)
-          {
-            withinApply[cur[j]] = curWithinApply && j == 0;
-            visit.push_back(cur[j]);
-          }
-        }
-      }
-      else if (it->second.isNull())
-      {
-        // carry the conversion
-        Node ret = cur;
-        bool childChanged = false;
-        std::vector<Node> children;
-        if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
-        {
-          children.push_back(cur.getOperator());
-        }
-        for (const Node& nc : cur)
-        {
-          it = visited.find(nc);
-          Assert(it != visited.end());
-          Assert(!it->second.isNull());
-          childChanged = childChanged || nc != it->second;
-          children.push_back(it->second);
-        }
-        if (childChanged)
-        {
-          ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
-        }
-        // now, convert and store the application
-        if (!withinApply[cur])
-        {
-          TNode op;
-          if (ret.getKind() == kind::APPLY_UF)
-          {
-            // could be a fully applied function variable
-            op = ret.getOperator();
-          }
-          else if (ret.getKind() == kind::HO_APPLY)
-          {
-            op = ret;
-            while (op.getKind() == kind::HO_APPLY)
-            {
-              op = op[0];
-            }
-          }
-          if (!op.isNull())
-          {
-            if (op.getKind() == kind::INST_CONSTANT)
-            {
-              Assert(quantifiers::TermUtil::getInstConstAttr(ret) == q);
-              Trace("ho-quant-trigger-debug")
-                  << "Ho variable apply term : " << ret << " with head " << op
-                  << std::endl;
-              if (ret.getKind() == kind::APPLY_UF)
-              {
-                Node prev = ret;
-                // for consistency, convert to HO_APPLY if fully applied
-                ret = uf::TheoryUfRewriter::getHoApplyForApplyUf(ret);
-              }
-              apps[op].push_back(ret);
-            }
-          }
-        }
-        visited[cur] = ret;
-      }
-    } while (!visit.empty());
-
-    // store the conversion
-    Assert(visited.find(ns[i]) != visited.end());
-    ns[i] = visited[ns[i]];
-  }
-}
-
-int HigherOrderTrigger::addInstantiations()
-{
-  // call the base class implementation
-  int addedFoLemmas = Trigger::addInstantiations();
-  // also adds predicate lemms to force app completion
-  int addedHoLemmas = addHoTypeMatchPredicateLemmas();
-  return addedHoLemmas + addedFoLemmas;
-}
-
-bool HigherOrderTrigger::sendInstantiation(InstMatch& m)
-{
-  if (options::hoMatching())
-  {
-    // get substitution corresponding to m
-    std::vector<TNode> vars;
-    std::vector<TNode> subs;
-    quantifiers::TermUtil* tutil = d_quantEngine->getTermUtil();
-    for (unsigned i = 0, size = d_quant[0].getNumChildren(); i < size; i++)
-    {
-      subs.push_back(m.d_vals[i]);
-      vars.push_back(tutil->getInstantiationConstant(d_quant, i));
-    }
-
-    Trace("ho-unif-debug") << "Run higher-order unification..." << std::endl;
-
-    // get the substituted form of all variable-operator ho application terms
-    std::map<TNode, std::vector<Node> > ho_var_apps_subs;
-    for (std::pair<const Node, std::vector<Node> >& ha : d_ho_var_apps)
-    {
-      TNode var = ha.first;
-      for (unsigned j = 0, size = ha.second.size(); j < size; j++)
-      {
-        TNode app = ha.second[j];
-        Node sapp =
-            app.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
-        ho_var_apps_subs[var].push_back(sapp);
-        Trace("ho-unif-debug") << "  app[" << var << "] : " << app << " -> "
-                               << sapp << std::endl;
-      }
-    }
-
-    // compute argument vectors for each variable
-    d_lchildren.clear();
-    d_arg_to_arg_rep.clear();
-    d_arg_vector.clear();
-    EqualityQuery* eq = d_quantEngine->getEqualityQuery();
-    for (std::pair<const TNode, std::vector<Node> >& ha : ho_var_apps_subs)
-    {
-      TNode var = ha.first;
-      unsigned vnum = var.getAttribute(InstVarNumAttribute());
-      Node value = m.d_vals[vnum];
-      Trace("ho-unif-debug") << "  val[" << var << "] = " << value << std::endl;
-
-      Trace("ho-unif-debug2") << "initialize lambda information..."
-                              << std::endl;
-      // initialize the lambda children
-      d_lchildren[vnum].push_back(value);
-      std::map<TNode, std::vector<Node> >::iterator ithb =
-          d_ho_var_bvs.find(var);
-      Assert(ithb != d_ho_var_bvs.end());
-      d_lchildren[vnum].insert(
-          d_lchildren[vnum].end(), ithb->second.begin(), ithb->second.end());
-
-      Trace("ho-unif-debug2") << "compute fixed arguments..." << std::endl;
-      // compute for each argument if it is only applied to a fixed value modulo
-      // equality
-      std::map<unsigned, Node> fixed_vals;
-      for (unsigned i = 0; i < ha.second.size(); i++)
-      {
-        std::vector<TNode> args;
-        Node f = uf::TheoryUfRewriter::decomposeHoApply(ha.second[i], args);
-        // Assert( f==value );
-        for (unsigned k = 0, size = args.size(); k < size; k++)
-        {
-          Node val = args[k];
-          std::map<unsigned, Node>::iterator itf = fixed_vals.find(k);
-          if (itf == fixed_vals.end())
-          {
-            fixed_vals[k] = val;
-          }
-          else if (!itf->second.isNull())
-          {
-            if (!eq->areEqual(itf->second, args[k]))
-            {
-              if (!d_quantEngine->getTermDatabase()->isEntailed(
-                      itf->second.eqNode(args[k]), true, eq))
-              {
-                fixed_vals[k] = Node::null();
-              }
-            }
-          }
-        }
-      }
-      if (Trace.isOn("ho-unif-debug"))
-      {
-        for (std::map<unsigned, Node>::iterator itf = fixed_vals.begin();
-             itf != fixed_vals.end();
-             ++itf)
-        {
-          Trace("ho-unif-debug") << "  arg[" << var << "][" << itf->first
-                                 << "] : " << itf->second << std::endl;
-        }
-      }
-
-      // now construct argument vectors
-      Trace("ho-unif-debug2") << "compute argument vectors..." << std::endl;
-      std::map<Node, unsigned> arg_to_rep;
-      for (unsigned index = 0, size = ithb->second.size(); index < size;
-           index++)
-      {
-        Node bv_at_index = ithb->second[index];
-        std::map<unsigned, Node>::iterator itf = fixed_vals.find(index);
-        Trace("ho-unif-debug") << "  * arg[" << var << "][" << index << "]";
-        if (itf != fixed_vals.end())
-        {
-          if (!itf->second.isNull())
-          {
-            Node r = eq->getRepresentative(itf->second);
-            std::map<Node, unsigned>::iterator itfr = arg_to_rep.find(r);
-            if (itfr != arg_to_rep.end())
-            {
-              d_arg_to_arg_rep[vnum][index] = itfr->second;
-              // function applied to equivalent values at multiple arguments,
-              // can permute variables
-              d_arg_vector[vnum][itfr->second].push_back(bv_at_index);
-              Trace("ho-unif-debug") << " = { self } ++ arg[" << var << "]["
-                                     << itfr->second << "]" << std::endl;
-            }
-            else
-            {
-              arg_to_rep[r] = index;
-              // function applied to single value, can either use variable or
-              // value at this argument position
-              d_arg_vector[vnum][index].push_back(bv_at_index);
-              d_arg_vector[vnum][index].push_back(itf->second);
-              if (!options::hoMatchingVarArgPriority())
-              {
-                std::reverse(d_arg_vector[vnum][index].begin(),
-                             d_arg_vector[vnum][index].end());
-              }
-              Trace("ho-unif-debug") << " = { self, " << itf->second << " } "
-                                     << std::endl;
-            }
-          }
-          else
-          {
-            // function is applied to disequal values, can only use variable at
-            // this argument position
-            d_arg_vector[vnum][index].push_back(bv_at_index);
-            Trace("ho-unif-debug") << " = { self } (disequal)" << std::endl;
-          }
-        }
-        else
-        {
-          // argument is irrelevant to matching, assume identity variable
-          d_arg_vector[vnum][index].push_back(bv_at_index);
-          Trace("ho-unif-debug") << " = { self } (irrelevant)" << std::endl;
-        }
-      }
-      Trace("ho-unif-debug2") << "finished." << std::endl;
-    }
-
-    return sendInstantiation(m, 0);
-  }
-  else
-  {
-    // do not run higher-order matching
-    return d_quantEngine->getInstantiate()->addInstantiation(d_quant, m);
-  }
-}
-
-// recursion depth limited by number of arguments of higher order variables
-// occurring as pattern operators (very small)
-bool HigherOrderTrigger::sendInstantiation(InstMatch& m, unsigned var_index)
-{
-  if (var_index == d_ho_var_list.size())
-  {
-    // we now have an instantiation to try
-    return d_quantEngine->getInstantiate()->addInstantiation(d_quant, m);
-  }
-  else
-  {
-    Node var = d_ho_var_list[var_index];
-    unsigned vnum = var.getAttribute(InstVarNumAttribute());
-    Assert(vnum < m.d_vals.size());
-    Node value = m.d_vals[vnum];
-    Assert(d_lchildren[vnum][0] == value);
-    Assert(d_ho_var_bvl.find(var) != d_ho_var_bvl.end());
-
-    // now, recurse on arguments to enumerate equivalent matching lambda
-    // expressions
-    bool ret =
-        sendInstantiationArg(m, var_index, vnum, 0, d_ho_var_bvl[var], false);
-
-    // reset the value
-    m.d_vals[vnum] = value;
-
-    return ret;
-  }
-}
-
-bool HigherOrderTrigger::sendInstantiationArg(InstMatch& m,
-                                              unsigned var_index,
-                                              unsigned vnum,
-                                              unsigned arg_index,
-                                              Node lbvl,
-                                              bool arg_changed)
-{
-  if (arg_index == lbvl.getNumChildren())
-  {
-    // construct the lambda
-    if (arg_changed)
-    {
-      Node body =
-          NodeManager::currentNM()->mkNode(kind::APPLY_UF, d_lchildren[vnum]);
-      Node lam = NodeManager::currentNM()->mkNode(kind::LAMBDA, lbvl, body);
-      m.d_vals[vnum] = lam;
-      Trace("ho-unif-debug2") << "  try " << vnum << " -> " << lam << std::endl;
-    }
-    return sendInstantiation(m, var_index + 1);
-  }
-  else
-  {
-    std::map<unsigned, unsigned>::iterator itr =
-        d_arg_to_arg_rep[vnum].find(arg_index);
-    unsigned rindex =
-        itr != d_arg_to_arg_rep[vnum].end() ? itr->second : arg_index;
-    std::map<unsigned, std::vector<Node> >::iterator itv =
-        d_arg_vector[vnum].find(rindex);
-    Assert(itv != d_arg_vector[vnum].end());
-    Node prev = lbvl[arg_index];
-    bool ret = false;
-    // try each argument in the vector
-    for (unsigned i = 0, size = itv->second.size(); i < size; i++)
-    {
-      bool new_arg_changed = arg_changed || prev != itv->second[i];
-      d_lchildren[vnum][arg_index + 1] = itv->second[i];
-      if (sendInstantiationArg(
-              m, var_index, vnum, arg_index + 1, lbvl, new_arg_changed))
-      {
-        ret = true;
-        break;
-      }
-    }
-    // clean up
-    d_lchildren[vnum][arg_index + 1] = prev;
-    return ret;
-  }
-}
-
-int HigherOrderTrigger::addHoTypeMatchPredicateLemmas()
-{
-  unsigned numLemmas = 0;
-  if (!d_ho_var_types.empty())
-  {
-    // this forces expansion of APPLY_UF terms to curried HO_APPLY chains
-    unsigned size = d_quantEngine->getTermDatabase()->getNumOperators();
-    for (unsigned j = 0; j < size; j++)
-    {
-      Node f = d_quantEngine->getTermDatabase()->getOperator(j);
-      if (f.isVar())
-      {
-        TypeNode tn = f.getType();
-        if (d_ho_var_types.find(tn) != d_ho_var_types.end())
-        {
-          Node u = d_quantEngine->getTermUtil()->getHoTypeMatchPredicate(tn);
-          Node au = NodeManager::currentNM()->mkNode(kind::APPLY_UF, u, f);
-          if (d_quantEngine->addLemma(au))
-          {
-            // this forces f to be a first-class member of the quantifier-free
-            // equality engine,
-            //  which in turn forces the quantifier-free theory solver to expand
-            //  it to HO_APPLY
-            Trace("ho-quant") << "Added ho match predicate lemma : " << au
-                              << std::endl;
-            numLemmas++;
-          }
-        }
-      }
-    }
-  }
-  return numLemmas;
-}
-
-} /* CVC4::theory::inst namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/ho_trigger.h b/src/theory/quantifiers/ho_trigger.h
deleted file mode 100644 (file)
index 87f7fe0..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/*********************                                                        */
-/*! \file ho_trigger.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief higher-order trigger class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__HO_TRIGGER_H
-#define __CVC4__THEORY__QUANTIFIERS__HO_TRIGGER_H
-
-#include <map>
-#include <unordered_set>
-
-#include "expr/node.h"
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/inst_match.h"
-#include "theory/quantifiers/trigger.h"
-
-namespace CVC4 {
-namespace theory {
-namespace inst {
-
-class Trigger;
-
-/** HigherOrder trigger
- *
- * This extends the trigger class with techniques that post-process
- * instantiations, specified by InstMatch objects, according to a variant of
- * Huet's algorithm. For details, see Chapter 16 of the Handbook of Automated
- * Reasoning (vol. 2), by Gilles Dowek.
- *
- * The main difference between HigherOrderTrigger and Trigger is the function
- * sendInstantiation(...). Recall that this function is called when its
- * underlying IMGenerator generates an InstMatch m using E-matching technique.
- * We enumerate additional instantiations based on m, when the domain of m
- * contains variables of function type.
- *
- * Examples below (f, x, y are universal variables):
- *
- * (EX1): (f x y) matches (k 0 1) in standard E-matching with:
- *
- * f -> k, x -> 0, y -> 1
- *
- * This match is extended to four possible solutions by this class:
- *
- * f -> \ xy. (k x y), x -> 0, y -> 1
- * f -> \ xy. (k 0 y), x -> 0, y -> 1
- * f -> \ xy. (k x 1), x -> 0, y -> 1
- * f -> \ xy. (k 0 1), x -> 0, y -> 1
- *
- *
- * (EX2): Similarly, (f x y) matches (k 0 0) with possible solutions:
- *
- * f -> \ xy. (k x x), x -> 0, y -> 0
- * f -> \ xy. (k y x), x -> 0, y -> 0
- * f -> \ xy. (k 0 x), x -> 0, y -> 0
- * f -> \ xy. (k x y), x -> 0, y -> 0
- * f -> \ xy. (k y y), x -> 0, y -> 0
- * f -> \ xy. (k 0 y), x -> 0, y -> 0
- * f -> \ xy. (k x 0), x -> 0, y -> 0
- * f -> \ xy. (k y 0), x -> 0, y -> 0
- * f -> \ xy. (k 0 0), x -> 0, y -> 0
- *
- *
- * (EX3): (f x y), (f x z) simultaneously match (k 0 1), (k 0 2) with possible
- * solutions:
- *
- * f -> \ xy. (k x y), x -> 0, y -> 1, z -> 2
- * f -> \ xy. (k 0 y), x -> 0, y -> 1, z -> 2
- *
- *
- * This class enumerates the lists above until one instantiation of that form is
- * successfully added via a call to Instantiate::addInstantiation(...)
- *
- *
- * It also implements a way of forcing APPLY_UF to expand to curried HO_APPLY to
- * handle a corner case where there are no matchable ground terms
- * (addHoTypeMatchPredicateLemmas).
- *
- */
-class HigherOrderTrigger : public Trigger
-{
-  friend class Trigger;
-
- private:
-  HigherOrderTrigger(QuantifiersEngine* qe,
-                     Node q,
-                     std::vector<Node>& nodes,
-                     std::map<Node, std::vector<Node> >& ho_apps);
-  virtual ~HigherOrderTrigger();
-
- public:
-  /** Collect higher order var apply terms
-   *
-   * Collect all top-level HO_APPLY terms in n whose head is a variable x in
-   * quantified formula q. Append all such terms in apps[x].
-   * This method may modify n so that it is in the expected form required for
-   * higher-order matching, in particular, APPLY_UF terms with variable
-   * operators are converted to curried applications of HO_APPLY.
-   */
-  static void collectHoVarApplyTerms(Node q,
-                                     Node& n,
-                                     std::map<Node, std::vector<Node> >& apps);
-  /** Collect higher order var apply terms
-   *
-   * Same as above, but with multiple terms ns.
-   */
-  static void collectHoVarApplyTerms(Node q,
-                                     std::vector<Node>& ns,
-                                     std::map<Node, std::vector<Node> >& apps);
-  /** add all available instantiations, based on the current context
-   *
-   * Extends Trigger::addInstantiations to also send
-   * lemmas based on addHoTypeMatchPredicateLemmas.
-   */
-  virtual int addInstantiations() override;
-
- protected:
-  /**
-   * Map from function-typed variables to their applications in the quantified
-   * formula d_f (member of Trigger).
-   */
-  std::map<Node, std::vector<Node> > d_ho_var_apps;
-  /**
-   * List of all function-typed variables that occur as the head of function
-   * applications in d_f.
-   */
-  std::vector<Node> d_ho_var_list;
-  /**
-   * Cached bound variables and bound variable list for each variable of
-   * function type. These are used for constructing lambda terms in
-   * instantiations.
-   */
-  std::map<TNode, std::vector<Node> > d_ho_var_bvs;
-  std::map<TNode, Node> d_ho_var_bvl;
-  /** the set of types of ho variables */
-  std::unordered_set<TypeNode, TypeNodeHashFunction> d_ho_var_types;
-  /** add higher-order type predicate lemmas
-   *
-   * Adds lemmas of the form P( f ), where P is the predicate
-   * returned by TermUtil::getHoTypeMatchPredicate( f.getType() ).
-   * These lemmas force certain functions f of type tn to appear as
-   * first-class terms in the quantifier-free UF solver, where recall a
-   * first-class term is one that occurs as an (external) term in its equality
-   * engine. These functions f are all operators that have at least one
-   * term f(t1...tn) indexed by TermDabatase and are such that
-   * f's type is the same as a function-typed variable we
-   * are considering in this class (in d_ho_var_apps).
-   *
-   * TODO: we may eliminate this based on how github issue #1115 is resolved.
-   */
-  int addHoTypeMatchPredicateLemmas();
-  /** send instantiation
-   *
-  * Sends an instantiation that is equivalent to m via
-  * Instantiate::addInstantiation(...). This method may modify m based on
-  * imitations and projections (Huet's algorithm), if m was generated by
-  * matching ground terms to function applications with variable heads.
-  * See examples (EX1)-(EX3) above.
-  */
-  bool sendInstantiation(InstMatch& m) override;
-
- private:
-  //-------------------- current information about the match
-  /**
-   * Map from variable position to the arguments of the lambda we generated
-   * for that variable.
-   *
-   * For example (EX4), take a quantified formula:
-   *   forall x f1 y f2. (...)
-   * Say we generated the match:
-   *   x -> 0
-   *   f1 -> k1
-   *   y -> 1
-   *   f2 -> k2
-   *   z -> 0
-   * where we matched
-   *   (f1 x y) with (k1 0 1) and
-   *   (f2 x z)  with (k2 0 0)
-   * Then the algorithm implemented by this class may modify the match to:
-   *   x -> 0
-   *   f1 -> (\ x1 x2. (k1 x1 1))
-   *   y -> 1
-   *   f2 -> (\ x1 x2. (k2 0 x1))
-   *   z -> 0
-   *
-   * In the above (modified) match, the contents of d_lchildren are:
-   *   1 -> { k1, x1, 1 }
-   *   3 -> { k2, 0, x1 }
-   */
-  std::map<unsigned, std::vector<Node> > d_lchildren;
-  /** map from variable position to the representative variable position.
-  * Used when two argument positions of a match are mapped to equal terms.
-  *
-  * In the above example (EX4), the first and second arguments of
-  * the match for f2 are equal.  Thus, in the above example,
-  * we have that d_arg_to_arg_rep is:
-  *   1 -> { 0 -> 0, 1 -> 1 }
-  *   3 -> { 0 -> 0, 1 -> 0 }
-  * In other words, the first argument
-  */
-  std::map<unsigned, std::map<unsigned, unsigned> > d_arg_to_arg_rep;
-  /** map from representative argument positions to the equivalence class
-   * of argument positions. In the above example (EX4), d_arg_vector is:
-   *   1 -> { 0 -> { 0 }, 1 -> { 1 } }
-   *   3 -> { 0 -> { 0, 1 } }
-   */
-  std::map<unsigned, std::map<unsigned, std::vector<Node> > > d_arg_vector;
-  //-------------------- end current information about the match
-
-  /** higher-order pattern unification algorithm
-   *
-  * Sends an instantiation that is equivalent to m via
-  * d_quantEngine->addInstantiation(...),
-  * based on Huet's algorithm.
-  *
-  * This is a helper function of sendInstantiation( m ) above.
-  *
-  * var_index is the index of the variable in m that we are currently processing
-  *   i.e. we are processing the var_index^{th} higher-order variable.
-  *
-  * For example, say we are processing the match from (EX4) above.
-  *   when var_index = 0,1, we are processing possibilities for
-  *    instantiation of f1,f2 respectively.
-  */
-  bool sendInstantiation(InstMatch& m, unsigned var_index);
-  /** higher-order pattern unification algorithm
-   * Sends an instantiation that is equivalent to m via
-   * d_quantEngine->addInstantiation(...).
-   * This is a helper function of sendInstantiation( m, var_index ) above.
-   *
-   * var_index is the index of the variable in m that we are currently
-   * processing
-   *   i.e. we are processing the var_index^{th} higher-order variable.
-   * vnum maps var_index to the actual variable number in m
-   * arg_index is the argument of the lambda term we are currently considering
-   * lbvl is the bound variable list associated with the term in m we are
-   * currently modifying
-   * arg_changed is whether we have modified m.
-   *
-   * For example, say we have modified our match from (EX4) to:
-   *   x -> 0
-   *   f1 -> (\ x1 x2. (k1 x1 1))
-   *   y -> 1
-   *   f2 -> (\ x1 x2. (k2 0 ?))
-   *   z -> 0
-   * That is, we are currently considering possibilities for the second
-   * argument of the body for f2.
-   * Then:
-   *   var_index = 1,
-   *   vnum = 3 (f2 is the 3^rd variable of our quantified formula)
-   *   arg_index = 1,
-   *   lbvl is d_ho_var_bvl[f2], and
-   *   arg_changed is true, since we modified at least one previous
-   *     argument of f1 or f2.
-   */
-  bool sendInstantiationArg(InstMatch& m,
-                            unsigned var_index,
-                            unsigned vnum,
-                            unsigned arg_index,
-                            Node lbvl,
-                            bool arg_changed);
-};
-
-} /* CVC4::theory::inst namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__HO_TRIGGER_H */
diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp
deleted file mode 100644 (file)
index 46ae8aa..0000000
+++ /dev/null
@@ -1,1138 +0,0 @@
-/*********************                                                        */
-/*! \file inst_match_generator.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Morgan Deters, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-#include "theory/quantifiers/inst_match_generator.h"
-
-#include "expr/datatype.h"
-#include "options/datatypes_options.h"
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/candidate_generator.h"
-#include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
-#include "theory/quantifiers_engine.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-
-namespace CVC4 {
-namespace theory {
-namespace inst {
-
-bool IMGenerator::sendInstantiation(Trigger* tparent, InstMatch& m)
-{
-  return tparent->sendInstantiation(m);
-}
-
-InstMatchGenerator::InstMatchGenerator( Node pat ){
-  d_cg = NULL;
-  d_needsReset = true;
-  d_active_add = true;
-  Assert( quantifiers::TermUtil::hasInstConstAttr(pat) );
-  d_pattern = pat;
-  d_match_pattern = pat;
-  d_match_pattern_type = pat.getType();
-  d_next = NULL;
-  d_independent_gen = false;
-}
-
-InstMatchGenerator::InstMatchGenerator() {
-  d_cg = NULL;
-  d_needsReset = true;
-  d_active_add = true;
-  d_next = NULL;
-  d_independent_gen = false;
-}
-
-InstMatchGenerator::~InstMatchGenerator()
-{
-  for( unsigned i=0; i<d_children.size(); i++ ){
-    delete d_children[i];
-  }
-  delete d_cg;
-}
-
-void InstMatchGenerator::setActiveAdd(bool val){
-  d_active_add = val;
-  if( d_next!=NULL ){
-    d_next->setActiveAdd(val);
-  }
-}
-
-int InstMatchGenerator::getActiveScore( QuantifiersEngine * qe ) {
-  if( d_match_pattern.isNull() ){
-    return -1;
-  }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){
-    Node f = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
-    unsigned ngt = qe->getTermDatabase()->getNumGroundTerms( f );
-    Trace("trigger-active-sel-debug") << "Number of ground terms for " << f << " is " << ngt << std::endl;
-    return ngt;
-  }else if( d_match_pattern.getKind()==INST_CONSTANT ){
-    TypeNode tn = d_match_pattern.getType();
-    unsigned ngtt = qe->getTermDatabase()->getNumTypeGroundTerms( tn );
-    Trace("trigger-active-sel-debug") << "Number of ground terms for " << tn << " is " << ngtt << std::endl;
-    return ngtt;
-//  }else if( d_match_pattern_getKind()==EQUAL ){
-    
-  }else{
-    return -1;
-  }
-}
-
-void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector< InstMatchGenerator * > & gens ){
-  if( !d_pattern.isNull() ){
-    Trace("inst-match-gen") << "Initialize, pattern term is " << d_pattern << std::endl;
-    if( d_match_pattern.getKind()==NOT ){
-      //we want to add the children of the NOT
-      d_match_pattern = d_pattern[0];
-    }
-    if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==GEQ ){
-      //make sure the matching portion of the equality is on the LHS of d_pattern
-      //  and record what d_match_pattern is
-      for( unsigned i=0; i<2; i++ ){
-        if( !quantifiers::TermUtil::hasInstConstAttr(d_match_pattern[i]) || d_match_pattern[i].getKind()==INST_CONSTANT ){
-          Node mp = d_match_pattern[1-i];
-          Node mpo = d_match_pattern[i];
-          if( mp.getKind()!=INST_CONSTANT ){
-            if( i==0 ){
-              if( d_match_pattern.getKind()==GEQ ){
-                d_pattern = NodeManager::currentNM()->mkNode( kind::GT, mp, mpo );
-                d_pattern = d_pattern.negate();
-              }else{
-                d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), mp, mpo );
-              }
-            }
-            d_eq_class_rel = mpo;
-            d_match_pattern = mp;
-          }
-          break;
-        }
-      }
-    }else if( d_match_pattern.getKind()==APPLY_SELECTOR_TOTAL && d_match_pattern[0].getKind()==INST_CONSTANT && 
-              options::purifyDtTriggers() && !options::dtSharedSelectors() ){
-      d_match_pattern = d_match_pattern[0];
-    }
-    d_match_pattern_type = d_match_pattern.getType();
-    Trace("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl;
-    d_match_pattern_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
-
-    //now, collect children of d_match_pattern
-    if (d_match_pattern.getKind() == INST_CONSTANT)
-    {
-      d_children_types.push_back(
-          d_match_pattern.getAttribute(InstVarNumAttribute()));
-    }
-    else
-    {
-      for (unsigned i = 0, size = d_match_pattern.getNumChildren(); i < size;
-           i++)
-      {
-        Node qa = quantifiers::TermUtil::getInstConstAttr(d_match_pattern[i]);
-        if (!qa.isNull())
-        {
-          InstMatchGenerator* cimg =
-              getInstMatchGenerator(q, d_match_pattern[i]);
-          if (cimg)
-          {
-            d_children.push_back(cimg);
-            d_children_index.push_back(i);
-            d_children_types.push_back(-2);
-          }else{
-            if (d_match_pattern[i].getKind() == INST_CONSTANT && qa == q)
-            {
-              d_children_types.push_back(
-                  d_match_pattern[i].getAttribute(InstVarNumAttribute()));
-            }
-            else
-            {
-              d_children_types.push_back(-1);
-            }
-          }
-        }
-        else
-        {
-          d_children_types.push_back(-1);
-        }
-      }
-    }
-
-    //create candidate generator
-    if( Trigger::isAtomicTrigger( d_match_pattern ) ){
-      //we will be scanning lists trying to find d_match_pattern.getOperator()
-      d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern );
-      //if matching on disequality, inform the candidate generator not to match on eqc
-      if( d_pattern.getKind()==NOT && d_pattern[0].getKind()==EQUAL ){
-        ((inst::CandidateGeneratorQE*)d_cg)->excludeEqc( d_eq_class_rel );
-        d_eq_class_rel = Node::null();
-      }
-    }else if( d_match_pattern.getKind()==INST_CONSTANT ){
-      if( d_pattern.getKind()==APPLY_SELECTOR_TOTAL ){
-        Expr selectorExpr = qe->getTermDatabase()->getMatchOperator( d_pattern ).toExpr();
-        size_t selectorIndex = Datatype::cindexOf(selectorExpr);
-        const Datatype& dt = Datatype::datatypeOf(selectorExpr);
-        const DatatypeConstructor& c = dt[selectorIndex];
-        Node cOp = Node::fromExpr(c.getConstructor());
-        Trace("inst-match-gen") << "Purify dt trigger " << d_pattern << ", will match terms of op " << cOp << std::endl;
-        d_cg = new inst::CandidateGeneratorQE( qe, cOp );
-      }else{
-        d_cg = new CandidateGeneratorQEAll( qe, d_match_pattern );
-      }
-    }else if( d_match_pattern.getKind()==EQUAL &&
-              d_match_pattern[0].getKind()==INST_CONSTANT && d_match_pattern[1].getKind()==INST_CONSTANT ){
-      //we will be producing candidates via literal matching heuristics
-      if( d_pattern.getKind()!=NOT ){
-        //candidates will be all equalities
-        d_cg = new inst::CandidateGeneratorQELitEq( qe, d_match_pattern );
-      }else{
-        //candidates will be all disequalities
-        d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern );
-      }
-    }else{
-      Trace("inst-match-gen-warn") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl;
-    }
-  }
-  gens.insert( gens.end(), d_children.begin(), d_children.end() );
-}
-
-/** get match (not modulo equality) */
-int InstMatchGenerator::getMatch(
-    Node f, Node t, InstMatch& m, QuantifiersEngine* qe, Trigger* tparent)
-{
-  Trace("matching") << "Matching " << t << " against pattern " << d_match_pattern << " ("
-                    << m << ")" << ", " << d_children.size() << ", pattern is " << d_pattern << std::endl;
-  Assert( !d_match_pattern.isNull() );
-  if (d_cg == nullptr)
-  {
-    Trace("matching-fail") << "Internal error for match generator." << std::endl;
-    return -2;
-  }else{
-    EqualityQuery* q = qe->getEqualityQuery();
-    bool success = true;
-    //save previous match
-    //InstMatch prev( &m );
-    std::vector< int > prev;
-    //if t is null
-    Assert( !t.isNull() );
-    Assert( !quantifiers::TermUtil::hasInstConstAttr(t) );
-    Assert( d_match_pattern.getKind()==INST_CONSTANT || t.getKind()==d_match_pattern.getKind() );
-    Assert( !Trigger::isAtomicTrigger( d_match_pattern ) || t.getOperator()==d_match_pattern.getOperator() );
-    //first, check if ground arguments are not equal, or a match is in conflict
-    Trace("matching-debug2") << "Setting immediate matches..." << std::endl;
-    for (unsigned i = 0, size = d_match_pattern.getNumChildren(); i < size; i++)
-    {
-      int ct = d_children_types[i];
-      if (ct >= 0)
-      {
-        Trace("matching-debug2") << "Setting " << ct << " to " << t[i] << "..."
-                                 << std::endl;
-        bool addToPrev = m.get(ct).isNull();
-        if (!m.set(q, ct, t[i]))
-        {
-          //match is in conflict
-          Trace("matching-fail") << "Match fail: " << m.get(ct) << " and "
-                                 << t[i] << std::endl;
-          success = false;
-          break;
-        }else if( addToPrev ){
-          Trace("matching-debug2") << "Success." << std::endl;
-          prev.push_back(ct);
-        }
-      }
-      else if (ct == -1)
-      {
-        if( !q->areEqual( d_match_pattern[i], t[i] ) ){
-          Trace("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl;
-          //ground arguments are not equal
-          success = false;
-          break;
-        }
-      }
-    }
-    Trace("matching-debug2") << "Done setting immediate matches, success = " << success << "." << std::endl;
-    //for variable matching
-    if( d_match_pattern.getKind()==INST_CONSTANT ){
-      bool addToPrev = m.get(d_children_types[0]).isNull();
-      if (!m.set(q, d_children_types[0], t))
-      {
-        success = false;
-      }else{
-        if( addToPrev ){
-          prev.push_back(d_children_types[0]);
-        }
-      }
-    //for relational matching
-    }else if( !d_eq_class_rel.isNull() && d_eq_class_rel.getKind()==INST_CONSTANT ){
-      int v = d_eq_class_rel.getAttribute(InstVarNumAttribute());
-      //also must fit match to equivalence class
-      bool pol = d_pattern.getKind()!=NOT;
-      Node pat = d_pattern.getKind()==NOT ? d_pattern[0] : d_pattern;
-      Node t_match;
-      if( pol ){
-        if( pat.getKind()==GT ){
-          t_match = NodeManager::currentNM()->mkNode(MINUS, t, qe->getTermUtil()->d_one);
-        }else{
-          t_match = t;
-        }
-      }else{
-        if( pat.getKind()==EQUAL ){
-          if( t.getType().isBoolean() ){
-            t_match = NodeManager::currentNM()->mkConst( !q->areEqual( qe->getTermUtil()->d_true, t ) );
-          }else{
-            Assert( t.getType().isReal() );
-            t_match = NodeManager::currentNM()->mkNode(PLUS, t, qe->getTermUtil()->d_one);
-          }
-        }else if( pat.getKind()==GEQ ){
-          t_match = NodeManager::currentNM()->mkNode(PLUS, t, qe->getTermUtil()->d_one);
-        }else if( pat.getKind()==GT ){
-          t_match = t;
-        }
-      }
-      if( !t_match.isNull() ){
-        bool addToPrev = m.get( v ).isNull();
-        if (!m.set(q, v, t_match))
-        {
-          success = false;
-        }else if( addToPrev ){
-          prev.push_back( v );
-        }
-      }
-    }
-    int ret_val = -1;
-    if( success ){
-      Trace("matching-debug2") << "Reset children..." << std::endl;
-      //now, fit children into match
-      //we will be requesting candidates for matching terms for each child
-      for (unsigned i = 0, size = d_children.size(); i < size; i++)
-      {
-        if( !d_children[i]->reset( t[ d_children_index[i] ], qe ) ){
-          success = false;
-          break;
-        }
-      }
-      if( success ){
-        Trace("matching-debug2") << "Continue next " << d_next << std::endl;
-        ret_val = continueNextMatch(f, m, qe, tparent);
-      }
-    }
-    if( ret_val<0 ){
-      for (int& pv : prev)
-      {
-        m.d_vals[pv] = Node::null();
-      }
-    }
-    return ret_val;
-  }
-}
-
-int InstMatchGenerator::continueNextMatch(Node f,
-                                          InstMatch& m,
-                                          QuantifiersEngine* qe,
-                                          Trigger* tparent)
-{
-  if( d_next!=NULL ){
-    return d_next->getNextMatch(f, m, qe, tparent);
-  }else{
-    if( d_active_add ){
-      return sendInstantiation(tparent, m) ? 1 : -1;
-    }else{
-      return 1;
-    }
-  }
-}
-
-/** reset instantiation round */
-void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){
-  if( !d_match_pattern.isNull() ){
-    Trace("matching-debug2") << this << " reset instantiation round." << std::endl;
-    d_needsReset = true;
-    if( d_cg ){
-      d_cg->resetInstantiationRound();
-    }
-  }
-  if( d_next ){
-    d_next->resetInstantiationRound( qe );
-  }
-  d_curr_exclude_match.clear();
-}
-
-bool InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){
-  eqc = qe->getEqualityQuery()->getRepresentative( eqc );
-  Trace("matching-debug2") << this << " reset " << eqc << "." << std::endl;
-  if( !d_eq_class_rel.isNull() && d_eq_class_rel.getKind()!=INST_CONSTANT ){
-    d_eq_class = d_eq_class_rel;
-  }else if( !eqc.isNull() ){
-    d_eq_class = eqc;
-  }
-  //we have a specific equivalence class in mind
-  //we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term
-  //just look in equivalence class of the RHS
-  d_cg->reset( d_eq_class );
-  d_needsReset = false;
-  
-  //generate the first candidate preemptively
-  d_curr_first_candidate = Node::null();
-  Node t;
-  do {
-    t = d_cg->getNextCandidate();
-    if( d_curr_exclude_match.find( t )==d_curr_exclude_match.end() ){
-      d_curr_first_candidate = t;
-    }
-  }while( !t.isNull() && d_curr_first_candidate.isNull() );
-  Trace("matching-summary") << "Reset " << d_match_pattern << " in " << eqc << " returns " << !d_curr_first_candidate.isNull() << "." << std::endl;
-
-  return !d_curr_first_candidate.isNull();
-}
-
-int InstMatchGenerator::getNextMatch(Node f,
-                                     InstMatch& m,
-                                     QuantifiersEngine* qe,
-                                     Trigger* tparent)
-{
-  if( d_needsReset ){
-    Trace("matching") << "Reset not done yet, must do the reset..." << std::endl;
-    reset( d_eq_class, qe );
-  }
-  d_curr_matched = Node::null();
-  Trace("matching") << this << " " << d_match_pattern << " get next match " << m << " in eq class " << d_eq_class << std::endl;
-  int success = -1;
-  Node t = d_curr_first_candidate;
-  do{
-    Trace("matching-debug2") << "Matching candidate : " << t << std::endl;
-    //if t not null, try to fit it into match m
-    if( !t.isNull() ){
-      if( d_curr_exclude_match.find( t )==d_curr_exclude_match.end() ){
-        Assert( t.getType().isComparableTo( d_match_pattern_type ) );
-        Trace("matching-summary") << "Try " << d_match_pattern << " : " << t << std::endl;
-        success = getMatch(f, t, m, qe, tparent);
-        if( d_independent_gen && success<0 ){
-          Assert( d_eq_class.isNull() );
-          d_curr_exclude_match[t] = true;
-        }
-      }
-      //get the next candidate term t
-      if( success<0 ){
-        t = d_cg->getNextCandidate();
-      }else{
-        d_curr_first_candidate = d_cg->getNextCandidate();
-      }
-    }
-  }while( success<0 && !t.isNull() );
-  d_curr_matched = t;
-  if( success<0 ){
-    Trace("matching-summary") << "..." << d_match_pattern << " failed, reset." << std::endl;
-    Trace("matching") << this << " failed, reset " << d_eq_class << std::endl;
-    //we failed, must reset
-    reset( d_eq_class, qe );
-  }else{
-    Trace("matching-summary") << "..." << d_match_pattern << " success." << std::endl;
-  }
-  return success;
-}
-
-int InstMatchGenerator::addInstantiations(Node f,
-                                          QuantifiersEngine* qe,
-                                          Trigger* tparent)
-{
-  //try to add instantiation for each match produced
-  int addedLemmas = 0;
-  InstMatch m( f );
-  while (getNextMatch(f, m, qe, tparent) > 0)
-  {
-    if( !d_active_add ){
-      if (sendInstantiation(tparent, m))
-      {
-        addedLemmas++;
-        if( qe->inConflict() ){
-          break;
-        }
-      }
-    }else{
-      addedLemmas++;
-      if( qe->inConflict() ){
-        break;
-      }
-    }
-    m.clear();
-  }
-  //return number of lemmas added
-  return addedLemmas;
-}
-
-
-InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( Node q, Node pat, QuantifiersEngine* qe ) {
-  std::vector< Node > pats;
-  pats.push_back( pat );
-  std::map< Node, InstMatchGenerator * > pat_map_init;
-  return mkInstMatchGenerator( q, pats, qe, pat_map_init );
-}
-
-InstMatchGenerator* InstMatchGenerator::mkInstMatchGeneratorMulti( Node q, std::vector< Node >& pats, QuantifiersEngine* qe ) {
-  Assert( pats.size()>1 );
-  InstMatchGeneratorMultiLinear * imgm = new InstMatchGeneratorMultiLinear( q, pats, qe );
-  std::vector< InstMatchGenerator* > gens;
-  imgm->initialize(q, qe, gens);
-  Assert( gens.size()==pats.size() );
-  std::vector< Node > patsn;
-  std::map< Node, InstMatchGenerator * > pat_map_init;
-  for( unsigned i=0; i<gens.size(); i++ ){
-    Node pn = gens[i]->d_match_pattern;
-    patsn.push_back( pn );
-    pat_map_init[pn] = gens[i];
-  }
-  //return mkInstMatchGenerator( q, patsn, qe, pat_map_init );
-  imgm->d_next = mkInstMatchGenerator( q, patsn, qe, pat_map_init );
-  return imgm;
-}
-
-InstMatchGenerator* InstMatchGenerator::mkInstMatchGenerator( Node q, std::vector< Node >& pats, QuantifiersEngine* qe, 
-                                                              std::map< Node, InstMatchGenerator * >& pat_map_init ) {
-  size_t pCounter = 0;
-  InstMatchGenerator* prev = NULL;
-  InstMatchGenerator* oinit = NULL;
-  while( pCounter<pats.size() ){
-    size_t counter = 0;
-    std::vector< InstMatchGenerator* > gens;
-    InstMatchGenerator* init;
-    std::map< Node, InstMatchGenerator * >::iterator iti = pat_map_init.find( pats[pCounter] );
-    if( iti==pat_map_init.end() ){
-      init = new InstMatchGenerator(pats[pCounter]);
-    }else{
-      init = iti->second;
-    }
-    if(pCounter==0){
-      oinit = init;
-    }
-    gens.push_back(init);
-    //chain the resulting match generators together
-    while (counter<gens.size()) {
-      InstMatchGenerator* curr = gens[counter];
-      if( prev ){
-        prev->d_next = curr;
-      }
-      curr->initialize(q, qe, gens);
-      prev = curr;
-      counter++;
-    }
-    pCounter++;
-  }
-  return oinit;
-}
-
-InstMatchGenerator* InstMatchGenerator::getInstMatchGenerator(Node q, Node n)
-{
-  if (n.getKind() == INST_CONSTANT)
-  {
-    return NULL;
-  }
-  Trace("var-trigger-debug") << "Is " << n << " a variable trigger?"
-                             << std::endl;
-  if (Trigger::isBooleanTermTrigger(n))
-  {
-    VarMatchGeneratorBooleanTerm* vmg =
-        new VarMatchGeneratorBooleanTerm(n[0], n[1]);
-    Trace("var-trigger") << "Boolean term trigger : " << n << ", var = " << n[0]
-                         << std::endl;
-    return vmg;
-  }
-  Node x;
-  if (options::purifyTriggers())
-  {
-    x = Trigger::getInversionVariable(n);
-  }
-  if (!x.isNull())
-  {
-    Node s = Trigger::getInversion(n, x);
-    VarMatchGeneratorTermSubs* vmg = new VarMatchGeneratorTermSubs(x, s);
-    Trace("var-trigger") << "Term substitution trigger : " << n
-                         << ", var = " << x << ", subs = " << s << std::endl;
-    return vmg;
-  }
-  return new InstMatchGenerator(n);
-}
-
-VarMatchGeneratorBooleanTerm::VarMatchGeneratorBooleanTerm( Node var, Node comp ) :
-  InstMatchGenerator(), d_comp( comp ), d_rm_prev( false ) {
-  d_children_types.push_back(var.getAttribute(InstVarNumAttribute()));
-}
-
-int VarMatchGeneratorBooleanTerm::getNextMatch(Node q,
-                                               InstMatch& m,
-                                               QuantifiersEngine* qe,
-                                               Trigger* tparent)
-{
-  int ret_val = -1;
-  if( !d_eq_class.isNull() ){
-    Node s = NodeManager::currentNM()->mkConst(qe->getEqualityQuery()->areEqual( d_eq_class, d_pattern ));
-    d_eq_class = Node::null();
-    d_rm_prev = m.get(d_children_types[0]).isNull();
-    if (!m.set(qe->getEqualityQuery(), d_children_types[0], s))
-    {
-      return -1;
-    }else{
-      ret_val = continueNextMatch(q, m, qe, tparent);
-      if( ret_val>0 ){
-        return ret_val;
-      }
-    }
-  }
-  if( d_rm_prev ){
-    m.d_vals[d_children_types[0]] = Node::null();
-    d_rm_prev = false;
-  }
-  return ret_val;
-}
-
-VarMatchGeneratorTermSubs::VarMatchGeneratorTermSubs( Node var, Node subs ) :
-  InstMatchGenerator(), d_var( var ), d_subs( subs ), d_rm_prev( false ){
-  d_children_types.push_back(d_var.getAttribute(InstVarNumAttribute()));
-  d_var_type = d_var.getType();
-}
-
-int VarMatchGeneratorTermSubs::getNextMatch(Node q,
-                                            InstMatch& m,
-                                            QuantifiersEngine* qe,
-                                            Trigger* tparent)
-{
-  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 );
-    s = Rewriter::rewrite( s );
-    Trace("var-trigger-matching") << "...got " << s << ", " << s.getKind() << std::endl;
-    d_eq_class = Node::null();
-    //if( s.getType().isSubtypeOf( d_var_type ) ){
-    d_rm_prev = m.get(d_children_types[0]).isNull();
-    if (!m.set(qe->getEqualityQuery(), d_children_types[0], s))
-    {
-      return -1;
-    }else{
-      ret_val = continueNextMatch(q, m, qe, tparent);
-      if( ret_val>0 ){
-        return ret_val;
-      }
-    }
-  }
-  if( d_rm_prev ){
-    m.d_vals[d_children_types[0]] = Node::null();
-    d_rm_prev = false;
-  }
-  return -1;
-}
-
-InstMatchGeneratorMultiLinear::InstMatchGeneratorMultiLinear( Node q, std::vector< Node >& pats, QuantifiersEngine* qe ) {
-  //order patterns to maximize eager matching failures
-  std::map< Node, std::vector< Node > > var_contains;
-  qe->getTermUtil()->getVarContains( q, pats, var_contains );
-  std::map< Node, std::vector< Node > > var_to_node;
-  for( std::map< Node, std::vector< Node > >::iterator it = var_contains.begin(); it != var_contains.end(); ++it ){
-    for( unsigned i=0; i<it->second.size(); i++ ){
-      var_to_node[ it->second[i] ].push_back( it->first );
-    }
-  }
-  std::vector< Node > pats_ordered;
-  std::vector< bool > pats_ordered_independent;
-  std::map< Node, bool > var_bound;
-  while( pats_ordered.size()<pats.size() ){
-    // score is lexographic ( bound vars, shared vars )
-    int score_max_1 = -1;
-    int score_max_2 = -1;
-    int score_index = -1;
-    for( unsigned i=0; i<pats.size(); i++ ){
-      Node p = pats[i];
-      if( std::find( pats_ordered.begin(), pats_ordered.end(), p )==pats_ordered.end() ){
-        int score_1 = 0;
-        int score_2 = 0;
-        for( unsigned j=0; j<var_contains[p].size(); j++ ){
-          Node v = var_contains[p][j];
-          if( var_bound.find( v )!=var_bound.end() ){
-            score_1++;
-          }else if( var_to_node[v].size()>1 ){
-            score_2++;
-          }
-        }
-        if( score_index==-1 || score_1>score_max_1 || ( score_1==score_max_1 && score_2>score_max_2 ) ){
-          score_index = i;
-          score_max_1 = score_1;
-          score_max_2 = score_2;
-        }
-      }
-    }
-    //update the variable bounds
-    Node mp = pats[score_index];
-    for( unsigned i=0; i<var_contains[mp].size(); i++ ){
-      var_bound[var_contains[mp][i]] = true;
-    }
-    pats_ordered.push_back( mp );
-    pats_ordered_independent.push_back( score_max_1==0 );
-  }
-  
-  Trace("multi-trigger-linear") << "Make children for linear multi trigger." << std::endl;
-  for( unsigned i=0; i<pats_ordered.size(); i++ ){
-    Trace("multi-trigger-linear") << "...make for " << pats_ordered[i] << std::endl;
-    InstMatchGenerator* cimg = getInstMatchGenerator(q, pats_ordered[i]);
-    Assert( cimg!=NULL );
-    d_children.push_back( cimg );
-    if( i==0 ){  //TODO : improve
-      cimg->setIndependent();
-    }
-  }
-}
-
-int InstMatchGeneratorMultiLinear::resetChildren( QuantifiersEngine* qe ){
-  for( unsigned i=0; i<d_children.size(); i++ ){
-    if( !d_children[i]->reset( Node::null(), qe ) ){
-      return -2;
-    }
-  }
-  return 1;
-}
-
-bool InstMatchGeneratorMultiLinear::reset( Node eqc, QuantifiersEngine* qe ) {
-  Assert( eqc.isNull() );
-  if( options::multiTriggerLinear() ){
-    return true;
-  }else{
-    return resetChildren( qe )>0;
-  }
-}
-
-int InstMatchGeneratorMultiLinear::getNextMatch(Node q,
-                                                InstMatch& m,
-                                                QuantifiersEngine* qe,
-                                                Trigger* tparent)
-{
-  Trace("multi-trigger-linear-debug") << "InstMatchGeneratorMultiLinear::getNextMatch : reset " << std::endl;
-  if( options::multiTriggerLinear() ){
-    //reset everyone
-    int rc_ret = resetChildren( qe );
-    if( rc_ret<0 ){
-      return rc_ret;
-    }
-  }
-  Trace("multi-trigger-linear-debug") << "InstMatchGeneratorMultiLinear::getNextMatch : continue match " << std::endl;
-  Assert( d_next!=NULL );
-  int ret_val = continueNextMatch(q, m, qe, tparent);
-  if( ret_val>0 ){
-    Trace("multi-trigger-linear") << "Successful multi-trigger instantiation." << std::endl;
-    if( options::multiTriggerLinear() ){
-      // now, restrict everyone
-      for( unsigned i=0; i<d_children.size(); i++ ){
-        Node mi = d_children[i]->getCurrentMatch();
-        Trace("multi-trigger-linear") << "   child " << i << " match : " << mi << std::endl;
-        d_children[i]->excludeMatch( mi );
-      }
-    }
-  }
-  return ret_val;
-}
-
-
-/** constructors */
-InstMatchGeneratorMulti::InstMatchGeneratorMulti(Node q,
-                                                 std::vector<Node>& pats,
-                                                 QuantifiersEngine* qe)
-    : d_quant(q)
-{
-  Trace("multi-trigger-cache") << "Making smart multi-trigger for " << q << std::endl;
-  std::map< Node, std::vector< Node > > var_contains;
-  qe->getTermUtil()->getVarContains( q, pats, var_contains );
-  //convert to indicies
-  for( std::map< Node, std::vector< Node > >::iterator it = var_contains.begin(); it != var_contains.end(); ++it ){
-    Trace("multi-trigger-cache") << "Pattern " << it->first << " contains: ";
-    for( int i=0; i<(int)it->second.size(); i++ ){
-      Trace("multi-trigger-cache") << it->second[i] << " ";
-      int index = it->second[i].getAttribute(InstVarNumAttribute());
-      d_var_contains[ it->first ].push_back( index );
-      d_var_to_node[ index ].push_back( it->first );
-    }
-    Trace("multi-trigger-cache") << std::endl;
-  }
-  for( unsigned i=0; i<pats.size(); i++ ){
-    Node n = pats[i];
-    //make the match generator
-    InstMatchGenerator* img =
-        InstMatchGenerator::mkInstMatchGenerator(q, n, qe);
-    img->setActiveAdd(false);
-    d_children.push_back(img);
-    //compute unique/shared variables
-    std::vector< int > unique_vars;
-    std::map< int, bool > shared_vars;
-    int numSharedVars = 0;
-    for( unsigned j=0; j<d_var_contains[n].size(); j++ ){
-      if( d_var_to_node[ d_var_contains[n][j] ].size()==1 ){
-        Trace("multi-trigger-cache") << "Var " << d_var_contains[n][j] << " is unique to " << pats[i] << std::endl;
-        unique_vars.push_back( d_var_contains[n][j] );
-      }else{
-        shared_vars[ d_var_contains[n][j] ] = true;
-        numSharedVars++;
-      }
-    }
-    //we use the latest shared variables, then unique variables
-    std::vector< int > vars;
-    unsigned index = i==0 ? pats.size()-1 : (i-1);
-    while( numSharedVars>0 && index!=i ){
-      for( std::map< int, bool >::iterator it = shared_vars.begin(); it != shared_vars.end(); ++it ){
-        if( it->second ){
-          if( std::find( d_var_contains[ pats[index] ].begin(), d_var_contains[ pats[index] ].end(), it->first )!=
-              d_var_contains[ pats[index] ].end() ){
-            vars.push_back( it->first );
-            shared_vars[ it->first ] = false;
-            numSharedVars--;
-          }
-        }
-      }
-      index = index==0 ? (int)(pats.size()-1) : (index-1);
-    }
-    vars.insert( vars.end(), unique_vars.begin(), unique_vars.end() );
-    Trace("multi-trigger-cache") << "   Index[" << i << "]: ";
-    for( unsigned j=0; j<vars.size(); j++ ){
-      Trace("multi-trigger-cache") << vars[j] << " ";
-    }
-    Trace("multi-trigger-cache") << std::endl;
-    //make ordered inst match trie
-    d_imtio[i] = new InstMatchTrie::ImtIndexOrder;
-    d_imtio[i]->d_order.insert( d_imtio[i]->d_order.begin(), vars.begin(), vars.end() );
-    d_children_trie.push_back( InstMatchTrieOrdered( d_imtio[i] ) );
-  }
-}
-
-InstMatchGeneratorMulti::~InstMatchGeneratorMulti()
-{
-  for( unsigned i=0; i<d_children.size(); i++ ){
-    delete d_children[i];
-  }
-  for( std::map< unsigned, InstMatchTrie::ImtIndexOrder* >::iterator it = d_imtio.begin(); it != d_imtio.end(); ++it ){
-    delete it->second;
-  }
-}
-
-/** reset instantiation round (call this whenever equivalence classes have changed) */
-void InstMatchGeneratorMulti::resetInstantiationRound( QuantifiersEngine* qe ){
-  for( unsigned i=0; i<d_children.size(); i++ ){
-    d_children[i]->resetInstantiationRound( qe );
-  }
-}
-
-/** reset, eqc is the equivalence class to search in (any if eqc=null) */
-bool InstMatchGeneratorMulti::reset( Node eqc, QuantifiersEngine* qe ){
-  for( unsigned i=0; i<d_children.size(); i++ ){
-    if( !d_children[i]->reset( eqc, qe ) ){
-      //return false;
-    }
-  }
-  return true;
-}
-
-int InstMatchGeneratorMulti::addInstantiations(Node q,
-                                               QuantifiersEngine* qe,
-                                               Trigger* tparent)
-{
-  int addedLemmas = 0;
-  Trace("multi-trigger-cache") << "Process smart multi trigger" << std::endl;
-  for( unsigned i=0; i<d_children.size(); i++ ){
-    Trace("multi-trigger-cache") << "Calculate matches " << i << std::endl;
-    std::vector< InstMatch > newMatches;
-    InstMatch m( q );
-    while (d_children[i]->getNextMatch(q, m, qe, tparent) > 0)
-    {
-      //m.makeRepresentative( qe );
-      newMatches.push_back( InstMatch( &m ) );
-      m.clear();
-    }
-    Trace("multi-trigger-cache") << "Made " << newMatches.size() << " new matches for index " << i << std::endl;
-    for( unsigned j=0; j<newMatches.size(); j++ ){
-      Trace("multi-trigger-cache2") << "...processing " << j << " / " << newMatches.size() << ", #lemmas = " << addedLemmas << std::endl;
-      processNewMatch(qe, tparent, newMatches[j], i, addedLemmas);
-      if( qe->inConflict() ){
-        return addedLemmas;
-      }
-    }
-  }
-  return addedLemmas;
-}
-
-void InstMatchGeneratorMulti::processNewMatch(QuantifiersEngine* qe,
-                                              Trigger* tparent,
-                                              InstMatch& m,
-                                              int fromChildIndex,
-                                              int& addedLemmas)
-{
-  //see if these produce new matches
-  d_children_trie[fromChildIndex].addInstMatch(qe, d_quant, m);
-  //possibly only do the following if we know that new matches will be produced?
-  //the issue is that instantiations are filtered in quantifiers engine, and so there is no guarentee that
-  // we can safely skip the following lines, even when we have already produced this match.
-  Trace("multi-trigger-cache-debug") << "Child " << fromChildIndex << " produced match " << m << std::endl;
-  //process new instantiations
-  int childIndex = (fromChildIndex+1)%(int)d_children.size();
-  processNewInstantiations(qe,
-                           tparent,
-                           m,
-                           addedLemmas,
-                           d_children_trie[childIndex].getTrie(),
-                           0,
-                           childIndex,
-                           fromChildIndex,
-                           true);
-}
-
-void InstMatchGeneratorMulti::processNewInstantiations(QuantifiersEngine* qe,
-                                                       Trigger* tparent,
-                                                       InstMatch& m,
-                                                       int& addedLemmas,
-                                                       InstMatchTrie* tr,
-                                                       int trieIndex,
-                                                       int childIndex,
-                                                       int endChildIndex,
-                                                       bool modEq)
-{
-  Assert( !qe->inConflict() );
-  if( childIndex==endChildIndex ){
-    // m is an instantiation
-    if (sendInstantiation(tparent, m))
-    {
-      addedLemmas++;
-      Trace("multi-trigger-cache-debug") << "-> Produced instantiation " << m
-                                         << std::endl;
-    }
-  }else if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){
-    int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex];
-    // Node curr_ic = qe->getTermUtil()->getInstantiationConstant( d_quant,
-    // curr_index );
-    Node n = m.get( curr_index );
-    if( n.isNull() ){
-      // add to InstMatch
-      for (std::pair<const Node, InstMatchTrie>& d : tr->d_data)
-      {
-        InstMatch mn(&m);
-        mn.setValue(curr_index, d.first);
-        processNewInstantiations(qe,
-                                 tparent,
-                                 mn,
-                                 addedLemmas,
-                                 &(d.second),
-                                 trieIndex + 1,
-                                 childIndex,
-                                 endChildIndex,
-                                 modEq);
-        if (qe->inConflict())
-        {
-          break;
-        }
-      }
-    }
-    // shared and set variable, try to merge
-    std::map<Node, InstMatchTrie>::iterator it = tr->d_data.find(n);
-    if (it != tr->d_data.end())
-    {
-      processNewInstantiations(qe,
-                               tparent,
-                               m,
-                               addedLemmas,
-                               &(it->second),
-                               trieIndex + 1,
-                               childIndex,
-                               endChildIndex,
-                               modEq);
-    }
-    if (modEq)
-    {
-      // check modulo equality for other possible instantiations
-      if (qe->getEqualityQuery()->getEngine()->hasTerm(n))
-      {
-        eq::EqClassIterator eqc(
-            qe->getEqualityQuery()->getEngine()->getRepresentative(n),
-            qe->getEqualityQuery()->getEngine());
-        while (!eqc.isFinished())
-        {
-          Node en = (*eqc);
-          if (en != n)
-          {
-            std::map<Node, InstMatchTrie>::iterator itc = tr->d_data.find(en);
-            if (itc != tr->d_data.end())
-            {
-              processNewInstantiations(qe,
-                                       tparent,
-                                       m,
-                                       addedLemmas,
-                                       &(itc->second),
-                                       trieIndex + 1,
-                                       childIndex,
-                                       endChildIndex,
-                                       modEq);
-              if (qe->inConflict())
-              {
-                break;
-              }
-            }
-          }
-          ++eqc;
-        }
-      }
-    }
-  }else{
-    int newChildIndex = (childIndex+1)%(int)d_children.size();
-    processNewInstantiations(qe,
-                             tparent,
-                             m,
-                             addedLemmas,
-                             d_children_trie[newChildIndex].getTrie(),
-                             0,
-                             newChildIndex,
-                             endChildIndex,
-                             modEq);
-  }
-}
-
-InstMatchGeneratorSimple::InstMatchGeneratorSimple(Node q,
-                                                   Node pat,
-                                                   QuantifiersEngine* qe)
-    : d_quant(q), d_match_pattern(pat)
-{
-  if( d_match_pattern.getKind()==NOT ){
-    d_match_pattern = d_match_pattern[0];
-    d_pol = false;
-  }else{
-    d_pol = true;
-  }
-  if( d_match_pattern.getKind()==EQUAL ){
-    d_eqc = d_match_pattern[1];
-    d_match_pattern = d_match_pattern[0];
-    Assert( !quantifiers::TermUtil::hasInstConstAttr( d_eqc ) );
-  }
-  Assert( Trigger::isSimpleTrigger( d_match_pattern ) );
-  for( unsigned i=0; i<d_match_pattern.getNumChildren(); i++ ){
-    if( d_match_pattern[i].getKind()==INST_CONSTANT ){
-      if( !options::cbqi() || quantifiers::TermUtil::getInstConstAttr(d_match_pattern[i])==q ){
-        d_var_num[i] = d_match_pattern[i].getAttribute(InstVarNumAttribute());
-      }else{
-        d_var_num[i] = -1;
-      }
-    }
-    d_match_pattern_arg_types.push_back( d_match_pattern[i].getType() );
-  }
-  d_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
-}
-
-void InstMatchGeneratorSimple::resetInstantiationRound( QuantifiersEngine* qe ) {
-  
-}
-int InstMatchGeneratorSimple::addInstantiations(Node q,
-                                                QuantifiersEngine* qe,
-                                                Trigger* tparent)
-{
-  int addedLemmas = 0;
-  quantifiers::TermArgTrie* tat;
-  if( d_eqc.isNull() ){
-    tat = qe->getTermDatabase()->getTermArgTrie( d_op );
-  }else{
-    if( d_pol ){
-      tat = qe->getTermDatabase()->getTermArgTrie( d_eqc, d_op );
-    }else{
-      Node r = qe->getEqualityQuery()->getRepresentative( d_eqc );
-      //iterate over all classes except r
-      tat = qe->getTermDatabase()->getTermArgTrie( Node::null(), d_op );
-      if( tat ){
-        for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){
-          if( it->first!=r ){
-            InstMatch m( q );
-            addInstantiations( m, qe, addedLemmas, 0, &(it->second) );
-            if( qe->inConflict() ){
-              break;
-            }
-          }
-        }
-        tat = NULL;
-      }
-    }
-  }
-  Debug("simple-trigger-debug") << "Adding instantiations based on " << tat << " from " << d_op << " " << d_eqc << std::endl;
-  if( tat ){
-    InstMatch m( q );
-    addInstantiations( m, qe, addedLemmas, 0, tat );
-  }
-  return addedLemmas;
-}
-
-void InstMatchGeneratorSimple::addInstantiations(InstMatch& m,
-                                                 QuantifiersEngine* qe,
-                                                 int& addedLemmas,
-                                                 unsigned argIndex,
-                                                 quantifiers::TermArgTrie* tat)
-{
-  Debug("simple-trigger-debug") << "Add inst " << argIndex << " " << d_match_pattern << std::endl;
-  if (argIndex == d_match_pattern.getNumChildren())
-  {
-    Assert( !tat->d_data.empty() );
-    TNode t = tat->getNodeData();
-    Debug("simple-trigger") << "Actual term is " << t << std::endl;
-    //convert to actual used terms
-    for( std::map< int, int >::iterator it = d_var_num.begin(); it != d_var_num.end(); ++it ){
-      if( it->second>=0 ){
-        Debug("simple-trigger") << "...set " << it->second << " " << t[it->first] << std::endl;
-        m.setValue( it->second, t[it->first] );
-      }
-    }
-    // we do not need the trigger parent for simple triggers (no post-processing
-    // required)
-    if (qe->getInstantiate()->addInstantiation(d_quant, m))
-    {
-      addedLemmas++;
-      Debug("simple-trigger") << "-> Produced instantiation " << m << std::endl;
-    }
-  }else{
-    if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){
-      int v = d_var_num[argIndex];
-      if( v!=-1 ){
-        for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){
-          Node t = it->first;
-          Node prev = m.get( v );
-          //using representatives, just check if equal
-          Assert( t.getType().isComparableTo( d_match_pattern_arg_types[argIndex] ) );
-          if( prev.isNull() || prev==t ){
-            m.setValue( v, t);
-            addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) );
-            m.setValue( v, prev);
-            if( qe->inConflict() ){
-              break;
-            }
-          }
-        }
-        return;
-      }
-      //inst constant from another quantified formula, treat as ground term  TODO: remove this?
-    }
-    Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] );
-    std::map< TNode, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r );
-    if( it!=tat->d_data.end() ){
-      addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) );
-    }
-  }
-}
-
-int InstMatchGeneratorSimple::getActiveScore( QuantifiersEngine * qe ) {
-  Node f = qe->getTermDatabase()->getMatchOperator( d_match_pattern );
-  unsigned ngt = qe->getTermDatabase()->getNumGroundTerms( f );
-  Trace("trigger-active-sel-debug") << "Number of ground terms for (simple) " << f << " is " << ngt << std::endl;
-  return ngt;   
-}
-
-
-}/* CVC4::theory::inst namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h
deleted file mode 100644 (file)
index 1903a0f..0000000
+++ /dev/null
@@ -1,694 +0,0 @@
-/*********************                                                        */
-/*! \file inst_match_generator.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Morgan Deters, Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief inst match generator class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H
-#define __CVC4__THEORY__QUANTIFIERS__INST_MATCH_GENERATOR_H
-
-#include <map>
-#include "theory/quantifiers/inst_match_trie.h"
-
-namespace CVC4 {
-namespace theory {
-
-class QuantifiersEngine;
-namespace quantifiers{
-  class TermArgTrie;
-}
-
-namespace inst {
-
-class Trigger;
-
-/** IMGenerator class
-*
-* Virtual base class for generating InstMatch objects, which correspond to
-* quantifier instantiations. The main use of this class is as a backend utility
-* to Trigger (see theory/quantifiers/trigger.h).
-*
-* Some functions below take as argument a pointer to the current quantifiers
-* engine, which is used for making various queries about what terms and
-* equalities exist in the current context.
-*
-* Some functions below take a pointer to a parent Trigger object, which is used
-* to post-process and finalize the instantiations through
-* sendInstantiation(...), where the parent trigger will make calls to
-* qe->getInstantiate()->addInstantiation(...). The latter function is the entry
-* point in which instantiate lemmas are enqueued to be sent on the output
-* channel.
-*/
-class IMGenerator {
-public:
-  virtual ~IMGenerator() {}
-  /** Reset instantiation round.
-  *
-  * Called once at beginning of an instantiation round.
-  */
-  virtual void resetInstantiationRound(QuantifiersEngine* qe) {}
-  /** Reset.
-  *
-  * eqc is the equivalence class to search in (any if eqc=null).
-  * Returns true if this generator can produce instantiations, and false
-  * otherwise. An example of when it returns false is if it can be determined
-  * that no appropriate matchable terms occur based on eqc.
-  */
-  virtual bool reset(Node eqc, QuantifiersEngine* qe) { return true; }
-  /** Get the next match.
-  *
-  * Must call reset( eqc ) before this function. This constructs an
-  * instantiation, which it populates in data structure m,
-  * based on the current context using the implemented matching algorithm.
-  *
-  * q is the quantified formula we are adding instantiations for
-  * m is the InstMatch object we are generating
-  *
-  * Returns a value >0 if an instantiation was successfully generated
-  */
-  virtual int getNextMatch(Node q,
-                           InstMatch& m,
-                           QuantifiersEngine* qe,
-                           Trigger* tparent)
-  {
-    return 0;
-  }
-  /** add instantiations
-  *
-  * This add all available instantiations for q based on the current context
-  * using the implemented matching algorithm. It typically is implemented as a
-  * fixed point of getNextMatch above.
-  *
-  * It returns the number of instantiations added using calls to calls to
-  * Instantiate::addInstantiation(...).
-  */
-  virtual int addInstantiations(Node q,
-                                QuantifiersEngine* qe,
-                                Trigger* tparent)
-  {
-    return 0;
-  }
-  /** get active score
-  *
-  * A heuristic value indicating how active this generator is.
-  */
-  virtual int getActiveScore( QuantifiersEngine * qe ) { return 0; }
- protected:
-  /** send instantiation
-   *
-   * This method sends instantiation, specified by m, to the parent trigger
-   * object, which will in turn make a call to
-   * Instantiate::addInstantiation(...). This method returns true if a
-   * call to Instantiate::addInstantiation(...) was successfully made,
-   * indicating that an instantiation was enqueued in the quantifier engine's
-   * lemma cache.
-   */
-  bool sendInstantiation(Trigger* tparent, InstMatch& m);
-};/* class IMGenerator */
-
-class CandidateGenerator;
-
-/** InstMatchGenerator class
-*
-* This is the default generator class for non-simple single triggers, that is,
-* triggers composed of a single term with nested term applications.
-* For example, { f( y, f( x, a ) ) } and { f( g( x ), a ) } are non-simple
-* triggers.
-*
-* Handling non-simple triggers is done by constructing a linked list of
-* InstMatchGenerator classes (see mkInstMatchGenerator), where each
-* InstMatchGenerator has a "d_next" pointer.  If d_next is NULL,
-* then this is the end of the InstMatchGenerator and the last
-* InstMatchGenerator is responsible for finalizing the instantiation.
-*
-* For (EX1), for the trigger f( y, f( x, a ) ), we construct the linked list:
-*
-* [ f( y, f( x, a ) ) ] -> [ f( x, a ) ] -> NULL
-*
-* In a call to getNextMatch,
-* if we match against a ground term f( b, c ), then the first InstMatchGenerator
-* in this list binds y to b, and tells the InstMatchGenerator [ f( x, a ) ] to
-* match f-applications in the equivalence class of c.
-*
-* CVC4 employs techniques that ensure that the number of instantiations
-* is worst-case polynomial wrt the number of ground terms.
-* Consider the axiom/pattern/context (EX2) :
-*
-*          axiom : forall x1 x2 x3 x4. F[ x1...x4 ]
-*
-*        trigger : P( f( x1 ), f( x2 ), f( x3 ), f( x4 ) )
-*
-* ground context : ~P( a, a, a, a ), a = f( c_1 ) = ... = f( c_100 )
-*
-* If E-matching were applied exhaustively, then x1, x2, x3, x4 would be
-* instantiated with all combinations of c_1, ... c_100, giving 100^4
-* instantiations.
-*
-* Instead, we enforce that at most 1 instantiation is produced for a
-* ( pattern, ground term ) pair per round. Meaning, only one instantiation is
-* generated when matching P( a, a, a, a ) against the generator
-* [P( f( x1 ), f( x2 ), f( x3 ), f( x4 ) )]. For details, see Section 3 of
-* Reynolds, Vampire 2016.
-*
-* To enforce these policies, we use a flag "d_active_add" which dictates the
-* behavior of the last element in the linked list. If d_active_add is
-*   true -> a call to getNextMatch(...) returns 1 only if adding the
-*           instantiation via a call to IMGenerator::sendInstantiation(...)
-*           successfully enqueues a lemma via a call to
-*           Instantiate::addInstantiation(...). This call may fail e.g. if we
-*           have already added the instantiation, or the instantiation is
-*           entailed.
-*   false -> a call to getNextMatch(...) returns 1 whenever an m is
-*            constructed, where typically the caller would use m.
-* This is important since a return value >0 signals that the current matched
-* terms should be flushed. Consider the above example (EX1), where
-* [ f(y,f(x,a)) ] is being matched against f(b,c),
-* [ f(x,a) ] is being matched against f(d,a) where c=f(d,a)
-* A successfully added instantiation { x->d, y->b } here signals we should
-* not produce further instantiations that match f(y,f(x,a)) with f(b,c).
-*
-* A number of special cases of triggers are covered by this generator (see
-* implementation of initialize), including :
-*   Literal triggers, e.g. x >= a, ~x = y
-*   Selector triggers, e.g. head( x )
-*   Triggers with invertible subterms, e.g. f( x+1 )
-*   Variable triggers, e.g. x
-*
-* All triggers above can be in the context of an equality, e.g.
-* { f( y, f( x, a ) ) = b } is a trigger that matches f( y, f( x, a ) ) to
-* ground terms in the equivalence class of b.
-* { ~f( y, f( x, a ) ) = b } is a trigger that matches f( y, f( x, a ) ) to any
-* ground terms not in the equivalence class of b.
-*/
-class InstMatchGenerator : public IMGenerator {
- public:
-  /** destructor */
-  ~InstMatchGenerator() override;
-
-  /** Reset instantiation round. */
-  void resetInstantiationRound(QuantifiersEngine* qe) override;
-  /** Reset. */
-  bool reset(Node eqc, QuantifiersEngine* qe) override;
-  /** Get the next match. */
-  int getNextMatch(Node q,
-                   InstMatch& m,
-                   QuantifiersEngine* qe,
-                   Trigger* tparent) override;
-  /** Add instantiations. */
-  int addInstantiations(Node q,
-                        QuantifiersEngine* qe,
-                        Trigger* tparent) override;
-
-  /** set active add flag (true by default)
-   *
-  * If active add is true, we call sendInstantiation in calls to getNextMatch,
-  * instead of returning the match. This is necessary so that we can ensure
-  * policies that are dependent upon knowing when instantiations are
-  * successfully added to the output channel through
-  * Instantiate::addInstantiation(...).
-  */
-  void setActiveAdd(bool val);
-  /** Get active score for this inst match generator
-   *
-   * See Trigger::getActiveScore for details.
-   */
-  int getActiveScore(QuantifiersEngine* qe) override;
-  /** exclude match
-   *
-   * Exclude matching d_match_pattern with Node n on subsequent calls to
-   * getNextMatch.
-   */
-  void excludeMatch(Node n) { d_curr_exclude_match[n] = true; }
-  /** Get current match.
-   * Returns the term we are currently matching.
-   */
-  Node getCurrentMatch() { return d_curr_matched; }
-  /** set that this match generator is independent
-   *
-  * A match generator is indepndent when this generator fails to produce a
-  * match in a call to getNextMatch, the overall matching fails.
-  */
-  void setIndependent() { d_independent_gen = true; }
-  //-------------------------------construction of inst match generators
-  /** mkInstMatchGenerator for single triggers, calls the method below */
-  static InstMatchGenerator* mkInstMatchGenerator(Node q,
-                                                  Node pat,
-                                                  QuantifiersEngine* qe);
-  /** mkInstMatchGenerator for the multi trigger case
-  *
-  * This linked list of InstMatchGenerator classes with one
-  * InstMatchGeneratorMultiLinear at the head and a list of trailing
-  * InstMatchGenerators corresponding to each unique subterm of pats with
-  * free variables.
-  */
-  static InstMatchGenerator* mkInstMatchGeneratorMulti(Node q,
-                                                       std::vector<Node>& pats,
-                                                       QuantifiersEngine* qe);
-  /** mkInstMatchGenerator
-  *
-  * This generates a linked list of InstMatchGenerators for each unique
-  * subterm of pats with free variables.
-  *
-  * q is the quantified formula associated with the generator we are making
-  * pats is a set of terms we are making InstMatchGenerator nodes for
-  * qe is a pointer to the quantifiers engine (used for querying necessary
-  * information during initialization) pat_map_init maps from terms to
-  * generators we have already made for them.
-  *
-  * It calls initialize(...) for all InstMatchGenerators generated by this call.
-  */
-  static InstMatchGenerator* mkInstMatchGenerator(
-      Node q,
-      std::vector<Node>& pats,
-      QuantifiersEngine* qe,
-      std::map<Node, InstMatchGenerator*>& pat_map_init);
-  //-------------------------------end construction of inst match generators
-
- protected:
-  /** constructors
-   *
-  * These are intentionally private, and are called during linked list
-  * construction in mkInstMatchGenerator.
-  */
-  InstMatchGenerator(Node pat);
-  InstMatchGenerator();
-  /** The pattern we are producing matches for.
-   *
-  * This term and d_match_pattern can be different since this
-  * term may involve  information regarding phase and (dis)equality entailment,
-  * or other special cases of Triggers.
-  *
-  * For example, for the trigger for P( x ) = false, which matches P( x ) with
-  * P( t ) in the equivalence class of false,
-  *   P( x ) = false is d_pattern
-  *   P( x ) is d_match_pattern
-  * Another example, for pure theory triggers like head( x ), we have
-  *   head( x ) is d_pattern
-  *   x is d_match_pattern
-  * since head( x ) can match any (List) datatype term x.
-  *
-  * If null, this is a multi trigger that is merging matches from d_children,
-  * which is used in InstMatchGeneratorMulti.
-  */
-  Node d_pattern;
-  /** The match pattern
-   * This is the term that is matched against ground terms,
-   * see examples above.
-   */
-  Node d_match_pattern;
-  /** The current term we are matching. */
-  Node d_curr_matched;
-  /** do we need to call reset on this generator? */
-  bool d_needsReset;
-  /** candidate generator
-   * This is the back-end utility for InstMatchGenerator.
-   * It generates a stream of candidate terms to match against d_match_pattern
-   * below, dependending upon what kind of term we are matching
-   * (e.g. a matchable term, a variable, a relation, etc.).
-   */
-  CandidateGenerator* d_cg;
-  /** children generators
-   * These match generators correspond to the children of the term
-   * we are matching with this generator.
-   * For example [ f( x, a ) ] is a child of [ f( y, f( x, a ) ) ]
-   * in the example (EX1) above.
-   */
-  std::vector<InstMatchGenerator*> d_children;
-  /** for each child, the index in the term
-   * For example [ f( x, a ) ] has index 1 in [ f( y, f( x, a ) ) ]
-   * in the example (EX1) above, indicating it is the 2nd child
-   * of the term.
-   */
-  std::vector<int> d_children_index;
-  /** children types
-   *
-   * If d_match_pattern is an instantiation constant, then this is a singleton
-   * vector containing the variable number of the d_match_pattern itself.
-   * If d_match_patterm is a term of the form f( t1, ..., tn ), then for each
-   * index i, d_children[i] stores the type of node ti is, where:
-   *   >= 0 : variable (indicates its number),
-   *   -1 : ground term,
-   *   -2 : child term.
-   */
-  std::vector<int> d_children_types;
-  /** The next generator in the linked list
-   * that this generator is a part of.
-   */
-  InstMatchGenerator* d_next;
-  /** The equivalence class we are currently matching in. */
-  Node d_eq_class;
-  /** If non-null, then this is a relational trigger of the form x ~
-   * d_eq_class_rel. */
-  Node d_eq_class_rel;
-  /** Excluded matches
-  * Stores the terms we are not allowed to match.
-  * These can for instance be specified by the smt2
-  * extended syntax (! ... :no-pattern).
-  */
-  std::map<Node, bool> d_curr_exclude_match;
-  /** Current first candidate
-  * Used in a key fail-quickly optimization which generates
-  * the first candidate term to match during reset().
-  */
-  Node d_curr_first_candidate;
-  /** Indepdendent generate
-  * If this flag is true, failures to match should be cached.
-  */
-  bool d_independent_gen;
-  /** active add flag, described above. */
-  bool d_active_add;
-  /** cached value of d_match_pattern.getType() */
-  TypeNode d_match_pattern_type;
-  /** the match operator for d_match_pattern
-   *
-   * See TermDatabase::getMatchOperator for details on match operators.
-   */
-  Node d_match_pattern_op;
-  /** get the match against ground term or formula t.
-   *
-   * d_match_pattern and t should have the same shape, that is,
-   * their match operator (see TermDatabase::getMatchOperator) is the same.
-   * only valid for use where !d_match_pattern.isNull().
-   */
-  int getMatch(
-      Node q, Node t, InstMatch& m, QuantifiersEngine* qe, Trigger* tparent);
-  /** Initialize this generator.
-   *
-   * q is the quantified formula associated with this generator.
-   *
-   * This constructs the appropriate information about what
-   * patterns we are matching and children generators.
-   *
-   * It may construct new (child) generators needed to implement
-   * the matching algorithm for this term. For each new generator
-   * constructed in this way, it adds them to gens.
-   */
-  void initialize(Node q,
-                  QuantifiersEngine* qe,
-                  std::vector<InstMatchGenerator*>& gens);
-  /** Continue next match
-   *
-  * This is called during getNextMatch when the current generator in the linked
-  * list succesfully satisfies its matching constraint. This function either
-  * calls getNextMatch of the next element in the linked list, or finalizes the
-  * match (calling sendInstantiation(...) if active add is true, or returning a
-  * value >0 if active add is false).  Its return value has the same semantics
-  * as getNextMatch.
-  */
-  int continueNextMatch(Node q,
-                        InstMatch& m,
-                        QuantifiersEngine* qe,
-                        Trigger* tparent);
-  /** Get inst match generator
-   *
-   * Gets the InstMatchGenerator that implements the
-   * appropriate matching algorithm for n within q
-   * within a linked list of InstMatchGenerators.
-   */
-  static InstMatchGenerator* getInstMatchGenerator(Node q, Node n);
-};/* class InstMatchGenerator */
-
-/** match generator for Boolean term ITEs
-* This handles the special case of triggers that look like ite( x, BV1, BV0 ).
-*/
-class VarMatchGeneratorBooleanTerm : public InstMatchGenerator {
-public:
-  VarMatchGeneratorBooleanTerm( Node var, Node comp );
-
-  /** Reset */
-  bool reset(Node eqc, QuantifiersEngine* qe) override
-  {
-    d_eq_class = eqc; 
-    return true;
-  }
-  /** Get the next match. */
-  int getNextMatch(Node q,
-                   InstMatch& m,
-                   QuantifiersEngine* qe,
-                   Trigger* tparent) override;
-
- private:
-  /** stores the true branch of the Boolean ITE */
-  Node d_comp;
-  /** stores whether we have written a value for var in the current match. */
-  bool d_rm_prev;
-};
-
-/** match generator for purified terms
-* This handles the special case of invertible terms like x+1 (see
-* Trigger::getTermInversionVariable).
-*/
-class VarMatchGeneratorTermSubs : public InstMatchGenerator {
-public:
-  VarMatchGeneratorTermSubs( Node var, Node subs );
-
-  /** Reset */
-  bool reset(Node eqc, QuantifiersEngine* qe) override
-  {
-    d_eq_class = eqc;
-    return true;
-  }
-  /** Get the next match. */
-  int getNextMatch(Node q,
-                   InstMatch& m,
-                   QuantifiersEngine* qe,
-                   Trigger* tparent) override;
-
- private:
-  /** variable we are matching (x in the example x+1). */
-  TNode d_var;
-  /** cache of d_var.getType() */
-  TypeNode d_var_type;
-  /** The substitution for what we match (x-1 in the example x+1). */
-  Node d_subs;
-  /** stores whether we have written a value for d_var in the current match. */
-  bool d_rm_prev;
-};
-
-/** InstMatchGeneratorMultiLinear class
-*
-* This is the default implementation of multi-triggers.
-*
-* Handling multi-triggers using this class is done by constructing a linked
-* list of InstMatchGenerator classes (see mkInstMatchGeneratorMulti), with one
-* InstMatchGeneratorMultiLinear at the head and a list of trailing
-* InstMatchGenerators.
-*
-* CVC4 employs techniques that ensure that the number of instantiations
-* is worst-case polynomial wrt the number of ground terms, where this class
-* lifts this policy to multi-triggers. In particular consider
-*
-*  multi-trigger : { f( x1 ), f( x2 ), f( x3 ), f( x4 ) }
-*
-* For this multi-trigger, we insist that for each i=1...4, and each ground term
-* t, there is at most 1 instantiation added as a result of matching
-*    ( f( x1 ), f( x2 ), f( x3 ), f( x4 ) )
-* against ground terms of the form
-*    ( s_1, s_2, s_3, s_4 ) where t = s_i for i=1,...,4.
-* Meaning we add instantiations for the multi-trigger
-* ( f( x1 ), f( x2 ), f( x3 ), f( x4 ) ) based on matching pairwise against:
-*   ( f( c_i11 ), f( c_i21 ), f( c_i31 ), f( c_i41 ) )
-*   ( f( c_i12 ), f( c_i22 ), f( c_i32 ), f( c_i42 ) )
-*   ( f( c_i13 ), f( c_i23 ), f( c_i33 ), f( c_i43 ) )
-* Where we require c_i{jk} != c_i{jl} for each i=1...4, k != l.
-*
-* For example, we disallow adding instantiations based on matching against both
-* ( f( c_1 ), f( c_2 ), f( c_4 ), f( c_6 ) ) and
-* ( f( c_1 ), f( c_3 ), f( c_5 ), f( c_7 ) )
-* against ( f( x1 ), f( x2 ), f( x3 ), f( x4 ) ), since f( c_1 ) is matched
-* against f( x1 ) twice.
-*
-* This policy can be disabled by --no-multi-trigger-linear.
-*
-*/
-class InstMatchGeneratorMultiLinear : public InstMatchGenerator {
-  friend class InstMatchGenerator;
-
- public:
-  /** Reset. */
-  bool reset(Node eqc, QuantifiersEngine* qe) override;
-  /** Get the next match. */
-  int getNextMatch(Node q,
-                   InstMatch& m,
-                   QuantifiersEngine* qe,
-                   Trigger* tparent) override;
-
- protected:
-  /** reset the children of this generator */
-  int resetChildren(QuantifiersEngine* qe);
-  /** constructor */
-  InstMatchGeneratorMultiLinear(Node q,
-                                std::vector<Node>& pats,
-                                QuantifiersEngine* qe);
-};/* class InstMatchGeneratorMulti */
-
-/** InstMatchGeneratorMulti
-*
-* This is an earlier implementation of multi-triggers
-* that is enabled by --multi-trigger-cache.
-* This generator takes the product of instantiations
-* found by single trigger matching, and does
-* not have the guarantee that the number of
-* instantiations is polynomial wrt the number of
-* ground terms.
-*/
-class InstMatchGeneratorMulti : public IMGenerator {
- public:
-  /** constructors */
-  InstMatchGeneratorMulti(Node q,
-                          std::vector<Node>& pats,
-                          QuantifiersEngine* qe);
-  /** destructor */
-  ~InstMatchGeneratorMulti() override;
-
-  /** Reset instantiation round. */
-  void resetInstantiationRound(QuantifiersEngine* qe) override;
-  /** Reset. */
-  bool reset(Node eqc, QuantifiersEngine* qe) override;
-  /** Add instantiations. */
-  int addInstantiations(Node q,
-                        QuantifiersEngine* qe,
-                        Trigger* tparent) override;
-
- private:
-  /** indexed trie */
-  typedef std::pair< std::pair< int, int >, InstMatchTrie* > IndexedTrie;
-  /** process new match
-   *
-   * Called during addInstantiations(...).
-   * Indicates we produced a match m for child fromChildIndex
-   * addedLemmas is how many instantiations we succesfully send
-   * via IMGenerator::sendInstantiation(...) calls.
-   */
-  void processNewMatch(QuantifiersEngine* qe,
-                       Trigger* tparent,
-                       InstMatch& m,
-                       int fromChildIndex,
-                       int& addedLemmas);
-  /** helper for process new match
-   * tr is the inst match trie (term index) we are currently traversing.
-   * trieIndex is depth we are in trie tr.
-   * childIndex is the index of the term in the multi trigger we are currently
-   *               processing.
-   * endChildIndex is the index of the term in the multi trigger that generated
-   *                  a new term, and hence we will end when the product
-   *                  computed by this function returns to.
-   * modEq is whether we are matching modulo equality.
-   */
-  void processNewInstantiations(QuantifiersEngine* qe,
-                                Trigger* tparent,
-                                InstMatch& m,
-                                int& addedLemmas,
-                                InstMatchTrie* tr,
-                                int trieIndex,
-                                int childIndex,
-                                int endChildIndex,
-                                bool modEq);
-  /** Map from pattern nodes to indices of variables they contain. */
-  std::map< Node, std::vector< int > > d_var_contains;
-  /** Map from variable indices to pattern nodes that contain them. */
-  std::map< int, std::vector< Node > > d_var_to_node;
-  /** quantified formula we are producing matches for */
-  Node d_quant;
-  /** children generators
-   * These are inst match generators for each term in the multi trigger.
-   */
-  std::vector< InstMatchGenerator* > d_children;
-  /** variable orderings
-   * Stores a heuristically determined variable ordering (unique
-   * variables first) for each term in the multi trigger.
-   */
-  std::map< unsigned, InstMatchTrie::ImtIndexOrder* > d_imtio;
-  /** inst match tries for each child node
-   * This data structure stores all InstMatch objects generated
-   * by matching for each term in the multi trigger.
-   */
-  std::vector< InstMatchTrieOrdered > d_children_trie;
-};/* class InstMatchGeneratorMulti */
-
-/** InstMatchGeneratorSimple class
-*
-* This is the default generator class for simple single triggers.
-* For example, { f( x, a ) }, { f( x, x ) } and { f( x, y ) } are simple single
-* triggers. In practice, around 70-90% of triggers are simple single triggers.
-*
-* Notice that simple triggers also can have an attached polarity.
-* For example, { P( x ) = false }, { f( x, y ) = a } and { ~f( a, x ) = b } are
-* simple single triggers.
-*
-* The implementation traverses the term indices in TermDatabase for adding
-* instantiations, which is more efficient than the techniques required for
-* handling non-simple single triggers.
-*
-* In contrast to other instantiation generators, it does not call
-* IMGenerator::sendInstantiation and for performance reasons instead calls
-* qe->getInstantiate()->addInstantiation(...) directly.
-*/
-class InstMatchGeneratorSimple : public IMGenerator {
- public:
-  /** constructors */
-  InstMatchGeneratorSimple(Node q, Node pat, QuantifiersEngine* qe);
-
-  /** Reset instantiation round. */
-  void resetInstantiationRound(QuantifiersEngine* qe) override;
-  /** Add instantiations. */
-  int addInstantiations(Node q,
-                        QuantifiersEngine* qe,
-                        Trigger* tparent) override;
-  /** Get active score. */
-  int getActiveScore(QuantifiersEngine* qe) override;
-
- private:
-  /** quantified formula for the trigger term */
-  Node d_quant;
-  /** the trigger term */
-  Node d_match_pattern;
-  /** equivalence class polarity information
-   *
-  * This stores the required polarity/equivalence class with this trigger.
-  * If d_eqc is non-null, we only produce matches { x->t } such that
-  * our context does not entail
-  *   ( d_match_pattern*{ x->t } = d_eqc) if d_pol = true, or
-  *   ( d_match_pattern*{ x->t } != d_eqc) if d_pol = false.
-  * where * denotes application of substitution.
-  */
-  bool d_pol;
-  Node d_eqc;
-  /** Match pattern arg types.
-   * Cached values of d_match_pattern[i].getType().
-   */
-  std::vector< TypeNode > d_match_pattern_arg_types;
-  /** The match operator d_match_pattern (see TermDb::getMatchOperator). */
-  Node d_op;
-  /** Map from child number to variable index. */
-  std::map< int, int > d_var_num;
-  /** add instantiations, helper function.
-   *
-   * m is the current match we are building,
-   * addedLemmas is the number of lemmas we have added via calls to
-   *                qe->getInstantiate()->aaddInstantiation(...),
-   * argIndex is the argument index in d_match_pattern we are currently
-   *              matching,
-   * tat is the term index we are currently traversing.
-   */
-  void addInstantiations(InstMatch& m,
-                         QuantifiersEngine* qe,
-                         int& addedLemmas,
-                         unsigned argIndex,
-                         quantifiers::TermArgTrie* tat);
-};/* class InstMatchGeneratorSimple */
-}
-}
-}
-
-#endif
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp
deleted file mode 100644 (file)
index 70dc9c4..0000000
+++ /dev/null
@@ -1,828 +0,0 @@
-/*********************                                                        */
-/*! \file inst_strategy_cbqi.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Tim King, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of counterexample-guided quantifier instantiation strategies
- **/
-#include "theory/quantifiers/inst_strategy_cbqi.h"
-
-#include "options/quantifiers_options.h"
-#include "smt/term_formula_removal.h"
-#include "theory/arith/partial_model.h"
-#include "theory/arith/theory_arith.h"
-#include "theory/arith/theory_arith_private.h"
-#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/quant_epr.h"
-#include "theory/quantifiers/quantifiers_attributes.h"
-#include "theory/quantifiers/quantifiers_rewriter.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
-#include "theory/theory_engine.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace CVC4::theory::arith;
-
-#define ARITH_INSTANTIATOR_USE_MINUS_DELTA
-
-InstStrategyCbqi::InstStrategyCbqi( QuantifiersEngine * qe )
-  : QuantifiersModule( qe ), d_added_cbqi_lemma( qe->getUserContext() ), 
-d_elim_quants( qe->getSatContext() ),
-d_nested_qe_waitlist_size( qe->getUserContext() ),
-d_nested_qe_waitlist_proc( qe->getUserContext() )
-//, d_added_inst( qe->getUserContext() )
-{
-  d_qid_count = 0;
-}
-
-bool InstStrategyCbqi::needsCheck( Theory::Effort e ) {
-  return e>=Theory::EFFORT_LAST_CALL;
-}
-
-QuantifiersModule::QEffort InstStrategyCbqi::needsModel(Theory::Effort e)
-{
-  for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
-    Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
-    if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){
-      return QEFFORT_STANDARD;
-    }
-  }
-  return QEFFORT_NONE;
-}
-
-bool InstStrategyCbqi::registerCbqiLemma( Node q ) {
-  if( !hasAddedCbqiLemma( q ) ){
-    d_added_cbqi_lemma.insert( q );
-    Trace("cbqi-debug") << "Do cbqi for " << q << std::endl;
-    //add cbqi lemma
-    //get the counterexample literal
-    Node ceLit = d_quantEngine->getTermUtil()->getCounterexampleLiteral( q );
-    Node ceBody = d_quantEngine->getTermUtil()->getInstConstantBody( q );
-    if( !ceBody.isNull() ){
-      //add counterexample lemma
-      Node lem = NodeManager::currentNM()->mkNode( OR, ceLit.negate(), ceBody.negate() );
-      //require any decision on cel to be phase=true
-      d_quantEngine->addRequirePhase( ceLit, true );
-      Debug("cbqi-debug") << "Require phase " << ceLit << " = true." << std::endl;
-      //add counterexample lemma
-      lem = Rewriter::rewrite( lem );
-      Trace("cbqi-lemma") << "Counterexample lemma : " << lem << std::endl;
-      registerCounterexampleLemma( q, lem );
-      
-      //totality lemmas for EPR
-      QuantEPR * qepr = d_quantEngine->getQuantEPR();
-      if( qepr!=NULL ){   
-        for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
-          TypeNode tn = q[0][i].getType();
-          if( tn.isSort() ){
-            if( qepr->isEPR( tn ) ){
-              //add totality lemma
-              std::map< TypeNode, std::vector< Node > >::iterator itc = qepr->d_consts.find( tn );
-              if( itc!=qepr->d_consts.end() ){
-                Assert( !itc->second.empty() );
-                Node ic = d_quantEngine->getTermUtil()->getInstantiationConstant( q, i );
-                std::vector< Node > disj;
-                for( unsigned j=0; j<itc->second.size(); j++ ){
-                  disj.push_back( ic.eqNode( itc->second[j] ) );
-                }
-                Node tlem = disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( kind::OR, disj );
-                Trace("cbqi-lemma") << "EPR totality lemma : " << tlem << std::endl;
-                d_quantEngine->getOutputChannel().lemma( tlem );
-              }else{
-                Assert( false );
-              }                  
-            }else{
-              Assert( !options::cbqiAll() );
-            }
-          }
-        }
-      }      
-      
-      //compute dependencies between quantified formulas
-      if( options::cbqiLitDepend() || options::cbqiInnermost() ){
-        std::vector< Node > ics;
-        TermUtil::computeVarContains( q, ics );
-        d_parent_quant[q].clear();
-        d_children_quant[q].clear();
-        std::vector< Node > dep;
-        for( unsigned i=0; i<ics.size(); i++ ){
-          Node qi = ics[i].getAttribute(InstConstantAttribute());
-          if( std::find( d_parent_quant[q].begin(), d_parent_quant[q].end(), qi )==d_parent_quant[q].end() ){
-            d_parent_quant[q].push_back( qi );
-            d_children_quant[qi].push_back( q );
-            Assert( hasAddedCbqiLemma( qi ) );
-            Node qicel = d_quantEngine->getTermUtil()->getCounterexampleLiteral( qi );
-            dep.push_back( qi );
-            dep.push_back( qicel );
-          }
-        }
-        if( !dep.empty() ){
-          Node dep_lemma = NodeManager::currentNM()->mkNode( kind::IMPLIES, ceLit, NodeManager::currentNM()->mkNode( kind::AND, dep ) );
-          Trace("cbqi-lemma") << "Counterexample dependency lemma : " << dep_lemma << std::endl;
-          d_quantEngine->getOutputChannel().lemma( dep_lemma );
-        }
-      }
-      
-      //must register all sub-quantifiers of counterexample lemma, register their lemmas
-      std::vector< Node > quants;
-      TermUtil::computeQuantContains( lem, quants );
-      for( unsigned i=0; i<quants.size(); i++ ){
-        if( doCbqi( quants[i] ) ){
-          registerCbqiLemma( quants[i] );
-        }
-        if( options::cbqiNestedQE() ){
-          //record these as counterexample quantifiers
-          QAttributes qa;
-          QuantAttributes::computeQuantAttributes( quants[i], qa );
-          if( !qa.d_qid_num.isNull() ){
-            d_id_to_ce_quant[ qa.d_qid_num ] = quants[i];
-            d_ce_quant_to_id[ quants[i] ] = qa.d_qid_num;
-            Trace("cbqi-nqe") << "CE quant id = " << qa.d_qid_num << " is " << quants[i] << std::endl;
-          }
-        }
-      }
-    }
-    return true;
-  }else{
-    return false;
-  }
-}
-
-void InstStrategyCbqi::reset_round( Theory::Effort effort ) {
-  d_cbqi_set_quant_inactive = false;
-  d_incomplete_check = false;
-  d_active_quant.clear();
-  //check if any cbqi lemma has not been added yet
-  for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
-    Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
-    //it is not active if it corresponds to a rewrite rule: we will process in rewrite engine
-    if( doCbqi( q ) ){
-      Assert( hasAddedCbqiLemma( q ) );
-      if( d_quantEngine->getModel()->isQuantifierActive( q ) ){
-        d_active_quant[q] = true;
-        Debug("cbqi-debug") << "Check quantified formula " << q << "..." << std::endl;
-        Node cel = d_quantEngine->getTermUtil()->getCounterexampleLiteral( q );
-        bool value;
-        if( d_quantEngine->getValuation().hasSatValue( cel, value ) ){
-          Debug("cbqi-debug") << "...CE Literal has value " << value << std::endl;
-          if( !value ){
-            if( d_quantEngine->getValuation().isDecision( cel ) ){
-              Trace("cbqi-warn") << "CBQI WARNING: Bad decision on CE Literal." << std::endl;
-            }else{
-              Trace("cbqi") << "Inactive : " << q << std::endl;
-              d_quantEngine->getModel()->setQuantifierActive( q, false );
-              d_cbqi_set_quant_inactive = true;
-              d_active_quant.erase( q );
-              d_elim_quants.insert( q );
-              Trace("cbqi-nqe") << "Inactive, waitlist proc/size = " << d_nested_qe_waitlist_proc[q].get() << "/" << d_nested_qe_waitlist_size[q].get() << std::endl;
-              //process from waitlist
-              while( d_nested_qe_waitlist_proc[q]<d_nested_qe_waitlist_size[q] ){
-                int index = d_nested_qe_waitlist_proc[q];
-                Assert( index>=0 );
-                Assert( index<(int)d_nested_qe_waitlist[q].size() );
-                Node nq = d_nested_qe_waitlist[q][index];
-                Node nqeqn = doNestedQENode( d_nested_qe_info[nq].d_q, q, nq, d_nested_qe_info[nq].d_inst_terms, d_nested_qe_info[nq].d_doVts );
-                Node dqelem = nq.eqNode( nqeqn ); 
-                Trace("cbqi-lemma") << "Delayed nested quantifier elimination lemma : " << dqelem << std::endl;
-                d_quantEngine->getOutputChannel().lemma( dqelem );
-                d_nested_qe_waitlist_proc[q] = index + 1;
-              }
-            }
-          }
-        }else{
-          Debug("cbqi-debug") << "...CE Literal does not have value " << std::endl;
-        }
-      }
-    }
-  }
-
-  //refinement: only consider innermost active quantified formulas
-  if( options::cbqiInnermost() ){
-    if( !d_children_quant.empty() && !d_active_quant.empty() ){
-      Trace("cbqi-debug") << "Find non-innermost quantifiers..." << std::endl;
-      std::vector< Node > ninner;
-      for( std::map< Node, bool >::iterator it = d_active_quant.begin(); it != d_active_quant.end(); ++it ){
-        std::map< Node, std::vector< Node > >::iterator itc = d_children_quant.find( it->first );
-        if( itc!=d_children_quant.end() ){
-          for( unsigned j=0; j<itc->second.size(); j++ ){
-            if( d_active_quant.find( itc->second[j] )!=d_active_quant.end() ){
-              Trace("cbqi-debug") << "Do not consider " << it->first << " since it is not innermost (" << itc->second[j] << std::endl;
-              ninner.push_back( it->first );
-              break;
-            }
-          }
-        }
-      } 
-      Trace("cbqi-debug") << "Found " << ninner.size() << " non-innermost." << std::endl;
-      for( unsigned i=0; i<ninner.size(); i++ ){
-        Assert( d_active_quant.find( ninner[i] )!=d_active_quant.end() );
-        d_active_quant.erase( ninner[i] );
-      }
-      Assert( !d_active_quant.empty() );
-      Trace("cbqi-debug") << "...done removing." << std::endl;
-    }
-  }
-  
-  processResetInstantiationRound( effort );
-}
-
-void InstStrategyCbqi::check(Theory::Effort e, QEffort quant_e)
-{
-  if (quant_e == QEFFORT_STANDARD)
-  {
-    Assert( !d_quantEngine->inConflict() );
-    double clSet = 0;
-    if( Trace.isOn("cbqi-engine") ){
-      clSet = double(clock())/double(CLOCKS_PER_SEC);
-      Trace("cbqi-engine") << "---Cbqi Engine Round, effort = " << e << "---" << std::endl;
-    }
-    unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting();
-    for( int ee=0; ee<=1; ee++ ){
-      //for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
-      //  Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
-      //  if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){
-      for( std::map< Node, bool >::iterator it = d_active_quant.begin(); it != d_active_quant.end(); ++it ){
-        Node q = it->first;
-        Trace("cbqi") << "CBQI : Process quantifier " << q[0] << " at effort " << ee << std::endl;
-        if( d_nested_qe.find( q )==d_nested_qe.end() ){
-          process( q, e, ee );
-          if( d_quantEngine->inConflict() ){
-            break;
-          }
-        }else{
-          Trace("cbqi-warn") << "CBQI : Cannot process already eliminated quantified formula " << q << std::endl;
-          Assert( false );
-        }
-      }
-      if( d_quantEngine->inConflict() || d_quantEngine->getNumLemmasWaiting()>lastWaiting ){
-        break;
-      }
-    }
-    if( Trace.isOn("cbqi-engine") ){
-      if( d_quantEngine->getNumLemmasWaiting()>lastWaiting ){
-        Trace("cbqi-engine") << "Added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl;
-      }
-      double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
-      Trace("cbqi-engine") << "Finished cbqi engine, time = " << (clSet2-clSet) << std::endl;
-    }
-  }
-}
-
-bool InstStrategyCbqi::checkComplete() {
-  if( ( !options::cbqiSat() && d_cbqi_set_quant_inactive ) || d_incomplete_check ){
-    return false;
-  }else{
-    return true;
-  }
-}
-
-bool InstStrategyCbqi::checkCompleteFor( Node q ) {
-  std::map< Node, int >::iterator it = d_do_cbqi.find( q );
-  if( it!=d_do_cbqi.end() ){
-    return it->second>0;
-  }else{
-    return false;
-  }
-}
-
-Node InstStrategyCbqi::getIdMarkedQuantNode( Node n, std::map< Node, Node >& visited ){
-  std::map< Node, Node >::iterator it = visited.find( n );
-  if( it==visited.end() ){
-    Node ret = n;
-    if( n.getKind()==FORALL ){
-      QAttributes qa;
-      QuantAttributes::computeQuantAttributes( n, qa );
-      if( qa.d_qid_num.isNull() ){
-        std::vector< Node > rc;
-        rc.push_back( n[0] );
-        rc.push_back( getIdMarkedQuantNode( n[1], visited ) );
-        Node avar = NodeManager::currentNM()->mkSkolem( "id", NodeManager::currentNM()->booleanType() );
-        QuantIdNumAttribute ida;
-        avar.setAttribute(ida,d_qid_count);
-        d_qid_count++;
-        std::vector< Node > iplc;
-        iplc.push_back( NodeManager::currentNM()->mkNode( INST_ATTRIBUTE, avar ) );
-        if( n.getNumChildren()==3 ){
-          for( unsigned i=0; i<n[2].getNumChildren(); i++ ){
-            iplc.push_back( n[2][i] );
-          }
-        }
-        rc.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, iplc ) );
-        ret = NodeManager::currentNM()->mkNode( FORALL, rc );
-      }
-    }else if( n.getNumChildren()>0 ){
-      std::vector< Node > children;
-      if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
-        children.push_back( n.getOperator() );
-      }
-      bool childChanged = false;
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        Node nc = getIdMarkedQuantNode( n[i], visited );
-        childChanged = childChanged || nc!=n[i];
-        children.push_back( nc );
-      }
-      if( childChanged ){
-        ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
-      }
-    }
-    visited[n] = ret;
-    return ret;
-  }else{
-    return it->second;
-  }
-}
-
-void InstStrategyCbqi::preRegisterQuantifier( Node q ) {
-  if( d_quantEngine->getOwner( q )==NULL && doCbqi( q ) ){
-    if( d_do_cbqi[q]==2 ){
-      //take full ownership of the quantified formula
-      d_quantEngine->setOwner( q, this );
-      
-      //mark all nested quantifiers with id
-      if( options::cbqiNestedQE() ){
-        std::map< Node, Node > visited;
-        Node mq = getIdMarkedQuantNode( q[1], visited );
-        if( mq!=q[1] ){
-          //do not do cbqi
-          d_do_cbqi[q] = false;
-          //instead do reduction
-          std::vector< Node > qqc;
-          qqc.push_back( q[0] );
-          qqc.push_back( mq );
-          if( q.getNumChildren()==3 ){
-            qqc.push_back( q[2] );
-          }
-          Node qq = NodeManager::currentNM()->mkNode( FORALL, qqc );
-          Node mlem = NodeManager::currentNM()->mkNode( IMPLIES, q, qq );
-          Trace("cbqi-lemma") << "Mark quant id lemma : " << mlem << std::endl;
-          d_quantEngine->getOutputChannel().lemma( mlem );
-        }
-      }
-    }
-  }
-}
-
-void InstStrategyCbqi::registerQuantifier( Node q ) {
-  if( doCbqi( q ) ){
-    if( registerCbqiLemma( q ) ){
-      Trace("cbqi") << "Registered cbqi lemma for quantifier : " << q << std::endl;
-    }
-  }
-}
-
-Node InstStrategyCbqi::doNestedQENode( Node q, Node ceq, Node n, std::vector< Node >& inst_terms, bool doVts ) {
-  // there is a nested quantified formula (forall y. nq[y,x]) such that 
-  //    q is (forall y. nq[y,t]) for ground terms t,
-  //    ceq is (forall y. nq[y,e]) for CE variables e.
-  // we call this function when we know (forall y. nq[y,e]) is equivalent to quantifier-free formula C[e].
-  // in this case, q is equivalent to the quantifier-free formula C[t].
-  if( d_nested_qe.find( ceq )==d_nested_qe.end() ){
-    d_nested_qe[ceq] = d_quantEngine->getInstantiatedConjunction( ceq );
-    Trace("cbqi-nqe") << "CE quantifier elimination : " << std::endl;
-    Trace("cbqi-nqe") << "  " << ceq << std::endl; 
-    Trace("cbqi-nqe") << "  " << d_nested_qe[ceq] << std::endl;
-    //should not contain quantifiers
-    Assert( !QuantifiersRewriter::containsQuantifiers( d_nested_qe[ceq] ) );
-  }
-  Assert( d_quantEngine->getTermUtil()->d_inst_constants[q].size()==inst_terms.size() );
-  //replace inst constants with instantiation
-  Node ret = d_nested_qe[ceq].substitute( d_quantEngine->getTermUtil()->d_inst_constants[q].begin(),
-                                          d_quantEngine->getTermUtil()->d_inst_constants[q].end(),
-                                          inst_terms.begin(), inst_terms.end() );
-  if( doVts ){
-    //do virtual term substitution
-    ret = Rewriter::rewrite( ret );
-    ret = d_quantEngine->getTermUtil()->rewriteVtsSymbols( ret );
-  }
-  Trace("cbqi-nqe") << "Nested quantifier elimination: " << std::endl;
-  Trace("cbqi-nqe") << "  " << n << std::endl; 
-  Trace("cbqi-nqe") << "  " << ret << std::endl;
-  return ret;
-}
-
-Node InstStrategyCbqi::doNestedQERec( Node q, Node n, std::map< Node, Node >& visited, std::vector< Node >& inst_terms, bool doVts ) {
-  if( visited.find( n )==visited.end() ){
-    Node ret = n;
-    if( n.getKind()==FORALL ){
-      QAttributes qa;
-      QuantAttributes::computeQuantAttributes( n, qa );
-      if( !qa.d_qid_num.isNull() ){
-        //if it has an id, check whether we have done quantifier elimination for this id
-        std::map< Node, Node >::iterator it = d_id_to_ce_quant.find( qa.d_qid_num );
-        if( it!=d_id_to_ce_quant.end() ){
-          Node ceq = it->second;
-          bool doNestedQe = d_elim_quants.contains( ceq );
-          if( doNestedQe ){
-            ret = doNestedQENode( q, ceq, n, inst_terms, doVts );
-          }else{
-            Trace("cbqi-nqe") << "Add to nested qe waitlist : " << std::endl;
-            Node nr = Rewriter::rewrite( n );
-            Trace("cbqi-nqe") << "  " << ceq << std::endl;
-            Trace("cbqi-nqe") << "  " << nr << std::endl;
-            int wlsize = d_nested_qe_waitlist_size[ceq] + 1;
-            d_nested_qe_waitlist_size[ceq] = wlsize;
-            if( wlsize<(int)d_nested_qe_waitlist[ceq].size() ){
-              d_nested_qe_waitlist[ceq][wlsize] = nr;
-            }else{
-              d_nested_qe_waitlist[ceq].push_back( nr );
-            }
-            d_nested_qe_info[nr].d_q = q;
-            d_nested_qe_info[nr].d_inst_terms.clear();
-            d_nested_qe_info[nr].d_inst_terms.insert( d_nested_qe_info[nr].d_inst_terms.end(), inst_terms.begin(), inst_terms.end() );
-            d_nested_qe_info[nr].d_doVts = doVts;
-            //TODO: ensure this holds by restricting prenex when cbqiNestedQe is true.
-            Assert( !options::cbqiInnermost() );
-          }
-        } 
-      } 
-    }else if( n.getNumChildren()>0 ){
-      std::vector< Node > children;
-      if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
-        children.push_back( n.getOperator() );
-      }
-      bool childChanged = false;
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        Node nc = doNestedQERec( q, n[i], visited, inst_terms, doVts );
-        childChanged = childChanged || nc!=n[i];
-        children.push_back( nc );
-      }
-      if( childChanged ){
-        ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
-      }
-    }
-    visited[n] = ret;
-    return ret;
-  }else{
-    return n;
-  }  
-}
-
-Node InstStrategyCbqi::doNestedQE( Node q, std::vector< Node >& inst_terms, Node lem, bool doVts ) {
-  std::map< Node, Node > visited;
-  return doNestedQERec( q, lem, visited, inst_terms, doVts );
-}
-
-void InstStrategyCbqi::registerCounterexampleLemma( Node q, Node lem ){
-  Trace("cbqi-debug") << "Counterexample lemma  : " << lem << std::endl;
-  d_quantEngine->addLemma( lem, false );
-}
-
-bool InstStrategyCbqi::hasNonCbqiOperator( Node n, std::map< Node, bool >& visited ){
-  if( visited.find( n )==visited.end() ){
-    visited[n] = true;
-    if( n.getKind()!=BOUND_VARIABLE && TermUtil::hasBoundVarAttr( n ) ){
-      if( !inst::Trigger::isCbqiKind( n.getKind() ) ){
-        Trace("cbqi-debug2") << "Non-cbqi kind : " << n.getKind() << " in " << n  << std::endl;
-        return true;
-      }else if( n.getKind()==MULT && ( n.getNumChildren()!=2 || !n[0].isConst() ) ){
-        Trace("cbqi-debug2") << "Non-linear arithmetic : " << n << std::endl;
-        return true;
-      }else if( n.getKind()==FORALL ){
-        return hasNonCbqiOperator( n[1], visited );
-      }else{
-        for( unsigned i=0; i<n.getNumChildren(); i++ ){
-          if( hasNonCbqiOperator( n[i], visited ) ){
-            return true;
-          }
-        }
-      }
-    }
-  }
-  return false;
-}
-
-// -1 : not cbqi sort, 0 : cbqi sort, 1 : cbqi sort regardless of quantifier body
-int InstStrategyCbqi::isCbqiSort( TypeNode tn, std::map< TypeNode, int >& visited ) {
-  std::map< TypeNode, int >::iterator itv = visited.find( tn );
-  if( itv==visited.end() ){
-    visited[tn] = 0;
-    int ret = -1;
-    if( tn.isInteger() || tn.isReal() || tn.isBoolean() || tn.isBitVector() ){
-      ret = 0;
-    }else if( tn.isDatatype() ){
-      ret = 1;
-      const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
-      for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-        for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
-          TypeNode crange = TypeNode::fromType( ((SelectorType)dt[i][j].getType()).getRangeType() );
-          int cret = isCbqiSort( crange, visited );
-          if( cret==-1 ){
-            visited[tn] = -1;
-            return -1;
-          }else if( cret<ret ){
-            ret = cret;
-          }
-        }
-      }
-    }else if( tn.isSort() ){
-      QuantEPR * qepr = d_quantEngine->getQuantEPR();
-      if( qepr!=NULL ){
-        ret = qepr->isEPR( tn ) ? 1 : -1;
-      }
-    }
-    visited[tn] = ret;
-    return ret;
-  }else{
-    return itv->second;
-  }
-}
-
-int InstStrategyCbqi::hasNonCbqiVariable( Node q ){
-  int hmin = 1;
-  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
-    TypeNode tn = q[0][i].getType();
-    std::map< TypeNode, int > visited;
-    int handled = isCbqiSort( tn, visited );
-    if( handled==-1 ){
-      return -1;
-    }else if( handled<hmin ){
-      hmin = handled;
-    }
-  }
-  return hmin;
-}
-
-bool InstStrategyCbqi::doCbqi( Node q ){
-  std::map< Node, int >::iterator it = d_do_cbqi.find( q );
-  if( it==d_do_cbqi.end() ){
-    int ret = 2;
-    if( !d_quantEngine->getQuantAttributes()->isQuantElim( q ) ){
-      Assert( !d_quantEngine->getQuantAttributes()->isQuantElimPartial( q ) );
-      //if has an instantiation pattern, don't do it
-      if( q.getNumChildren()==3 && options::eMatching() && options::userPatternsQuant()!=USER_PAT_MODE_IGNORE ){
-        for( unsigned i=0; i<q[2].getNumChildren(); i++ ){
-          if( q[2][i].getKind()==INST_PATTERN ){
-            ret = 0;
-          }
-        }
-      }
-      if( d_quantEngine->getQuantAttributes()->isSygus( q ) ){
-        ret = 0;
-      }
-      if( ret!=0 ){
-        //if quantifier has a non-handled variable, then do not use cbqi
-        //if quantifier has an APPLY_UF term, then do not use cbqi unless EPR
-        int ncbqiv = hasNonCbqiVariable( q );
-        if( ncbqiv==0 || ncbqiv==1 ){
-          std::map< Node, bool > visited;
-          if( hasNonCbqiOperator( q[1], visited ) ){
-            if( ncbqiv==1 ){
-              //all variables are fully handled, this implies this will be handlable regardless of body (e.g. for EPR)
-              //  so, try but not exclusively
-              ret = 1;
-            }else{
-              //cannot be handled
-              ret = 0;
-            }
-          }
-        }else{
-          // unhandled variable type
-          ret = 0;
-        }
-        if( ret==0 && options::cbqiAll() ){
-          //try but not exclusively
-          ret = 1;
-        }
-      }
-    }
-    Trace("cbqi-quant") << "doCbqi " << q << " returned " << ret << std::endl;
-    d_do_cbqi[q] = ret;
-    return ret!=0;
-  }else{
-    return it->second!=0;
-  }
-}
-
-Node InstStrategyCbqi::getNextDecisionRequestProc( Node q, std::map< Node, bool >& proc ) {
-  if( proc.find( q )==proc.end() ){
-    proc[q] = true;
-    //first check children
-    std::map< Node, std::vector< Node > >::iterator itc = d_children_quant.find( q );
-    if( itc!=d_children_quant.end() ){
-      for( unsigned j=0; j<itc->second.size(); j++ ){
-        Node d = getNextDecisionRequestProc( itc->second[j], proc );
-        if( !d.isNull() ){
-          return d;
-        }
-      }
-    }
-    //then check self
-    if( hasAddedCbqiLemma( q ) ){
-      Node cel = d_quantEngine->getTermUtil()->getCounterexampleLiteral( q );
-      bool value;
-      if( !d_quantEngine->getValuation().hasSatValue( cel, value ) ){
-        Trace("cbqi-dec") << "CBQI: get next decision " << cel << std::endl;
-        return cel;
-      }
-    }    
-  }
-  return Node::null(); 
-}
-
-Node InstStrategyCbqi::getNextDecisionRequest( unsigned& priority ){
-  std::map< Node, bool > proc;
-  //for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
-  //  Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
-  for( NodeSet::const_iterator it = d_added_cbqi_lemma.begin(); it != d_added_cbqi_lemma.end(); ++it ){
-    Node q = *it;
-    Node d = getNextDecisionRequestProc( q, proc );
-    if( !d.isNull() ){
-      priority = 0;
-      return d;
-    }
-  }
-  return Node::null();
-}
-
-
-
-//new implementation
-
-bool CegqiOutputInstStrategy::doAddInstantiation( std::vector< Node >& subs ) {
-  return d_out->doAddInstantiation( subs );
-}
-
-bool CegqiOutputInstStrategy::isEligibleForInstantiation( Node n ) {
-  return d_out->isEligibleForInstantiation( n );
-}
-
-bool CegqiOutputInstStrategy::addLemma( Node lem ) {
-  return d_out->addLemma( lem );
-}
-
-
-InstStrategyCegqi::InstStrategyCegqi( QuantifiersEngine * qe )
-  : InstStrategyCbqi( qe ) {
-  d_out = new CegqiOutputInstStrategy( this );
-  d_small_const = NodeManager::currentNM()->mkConst( Rational(1)/Rational(1000000) );
-  d_check_vts_lemma_lc = false;
-}
-
-InstStrategyCegqi::~InstStrategyCegqi()
-{
-  delete d_out;
-
-  for(std::map< Node, CegInstantiator * >::iterator i = d_cinst.begin(),
-          iend = d_cinst.end(); i != iend; ++i) {
-    CegInstantiator * instantiator = (*i).second;
-    delete instantiator;
-  }
-  d_cinst.clear();
-}
-
-void InstStrategyCegqi::processResetInstantiationRound( Theory::Effort effort ) {
-  d_check_vts_lemma_lc = false;
-}
-
-void InstStrategyCegqi::process( Node q, Theory::Effort effort, int e ) {
-  if( e==0 ){
-    CegInstantiator * cinst = getInstantiator( q );
-    Trace("inst-alg") << "-> Run cegqi for " << q << std::endl;
-    d_curr_quant = q;
-    if( !cinst->check() ){
-      d_incomplete_check = true;
-      d_check_vts_lemma_lc = true;
-    }
-    d_curr_quant = Node::null();
-  }else if( e==1 ){
-    //minimize the free delta heuristically on demand
-    if( d_check_vts_lemma_lc ){
-      Trace("inst-alg") << "-> Minimize delta heuristic, for " << q << std::endl;
-      d_check_vts_lemma_lc = false;
-      d_small_const = NodeManager::currentNM()->mkNode( MULT, d_small_const, d_small_const );
-      d_small_const = Rewriter::rewrite( d_small_const );
-      //heuristic for now, until we know how to do nested quantification
-      Node delta = d_quantEngine->getTermUtil()->getVtsDelta( true, false );
-      if( !delta.isNull() ){
-        Trace("quant-vts-debug") << "Delta lemma for " << d_small_const << std::endl;
-        Node delta_lem_ub = NodeManager::currentNM()->mkNode( LT, delta, d_small_const );
-        d_quantEngine->getOutputChannel().lemma( delta_lem_ub );
-      }
-      std::vector< Node > inf;
-      d_quantEngine->getTermUtil()->getVtsTerms( inf, true, false, false );
-      for( unsigned i=0; i<inf.size(); i++ ){
-        Trace("quant-vts-debug") << "Infinity lemma for " << inf[i] << " " << d_small_const << std::endl;
-        Node inf_lem_lb = NodeManager::currentNM()->mkNode( GT, inf[i], NodeManager::currentNM()->mkConst( Rational(1)/d_small_const.getConst<Rational>() ) );
-        d_quantEngine->getOutputChannel().lemma( inf_lem_lb );
-      }
-    }
-  }
-}
-
-bool InstStrategyCegqi::doAddInstantiation( std::vector< Node >& subs ) {
-  Assert( !d_curr_quant.isNull() );
-  //if doing partial quantifier elimination, record the instantiation and set the incomplete flag instead of sending instantiation lemma
-  if( d_quantEngine->getQuantAttributes()->isQuantElimPartial( d_curr_quant ) ){
-    d_cbqi_set_quant_inactive = true;
-    d_incomplete_check = true;
-    d_quantEngine->getInstantiate()->recordInstantiation(
-        d_curr_quant, subs, false, false);
-    return true;
-  }else{
-    //check if we need virtual term substitution (if used delta or infinity)
-    bool used_vts = d_quantEngine->getTermUtil()->containsVtsTerm( subs, false );
-    if (d_quantEngine->getInstantiate()->addInstantiation(
-            d_curr_quant, subs, false, false, used_vts))
-    {
-      ++(d_quantEngine->d_statistics.d_instantiations_cbqi);
-      //d_added_inst.insert( d_curr_quant );
-      return true;
-    }else{
-      //this should never happen for monotonic selection strategies
-      Trace("cbqi-warn") << "WARNING: Existing instantiation" << std::endl;
-      return false;
-    }
-  }
-}
-
-bool InstStrategyCegqi::addLemma( Node lem ) {
-  return d_quantEngine->addLemma( lem );
-}
-
-bool InstStrategyCegqi::isEligibleForInstantiation( Node n ) {
-  if( n.getKind()==INST_CONSTANT || n.getKind()==SKOLEM ){
-    if( n.getAttribute(VirtualTermSkolemAttribute()) ){
-      // virtual terms are allowed
-      return true;
-    }else{
-      TypeNode tn = n.getType();
-      if( tn.isSort() ){
-        QuantEPR * qepr = d_quantEngine->getQuantEPR();
-        if( qepr!=NULL ){
-          //legal if in the finite set of constants of type tn
-          if( qepr->isEPRConstant( tn, n ) ){
-            return true;
-          }
-        }
-      }
-      //only legal if current quantified formula contains n
-      return TermUtil::containsTerm( d_curr_quant, n );
-    }
-  }else{
-    return true;
-  }
-}
-
-CegInstantiator * InstStrategyCegqi::getInstantiator( Node q ) {
-  std::map< Node, CegInstantiator * >::iterator it = d_cinst.find( q );
-  if( it==d_cinst.end() ){
-    CegInstantiator * cinst = new CegInstantiator( d_quantEngine, d_out, true, true );
-    d_cinst[q] = cinst;
-    return cinst;
-  }else{
-   return it->second;
-  }
-}
-
-void InstStrategyCegqi::registerQuantifier( Node q ) {
-  if( doCbqi( q ) ){
-    // get the instantiator  
-    if( options::cbqiPreRegInst() ){
-      getInstantiator( q );
-    }
-    // register the cbqi lemma
-    if( registerCbqiLemma( q ) ){
-      Trace("cbqi") << "Registered cbqi lemma for quantifier : " << q << std::endl;
-    }
-  }
-}
-
-void InstStrategyCegqi::registerCounterexampleLemma( Node q, Node lem ) {
-  //must register with the instantiator
-  //must explicitly remove ITEs so that we record dependencies
-  std::vector< Node > ce_vars;
-  for( unsigned i=0; i<d_quantEngine->getTermUtil()->getNumInstantiationConstants( q ); i++ ){
-    ce_vars.push_back( d_quantEngine->getTermUtil()->getInstantiationConstant( q, i ) );
-  }
-  std::vector< Node > lems;
-  lems.push_back( lem );
-  CegInstantiator * cinst = getInstantiator( q );
-  cinst->registerCounterexampleLemma( lems, ce_vars );
-  for( unsigned i=0; i<lems.size(); i++ ){
-    Trace("cbqi-debug") << "Counterexample lemma " << i << " : " << lems[i] << std::endl;
-    d_quantEngine->addLemma( lems[i], false );
-  }
-}
-
-void InstStrategyCegqi::presolve() {
-  if( options::cbqiPreRegInst() ){
-    for( std::map< Node, CegInstantiator * >::iterator it = d_cinst.begin(); it != d_cinst.end(); ++it ){
-      Trace("cbqi-presolve") << "Presolve " << it->first << std::endl;
-      it->second->presolve( it->first );
-    }
-  }
-}
-
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h
deleted file mode 100644 (file)
index 26591c6..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*********************                                                        */
-/*! \file inst_strategy_cbqi.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Morgan Deters, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief counterexample-guided quantifier instantiation
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__INST_STRATEGY_CBQI_H
-#define __CVC4__INST_STRATEGY_CBQI_H
-
-#include "theory/arith/arithvar.h"
-#include "theory/quantifiers/ceg_instantiator.h"
-#include "theory/quantifiers/instantiation_engine.h"
-#include "util/statistics_registry.h"
-
-namespace CVC4 {
-namespace theory {
-
-namespace arith {
-  class TheoryArith;
-}
-
-namespace quantifiers {
-
-class InstStrategyCbqi : public QuantifiersModule {
-  typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
-  typedef context::CDHashMap< Node, int, NodeHashFunction> NodeIntMap;
-
- protected:
-  bool d_cbqi_set_quant_inactive;
-  bool d_incomplete_check;
-  /** whether we have added cbqi lemma */
-  NodeSet d_added_cbqi_lemma;
-  /** whether we have added cbqi lemma */
-  NodeSet d_elim_quants;
-  /** parent guards */
-  std::map< Node, std::vector< Node > > d_parent_quant;
-  std::map< Node, std::vector< Node > > d_children_quant;
-  std::map< Node, bool > d_active_quant;
-  /** whether we have instantiated quantified formulas */
-  //NodeSet d_added_inst;
-  /** whether to do cbqi for this quantified formula 0 : no, 2 : yes, 1 : yes but not exclusively, -1 : heuristically */
-  std::map< Node, int > d_do_cbqi;
-  /** register ce lemma */
-  bool registerCbqiLemma( Node q );
-  virtual void registerCounterexampleLemma( Node q, Node lem );
-  /** has added cbqi lemma */
-  bool hasAddedCbqiLemma( Node q ) { return d_added_cbqi_lemma.find( q )!=d_added_cbqi_lemma.end(); }
-  /** helper functions */
-  int hasNonCbqiVariable( Node q );
-  bool hasNonCbqiOperator( Node n, std::map< Node, bool >& visited );
-  int isCbqiSort( TypeNode tn, std::map< TypeNode, int >& visited );
-  /** get next decision request with dependency checking */
-  Node getNextDecisionRequestProc( Node q, std::map< Node, bool >& proc );  
-  /** process functions */
-  virtual void processResetInstantiationRound( Theory::Effort effort ) = 0;
-  virtual void process( Node q, Theory::Effort effort, int e ) = 0;
-
- protected:
-  //for identification
-  uint64_t d_qid_count;
-  //nested qe map
-  std::map< Node, Node > d_nested_qe;
-  //mark ids on quantifiers 
-  Node getIdMarkedQuantNode( Node n, std::map< Node, Node >& visited );
-  // id to ce quant
-  std::map< Node, Node > d_id_to_ce_quant;
-  std::map< Node, Node > d_ce_quant_to_id;
-  //do nested quantifier elimination recursive
-  Node doNestedQENode( Node q, Node ceq, Node n, std::vector< Node >& inst_terms, bool doVts );
-  Node doNestedQERec( Node q, Node n, std::map< Node, Node >& visited, std::vector< Node >& inst_terms, bool doVts );
-  //elimination information (for delayed elimination)
-  class NestedQEInfo {
-  public:
-    NestedQEInfo() : d_doVts(false){}
-    ~NestedQEInfo(){}
-    Node d_q;
-    std::vector< Node > d_inst_terms;
-    bool d_doVts;
-  };
-  std::map< Node, NestedQEInfo > d_nested_qe_info;
-  NodeIntMap d_nested_qe_waitlist_size;
-  NodeIntMap d_nested_qe_waitlist_proc;
-  std::map< Node, std::vector< Node > > d_nested_qe_waitlist;
-
- public:
-  //do nested quantifier elimination
-  Node doNestedQE( Node q, std::vector< Node >& inst_terms, Node lem, bool doVts );
-
- public:
-  InstStrategyCbqi( QuantifiersEngine * qe );
-
-  /** whether to do CBQI for quantifier q */
-  bool doCbqi( Node q );
-  /** process functions */
-  bool needsCheck( Theory::Effort e );
-  QEffort needsModel(Theory::Effort e);
-  void reset_round( Theory::Effort e );
-  void check(Theory::Effort e, QEffort quant_e);
-  bool checkComplete();
-  bool checkCompleteFor( Node q );
-  void preRegisterQuantifier( Node q );
-  void registerQuantifier( Node q );
-  /** get next decision request */
-  Node getNextDecisionRequest( unsigned& priority );
-};
-
-//generalized counterexample guided quantifier instantiation
-
-class InstStrategyCegqi;
-
-class CegqiOutputInstStrategy : public CegqiOutput {
-public:
-  CegqiOutputInstStrategy( InstStrategyCegqi * out ) : d_out( out ){}
-  InstStrategyCegqi * d_out;
-  bool doAddInstantiation( std::vector< Node >& subs );
-  bool isEligibleForInstantiation( Node n );
-  bool addLemma( Node lem );
-};
-
-class InstStrategyCegqi : public InstStrategyCbqi {
- protected:
-  CegqiOutputInstStrategy * d_out;
-  std::map< Node, CegInstantiator * > d_cinst;
-  Node d_small_const;
-  Node d_curr_quant;
-  bool d_check_vts_lemma_lc;
-  /** process functions */
-  void processResetInstantiationRound(Theory::Effort effort) override;
-  void process(Node f, Theory::Effort effort, int e) override;
-  /** register ce lemma */
-  void registerCounterexampleLemma(Node q, Node lem) override;
-
- public:
-  InstStrategyCegqi( QuantifiersEngine * qe );
-  ~InstStrategyCegqi() override;
-
-  bool doAddInstantiation( std::vector< Node >& subs );
-  bool isEligibleForInstantiation( Node n );
-  bool addLemma( Node lem );
-  /** identify */
-  std::string identify() const override { return std::string("Cegqi"); }
-
-  //get instantiator for quantifier
-  CegInstantiator * getInstantiator( Node q );
-  //register quantifier
-  void registerQuantifier(Node q) override;
-  //presolve
-  void presolve() override;
-};
-
-}
-}
-}
-
-#endif
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp
deleted file mode 100644 (file)
index c39df58..0000000
+++ /dev/null
@@ -1,613 +0,0 @@
-/*********************                                                        */
-/*! \file inst_strategy_e_matching.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Morgan Deters, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of e matching instantiation strategies
- **/
-
-#include "theory/quantifiers/inst_strategy_e_matching.h"
-#include "theory/quantifiers/inst_match_generator.h"
-#include "theory/quantifiers/quant_relevance.h"
-#include "theory/quantifiers/quantifiers_attributes.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/theory_engine.h"
-
-using namespace std;
-
-namespace CVC4 {
-
-using namespace kind;
-using namespace context;
-
-namespace theory {
-
-using namespace inst;
-
-namespace quantifiers {
-
-//priority levels :
-//1 : user patterns (when user-pat!={resort,ignore}), auto-gen patterns (for non-user pattern quantifiers, or when user-pat={resort,ignore})
-//2 : user patterns (when user-pat=resort), auto gen patterns (for user pattern quantifiers when user-pat=use)
-
-// user-pat=interleave alternates between use and resort
-
-struct sortQuantifiersForSymbol {
-  QuantifiersEngine* d_qe;
-  std::map< Node, Node > d_op_map;
-  bool operator() (Node i, Node j) {
-    int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_op_map[i] );
-    int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_op_map[j] );
-    if( nqfsi<nqfsj ){
-      return true;
-    }else if( nqfsi>nqfsj ){
-      return false;
-    }else{
-      return false;
-    }
-  }
-};
-
-struct sortTriggers {
-  bool operator() (Node i, Node j) {
-    int wi = Trigger::getTriggerWeight( i );
-    int wj = Trigger::getTriggerWeight( j );
-    if( wi==wj ){
-      return i<j;
-    }else{
-      return wi<wj;
-    }
-  }
-};
-
-void InstStrategyUserPatterns::processResetInstantiationRound( Theory::Effort effort ){
-  Trace("inst-alg-debug") << "reset user triggers" << std::endl;
-  //reset triggers
-  for( std::map< Node, std::vector< Trigger* > >::iterator it = d_user_gen.begin(); it != d_user_gen.end(); ++it ){
-    for( unsigned i=0; i<it->second.size(); i++ ){
-      it->second[i]->resetInstantiationRound();
-      it->second[i]->reset( Node::null() );
-    }
-  }
-  Trace("inst-alg-debug") << "done reset user triggers" << std::endl;
-}
-
-int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){
-  if( e==0 ){
-    return STATUS_UNFINISHED;
-  }else{
-    int peffort = d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ? 2 : 1;
-    if( e<peffort ){
-      return STATUS_UNFINISHED;
-    }else if( e==peffort ){
-      d_counter[f]++;
-
-      Trace("inst-alg") << "-> User-provided instantiate " << f << "..." << std::endl;
-      if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT  ){
-        for( unsigned i=0; i<d_user_gen_wait[f].size(); i++ ){
-          Trigger * t = Trigger::mkTrigger( d_quantEngine, f, d_user_gen_wait[f][i], true, Trigger::TR_RETURN_NULL );
-          if( t ){
-            d_user_gen[f].push_back( t );
-          }
-        }
-        d_user_gen_wait[f].clear();
-      }
-
-      for( unsigned i=0; i<d_user_gen[f].size(); i++ ){
-        bool processTrigger = true;
-        if( processTrigger ){
-          Trace("process-trigger") << "  Process (user) ";
-          d_user_gen[f][i]->debugPrint("process-trigger");
-          Trace("process-trigger") << "..." << std::endl;
-          int numInst = d_user_gen[f][i]->addInstantiations();
-          Trace("process-trigger") << "  Done, numInst = " << numInst << "." << std::endl;
-          d_quantEngine->d_statistics.d_instantiations_user_patterns += numInst;
-          if( d_user_gen[f][i]->isMultiTrigger() ){
-            d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst;
-          }
-          if( d_quantEngine->inConflict() ){
-            break;
-          }
-        }
-      }
-    }
-  }
-  return STATUS_UNKNOWN;
-}
-
-void InstStrategyUserPatterns::addUserPattern( Node q, Node pat ){
-  Assert( pat.getKind()==INST_PATTERN );
-  //add to generators
-  bool usable = true;
-  std::vector< Node > nodes;
-  for( unsigned i=0; i<pat.getNumChildren(); i++ ){
-    Node pat_use = Trigger::getIsUsableTrigger( pat[i], q );
-    if( pat_use.isNull() ){
-      Trace("trigger-warn") << "User-provided trigger is not usable : " << pat << " because of " << pat[i] << std::endl;
-      usable = false;
-      break;
-    }else{
-      nodes.push_back( pat_use );
-    }
-  }
-  if( usable ){
-    Trace("user-pat") << "Add user pattern: " << pat << " for " << q << std::endl;
-    //check match option
-    if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ){
-      d_user_gen_wait[q].push_back( nodes );
-    }else{
-      Trigger * t = Trigger::mkTrigger( d_quantEngine, q, nodes, true, Trigger::TR_MAKE_NEW );
-      if( t ){
-        d_user_gen[q].push_back( t );
-      }else{
-        Trace("trigger-warn") << "Failed to construct trigger : " << pat << " due to variable mismatch" << std::endl;
-      }
-    }
-  }
-}
-
-InstStrategyAutoGenTriggers::InstStrategyAutoGenTriggers( QuantifiersEngine* qe ) : InstStrategy( qe ){
-  //how to select trigger terms
-  d_tr_strategy = options::triggerSelMode();
-  //whether to select new triggers during the search
-  if( options::incrementTriggers() ){
-    d_regenerate_frequency = 3;
-    d_regenerate = true;
-  }else{
-    d_regenerate_frequency = 1;
-    d_regenerate = false;
-  }
-}
-
-void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){
-  Trace("inst-alg-debug") << "reset auto-gen triggers" << std::endl;
-  //reset triggers
-  for( unsigned r=0; r<2; r++ ){
-    for( std::map< Node, std::map< Trigger*, bool > >::iterator it = d_auto_gen_trigger[r].begin(); it != d_auto_gen_trigger[r].end(); ++it ){
-      for( std::map< Trigger*, bool >::iterator itt = it->second.begin(); itt != it->second.end(); ++itt ){
-        itt->first->resetInstantiationRound();
-        itt->first->reset( Node::null() );
-      }
-    }
-  }
-  d_processed_trigger.clear();
-  Trace("inst-alg-debug") << "done reset auto-gen triggers" << std::endl;
-}
-
-int InstStrategyAutoGenTriggers::process( Node f, Theory::Effort effort, int e ){
-  UserPatMode upMode = d_quantEngine->getInstUserPatMode();
-  if( hasUserPatterns( f ) && upMode==USER_PAT_MODE_TRUST ){
-    return STATUS_UNKNOWN;
-  }else{
-    int peffort = ( hasUserPatterns( f ) && upMode!=USER_PAT_MODE_IGNORE && upMode!=USER_PAT_MODE_RESORT ) ? 2 : 1;
-    if( e<peffort ){
-      return STATUS_UNFINISHED;
-    }else{
-      Trace("inst-alg") << "-> Auto-gen instantiate " << f << "..." << std::endl;
-      bool gen = false;
-      if( e==peffort ){
-        if( d_counter.find( f )==d_counter.end() ){
-          d_counter[f] = 0;
-          gen = true;
-        }else{
-          d_counter[f]++;
-          gen = d_regenerate && d_counter[f]%d_regenerate_frequency==0;
-        }
-      }else{
-        gen = true;
-      }
-      if( gen ){
-        generateTriggers( f );
-        if( d_counter[f]==0 && d_auto_gen_trigger[0][f].empty() && d_auto_gen_trigger[1][f].empty() && f.getNumChildren()==2 ){
-          Trace("trigger-warn") << "Could not find trigger for " << f << std::endl;
-        }
-      }
-
-      //if( e==4 ){
-      //  d_processed_trigger.clear();
-      //  d_quantEngine->getEqualityQuery()->setLiberal( true );
-      //}
-      if( options::triggerActiveSelMode()!=TRIGGER_ACTIVE_SEL_ALL ){
-        int max_score = -1;
-        Trigger * max_trigger = NULL;
-        for( std::map< Trigger*, bool >::iterator itt = d_auto_gen_trigger[0][f].begin(); itt != d_auto_gen_trigger[0][f].end(); ++itt ){
-          int score = itt->first->getActiveScore();
-          if( options::triggerActiveSelMode()==TRIGGER_ACTIVE_SEL_MIN ){
-            if( score>=0 && ( score<max_score || max_score<0 ) ){
-              max_score = score;
-              max_trigger = itt->first;
-            } 
-          }else{
-            if( score>max_score ){
-              max_score = score;
-              max_trigger = itt->first;
-            }
-          }
-          d_auto_gen_trigger[0][f][itt->first] = false;
-        }
-        if( max_trigger!=NULL ){
-          d_auto_gen_trigger[0][f][max_trigger] = true;
-        }
-      }
-      
-      bool hasInst = false;
-      for( unsigned r=0; r<2; r++ ){
-        for( std::map< Trigger*, bool >::iterator itt = d_auto_gen_trigger[r][f].begin(); itt != d_auto_gen_trigger[r][f].end(); ++itt ){
-          Trigger* tr = itt->first;
-          if( tr ){
-            bool processTrigger = itt->second;
-            if( processTrigger && d_processed_trigger[f].find( tr )==d_processed_trigger[f].end() ){
-              d_processed_trigger[f][tr] = true;
-              Trace("process-trigger") << "  Process ";
-              tr->debugPrint("process-trigger");
-              Trace("process-trigger") << "..." << std::endl;
-              int numInst = tr->addInstantiations();
-              hasInst = numInst>0 || hasInst;
-              Trace("process-trigger") << "  Done, numInst = " << numInst << "." << std::endl;
-              d_quantEngine->d_statistics.d_instantiations_auto_gen += numInst;
-              if( r==1 ){
-                d_quantEngine->d_statistics.d_multi_trigger_instantiations += numInst;
-              }
-              if( d_quantEngine->inConflict() ){
-                break;
-              }
-            }
-          }
-        }
-        if( d_quantEngine->inConflict() || ( hasInst && options::multiTriggerPriority() ) ){
-          break;
-        }
-      }
-      //if( e==4 ){
-      //  d_quantEngine->getEqualityQuery()->setLiberal( false );
-      //}
-      return STATUS_UNKNOWN;
-    }
-  }
-}
-
-void InstStrategyAutoGenTriggers::generateTriggers( Node f ){
-  Trace("auto-gen-trigger-debug") << "Generate triggers for " << f << ", #var=" << f[0].getNumChildren() << "..." << std::endl;
-  if( d_patTerms[0].find( f )==d_patTerms[0].end() ){
-    //determine all possible pattern terms based on trigger term selection strategy d_tr_strategy
-    d_patTerms[0][f].clear();
-    d_patTerms[1][f].clear();
-    bool ntrivTriggers = options::relationalTriggers();
-    std::vector< Node > patTermsF;
-    std::map< Node, inst::TriggerTermInfo > tinfo;
-    //well-defined function: can assume LHS is only trigger
-    if( options::quantFunWellDefined() ){
-      Node hd = QuantAttributes::getFunDefHead( f );
-      if( !hd.isNull() ){
-        hd = d_quantEngine->getTermUtil()
-                 ->substituteBoundVariablesToInstConstants(hd, f);
-        patTermsF.push_back( hd );
-        tinfo[hd].init( f, hd );
-      }
-    }
-    //otherwise, use algorithm for collecting pattern terms
-    if( patTermsF.empty() ){
-      Node bd = d_quantEngine->getTermUtil()->getInstConstantBody( f );
-      Trigger::collectPatTerms( f, bd, patTermsF, d_tr_strategy, d_user_no_gen[f], tinfo, true );
-      if( ntrivTriggers ){
-        sortTriggers st;
-        std::sort( patTermsF.begin(), patTermsF.end(), st );
-      }
-      if( Trace.isOn("auto-gen-trigger-debug") ){
-        Trace("auto-gen-trigger-debug") << "Collected pat terms for " << bd << ", no-patterns : " << d_user_no_gen[f].size() << std::endl;
-        for( unsigned i=0; i<patTermsF.size(); i++ ){
-          Assert( tinfo.find( patTermsF[i] )!=tinfo.end() );
-          Trace("auto-gen-trigger-debug") << "   " << patTermsF[i] << std::endl;
-          Trace("auto-gen-trigger-debug2") << "     info = [" << tinfo[patTermsF[i]].d_reqPol << ", " << tinfo[patTermsF[i]].d_reqPolEq << ", " << tinfo[patTermsF[i]].d_fv.size() << "]" << std::endl;
-        }
-        Trace("auto-gen-trigger-debug") << std::endl;
-      }
-    }
-    //sort into single/multi triggers, calculate which terms should not be considered
-    std::map< Node, bool > vcMap;
-    std::map< Node, bool > rmPatTermsF;
-    int last_weight = -1;
-    for( unsigned i=0; i<patTermsF.size(); i++ ){
-      Assert( patTermsF[i].getKind()!=NOT );
-      bool newVar = false;
-      for( unsigned j=0; j<tinfo[ patTermsF[i] ].d_fv.size(); j++ ){
-        if( vcMap.find( tinfo[ patTermsF[i] ].d_fv[j] )==vcMap.end() ){
-          vcMap[tinfo[ patTermsF[i] ].d_fv[j]] = true;
-          newVar = true;
-        }
-      }
-      int curr_w = Trigger::getTriggerWeight( patTermsF[i] );
-      if( ntrivTriggers && !newVar && last_weight!=-1 && curr_w>last_weight ){
-        Trace("auto-gen-trigger-debug") << "...exclude expendible non-trivial trigger : " << patTermsF[i] << std::endl;
-        rmPatTermsF[patTermsF[i]] = true;
-      }else{
-        last_weight = curr_w;
-      }
-    }
-    d_num_trigger_vars[f] = vcMap.size();
-    if( d_num_trigger_vars[f]>0 && d_num_trigger_vars[f]<f[0].getNumChildren() ){
-      Trace("auto-gen-trigger-partial") << "Quantified formula : " << f << std::endl;
-      Trace("auto-gen-trigger-partial") << "...does not contain all variables in triggers!!!" << std::endl;
-      if( options::partialTriggers() ){
-        std::vector< Node > vcs[2];
-        for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
-          Node ic = d_quantEngine->getTermUtil()->getInstantiationConstant( f, i );
-          vcs[ vcMap.find( ic )==vcMap.end() ? 0 : 1 ].push_back( f[0][i] );
-        }
-        for( unsigned i=0; i<2; i++ ){
-          d_vc_partition[i][f] = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, vcs[i] );
-        }
-      }else{
-        return;
-      }
-    }
-    for( unsigned i=0; i<patTermsF.size(); i++ ){
-      Node pat = patTermsF[i];
-      if( rmPatTermsF.find( pat )==rmPatTermsF.end() ){
-        Trace("auto-gen-trigger-debug") << "...processing pattern " << pat << std::endl;
-        Node mpat = pat;
-        //process the pattern: if it has a required polarity, consider it
-        Assert( tinfo.find( pat )!=tinfo.end() );
-        int rpol = tinfo[pat].d_reqPol;
-        Node rpoleq = tinfo[pat].d_reqPolEq;
-        unsigned num_fv = tinfo[pat].d_fv.size();
-        Trace("auto-gen-trigger-debug") << "...required polarity for " << pat << " is " << rpol << ", eq=" << rpoleq << std::endl;
-        if( rpol!=0 ){
-          Assert( rpol==1 || rpol==-1 );
-          if( Trigger::isRelationalTrigger( pat ) ){
-            pat = rpol==-1 ? pat.negate() : pat;
-          }else{
-            Assert( Trigger::isAtomicTrigger( pat ) );
-            if( pat.getType().isBoolean() && rpoleq.isNull() ){
-              if( options::literalMatchMode()==LITERAL_MATCH_USE ){
-                pat = NodeManager::currentNM()->mkNode( EQUAL, pat, NodeManager::currentNM()->mkConst( rpol==-1 ) ).negate();
-              }else if( options::literalMatchMode()!=LITERAL_MATCH_NONE ){
-                pat = NodeManager::currentNM()->mkNode( EQUAL, pat, NodeManager::currentNM()->mkConst( rpol==1 ) );
-              }
-            }else{
-              Assert( !rpoleq.isNull() );
-              if( rpol==-1 ){
-                if( options::literalMatchMode()!=LITERAL_MATCH_NONE ){
-                  //all equivalence classes except rpoleq
-                  pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq ).negate();
-                }
-              }else if( rpol==1 ){
-                if( options::literalMatchMode()==LITERAL_MATCH_AGG ){
-                  //only equivalence class rpoleq
-                  pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq );
-                }
-                //all equivalence classes that are not disequal to rpoleq TODO?
-              }
-            }
-          }
-          Trace("auto-gen-trigger-debug") << "...got : " << pat << std::endl;
-        }else{
-          if( Trigger::isRelationalTrigger( pat ) ){
-            //consider both polarities
-            addPatternToPool( f, pat.negate(), num_fv, mpat );
-          }
-        }
-        addPatternToPool( f, pat, num_fv, mpat );
-      }
-    }
-    //tinfo not used below this point
-    d_made_multi_trigger[f] = false;
-    Trace("auto-gen-trigger") << "Single trigger pool for " << f << " : " << std::endl;
-    for( unsigned i=0; i<d_patTerms[0][f].size(); i++ ){
-      Trace("auto-gen-trigger") << "   " << d_patTerms[0][f][i] << std::endl;
-    }
-    if( !d_patTerms[1][f].empty() ){
-      Trace("auto-gen-trigger") << "Multi-trigger term pool for " << f << " : " << std::endl;
-      for( unsigned i=0; i<d_patTerms[1][f].size(); i++ ){
-        Trace("auto-gen-trigger") << "   " << d_patTerms[1][f][i] << std::endl;
-      }
-    }
-  }
-
-  unsigned rmin = d_patTerms[0][f].empty() ? 1 : 0;
-  unsigned rmax = options::multiTriggerWhenSingle() ? 1 : rmin;
-  for( unsigned r=rmin; r<=rmax; r++ ){
-    std::vector< Node > patTerms;
-    for( int i=0; i<(int)d_patTerms[r][f].size(); i++ ){
-      if( r==1 || d_single_trigger_gen.find( d_patTerms[r][f][i] )==d_single_trigger_gen.end() ){
-        patTerms.push_back( d_patTerms[r][f][i] );
-      }
-    }
-    if( !patTerms.empty() ){
-      Trace("auto-gen-trigger") << "Generate trigger for " << f << std::endl;
-      //sort terms based on relevance
-      if( options::relevantTriggers() ){
-        sortQuantifiersForSymbol sqfs;
-        sqfs.d_qe = d_quantEngine;
-        for( unsigned i=0; i<patTerms.size(); i++ ){
-          Assert( d_pat_to_mpat.find( patTerms[i] )!=d_pat_to_mpat.end() );
-          Assert( d_pat_to_mpat[patTerms[i]].hasOperator() );
-          sqfs.d_op_map[ patTerms[i] ] = d_pat_to_mpat[patTerms[i]].getOperator();
-        }        
-        //sort based on # occurrences (this will cause Trigger to select rarer symbols)
-        std::sort( patTerms.begin(), patTerms.end(), sqfs );
-        Debug("relevant-trigger") << "Terms based on relevance: " << std::endl;
-        for( unsigned i=0; i<patTerms.size(); i++ ){
-          Debug("relevant-trigger") << "   " << patTerms[i] << " from " << d_pat_to_mpat[patTerms[i]] << " (";
-          Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_pat_to_mpat[patTerms[i]].getOperator() ) << ")" << std::endl;
-        }
-      }
-      //now, generate the trigger...
-      Trigger* tr = NULL;
-      if( d_is_single_trigger[ patTerms[0] ] ){
-        tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], false, Trigger::TR_RETURN_NULL, d_num_trigger_vars[f] );
-        d_single_trigger_gen[ patTerms[0] ] = true;
-      }else{
-        //only generate multi trigger if option set, or if no single triggers exist
-        if( !d_patTerms[0][f].empty() ){
-          if( options::multiTriggerWhenSingle() ){
-            Trace("multi-trigger-debug") << "Resort to choosing multi-triggers..." << std::endl;
-          }else{
-            return;
-          }
-        }
-        //if we are re-generating triggers, shuffle based on some method
-        if( d_made_multi_trigger[f] ){
-          std::random_shuffle( patTerms.begin(), patTerms.end() ); //shuffle randomly
-        }else{
-          d_made_multi_trigger[f] = true;
-        }
-        //will possibly want to get an old trigger
-        tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, false, Trigger::TR_GET_OLD, d_num_trigger_vars[f] );
-      }
-      if( tr ){
-        addTrigger( tr, f );
-        //if we are generating additional triggers...
-        if( !tr->isMultiTrigger() ){
-          unsigned index = 0;
-          if( index<patTerms.size() ){
-            //Notice() << "check add additional" << std::endl;
-            //check if similar patterns exist, and if so, add them additionally
-            unsigned nqfs_curr = 0;
-            if( options::relevantTriggers() ){
-              nqfs_curr = d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[0].getOperator() );
-            }
-            index++;
-            bool success = true;
-            while( success && index<patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){
-              success = false;
-              if( !options::relevantTriggers() ||
-                  d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[index].getOperator() )<=nqfs_curr ){
-                d_single_trigger_gen[ patTerms[index] ] = true;
-                Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], false, Trigger::TR_RETURN_NULL, d_num_trigger_vars[f] );
-                addTrigger( tr2, f );
-                success = true;
-              }
-              index++;
-            }
-            //Notice() << "done check add additional" << std::endl;
-          }
-        }
-      }
-    }
-  }
-}
-
-void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat ) {
-  d_pat_to_mpat[pat] = mpat;
-  unsigned num_vars = options::partialTriggers() ? d_num_trigger_vars[q] : q[0].getNumChildren();
-  if( num_fv==num_vars && ( options::pureThTriggers() || !Trigger::isPureTheoryTrigger( pat ) ) ){
-    d_patTerms[0][q].push_back( pat );
-    d_is_single_trigger[ pat ] = true;
-  }else{
-    d_patTerms[1][q].push_back( pat );
-    d_is_single_trigger[ pat ] = false;
-  }
-}
-
-
-void InstStrategyAutoGenTriggers::addTrigger( inst::Trigger * tr, Node q ) {
-  if( tr ){
-    if( d_num_trigger_vars[q]<q[0].getNumChildren() ){
-      //partial trigger : generate implication to mark user pattern
-      Node pat =
-          d_quantEngine->getTermUtil()->substituteInstConstantsToBoundVariables(
-              tr->getInstPattern(), q);
-      Node ipl = NodeManager::currentNM()->mkNode(INST_PATTERN_LIST, pat);
-      Node qq = NodeManager::currentNM()->mkNode( FORALL, d_vc_partition[1][q], NodeManager::currentNM()->mkNode( FORALL, d_vc_partition[0][q], q[1] ), ipl );
-      Trace("auto-gen-trigger-partial") << "Make partially specified user pattern: " << std::endl;
-      Trace("auto-gen-trigger-partial") << "  " << qq << std::endl;
-      Node lem = NodeManager::currentNM()->mkNode( OR, q.negate(), qq );
-      d_quantEngine->addLemma( lem );
-    }else{
-      unsigned tindex;
-      if( tr->isMultiTrigger() ){
-        //disable all other multi triggers
-        for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[1][q].begin(); it != d_auto_gen_trigger[1][q].end(); ++it ){
-          d_auto_gen_trigger[1][q][ it->first ] = false;
-        }
-        tindex = 1;
-      }else{
-        tindex = 0;
-      }
-      //making it during an instantiation round, so must reset
-      if( d_auto_gen_trigger[tindex][q].find( tr )==d_auto_gen_trigger[tindex][q].end() ){
-        tr->resetInstantiationRound();
-        tr->reset( Node::null() );
-      }
-      d_auto_gen_trigger[tindex][q][tr] = true;
-    }
-  }
-}
-
-bool InstStrategyAutoGenTriggers::hasUserPatterns( Node q ) {
-  if( q.getNumChildren()==3 ){
-    std::map< Node, bool >::iterator it = d_hasUserPatterns.find( q );
-    if( it==d_hasUserPatterns.end() ){
-      bool hasPat = false;
-      for( unsigned i=0; i<q[2].getNumChildren(); i++ ){
-        if( q[2][i].getKind()==INST_PATTERN ){
-          hasPat = true;
-          break;
-        }
-      }
-      d_hasUserPatterns[q] = hasPat;
-      return hasPat;
-    }else{
-      return it->second;
-    }
-  }else{
-    return false;
-  }
-}
-
-void InstStrategyAutoGenTriggers::addUserNoPattern( Node q, Node pat ) {
-  Assert( pat.getKind()==INST_NO_PATTERN && pat.getNumChildren()==1 );
-  if( std::find( d_user_no_gen[q].begin(), d_user_no_gen[q].end(), pat[0] )==d_user_no_gen[q].end() ){
-    Trace("user-pat") << "Add user no-pattern: " << pat[0] << " for " << q << std::endl;
-    d_user_no_gen[q].push_back( pat[0] );
-  }
-}
-
-/*  TODO?
-bool InstStrategyLocalTheoryExt::isLocalTheoryExt( Node f ) {
-  std::map< Node, bool >::iterator itq = d_quant.find( f );
-  if( itq==d_quant.end() ){
-    //generate triggers
-    Node bd = d_quantEngine->getTermUtil()->getInstConstantBody( f );
-    std::vector< Node > vars;
-    std::vector< Node > patTerms;
-    bool ret = Trigger::isLocalTheoryExt( bd, vars, patTerms );
-    if( ret ){
-      d_quant[f] = ret;
-      //add all variables to trigger that don't already occur
-      for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
-        Node x = d_quantEngine->getTermUtil()->getInstantiationConstant( f, i );
-        if( std::find( vars.begin(), vars.end(), x )==vars.end() ){
-          patTerms.push_back( x );
-        }
-      }
-      Trace("local-t-ext") << "Local theory extensions trigger for " << f << " : " << std::endl;
-      for( unsigned i=0; i<patTerms.size(); i++ ){
-        Trace("local-t-ext") << "  " << patTerms[i] << std::endl;
-      }
-      Trace("local-t-ext") << std::endl;
-      Trigger * tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, true, Trigger::TR_GET_OLD );
-      d_lte_trigger[f] = tr;
-    }else{
-      Trace("local-t-ext") << "No local theory extensions trigger for " << f << "." << std::endl;
-      Trace("local-t-ext-warn") << "WARNING: not local theory extensions : " << f << std::endl;
-    }
-    d_quant[f] = ret;
-    return ret;
-  }else{
-    return itq->second;
-  }
-}
-*/
-
-} /* CVC4::theory::quantifiers namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.h b/src/theory/quantifiers/inst_strategy_e_matching.h
deleted file mode 100644 (file)
index 1a0ec9b..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*********************                                                        */
-/*! \file inst_strategy_e_matching.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Morgan Deters, Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief E matching instantiation strategies
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__INST_STRATEGY_E_MATCHING_H
-#define __CVC4__INST_STRATEGY_E_MATCHING_H
-
-#include "context/context.h"
-#include "context/context_mm.h"
-#include "theory/quantifiers/instantiation_engine.h"
-#include "theory/quantifiers/trigger.h"
-#include "theory/quantifiers_engine.h"
-#include "util/statistics_registry.h"
-#include "options/quantifiers_options.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-//instantiation strategies
-
-class InstStrategyUserPatterns : public InstStrategy{
-private:
-  /** explicitly provided patterns */
-  std::map< Node, std::vector< inst::Trigger* > > d_user_gen;
-  /** waiting to be generated patterns */
-  std::map< Node, std::vector< std::vector< Node > > > d_user_gen_wait;
-  /** counter for quantifiers */
-  std::map< Node, int > d_counter;
-  /** process functions */
-  void processResetInstantiationRound( Theory::Effort effort );
-  int process( Node f, Theory::Effort effort, int e );
-public:
-  InstStrategyUserPatterns( QuantifiersEngine* ie ) :
-      InstStrategy( ie ){}
-  ~InstStrategyUserPatterns(){}
-public:
-  /** add pattern */
-  void addUserPattern( Node q, Node pat );
-  /** get num patterns */
-  int getNumUserGenerators( Node q ) { return (int)d_user_gen[q].size(); }
-  /** get user pattern */
-  inst::Trigger* getUserGenerator( Node q, int i ) { return d_user_gen[q][ i ]; }
-  /** identify */
-  std::string identify() const { return std::string("UserPatterns"); }
-};/* class InstStrategyUserPatterns */
-
-class InstStrategyAutoGenTriggers : public InstStrategy {
-public:
-  enum {
-    RELEVANCE_NONE,
-    RELEVANCE_DEFAULT,
-  };
-private:
-  /** trigger generation strategy */
-  TriggerSelMode d_tr_strategy;
-  /** regeneration */
-  bool d_regenerate;
-  int d_regenerate_frequency;
-  /** (single,multi) triggers for each quantifier */
-  std::map< Node, std::map< inst::Trigger*, bool > > d_auto_gen_trigger[2];
-  std::map< Node, int > d_counter;
-  /** single, multi triggers for each quantifier */
-  std::map< Node, std::vector< Node > > d_patTerms[2];
-  std::map< Node, std::map< Node, bool > > d_patReqPol;
-  /** information about triggers */
-  std::map< Node, bool > d_is_single_trigger;
-  std::map< Node, bool > d_single_trigger_gen;
-  std::map< Node, bool > d_made_multi_trigger;
-  //processed trigger this round
-  std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger;
-  //instantiation no patterns
-  std::map< Node, std::vector< Node > > d_user_no_gen;
-  // number of trigger variables per quantifier
-  std::map< Node, unsigned > d_num_trigger_vars;
-  std::map< Node, Node > d_vc_partition[2];
-  std::map< Node, Node > d_pat_to_mpat;
-private:
-  /** process functions */
-  void processResetInstantiationRound( Theory::Effort effort );
-  int process( Node q, Theory::Effort effort, int e );
-  /** generate triggers */
-  void generateTriggers( Node q );
-  void addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat );
-  void addTrigger( inst::Trigger * tr, Node f );
-  /** has user patterns */
-  bool hasUserPatterns( Node q );
-  /** has user patterns */
-  std::map< Node, bool > d_hasUserPatterns;
-public:
-  InstStrategyAutoGenTriggers( QuantifiersEngine* qe );
-  ~InstStrategyAutoGenTriggers(){}
-public:
-  /** get auto-generated trigger */
-  inst::Trigger* getAutoGenTrigger( Node q );
-  /** identify */
-  std::string identify() const { return std::string("AutoGenTriggers"); }
-  /** add pattern */
-  void addUserNoPattern( Node q, Node pat );
-};/* class InstStrategyAutoGenTriggers */
-
-
-}
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif
index e04217b162d0eb005ff396b2f9bacb94662050b8..810ceee4fc95147822d6823d3a0f95026994395b 100644 (file)
@@ -17,7 +17,7 @@
 #include "options/quantifiers_options.h"
 #include "smt/smt_statistics_registry.h"
 #include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/inst_strategy_cbqi.h"
+#include "theory/quantifiers/cegqi/inst_strategy_cbqi.h"
 #include "theory/quantifiers/quantifiers_attributes.h"
 #include "theory/quantifiers/quantifiers_rewriter.h"
 #include "theory/quantifiers/term_database.h"
diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp
deleted file mode 100644 (file)
index 0c847b5..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*********************                                                        */
-/*! \file instantiation_engine.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Morgan Deters, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of instantiation engine class
- **/
-
-#include "theory/quantifiers/instantiation_engine.h"
-
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/inst_strategy_e_matching.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
-#include "theory/theory_engine.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace CVC4::theory::inst;
-
-InstantiationEngine::InstantiationEngine(QuantifiersEngine* qe)
-    : QuantifiersModule(qe),
-      d_instStrategies(),
-      d_isup(),
-      d_i_ag(),
-      d_quants() {
-  if (options::eMatching()) {
-    // these are the instantiation strategies for E-matching
-    // user-provided patterns
-    if (options::userPatternsQuant() != USER_PAT_MODE_IGNORE) {
-      d_isup.reset(new InstStrategyUserPatterns(d_quantEngine));
-      d_instStrategies.push_back(d_isup.get());
-    }
-
-    // auto-generated patterns
-    d_i_ag.reset(new InstStrategyAutoGenTriggers(d_quantEngine));
-    d_instStrategies.push_back(d_i_ag.get());
-  }
-}
-
-InstantiationEngine::~InstantiationEngine() {}
-
-void InstantiationEngine::presolve() {
-  for( unsigned i=0; i<d_instStrategies.size(); ++i ){
-    d_instStrategies[i]->presolve();
-  }
-}
-
-void InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
-  unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting();
-  //iterate over an internal effort level e
-  int e = 0;
-  int eLimit = effort==Theory::EFFORT_LAST_CALL ? 10 : 2;
-  bool finished = false;
-  //while unfinished, try effort level=0,1,2....
-  while( !finished && e<=eLimit ){
-    Debug("inst-engine") << "IE: Prepare instantiation (" << e << ")." << std::endl;
-    finished = true;
-    //instantiate each quantifier
-    for( unsigned i=0; i<d_quants.size(); i++ ){
-      Node q = d_quants[i];
-      Debug("inst-engine-debug") << "IE: Instantiate " << q << "..." << std::endl;
-      //int e_use = d_quantEngine->getRelevance( q )==-1 ? e - 1 : e;
-      int e_use = e;
-      if( e_use>=0 ){
-        Trace("inst-engine-debug") << "inst-engine : " << q << std::endl;
-        //check each instantiation strategy
-        for( unsigned j=0; j<d_instStrategies.size(); j++ ){
-          InstStrategy* is = d_instStrategies[j];
-          Trace("inst-engine-debug") << "Do " << is->identify() << " " << e_use << std::endl;
-          int quantStatus = is->process( q, effort, e_use );
-          Trace("inst-engine-debug") << " -> status is " << quantStatus << ", conflict=" << d_quantEngine->inConflict() << std::endl;
-          if( d_quantEngine->inConflict() ){
-            return;
-          }else if( quantStatus==InstStrategy::STATUS_UNFINISHED ){
-            finished = false;
-          }
-        }
-      }
-    }
-    //do not consider another level if already added lemma at this level
-    if( d_quantEngine->getNumLemmasWaiting()>lastWaiting ){
-      finished = true;
-    }
-    e++;
-  }
-}
-
-bool InstantiationEngine::needsCheck( Theory::Effort e ){
-  return d_quantEngine->getInstWhenNeedsCheck( e );
-}
-
-void InstantiationEngine::reset_round( Theory::Effort e ){
-  //if not, proceed to instantiation round
-  //reset the instantiation strategies
-  for( unsigned i=0; i<d_instStrategies.size(); ++i ){
-    InstStrategy* is = d_instStrategies[i];
-    is->processResetInstantiationRound( e );
-  }
-}
-
-void InstantiationEngine::check(Theory::Effort e, QEffort quant_e)
-{
-  CodeTimer codeTimer(d_quantEngine->d_statistics.d_ematching_time);
-  if (quant_e == QEFFORT_STANDARD)
-  {
-    double clSet = 0;
-    if( Trace.isOn("inst-engine") ){
-      clSet = double(clock())/double(CLOCKS_PER_SEC);
-      Trace("inst-engine") << "---Instantiation Engine Round, effort = " << e << "---" << std::endl;
-    }
-    //collect all active quantified formulas belonging to this
-    bool quantActive = false;
-    d_quants.clear();
-    for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
-      Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true );
-      if( d_quantEngine->hasOwnership( q, this ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){
-        quantActive = true;
-        d_quants.push_back( q );
-      }
-    }
-    Trace("inst-engine-debug") << "InstEngine: check: # asserted quantifiers " << d_quants.size() << "/";
-    Trace("inst-engine-debug") << d_quantEngine->getModel()->getNumAssertedQuantifiers() << " " << quantActive << std::endl;
-    if( quantActive ){
-      unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting();
-      doInstantiationRound( e );
-      if( d_quantEngine->inConflict() ){
-        Assert( d_quantEngine->getNumLemmasWaiting()>lastWaiting );
-        Trace("inst-engine") << "Conflict, added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl;
-      }else if( d_quantEngine->hasAddedLemma() ){
-        Trace("inst-engine") << "Added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting)  << std::endl;
-      }
-    }else{
-      d_quants.clear();
-    }
-    if( Trace.isOn("inst-engine") ){
-      double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
-      Trace("inst-engine") << "Finished instantiation engine, time = " << (clSet2-clSet) << std::endl;
-    }
-  }
-}
-
-bool InstantiationEngine::checkCompleteFor( Node q ) {
-  //TODO?
-  return false;
-}
-
-void InstantiationEngine::preRegisterQuantifier( Node q ) {
-  if( options::strictTriggers() && q.getNumChildren()==3 ){
-    //if strict triggers, take ownership of this quantified formula
-    bool hasPat = false;
-    for( unsigned i=0; i<q[2].getNumChildren(); i++ ){
-      if( q[2][i].getKind()==INST_PATTERN || q[2][i].getKind()==INST_NO_PATTERN  ){
-        hasPat = true;
-        break;
-      }
-    }
-    if( hasPat ){
-      d_quantEngine->setOwner( q, this, 1 );
-    }
-  }
-}
-
-void InstantiationEngine::registerQuantifier( Node f ){
-  if( d_quantEngine->hasOwnership( f, this ) ){
-    //for( unsigned i=0; i<d_instStrategies.size(); ++i ){
-    //  d_instStrategies[i]->registerQuantifier( f );
-    //}
-    //take into account user patterns
-    if( f.getNumChildren()==3 ){
-      Node subsPat =
-          d_quantEngine->getTermUtil()->substituteBoundVariablesToInstConstants(
-              f[2], f);
-      //add patterns
-      for( int i=0; i<(int)subsPat.getNumChildren(); i++ ){
-        //Notice() << "Add pattern " << subsPat[i] << " for " << f << std::endl;
-        if( subsPat[i].getKind()==INST_PATTERN ){
-          addUserPattern( f, subsPat[i] );
-        }else if( subsPat[i].getKind()==INST_NO_PATTERN ){
-          addUserNoPattern( f, subsPat[i] );
-        }
-      }
-    }
-  }
-}
-
-void InstantiationEngine::addUserPattern(Node q, Node pat) {
-  if (d_isup) {
-    d_isup->addUserPattern(q, pat);
-  }
-}
-
-void InstantiationEngine::addUserNoPattern(Node q, Node pat) {
-  if (d_i_ag) {
-    d_i_ag->addUserNoPattern(q, pat);
-  }
-}
diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h
deleted file mode 100644 (file)
index 18b5ea1..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*********************                                                        */
-/*! \file instantiation_engine.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Morgan Deters, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Instantiation Engine classes
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__INSTANTIATION_ENGINE_H
-#define __CVC4__THEORY__QUANTIFIERS__INSTANTIATION_ENGINE_H
-
-#include <memory>
-
-#include "theory/quantifiers_engine.h"
-#include "theory/quantifiers/theory_quantifiers.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class InstStrategyUserPatterns;
-class InstStrategyAutoGenTriggers;
-class InstStrategyFreeVariable;
-
-/** instantiation strategy class */
-class InstStrategy {
-public:
-  enum Status {
-    STATUS_UNFINISHED,
-    STATUS_UNKNOWN,
-  };/* enum Status */
-protected:
-  /** reference to the instantiation engine */
-  QuantifiersEngine* d_quantEngine;
-public:
-  InstStrategy( QuantifiersEngine* qe ) : d_quantEngine( qe ){}
-  virtual ~InstStrategy(){}
-  /** presolve */
-  virtual void presolve() {}
-  /** reset instantiation */
-  virtual void processResetInstantiationRound( Theory::Effort effort ) = 0;
-  /** process method, returns a status */
-  virtual int process( Node f, Theory::Effort effort, int e ) = 0;
-  /** identify */
-  virtual std::string identify() const { return std::string("Unknown"); }
-  /** register quantifier */
-  //virtual void registerQuantifier( Node q ) {}
-};/* class InstStrategy */
-
-class InstantiationEngine : public QuantifiersModule {
- private:
-  /** instantiation strategies */
-  std::vector<InstStrategy*> d_instStrategies;
-  /** user-pattern instantiation strategy */
-  std::unique_ptr<InstStrategyUserPatterns> d_isup;
-  /** auto gen triggers; only kept for destructor cleanup */
-  std::unique_ptr<InstStrategyAutoGenTriggers> d_i_ag;
-
-  typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
-  /** current processing quantified formulas */
-  std::vector<Node> d_quants;
-
-  /** is the engine incomplete for this quantifier */
-  bool isIncomplete(Node q);
-  /** do instantiation round */
-  void doInstantiationRound(Theory::Effort effort);
-
- public:
-  InstantiationEngine(QuantifiersEngine* qe);
-  ~InstantiationEngine();
-  void presolve();
-  bool needsCheck(Theory::Effort e);
-  void reset_round(Theory::Effort e);
-  void check(Theory::Effort e, QEffort quant_e);
-  bool checkCompleteFor(Node q);
-  void preRegisterQuantifier(Node q);
-  void registerQuantifier(Node q);
-  Node explain(TNode n) { return Node::null(); }
-  /** add user pattern */
-  void addUserPattern(Node q, Node pat);
-  void addUserNoPattern(Node q, Node pat);
-  /** Identify this module */
-  std::string identify() const { return "InstEngine"; }
-}; /* class InstantiationEngine */
-
-}/* CVC4::theory::quantifiers namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__INSTANTIATION_ENGINE_H */
index b84499ee4a8daa99cc7a912d2b2c5307630914bf..cafd6e5798208f30a763c813bd55403a2aef7e56 100644 (file)
@@ -25,7 +25,7 @@
 #include "smt/smt_engine_scope.h"
 #include "theory/quantifiers/term_database.h"
 #include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/ematching/trigger.h"
 #include "theory/rewriter.h"
 
 using namespace CVC4;
diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp
deleted file mode 100644 (file)
index fbd122b..0000000
+++ /dev/null
@@ -1,808 +0,0 @@
-/*********************                                                        */
-/*! \file model_builder.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of model builder class
- **/
-
-#include "theory/quantifiers/model_builder.h"
-
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/model_engine.h"
-#include "theory/quantifiers/quantifiers_attributes.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
-#include "theory/theory_engine.h"
-#include "theory/uf/equality_engine.h"
-#include "theory/uf/theory_uf.h"
-#include "theory/uf/theory_uf_model.h"
-#include "theory/uf/theory_uf_strong_solver.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-
-QModelBuilder::QModelBuilder(context::Context* c, QuantifiersEngine* qe)
-    : TheoryEngineModelBuilder(qe->getTheoryEngine()),
-      d_qe(qe),
-      d_addedLemmas(0),
-      d_triedLemmas(0) {}
-
-bool QModelBuilder::optUseModel() {
-  return options::mbqiMode()!=MBQI_NONE || options::fmfBound();
-}
-
-bool QModelBuilder::preProcessBuildModel(TheoryModel* m) {
-  return preProcessBuildModelStd( m );
-}
-
-bool QModelBuilder::preProcessBuildModelStd(TheoryModel* m) {
-  d_addedLemmas = 0;
-  d_triedLemmas = 0;
-  if( options::fmfEmptySorts() || options::fmfFunWellDefinedRelevant() ){
-    FirstOrderModel * fm = (FirstOrderModel*)m;
-    //traverse equality engine
-    std::map< TypeNode, bool > eqc_usort;
-    eq::EqClassesIterator eqcs_i =
-        eq::EqClassesIterator(fm->getEqualityEngine());
-    while( !eqcs_i.isFinished() ){
-      TypeNode tr = (*eqcs_i).getType();
-      eqc_usort[tr] = true;
-      ++eqcs_i;
-    }
-    //look at quantified formulas
-    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
-      Node q = fm->getAssertedQuantifier( i, true );
-      if( fm->isQuantifierActive( q ) ){
-        //check if any of these quantified formulas can be set inactive
-        if( options::fmfEmptySorts() ){
-          for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
-            TypeNode tn = q[0][i].getType();
-            //we are allowed to assume the type is empty
-            if( tn.isSort() && eqc_usort.find( tn )==eqc_usort.end() ){
-              Trace("model-engine-debug") << "Empty domain quantified formula : " << q << std::endl;
-              fm->setQuantifierActive( q, false );
-            }
-          }
-        }else if( options::fmfFunWellDefinedRelevant() ){
-          if( q[0].getNumChildren()==1 ){
-            TypeNode tn = q[0][0].getType();
-            if( tn.getAttribute(AbsTypeFunDefAttribute()) ){
-              //Trace("model-engine-debug2") << "...possible irrelevant function def : " << q << ", #rr = " << d_quantEngine->getModel()->d_rep_set.getNumRelevantGroundReps( tn ) << std::endl;
-              //we are allowed to assume the introduced type is empty
-              if( eqc_usort.find( tn )==eqc_usort.end() ){
-                Trace("model-engine-debug") << "Irrelevant function definition : " << q << std::endl;
-                fm->setQuantifierActive( q, false );
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-  return true;
-}
-
-void QModelBuilder::debugModel( TheoryModel* m ){
-  //debug the model: cycle through all instantiations for all quantifiers, report ones that are not true
-  if( Trace.isOn("quant-check-model") ){
-    FirstOrderModel* fm = (FirstOrderModel*)m;
-    Trace("quant-check-model") << "Testing quantifier instantiations..." << std::endl;
-    int tests = 0;
-    int bad = 0;
-    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
-      Node f = fm->getAssertedQuantifier( i );
-      std::vector< Node > vars;
-      for( unsigned j=0; j<f[0].getNumChildren(); j++ ){
-        vars.push_back( f[0][j] );
-      }
-      QRepBoundExt qrbe(d_qe);
-      RepSetIterator riter(d_qe->getModel()->getRepSet(), &qrbe);
-      if( riter.setQuantifier( f ) ){
-        while( !riter.isFinished() ){
-          tests++;
-          std::vector< Node > terms;
-          for (unsigned k = 0; k < riter.getNumTerms(); k++)
-          {
-            terms.push_back( riter.getCurrentTerm( k ) );
-          }
-          Node n = d_qe->getInstantiate()->getInstantiation(f, vars, terms);
-          Node val = fm->getValue( n );
-          if (val != d_qe->getTermUtil()->d_true)
-          {
-            Trace("quant-check-model") << "*******  Instantiation " << n << " for " << std::endl;
-            Trace("quant-check-model") << "         " << f << std::endl;
-            Trace("quant-check-model") << "         Evaluates to " << val << std::endl;
-            bad++;
-          }
-          riter.increment();
-        }
-        Trace("quant-check-model") << "Tested " << tests << " instantiations";
-        if( bad>0 ){
-          Trace("quant-check-model") << ", " << bad << " failed" << std::endl;
-        }
-        Trace("quant-check-model") << "." << std::endl;
-      }else{
-        if( riter.isIncomplete() ){
-          Trace("quant-check-model") << "Warning: Could not test quantifier " << f << std::endl;
-        }
-      }
-    }
-  }
-}
-
-bool TermArgBasisTrie::addTerm(FirstOrderModel* fm, Node n, unsigned argIndex)
-{
-  if (argIndex < n.getNumChildren())
-  {
-    Node r;
-    if( n[ argIndex ].getAttribute(ModelBasisAttribute()) ){
-      r = n[ argIndex ];
-    }else{
-      r = fm->getRepresentative( n[ argIndex ] );
-    }
-    std::map< Node, TermArgBasisTrie >::iterator it = d_data.find( r );
-    if( it==d_data.end() ){
-      d_data[r].addTerm(fm, n, argIndex + 1);
-      return true;
-    }else{
-      return it->second.addTerm(fm, n, argIndex + 1);
-    }
-  }else{
-    return false;
-  }
-}
-
-QModelBuilderIG::QModelBuilderIG(context::Context* c, QuantifiersEngine* qe)
-    : QModelBuilder(c, qe),
-      d_basisNoMatch(c),
-      d_didInstGen(false),
-      d_numQuantSat(0),
-      d_numQuantInstGen(0),
-      d_numQuantNoInstGen(0),
-      d_numQuantNoSelForm(0),
-      d_instGenMatches(0) {}
-
-/*
-Node QModelBuilderIG::getCurrentUfModelValue( FirstOrderModel* fm, Node n, std::vector< Node > & args, bool partial ) {
-  return n;
-}
-*/
-
-bool QModelBuilderIG::processBuildModel( TheoryModel* m ) {
-  FirstOrderModel* f = (FirstOrderModel*)m;
-  FirstOrderModelIG* fm = f->asFirstOrderModelIG();
-  Trace("model-engine-debug") << "Process build model " << optUseModel() << std::endl;
-  d_didInstGen = false;
-  //reset the internal information
-  reset( fm );
-  //only construct first order model if optUseModel() is true
-  if( optUseModel() ){
-    Trace("model-engine-debug") << "Initializing " << fm->getNumAssertedQuantifiers() << " quantifiers..." << std::endl;
-    //check if any quantifiers are un-initialized
-    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
-      Node q = fm->getAssertedQuantifier( i );
-      if( d_qe->getModel()->isQuantifierActive( q ) ){
-        int lems = initializeQuantifier(q, q, f);
-        d_statistics.d_init_inst_gen_lemmas += lems;
-        d_addedLemmas += lems;
-        if( d_qe->inConflict() ){
-          break;
-        }
-      }
-    }
-    if( d_addedLemmas>0 ){
-      Trace("model-engine") << "Initialize, Added Lemmas = " << d_addedLemmas << std::endl;
-      return false;
-    }else{
-      Assert( !d_qe->inConflict() );
-      //initialize model
-      fm->initialize();
-      //analyze the functions
-      Trace("model-engine-debug") << "Analyzing model..." << std::endl;
-      analyzeModel( fm );
-      //analyze the quantifiers
-      Trace("model-engine-debug") << "Analyzing quantifiers..." << std::endl;
-      d_uf_prefs.clear();
-      for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
-        Node q = fm->getAssertedQuantifier( i );
-        analyzeQuantifier( fm, q );
-      }
-
-      //if applicable, find exceptions to model via inst-gen
-      if( options::fmfInstGen() ){
-        d_didInstGen = true;
-        d_instGenMatches = 0;
-        d_numQuantSat = 0;
-        d_numQuantInstGen = 0;
-        d_numQuantNoInstGen = 0;
-        d_numQuantNoSelForm = 0;
-        //now, see if we know that any exceptions via InstGen exist
-        Trace("model-engine-debug") << "Perform InstGen techniques for quantifiers..." << std::endl;
-        for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
-          Node f = fm->getAssertedQuantifier( i );
-          if( d_qe->getModel()->isQuantifierActive( f ) ){
-            int lems = doInstGen( fm, f );
-            d_statistics.d_inst_gen_lemmas += lems;
-            d_addedLemmas += lems;
-            //temporary
-            if( lems>0 ){
-              d_numQuantInstGen++;
-            }else if( hasInstGen( f ) ){
-              d_numQuantNoInstGen++;
-            }else{
-              d_numQuantNoSelForm++;
-            }
-            if( d_qe->inConflict() || ( options::fmfInstGenOneQuantPerRound() && lems>0 ) ){
-              break;
-            }
-          }else{
-            d_numQuantSat++;
-          }
-        }
-        Trace("model-engine-debug") << "Quantifiers sat/ig/n-ig/null " << d_numQuantSat << " / " << d_numQuantInstGen << " / ";
-        Trace("model-engine-debug") << d_numQuantNoInstGen << " / " << d_numQuantNoSelForm << std::endl;
-        Trace("model-engine-debug") << "Inst-gen # matches examined = " << d_instGenMatches << std::endl;
-        if( Trace.isOn("model-engine") ){
-          if( d_addedLemmas>0 ){
-            Trace("model-engine") << "InstGen, added lemmas = " << d_addedLemmas << std::endl;
-          }else{
-            Trace("model-engine") << "No InstGen lemmas..." << std::endl;
-          }
-        }
-      }
-      //construct the model if necessary
-      if( d_addedLemmas==0 ){
-        //if no immediate exceptions, build the model
-        //  this model will be an approximation that will need to be tested via exhaustive instantiation
-        Trace("model-engine-debug") << "Building model..." << std::endl;
-        //build model for UF
-        for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
-          Trace("model-engine-debug-uf") << "Building model for " << it->first << "..." << std::endl;
-          constructModelUf( fm, it->first );
-        }
-        Trace("model-engine-debug") << "Done building models." << std::endl;
-      }else{
-        return false;
-      }
-    }
-  }
-  //update models
-  for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
-    it->second.update( fm );
-    Trace("model-func") << "QModelBuilder: Make function value from tree " << it->first << std::endl;
-    //construct function values
-    Node f_def = it->second.getFunctionValue( "$x" );
-    fm->assignFunctionDefinition( it->first, f_def );
-  }
-  Assert( d_addedLemmas==0 );
-  return TheoryEngineModelBuilder::processBuildModel( m );
-}
-
-int QModelBuilderIG::initializeQuantifier(Node f, Node fp, FirstOrderModel* fm)
-{
-  if( d_quant_basis_match_added.find( f )==d_quant_basis_match_added.end() ){
-    //create the basis match if necessary
-    if( d_quant_basis_match.find( f )==d_quant_basis_match.end() ){
-      Trace("inst-fmf-init") << "Initialize " << f << std::endl;
-      //add the model basis instantiation
-      // This will help produce the necessary information for model completion.
-      // We do this by extending distinguish ground assertions (those
-      //   containing terms with "model basis" attribute) to hold for all cases.
-
-      ////first, check if any variables are required to be equal
-      //for( std::map< Node, bool >::iterator it = d_quantEngine->d_phase_reqs[f].begin();
-      //    it != d_quantEngine->d_phase_reqs[f].end(); ++it ){
-      //  Node n = it->first;
-      //  if( n.getKind()==EQUAL && n[0].getKind()==INST_CONSTANT && n[1].getKind()==INST_CONSTANT ){
-      //    Notice() << "Unhandled phase req: " << n << std::endl;
-      //  }
-      //}
-      d_quant_basis_match[f] = InstMatch( f );
-      for (unsigned j = 0; j < f[0].getNumChildren(); j++)
-      {
-        Node t = fm->getModelBasisTerm(f[0][j].getType());
-        //calculate the basis match for f
-        d_quant_basis_match[f].setValue( j, t );
-      }
-      ++(d_statistics.d_num_quants_init);
-    }
-    //try to add it
-    Trace("inst-fmf-init") << "Init: try to add match " << d_quant_basis_match[f] << std::endl;
-    //add model basis instantiation
-    if (d_qe->getInstantiate()->addInstantiation(fp, d_quant_basis_match[f]))
-    {
-      d_quant_basis_match_added[f] = true;
-      return 1;
-    }else{
-      //shouldn't happen usually, but will occur if x != y is a required literal for f.
-      //Notice() << "No model basis for " << f << std::endl;
-      d_quant_basis_match_added[f] = false;
-    }
-  }
-  return 0;
-}
-
-void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){
-  FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
-  d_uf_model_constructed.clear();
-  //determine if any functions are constant
-  for( std::map< Node, uf::UfModelTree >::iterator it = fmig->d_uf_model_tree.begin(); it != fmig->d_uf_model_tree.end(); ++it ){
-    Node op = it->first;
-    TermArgBasisTrie tabt;
-    std::map< Node, std::vector< Node > >::iterator itut = fmig->d_uf_terms.find( op );
-    if( itut!=fmig->d_uf_terms.end() ){
-      for( size_t i=0; i<itut->second.size(); i++ ){
-        Node n = fmig->d_uf_terms[op][i];
-        //for calculating if op is constant
-        Node v = fmig->getRepresentative( n );
-        if( i==0 ){
-          d_uf_prefs[op].d_const_val = v;
-        }else if( v!=d_uf_prefs[op].d_const_val ){
-          d_uf_prefs[op].d_const_val = Node::null();
-          break;
-        }
-        //for calculating terms that we don't need to consider
-        //if( d_qe->getTermDatabase()->isTermActive( n ) || n.getAttribute(ModelBasisArgAttribute())!=0 ){
-        if( d_basisNoMatch.find( n )==d_basisNoMatch.end() ){
-          //need to consider if it is not congruent modulo model basis
-          if( !tabt.addTerm( fmig, n ) ){
-            d_basisNoMatch[n] = true;
-          }
-        }
-      }
-    }
-    if( !d_uf_prefs[op].d_const_val.isNull() ){
-      fmig->d_uf_model_gen[op].setDefaultValue( d_uf_prefs[op].d_const_val );
-      fmig->d_uf_model_gen[op].makeModel( fmig, it->second );
-      Debug("fmf-model-cons") << "Function " << op << " is the constant function ";
-      fmig->printRepresentativeDebug( "fmf-model-cons", d_uf_prefs[op].d_const_val );
-      Debug("fmf-model-cons") << std::endl;
-      d_uf_model_constructed[op] = true;
-    }else{
-      d_uf_model_constructed[op] = false;
-    }
-  }
-}
-
-bool QModelBuilderIG::hasConstantDefinition( Node n ){
-  Node lit = n.getKind()==NOT ? n[0] : n;
-  if( lit.getKind()==APPLY_UF ){
-    Node op = lit.getOperator();
-    if( !d_uf_prefs[op].d_const_val.isNull() ){
-      return true;
-    }
-  }
-  return false;
-}
-
-QModelBuilderIG::Statistics::Statistics():
-  d_num_quants_init("QModelBuilderIG::Number_Quantifiers", 0),
-  d_num_partial_quants_init("QModelBuilderIG::Number_Partial_Quantifiers", 0),
-  d_init_inst_gen_lemmas("QModelBuilderIG::Initialize_Inst_Gen_Lemmas", 0 ),
-  d_inst_gen_lemmas("QModelBuilderIG::Inst_Gen_Lemmas", 0 ),
-  d_eval_formulas("QModelBuilderIG::Eval_Formulas", 0 ),
-  d_eval_uf_terms("QModelBuilderIG::Eval_Uf_Terms", 0 ),
-  d_eval_lits("QModelBuilderIG::Eval_Lits", 0 ),
-  d_eval_lits_unknown("QModelBuilderIG::Eval_Lits_Unknown", 0 )
-{
-  smtStatisticsRegistry()->registerStat(&d_num_quants_init);
-  smtStatisticsRegistry()->registerStat(&d_num_partial_quants_init);
-  smtStatisticsRegistry()->registerStat(&d_init_inst_gen_lemmas);
-  smtStatisticsRegistry()->registerStat(&d_inst_gen_lemmas);
-  smtStatisticsRegistry()->registerStat(&d_eval_formulas);
-  smtStatisticsRegistry()->registerStat(&d_eval_uf_terms);
-  smtStatisticsRegistry()->registerStat(&d_eval_lits);
-  smtStatisticsRegistry()->registerStat(&d_eval_lits_unknown);
-}
-
-QModelBuilderIG::Statistics::~Statistics(){
-  smtStatisticsRegistry()->unregisterStat(&d_num_quants_init);
-  smtStatisticsRegistry()->unregisterStat(&d_num_partial_quants_init);
-  smtStatisticsRegistry()->unregisterStat(&d_init_inst_gen_lemmas);
-  smtStatisticsRegistry()->unregisterStat(&d_inst_gen_lemmas);
-  smtStatisticsRegistry()->unregisterStat(&d_eval_formulas);
-  smtStatisticsRegistry()->unregisterStat(&d_eval_uf_terms);
-  smtStatisticsRegistry()->unregisterStat(&d_eval_lits);
-  smtStatisticsRegistry()->unregisterStat(&d_eval_lits_unknown);
-}
-
-//do exhaustive instantiation
-int QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
-  if( optUseModel() ){
-    QRepBoundExt qrbe(d_qe);
-    RepSetIterator riter(d_qe->getModel()->getRepSet(), &qrbe);
-    if( riter.setQuantifier( f ) ){
-      FirstOrderModelIG * fmig = (FirstOrderModelIG*)d_qe->getModel();
-      Debug("inst-fmf-ei") << "Reset evaluate..." << std::endl;
-      fmig->resetEvaluate();
-      Debug("inst-fmf-ei") << "Begin instantiation..." << std::endl;
-      EqualityQuery* qy = d_qe->getEqualityQuery();
-      Instantiate* inst = d_qe->getInstantiate();
-      TermUtil* util = d_qe->getTermUtil();
-      while( !riter.isFinished() && ( d_addedLemmas==0 || !options::fmfOneInstPerRound() ) ){
-        d_triedLemmas++;
-        if( Debug.isOn("inst-fmf-ei-debug") ){
-          for( int i=0; i<(int)riter.d_index.size(); i++ ){
-            Debug("inst-fmf-ei-debug") << i << " : " << riter.d_index[i] << " : " << riter.getCurrentTerm( i ) << std::endl;
-          }
-        }
-        int eval = 0;
-        int depIndex;
-        //see if instantiation is already true in current model
-        if( Debug.isOn("fmf-model-eval") ){
-          Debug("fmf-model-eval") << "Evaluating ";
-          riter.debugPrintSmall("fmf-model-eval");
-          Debug("fmf-model-eval") << "Done calculating terms." << std::endl;
-        }
-        //if evaluate(...)==1, then the instantiation is already true in the model
-        //  depIndex is the index of the least significant variable that this evaluation relies upon
-        depIndex = riter.getNumTerms()-1;
-        Debug("fmf-model-eval") << "We will evaluate "
-                                << util->getInstConstantBody(f) << std::endl;
-        eval = fmig->evaluate(util->getInstConstantBody(f), depIndex, &riter);
-        if( eval==1 ){
-          Debug("fmf-model-eval") << "  Returned success with depIndex = " << depIndex << std::endl;
-        }else{
-          Debug("fmf-model-eval") << "  Returned " << (eval==-1 ? "failure" : "unknown") << ", depIndex = " << depIndex << std::endl;
-        }
-        if( eval==1 ){
-          //instantiation is already true -> skip
-          riter.incrementAtIndex(depIndex);
-        }else{
-          //instantiation was not shown to be true, construct the match
-          InstMatch m( f );
-          for (unsigned i = 0; i < riter.getNumTerms(); i++)
-          {
-            m.set(qy, i, riter.getCurrentTerm(i));
-          }
-          Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
-          //add as instantiation
-          if (inst->addInstantiation(f, m, true))
-          {
-            d_addedLemmas++;
-            if( d_qe->inConflict() ){
-              break;
-            }
-            //if the instantiation is show to be false, and we wish to skip multiple instantiations at once
-            if( eval==-1 ){
-              riter.incrementAtIndex(depIndex);
-            }else{
-              riter.increment();
-            }
-          }else{
-            Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl;
-            riter.increment();
-          }
-        }
-      }
-      //print debugging information
-      if( fmig ){
-        d_statistics.d_eval_formulas += fmig->d_eval_formulas;
-        d_statistics.d_eval_uf_terms += fmig->d_eval_uf_terms;
-        d_statistics.d_eval_lits += fmig->d_eval_lits;
-        d_statistics.d_eval_lits_unknown += fmig->d_eval_lits_unknown;
-      }
-      Trace("inst-fmf-ei") << "For " << f << ", finished: " << std::endl;
-      Trace("inst-fmf-ei") << "   Inst Tried: " << d_triedLemmas << std::endl;
-      Trace("inst-fmf-ei") << "   Inst Added: " << d_addedLemmas << std::endl;
-      if( d_addedLemmas>1000 ){
-        Trace("model-engine-warn") << "WARNING: many instantiations produced for " << f << ": " << std::endl;
-        Trace("model-engine-warn") << "   Inst Tried: " << d_triedLemmas << std::endl;
-        Trace("model-engine-warn") << "   Inst Added: " << d_addedLemmas << std::endl;
-        Trace("model-engine-warn") << std::endl;
-      }
-    }
-    //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
-    return riter.isIncomplete() ? -1 : 1;
-  }else{
-    return 0;
-  }
-}
-
-
-
-void QModelBuilderDefault::reset( FirstOrderModel* fm ){
-  d_quant_selection_lit.clear();
-  d_quant_selection_lit_candidates.clear();
-  d_quant_selection_lit_terms.clear();
-  d_term_selection_lit.clear();
-  d_op_selection_terms.clear();
-}
-
-
-int QModelBuilderDefault::getSelectionScore( std::vector< Node >& uf_terms ) {
-  /*
-  size_t maxChildren = 0;
-  for( size_t i=0; i<uf_terms.size(); i++ ){
-    if( uf_terms[i].getNumChildren()>maxChildren ){
-      maxChildren = uf_terms[i].getNumChildren();
-    }
-  }
-  //TODO: look at how many entries they have?
-  return (int)maxChildren;
-  */
-  return 0;
-}
-
-void QModelBuilderDefault::analyzeQuantifier( FirstOrderModel* fm, Node f ){
-  if( d_qe->getModel()->isQuantifierActive( f ) ){
-    FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
-    Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl;
-    //the pro/con preferences for this quantifier
-    std::vector< Node > pro_con[2];
-    //the terms in the selection literal we choose
-    std::vector< Node > selectionLitTerms;
-    Trace("inst-gen-debug-quant") << "Inst-gen analyze " << f << std::endl;
-    //for each asserted quantifier f,
-    // - determine selection literals
-    // - check which function/predicates have good and bad definitions for satisfying f
-    if( d_phase_reqs.find( f )==d_phase_reqs.end() ){
-      d_phase_reqs[f].initialize( d_qe->getTermUtil()->getInstConstantBody( f ), true );
-    }
-    int selectLitScore = -1;
-    for( std::map< Node, bool >::iterator it = d_phase_reqs[f].d_phase_reqs.begin(); it != d_phase_reqs[f].d_phase_reqs.end(); ++it ){
-      //the literal n is phase-required for quantifier f
-      Node n = it->first;
-      Node gn = fm->getModelBasis(f, n);
-      Debug("fmf-model-req") << "   Req: " << n << " -> " << it->second << std::endl;
-      bool value;
-      //if the corresponding ground abstraction literal has a SAT value
-      if( d_qe->getValuation().hasSatValue( gn, value ) ){
-        //collect the non-ground uf terms that this literal contains
-        //  and compute if all of the symbols in this literal have
-        //  constant definitions.
-        bool isConst = true;
-        std::vector< Node > uf_terms;
-        if( TermUtil::hasInstConstAttr(n) ){
-          isConst = false;
-          if( gn.getKind()==APPLY_UF ){
-            uf_terms.push_back( gn );
-            isConst = hasConstantDefinition( gn );
-          }else if( gn.getKind()==EQUAL ){
-            isConst = true;
-            for( int j=0; j<2; j++ ){
-              if( TermUtil::hasInstConstAttr(n[j]) ){
-                if( n[j].getKind()==APPLY_UF &&
-                    fmig->d_uf_model_tree.find( gn[j].getOperator() )!=fmig->d_uf_model_tree.end() ){
-                  uf_terms.push_back( gn[j] );
-                  isConst = isConst && hasConstantDefinition( gn[j] );
-                }else{
-                  isConst = false;
-                }
-              }
-            }
-          }
-        }
-        //check if the value in the SAT solver matches the preference according to the quantifier
-        int pref = 0;
-        if( value!=it->second ){
-          //we have a possible selection literal
-          bool selectLit = d_quant_selection_lit[f].isNull();
-          bool selectLitConstraints = true;
-          //it is a constantly defined selection literal : the quantifier is sat
-          if( isConst ){
-            selectLit = selectLit || d_qe->getModel()->isQuantifierActive( f );
-            d_qe->getModel()->setQuantifierActive( f, false );
-            //check if choosing this literal would add any additional constraints to default definitions
-            selectLitConstraints = false;
-            for( int j=0; j<(int)uf_terms.size(); j++ ){
-              Node op = uf_terms[j].getOperator();
-              if( d_uf_prefs[op].d_reconsiderModel ){
-                selectLitConstraints = true;
-              }
-            }
-            if( !selectLitConstraints ){
-              selectLit = true;
-            }
-          }
-          //also check if it is naturally a better literal
-          if( !selectLit ){
-            int score = getSelectionScore( uf_terms );
-            //Trace("inst-gen-debug") << "Check " << score << " < " << selectLitScore << std::endl;
-            selectLit = score<selectLitScore;
-          }
-          //see if we wish to choose this as a selection literal
-          d_quant_selection_lit_candidates[f].push_back( value ? n : n.notNode() );
-          if( selectLit ){
-            selectLitScore = getSelectionScore( uf_terms );
-            Trace("inst-gen-debug") << "Choose selection literal " << gn << std::endl;
-            Trace("inst-gen-debug") << "  flags: " << isConst << " " << selectLitConstraints << " " << selectLitScore << std::endl;
-            d_quant_selection_lit[f] = value ? n : n.notNode();
-            selectionLitTerms.clear();
-            selectionLitTerms.insert( selectionLitTerms.begin(), uf_terms.begin(), uf_terms.end() );
-            if( !selectLitConstraints ){
-              break;
-            }
-          }
-          pref = 1;
-        }else{
-          pref = -1;
-        }
-        //if we are not yet SAT, so we will add to preferences
-        if( d_qe->getModel()->isQuantifierActive( f ) ){
-          Debug("fmf-model-prefs") << "  It is " << ( pref==1 ? "pro" : "con" );
-          Debug("fmf-model-prefs") << " the definition of " << n << std::endl;
-          for( int j=0; j<(int)uf_terms.size(); j++ ){
-            pro_con[ pref==1 ? 0 : 1 ].push_back( uf_terms[j] );
-          }
-        }
-      }
-    }
-    //process information about selection literal for f
-    if( !d_quant_selection_lit[f].isNull() ){
-      d_quant_selection_lit_terms[f].insert( d_quant_selection_lit_terms[f].begin(), selectionLitTerms.begin(), selectionLitTerms.end() );
-      for( int i=0; i<(int)selectionLitTerms.size(); i++ ){
-        d_term_selection_lit[ selectionLitTerms[i] ] = d_quant_selection_lit[f];
-        d_op_selection_terms[ selectionLitTerms[i].getOperator() ].push_back( selectionLitTerms[i] );
-      }
-    }else{
-      Trace("inst-gen-warn") << "WARNING: " << f << " has no selection literals" << std::endl;
-    }
-    //process information about requirements and preferences of quantifier f
-    if( !d_qe->getModel()->isQuantifierActive( f ) ){
-      Debug("fmf-model-prefs") << "  * Constant SAT due to definition of ops: ";
-      for( int i=0; i<(int)selectionLitTerms.size(); i++ ){
-        Debug("fmf-model-prefs") << selectionLitTerms[i] << " ";
-        d_uf_prefs[ selectionLitTerms[i].getOperator() ].d_reconsiderModel = false;
-      }
-      Debug("fmf-model-prefs") << std::endl;
-    }else{
-      //note quantifier's value preferences to models
-      for( int k=0; k<2; k++ ){
-        for( int j=0; j<(int)pro_con[k].size(); j++ ){
-          Node op = pro_con[k][j].getOperator();
-          Node r = fmig->getRepresentative( pro_con[k][j] );
-          d_uf_prefs[op].setValuePreference( f, pro_con[k][j], r, k==0 );
-        }
-      }
-    }
-  }
-}
-
-int QModelBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){
-  int addedLemmas = 0;
-  //we wish to add all known exceptions to our selection literal for f. this will help to refine our current model.
-  //This step is advantageous over exhaustive instantiation, since we are adding instantiations that involve model basis terms,
-  //  effectively acting as partial instantiations instead of pointwise instantiations.
-  if( !d_quant_selection_lit[f].isNull() ){
-    Trace("inst-gen") << "Do Inst-Gen for " << f << std::endl;
-    for( size_t i=0; i<d_quant_selection_lit_candidates[f].size(); i++ ){
-      bool phase = d_quant_selection_lit_candidates[f][i].getKind()!=NOT;
-      Node lit = d_quant_selection_lit_candidates[f][i].getKind()==NOT ? d_quant_selection_lit_candidates[f][i][0] : d_quant_selection_lit_candidates[f][i];
-      Assert( TermUtil::hasInstConstAttr(lit) );
-      std::vector< Node > tr_terms;
-      if( lit.getKind()==APPLY_UF ){
-        //only match predicates that are contrary to this one, use literal matching
-        Node eq = NodeManager::currentNM()->mkNode(
-            EQUAL, lit, NodeManager::currentNM()->mkConst(!phase));
-        tr_terms.push_back( eq );
-      }else if( lit.getKind()==EQUAL ){
-        //collect trigger terms
-        for( int j=0; j<2; j++ ){
-          if( TermUtil::hasInstConstAttr(lit[j]) ){
-            if( lit[j].getKind()==APPLY_UF ){
-              tr_terms.push_back( lit[j] );
-            }else{
-              tr_terms.clear();
-              break;
-            }
-          }
-        }
-        if( tr_terms.size()==1 && !phase ){
-          //equality between a function and a ground term, use literal matching
-          tr_terms.clear();
-          tr_terms.push_back( lit );
-        }
-      }
-      //if applicable, try to add exceptions here
-      if( !tr_terms.empty() ){
-        //make a trigger for these terms, add instantiations
-        inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, true, inst::Trigger::TR_MAKE_NEW );
-        //Notice() << "Trigger = " << (*tr) << std::endl;
-        tr->resetInstantiationRound();
-        tr->reset( Node::null() );
-        //d_qe->d_optInstMakeRepresentative = false;
-        //d_qe->d_optMatchIgnoreModelBasis = true;
-        addedLemmas += tr->addInstantiations();
-      }
-    }
-  }
-  return addedLemmas;
-}
-
-void QModelBuilderDefault::constructModelUf( FirstOrderModel* fm, Node op ){
-  FirstOrderModelIG* fmig = fm->asFirstOrderModelIG();
-  if( optReconsiderFuncConstants() ){
-    //reconsider constant functions that weren't necessary
-    if( d_uf_model_constructed[op] ){
-      if( d_uf_prefs[op].d_reconsiderModel ){
-        //if we are allowed to reconsider default value, then see if the default value can be improved
-        Node v = d_uf_prefs[op].d_const_val;
-        if( d_uf_prefs[op].d_value_pro_con[0][v].empty() ){
-          Debug("fmf-model-cons-debug") << "Consider changing the default value for " << op << std::endl;
-          fmig->d_uf_model_tree[op].clear();
-          fmig->d_uf_model_gen[op].clear();
-          d_uf_model_constructed[op] = false;
-        }
-      }
-    }
-  }
-  if( !d_uf_model_constructed[op] ){
-    //construct the model for the uninterpretted function/predicate
-    bool setDefaultVal = true;
-    Node defaultTerm = fmig->getModelBasisOpTerm(op);
-    Trace("fmf-model-cons") << "Construct model for " << op << "..." << std::endl;
-    //set the values in the model
-    std::map< Node, std::vector< Node > >::iterator itut = fmig->d_uf_terms.find( op );
-    if( itut!=fmig->d_uf_terms.end() ){
-      for( size_t i=0; i<itut->second.size(); i++ ){
-        Node n = itut->second[i];
-        // only consider unique up to congruence (in model equality engine)?
-        Node v = fmig->getRepresentative( n );
-        Trace("fmf-model-cons") << "Set term " << n << " : "
-                                << fmig->getRepSet()->getIndexFor(v) << " " << v
-                                << std::endl;
-        //if this assertion did not help the model, just consider it ground
-        //set n = v in the model tree
-        //set it as ground value
-        fmig->d_uf_model_gen[op].setValue( fm, n, v );
-        if( fmig->d_uf_model_gen[op].optUsePartialDefaults() ){
-          //also set as default value if necessary
-          if( n.hasAttribute(ModelBasisArgAttribute()) && n.getAttribute(ModelBasisArgAttribute())!=0 ){
-            Trace("fmf-model-cons") << "  Set as default." << std::endl;
-            fmig->d_uf_model_gen[op].setValue( fm, n, v, false );
-            if( n==defaultTerm ){
-              //incidentally already set, we will not need to find a default value
-              setDefaultVal = false;
-            }
-          }
-        }else{
-          if( n==defaultTerm ){
-            fmig->d_uf_model_gen[op].setValue( fm, n, v, false );
-            //incidentally already set, we will not need to find a default value
-            setDefaultVal = false;
-          }
-        }
-      }
-    }
-    //set the overall default value if not set already  (is this necessary??)
-    if( setDefaultVal ){
-      Trace("fmf-model-cons") << "  Choose default value..." << std::endl;
-      //chose defaultVal based on heuristic, currently the best ratio of "pro" responses
-      Node defaultVal = d_uf_prefs[op].getBestDefaultValue( defaultTerm, fm );
-      if( defaultVal.isNull() ){
-        if (!fmig->getRepSet()->hasType(defaultTerm.getType()))
-        {
-          Node mbt = fmig->getModelBasisTerm(defaultTerm.getType());
-          fmig->getRepSetPtr()->d_type_reps[defaultTerm.getType()].push_back(
-              mbt);
-        }
-        defaultVal =
-            fmig->getRepSet()->getRepresentative(defaultTerm.getType(), 0);
-      }
-      Assert( !defaultVal.isNull() );
-      Trace("fmf-model-cons")
-          << "Set default term : " << fmig->getRepSet()->getIndexFor(defaultVal)
-          << std::endl;
-      fmig->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
-    }
-    Debug("fmf-model-cons") << "  Making model...";
-    fmig->d_uf_model_gen[op].makeModel( fm, fmig->d_uf_model_tree[op] );
-    d_uf_model_constructed[op] = true;
-    Debug("fmf-model-cons") << "  Finished constructing model for " << op << "." << std::endl;
-  }
-}
diff --git a/src/theory/quantifiers/model_builder.h b/src/theory/quantifiers/model_builder.h
deleted file mode 100644 (file)
index 4eb592b..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*********************                                                        */
-/*! \file model_builder.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Morgan Deters, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Model Builder class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__MODEL_BUILDER_H
-#define __CVC4__THEORY__QUANTIFIERS__MODEL_BUILDER_H
-
-#include "theory/quantifiers_engine.h"
-#include "theory/theory_model_builder.h"
-#include "theory/uf/theory_uf_model.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-
-class QModelBuilder : public TheoryEngineModelBuilder
-{
-protected:
-  //quantifiers engine
-  QuantifiersEngine* d_qe;
-  bool preProcessBuildModel(TheoryModel* m); //must call preProcessBuildModelStd
-  bool preProcessBuildModelStd(TheoryModel* m);
-  /** number of lemmas generated while building model */
-  unsigned d_addedLemmas;
-  unsigned d_triedLemmas;
-public:
-  QModelBuilder( context::Context* c, QuantifiersEngine* qe );
-
-  //do exhaustive instantiation  
-  // 0 :  failed, but resorting to true exhaustive instantiation may work
-  // >0 : success
-  // <0 : failed
-  virtual int doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) { return false; }
-  //whether to construct model
-  virtual bool optUseModel();
-  /** exist instantiation ? */
-  virtual bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false ) { return false; }
-  //debug model
-  virtual void debugModel( TheoryModel* m );
-  //statistics 
-  unsigned getNumAddedLemmas() { return d_addedLemmas; }
-  unsigned getNumTriedLemmas() { return d_triedLemmas; }
-};
-
-
-
-
-
-class TermArgBasisTrie {
-public:
-  /** the data */
-  std::map< Node, TermArgBasisTrie > d_data;
-  /** add term to the trie */
-  bool addTerm(FirstOrderModel* fm, Node n, unsigned argIndex = 0);
-};/* class TermArgBasisTrie */
-
-/** model builder class
-  *  This class is capable of building candidate models based on the current quantified formulas
-  *  that are asserted.  Use:
-  *  (1) call QModelBuilder::buildModel( m, false );, where m is a FirstOrderModel
-  *  (2) if candidate model is determined to be a real model,
-           then call QModelBuilder::buildModel( m, true );
-  */
-class QModelBuilderIG : public QModelBuilder
-{
-  typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
-
- protected:
-  BoolMap d_basisNoMatch;
-  //map from operators to model preference data
-  std::map< Node, uf::UfModelPreferenceData > d_uf_prefs;
-  //built model uf
-  std::map< Node, bool > d_uf_model_constructed;
-  //whether inst gen was done
-  bool d_didInstGen;
-  /** process build model */
-  virtual bool processBuildModel( TheoryModel* m );
-
- protected:
-  //reset
-  virtual void reset( FirstOrderModel* fm ) = 0;
-  //initialize quantifiers, return number of lemmas produced
-  virtual int initializeQuantifier(Node f, Node fp, FirstOrderModel* fm);
-  //analyze model
-  virtual void analyzeModel( FirstOrderModel* fm );
-  //analyze quantifiers
-  virtual void analyzeQuantifier( FirstOrderModel* fm, Node f ) = 0;
-  //do InstGen techniques for quantifier, return number of lemmas produced
-  virtual int doInstGen( FirstOrderModel* fm, Node f ) = 0;
-  //theory-specific build models
-  virtual void constructModelUf( FirstOrderModel* fm, Node op ) = 0;
-
- protected:
-  //map from quantifiers to if are SAT
-  //std::map< Node, bool > d_quant_sat;
-  //which quantifiers have been initialized
-  std::map< Node, bool > d_quant_basis_match_added;
-  //map from quantifiers to model basis match
-  std::map< Node, InstMatch > d_quant_basis_match;
-
- protected:  // helper functions
-  /** term has constant definition */
-  bool hasConstantDefinition( Node n );
-
- public:
-  QModelBuilderIG( context::Context* c, QuantifiersEngine* qe );
-
- public:
-  /** statistics class */
-  class Statistics {
-  public:
-    IntStat d_num_quants_init;
-    IntStat d_num_partial_quants_init;
-    IntStat d_init_inst_gen_lemmas;
-    IntStat d_inst_gen_lemmas;
-    IntStat d_eval_formulas;
-    IntStat d_eval_uf_terms;
-    IntStat d_eval_lits;
-    IntStat d_eval_lits_unknown;
-    Statistics();
-    ~Statistics();
-  };
-  Statistics d_statistics;
-  // is term selected
-  virtual bool isTermSelected( Node n ) { return false; }
-  /** quantifier has inst-gen definition */
-  virtual bool hasInstGen( Node f ) = 0;
-  /** did inst gen this round? */
-  bool didInstGen() { return d_didInstGen; }
-  // is quantifier active?
-  bool isQuantifierActive( Node f );
-  //do exhaustive instantiation
-  int doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort );
-
-  //temporary stats
-  int d_numQuantSat;
-  int d_numQuantInstGen;
-  int d_numQuantNoInstGen;
-  int d_numQuantNoSelForm;
-  //temporary stat
-  int d_instGenMatches;
-};/* class QModelBuilder */
-
-
-class QModelBuilderDefault : public QModelBuilderIG
-{
- private:  /// information for (old) InstGen
-  // map from quantifiers to their selection literals
-  std::map< Node, Node > d_quant_selection_lit;
-  std::map< Node, std::vector< Node > > d_quant_selection_lit_candidates;
-  //map from quantifiers to their selection literal terms
-  std::map< Node, std::vector< Node > > d_quant_selection_lit_terms;
-  //map from terms to the selection literals they exist in
-  std::map< Node, Node > d_term_selection_lit;
-  //map from operators to terms that appear in selection literals
-  std::map< Node, std::vector< Node > > d_op_selection_terms;
-  //get selection score
-  int getSelectionScore( std::vector< Node >& uf_terms );
-
- protected:
-  //reset
-  void reset(FirstOrderModel* fm) override;
-  //analyze quantifier
-  void analyzeQuantifier(FirstOrderModel* fm, Node f) override;
-  //do InstGen techniques for quantifier, return number of lemmas produced
-  int doInstGen(FirstOrderModel* fm, Node f) override;
-  //theory-specific build models
-  void constructModelUf(FirstOrderModel* fm, Node op) override;
-
- protected:
-  std::map< Node, QuantPhaseReq > d_phase_reqs;
-
- public:
-  QModelBuilderDefault( context::Context* c, QuantifiersEngine* qe ) : QModelBuilderIG( c, qe ){}
-
-  //options
-  bool optReconsiderFuncConstants() { return true; }
-  //has inst gen
-  bool hasInstGen(Node f) override
-  {
-    return !d_quant_selection_lit[f].isNull();
-  }
-};
-
-}/* CVC4::theory::quantifiers namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__MODEL_BUILDER_H */
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
deleted file mode 100644 (file)
index fe6e394..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-/*********************                                                        */
-/*! \file model_engine.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Morgan Deters, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of model engine class
- **/
-
-#include "theory/quantifiers/model_engine.h"
-
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/ambqi_builder.h"
-#include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/full_model_check.h"
-#include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/quantifiers_attributes.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/theory_engine.h"
-#include "theory/uf/equality_engine.h"
-#include "theory/uf/theory_uf.h"
-#include "theory/uf/theory_uf_strong_solver.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace CVC4::theory::inst;
-
-//Model Engine constructor
-ModelEngine::ModelEngine( context::Context* c, QuantifiersEngine* qe ) :
-QuantifiersModule( qe ),
-d_incomplete_check(true),
-d_addedLemmas(0),
-d_triedLemmas(0),
-d_totalLemmas(0)
-{
-
-}
-
-ModelEngine::~ModelEngine() {
-
-}
-
-bool ModelEngine::needsCheck( Theory::Effort e ) {
-  return e==Theory::EFFORT_LAST_CALL;
-}
-
-QuantifiersModule::QEffort ModelEngine::needsModel(Theory::Effort e)
-{
-  if( options::mbqiInterleave() ){
-    return QEFFORT_STANDARD;
-  }else{
-    return QEFFORT_MODEL;
-  }
-}
-
-void ModelEngine::reset_round( Theory::Effort e ) {
-  d_incomplete_check = true;
-}
-void ModelEngine::check(Theory::Effort e, QEffort quant_e)
-{
-  bool doCheck = false;
-  if( options::mbqiInterleave() ){
-    doCheck = quant_e == QEFFORT_STANDARD && d_quantEngine->hasAddedLemma();
-  }
-  if( !doCheck ){
-    doCheck = quant_e == QEFFORT_MODEL;
-  }
-  if( doCheck ){
-    Assert( !d_quantEngine->inConflict() );
-    int addedLemmas = 0;
-    FirstOrderModel* fm = d_quantEngine->getModel();
-
-    //the following will test that the model satisfies all asserted universal quantifiers by
-    // (model-based) exhaustive instantiation.
-    double clSet = 0;
-    if( Trace.isOn("model-engine") ){
-      Trace("model-engine") << "---Model Engine Round---" << std::endl;
-      clSet = double(clock())/double(CLOCKS_PER_SEC);
-    }
-
-    Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl;
-    //let the strong solver verify that the model is minimal
-    //for debugging, this will if there are terms in the model that the strong solver was not notified of
-    uf::StrongSolverTheoryUF * ufss = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getStrongSolver();
-    if( !ufss || ufss->debugModel( fm ) ){
-      Trace("model-engine-debug") << "Check model..." << std::endl;
-      d_incomplete_check = false;
-      //print debug
-      if( Trace.isOn("fmf-model-complete") ){
-        Trace("fmf-model-complete") << std::endl;
-        debugPrint("fmf-model-complete");
-      }
-      //successfully built an acceptable model, now check it
-      addedLemmas += checkModel();
-    }else{
-      addedLemmas++;
-    }
-
-    if( Trace.isOn("model-engine") ){
-      double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
-      Trace("model-engine") << "Finished model engine, time = " << (clSet2-clSet) << std::endl;
-    }
-
-    if( addedLemmas==0 ){
-      Trace("model-engine-debug") << "No lemmas added, incomplete = " << ( d_incomplete_check || !d_incomplete_quants.empty() ) << std::endl;
-      //CVC4 will answer SAT or unknown
-      if( Trace.isOn("fmf-consistent") ){
-        Trace("fmf-consistent") << std::endl;
-        debugPrint("fmf-consistent");
-      }
-    }
-  }
-}
-
-bool ModelEngine::checkComplete() {
-  return !d_incomplete_check;
-}
-
-bool ModelEngine::checkCompleteFor( Node q ) {
-  return std::find( d_incomplete_quants.begin(), d_incomplete_quants.end(), q )==d_incomplete_quants.end();
-}
-
-void ModelEngine::registerQuantifier( Node f ){
-  if( Trace.isOn("fmf-warn") ){
-    bool canHandle = true;
-    for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
-      TypeNode tn = f[0][i].getType();
-      if( !tn.isSort() ){
-        if( !tn.getCardinality().isFinite() ){
-          if( tn.isInteger() ){
-            if( !options::fmfBound() ){
-              canHandle = false;
-            }
-          }else{
-            canHandle = false;
-          }
-        }
-      }
-    }
-    if( !canHandle ){
-      Trace("fmf-warn") << "Warning : Model Engine : may not be able to answer SAT because of formula : " << f << std::endl;
-    }
-  }
-}
-
-void ModelEngine::assertNode( Node f ){
-
-}
-
-bool ModelEngine::optOneQuantPerRound(){
-  return options::fmfOneQuantPerRound();
-}
-
-
-int ModelEngine::checkModel(){
-  FirstOrderModel* fm = d_quantEngine->getModel();
-
-  //flatten the representatives
-  //Trace("model-engine-debug") << "Flattening representatives...." << std::endl;
-  // d_quantEngine->getEqualityQuery()->flattenRepresentatives(
-  // fm->getRepSet()->d_type_reps );
-
-  //for debugging, setup
-  for (std::map<TypeNode, std::vector<Node> >::iterator it =
-           fm->getRepSetPtr()->d_type_reps.begin();
-       it != fm->getRepSetPtr()->d_type_reps.end();
-       ++it)
-  {
-    if( it->first.isSort() ){
-      Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
-      Trace("model-engine-debug") << "        Reps : ";
-      for( size_t i=0; i<it->second.size(); i++ ){
-        Trace("model-engine-debug") << it->second[i] << "  ";
-      }
-      Trace("model-engine-debug") << std::endl;
-      Trace("model-engine-debug") << "   Term reps : ";
-      for( size_t i=0; i<it->second.size(); i++ ){
-        Node r = d_quantEngine->getInternalRepresentative( it->second[i], Node::null(), 0 );
-        Trace("model-engine-debug") << r << " ";
-      }
-      Trace("model-engine-debug") << std::endl;
-      Node mbt = fm->getModelBasisTerm(it->first);
-      Trace("model-engine-debug") << "  Basis term : " << mbt << std::endl;
-    }
-  }
-
-  d_triedLemmas = 0;
-  d_addedLemmas = 0;
-  d_totalLemmas = 0;
-  //for statistics
-  if( Trace.isOn("model-engine") ){
-    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
-      Node f = fm->getAssertedQuantifier( i );
-      if( d_quantEngine->getModel()->isQuantifierActive( f ) && d_quantEngine->hasOwnership( f, this ) ){
-        int totalInst = 1;
-        for( unsigned j=0; j<f[0].getNumChildren(); j++ ){
-          TypeNode tn = f[0][j].getType();
-          if (fm->getRepSet()->hasType(tn))
-          {
-            totalInst =
-                totalInst * (int)fm->getRepSet()->getNumRepresentatives(tn);
-          }
-        }
-        d_totalLemmas += totalInst;
-      }
-    }
-  }
-
-  Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl;
-  // FMC uses two sub-effort levels
-  int e_max = options::mbqiMode()==MBQI_FMC || options::mbqiMode()==MBQI_FMC_INTERVAL ? 2 : ( options::mbqiMode()==MBQI_TRUST ? 0 : 1 );
-  for( int e=0; e<e_max; e++) {
-    d_incomplete_quants.clear();
-    for( unsigned i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
-      Node q = fm->getAssertedQuantifier( i, true );
-      Trace("fmf-exh-inst") << "-> Exhaustive instantiate " << q << ", effort = " << e << "..." << std::endl;
-      //determine if we should check this quantifier
-      if( d_quantEngine->getModel()->isQuantifierActive( q ) && d_quantEngine->hasOwnership( q, this ) ){
-        exhaustiveInstantiate( q, e );
-        if( d_quantEngine->inConflict() || ( optOneQuantPerRound() && d_addedLemmas>0 ) ){
-          break;
-        }
-      }else{
-        Trace("fmf-exh-inst") << "-> Inactive : " << q << std::endl;
-      }
-    }
-    if( d_addedLemmas>0 ){
-      break;
-    }else{
-      Assert( !d_quantEngine->inConflict() );
-    }
-  }
-
-  //print debug information
-  if( d_quantEngine->inConflict() ){
-    Trace("model-engine") << "Conflict, added lemmas = ";
-  }else{
-    Trace("model-engine") << "Added Lemmas = ";
-  } 
-  Trace("model-engine") << d_addedLemmas << " / " << d_triedLemmas << " / ";
-  Trace("model-engine") << d_totalLemmas << std::endl;
-  return d_addedLemmas;
-}
-
-
-
-void ModelEngine::exhaustiveInstantiate( Node f, int effort ){
-  //first check if the builder can do the exhaustive instantiation
-  quantifiers::QModelBuilder * mb = d_quantEngine->getModelBuilder();
-  unsigned prev_alem = mb->getNumAddedLemmas();
-  unsigned prev_tlem = mb->getNumTriedLemmas();
-  int retEi = mb->doExhaustiveInstantiation( d_quantEngine->getModel(), f, effort );
-  if( retEi!=0 ){
-    if( retEi<0 ){
-      Trace("fmf-exh-inst") << "-> Builder determined complete instantiation was impossible." << std::endl;
-      d_incomplete_quants.push_back( f );
-    }else{
-      Trace("fmf-exh-inst") << "-> Builder determined instantiation(s)." << std::endl;
-    }
-    d_triedLemmas += mb->getNumTriedLemmas()-prev_tlem;
-    d_addedLemmas += mb->getNumAddedLemmas()-prev_alem;
-    d_quantEngine->d_statistics.d_instantiations_fmf_mbqi += mb->getNumAddedLemmas();
-  }else{
-    if( Trace.isOn("fmf-exh-inst-debug") ){
-      Trace("fmf-exh-inst-debug") << "   Instantiation Constants: ";
-      for( size_t i=0; i<f[0].getNumChildren(); i++ ){
-        Trace("fmf-exh-inst-debug") << d_quantEngine->getTermUtil()->getInstantiationConstant( f, i ) << " ";
-      }
-      Trace("fmf-exh-inst-debug") << std::endl;
-    }
-    //create a rep set iterator and iterate over the (relevant) domain of the quantifier
-    QRepBoundExt qrbe(d_quantEngine);
-    RepSetIterator riter(d_quantEngine->getModel()->getRepSet(), &qrbe);
-    if( riter.setQuantifier( f ) ){
-      Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter.isIncomplete() << "..." << std::endl;
-      if( !riter.isIncomplete() ){
-        int triedLemmas = 0;
-        int addedLemmas = 0;
-        EqualityQuery* qy = d_quantEngine->getEqualityQuery();
-        Instantiate* inst = d_quantEngine->getInstantiate();
-        while( !riter.isFinished() && ( addedLemmas==0 || !options::fmfOneInstPerRound() ) ){
-          //instantiation was not shown to be true, construct the match
-          InstMatch m( f );
-          for (unsigned i = 0; i < riter.getNumTerms(); i++)
-          {
-            m.set(qy, i, riter.getCurrentTerm(i));
-          }
-          Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl;
-          triedLemmas++;
-          //add as instantiation
-          if (inst->addInstantiation(f, m, true))
-          {
-            addedLemmas++;
-            if( d_quantEngine->inConflict() ){
-              break;
-            }
-          }else{
-            Debug("fmf-model-eval") << "* Failed Add instantiation " << m << std::endl;
-          }
-          riter.increment();
-        }
-        d_addedLemmas += addedLemmas;
-        d_triedLemmas += triedLemmas;
-        d_quantEngine->d_statistics.d_instantiations_fmf_exh += addedLemmas;
-      }
-    }else{
-      Trace("fmf-exh-inst") << "...exhaustive instantiation did set, incomplete=" << riter.isIncomplete() << "..." << std::endl;
-    }
-    //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
-    if( riter.isIncomplete() ){
-      d_incomplete_quants.push_back( f );
-    }
-  }
-}
-
-void ModelEngine::debugPrint( const char* c ){
-  Trace( c ) << "Quantifiers: " << std::endl;
-  for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
-    Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
-    if( d_quantEngine->hasOwnership( q, this ) ){
-      Trace( c ) << "   ";
-      if( !d_quantEngine->getModel()->isQuantifierActive( q ) ){
-        Trace( c ) << "*Inactive* ";
-      }else{
-        Trace( c ) << "           ";
-      }
-      Trace( c ) << q << std::endl;
-    }
-  }
-  //d_quantEngine->getModel()->debugPrint( c );
-}
-
diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h
deleted file mode 100644 (file)
index 840ff42..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*********************                                                        */
-/*! \file model_engine.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Morgan Deters, Andrew Reynolds, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Model Engine class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__MODEL_ENGINE_H
-#define __CVC4__THEORY__QUANTIFIERS__MODEL_ENGINE_H
-
-#include "theory/quantifiers_engine.h"
-#include "theory/quantifiers/model_builder.h"
-#include "theory/theory_model.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class ModelEngine : public QuantifiersModule
-{
-  friend class RepSetIterator;
-private:
-  //options
-  bool optOneQuantPerRound();
-private:
-  //check model
-  int checkModel();
-  //exhaustively instantiate quantifier (possibly using mbqi)
-  void exhaustiveInstantiate( Node f, int effort = 0 );
-private:
-  //temporary statistics
-  //is the exhaustive instantiation incomplete?
-  bool d_incomplete_check;
-  // set of quantified formulas for which check was incomplete
-  std::vector< Node > d_incomplete_quants;
-  int d_addedLemmas;
-  int d_triedLemmas;
-  int d_totalLemmas;
-public:
-  ModelEngine( context::Context* c, QuantifiersEngine* qe );
-  virtual ~ModelEngine();
-public:
-  bool needsCheck( Theory::Effort e );
-  QEffort needsModel(Theory::Effort e);
-  void reset_round( Theory::Effort e );
-  void check(Theory::Effort e, QEffort quant_e);
-  bool checkComplete();
-  bool checkCompleteFor( Node q );
-  void registerQuantifier( Node f );
-  void assertNode( Node f );
-  Node explain(TNode n){ return Node::null(); }
-  void debugPrint( const char* c );
-  /** Identify this module */
-  std::string identify() const { return "ModelEngine"; }
-};/* class ModelEngine */
-
-}/* CVC4::theory::quantifiers namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__MODEL_ENGINE_H */
index 23e2ad721e60c2c13243679e0635ce9673872031..efc2f3064fe660f9362b9e522754281e1c254d10 100644 (file)
@@ -24,7 +24,7 @@
 #include "theory/quantifiers/quant_util.h"
 #include "theory/quantifiers/term_database.h"
 #include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/ematching/trigger.h"
 #include "theory/theory_engine.h"
 
 using namespace CVC4::kind;
index 92d42d5787d3c1d6b48a2098d29095a63ae8c74e..d80a7cf821bfa9c582d40fd8cb01efa630e04573 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "theory/quantifiers_engine.h"
 #include "options/quantifiers_options.h"
-#include "theory/quantifiers/ce_guided_instantiation.h"
+#include "theory/quantifiers/sygus/ce_guided_instantiation.h"
 #include "theory/quantifiers/fun_def_engine.h"
 #include "theory/quantifiers/rewrite_engine.h"
 #include "theory/quantifiers/term_util.h"
index 472316cae647ff8b7b477b23543b06f786af129d..5586c04fb762479b09fa8e443df6a485de7e9e9b 100644 (file)
@@ -21,7 +21,7 @@
 #include "theory/quantifiers/skolemize.h"
 #include "theory/quantifiers/term_database.h"
 #include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/ematching/trigger.h"
 
 using namespace std;
 using namespace CVC4::kind;
index 922a8cce6b9f01701e32eebded660aa108be7f43..7f78eb049392d5233ab1416a862c46677f2bbe7b 100644 (file)
@@ -18,9 +18,9 @@
 
 #include "options/quantifiers_options.h"
 #include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/inst_match_generator.h"
+#include "theory/quantifiers/ematching/inst_match_generator.h"
 #include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/model_engine.h"
+#include "theory/quantifiers/fmf/model_engine.h"
 #include "theory/quantifiers/quant_conflict_find.h"
 #include "theory/quantifiers/quant_util.h"
 #include "theory/quantifiers/quantifiers_attributes.h"
index cfca96259a92b9d443f16c377e77fd86e94fe5eb..2253ac1dad72617591faa18b896b1c95ecd6e8a6 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "context/context.h"
 #include "context/context_mm.h"
-#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/ematching/trigger.h"
 #include "theory/quantifiers/quant_conflict_find.h"
 #include "theory/quantifiers_engine.h"
 
diff --git a/src/theory/quantifiers/sygus/ce_guided_conjecture.cpp b/src/theory/quantifiers/sygus/ce_guided_conjecture.cpp
new file mode 100644 (file)
index 0000000..7bcaa0c
--- /dev/null
@@ -0,0 +1,894 @@
+/*********************                                                        */
+/*! \file ce_guided_conjecture.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief implementation of class that encapsulates counterexample-guided instantiation
+ **        techniques for a single SyGuS synthesis conjecture
+ **/
+#include "theory/quantifiers/sygus/ce_guided_conjecture.h"
+
+#include "expr/datatype.h"
+#include "options/base_options.h"
+#include "options/quantifiers_options.h"
+#include "printer/printer.h"
+#include "prop/prop_engine.h"
+#include "smt/smt_statistics_registry.h"
+#include "theory/quantifiers/sygus/ce_guided_instantiation.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/instantiate.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/skolemize.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/theory_engine.h"
+
+using namespace CVC4::kind;
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+// recursion is not an issue since OR nodes are flattened by the (quantifiers) rewriter
+// this function is for sanity since solution correctness in SyGuS depends on fully miniscoping based on this function
+void collectDisjuncts( Node n, std::vector< Node >& d ) {
+  if( n.getKind()==OR ){
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      collectDisjuncts( n[i], d );
+    }
+  }else{
+    d.push_back( n );
+  }
+}
+
+CegConjecture::CegConjecture(QuantifiersEngine* qe)
+    : d_qe(qe),
+      d_ceg_si(new CegConjectureSingleInv(qe, this)),
+      d_ceg_pbe(new CegConjecturePbe(qe, this)),
+      d_ceg_proc(new CegConjectureProcess(qe)),
+      d_ceg_gc(new CegGrammarConstructor(qe, this)),
+      d_refine_count(0),
+      d_syntax_guided(false) {}
+
+CegConjecture::~CegConjecture() {}
+
+void CegConjecture::assign( Node q ) {
+  Assert( d_embed_quant.isNull() );
+  Assert( q.getKind()==FORALL );
+  Trace("cegqi") << "CegConjecture : assign : " << q << std::endl;
+  d_quant = q;
+
+  // pre-simplify the quantified formula based on the process utility
+  d_simp_quant = d_ceg_proc->preSimplify(d_quant);
+
+  std::map< Node, Node > templates; 
+  std::map< Node, Node > templates_arg;
+  //register with single invocation if applicable
+  if (d_qe->getQuantAttributes()->isSygus(q))
+  {
+    d_ceg_si->initialize(d_simp_quant);
+    d_simp_quant = d_ceg_si->getSimplifiedConjecture();
+    // carry the templates
+    for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+      Node v = q[0][i];
+      Node templ = d_ceg_si->getTemplate(v);
+      if( !templ.isNull() ){
+        templates[v] = templ;
+        templates_arg[v] = d_ceg_si->getTemplateArg(v);
+      }
+    }
+  }
+
+  // post-simplify the quantified formula based on the process utility
+  d_simp_quant = d_ceg_proc->postSimplify(d_simp_quant);
+
+  // finished simplifying the quantified formula at this point
+
+  // convert to deep embedding and finalize single invocation here
+  d_embed_quant = d_ceg_gc->process(d_simp_quant, templates, templates_arg);
+  Trace("cegqi") << "CegConjecture : converted to embedding : " << d_embed_quant << std::endl;
+
+  // we now finalize the single invocation module, based on the syntax restrictions
+  if (d_qe->getQuantAttributes()->isSygus(q))
+  {
+    d_ceg_si->finishInit( d_ceg_gc->isSyntaxRestricted(), d_ceg_gc->hasSyntaxITE() );
+  }
+
+  Assert( d_candidates.empty() );
+  std::vector< Node > vars;
+  for( unsigned i=0; i<d_embed_quant[0].getNumChildren(); i++ ){
+    vars.push_back( d_embed_quant[0][i] );
+    Node e = NodeManager::currentNM()->mkSkolem( "e", d_embed_quant[0][i].getType() );
+    d_candidates.push_back( e );
+  }
+  Trace("cegqi") << "Base quantified formula is : " << d_embed_quant << std::endl;
+  //construct base instantiation
+  d_base_inst = Rewriter::rewrite(d_qe->getInstantiate()->getInstantiation(
+      d_embed_quant, vars, d_candidates));
+  Trace("cegqi") << "Base instantiation is :      " << d_base_inst << std::endl;
+  d_base_body = d_base_inst;
+  if (d_base_body.getKind() == NOT && d_base_body[0].getKind() == FORALL)
+  {
+    for (const Node& v : d_base_body[0][0])
+    {
+      d_base_vars.push_back(v);
+    }
+    d_base_body = d_base_body[0][1];
+  }
+
+  // register this term with sygus database and other utilities that impact
+  // the enumerative sygus search
+  std::vector< Node > guarded_lemmas;
+  if( !isSingleInvocation() ){
+    d_ceg_proc->initialize(d_base_inst, d_candidates);
+    if( options::sygusPbe() ){
+      d_ceg_pbe->initialize(d_base_inst, d_candidates, guarded_lemmas);
+    } else {
+      for (unsigned i = 0; i < d_candidates.size(); i++) {
+        Node e = d_candidates[i];
+        d_qe->getTermDatabaseSygus()->registerEnumerator(e, e, this);
+      }
+    }
+  }
+
+  if (d_qe->getQuantAttributes()->isSygus(q))
+  {
+    collectDisjuncts( d_base_inst, d_base_disj );
+    Trace("cegqi") << "Conjecture has " << d_base_disj.size() << " disjuncts." << std::endl;
+    //store the inner variables for each disjunct
+    for( unsigned j=0; j<d_base_disj.size(); j++ ){
+      Trace("cegqi") << "  " << j << " : " << d_base_disj[j] << std::endl;
+      d_inner_vars_disj.push_back( std::vector< Node >() );
+      //if the disjunct is an existential, store it
+      if( d_base_disj[j].getKind()==NOT && d_base_disj[j][0].getKind()==FORALL ){
+        for( unsigned k=0; k<d_base_disj[j][0][0].getNumChildren(); k++ ){
+          d_inner_vars.push_back( d_base_disj[j][0][0][k] );
+          d_inner_vars_disj[j].push_back( d_base_disj[j][0][0][k] );
+        }
+      }
+    }
+    d_syntax_guided = true;
+  }
+  else if (d_qe->getQuantAttributes()->isSynthesis(q))
+  {
+    d_syntax_guided = false;
+  }else{
+    Assert( false );
+  }
+  
+  // initialize the guard
+  if( !d_syntax_guided ){
+    if( d_nsg_guard.isNull() ){
+      d_nsg_guard = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "G", NodeManager::currentNM()->booleanType() ) );
+      d_nsg_guard = d_qe->getValuation().ensureLiteral( d_nsg_guard );
+      AlwaysAssert( !d_nsg_guard.isNull() );
+      d_qe->getOutputChannel().requirePhase( d_nsg_guard, true );
+      // negated base as a guarded lemma
+      guarded_lemmas.push_back( d_base_inst.negate() );
+    }
+  }else if( d_ceg_si->getGuard().isNull() ){
+    std::vector< Node > lems;
+    d_ceg_si->getInitialSingleInvLemma( lems );
+    for( unsigned i=0; i<lems.size(); i++ ){
+      Trace("cegqi-lemma") << "Cegqi::Lemma : single invocation " << i << " : " << lems[i] << std::endl;
+      d_qe->getOutputChannel().lemma( lems[i] );
+      if( Trace.isOn("cegqi-debug") ){
+        Node rlem = Rewriter::rewrite( lems[i] );
+        Trace("cegqi-debug") << "...rewritten : " << rlem << std::endl;
+      }
+    }
+  }
+  Assert( !getGuard().isNull() );
+  Node gneg = getGuard().negate();
+  for( unsigned i=0; i<guarded_lemmas.size(); i++ ){
+    Node lem = NodeManager::currentNM()->mkNode( OR, gneg, guarded_lemmas[i] );
+    Trace("cegqi-lemma") << "Cegqi::Lemma : initial (guarded) lemma : " << lem << std::endl;
+    d_qe->getOutputChannel().lemma( lem );
+  }
+
+  // assign the cegis sampler if applicable
+  if (options::cegisSample() != CEGIS_SAMPLE_NONE)
+  {
+    Trace("cegis-sample") << "Initialize sampler for " << d_base_body << "..."
+                          << std::endl;
+    TypeNode bt = d_base_body.getType();
+    d_cegis_sampler.initialize(bt, d_base_vars, options::sygusSamples());
+  }
+
+  Trace("cegqi") << "...finished, single invocation = " << isSingleInvocation() << std::endl;
+}
+
+Node CegConjecture::getGuard() {
+  return !d_syntax_guided ? d_nsg_guard : d_ceg_si->getGuard();
+}
+
+bool CegConjecture::isSingleInvocation() const {
+  return d_ceg_si->isSingleInvocation();
+}
+
+bool CegConjecture::needsCheck( std::vector< Node >& lem ) {
+  if( isSingleInvocation() && !d_ceg_si->needsCheck() ){
+    return false;
+  }else{
+    bool value;
+    Assert( !getGuard().isNull() );
+    // non or fully single invocation : look at guard only
+    if( d_qe->getValuation().hasSatValue( getGuard(), value ) ) {
+      if( !value ){
+        Trace("cegqi-engine-debug") << "Conjecture is infeasible." << std::endl;
+        return false;
+      }
+    }else{
+      Assert( false );
+    }
+    return true;
+  }
+}
+
+
+void CegConjecture::doSingleInvCheck(std::vector< Node >& lems) {
+  if( d_ceg_si!=NULL ){
+    d_ceg_si->check(lems);
+  }
+}
+
+void CegConjecture::doBasicCheck(std::vector< Node >& lems) {
+  std::vector< Node > model_terms;
+  std::vector< Node > clist;
+  getCandidateList( clist, true );
+  Assert( clist.size()==d_quant[0].getNumChildren() );
+  getModelValues( clist, model_terms );
+  if (d_qe->getInstantiate()->addInstantiation(d_quant, model_terms))
+  {
+    //record the instantiation
+    recordInstantiation( model_terms );
+  }else{
+    Assert( false );
+  }
+}
+
+bool CegConjecture::needsRefinement() { 
+  return !d_ce_sk.empty();
+}
+
+void CegConjecture::getCandidateList( std::vector< Node >& clist, bool forceOrig ) {
+  if( d_ceg_pbe->isPbe() && !forceOrig ){
+    d_ceg_pbe->getCandidateList( d_candidates, clist );
+  }else{
+    clist.insert( clist.end(), d_candidates.begin(), d_candidates.end() );
+  }
+}
+
+bool CegConjecture::constructCandidates( std::vector< Node >& clist, std::vector< Node >& model_values, std::vector< Node >& candidate_values, 
+                                         std::vector< Node >& lems ) {
+  Assert( clist.size()==model_values.size() );
+  if( d_ceg_pbe->isPbe() ){
+    return d_ceg_pbe->constructCandidates( clist, model_values, d_candidates, candidate_values, lems );
+  }else{
+    Assert( model_values.size()==d_candidates.size() );
+    candidate_values.insert( candidate_values.end(), model_values.begin(), model_values.end() );
+  }
+  return true;
+}
+
+void CegConjecture::doCheck(std::vector< Node >& lems, std::vector< Node >& model_values) {
+  std::vector< Node > clist;
+  getCandidateList( clist );
+  std::vector< Node > c_model_values;
+  Trace("cegqi-check") << "CegConjuncture : check, build candidates..." << std::endl;
+  bool constructed_cand = constructCandidates( clist, model_values, c_model_values, lems );
+
+  //must get a counterexample to the value of the current candidate
+  Node inst;
+  if( constructed_cand ){
+    if( Trace.isOn("cegqi-check")  ){
+      Trace("cegqi-check") << "CegConjuncture : check candidate : " << std::endl;
+      for( unsigned i=0; i<c_model_values.size(); i++ ){
+        Trace("cegqi-check") << "  " << i << " : " << d_candidates[i] << " -> " << c_model_values[i] << std::endl;
+      }
+    }
+    Assert( c_model_values.size()==d_candidates.size() );
+    inst = d_base_inst.substitute( d_candidates.begin(), d_candidates.end(), c_model_values.begin(), c_model_values.end() );
+  }else{
+    inst = d_base_inst;
+  }
+  
+  //check whether we will run CEGIS on inner skolem variables
+  bool sk_refine = ( !isGround() || d_refine_count==0 ) && ( !d_ceg_pbe->isPbe() || constructed_cand );
+  if( sk_refine ){
+    if (options::cegisSample() == CEGIS_SAMPLE_TRUST)
+    {
+      // we have that the current candidate passed a sample test
+      // since we trust sampling in this mode, we assert there is no
+      // counterexample to the conjecture here.
+      NodeManager* nm = NodeManager::currentNM();
+      Node lem = nm->mkNode(OR, d_quant.negate(), nm->mkConst(false));
+      lem = getStreamGuardedLemma(lem);
+      lems.push_back(lem);
+      recordInstantiation(c_model_values);
+      return;
+    }
+    Assert( d_ce_sk.empty() );
+    d_ce_sk.push_back( std::vector< Node >() );
+  }else{
+    if( !constructed_cand ){
+      return;
+    }
+  }
+  
+  std::vector< Node > ic;
+  ic.push_back( d_quant.negate() );
+  std::vector< Node > d;
+  collectDisjuncts( inst, d );
+  Assert( d.size()==d_base_disj.size() );
+  //immediately skolemize inner existentials
+  for( unsigned i=0; i<d.size(); i++ ){
+    Node dr = Rewriter::rewrite( d[i] );
+    if( dr.getKind()==NOT && dr[0].getKind()==FORALL ){
+      if( constructed_cand ){
+        ic.push_back(d_qe->getSkolemize()->getSkolemizedBody(dr[0]).negate());
+      }
+      if( sk_refine ){
+        Assert( !isGround() );
+        d_ce_sk.back().push_back( dr[0] );
+      }
+    }else{
+      if( constructed_cand ){
+        ic.push_back( dr );
+        if( !d_inner_vars_disj[i].empty() ){
+          Trace("cegqi-debug") << "*** quantified disjunct : " << d[i] << " simplifies to " << dr << std::endl;
+        }
+      }
+      if( sk_refine ){
+        d_ce_sk.back().push_back( Node::null() );
+      }
+    }
+  }
+  if( constructed_cand ){
+    Node lem = NodeManager::currentNM()->mkNode( OR, ic );
+    lem = Rewriter::rewrite( lem );
+    //eagerly unfold applications of evaluation function
+    if( options::sygusDirectEval() ){
+      Trace("cegqi-debug") << "pre-unfold counterexample : " << lem << std::endl;
+      std::map< Node, Node > visited_n;
+      lem = d_qe->getTermDatabaseSygus()->getEagerUnfold( lem, visited_n );
+    }
+    lem = getStreamGuardedLemma(lem);
+    lems.push_back( lem );
+    recordInstantiation( c_model_values );
+  }
+}
+        
+void CegConjecture::doRefine( std::vector< Node >& lems ){
+  Assert( lems.empty() );
+  Assert( d_ce_sk.size()==1 );
+
+  //first, make skolem substitution
+  Trace("cegqi-refine") << "doRefine : construct skolem substitution..." << std::endl;
+  std::vector< Node > sk_vars;
+  std::vector< Node > sk_subs;
+  //collect the substitution over all disjuncts
+  for( unsigned k=0; k<d_ce_sk[0].size(); k++ ){
+    Node ce_q = d_ce_sk[0][k];
+    if( !ce_q.isNull() ){
+      Assert( !d_inner_vars_disj[k].empty() );
+      std::vector<Node> skolems;
+      d_qe->getSkolemize()->getSkolemConstants(ce_q, skolems);
+      Assert(d_inner_vars_disj[k].size() == skolems.size());
+      std::vector< Node > model_values;
+      getModelValues(skolems, model_values);
+      sk_vars.insert( sk_vars.end(), d_inner_vars_disj[k].begin(), d_inner_vars_disj[k].end() );
+      sk_subs.insert( sk_subs.end(), model_values.begin(), model_values.end() );
+    }else{
+      if( !d_inner_vars_disj[k].empty() ){
+        //denegrate case : quantified disjunct was trivially true and does not need to be refined
+        //add trivial substitution (in case we need substitution for previous cex's)
+        for( unsigned i=0; i<d_inner_vars_disj[k].size(); i++ ){
+          sk_vars.push_back( d_inner_vars_disj[k][i] );
+          sk_subs.push_back( getModelValue( d_inner_vars_disj[k][i] ) ); // will return dummy value
+        }
+      }
+    }
+  } 
+  
+  //for conditional evaluation
+  std::vector< Node > lem_c;
+  Assert( d_ce_sk[0].size()==d_base_disj.size() );
+  std::vector< Node > inst_cond_c;
+  Trace("cegqi-refine") << "doRefine : Construct refinement lemma..." << std::endl;
+  for( unsigned k=0; k<d_ce_sk[0].size(); k++ ){
+    Node ce_q = d_ce_sk[0][k];
+    Trace("cegqi-refine-debug") << "  For counterexample point, disjunct " << k << " : " << ce_q << " " << d_base_disj[k] << std::endl;
+    Node c_disj;
+    if( !ce_q.isNull() ){
+      Assert( d_base_disj[k].getKind()==kind::NOT && d_base_disj[k][0].getKind()==kind::FORALL );
+      c_disj = d_base_disj[k][0][1];
+    }else{
+      if( d_inner_vars_disj[k].empty() ){
+        c_disj = d_base_disj[k].negate();
+      }else{
+        //denegrate case : quantified disjunct was trivially true and does not need to be refined
+        Trace("cegqi-refine-debug") << "*** skip " << d_base_disj[k] << std::endl;
+      }
+    }
+    if( !c_disj.isNull() ){
+      //compute the body, inst_cond
+      //standard CEGIS refinement : plug in values, assert that d_candidates must satisfy entire specification
+      lem_c.push_back( c_disj );
+    }
+  }
+  Assert( sk_vars.size()==sk_subs.size() );
+  
+  Node base_lem = lem_c.size()==1 ? lem_c[0] : NodeManager::currentNM()->mkNode( AND, lem_c );
+  
+  Trace("cegqi-refine") << "doRefine : construct and finalize lemmas..." << std::endl;
+  
+  
+  base_lem = base_lem.substitute( sk_vars.begin(), sk_vars.end(), sk_subs.begin(), sk_subs.end() );
+  base_lem = Rewriter::rewrite( base_lem );
+  d_refinement_lemmas.push_back(base_lem);
+
+  Node lem =
+      NodeManager::currentNM()->mkNode(OR, getGuard().negate(), base_lem);
+  lems.push_back( lem );
+
+  d_ce_sk.clear();
+}
+
+void CegConjecture::preregisterConjecture( Node q ) {
+  d_ceg_si->preregisterConjecture( q );
+}
+
+void CegConjecture::getModelValues( std::vector< Node >& n, std::vector< Node >& v ) {
+  Trace("cegqi-engine") << "  * Value is : ";
+  for( unsigned i=0; i<n.size(); i++ ){
+    Node nv = getModelValue( n[i] );
+    v.push_back( nv );
+    if( Trace.isOn("cegqi-engine") ){
+      TypeNode tn = nv.getType();
+      Trace("cegqi-engine") << n[i] << " -> ";
+      std::stringstream ss;
+      Printer::getPrinter(options::outputLanguage())->toStreamSygus(ss, nv);
+      Trace("cegqi-engine") << ss.str() << " ";
+      if (Trace.isOn("cegqi-engine-rr"))
+      {
+        Node bv = d_qe->getTermDatabaseSygus()->sygusToBuiltin(nv, tn);
+        bv = Rewriter::rewrite(bv);
+        Trace("cegqi-engine-rr") << " -> " << bv << std::endl;
+      }
+    }
+    Assert( !nv.isNull() );
+  }
+  Trace("cegqi-engine") << std::endl;
+}
+
+Node CegConjecture::getModelValue( Node n ) {
+  Trace("cegqi-mv") << "getModelValue for : " << n << std::endl;
+  return d_qe->getModel()->getValue( n );
+}
+
+void CegConjecture::debugPrint( const char * c ) {
+  Trace(c) << "Synthesis conjecture : " << d_embed_quant << std::endl;
+  Trace(c) << "  * Candidate program/output symbol : ";
+  for( unsigned i=0; i<d_candidates.size(); i++ ){
+    Trace(c) << d_candidates[i] << " ";
+  }
+  Trace(c) << std::endl;
+  Trace(c) << "  * Candidate ce skolems : ";
+  for( unsigned i=0; i<d_ce_sk.size(); i++ ){
+    Trace(c) << d_ce_sk[i] << " ";
+  }
+}
+
+Node CegConjecture::getCurrentStreamGuard() const {
+  if( d_stream_guards.empty() ){
+    return Node::null();
+  }else{
+    return d_stream_guards.back();
+  }
+}
+
+Node CegConjecture::getStreamGuardedLemma(Node n) const
+{
+  if (options::sygusStream())
+  {
+    // if we are in streaming mode, we guard with the current stream guard
+    Node csg = getCurrentStreamGuard();
+    Assert(!csg.isNull());
+    return NodeManager::currentNM()->mkNode(kind::OR, csg.negate(), n);
+  }
+  return n;
+}
+
+Node CegConjecture::getNextDecisionRequest( unsigned& priority ) {
+  // first, must try the guard
+  // which denotes "this conjecture is feasible"
+  Node feasible_guard = getGuard();
+  bool value;
+  if( !d_qe->getValuation().hasSatValue( feasible_guard, value ) ) {
+    priority = 0;
+    return feasible_guard;
+  }else{
+    if( value ){  
+      // the conjecture is feasible
+      if( options::sygusStream() ){
+        Assert( !isSingleInvocation() );
+        // if we are in sygus streaming mode, then get the "next guard" 
+        // which denotes "we have not yet generated the next solution to the conjecture"
+        Node curr_stream_guard = getCurrentStreamGuard();
+        bool needs_new_stream_guard = false;
+        if( curr_stream_guard.isNull() ){
+          needs_new_stream_guard = true;
+        }else{
+          // check the polarity of the guard
+          if( !d_qe->getValuation().hasSatValue( curr_stream_guard, value ) ) {
+            priority = 0;
+            return curr_stream_guard;
+          }else{
+            if( !value ){
+              Trace("cegqi-debug") << "getNextDecision : we have a new solution since stream guard was propagated false: " << curr_stream_guard << std::endl;
+              // we have generated a solution, print it
+              // get the current output stream
+              // this output stream should coincide with wherever --dump-synth is output on
+              Options& nodeManagerOptions = NodeManager::currentNM()->getOptions();
+              printSynthSolution( *nodeManagerOptions.getOut(), false );
+              // need to make the next stream guard
+              needs_new_stream_guard = true;
+              
+              // We will not refine the current candidate solution since it is a solution
+              // thus, we clear information regarding the current refinement
+              d_ce_sk.clear();
+              // However, we need to exclude the current solution using an explicit refinement 
+              // so that we proceed to the next solution. 
+              std::vector< Node > clist;
+              getCandidateList( clist );
+              Trace("cegqi-debug") << "getNextDecision : solution was : " << std::endl;
+              std::vector< Node > exp;
+              for( unsigned i=0; i<clist.size(); i++ ){
+                Node cprog = clist[i];
+                Node sol = cprog;
+                if( !d_cinfo[cprog].d_inst.empty() ){
+                  sol = d_cinfo[cprog].d_inst.back();
+                  // add to explanation of exclusion
+                  d_qe->getTermDatabaseSygus()
+                      ->getExplain()
+                      ->getExplanationForConstantEquality(cprog, sol, exp);
+                }
+                Trace("cegqi-debug") << "  " << cprog << " -> " << sol << std::endl;
+              }
+              Assert( !exp.empty() );
+              Node exc_lem = exp.size()==1 ? exp[0] : NodeManager::currentNM()->mkNode( kind::AND, exp );
+              exc_lem = exc_lem.negate();
+              Trace("cegqi-lemma") << "Cegqi::Lemma : stream exclude current solution : " << exc_lem << std::endl;
+              d_qe->getOutputChannel().lemma( exc_lem );
+            }
+          }
+        }
+        if( needs_new_stream_guard ){
+          // generate a new stream guard
+          curr_stream_guard = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "G_Stream", NodeManager::currentNM()->booleanType() ) );
+          curr_stream_guard = d_qe->getValuation().ensureLiteral( curr_stream_guard );
+          AlwaysAssert( !curr_stream_guard.isNull() );
+          d_qe->getOutputChannel().requirePhase( curr_stream_guard, true );
+          d_stream_guards.push_back( curr_stream_guard );
+          Trace("cegqi-debug") << "getNextDecision : allocate new stream guard : " << curr_stream_guard << std::endl;
+          // return it as a decision
+          priority = 0;
+          return curr_stream_guard;
+        }
+      }
+    }else{
+      Trace("cegqi-debug") << "getNextDecision : conjecture is infeasible." << std::endl;
+    } 
+  }
+  return Node::null();
+}
+
+void CegConjecture::printSynthSolution( std::ostream& out, bool singleInvocation ) {
+  Trace("cegqi-debug") << "Printing synth solution..." << std::endl;
+  Assert( d_quant[0].getNumChildren()==d_embed_quant[0].getNumChildren() );
+  std::vector<Node> sols;
+  std::vector<int> statuses;
+  getSynthSolutionsInternal(sols, statuses, singleInvocation);
+  for (unsigned i = 0, size = d_embed_quant[0].getNumChildren(); i < size; i++)
+  {
+    Node sol = sols[i];
+    if (!sol.isNull())
+    {
+      Node prog = d_embed_quant[0][i];
+      int status = statuses[i];
+      TypeNode tn = prog.getType();
+      const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
+      std::stringstream ss;
+      ss << prog;
+      std::string f(ss.str());
+      f.erase(f.begin());
+      out << "(define-fun " << f << " ";
+      if( dt.getSygusVarList().isNull() ){
+        out << "() ";
+      }else{
+        out << dt.getSygusVarList() << " ";
+      }
+      out << dt.getSygusType() << " ";
+      if( status==0 ){
+        out << sol;
+      }else{
+        Printer::getPrinter(options::outputLanguage())->toStreamSygus(out, sol);
+      }
+      out << ")" << std::endl;
+      CegInstantiation* cei = d_qe->getCegInstantiation();
+      ++(cei->d_statistics.d_solutions);
+
+      if (status != 0 && options::sygusRewSynth())
+      {
+        TermDbSygus* sygusDb = d_qe->getTermDatabaseSygus();
+        std::map<Node, SygusSamplerExt>::iterator its = d_sampler.find(prog);
+        if (its == d_sampler.end())
+        {
+          d_sampler[prog].initializeSygusExt(
+              d_qe, prog, options::sygusSamples());
+          its = d_sampler.find(prog);
+        }
+        Node solb = sygusDb->sygusToBuiltin(sol, prog.getType());
+        Node eq_sol = its->second.registerTerm(solb);
+        // eq_sol is a candidate solution that is equivalent to sol
+        if (eq_sol != solb)
+        {
+          ++(cei->d_statistics.d_candidate_rewrites);
+          if (!eq_sol.isNull())
+          {
+            // Terms solb and eq_sol are equivalent under sample points but do
+            // not rewrite to the same term. Hence, this indicates a candidate
+            // rewrite.
+            out << "(candidate-rewrite " << solb << " " << eq_sol << ")"
+                << std::endl;
+            ++(cei->d_statistics.d_candidate_rewrites_print);
+            // debugging information
+            if (Trace.isOn("sygus-rr-debug"))
+            {
+              ExtendedRewriter* er = sygusDb->getExtRewriter();
+              Node solbr = er->extendedRewrite(solb);
+              Node eq_solr = er->extendedRewrite(eq_sol);
+              Trace("sygus-rr-debug")
+                  << "; candidate #1 ext-rewrites to: " << solbr << std::endl;
+              Trace("sygus-rr-debug")
+                  << "; candidate #2 ext-rewrites to: " << eq_solr << std::endl;
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+void CegConjecture::getSynthSolutions(std::map<Node, Node>& sol_map,
+                                      bool singleInvocation)
+{
+  NodeManager* nm = NodeManager::currentNM();
+  TermDbSygus* sygusDb = d_qe->getTermDatabaseSygus();
+  std::vector<Node> sols;
+  std::vector<int> statuses;
+  getSynthSolutionsInternal(sols, statuses, singleInvocation);
+  for (unsigned i = 0, size = d_embed_quant[0].getNumChildren(); i < size; i++)
+  {
+    Node sol = sols[i];
+    int status = statuses[i];
+    // get the builtin solution
+    Node bsol = sol;
+    if (status != 0)
+    {
+      // convert sygus to builtin here
+      bsol = sygusDb->sygusToBuiltin(sol, sol.getType());
+    }
+    // convert to lambda
+    TypeNode tn = d_embed_quant[0][i].getType();
+    const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
+    Node bvl = Node::fromExpr(dt.getSygusVarList());
+    if (!bvl.isNull())
+    {
+      bsol = nm->mkNode(LAMBDA, bvl, bsol);
+    }
+    // store in map
+    Node fvar = d_quant[0][i];
+    Assert(fvar.getType() == bsol.getType());
+    sol_map[fvar] = bsol;
+  }
+}
+
+void CegConjecture::getSynthSolutionsInternal(std::vector<Node>& sols,
+                                              std::vector<int>& statuses,
+                                              bool singleInvocation)
+{
+  for (unsigned i = 0, size = d_embed_quant[0].getNumChildren(); i < size; i++)
+  {
+    Node prog = d_embed_quant[0][i];
+    Trace("cegqi-debug") << "  get solution for " << prog << std::endl;
+    TypeNode tn = prog.getType();
+    Assert(tn.isDatatype());
+    // get the solution
+    Node sol;
+    int status = -1;
+    if (singleInvocation)
+    {
+      Assert(d_ceg_si != NULL);
+      sol = d_ceg_si->getSolution(i, tn, status, true);
+      if (!sol.isNull())
+      {
+        sol = sol.getKind() == LAMBDA ? sol[1] : sol;
+      }
+    }
+    else
+    {
+      Node cprog = getCandidate(i);
+      if (!d_cinfo[cprog].d_inst.empty())
+      {
+        // the solution is just the last instantiated term
+        sol = d_cinfo[cprog].d_inst.back();
+        status = 1;
+
+        // check if there was a template
+        Node sf = d_quant[0][i];
+        Node templ = d_ceg_si->getTemplate(sf);
+        if (!templ.isNull())
+        {
+          Trace("cegqi-inv-debug")
+              << sf << " used template : " << templ << std::endl;
+          // if it was not embedded into the grammar
+          if (!options::sygusTemplEmbedGrammar())
+          {
+            TNode templa = d_ceg_si->getTemplateArg(sf);
+            // make the builtin version of the full solution
+            TermDbSygus* sygusDb = d_qe->getTermDatabaseSygus();
+            sol = sygusDb->sygusToBuiltin(sol, sol.getType());
+            Trace("cegqi-inv") << "Builtin version of solution is : " << sol
+                               << ", type : " << sol.getType() << std::endl;
+            TNode tsol = sol;
+            sol = templ.substitute(templa, tsol);
+            Trace("cegqi-inv-debug") << "With template : " << sol << std::endl;
+            sol = Rewriter::rewrite(sol);
+            Trace("cegqi-inv-debug") << "Simplified : " << sol << std::endl;
+            // now, reconstruct to the syntax
+            sol = d_ceg_si->reconstructToSyntax(sol, tn, status, true);
+            sol = sol.getKind() == LAMBDA ? sol[1] : sol;
+            Trace("cegqi-inv-debug")
+                << "Reconstructed to syntax : " << sol << std::endl;
+          }
+          else
+          {
+            Trace("cegqi-inv-debug")
+                << "...was embedding into grammar." << std::endl;
+          }
+        }
+        else
+        {
+          Trace("cegqi-inv-debug")
+              << sf << " did not use template" << std::endl;
+        }
+      }
+      else
+      {
+        Trace("cegqi-warn") << "WARNING : No recorded instantiations for "
+                               "syntax-guided solution!"
+                            << std::endl;
+      }
+    }
+    sols.push_back(sol);
+    statuses.push_back(status);
+  }
+}
+
+Node CegConjecture::getSymmetryBreakingPredicate(
+    Node x, Node e, TypeNode tn, unsigned tindex, unsigned depth)
+{
+  std::vector<Node> sb_lemmas;
+
+  // based on simple preprocessing
+  Node ppred =
+      d_ceg_proc->getSymmetryBreakingPredicate(x, e, tn, tindex, depth);
+  if (!ppred.isNull())
+  {
+    sb_lemmas.push_back(ppred);
+  }
+
+  // other static conjecture-dependent symmetry breaking goes here
+
+  if (!sb_lemmas.empty())
+  {
+    return sb_lemmas.size() == 1
+               ? sb_lemmas[0]
+               : NodeManager::currentNM()->mkNode(kind::AND, sb_lemmas);
+  }
+  else
+  {
+    return Node::null();
+  }
+}
+
+bool CegConjecture::sampleAddRefinementLemma(std::vector<Node>& vals,
+                                             std::vector<Node>& lems)
+{
+  if (Trace.isOn("cegis-sample"))
+  {
+    Trace("cegis-sample") << "Check sampling for candidate solution"
+                          << std::endl;
+    for (unsigned i = 0, size = vals.size(); i < size; i++)
+    {
+      Trace("cegis-sample")
+          << "  " << d_candidates[i] << " -> " << vals[i] << std::endl;
+    }
+  }
+  Assert(vals.size() == d_candidates.size());
+  Node sbody = d_base_body.substitute(
+      d_candidates.begin(), d_candidates.end(), vals.begin(), vals.end());
+  Trace("cegis-sample-debug") << "Sample " << sbody << std::endl;
+  // do eager unfolding
+  std::map<Node, Node> visited_n;
+  sbody = d_qe->getTermDatabaseSygus()->getEagerUnfold(sbody, visited_n);
+  Trace("cegis-sample") << "Sample (after unfolding): " << sbody << std::endl;
+
+  NodeManager* nm = NodeManager::currentNM();
+  for (unsigned i = 0, size = d_cegis_sampler.getNumSamplePoints(); i < size;
+       i++)
+  {
+    if (d_cegis_sample_refine.find(i) == d_cegis_sample_refine.end())
+    {
+      Node ev = d_cegis_sampler.evaluate(sbody, i);
+      Trace("cegis-sample-debug")
+          << "...evaluate point #" << i << " to " << ev << std::endl;
+      Assert(ev.isConst());
+      Assert(ev.getType().isBoolean());
+      if (!ev.getConst<bool>())
+      {
+        Trace("cegis-sample-debug") << "...false for point #" << i << std::endl;
+        // mark this as a CEGIS point (no longer sampled)
+        d_cegis_sample_refine.insert(i);
+        std::vector<Node> vars;
+        std::vector<Node> pt;
+        d_cegis_sampler.getSamplePoint(i, vars, pt);
+        Assert(d_base_vars.size() == pt.size());
+        Node rlem = d_base_body.substitute(
+            d_base_vars.begin(), d_base_vars.end(), pt.begin(), pt.end());
+        rlem = Rewriter::rewrite(rlem);
+        if (std::find(
+                d_refinement_lemmas.begin(), d_refinement_lemmas.end(), rlem)
+            == d_refinement_lemmas.end())
+        {
+          if (Trace.isOn("cegis-sample"))
+          {
+            Trace("cegis-sample") << "   false for point #" << i << " : ";
+            for (const Node& cn : pt)
+            {
+              Trace("cegis-sample") << cn << " ";
+            }
+            Trace("cegis-sample") << std::endl;
+          }
+          Trace("cegqi-engine") << "  *** Refine by sampling" << std::endl;
+          d_refinement_lemmas.push_back(rlem);
+          // if trust, we are not interested in sending out refinement lemmas
+          if (options::cegisSample() != CEGIS_SAMPLE_TRUST)
+          {
+            Node lem = nm->mkNode(OR, getGuard().negate(), rlem);
+            lems.push_back(lem);
+          }
+          return true;
+        }
+        else
+        {
+          Trace("cegis-sample-debug") << "...duplicate." << std::endl;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+}/* namespace CVC4::theory::quantifiers */
+}/* namespace CVC4::theory */
+}/* namespace CVC4 */
diff --git a/src/theory/quantifiers/sygus/ce_guided_conjecture.h b/src/theory/quantifiers/sygus/ce_guided_conjecture.h
new file mode 100644 (file)
index 0000000..1ef8fef
--- /dev/null
@@ -0,0 +1,283 @@
+/*********************                                                        */
+/*! \file ce_guided_conjecture.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief class that encapsulates counterexample-guided instantiation
+ **        techniques for a single SyGuS synthesis conjecture
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_CONJECTURE_H
+#define __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_CONJECTURE_H
+
+#include <memory>
+
+#include "theory/quantifiers/sygus/sygus_pbe.h"
+#include "theory/quantifiers/sygus/ce_guided_single_inv.h"
+#include "theory/quantifiers/sygus/sygus_grammar_cons.h"
+#include "theory/quantifiers/sygus/sygus_process_conj.h"
+#include "theory/quantifiers/sygus_sampler.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+/** a synthesis conjecture
+ * This class implements approaches for a synthesis conecjture, given by data
+ * member d_quant.
+ * This includes both approaches for synthesis in Reynolds et al CAV 2015. It
+ * determines which approach and optimizations are applicable to the
+ * conjecture, and has interfaces for implementing them.
+ */
+class CegConjecture {
+public:
+  CegConjecture( QuantifiersEngine * qe );
+  ~CegConjecture();
+  /** get original version of conjecture */
+  Node getConjecture() { return d_quant; }
+  /** get deep embedding version of conjecture */
+  Node getEmbeddedConjecture() { return d_embed_quant; }
+  /** get next decision request */
+  Node getNextDecisionRequest( unsigned& priority );
+
+  //-------------------------------for counterexample-guided check/refine
+  /** increment the number of times we have successfully done candidate
+   * refinement */
+  void incrementRefineCount() { d_refine_count++; }
+  /** whether the conjecture is waiting for a call to doCheck below */
+  bool needsCheck( std::vector< Node >& lem );
+  /** whether the conjecture is waiting for a call to doRefine below */
+  bool needsRefinement();
+  /** get the list of candidates */
+  void getCandidateList( std::vector< Node >& clist, bool forceOrig = false );
+  /** do single invocation check 
+  * This updates Gamma for an iteration of step 2 of Figure 1 of Reynolds et al CAV 2015.
+  */
+  void doSingleInvCheck(std::vector< Node >& lems);
+  /** do syntax-guided enumerative check 
+  * This is step 2(a) of Figure 3 of Reynolds et al CAV 2015.
+  */
+  void doCheck(std::vector< Node >& lems, std::vector< Node >& model_values);
+  /** do basic check 
+  * This is called for non-SyGuS synthesis conjectures
+  */
+  void doBasicCheck(std::vector< Node >& lems);
+  /** do refinement 
+  * This is step 2(b) of Figure 3 of Reynolds et al CAV 2015.
+  */
+  void doRefine(std::vector< Node >& lems);
+  //-------------------------------end for counterexample-guided check/refine
+  /**
+   * prints the synthesis solution to output stream out.
+   *
+   * singleInvocation : set to true if we should consult the single invocation
+   * module to get synthesis solutions.
+   */
+  void printSynthSolution( std::ostream& out, bool singleInvocation );
+  /** get synth solutions
+   *
+   * This returns a map from function-to-synthesize variables to their
+   * builtin solution, which has the same type. For example, for synthesis
+   * conjecture exists f. forall x. f( x )>x, this function may return the map
+   * containing the entry:
+   *   f -> (lambda x. x+1)
+   *
+   * singleInvocation : set to true if we should consult the single invocation
+   * module to get synthesis solutions.
+   */
+  void getSynthSolutions(std::map<Node, Node>& sol_map, bool singleInvocation);
+  /** get guard, this is "G" in Figure 3 of Reynolds et al CAV 2015 */
+  Node getGuard();
+  /** is ground */
+  bool isGround() { return d_inner_vars.empty(); }
+  /** does this conjecture correspond to a syntax-guided synthesis input */
+  bool isSyntaxGuided() const { return d_syntax_guided; }
+  /** are we using single invocation techniques */
+  bool isSingleInvocation() const;
+  /** preregister conjecture 
+  * This is used as a heuristic for solution reconstruction, so that we 
+  * remember expressions in the conjecture before preprocessing, since they
+  * may be helpful during solution reconstruction (Figure 5 of Reynolds et al CAV 2015)
+  */
+  void preregisterConjecture( Node q );
+  /** assign conjecture q to this class */
+  void assign( Node q );
+  /** has a conjecture been assigned to this class */
+  bool isAssigned() { return !d_embed_quant.isNull(); }
+  /** get model values for terms n, store in vector v */
+  void getModelValues( std::vector< Node >& n, std::vector< Node >& v );
+  /** get model value for term n */
+  Node getModelValue( Node n );
+
+  //-----------------------------------refinement lemmas
+  /** get number of refinement lemmas we have added so far */
+  unsigned getNumRefinementLemmas() { return d_refinement_lemmas.size(); }
+  /** get refinement lemma
+   *
+   * If d_embed_quant is forall d. exists y. P( d, y ), then a refinement
+   * lemma is one of the form ~P( d_candidates, c ) for some c.
+   */
+  Node getRefinementLemma( unsigned i ) { return d_refinement_lemmas[i]; }
+  /** sample add refinement lemma
+   *
+   * This function will check if there is a sample point in d_sampler that
+   * refutes the candidate solution (d_quant_vars->vals). If so, it adds a
+   * refinement lemma to the lists d_refinement_lemmas that corresponds to that
+   * sample point, and adds a lemma to lems if cegisSample mode is not trust.
+   */
+  bool sampleAddRefinementLemma(std::vector<Node>& vals,
+                                std::vector<Node>& lems);
+  //-----------------------------------end refinement lemmas
+
+  /** get program by examples utility */
+  CegConjecturePbe* getPbe() { return d_ceg_pbe.get(); }
+  /** get utility for static preprocessing and analysis of conjectures */
+  CegConjectureProcess* getProcess() { return d_ceg_proc.get(); }
+  /** get the symmetry breaking predicate for type */
+  Node getSymmetryBreakingPredicate(
+      Node x, Node e, TypeNode tn, unsigned tindex, unsigned depth);
+  /** print out debug information about this conjecture */
+  void debugPrint( const char * c );
+private:
+  /** reference to quantifier engine */
+  QuantifiersEngine * d_qe;
+  /** single invocation utility */
+  std::unique_ptr<CegConjectureSingleInv> d_ceg_si;
+  /** program by examples utility */
+  std::unique_ptr<CegConjecturePbe> d_ceg_pbe;
+  /** utility for static preprocessing and analysis of conjectures */
+  std::unique_ptr<CegConjectureProcess> d_ceg_proc;
+  /** grammar utility */
+  std::unique_ptr<CegGrammarConstructor> d_ceg_gc;
+  /** list of constants for quantified formula
+  * The outer Skolems for the negation of d_embed_quant.
+  */
+  std::vector< Node > d_candidates;
+  /** base instantiation
+  * If d_embed_quant is forall d. exists y. P( d, y ), then
+  * this is the formula  exists y. P( d_candidates, y ).
+  */
+  Node d_base_inst;
+  /** If d_base_inst is exists y. P( d, y ), then this is y. */
+  std::vector<Node> d_base_vars;
+  /**
+   * If d_base_inst is exists y. P( d, y ), then this is the formula
+   * P( d_candidates, y ).
+   */
+  Node d_base_body;
+  /** expand base inst to disjuncts */
+  std::vector< Node > d_base_disj;
+  /** list of variables on inner quantification */
+  std::vector< Node > d_inner_vars;
+  std::vector< std::vector< Node > > d_inner_vars_disj;
+  /** current extential quantifeirs whose couterexamples we must refine */
+  std::vector< std::vector< Node > > d_ce_sk;
+
+  //-----------------------------------refinement lemmas
+  /** refinement lemmas */
+  std::vector< Node > d_refinement_lemmas;
+  //-----------------------------------end refinement lemmas
+
+  /** the asserted (negated) conjecture */
+  Node d_quant;
+  /** (negated) conjecture after simplification */
+  Node d_simp_quant;
+  /** (negated) conjecture after simplification, conversion to deep embedding */
+  Node d_embed_quant;
+  /** candidate information */
+  class CandidateInfo {
+  public:
+    CandidateInfo(){}
+    /** list of terms we have instantiated candidates with */
+    std::vector< Node > d_inst;
+  };
+  std::map< Node, CandidateInfo > d_cinfo;  
+  /** number of times we have called doRefine */
+  unsigned d_refine_count;
+  /** construct candidates */
+  bool constructCandidates( std::vector< Node >& clist, std::vector< Node >& model_values, 
+                            std::vector< Node >& candidate_values, std::vector< Node >& lems );
+  /** get candidadate */
+  Node getCandidate( unsigned int i ) { return d_candidates[i]; }
+  /** record instantiation (this is used to construct solutions later) */
+  void recordInstantiation( std::vector< Node >& vs ) {
+    Assert( vs.size()==d_candidates.size() );
+    for( unsigned i=0; i<vs.size(); i++ ){
+      d_cinfo[d_candidates[i]].d_inst.push_back( vs[i] );
+    }
+  }
+  /** get synth solutions internal
+   *
+   * This function constructs the body of solutions for all
+   * functions-to-synthesize in this conjecture and stores them in sols, in
+   * order. For each solution added to sols, we add an integer indicating what
+   * kind of solution n is, where if sols[i] = n, then
+   *   if status[i] = 0: n is the (builtin term) corresponding to the solution,
+   *   if status[i] = 1: n is the sygus representation of the solution.
+   * We store builtin versions under some conditions (such as when the sygus
+   * grammar is being ignored).
+   *
+   * singleInvocation : set to true if we should consult the single invocation
+   * module to get synthesis solutions.
+   *
+   * For example, for conjecture exists fg. forall x. f(x)>g(x), this function
+   * may set ( sols, status ) to ( { x+1, d_x() }, { 1, 0 } ), where d_x() is
+   * the sygus datatype constructor corresponding to variable x.
+   */
+  void getSynthSolutionsInternal(std::vector<Node>& sols,
+                                 std::vector<int>& status,
+                                 bool singleInvocation);
+  //-------------------------------- sygus stream
+  /** the streaming guards for sygus streaming mode */
+  std::vector< Node > d_stream_guards;
+  /** get current stream guard */
+  Node getCurrentStreamGuard() const;
+  /** get stream guarded lemma
+   *
+   * If sygusStream is enabled, this returns ( G V n ) where G is the guard
+   * returned by getCurrentStreamGuard, otherwise this returns n.
+   */
+  Node getStreamGuardedLemma(Node n) const;
+  //-------------------------------- end sygus stream
+  //-------------------------------- non-syntax guided (deprecated)
+  /** Whether we are syntax-guided (e.g. was the input in SyGuS format).
+   * This includes SyGuS inputs where no syntactic restrictions are provided.
+   */
+  bool d_syntax_guided;
+  /** the guard for non-syntax-guided synthesis */
+  Node d_nsg_guard;
+  //-------------------------------- end non-syntax guided (deprecated)
+  /** sygus sampler objects for each program variable
+   *
+   * This is used for the sygusRewSynth() option to synthesize new candidate
+   * rewrite rules.
+   */
+  std::map<Node, SygusSamplerExt> d_sampler;
+  /** sampler object for the option cegisSample()
+   *
+   * This samples points of the type of the inner variables of the synthesis
+   * conjecture (d_base_vars).
+   */
+  SygusSampler d_cegis_sampler;
+  /** cegis sample refine points
+   *
+   * Stores the list of indices of sample points in d_cegis_sampler we have
+   * added as refinement lemmas.
+   */
+  std::unordered_set<unsigned> d_cegis_sample_refine;
+};
+
+} /* namespace CVC4::theory::quantifiers */
+} /* namespace CVC4::theory */
+} /* namespace CVC4 */
+
+#endif
diff --git a/src/theory/quantifiers/sygus/ce_guided_instantiation.cpp b/src/theory/quantifiers/sygus/ce_guided_instantiation.cpp
new file mode 100644 (file)
index 0000000..35098f5
--- /dev/null
@@ -0,0 +1,388 @@
+/*********************                                                        */
+/*! \file ce_guided_instantiation.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Tim King, Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief counterexample guided instantiation class
+ **   This class is the entry point for both synthesis algorithms in Reynolds et al CAV 2015
+ **
+ **/
+#include "theory/quantifiers/sygus/ce_guided_instantiation.h"
+
+#include "options/quantifiers_options.h"
+#include "smt/smt_statistics_registry.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
+#include "theory/quantifiers/term_util.h"
+//FIXME : remove this include (github issue #1156)
+#include "theory/bv/theory_bv_rewriter.h"
+
+using namespace CVC4::kind;
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+CegInstantiation::CegInstantiation( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ){
+  d_conj = new CegConjecture( qe );
+  d_last_inst_si = false;
+}
+
+CegInstantiation::~CegInstantiation(){ 
+  delete d_conj;
+}
+
+bool CegInstantiation::needsCheck( Theory::Effort e ) {
+  return e>=Theory::EFFORT_LAST_CALL;
+}
+
+QuantifiersModule::QEffort CegInstantiation::needsModel(Theory::Effort e)
+{
+  return d_conj->isSingleInvocation() ? QEFFORT_STANDARD : QEFFORT_MODEL;
+}
+
+void CegInstantiation::check(Theory::Effort e, QEffort quant_e)
+{
+  unsigned echeck =
+      d_conj->isSingleInvocation() ? QEFFORT_STANDARD : QEFFORT_MODEL;
+  if( quant_e==echeck ){
+    Trace("cegqi-engine") << "---Counterexample Guided Instantiation Engine---" << std::endl;
+    Trace("cegqi-engine-debug") << std::endl;
+    bool active = false;
+    bool value;
+    if( d_quantEngine->getValuation().hasSatValue( d_conj->getConjecture(), value ) ) {
+      active = value;
+    }else{
+      Trace("cegqi-engine-debug") << "...no value for quantified formula." << std::endl;
+    }
+    Trace("cegqi-engine-debug") << "Current conjecture status : active : " << active << std::endl;
+    std::vector< Node > lem;
+    if( active && d_conj->needsCheck( lem ) ){
+      checkCegConjecture( d_conj );
+    }else{
+      Trace("cegqi-engine-debug") << "...does not need check." << std::endl;
+      for( unsigned i=0; i<lem.size(); i++ ){
+        Trace("cegqi-lemma") << "Cegqi::Lemma : check lemma : " << lem[i] << std::endl;
+        d_quantEngine->addLemma( lem[i] );
+      }
+    }
+    Trace("cegqi-engine") << "Finished Counterexample Guided Instantiation engine." << std::endl;
+  }
+}
+
+void CegInstantiation::registerQuantifier( Node q ) {
+  if( d_quantEngine->getOwner( q )==this ){ // && d_eval_axioms.find( q )==d_eval_axioms.end() ){
+    if( !d_conj->isAssigned() ){
+      Trace("cegqi") << "Register conjecture : " << q << std::endl;
+      d_conj->assign( q );
+    }else{
+      Assert( d_conj->getEmbeddedConjecture()==q );
+    }
+  }else{
+    Trace("cegqi-debug") << "Register quantifier : " << q << std::endl;
+  }
+}
+
+Node CegInstantiation::getNextDecisionRequest( unsigned& priority ) {
+  if( d_conj->isAssigned() ){
+    Node dec_req = d_conj->getNextDecisionRequest( priority );
+    if( !dec_req.isNull() ){
+      Trace("cegqi-debug") << "CEGQI : Decide next on : " << dec_req << "..." << std::endl;
+      return dec_req;
+    }
+  }
+  return Node::null();
+}
+
+void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
+  Node q = conj->getEmbeddedConjecture();
+  Node aq = conj->getConjecture();
+  if( Trace.isOn("cegqi-engine-debug") ){
+    conj->debugPrint("cegqi-engine-debug");
+    Trace("cegqi-engine-debug") << std::endl;
+  }
+
+  if( !conj->needsRefinement() ){
+    Trace("cegqi-engine-debug") << "Do conjecture check..." << std::endl;
+    if( conj->isSyntaxGuided() ){
+      std::vector< Node > clems;
+      conj->doSingleInvCheck( clems );
+      if( !clems.empty() ){
+        d_last_inst_si = true;
+        for( unsigned j=0; j<clems.size(); j++ ){
+          Trace("cegqi-lemma") << "Cegqi::Lemma : single invocation instantiation : " << clems[j] << std::endl;
+          d_quantEngine->addLemma( clems[j] );
+        }
+        d_statistics.d_cegqi_si_lemmas += clems.size();
+        Trace("cegqi-engine") << "  ...try single invocation." << std::endl;
+        return;
+      }
+      //ignore return value here
+      std::vector< Node > clist;
+      conj->getCandidateList( clist );
+      std::vector< Node > model_values;
+      conj->getModelValues( clist, model_values );
+      if( options::sygusDirectEval() ){
+        bool addedEvalLemmas = false;
+        if( options::sygusCRefEval() ){
+          Trace("cegqi-engine") << "  *** Do conjecture refinement evaluation..." << std::endl;
+          // see if any refinement lemma is refuted by evaluation
+          std::vector< Node > cre_lems;
+          getCRefEvaluationLemmas( conj, clist, model_values, cre_lems );
+          if( !cre_lems.empty() ){
+            for( unsigned j=0; j<cre_lems.size(); j++ ){
+              Node lem = cre_lems[j];
+              if( d_quantEngine->addLemma( lem ) ){
+                Trace("cegqi-lemma") << "Cegqi::Lemma : cref evaluation : " << lem << std::endl;
+                addedEvalLemmas = true;
+              }
+            }
+            if( addedEvalLemmas ){
+              //return;
+            }
+          }
+        }
+        Trace("cegqi-engine") << "  *** Do direct evaluation..." << std::endl;
+        std::vector< Node > eager_terms; 
+        std::vector< Node > eager_vals; 
+        std::vector< Node > eager_exps;
+        for( unsigned j=0; j<clist.size(); j++ ){
+          Trace("cegqi-debug") << "  register " << clist[j] << " -> " << model_values[j] << std::endl;
+          d_quantEngine->getTermDatabaseSygus()->registerModelValue( clist[j], model_values[j], eager_terms, eager_vals, eager_exps );
+        }
+        Trace("cegqi-debug") << "...produced " << eager_terms.size()  << " eager evaluation lemmas." << std::endl;
+        if( !eager_terms.empty() ){
+          for( unsigned j=0; j<eager_terms.size(); j++ ){
+            Node lem = NodeManager::currentNM()->mkNode( kind::OR, eager_exps[j].negate(), eager_terms[j].eqNode( eager_vals[j] ) );
+            if( d_quantEngine->getTheoryEngine()->isTheoryEnabled(THEORY_BV) ){
+              //FIXME: hack to incorporate hacks from BV for division by zero (github issue #1156)
+              lem = bv::TheoryBVRewriter::eliminateBVSDiv( lem );
+            }
+            if( d_quantEngine->addLemma( lem ) ){
+              Trace("cegqi-lemma") << "Cegqi::Lemma : evaluation : " << lem << std::endl;
+              addedEvalLemmas = true;
+            }
+          }
+        }
+        if( addedEvalLemmas ){
+          return;
+        }
+      }
+      
+      Trace("cegqi-engine") << "  *** Check candidate phase..." << std::endl;
+      std::vector< Node > cclems;
+      conj->doCheck( cclems, model_values );
+      bool addedLemma = false;
+      for( unsigned i=0; i<cclems.size(); i++ ){
+        Node lem = cclems[i];
+        d_last_inst_si = false;
+        Trace("cegqi-lemma") << "Cegqi::Lemma : counterexample : " << lem << std::endl;
+        if( d_quantEngine->addLemma( lem ) ){
+          ++(d_statistics.d_cegqi_lemmas_ce);
+          addedLemma = true;
+        }else{
+          //this may happen if we eagerly unfold, simplify to true
+          if( !options::sygusDirectEval() ){
+            Trace("cegqi-warn") << "  ...FAILED to add candidate!" << std::endl;
+          }else{
+            Trace("cegqi-engine-debug") << "  ...FAILED to add candidate!" << std::endl;
+          }
+        }
+      }
+      if( addedLemma ){
+        Trace("cegqi-engine") << "  ...check for counterexample." << std::endl;
+      }else{
+        if( conj->needsRefinement() ){
+          //immediately go to refine candidate
+          checkCegConjecture( conj );
+          return;
+        }
+      } 
+    }else{
+      Assert( aq==q );
+      Trace("cegqi-engine") << "  *** Check candidate phase (non-SyGuS)." << std::endl;
+      std::vector< Node > lems;
+      conj->doBasicCheck(lems);
+      Assert(lems.empty());
+    }
+  }else{
+    Trace("cegqi-engine") << "  *** Refine candidate phase..." << std::endl;
+    std::vector< Node > rlems;
+    conj->doRefine( rlems );
+    bool addedLemma = false;
+    for( unsigned i=0; i<rlems.size(); i++ ){
+      Node lem = rlems[i];
+      Trace("cegqi-lemma") << "Cegqi::Lemma : candidate refinement : " << lem << std::endl;
+      bool res = d_quantEngine->addLemma( lem );
+      if( res ){
+        ++(d_statistics.d_cegqi_lemmas_refine);
+        conj->incrementRefineCount();
+        addedLemma = true;
+      }else{
+        Trace("cegqi-warn") << "  ...FAILED to add refinement!" << std::endl;
+      }
+    }
+    if( addedLemma ){
+      Trace("cegqi-engine") << "  ...refine candidate." << std::endl;
+    }
+  }
+}
+
+void CegInstantiation::getCRefEvaluationLemmas( CegConjecture * conj, std::vector< Node >& vs, std::vector< Node >& ms, std::vector< Node >& lems ) {
+  Trace("sygus-cref-eval") << "Cref eval : conjecture has " << conj->getNumRefinementLemmas() << " refinement lemmas." << std::endl;
+  unsigned nlemmas = conj->getNumRefinementLemmas();
+  if (nlemmas > 0 || options::cegisSample() != CEGIS_SAMPLE_NONE)
+  {
+    Assert( vs.size()==ms.size() );
+
+    TermDbSygus* tds = d_quantEngine->getTermDatabaseSygus();
+    Node nfalse = d_quantEngine->getTermUtil()->d_false;
+    Node neg_guard = conj->getGuard().negate();
+    for (unsigned i = 0; i <= nlemmas; i++)
+    {
+      if (i == nlemmas)
+      {
+        bool addedSample = false;
+        // find a new one by sampling, if applicable
+        if (options::cegisSample() != CEGIS_SAMPLE_NONE)
+        {
+          addedSample = conj->sampleAddRefinementLemma(ms, lems);
+        }
+        if (!addedSample)
+        {
+          return;
+        }
+      }
+      Node lem;
+      std::map< Node, Node > visited;
+      std::map< Node, std::vector< Node > > exp;
+      lem = conj->getRefinementLemma(i);
+      if( !lem.isNull() ){
+        std::vector< Node > lem_conj;
+        //break into conjunctions
+        if( lem.getKind()==kind::AND ){
+          for( unsigned i=0; i<lem.getNumChildren(); i++ ){
+            lem_conj.push_back( lem[i] );
+          }
+        }else{
+          lem_conj.push_back( lem );
+        }
+        EvalSygusInvarianceTest vsit;
+        for( unsigned j=0; j<lem_conj.size(); j++ ){
+          Node lemc = lem_conj[j];
+          Trace("sygus-cref-eval") << "Check refinement lemma conjunct " << lemc << " against current model." << std::endl;
+          Trace("sygus-cref-eval2") << "Check refinement lemma conjunct " << lemc << " against current model." << std::endl;
+          Node cre_lem;
+          Node lemcs = lemc.substitute( vs.begin(), vs.end(), ms.begin(), ms.end() );
+          Trace("sygus-cref-eval2") << "...under substitution it is : " << lemcs << std::endl;
+          Node lemcsu = vsit.doEvaluateWithUnfolding(tds, lemcs);
+          Trace("sygus-cref-eval2") << "...after unfolding is : " << lemcsu << std::endl;
+          if( lemcsu==d_quantEngine->getTermUtil()->d_false ){
+            std::vector< Node > msu;
+            std::vector< Node > mexp;
+            msu.insert( msu.end(), ms.begin(), ms.end() );
+            for( unsigned k=0; k<vs.size(); k++ ){
+              vsit.setUpdatedTerm(msu[k]);
+              msu[k] = vs[k];
+              // substitute for everything except this
+              Node sconj =
+                  lemc.substitute(vs.begin(), vs.end(), msu.begin(), msu.end());
+              vsit.init(sconj, vs[k], nfalse);
+              // get minimal explanation for this
+              Node ut = vsit.getUpdatedTerm();
+              Trace("sygus-cref-eval2-debug")
+                  << "  compute min explain of : " << vs[k] << " = " << ut
+                  << std::endl;
+              d_quantEngine->getTermDatabaseSygus()
+                  ->getExplain()
+                  ->getExplanationFor(vs[k], ut, mexp, vsit);
+              msu[k] = ut;
+            }
+            if( !mexp.empty() ){
+              Node en = mexp.size()==1 ? mexp[0] : NodeManager::currentNM()->mkNode( kind::AND, mexp );
+              cre_lem = NodeManager::currentNM()->mkNode( kind::OR, en.negate(), neg_guard );
+            }else{
+              cre_lem = neg_guard;
+            }
+          }
+          if( !cre_lem.isNull() ){
+            if( std::find( lems.begin(), lems.end(), cre_lem )==lems.end() ){
+              Trace("sygus-cref-eval") << "...produced lemma : " << cre_lem << std::endl;
+              lems.push_back( cre_lem );
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+void CegInstantiation::printSynthSolution( std::ostream& out ) {
+  if( d_conj->isAssigned() )
+  {
+    d_conj->printSynthSolution( out, d_last_inst_si );
+  }
+  else
+  {
+    Assert( false );
+  }
+}
+
+void CegInstantiation::getSynthSolutions(std::map<Node, Node>& sol_map)
+{
+  if (d_conj->isAssigned())
+  {
+    d_conj->getSynthSolutions(sol_map, d_last_inst_si);
+  }
+  else
+  {
+    Assert(false);
+  }
+}
+
+void CegInstantiation::preregisterAssertion( Node n ) {
+  //check if it sygus conjecture
+  if( QuantAttributes::checkSygusConjecture( n ) ){
+    //this is a sygus conjecture
+    Trace("cegqi") << "Preregister sygus conjecture : " << n << std::endl;
+    d_conj->preregisterConjecture( n );
+  }
+}
+
+CegInstantiation::Statistics::Statistics()
+    : d_cegqi_lemmas_ce("CegInstantiation::cegqi_lemmas_ce", 0),
+      d_cegqi_lemmas_refine("CegInstantiation::cegqi_lemmas_refine", 0),
+      d_cegqi_si_lemmas("CegInstantiation::cegqi_lemmas_si", 0),
+      d_solutions("CegConjecture::solutions", 0),
+      d_candidate_rewrites_print("CegConjecture::candidate_rewrites_print", 0),
+      d_candidate_rewrites("CegConjecture::candidate_rewrites", 0)
+
+{
+  smtStatisticsRegistry()->registerStat(&d_cegqi_lemmas_ce);
+  smtStatisticsRegistry()->registerStat(&d_cegqi_lemmas_refine);
+  smtStatisticsRegistry()->registerStat(&d_cegqi_si_lemmas);
+  smtStatisticsRegistry()->registerStat(&d_solutions);
+  smtStatisticsRegistry()->registerStat(&d_candidate_rewrites_print);
+  smtStatisticsRegistry()->registerStat(&d_candidate_rewrites);
+}
+
+CegInstantiation::Statistics::~Statistics(){
+  smtStatisticsRegistry()->unregisterStat(&d_cegqi_lemmas_ce);
+  smtStatisticsRegistry()->unregisterStat(&d_cegqi_lemmas_refine);
+  smtStatisticsRegistry()->unregisterStat(&d_cegqi_si_lemmas);
+  smtStatisticsRegistry()->unregisterStat(&d_solutions);
+  smtStatisticsRegistry()->unregisterStat(&d_candidate_rewrites_print);
+  smtStatisticsRegistry()->unregisterStat(&d_candidate_rewrites);
+}
+
+}/* namespace CVC4::theory::quantifiers */
+}/* namespace CVC4::theory */
+}/* namespace CVC4 */
diff --git a/src/theory/quantifiers/sygus/ce_guided_instantiation.h b/src/theory/quantifiers/sygus/ce_guided_instantiation.h
new file mode 100644 (file)
index 0000000..087836d
--- /dev/null
@@ -0,0 +1,90 @@
+/*********************                                                        */
+/*! \file ce_guided_instantiation.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief counterexample guided instantiation class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_INSTANTIATION_H
+#define __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_INSTANTIATION_H
+
+#include "context/cdhashmap.h"
+#include "theory/quantifiers/sygus/ce_guided_conjecture.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class CegInstantiation : public QuantifiersModule
+{
+  typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+private:
+  /** the quantified formula stating the synthesis conjecture */
+  CegConjecture * d_conj;
+  /** last instantiation by single invocation module? */
+  bool d_last_inst_si;
+private: //for direct evaluation
+  /** get refinement evaluation */
+  void getCRefEvaluationLemmas( CegConjecture * conj, std::vector< Node >& vs, std::vector< Node >& ms, std::vector< Node >& lems );
+private:
+  /** check conjecture */
+  void checkCegConjecture( CegConjecture * conj );
+public:
+  CegInstantiation( QuantifiersEngine * qe, context::Context* c );
+  ~CegInstantiation();
+public:
+  bool needsCheck( Theory::Effort e );
+  QEffort needsModel(Theory::Effort e);
+  /* Call during quantifier engine's check */
+  void check(Theory::Effort e, QEffort quant_e);
+  /* Called for new quantifiers */
+  void registerQuantifier( Node q );
+  /** get the next decision request */
+  Node getNextDecisionRequest( unsigned& priority );
+  /** Identify this module (for debugging, dynamic configuration, etc..) */
+  std::string identify() const { return "CegInstantiation"; }
+  /** print solution for synthesis conjectures */
+  void printSynthSolution( std::ostream& out );
+  /** get synth solutions
+   *
+   * This function adds entries to sol_map that map functions-to-synthesize
+   * with their solutions, for all active conjectures (currently just the one
+   * assigned to d_conj). This should be called immediately after the solver
+   * answers unsat for sygus input.
+   *
+   * For details on what is added to sol_map, see
+   * CegConjecture::getSynthSolutions.
+   */
+  void getSynthSolutions(std::map<Node, Node>& sol_map);
+  /** preregister assertion (before rewrite) */
+  void preregisterAssertion( Node n );
+public:
+  class Statistics {
+  public:
+    IntStat d_cegqi_lemmas_ce;
+    IntStat d_cegqi_lemmas_refine;
+    IntStat d_cegqi_si_lemmas;
+    IntStat d_solutions;
+    IntStat d_candidate_rewrites_print;
+    IntStat d_candidate_rewrites;
+    Statistics();
+    ~Statistics();
+  };/* class CegInstantiation::Statistics */
+  Statistics d_statistics;
+}; /* class CegInstantiation */
+
+} /* namespace CVC4::theory::quantifiers */
+} /* namespace CVC4::theory */
+} /* namespace CVC4 */
+
+#endif
diff --git a/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp b/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp
new file mode 100644 (file)
index 0000000..d59f1f3
--- /dev/null
@@ -0,0 +1,1004 @@
+/*********************                                                        */
+/*! \file ce_guided_single_inv.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief utility for processing single invocation synthesis conjectures
+ **
+ **/
+#include "theory/quantifiers/sygus/ce_guided_single_inv.h"
+
+#include "options/quantifiers_options.h"
+#include "theory/arith/arith_msum.h"
+#include "theory/quantifiers/term_enumeration.h"
+#include "theory/quantifiers/term_util.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace std;
+
+namespace CVC4 {
+
+bool CegqiOutputSingleInv::doAddInstantiation( std::vector< Node >& subs ) {
+  return d_out->doAddInstantiation( subs );
+}
+
+bool CegqiOutputSingleInv::isEligibleForInstantiation( Node n ) {
+  return d_out->isEligibleForInstantiation( n );
+}
+
+bool CegqiOutputSingleInv::addLemma( Node n ) {
+  return d_out->addLemma( n );
+}
+
+CegConjectureSingleInv::CegConjectureSingleInv(QuantifiersEngine* qe,
+                                               CegConjecture* p)
+    : d_qe(qe),
+      d_parent(p),
+      d_sip(new SingleInvocationPartition),
+      d_sol(new CegConjectureSingleInvSol(qe)),
+      d_cosi(new CegqiOutputSingleInv(this)),
+      d_cinst(NULL),
+      d_c_inst_match_trie(NULL),
+      d_has_ites(true),
+      d_single_invocation(false) {
+  //  third and fourth arguments set to (false,false) until we have solution
+  //  reconstruction for delta and infinity
+  d_cinst = new CegInstantiator(d_qe, d_cosi, false, false);
+
+  if (options::incrementalSolving()) {
+    d_c_inst_match_trie = new inst::CDInstMatchTrie(qe->getUserContext());
+  }
+}
+
+CegConjectureSingleInv::~CegConjectureSingleInv() {
+  if (d_c_inst_match_trie) {
+    delete d_c_inst_match_trie;
+  }
+  delete d_cinst;
+  delete d_cosi;
+  delete d_sol;  // (new CegConjectureSingleInvSol(qe)),
+  delete d_sip;  // d_sip(new SingleInvocationPartition),
+}
+
+void CegConjectureSingleInv::getInitialSingleInvLemma( std::vector< Node >& lems ) {
+  Assert( d_si_guard.isNull() );
+  //single invocation guard
+  d_si_guard = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "G", NodeManager::currentNM()->booleanType() ) );
+  d_si_guard = d_qe->getValuation().ensureLiteral( d_si_guard );
+  AlwaysAssert( !d_si_guard.isNull() );
+  d_qe->getOutputChannel().requirePhase( d_si_guard, true );
+
+  if( !d_single_inv.isNull() ) {
+    //make for new var/sk
+    d_single_inv_var.clear();
+    d_single_inv_sk.clear();
+    Node inst;
+    if( d_single_inv.getKind()==FORALL ){
+      for( unsigned i=0; i<d_single_inv[0].getNumChildren(); i++ ){
+        std::stringstream ss;
+        ss << "k_" << d_single_inv[0][i];
+        Node k = NodeManager::currentNM()->mkSkolem( ss.str(), d_single_inv[0][i].getType(), "single invocation function skolem" );
+        d_single_inv_var.push_back( d_single_inv[0][i] );
+        d_single_inv_sk.push_back( k );
+        d_single_inv_sk_index[k] = i;
+      }
+      inst = d_single_inv[1].substitute( d_single_inv_var.begin(), d_single_inv_var.end(), d_single_inv_sk.begin(), d_single_inv_sk.end() );
+    }else{
+      inst = d_single_inv;
+    }
+    inst = TermUtil::simpleNegate( inst );
+    Trace("cegqi-si") << "Single invocation initial lemma : " << inst << std::endl;
+
+    //register with the instantiator
+    Node ginst = NodeManager::currentNM()->mkNode( OR, d_si_guard.negate(), inst );
+    lems.push_back( ginst );
+    //make and register the instantiator
+    if( d_cinst ){
+      delete d_cinst;
+    }
+    d_cinst = new CegInstantiator( d_qe, d_cosi, false, false );
+    d_cinst->registerCounterexampleLemma( lems, d_single_inv_sk );
+  }
+}
+
+void CegConjectureSingleInv::initialize( Node q ) {
+  // can only register one quantified formula with this
+  Assert( d_quant.isNull() );
+  d_quant = q;
+  d_simp_quant = q;
+  Trace("cegqi-si") << "CegConjectureSingleInv::initialize : " << q << std::endl;
+  // infer single invocation-ness
+  std::vector< Node > progs;
+  std::map< Node, std::vector< Node > > prog_vars;
+  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+    Node sf = q[0][i];
+    progs.push_back( sf );
+    Node sfvl = sf.getAttribute(SygusSynthFunVarListAttribute());
+    for( unsigned j=0; j<sfvl.getNumChildren(); j++ ){
+      prog_vars[sf].push_back( sfvl[j] );
+    }
+  }
+  // compute single invocation partition
+  if( options::cegqiSingleInvMode()!=CEGQI_SI_MODE_NONE ){
+    Node qq;
+    if( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ){
+      qq = q[1][0][1];
+    }else{
+      qq = TermUtil::simpleNegate( q[1] );
+    }
+    //process the single invocation-ness of the property
+    if( !d_sip->init( progs, qq ) ){
+      Trace("cegqi-si") << "...not single invocation (type mismatch)" << std::endl;
+    }else{
+      Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl;
+      d_sip->debugPrint( "cegqi-si" );
+
+      //map from program to bound variables
+      std::vector<Node> funcs;
+      d_sip->getFunctions(funcs);
+      for (unsigned j = 0, size = funcs.size(); j < size; j++)
+      {
+        Assert(std::find(progs.begin(), progs.end(), funcs[j]) != progs.end());
+        d_prog_to_sol_index[funcs[j]] = j;
+      }
+
+      //check if it is single invocation
+      if (!d_sip->isPurelySingleInvocation())
+      {
+        if( options::sygusInvTemplMode() != SYGUS_INV_TEMPL_MODE_NONE ){
+          //if we are doing invariant templates, then construct the template
+          Trace("cegqi-si") << "- Do transition inference..." << std::endl;
+          d_ti[q].process( qq );
+          Trace("cegqi-inv") << std::endl;
+          if( !d_ti[q].d_func.isNull() ){
+            // map the program back via non-single invocation map
+            Node prog = d_ti[q].d_func;
+            std::vector< Node > prog_templ_vars;
+            prog_templ_vars.insert( prog_templ_vars.end(), d_ti[q].d_vars.begin(), d_ti[q].d_vars.end() );
+            d_trans_pre[prog] = d_ti[q].getComponent( 1 );
+            d_trans_post[prog] = d_ti[q].getComponent( -1 );
+            Trace("cegqi-inv") << "   precondition : " << d_trans_pre[prog] << std::endl;
+            Trace("cegqi-inv") << "  postcondition : " << d_trans_post[prog] << std::endl;
+            std::vector<Node> sivars;
+            d_sip->getSingleInvocationVariables(sivars);
+            Node invariant = d_sip->getFunctionInvocationFor(prog);
+            Assert(!invariant.isNull());
+            invariant = invariant.substitute(sivars.begin(),
+                                             sivars.end(),
+                                             prog_templ_vars.begin(),
+                                             prog_templ_vars.end());
+            Trace("cegqi-inv") << "      invariant : " << invariant << std::endl;
+            
+            // store simplified version of quantified formula
+            d_simp_quant = d_sip->getFullSpecification();
+            std::vector< Node > new_bv;
+            for (unsigned j = 0, size = sivars.size(); j < size; j++)
+            {
+              new_bv.push_back(
+                  NodeManager::currentNM()->mkBoundVar(sivars[j].getType()));
+            }
+            d_simp_quant = d_simp_quant.substitute(
+                sivars.begin(), sivars.end(), new_bv.begin(), new_bv.end());
+            Assert( q[1].getKind()==NOT && q[1][0].getKind()==FORALL );
+            for( unsigned j=0; j<q[1][0][0].getNumChildren(); j++ ){
+              new_bv.push_back( q[1][0][0][j] );
+            }
+            d_simp_quant = NodeManager::currentNM()->mkNode( kind::FORALL, NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, new_bv ), d_simp_quant ).negate();
+            d_simp_quant = Rewriter::rewrite( d_simp_quant );
+            d_simp_quant = NodeManager::currentNM()->mkNode( kind::FORALL, q[0], d_simp_quant, q[2] );
+            Trace("cegqi-si") << "Rewritten quantifier : " << d_simp_quant << std::endl;
+
+            //construct template argument
+            d_templ_arg[prog] = NodeManager::currentNM()->mkSkolem( "I", invariant.getType() );
+            
+            //construct template
+            Node templ;
+            if( options::sygusInvAutoUnfold() ){
+              if( d_ti[q].isComplete() ){
+                Trace("cegqi-inv-auto-unfold") << "Automatic deterministic unfolding... " << std::endl;
+                // auto-unfold
+                DetTrace dt;
+                int init_dt = d_ti[q].initializeTrace( dt );
+                if( init_dt==0 ){
+                  Trace("cegqi-inv-auto-unfold") << "  Init : ";
+                  dt.print("cegqi-inv-auto-unfold");
+                  Trace("cegqi-inv-auto-unfold") << std::endl;
+                  unsigned counter = 0;
+                  unsigned status = 0;
+                  while( counter<100 && status==0 ){
+                    status = d_ti[q].incrementTrace( dt );
+                    counter++;
+                    Trace("cegqi-inv-auto-unfold") << "  #" << counter << " : ";
+                    dt.print("cegqi-inv-auto-unfold");
+                    Trace("cegqi-inv-auto-unfold") << "...status = " << status << std::endl;
+                  }
+                  if( status==1 ){
+                    // we have a trivial invariant
+                    templ = d_ti[q].constructFormulaTrace( dt );
+                    Trace("cegqi-inv") << "By finite deterministic terminating trace, a solution invariant is : " << std::endl;
+                    Trace("cegqi-inv") << "   " << templ << std::endl;
+                    // FIXME : this should be unnecessary
+                    templ = NodeManager::currentNM()->mkNode( AND, templ, d_templ_arg[prog] );
+                  }
+                }else{
+                  Trace("cegqi-inv-auto-unfold") << "...failed initialize." << std::endl;
+                }
+              }
+            }
+            if( templ.isNull() ){
+              if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){
+                //d_templ[prog] = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] );
+                templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], d_templ_arg[prog] );
+              }else{
+                Assert( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST );
+                //d_templ[prog] = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) );
+                templ = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], d_templ_arg[prog] );
+              }
+            }
+            Trace("cegqi-inv") << "       template (pre-substitution) : " << templ << std::endl;
+            Assert( !templ.isNull() );
+            // subsitute the template arguments
+            templ = templ.substitute( prog_templ_vars.begin(), prog_templ_vars.end(), prog_vars[prog].begin(), prog_vars[prog].end() );
+            Trace("cegqi-inv") << "       template : " << templ << std::endl;
+            d_templ[prog] = templ;
+          }
+        }
+      }else{
+        //we are fully single invocation
+        d_single_invocation = true;
+      }
+    }
+  }
+}
+
+void CegConjectureSingleInv::finishInit( bool syntaxRestricted, bool hasItes ) {
+  d_has_ites = hasItes;
+  // do not do single invocation if grammar is restricted and CEGQI_SI_MODE_ALL is not enabled
+  if( options::cegqiSingleInvMode()==CEGQI_SI_MODE_USE && d_single_invocation && syntaxRestricted ){
+    d_single_invocation = false;
+    Trace("cegqi-si") << "...grammar is restricted, do not use single invocation techniques." << std::endl;
+  }
+
+  // we now have determined whether we will do single invocation techniques
+  if( d_single_invocation ){
+    d_single_inv = d_sip->getSingleInvocation();
+    d_single_inv = TermUtil::simpleNegate( d_single_inv );
+    std::vector<Node> func_vars;
+    d_sip->getFunctionVariables(func_vars);
+    if (!func_vars.empty())
+    {
+      Node pbvl = NodeManager::currentNM()->mkNode(BOUND_VAR_LIST, func_vars);
+      d_single_inv = NodeManager::currentNM()->mkNode( FORALL, pbvl, d_single_inv );
+    }
+    //now, introduce the skolems
+    std::vector<Node> sivars;
+    d_sip->getSingleInvocationVariables(sivars);
+    for (unsigned i = 0, size = sivars.size(); i < size; i++)
+    {
+      Node v = NodeManager::currentNM()->mkSkolem(
+          "a", sivars[i].getType(), "single invocation arg");
+      d_single_inv_arg_sk.push_back( v );
+    }
+    d_single_inv = d_single_inv.substitute(sivars.begin(),
+                                           sivars.end(),
+                                           d_single_inv_arg_sk.begin(),
+                                           d_single_inv_arg_sk.end());
+    Trace("cegqi-si") << "Single invocation formula is : " << d_single_inv << std::endl;
+    if( options::cbqiPreRegInst() && d_single_inv.getKind()==FORALL ){
+      //just invoke the presolve now
+      d_cinst->presolve( d_single_inv );
+    }
+  }else{
+    d_single_inv = Node::null();
+    Trace("cegqi-si") << "Formula is not single invocation." << std::endl;
+    if( options::cegqiSingleInvAbort() ){
+      Notice() << "Property is not single invocation." << std::endl;
+      exit( 1 );
+    }
+  }
+}
+
+bool CegConjectureSingleInv::doAddInstantiation( std::vector< Node >& subs ){
+  Assert( d_single_inv_sk.size()==subs.size() );
+  Trace("cegqi-si-inst-debug") << "CegConjectureSingleInv::doAddInstantiation, #vars = ";
+  Trace("cegqi-si-inst-debug") << d_single_inv_sk.size() << "..." << std::endl;
+  std::stringstream siss;
+  if( Trace.isOn("cegqi-si-inst-debug") || Trace.isOn("cegqi-engine") ){
+    siss << "  * single invocation: " << std::endl;
+    for( unsigned j=0; j<d_single_inv_sk.size(); j++ ){
+      Node op = d_sip->getFunctionForFirstOrderVariable(d_single_inv[0][j]);
+      Assert(!op.isNull());
+      siss << "    * " << op;
+      siss << " (" << d_single_inv_sk[j] << ")";
+      siss << " -> " << subs[j] << std::endl;
+    }
+  }
+  Trace("cegqi-si-inst-debug") << siss.str();
+
+  bool alreadyExists;
+  Node lem;
+  if( subs.empty() ){
+    Assert( d_single_inv.getKind()!=FORALL );
+    alreadyExists = false;
+    lem = d_single_inv;
+  }else{
+    Assert( d_single_inv.getKind()==FORALL );
+    if( options::incrementalSolving() ){
+      alreadyExists = !d_c_inst_match_trie->addInstMatch( d_qe, d_single_inv, subs, d_qe->getUserContext() );
+    }else{
+      alreadyExists = !d_inst_match_trie.addInstMatch( d_qe, d_single_inv, subs );
+    }
+    Trace("cegqi-si-inst-debug") << "  * success = " << !alreadyExists << std::endl;
+    //Trace("cegqi-si-inst-debug") << siss.str();
+    //Trace("cegqi-si-inst-debug") << "  * success = " << !alreadyExists << std::endl;
+    if( alreadyExists ){
+      return false;
+    }else{
+      Trace("cegqi-engine") << siss.str() << std::endl;
+      Assert( d_single_inv_var.size()==subs.size() );
+      lem = d_single_inv[1].substitute( d_single_inv_var.begin(), d_single_inv_var.end(), subs.begin(), subs.end() );
+      if( d_qe->getTermUtil()->containsVtsTerm( lem ) ){
+        Trace("cegqi-engine-debug") << "Rewrite based on vts symbols..." << std::endl;
+        lem = d_qe->getTermUtil()->rewriteVtsSymbols( lem );
+      }
+    }
+  }
+  Trace("cegqi-engine-debug") << "Rewrite..." << std::endl;
+  lem = Rewriter::rewrite( lem );
+  Trace("cegqi-si") << "Single invocation lemma : " << lem << std::endl;
+  if( std::find( d_lemmas_produced.begin(), d_lemmas_produced.end(), lem )==d_lemmas_produced.end() ){
+    d_curr_lemmas.push_back( lem );
+    d_lemmas_produced.push_back( lem );
+    d_inst.push_back( std::vector< Node >() );
+    d_inst.back().insert( d_inst.back().end(), subs.begin(), subs.end() );
+  }
+  return true;
+}
+
+bool CegConjectureSingleInv::isEligibleForInstantiation( Node n ) {
+  return n.getKind()!=SKOLEM || std::find( d_single_inv_arg_sk.begin(), d_single_inv_arg_sk.end(), n )!=d_single_inv_arg_sk.end();
+}
+
+bool CegConjectureSingleInv::addLemma( Node n ) {
+  d_curr_lemmas.push_back( n );
+  return true;
+}
+
+bool CegConjectureSingleInv::check( std::vector< Node >& lems ) {
+  if( !d_single_inv.isNull() ) {
+    Trace("cegqi-si-debug") << "CegConjectureSingleInv::check..." << std::endl;
+    Trace("cegqi-si-debug") << "CegConjectureSingleInv::check consulting ceg instantiation..." << std::endl;
+    d_curr_lemmas.clear();
+    Assert( d_cinst!=NULL );
+    //call check for instantiator
+    d_cinst->check();
+    Trace("cegqi-si-debug") << "...returned " << d_curr_lemmas.size() << " lemmas " <<  std::endl;
+    //add lemmas
+    lems.insert( lems.end(), d_curr_lemmas.begin(), d_curr_lemmas.end() );
+    return !lems.empty();
+  }else{
+    // not single invocation
+    return false;
+  }
+}
+
+Node CegConjectureSingleInv::constructSolution( std::vector< unsigned >& indices, unsigned i, unsigned index, std::map< Node, Node >& weak_imp ) {
+  Assert( index<d_inst.size() );
+  Assert( i<d_inst[index].size() );
+  unsigned uindex = indices[index];
+  if( index==indices.size()-1 ){
+    return d_inst[uindex][i];
+  }else{
+    Node cond = d_lemmas_produced[uindex];
+    //weaken based on unsat core
+    std::map< Node, Node >::iterator itw = weak_imp.find( cond );
+    if( itw!=weak_imp.end() ){
+      cond = itw->second;
+    }
+    cond = TermUtil::simpleNegate( cond );
+    Node ite1 = d_inst[uindex][i];
+    Node ite2 = constructSolution( indices, i, index+1, weak_imp );
+    return NodeManager::currentNM()->mkNode( ITE, cond, ite1, ite2 );
+  }
+}
+
+//TODO: use term size?
+struct sortSiInstanceIndices {
+  CegConjectureSingleInv* d_ccsi;
+  int d_i;
+  bool operator() (unsigned i, unsigned j) {
+    if( d_ccsi->d_inst[i][d_i].isConst() && !d_ccsi->d_inst[j][d_i].isConst() ){
+      return true;
+    }else{
+      return false;
+    }
+  }
+};
+
+
+Node CegConjectureSingleInv::postProcessSolution( Node n ){
+  ////remove boolean ITE (not allowed for sygus comp 2015)
+  //if( n.getKind()==ITE && n.getType().isBoolean() ){
+  //  Node n1 = postProcessSolution( n[1] );
+  //  Node n2 = postProcessSolution( n[2] );
+  //  return NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, n[0], n1 ),
+  //                                               NodeManager::currentNM()->mkNode( AND, n[0].negate(), n2 ) );
+  //}else{
+  bool childChanged = false;
+  Kind k = n.getKind();
+  if( n.getKind()==INTS_DIVISION_TOTAL ){
+    k = INTS_DIVISION;
+    childChanged = true;
+  }else if( n.getKind()==INTS_MODULUS_TOTAL ){
+    k = INTS_MODULUS;
+    childChanged = true;
+  }
+  std::vector< Node > children;
+  for( unsigned i=0; i<n.getNumChildren(); i++ ){
+    Node nn = postProcessSolution( n[i] );
+    children.push_back( nn );
+    childChanged = childChanged || nn!=n[i];
+  }
+  if( childChanged ){
+    if( n.hasOperator() && k==n.getKind() ){
+      children.insert( children.begin(), n.getOperator() );
+    }
+    return NodeManager::currentNM()->mkNode( k, children );
+  }else{
+    return n;
+  }
+  //}
+}
+
+
+Node CegConjectureSingleInv::getSolution( unsigned sol_index, TypeNode stn, int& reconstructed, bool rconsSygus ){
+  Assert( d_sol!=NULL );
+  Assert( !d_lemmas_produced.empty() );
+  const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
+  Node varList = Node::fromExpr( dt.getSygusVarList() );
+  Node prog = d_quant[0][sol_index];
+  std::vector< Node > vars;
+  Node s;
+  if( d_prog_to_sol_index.find( prog )==d_prog_to_sol_index.end() ){
+    Trace("csi-sol") << "Get solution for (unconstrained) " << prog << std::endl;
+    s = d_qe->getTermEnumeration()->getEnumerateTerm(
+        TypeNode::fromType(dt.getSygusType()), 0);
+  }else{
+    Trace("csi-sol") << "Get solution for " << prog << ", with skolems : ";
+    sol_index = d_prog_to_sol_index[prog];
+    d_sol->d_varList.clear();
+    Assert( d_single_inv_arg_sk.size()==varList.getNumChildren() );
+    for( unsigned i=0; i<d_single_inv_arg_sk.size(); i++ ){
+      Trace("csi-sol") << d_single_inv_arg_sk[i] << " ";
+      vars.push_back( d_single_inv_arg_sk[i] );
+      d_sol->d_varList.push_back( varList[i] );
+    }
+    Trace("csi-sol") << std::endl;
+
+    //construct the solution
+    Trace("csi-sol") << "Sort solution return values " << sol_index << std::endl;
+    bool useUnsatCore = false;
+    std::vector< Node > active_lemmas;
+    //minimize based on unsat core, if possible
+    std::map< Node, Node > weak_imp;
+    if( options::cegqiSolMinCore() ){
+      if( options::cegqiSolMinInst() ){
+        if( d_qe->getUnsatCoreLemmas( active_lemmas, weak_imp ) ){
+          useUnsatCore = true;
+        }
+      }else{
+        if( d_qe->getUnsatCoreLemmas( active_lemmas ) ){
+          useUnsatCore = true;
+        }
+      }
+    } 
+    Assert( d_lemmas_produced.size()==d_inst.size() );
+    std::vector< unsigned > indices;
+    for( unsigned i=0; i<d_lemmas_produced.size(); i++ ){
+      bool incl = true;
+      if( useUnsatCore ){
+        incl = std::find( active_lemmas.begin(), active_lemmas.end(), d_lemmas_produced[i] )!=active_lemmas.end();
+      }
+      if( incl ){
+        Assert( sol_index<d_inst[i].size() );
+        indices.push_back( i );
+      }
+    }
+    Trace("csi-sol") << "...included " << indices.size() << " / " << d_lemmas_produced.size() << " instantiations." << std::endl;
+    Assert( !indices.empty() );
+    //sort indices based on heuristic : currently, do all constant returns first (leads to simpler conditions)
+    // TODO : to minimize solution size, put the largest term last
+    sortSiInstanceIndices ssii;
+    ssii.d_ccsi = this;
+    ssii.d_i = sol_index;
+    std::sort( indices.begin(), indices.end(), ssii );
+    Trace("csi-sol") << "Construct solution" << std::endl;
+    s = constructSolution( indices, sol_index, 0, weak_imp );
+    Assert( vars.size()==d_sol->d_varList.size() );
+    s = s.substitute( vars.begin(), vars.end(), d_sol->d_varList.begin(), d_sol->d_varList.end() );
+  }
+  d_orig_solution = s;
+
+  //simplify the solution
+  Trace("csi-sol") << "Solution (pre-simplification): " << d_orig_solution << std::endl;
+  s = d_sol->simplifySolution( s, stn );
+  Trace("csi-sol") << "Solution (post-simplification): " << s << std::endl;
+  return reconstructToSyntax( s, stn, reconstructed, rconsSygus );
+}
+
+Node CegConjectureSingleInv::reconstructToSyntax( Node s, TypeNode stn, int& reconstructed, bool rconsSygus ) {
+  d_solution = s;
+  const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
+
+  //reconstruct the solution into sygus if necessary
+  reconstructed = 0;
+  if( options::cegqiSingleInvReconstruct() && !dt.getSygusAllowAll() && !stn.isNull() && rconsSygus ){
+    d_sol->preregisterConjecture( d_orig_conjecture );
+    d_sygus_solution = d_sol->reconstructSolution( s, stn, reconstructed );
+    if( reconstructed==1 ){
+      Trace("csi-sol") << "Solution (post-reconstruction into Sygus): " << d_sygus_solution << std::endl;
+    }
+  }else{
+    Trace("csi-sol") << "Post-process solution..." << std::endl;
+    Node prev = d_solution;
+    d_solution = postProcessSolution( d_solution );
+    if( prev!=d_solution ){
+      Trace("csi-sol") << "Solution (after post process) : " << d_solution << std::endl;
+    }
+  }
+
+
+  if( Trace.isOn("csi-sol") ){
+    //debug solution
+    if( !d_sol->debugSolution( d_solution ) ){
+      Trace("csi-sol") << "WARNING : solution " << d_solution << " contains free constants." << std::endl;
+      //exit( 47 );
+    }else{
+      //exit( 49 );
+    }
+  }
+  if( Trace.isOn("cegqi-stats") ){
+    int tsize, itesize;
+    tsize = 0;itesize = 0;
+    d_sol->debugTermSize( d_orig_solution, tsize, itesize );
+    Trace("cegqi-stats") << tsize << " " << itesize << " ";
+    tsize = 0;itesize = 0;
+    d_sol->debugTermSize( d_solution, tsize, itesize );
+    Trace("cegqi-stats") << tsize << " " << itesize << " ";
+    if( !d_sygus_solution.isNull() ){
+      tsize = 0;itesize = 0;
+      d_sol->debugTermSize( d_sygus_solution, tsize, itesize );
+      Trace("cegqi-stats") << tsize << " - ";
+    }else{
+      Trace("cegqi-stats") << "null ";
+    }
+    Trace("cegqi-stats") << std::endl;
+  }
+  Node sol;
+  if( reconstructed==1 ){
+    sol = d_sygus_solution;
+  }else if( reconstructed==-1 ){
+    return Node::null();
+  }else{
+    sol = d_solution;
+  }
+  //make into lambda
+  if( !dt.getSygusVarList().isNull() ){
+    Node varList = Node::fromExpr( dt.getSygusVarList() );
+    return NodeManager::currentNM()->mkNode( LAMBDA, varList, sol );
+  }else{
+    return sol;
+  }
+}
+
+bool CegConjectureSingleInv::needsCheck() {
+  if( options::cegqiSingleInvMode()==CEGQI_SI_MODE_ALL_ABORT ){
+    if( !d_has_ites ){
+      return d_inst.empty();
+    }
+  }
+  return true;
+}
+
+void CegConjectureSingleInv::preregisterConjecture( Node q ) {
+  d_orig_conjecture = q;
+}
+
+bool DetTrace::DetTraceTrie::add( Node loc, std::vector< Node >& val, unsigned index ){
+  if( index==val.size() ){
+    if( d_children.empty() ){
+      d_children[loc].clear();
+      return true;
+    }else{
+      return false;
+    }
+  }else{
+    return d_children[val[index]].add( loc, val, index+1 );
+  }
+}
+
+Node DetTrace::DetTraceTrie::constructFormula( std::vector< Node >& vars, unsigned index ){
+  if( index==vars.size() ){
+    return NodeManager::currentNM()->mkConst( true );    
+  }else{
+    std::vector< Node > disj;
+    for( std::map< Node, DetTraceTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+      Node eq = vars[index].eqNode( it->first );
+      if( index<vars.size()-1 ){
+        Node conc = it->second.constructFormula( vars, index+1 );
+        disj.push_back( NodeManager::currentNM()->mkNode( kind::AND, eq, conc ) );
+      }else{
+        disj.push_back( eq );
+      }
+    }
+    Assert( !disj.empty() );
+    return disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( kind::OR, disj );
+  }
+}
+
+bool DetTrace::increment( Node loc, std::vector< Node >& vals ){
+  if( d_trie.add( loc, vals ) ){
+    for( unsigned i=0; i<vals.size(); i++ ){
+      d_curr[i] = vals[i];
+    }
+    return true;
+  }else{
+    return false;
+  }
+}
+
+Node DetTrace::constructFormula( std::vector< Node >& vars ) {
+  return d_trie.constructFormula( vars );
+}
+
+
+void DetTrace::print( const char* c ) {
+  for( unsigned i=0; i<d_curr.size(); i++ ){
+    Trace(c) << d_curr[i] << " ";
+  }
+}
+
+void TransitionInference::initialize( Node f, std::vector< Node >& vars ) {
+  Assert( d_vars.empty() );
+  d_func = f;
+  d_vars.insert( d_vars.end(), vars.begin(), vars.end() );
+}
+
+
+void TransitionInference::getConstantSubstitution( std::vector< Node >& vars, std::vector< Node >& disjuncts, std::vector< Node >& const_var, std::vector< Node >& const_subs, bool reqPol ) {
+  for( unsigned j=0; j<disjuncts.size(); j++ ){
+    Node sn;
+    if( !const_var.empty() ){
+      sn = disjuncts[j].substitute( const_var.begin(), const_var.end(), const_subs.begin(), const_subs.end() );
+      sn = Rewriter::rewrite( sn );
+    }else{
+      sn = disjuncts[j];
+    }
+    bool slit_pol = sn.getKind()!=NOT;
+    Node slit = sn.getKind()==NOT ? sn[0] : sn;
+    if( slit.getKind()==EQUAL && slit_pol==reqPol ){
+      // check if it is a variable equality
+      TNode v;
+      Node s;
+      for( unsigned r=0; r<2; r++ ){
+        if( std::find( vars.begin(), vars.end(), slit[r] )!=vars.end() ){
+          if( !TermUtil::containsTerm( slit[1-r], slit[r] ) ){
+            v = slit[r];
+            s = slit[1-r];
+            break;
+          }
+        }
+      }
+      if( v.isNull() ){
+        //solve for var
+        std::map< Node, Node > msum;
+        if (ArithMSum::getMonomialSumLit(slit, msum))
+        {
+          for( std::map< Node, Node >::iterator itm = msum.begin(); itm != msum.end(); ++itm ){
+            if( std::find( vars.begin(), vars.end(), itm->first )!=vars.end() ){  
+              Node veq_c;
+              Node val;
+              int ires =
+                  ArithMSum::isolate(itm->first, msum, veq_c, val, EQUAL);
+              if( ires!=0 && veq_c.isNull() && !TermUtil::containsTerm( val, itm->first ) ){
+                v = itm->first;
+                s = val;
+              }
+            }
+          }
+        }
+      }
+      if( !v.isNull() ){
+        TNode ts = s;
+        for( unsigned k=0; k<const_subs.size(); k++ ){
+          const_subs[k] = Rewriter::rewrite( const_subs[k].substitute( v, ts ) );
+        }
+        Trace("cegqi-inv-debug2") << "...substitution : " << v << " -> " << s << std::endl;
+        const_var.push_back( v );
+        const_subs.push_back( s );
+      }
+    }
+  }
+}
+
+void TransitionInference::process( Node n ) {
+  d_complete = true;
+  std::vector< Node > n_check;
+  if( n.getKind()==AND ){
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      n_check.push_back( n[i] );
+    }
+  }else{
+    n_check.push_back( n );
+  }
+  for( unsigned i=0; i<n_check.size(); i++ ){
+    Node nn = n_check[i];
+    std::map< Node, bool > visited;
+    std::map< bool, Node > terms;
+    std::vector< Node > disjuncts;
+    Trace("cegqi-inv") << "TransitionInference : Process disjunct : " << nn << std::endl;
+    if( processDisjunct( nn, terms, disjuncts, visited, true ) ){
+      if( !terms.empty() ){
+        Node norm_args;
+        int comp_num;
+        std::map< bool, Node >::iterator itt = terms.find( false );
+        if( itt!=terms.end() ){
+          norm_args = itt->second;
+          if( terms.find( true )!=terms.end() ){
+            comp_num = 0;
+          }else{
+            comp_num = -1;
+          }
+        }else{
+          norm_args = terms[true];
+          comp_num = 1;
+        }
+        std::vector< Node > subs;
+        for( unsigned j=0; j<norm_args.getNumChildren(); j++ ){
+          subs.push_back( norm_args[j] );
+        }        
+        Trace("cegqi-inv-debug2") << "  normalize based on " << norm_args << std::endl;
+        Assert( d_vars.size()==subs.size() );
+        for( unsigned j=0; j<disjuncts.size(); j++ ){
+          disjuncts[j] = Rewriter::rewrite( disjuncts[j].substitute( subs.begin(), subs.end(), d_vars.begin(), d_vars.end() ) );
+          Trace("cegqi-inv-debug2") << "  ..." << disjuncts[j] << std::endl;
+        }
+        std::vector< Node > const_var;
+        std::vector< Node > const_subs;
+        if( comp_num==0 ){
+          //transition
+          Assert( terms.find( true )!=terms.end() );
+          Node next = terms[true];
+          next = Rewriter::rewrite( next.substitute( subs.begin(), subs.end(), d_vars.begin(), d_vars.end() ) );
+          Trace("cegqi-inv-debug") << "transition next predicate : " << next << std::endl;
+          // normalize the other direction
+          std::vector< Node > rvars;
+          for( unsigned i=0; i<next.getNumChildren(); i++ ){
+            rvars.push_back( next[i] );
+          }
+          if( d_prime_vars.size()<next.getNumChildren() ){
+            for( unsigned i=0; i<next.getNumChildren(); i++ ){
+              Node v = NodeManager::currentNM()->mkSkolem( "ir", next[i].getType(), "template inference rev argument" );
+              d_prime_vars.push_back( v );
+            }
+          }
+          Trace("cegqi-inv-debug2") << "  normalize based on " << next << std::endl;
+          Assert( d_vars.size()==subs.size() );
+          for( unsigned j=0; j<disjuncts.size(); j++ ){
+            disjuncts[j] = Rewriter::rewrite( disjuncts[j].substitute( rvars.begin(), rvars.end(), d_prime_vars.begin(), d_prime_vars.end() ) );
+            Trace("cegqi-inv-debug2") << "  ..." << disjuncts[j] << std::endl;
+          }
+          getConstantSubstitution( d_prime_vars, disjuncts, const_var, const_subs, false );
+        }else{
+          getConstantSubstitution( d_vars, disjuncts, const_var, const_subs, false );
+        }
+        Node res;
+        if( disjuncts.empty() ){
+          res = NodeManager::currentNM()->mkConst( false );
+        }else if( disjuncts.size()==1 ){
+          res = disjuncts[0];
+        }else{
+          res = NodeManager::currentNM()->mkNode( kind::OR, disjuncts );
+        }
+        if( !res.hasBoundVar() ){
+          Trace("cegqi-inv") << "*** inferred " << ( comp_num==1 ? "pre" : ( comp_num==-1 ? "post" : "trans" ) ) << "-condition : " << res << std::endl;
+          d_com[comp_num].d_conjuncts.push_back( res );
+          if( !const_var.empty() ){
+            bool has_const_eq = const_var.size()==d_vars.size();
+            Trace("cegqi-inv") << "    with constant substitution, complete = " << has_const_eq << " : " << std::endl;
+            for( unsigned i=0; i<const_var.size(); i++ ){
+              Trace("cegqi-inv") << "      " << const_var[i] << " -> " << const_subs[i] << std::endl;
+              if( has_const_eq ){
+                d_com[comp_num].d_const_eq[res][const_var[i]] = const_subs[i];
+              }
+            }
+            Trace("cegqi-inv") << "...size = " << const_var.size() << ", #vars = " << d_vars.size() << std::endl;
+          }
+        }else{
+          Trace("cegqi-inv-debug2") << "...failed, free variable." << std::endl;
+          d_complete = false;
+        }
+      }
+    }else{
+      d_complete = false;
+    }
+  }
+  
+  // finalize the components
+  for( int i=-1; i<=1; i++ ){
+    Node ret;
+    if( d_com[i].d_conjuncts.empty() ){
+      ret = NodeManager::currentNM()->mkConst( true );
+    }else if( d_com[i].d_conjuncts.size()==1 ){
+      ret = d_com[i].d_conjuncts[0];
+    }else{
+      ret = NodeManager::currentNM()->mkNode( kind::AND, d_com[i].d_conjuncts );
+    }
+    if( i==0 || i==1 ){
+      // pre-condition and transition are negated
+      ret = TermUtil::simpleNegate( ret );
+    }
+    d_com[i].d_this = ret;
+  }
+}
+
+bool TransitionInference::processDisjunct( Node n, std::map< bool, Node >& terms, std::vector< Node >& disjuncts, 
+                                           std::map< Node, bool >& visited, bool topLevel ) {
+  if( visited.find( n )==visited.end() ){
+    visited[n] = true;
+    bool childTopLevel = n.getKind()==OR && topLevel;
+    //if another part mentions UF or a free variable, then fail
+    bool lit_pol = n.getKind()!=NOT;
+    Node lit = n.getKind()==NOT ? n[0] : n;
+    if( lit.getKind()==APPLY_UF ){
+      Node op = lit.getOperator();
+      if( d_func.isNull() ){
+        d_func = op;
+        Trace("cegqi-inv-debug") << "Use " << op << " with args ";
+        for( unsigned i=0; i<lit.getNumChildren(); i++ ){
+          Node v = NodeManager::currentNM()->mkSkolem( "i", lit[i].getType(), "template inference argument" );
+          d_vars.push_back( v );
+          Trace("cegqi-inv-debug") << v << " ";
+        }
+        Trace("cegqi-inv-debug") << std::endl;
+      }
+      if( op!=d_func ){
+        Trace("cegqi-inv-debug") << "...failed, free function : " << n << std::endl;
+        return false;
+      }else if( topLevel ){
+        if( terms.find( lit_pol )==terms.end() ){
+          terms[lit_pol] = lit;
+          return true;
+        }else{
+          Trace("cegqi-inv-debug") << "...failed, repeated inv-app : " << lit << std::endl;
+          return false;
+        }
+      }else{
+        Trace("cegqi-inv-debug") << "...failed, non-entailed inv-app : " << lit << std::endl;
+        return false;
+      }
+    }else if( topLevel && !childTopLevel ){
+      disjuncts.push_back( n );
+    }
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      if( !processDisjunct( n[i], terms, disjuncts, visited, childTopLevel ) ){
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+Node TransitionInference::getComponent( int i ) {
+  return d_com[i].d_this;
+}
+
+int TransitionInference::initializeTrace( DetTrace& dt, Node loc, bool fwd ) {
+  int index = fwd ? 1 : -1;
+  Assert( d_com[index].has( loc ) );
+  std::map< Node, std::map< Node, Node > >::iterator it = d_com[index].d_const_eq.find( loc );
+  if( it!=d_com[index].d_const_eq.end() ){
+    std::vector< Node > next;
+    for( unsigned i=0; i<d_vars.size(); i++ ){
+      Node v = d_vars[i];
+      Assert( it->second.find( v )!=it->second.end() );
+      next.push_back( it->second[v] );
+      dt.d_curr.push_back( it->second[v] );
+    }
+    Trace("cegqi-inv-debug2") << "dtrace : initial increment" << std::endl;
+    bool ret = dt.increment( loc, next );
+    AlwaysAssert( ret );
+    return 0;
+  }
+  return -1;
+}
+  
+int TransitionInference::incrementTrace( DetTrace& dt, Node loc, bool fwd ) {
+  Assert( d_com[0].has( loc ) );
+  // check if it satisfies the pre/post condition
+  int check_index = fwd ? -1 : 1;
+  Node cc = getComponent( check_index );
+  Assert( !cc.isNull() );
+  Node ccr = Rewriter::rewrite( cc.substitute( d_vars.begin(), d_vars.end(), dt.d_curr.begin(), dt.d_curr.end() ) );
+  if( ccr.isConst() ){
+    if( ccr.getConst<bool>()==( fwd ? false : true ) ){
+      Trace("cegqi-inv-debug2") << "dtrace : counterexample" << std::endl;
+      return 2;
+    }
+  }
+
+
+  // terminates?
+  Node c = getComponent( 0 );
+  Assert( !c.isNull() );
+
+  Assert( d_vars.size()==dt.d_curr.size() );
+  Node cr = Rewriter::rewrite( c.substitute( d_vars.begin(), d_vars.end(), dt.d_curr.begin(), dt.d_curr.end() ) );
+  if( cr.isConst() ){
+    if( !cr.getConst<bool>() ){
+      Trace("cegqi-inv-debug2") << "dtrace : terminated" << std::endl;
+      return 1;
+    }else{
+      return -1;
+    }
+  }
+  if( fwd ){
+    std::map< Node, std::map< Node, Node > >::iterator it = d_com[0].d_const_eq.find( loc );
+    if( it!=d_com[0].d_const_eq.end() ){
+      std::vector< Node > next;
+      for( unsigned i=0; i<d_prime_vars.size(); i++ ){
+        Node pv = d_prime_vars[i];
+        Assert( it->second.find( pv )!=it->second.end() );
+        Node pvs = it->second[pv];
+        Assert( d_vars.size()==dt.d_curr.size() );
+        Node pvsr = Rewriter::rewrite( pvs.substitute( d_vars.begin(), d_vars.end(), dt.d_curr.begin(), dt.d_curr.end() ) );
+        next.push_back( pvsr );
+      }
+      if( dt.increment( loc, next ) ){
+        Trace("cegqi-inv-debug2") << "dtrace : success increment" << std::endl;
+        return 0;
+      }else{
+        // looped
+        Trace("cegqi-inv-debug2") << "dtrace : looped" << std::endl;
+        return 1;
+      }
+    }
+  }else{
+    //TODO
+  }
+  return -1;
+}
+
+int TransitionInference::initializeTrace( DetTrace& dt, bool fwd ) {
+  Trace("cegqi-inv-debug2") << "Initialize trace" << std::endl;
+  int index = fwd ? 1 : -1;
+  if( d_com[index].d_conjuncts.size()==1 ){
+    return initializeTrace( dt, d_com[index].d_conjuncts[0], fwd );
+  }else{
+    return -1;
+  }
+}
+
+int TransitionInference::incrementTrace( DetTrace& dt, bool fwd ) {
+  if( d_com[0].d_conjuncts.size()==1 ){
+    return incrementTrace( dt, d_com[0].d_conjuncts[0], fwd );
+  }else{
+    return -1;
+  }
+}
+
+Node TransitionInference::constructFormulaTrace( DetTrace& dt ) {
+  return dt.constructFormula( d_vars );
+}
+  
+} //namespace CVC4
+
diff --git a/src/theory/quantifiers/sygus/ce_guided_single_inv.h b/src/theory/quantifiers/sygus/ce_guided_single_inv.h
new file mode 100644 (file)
index 0000000..abdbef7
--- /dev/null
@@ -0,0 +1,248 @@
+/*********************                                                        */
+/*! \file ce_guided_single_inv.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief utility for processing single invocation synthesis conjectures
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_SINGLE_INV_H
+#define __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_SINGLE_INV_H
+
+#include "context/cdlist.h"
+#include "theory/quantifiers/sygus/ce_guided_single_inv_sol.h"
+#include "theory/quantifiers/inst_match_trie.h"
+#include "theory/quantifiers/cegqi/inst_strategy_cbqi.h"
+#include "theory/quantifiers/single_inv_partition.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class CegConjecture;
+class CegConjectureSingleInv;
+class CegEntailmentInfer;
+
+class CegqiOutputSingleInv : public CegqiOutput {
+public:
+  CegqiOutputSingleInv( CegConjectureSingleInv * out ) : d_out( out ){}
+  virtual ~CegqiOutputSingleInv() {}
+  CegConjectureSingleInv * d_out;
+  bool doAddInstantiation( std::vector< Node >& subs );
+  bool isEligibleForInstantiation( Node n );
+  bool addLemma( Node lem );
+};
+
+class DetTrace {
+private:
+  class DetTraceTrie {
+  public:
+    std::map< Node, DetTraceTrie > d_children;
+    bool add( Node loc, std::vector< Node >& val, unsigned index = 0 );
+    void clear() { d_children.clear(); }
+    Node constructFormula( std::vector< Node >& vars, unsigned index = 0 );
+  };
+  DetTraceTrie d_trie;
+public:
+  std::vector< Node > d_curr;
+  bool increment( Node loc, std::vector< Node >& vals );
+  Node constructFormula( std::vector< Node >& vars );
+  void print( const char* c );
+};
+
+class TransitionInference {
+private:
+  bool processDisjunct( Node n, std::map< bool, Node >& terms, std::vector< Node >& disjuncts, std::map< Node, bool >& visited, bool topLevel );
+  void getConstantSubstitution( std::vector< Node >& vars, std::vector< Node >& disjuncts, std::vector< Node >& const_var, std::vector< Node >& const_subs, bool reqPol );
+  bool d_complete;
+public:
+  TransitionInference() : d_complete( false ) {}
+  std::vector< Node > d_vars;
+  std::vector< Node > d_prime_vars;
+  Node d_func;
+  
+  class Component {
+  public:
+    Component(){}
+    Node d_this;
+    std::vector< Node > d_conjuncts;
+    std::map< Node, std::map< Node, Node > > d_const_eq;
+    bool has( Node c ) { return std::find( d_conjuncts.begin(), d_conjuncts.end(), c )!=d_conjuncts.end(); }
+  };
+  std::map< int, Component > d_com;
+  
+  void initialize( Node f, std::vector< Node >& vars );
+  void process( Node n );
+  Node getComponent( int i );
+  bool isComplete() { return d_complete; }
+  
+  // 0 : success, 1 : terminated, 2 : counterexample, -1 : invalid
+  int initializeTrace( DetTrace& dt, Node loc, bool fwd = true );
+  int incrementTrace( DetTrace& dt, Node loc, bool fwd = true );
+  int initializeTrace( DetTrace& dt, bool fwd = true );
+  int incrementTrace( DetTrace& dt, bool fwd = true );
+  Node constructFormulaTrace( DetTrace& dt );
+};
+
+// this class infers whether a conjecture is single invocation (Reynolds et al CAV 2015), and sets up the
+// counterexample-guided quantifier instantiation utility (d_cinst), and methods for solution
+// reconstruction (d_sol).
+// It also has more advanced techniques for:
+// (1) partitioning a conjecture into single invocation / non-single invocation portions for invariant synthesis,
+// (2) inferring whether the conjecture corresponds to a deterministic transistion system (by utility d_ti).
+// For these techniques, we may generate a template (d_templ) which specifies a restricted
+// solution space. We may in turn embed this template as a SyGuS grammar.
+class CegConjectureSingleInv {
+ private:
+  friend class CegqiOutputSingleInv;
+  //presolve
+  void collectPresolveEqTerms( Node n,
+                               std::map< Node, std::vector< Node > >& teq );
+  void getPresolveEqConjuncts( std::vector< Node >& vars,
+                               std::vector< Node >& terms,
+                               std::map< Node, std::vector< Node > >& teq,
+                               Node n, std::vector< Node >& conj );
+  // constructing solution
+  Node constructSolution(std::vector<unsigned>& indices, unsigned i,
+                         unsigned index, std::map<Node, Node>& weak_imp);
+  Node postProcessSolution(Node n);
+ private:
+  QuantifiersEngine* d_qe;
+  CegConjecture* d_parent;
+  // single invocation inference utility
+  SingleInvocationPartition* d_sip;
+  // transition inference module for each function to synthesize
+  std::map< Node, TransitionInference > d_ti;
+  // solution reconstruction
+  CegConjectureSingleInvSol* d_sol;
+  // the instantiator's output channel
+  CegqiOutputSingleInv* d_cosi;
+  // the instantiator
+  CegInstantiator* d_cinst;
+
+  // list of skolems for each argument of programs
+  std::vector<Node> d_single_inv_arg_sk;
+  // list of variables/skolems for each program
+  std::vector<Node> d_single_inv_var;
+  std::vector<Node> d_single_inv_sk;
+  std::map<Node, int> d_single_inv_sk_index;
+  // program to solution index
+  std::map<Node, unsigned> d_prog_to_sol_index;
+  // lemmas produced
+  inst::InstMatchTrie d_inst_match_trie;
+  inst::CDInstMatchTrie* d_c_inst_match_trie;
+  // original conjecture
+  Node d_orig_conjecture;
+  // solution
+  Node d_orig_solution;
+  Node d_solution;
+  Node d_sygus_solution;
+  // whether the grammar for our solution allows ITEs, this tells us when reconstruction is infeasible
+  bool d_has_ites;
+
+ public:
+  // lemmas produced
+  std::vector<Node> d_lemmas_produced;
+  std::vector<std::vector<Node> > d_inst;
+
+ private:
+  std::vector<Node> d_curr_lemmas;
+  // add instantiation
+  bool doAddInstantiation( std::vector< Node >& subs );
+  //is eligible for instantiation
+  bool isEligibleForInstantiation( Node n );
+  // add lemma
+  bool addLemma( Node lem );
+  // conjecture
+  Node d_quant;
+  Node d_simp_quant;
+  // are we single invocation?
+  bool d_single_invocation;
+  // single invocation portion of quantified formula
+  Node d_single_inv;
+  Node d_si_guard;
+  // transition relation version per program
+  std::map< Node, Node > d_trans_pre;
+  std::map< Node, Node > d_trans_post;
+  // the template for each function to synthesize
+  std::map< Node, Node > d_templ;
+  // the template argument for each function to synthesize (occurs in exactly one position of its template)
+  std::map< Node, Node > d_templ_arg;
+  
+ public:
+  CegConjectureSingleInv( QuantifiersEngine * qe, CegConjecture * p );
+  ~CegConjectureSingleInv();
+
+  // get simplified conjecture
+  Node getSimplifiedConjecture() { return d_simp_quant; }
+  // get single invocation guard
+  Node getGuard() { return d_si_guard; }
+ public:
+  //get the single invocation lemma(s)
+  void getInitialSingleInvLemma( std::vector< Node >& lems );
+  // initialize this class for synthesis conjecture q
+  void initialize( Node q );
+  // finish initialize, sets up final decisions about whether to use single invocation techniques
+  //  syntaxRestricted is whether the syntax for solutions for the initialized conjecture is restricted
+  //  hasItes is whether the syntax for solutions for the initialized conjecture allows ITEs
+  void finishInit( bool syntaxRestricted, bool hasItes );
+  //check
+  bool check( std::vector< Node >& lems );
+  //get solution
+  Node getSolution( unsigned sol_index, TypeNode stn, int& reconstructed, bool rconsSygus = true );
+  //reconstruct to syntax
+  Node reconstructToSyntax( Node s, TypeNode stn, int& reconstructed,
+                            bool rconsSygus = true );
+  // has ites
+  bool hasITEs() { return d_has_ites; }
+  // is single invocation
+  bool isSingleInvocation() const { return !d_single_inv.isNull(); }
+  //needs check
+  bool needsCheck();
+  /** preregister conjecture */
+  void preregisterConjecture( Node q );
+
+  Node getTransPre(Node prog) const {
+    std::map<Node, Node>::const_iterator location = d_trans_pre.find(prog);
+    return location->second;
+  }
+
+  Node getTransPost(Node prog) const {
+    std::map<Node, Node>::const_iterator location = d_trans_post.find(prog);
+    return location->second;
+  }
+  // get template for program prog. This returns a term of the form t[x] where x is the template argument (see below)
+  Node getTemplate(Node prog) const {
+    std::map<Node, Node>::const_iterator tmpl = d_templ.find(prog);
+    if( tmpl!=d_templ.end() ){
+      return tmpl->second;
+    }else{
+      return Node::null();
+    }
+  }
+  // get the template argument for program prog.
+  // This is a variable which indicates the position of the function/predicate to synthesize.
+  Node getTemplateArg(Node prog) const {
+    std::map<Node, Node>::const_iterator tmpla = d_templ_arg.find(prog);
+    if( tmpla != d_templ_arg.end() ){
+      return tmpla->second;
+    }else{
+      return Node::null();
+    }
+  }
+};
+
+}/* namespace CVC4::theory::quantifiers */
+}/* namespace CVC4::theory */
+}/* namespace CVC4 */
+
+#endif
diff --git a/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.cpp b/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.cpp
new file mode 100644 (file)
index 0000000..f900297
--- /dev/null
@@ -0,0 +1,1512 @@
+/*********************                                                        */
+/*! \file ce_guided_single_inv_sol.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Paul Meng, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief utility for processing single invocation synthesis conjectures
+ **
+ **/
+#include "theory/quantifiers/sygus/ce_guided_single_inv_sol.h"
+
+#include "expr/datatype.h"
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/sygus/ce_guided_instantiation.h"
+#include "theory/quantifiers/sygus/ce_guided_single_inv.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
+#include "theory/quantifiers/term_enumeration.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers/ematching/trigger.h"
+#include "theory/theory_engine.h"
+
+using namespace CVC4::kind;
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+bool doCompare(Node a, Node b, Kind k)
+{
+  Node com = NodeManager::currentNM()->mkNode(k, a, b);
+  com = Rewriter::rewrite(com);
+  Assert(com.getType().isBoolean());
+  return com.isConst() && com.getConst<bool>();
+}
+
+CegConjectureSingleInvSol::CegConjectureSingleInvSol(QuantifiersEngine* qe)
+    : d_qe(qe), d_id_count(0), d_root_id() {}
+
+bool CegConjectureSingleInvSol::debugSolution( Node sol ) {
+  if( sol.getKind()==SKOLEM ){
+    return false;
+  }else{
+    for( unsigned i=0; i<sol.getNumChildren(); i++ ){
+      if( !debugSolution( sol[i] ) ){
+        return false;
+      }
+    }
+    return true;
+  }
+
+}
+
+void CegConjectureSingleInvSol::debugTermSize( Node sol, int& t_size, int& num_ite ) {
+  std::map< Node, int >::iterator it = d_dterm_size.find( sol );
+  if( it==d_dterm_size.end() ){
+    int prev = t_size;
+    int prev_ite = num_ite;
+    t_size++;
+    if( sol.getKind()==ITE ){
+      num_ite++;
+    }
+    for( unsigned i=0; i<sol.getNumChildren(); i++ ){
+      debugTermSize( sol[i], t_size, num_ite );
+    }
+    d_dterm_size[sol] = t_size-prev;
+    d_dterm_ite_size[sol] = num_ite-prev_ite;
+  }else{
+    t_size += it->second;
+    num_ite += d_dterm_ite_size[sol];
+  }
+}
+
+
+Node CegConjectureSingleInvSol::pullITEs( Node s ) {
+  if( s.getKind()==ITE ){
+    bool success;
+    do {
+      success = false;
+      std::vector< Node > conj;
+      Node t;
+      Node rem;
+      if( pullITECondition( s, s, conj, t, rem, 0 ) ){
+        Assert( !conj.empty() );
+        Node cond = conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj );
+        Trace("csi-sol-debug") << "For " << s << ", can pull " << cond << " -> " << t << " with remainder " << rem << std::endl;
+        t = pullITEs( t );
+        rem = pullITEs( rem );
+        Trace("csi-pull-ite") << "PI: Rewrite : " << s << std::endl;
+        Node prev = s;
+        s = NodeManager::currentNM()->mkNode( ITE, TermUtil::simpleNegate( cond ), t, rem );
+        Trace("csi-pull-ite") << "PI: Rewrite Now : " << s << std::endl;
+        Trace("csi-pull-ite") << "(= " << prev << " " << s << ")" << std::endl;
+        success = true;
+      }
+    }while( success );
+  }
+  return s;
+}
+
+// pull condition common to all ITE conditions in path of size > 1
+bool CegConjectureSingleInvSol::pullITECondition( Node root, Node n_ite, std::vector< Node >& conj, Node& t, Node& rem, int depth ) {
+  Assert( n_ite.getKind()==ITE );
+  std::vector< Node > curr_conj;
+  std::vector< Node > orig_conj;
+  bool isAnd;
+  if( n_ite[0].getKind()==AND || n_ite[0].getKind()==OR ){
+    isAnd = n_ite[0].getKind()==AND;
+    for( unsigned i=0; i<n_ite[0].getNumChildren(); i++ ){
+      Node cond = n_ite[0][i];
+      orig_conj.push_back( cond );
+      if( n_ite[0].getKind()==OR ){
+        cond = TermUtil::simpleNegate( cond );
+      }
+      curr_conj.push_back( cond );
+    }
+  }else{
+    Node neg = n_ite[0].negate();
+    if( std::find( conj.begin(), conj.end(), neg )!=conj.end() ){
+      //if negation of condition exists, use it
+      isAnd = false;
+      curr_conj.push_back( neg );
+    }else{
+      //otherwise, use condition
+      isAnd = true;
+      curr_conj.push_back( n_ite[0] );
+    }
+    orig_conj.push_back( n_ite[0] );
+  }
+  // take intersection with current conditions
+  std::vector< Node > new_conj;
+  std::vector< Node > prev_conj;
+  if( n_ite==root ){
+    new_conj.insert( new_conj.end(), curr_conj.begin(), curr_conj.end() );
+    Trace("csi-sol-debug") << "Pull ITE root " << n_ite << ", #conj = " << new_conj.size() << std::endl;
+  }else{
+    for( unsigned i=0; i<curr_conj.size(); i++ ){
+      if( std::find( conj.begin(), conj.end(), curr_conj[i] )!=conj.end() ){
+        new_conj.push_back( curr_conj[i] );
+      }
+    }
+    Trace("csi-sol-debug") << "Pull ITE " << n_ite << ", #conj = " << conj.size() << " intersect " << curr_conj.size() << " = " << new_conj.size() << std::endl;
+  }
+  //cannot go further
+  if( new_conj.empty() ){
+    return false;
+  }
+  //it is an intersection with current
+  conj.clear();
+  conj.insert( conj.end(), new_conj.begin(), new_conj.end() );
+  //recurse if possible
+  Node trec = n_ite[ isAnd ? 2 : 1 ];
+  Node tval = n_ite[ isAnd ? 1 : 2 ];
+  bool success = false;
+  if( trec.getKind()==ITE ){
+    prev_conj.insert( prev_conj.end(), conj.begin(), conj.end() );
+    success = pullITECondition( root, trec, conj, t, rem, depth+1 );
+  }
+  if( !success && depth>0 ){
+    t = trec;
+    rem = trec;
+    success = true;
+    if( trec.getKind()==ITE ){
+      //restore previous state
+      conj.clear();
+      conj.insert( conj.end(), prev_conj.begin(), prev_conj.end() );
+    }
+  }
+  if( success ){
+    //make remainder : strip out conditions in conj
+    Assert( !conj.empty() );
+    std::vector< Node > cond_c;
+    Assert( orig_conj.size()==curr_conj.size() );
+    for( unsigned i=0; i<curr_conj.size(); i++ ){
+      if( std::find( conj.begin(), conj.end(), curr_conj[i] )==conj.end() ){
+        cond_c.push_back( orig_conj[i] );
+      }
+    }
+    if( cond_c.empty() ){
+      rem = tval;
+    }else{
+      Node new_cond = cond_c.size()==1 ? cond_c[0] : NodeManager::currentNM()->mkNode( n_ite[0].getKind(), cond_c );
+      rem = NodeManager::currentNM()->mkNode( ITE, new_cond, isAnd ? tval : rem, isAnd ? rem : tval );
+    }
+    return true;
+  }else{
+    return false;
+  }
+}
+
+Node CegConjectureSingleInvSol::flattenITEs( Node n, bool rec ) {
+  Assert( !n.isNull() );
+  if( n.getKind()==ITE ){
+    Trace("csi-sol-debug") << "Flatten ITE." << std::endl;
+    Node ret;
+    Node n0 = rec ? flattenITEs( n[0] ) : n[0];
+    Node n1 = rec ? flattenITEs( n[1] ) : n[1];
+    Node n2 = rec ? flattenITEs( n[2] ) : n[2];
+    Assert( !n0.isNull() );
+    Assert( !n1.isNull() );
+    Assert( !n2.isNull() );
+    if( n0.getKind()==NOT ){
+      ret = NodeManager::currentNM()->mkNode( ITE, n0[0], n2, n1 );
+    }else if( n0.getKind()==AND || n0.getKind()==OR ){
+      std::vector< Node > children;
+      for( unsigned i=1; i<n0.getNumChildren(); i++ ){
+        children.push_back( n0[i] );
+      }
+      Node rem = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( n0.getKind(), children );
+      if( n0.getKind()==AND ){
+        ret = NodeManager::currentNM()->mkNode( ITE, rem, NodeManager::currentNM()->mkNode( ITE, n0[0], n1, n2 ), n2 );
+      }else{
+        ret = NodeManager::currentNM()->mkNode( ITE, rem, n1, NodeManager::currentNM()->mkNode( ITE, n0[0], n1, n2 ) );
+      }
+    }else{
+      if( n0.getKind()==ITE ){
+        n0 = NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, n0, n1 ),
+                                                   NodeManager::currentNM()->mkNode( AND, n0.negate(), n2 ) );
+      }else if( n0.getKind()==EQUAL && n0[0].getType().isBoolean() ){
+        n0 = NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, n0, n1 ),
+                                                   NodeManager::currentNM()->mkNode( AND, n0.negate(), n1.negate() ) );
+      }else{
+        return NodeManager::currentNM()->mkNode( ITE, n0, n1, n2 );
+      }
+      ret = NodeManager::currentNM()->mkNode( ITE, n0, n1, n2 );
+    }
+    Assert( !ret.isNull() );
+    return flattenITEs( ret, false );
+  }else{
+    if( n.getNumChildren()>0 ){
+      std::vector< Node > children;
+      if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+        children.push_back( n.getOperator() );
+      }
+      bool childChanged = false;
+      for( unsigned i=0; i<n.getNumChildren(); i++ ){
+        Node nc = flattenITEs( n[i] );
+        children.push_back( nc );
+        childChanged = childChanged || nc!=n[i];
+      }
+      if( !childChanged ){
+        return n;
+      }else{
+        return NodeManager::currentNM()->mkNode( n.getKind(), children );
+      }
+    }else{
+      return n;
+    }
+  }
+}
+
+// assign is from literals to booleans
+// union_find is from args to values
+
+bool CegConjectureSingleInvSol::getAssign( bool pol, Node n, std::map< Node, bool >& assign, std::vector< Node >& new_assign, std::vector< Node >& vars,
+                                        std::vector< Node >& new_vars, std::vector< Node >& new_subs ) {
+  std::map< Node, bool >::iterator ita = assign.find( n );
+  if( ita!=assign.end() ){
+    Trace("csi-simp-debug") << "---already assigned, lookup " << pol << " " << ita->second << std::endl;
+    return pol==ita->second;
+  }else if( n.isConst() ){
+    return pol==(n==d_qe->getTermUtil()->d_true);
+  }else{
+    Trace("csi-simp-debug") << "---assign " << n << " " << pol << std::endl;
+    assign[n] = pol;
+    new_assign.push_back( n );
+    if( ( pol && n.getKind()==AND ) || ( !pol && n.getKind()==OR ) ){
+      for( unsigned i=0; i<n.getNumChildren(); i++ ){
+        if( !getAssign( pol, n[i], assign, new_assign, vars, new_vars, new_subs ) ){
+          return false;
+        }
+      }
+    }else if( n.getKind()==NOT ){
+      return getAssign( !pol, n[0], assign, new_assign, vars, new_vars, new_subs );
+    }else if( pol && n.getKind()==EQUAL ){
+      getAssignEquality( n, vars, new_vars, new_subs );
+    }
+  }
+  return true;
+}
+
+bool CegConjectureSingleInvSol::getAssignEquality( Node eq, std::vector< Node >& vars, std::vector< Node >& new_vars, std::vector< Node >& new_subs ) {
+  Assert( eq.getKind()==EQUAL );
+  //try to find valid argument
+  for( unsigned r=0; r<2; r++ ){
+    if( std::find( d_varList.begin(), d_varList.end(), eq[r] )!=d_varList.end() ){
+      Assert( std::find( vars.begin(), vars.end(), eq[r] )==vars.end() );
+      if( std::find( new_vars.begin(), new_vars.end(), eq[r] )==new_vars.end() ){
+        Node eqro = eq[r==0 ? 1 : 0 ];
+        if( !d_qe->getTermUtil()->containsTerm( eqro, eq[r] ) ){
+          Trace("csi-simp-debug") << "---equality " << eq[r] << " = " << eqro << std::endl;
+          new_vars.push_back( eq[r] );
+          new_subs.push_back( eqro );
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+Node CegConjectureSingleInvSol::simplifySolution( Node sol, TypeNode stn ){
+  int tsize, itesize;
+  if( Trace.isOn("csi-sol") ){
+    tsize = 0;itesize = 0;
+    debugTermSize( sol, tsize, itesize );
+    Trace("csi-sol") << tsize << " " << itesize << " rewrite..." << std::endl;
+    Trace("csi-sol-debug") << "sol : " << sol << "..." << std::endl;
+  }
+  Node sol0 = Rewriter::rewrite( sol );
+  Trace("csi-sol") << "now : " << sol0 << std::endl;
+
+  Node curr_sol = sol0;
+  Node prev_sol;
+  do{
+    prev_sol = curr_sol;
+    //first, pull ITE conditions
+    if( Trace.isOn("csi-sol") ){
+      tsize = 0;itesize = 0;
+      debugTermSize( curr_sol, tsize, itesize );
+      Trace("csi-sol") << tsize << " " << itesize << " pull ITE..." << std::endl;
+      Trace("csi-sol-debug") << "sol : " << curr_sol << "..." << std::endl;
+    }
+    Node sol1 = pullITEs( curr_sol );
+    Trace("csi-sol") << "now : " << sol1 << std::endl;
+    //do standard rewriting
+    if( sol1!=curr_sol ){
+      if( Trace.isOn("csi-sol") ){
+        tsize = 0;itesize = 0;
+        debugTermSize( sol1, tsize, itesize );
+        Trace("csi-sol") << tsize << " " << itesize << " rewrite..." << std::endl;
+        Trace("csi-sol-debug") << "sol : " << sol1 << "..." << std::endl;
+      }
+      Node sol2 = Rewriter::rewrite( sol1 );
+      Trace("csi-sol") << "now : " << sol2 << std::endl;
+      curr_sol = sol2;
+    }
+    //now do branch analysis
+    if( Trace.isOn("csi-sol") ){
+      tsize = 0;itesize = 0;
+      debugTermSize( curr_sol, tsize, itesize );
+      Trace("csi-sol") << tsize << " " << itesize << " simplify solution..." << std::endl;
+      Trace("csi-sol-debug") << "sol : " << curr_sol << "..." << std::endl;
+    }
+    std::map< Node, bool > sassign;
+    std::vector< Node > svars;
+    std::vector< Node > ssubs;
+    Node sol3 = simplifySolutionNode( curr_sol, stn, sassign, svars, ssubs, 0 );
+    Trace("csi-sol") << "now : " << sol3 << std::endl;
+    if( sol3!=curr_sol ){
+      //do standard rewriting again
+      if( Trace.isOn("csi-sol" ) ){
+        tsize = 0;itesize = 0;
+        debugTermSize( sol3, tsize, itesize );
+        Trace("csi-sol") << tsize << " " << itesize << " rewrite..." << std::endl;
+      }
+      Node sol4 = Rewriter::rewrite( sol3 );
+      Trace("csi-sol") << "now : " << sol4 << std::endl;
+      curr_sol = sol4;
+    }
+  }while( curr_sol!=prev_sol );
+
+  return curr_sol;
+}
+
+Node CegConjectureSingleInvSol::simplifySolutionNode( Node sol, TypeNode stn, std::map< Node, bool >& assign,
+                                                      std::vector< Node >& vars, std::vector< Node >& subs, int status ) {
+
+  Assert( vars.size()==subs.size() );
+  std::map< Node, bool >::iterator ita = assign.find( sol );
+  if( ita!=assign.end() ){
+    //it is currently assigned a boolean value
+    return NodeManager::currentNM()->mkConst( ita->second );
+  }else{
+    d_qe->getTermDatabaseSygus()->registerSygusType( stn );
+    std::map< int, TypeNode > stnc;
+    if( !stn.isNull() ){
+      int karg = d_qe->getTermDatabaseSygus()->getKindConsNum( stn, sol.getKind() );
+      if( karg!=-1 ){
+        const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
+        if( dt[karg].getNumArgs()==sol.getNumChildren() ){
+          for( unsigned i=0; i<dt[karg].getNumArgs(); i++ ){
+            stnc[i] = d_qe->getTermDatabaseSygus()->getArgType( dt[karg], i );
+          }
+        }
+      }
+    }
+
+    if( sol.getKind()==ITE ){
+      Trace("csi-simp") << "Simplify ITE " << std::endl;
+      std::vector< Node > children;
+      for( unsigned r=1; r<=2; r++ ){
+        std::vector< Node > new_assign;
+        std::vector< Node > new_vars;
+        std::vector< Node > new_subs;
+        if( getAssign( r==1, sol[0], assign, new_assign, vars, new_vars, new_subs ) ){
+          Trace("csi-simp") << "- branch " << r << " led to " << new_assign.size() << " assignments, " << new_vars.size() << " equalities." << std::endl;
+          unsigned prev_size = vars.size();
+          Node nc = sol[r];
+          if( !new_vars.empty() ){
+            nc = nc.substitute( new_vars.begin(), new_vars.end(), new_subs.begin(), new_subs.end() );
+            vars.insert( vars.end(), new_vars.begin(), new_vars.end() );
+            subs.insert( subs.end(), new_subs.begin(), new_subs.end() );
+          }
+          nc = simplifySolutionNode( nc, stnc[r], assign, vars, subs, 0 );
+          children.push_back( nc );
+          //clean up substitution
+          if( !new_vars.empty() ){
+            vars.resize( prev_size );
+            subs.resize( prev_size );
+          }
+        }else{
+          Trace("csi-simp") << "- branch " << r << " of " << sol[0] << " is infeasible." << std::endl;
+        }
+        //clean up assignment
+        for( unsigned i=0; i<new_assign.size(); i++ ){
+          assign.erase( new_assign[i] );
+        }
+      }
+      if( children.size()==1 || ( children.size()==2 && children[0]==children[1] ) ){
+        return children[0];
+      }else{
+        Assert( children.size()==2 );
+        Node ncond = simplifySolutionNode( sol[0], stnc[0], assign, vars, subs, 0 );
+        Node ret = NodeManager::currentNM()->mkNode( ITE, ncond, children[0], children[1] );
+
+        //expand/flatten if necessary
+        Node orig_ret = ret;
+        if( !stnc[0].isNull() ){
+          d_qe->getTermDatabaseSygus()->registerSygusType( stnc[0] );
+          Node prev_ret;
+          while( !d_qe->getTermDatabaseSygus()->hasKind( stnc[0], ret[0].getKind() ) && ret!=prev_ret ){
+            prev_ret = ret;
+            Node exp_c = d_qe->getTermDatabaseSygus()->expandBuiltinTerm( ret[0] );
+            if( !exp_c.isNull() ){
+              Trace("csi-simp-debug") << "Pre expand to " << ret[0] << " to " << exp_c << std::endl;
+              ret = NodeManager::currentNM()->mkNode( ITE, exp_c, ret[1], ret[2] );
+            }
+            if( !d_qe->getTermDatabaseSygus()->hasKind( stnc[0], ret[0].getKind() ) ){
+              Trace("csi-simp-debug") << "Flatten based on " << ret[0] << "." << std::endl;
+              ret = flattenITEs( ret, false );
+            }
+          }
+        }
+        return ret;
+        /*
+        if( orig_ret!=ret ){
+          Trace("csi-simp") << "Try expanded ITE" << std::endl;
+          return ret;//simplifySolutionNode( ret, stn, assign, vars, subs, status );
+        }else{
+          return ret;
+        }
+        */
+      }
+    }else if( sol.getKind()==OR || sol.getKind()==AND ){
+      Trace("csi-simp") << "Simplify " << sol.getKind() << std::endl;
+      //collect new equalities
+      std::map< Node, bool > atoms;
+      std::vector< Node > inc;
+      std::vector< Node > children;
+      std::vector< Node > new_vars;
+      std::vector< Node > new_subs;
+      Node bc = sol.getKind()==OR ? d_qe->getTermUtil()->d_true : d_qe->getTermUtil()->d_false;
+      for( unsigned i=0; i<sol.getNumChildren(); i++ ){
+        bool do_exc = false;
+        Node c;
+        std::map< Node, bool >::iterator ita = assign.find( sol[i] );
+        if( ita==assign.end() ){
+          c = sol[i];
+        }else{
+          c = NodeManager::currentNM()->mkConst( ita->second );
+        }
+        Trace("csi-simp") << "  - child " << i << " : " << c << std::endl;
+        if( c.isConst() ){
+          if( c==bc ){
+            Trace("csi-simp") << "  ...singularity." << std::endl;
+            return bc;
+          }else{
+            do_exc = true;
+          }
+        }else{
+          Node atom = c.getKind()==NOT ? c[0] : c;
+          bool pol = c.getKind()!=NOT;
+          std::map< Node, bool >::iterator it = atoms.find( atom );
+          if( it==atoms.end() ){
+            atoms[atom] = pol;
+            if( status==0 && atom.getKind()==EQUAL ){
+              if( pol==( sol.getKind()==AND ) ){
+                Trace("csi-simp") << "  ...equality." << std::endl;
+                if( getAssignEquality( atom, vars, new_vars, new_subs ) ){
+                  children.push_back( sol[i] );
+                  do_exc = true;
+                }
+              }
+            }
+          }else{
+            //repeated atom
+            if( it->second!=pol ){
+              return NodeManager::currentNM()->mkConst( sol.getKind()==OR );
+            }else{
+              do_exc = true;
+            }
+          }
+        }
+        if( !do_exc ){
+          inc.push_back( sol[i] );
+        }else{
+          Trace("csi-simp") << "  ...exclude." << std::endl;
+        }
+      }
+      if( !new_vars.empty() ){
+        if( !inc.empty() ){
+          Node ret = inc.size()==1 ? inc[0] : NodeManager::currentNM()->mkNode( sol.getKind(), inc );
+          Trace("csi-simp") << "Base return is : " << ret << std::endl;
+          // apply substitution
+          ret = ret.substitute( new_vars.begin(), new_vars.end(), new_subs.begin(), new_subs.end() );
+          ret = Rewriter::rewrite( ret );
+          Trace("csi-simp") << "After substitution : " << ret << std::endl;
+          unsigned prev_size = vars.size();
+          vars.insert( vars.end(), new_vars.begin(), new_vars.end() );
+          subs.insert( subs.end(), new_subs.begin(), new_subs.end() );
+          ret = simplifySolutionNode( ret, TypeNode::null(), assign, vars, subs, 1 );
+          //clean up substitution
+          if( !vars.empty() ){
+            vars.resize( prev_size );
+            subs.resize( prev_size );
+          }
+          //Trace("csi-simp") << "After simplification : " << ret << std::endl;
+          if( ret.isConst() ){
+            if( ret==bc ){
+              return bc;
+            }
+          }else{
+            if( ret.getKind()==sol.getKind() ){
+              for( unsigned i=0; i<ret.getNumChildren(); i++ ){
+                children.push_back( ret[i] );
+              }
+            }else{
+              children.push_back( ret );
+            }
+          }
+        }
+      }else{
+        //recurse on children
+        for( unsigned i=0; i<inc.size(); i++ ){
+          Node retc = simplifySolutionNode( inc[i], TypeNode::null(), assign, vars, subs, 0 );
+          if( retc.isConst() ){
+            if( retc==bc ){
+              return bc;
+            }
+          }else{
+            children.push_back( retc );
+          }
+        }
+      }
+      // now, remove all equalities that are implied
+      std::vector< Node > final_children;
+      for( unsigned i=0; i<children.size(); i++ ){
+        bool red = false;
+        Node atom = children[i].getKind()==NOT ? children[i][0] : children[i];
+        bool pol = children[i].getKind()!=NOT;
+        if( status==0 && atom.getKind()==EQUAL ){
+          if( pol!=( sol.getKind()==AND ) ){
+            std::vector< Node > tmp_vars;
+            std::vector< Node > tmp_subs;
+            if( getAssignEquality( atom, vars, tmp_vars, tmp_subs ) ){
+              Trace("csi-simp-debug") << "Check if " << children[i] << " is redundant in " << sol << std::endl;
+              for( unsigned j=0; j<children.size(); j++ ){
+                if( j!=i && ( j>i || std::find( final_children.begin(), final_children.end(), children[j] )!=final_children.end() ) ){
+                  Node sj = children[j].substitute( tmp_vars.begin(), tmp_vars.end(), tmp_subs.begin(), tmp_subs.end() );
+                  sj = Rewriter::rewrite( sj );
+                  if( sj==( sol.getKind()==AND ? d_qe->getTermUtil()->d_false : d_qe->getTermUtil()->d_true ) ){
+                    Trace("csi-simp") << "--- " << children[i].negate() << " is implied by " << children[j].negate() << std::endl;
+                    red = true;
+                    break;
+                  }
+                }
+              }
+              if( !red ){
+                Trace("csi-simp-debug") << "...is not." << std::endl;
+              }
+            }
+          }
+        }
+        if( !red ){
+          final_children.push_back( children[i] );
+        }
+      }
+      return final_children.size()==0 ? NodeManager::currentNM()->mkConst( sol.getKind()==AND ) :
+             ( final_children.size()==1 ? final_children[0] : NodeManager::currentNM()->mkNode( sol.getKind(), final_children ) );
+    }else{
+      //generic simplification
+      std::vector< Node > children;
+      if( sol.getMetaKind() == kind::metakind::PARAMETERIZED ){
+        children.push_back( sol.getOperator() );
+      }
+      bool childChanged = false;
+      for( unsigned i=0; i<sol.getNumChildren(); i++ ){
+        Node nc = simplifySolutionNode( sol[i], stnc[i], assign, vars, subs, 0 );
+        childChanged = childChanged || nc!=sol[i];
+        children.push_back( nc );
+      }
+      if( childChanged ){
+        return NodeManager::currentNM()->mkNode( sol.getKind(), children );
+      }
+    }
+    return sol;
+  }
+}
+
+
+void CegConjectureSingleInvSol::preregisterConjecture( Node q ) {
+  Trace("csi-sol") << "Preregister conjecture : " << q << std::endl;
+  Node n = q;
+  if( n.getKind()==FORALL ){
+    n = n[1];
+  }
+  if( n.getKind()==EXISTS ){
+    if( n[0].getNumChildren()==d_varList.size() ){
+      std::vector< Node > evars;
+      for( unsigned i=0; i<n[0].getNumChildren(); i++ ){
+        evars.push_back( n[0][i] );
+      }
+      n = n[1].substitute( evars.begin(), evars.end(), d_varList.begin(), d_varList.end() );
+    }else{
+      Trace("csi-sol") << "Not the same number of variables, return." << std::endl;
+      return;
+    }
+  }
+  Trace("csi-sol") << "Preregister node for solution reconstruction : " << n << std::endl;
+  registerEquivalentTerms( n );
+}
+
+Node CegConjectureSingleInvSol::reconstructSolution( Node sol, TypeNode stn, int& reconstructed ) {
+  Trace("csi-rcons") << "Solution (pre-reconstruction) is : " << sol << std::endl;
+  int status;
+  d_root_id = collectReconstructNodes( sol, stn, status );
+  if( status==0 ){
+    Node ret = getReconstructedSolution( d_root_id );
+    Trace("csi-rcons") << "Sygus solution is : " << ret << std::endl;
+    Assert( !ret.isNull() );
+    reconstructed = 1;
+    return ret;
+  }else{
+    //Trace("csi-debug-sol") << "Induced solution template is : " << d_templ_solution << std::endl;
+    if( Trace.isOn("csi-rcons") ){
+      for( std::map< TypeNode, std::map< Node, int > >::iterator it = d_rcons_to_id.begin(); it != d_rcons_to_id.end(); ++it ){
+        TypeNode tn = it->first;
+        Assert( tn.isDatatype() );
+        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+        Trace("csi-rcons") << "Terms to reconstruct of type " << dt.getName() << " : " << std::endl;
+        for( std::map< Node, int >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+          if( d_reconstruct.find( it2->second )==d_reconstruct.end() ){
+            Trace("csi-rcons") << "  " << it2->first << std::endl;
+          }
+        }
+        Assert( !it->second.empty() );
+      }
+    }
+    unsigned index = 0;
+    std::map< TypeNode, bool > active;
+    for( std::map< TypeNode, std::map< Node, int > >::iterator it = d_rcons_to_id.begin(); it != d_rcons_to_id.end(); ++it ){
+      active[it->first] = true;
+    }
+    //enumerate for all types
+    do {
+      std::vector< TypeNode > to_erase;
+      for( std::map< TypeNode, bool >::iterator it = active.begin(); it != active.end(); ++it ){
+        TypeNode stn = it->first;
+        Node ns = d_qe->getTermEnumeration()->getEnumerateTerm(stn, index);
+        if( ns.isNull() ){
+          to_erase.push_back( stn );
+        }else{
+          Node nb = d_qe->getTermDatabaseSygus()->sygusToBuiltin( ns, stn );
+          Node nr = Rewriter::rewrite( nb );//d_qe->getTermDatabaseSygus()->getNormalized( stn, nb, false, false );
+          Trace("csi-rcons-debug2") << "  - try " << ns << " -> " << nr << " for " << stn << " " << nr.getKind() << std::endl;
+          std::map< Node, int >::iterator itt = d_rcons_to_id[stn].find( nr );
+          if( itt!= d_rcons_to_id[stn].end() ){
+            // if it is not already reconstructed
+            if( d_reconstruct.find( itt->second )==d_reconstruct.end() ){
+              Trace("csi-rcons") << "...reconstructed " << ns << " for term " << nr << std::endl;
+              bool do_check = true;//getPathToRoot( itt->second );
+              setReconstructed( itt->second, ns );
+              if( do_check ){
+                Trace("csi-rcons-debug") << "...path to root, try reconstruction." << std::endl;
+                d_tmp_fail.clear();
+                Node ret = getReconstructedSolution( d_root_id );
+                if( !ret.isNull() ){
+                  Trace("csi-rcons") << "Sygus solution (after enumeration) is : " << ret << std::endl;
+                  reconstructed = 1;
+                  return ret;
+                }
+              }else{
+                Trace("csi-rcons-debug") << "...no path to root." << std::endl;
+              }
+            }
+          }
+        }
+      }
+      for( unsigned i=0; i<to_erase.size(); i++ ){
+        active.erase( to_erase[i] );
+      }
+      index++;
+      if( index%100==0 ){
+        Trace("csi-rcons-stats") << "Tried " << index << " for each type."  << std::endl;
+      }
+    }while( !active.empty() );
+
+    // we ran out of elements, return null
+    reconstructed = -1;
+    Warning() << CommandFailure("Cannot get synth function: reconstruction to syntax failed.");
+    return Node::null(); // return sol;
+  }
+}
+
+int CegConjectureSingleInvSol::collectReconstructNodes( Node t, TypeNode stn, int& status ) {
+  std::map< Node, int >::iterator itri = d_rcons_to_status[stn].find( t );
+  if( itri!=d_rcons_to_status[stn].end() ){
+    status = itri->second;
+    //Trace("csi-rcons-debug") << "-> (cached) " << status << " for " << d_rcons_to_id[stn][t] << std::endl;
+    return d_rcons_to_id[stn][t];
+  }else{
+    status = 1;
+    // register the type
+    registerType(stn);
+    int id = allocate( t, stn );
+    d_rcons_to_status[stn][t] = -1;
+    TypeNode tn = t.getType();
+    Assert( stn.isDatatype() );
+    const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
+    Assert( dt.isSygus() );
+    Trace("csi-rcons-debug") << "Check reconstruct " << t << ", sygus type " << dt.getName() << ", kind " << t.getKind() << ", id : " << id << std::endl;
+    int carg = -1;
+    int karg = -1;
+    // first, do standard minimizations
+    Node min_t = d_qe->getTermDatabaseSygus()->minimizeBuiltinTerm( t );
+    Trace("csi-rcons-debug") << "Minimized term is : " << min_t << std::endl;
+    //check if op is in syntax sort
+    carg = d_qe->getTermDatabaseSygus()->getOpConsNum( stn, min_t );
+    if( carg!=-1 ){
+      Trace("csi-rcons-debug") << "  Type has operator." << std::endl;
+      d_reconstruct[id] = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, Node::fromExpr( dt[carg].getConstructor() ) );
+      status = 0;
+    }else{
+      //check if kind is in syntax sort
+      karg = d_qe->getTermDatabaseSygus()->getKindConsNum( stn, min_t.getKind() );
+      if( karg!=-1 ){
+        //collect the children of min_t
+        std::vector< Node > tchildren;
+        if( min_t.getNumChildren()>dt[karg].getNumArgs() && quantifiers::TermUtil::isAssoc( min_t.getKind() ) && dt[karg].getNumArgs()==2 ){
+          tchildren.push_back( min_t[0] );
+          std::vector< Node > rem_children;
+          for( unsigned i=1; i<min_t.getNumChildren(); i++ ){
+            rem_children.push_back( min_t[i] );
+          }
+          Node t2 = NodeManager::currentNM()->mkNode( min_t.getKind(), rem_children );
+          tchildren.push_back( t2 );
+          Trace("csi-rcons-debug") << "...split n-ary to binary " << min_t[0] << " " << t2 << "." << std::endl;
+        }else{
+          for( unsigned i=0; i<min_t.getNumChildren(); i++ ){
+            tchildren.push_back( min_t[i] );
+          }
+        }
+        //recurse on the children
+        if( tchildren.size()==dt[karg].getNumArgs() ){
+          Trace("csi-rcons-debug") << "Type for " << id << " has kind " << min_t.getKind() << ", recurse." << std::endl;
+          status = 0;
+          Node cons = Node::fromExpr( dt[karg].getConstructor() );
+          if( !collectReconstructNodes( id, tchildren, dt[karg], d_reconstruct_op[id][cons], status ) ){
+            Trace("csi-rcons-debug") << "...failure for " << id << " " << dt[karg].getName() << std::endl;
+            d_reconstruct_op[id].erase( cons );
+            status = 1;
+          }
+        }else{
+          Trace("csi-rcons-debug") << "Type for " << id << " has kind " << min_t.getKind() << ", but argument # mismatch." << std::endl;
+        }
+      }
+      if( status!=0 ){
+        //try constant reconstruction
+        if( min_t.isConst() ){
+          Trace("csi-rcons-debug") << "...try constant reconstruction." << std::endl;
+          Node min_t_c = builtinToSygusConst(min_t, stn);
+          if( !min_t_c.isNull() ){
+            Trace("csi-rcons-debug") << "   constant reconstruction success for " << id << ", result = " << min_t_c << std::endl;
+            d_reconstruct[id] = min_t_c;
+            status = 0;
+          }
+        }
+        if( status!=0 ){
+          //try identity functions
+          for (unsigned ii : d_id_funcs[stn])
+          {
+            Assert( dt[ii].getNumArgs()==1 );
+            //try to directly reconstruct from single argument
+            std::vector< Node > tchildren;
+            tchildren.push_back( min_t );
+            TypeNode stnc = TypeNode::fromType( ((SelectorType)dt[ii][0].getType()).getRangeType() );
+            Trace("csi-rcons-debug") << "...try identity function " << dt[ii].getSygusOp() << ", child type is " << stnc << std::endl;
+            status = 0;
+            Node cons = Node::fromExpr( dt[ii].getConstructor() );
+            if( !collectReconstructNodes( id, tchildren, dt[ii], d_reconstruct_op[id][cons], status ) ){
+              d_reconstruct_op[id].erase( cons );
+              status = 1;
+            }else{
+              Trace("csi-rcons-debug") << "   identity function success for " << id << std::endl;
+              break;
+            }
+          }
+          if( status!=0 ){
+            //try other options, such as matching against other constructors
+            Trace("csi-rcons-debug") << "Try matching for " << id << "." << std::endl;
+            bool success;
+            int c_index = 0;
+            do{
+              success = false;
+              int index_found;
+              std::vector< Node > args;
+              if (getMatch(min_t, stn, index_found, args, karg, c_index))
+              {
+                success = true;
+                status = 0;
+                Node cons = Node::fromExpr( dt[index_found].getConstructor() );
+                Trace("csi-rcons-debug") << "Try alternative for " << id << ", matching " << dt[index_found].getName() << " with children : " << std::endl;
+                for( unsigned i=0; i<args.size(); i++ ){
+                  Trace("csi-rcons-debug") << "  " << args[i] << std::endl;
+                }
+                if( !collectReconstructNodes( id, args, dt[index_found], d_reconstruct_op[id][cons], status ) ){
+                  d_reconstruct_op[id].erase( cons );
+                  status = 1;
+                }else{
+                  c_index = index_found+1;
+                }
+              }
+            }while( success && status!=0 );
+
+            if( status!=0 ){
+              // construct an equivalence class of terms that are equivalent to t
+              if( d_rep[id]==id ){
+                Trace("csi-rcons-debug") << "Try rewriting for " << id << "." << std::endl;
+                //get equivalence class of term
+                std::vector< Node > equiv;
+                if( tn.isBoolean() ){
+                  Node curr = min_t;
+                  Node new_t;
+                  do{
+                    new_t = Node::null();
+                    if( curr.getKind()==EQUAL ){
+                      if( curr[0].getType().isInteger() || curr[0].getType().isReal() ){
+                        new_t = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( LEQ, curr[0], curr[1] ),
+                                                                      NodeManager::currentNM()->mkNode( LEQ, curr[1], curr[0] ) );
+                      }else if( curr[0].getType().isBoolean() ){
+                        new_t = NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, curr[0], curr[1] ),
+                                                                      NodeManager::currentNM()->mkNode( AND, curr[0].negate(), curr[1].negate() ) );
+                      }else{
+                        new_t = NodeManager::currentNM()->mkNode( NOT, NodeManager::currentNM()->mkNode( NOT, curr ) );
+                      }
+                    }else if( curr.getKind()==ITE ){
+                      new_t = NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, curr[0], curr[1] ),
+                                                                    NodeManager::currentNM()->mkNode( AND, curr[0].negate(), curr[2] ) );
+                    }else if( curr.getKind()==OR || curr.getKind()==AND ){
+                      new_t = TermUtil::simpleNegate( curr ).negate();
+                    }else if( curr.getKind()==NOT ){
+                      new_t = TermUtil::simpleNegate( curr[0] );
+                    }else{
+                      new_t = NodeManager::currentNM()->mkNode( NOT, NodeManager::currentNM()->mkNode( NOT, curr ) );
+                    }
+                    if( !new_t.isNull() ){
+                      if( new_t!=min_t && std::find( equiv.begin(), equiv.end(), new_t )==equiv.end() ){
+                        curr = new_t;
+                        equiv.push_back( new_t );
+                      }else{
+                        new_t = Node::null();
+                      }
+                    }
+                  }while( !new_t.isNull() );
+                }
+                //get decompositions
+                for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+                  Kind k = d_qe->getTermDatabaseSygus()->getConsNumKind( stn, i );
+                  getEquivalentTerms( k, min_t, equiv );
+                }
+                //assign ids to terms
+                Trace("csi-rcons-debug") << "Term " << id << " is equivalent to " << equiv.size() << " terms : " << std::endl;
+                std::vector< int > equiv_ids;
+                for( unsigned i=0; i<equiv.size(); i++ ){
+                  Trace("csi-rcons-debug") << "  " << equiv[i] << std::endl;
+                  if( d_rcons_to_id[stn].find( equiv[i] )==d_rcons_to_id[stn].end() ){
+                    int eq_id = allocate( equiv[i], stn );
+                    d_eqc.erase( eq_id );
+                    d_rep[eq_id] = id;
+                    d_eqc[id].push_back( eq_id );
+                    equiv_ids.push_back( eq_id );
+                  }else{
+                    equiv_ids.push_back( -1 );
+                  }
+                }
+                // now, try each of them
+                for( unsigned i=0; i<equiv.size(); i++ ){
+                  if( equiv_ids[i]!=-1 ){
+                    collectReconstructNodes( equiv[i], stn, status );
+                    //if one succeeds
+                    if( status==0 ){
+                      Node rsol = getReconstructedSolution( equiv_ids[i] );
+                      Assert( !rsol.isNull() );
+                      //set all members of the equivalence class that this is the reconstructed solution
+                      setReconstructed( id, rsol );
+                      break;
+                    }
+                  }
+                }
+              }else{
+                Trace("csi-rcons-debug") << "Do not try rewriting for " << id << ", rep = " << d_rep[id] << std::endl;
+              }
+            }
+          }
+        }
+      }
+    }
+    if( status!=0 ){
+      Trace("csi-rcons-debug") << "-> *** reconstruction required for id " << id << std::endl;
+    }else{
+      Trace("csi-rcons-debug") << "-> success for " << id << std::endl;
+    }
+    d_rcons_to_status[stn][t] = status;
+    return id;
+  }
+}
+
+bool CegConjectureSingleInvSol::collectReconstructNodes( int pid, std::vector< Node >& ts, const DatatypeConstructor& dtc, std::vector< int >& ids, int& status ) {
+  Assert( dtc.getNumArgs()==ts.size() );
+  for( unsigned i=0; i<ts.size(); i++ ){
+    TypeNode cstn = d_qe->getTermDatabaseSygus()->getArgType( dtc, i );
+    int cstatus;
+    int c_id = collectReconstructNodes( ts[i], cstn, cstatus );
+    if( cstatus==-1 ){
+      return false;
+    }else if( cstatus!=0 ){
+      status = 1;
+    }
+    ids.push_back( c_id );
+  }
+  for( unsigned i=0; i<ids.size(); i++ ){
+    d_parents[ids[i]].push_back( pid );
+  }
+  return true;
+}
+
+  /*
+  //flatten ITEs if necessary  TODO : carry assignment or move this elsewhere
+  if( t.getKind()==ITE ){
+    TypeNode cstn = tds->getArgType( dt[karg], 0 );
+    tds->registerSygusType( cstn );
+    Node prev_t;
+    while( !tds->hasKind( cstn, t[0].getKind() ) && t!=prev_t ){
+      prev_t = t;
+      Node exp_c = tds->expandBuiltinTerm( t[0] );
+      if( !exp_c.isNull() ){
+        t = NodeManager::currentNM()->mkNode( ITE, exp_c, t[1], t[2] );
+        Trace("csi-rcons-debug") << "Pre expand to " << t << std::endl;
+      }
+      t = flattenITEs( t, false );
+      if( t!=prev_t ){
+        Trace("csi-rcons-debug") << "Flatten ITE to " << t << std::endl;
+        std::map< Node, bool > sassign;
+        std::vector< Node > svars;
+        std::vector< Node > ssubs;
+        t = simplifySolutionNode( t, sassign, svars, ssubs, 0 );
+      }
+      Assert( t.getKind()==ITE );
+    }
+  }
+  */
+
+
+Node CegConjectureSingleInvSol::CegConjectureSingleInvSol::getReconstructedSolution( int id, bool mod_eq ) {
+  std::map< int, Node >::iterator it = d_reconstruct.find( id );
+  if( it!=d_reconstruct.end() ){
+    return it->second;
+  }else{
+    if( std::find( d_tmp_fail.begin(), d_tmp_fail.end(), id )!=d_tmp_fail.end() ){
+      return Node::null();
+    }else{
+      // try each child option
+      std::map< int, std::map< Node, std::vector< int > > >::iterator ito = d_reconstruct_op.find( id );
+      if( ito!=d_reconstruct_op.end() ){
+        for( std::map< Node, std::vector< int > >::iterator itt = ito->second.begin(); itt != ito->second.end(); ++itt ){
+          std::vector< Node > children;
+          children.push_back( itt->first );
+          bool success = true;
+          for( unsigned i=0; i<itt->second.size(); i++ ){
+            Node nc = getReconstructedSolution( itt->second[i] );
+            if( nc.isNull() ){
+              success = false;
+              break;
+            }else{
+              children.push_back( nc );
+            }
+          }
+          if( success ){
+            Node ret = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+            setReconstructed( id, ret );
+            return ret;
+          }
+        }
+      }
+      // try terms in the equivalence class of this
+      if( mod_eq ){
+        int rid = d_rep[id];
+        for( unsigned i=0; i<d_eqc[rid].size(); i++ ){
+          int tid = d_eqc[rid][i];
+          if( tid!=id ){
+            Node eret = getReconstructedSolution( tid, false );
+            if( !eret.isNull() ){
+              setReconstructed( id, eret );
+              return eret;
+            }
+          }
+        }
+      }
+      d_tmp_fail.push_back( id );
+      return Node::null();
+    }
+  }
+}
+
+int CegConjectureSingleInvSol::allocate( Node n, TypeNode stn ) {
+  std::map< Node, int >::iterator it = d_rcons_to_id[stn].find( n );
+  if( it==d_rcons_to_id[stn].end() ){
+    int ret = d_id_count;
+    if( Trace.isOn("csi-rcons-debug") ){
+      const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
+      Trace("csi-rcons-debug") << "id " << ret << " : " << n << " " <<  dt.getName() << std::endl;
+    }
+    d_id_node[d_id_count] = n;
+    d_id_type[d_id_count] = stn;
+    d_rep[d_id_count] = d_id_count;
+    d_eqc[d_id_count].push_back( d_id_count );
+    d_rcons_to_id[stn][n] = d_id_count;
+    d_id_count++;
+    return ret;
+  }else{
+    return it->second;
+  }
+}
+
+bool CegConjectureSingleInvSol::getPathToRoot( int id ) {
+  if( id==d_root_id ){
+    return true;
+  }else{
+    std::map< int, Node >::iterator it = d_reconstruct.find( id );
+    if( it!=d_reconstruct.end() ){
+      return false;
+    }else{
+      int rid = d_rep[id];
+      for( unsigned j=0; j<d_parents[rid].size(); j++ ){
+        if( getPathToRoot( d_parents[rid][j] ) ){
+          return true;
+        }
+      }
+      return false;
+    }
+  }
+}
+
+void CegConjectureSingleInvSol::setReconstructed( int id, Node n ) {
+  //set all equivalent to this as reconstructed
+  int rid = d_rep[id];
+  for( unsigned i=0; i<d_eqc[rid].size(); i++ ){
+    d_reconstruct[d_eqc[rid][i]] = n;
+  }
+}
+
+void CegConjectureSingleInvSol::getEquivalentTerms( Kind k, Node n, std::vector< Node >& equiv ) {
+  if( k==AND || k==OR ){
+    equiv.push_back( NodeManager::currentNM()->mkNode( k, n, n ) );
+    equiv.push_back( NodeManager::currentNM()->mkNode( k, n, NodeManager::currentNM()->mkConst( k==AND ) ) );
+  }
+  //multiplication for integers
+  //TODO for bitvectors
+  Kind mk = ( k==PLUS || k==MINUS ) ? MULT : UNDEFINED_KIND;
+  if( mk!=UNDEFINED_KIND ){
+    if( n.getKind()==mk && n[0].isConst() && n[0].getType().isInteger() ){
+      bool success = true;
+      for( unsigned i=0; i<2; i++ ){
+        Node eq;
+        if( k==PLUS || k==MINUS ){
+          Node oth = NodeManager::currentNM()->mkConst( Rational(i==0 ? 1000 : -1000) );
+          eq = i==0 ? NodeManager::currentNM()->mkNode( LEQ, n[0], oth ) : NodeManager::currentNM()->mkNode( GEQ, n[0], oth );
+        }
+        if( !eq.isNull() ){
+          eq = Rewriter::rewrite( eq );
+          if( eq!=d_qe->getTermUtil()->d_true ){
+            success = false;
+            break;
+          }
+        }
+      }
+      if( success ){
+        Node var = n[1];
+        Node rem;
+        if( k==PLUS || k==MINUS ){
+          int rem_coeff = (int)n[0].getConst<Rational>().getNumerator().getSignedInt();
+          if( rem_coeff>0 && k==PLUS ){
+            rem_coeff--;
+          }else if( rem_coeff<0 && k==MINUS ){
+            rem_coeff++;
+          }else{
+            success = false;
+          }
+          if( success ){
+            rem = NodeManager::currentNM()->mkNode( MULT, NodeManager::currentNM()->mkConst( Rational(rem_coeff) ), var );
+            rem = Rewriter::rewrite( rem );
+          }
+        }
+        if( !rem.isNull() ){
+          equiv.push_back( NodeManager::currentNM()->mkNode( k, rem, var ) );
+        }
+      }
+    }
+  }
+  //negative constants
+  if( k==MINUS ){
+    if( n.isConst() && n.getType().isInteger() && n.getConst<Rational>().getNumerator().strictlyNegative() ){
+      Node nn = NodeManager::currentNM()->mkNode( UMINUS, n );
+      nn = Rewriter::rewrite( nn );
+      equiv.push_back( NodeManager::currentNM()->mkNode( MINUS, NodeManager::currentNM()->mkConst( Rational(0) ), nn ) );
+    }
+  }
+  //inequalities
+  if( k==GEQ || k==LEQ || k==LT || k==GT || k==NOT ){
+    Node atom = n.getKind()==NOT ? n[0] : n;
+    bool pol = n.getKind()!=NOT;
+    Kind ak = atom.getKind();
+    if( ( ak==GEQ || ak==LEQ || ak==LT || ak==GT ) && ( pol || k!=NOT ) ){
+      Node t1 = atom[0];
+      Node t2 = atom[1];
+      if( !pol ){
+        ak = ak==GEQ ? LT : ( ak==LEQ ? GT : ( ak==LT ? GEQ : LEQ ) );
+      }
+      if( k==NOT ){
+        equiv.push_back( NodeManager::currentNM()->mkNode( ak==GEQ ? LT : ( ak==LEQ ? GT : ( ak==LT ? GEQ : LEQ ) ), t1, t2 ).negate() );
+      }else if( k==ak ){
+        equiv.push_back( NodeManager::currentNM()->mkNode( k, t1, t2 ) );
+      }else if( (k==GEQ || k==LEQ)==(ak==GEQ || ak==LEQ) ){
+        equiv.push_back( NodeManager::currentNM()->mkNode( k, t2, t1 ) );
+      }else if( t1.getType().isInteger() && t2.getType().isInteger() ){
+        if( (k==GEQ || k==GT)!=(ak==GEQ || ak==GT) ){
+          Node ts = t1;
+          t1 = t2;
+          t2 = ts;
+          ak = ak==GEQ ? LEQ : ( ak==LEQ ? GEQ : ( ak==LT ? GT : LT ) );
+        }
+        t2 = NodeManager::currentNM()->mkNode( PLUS, t2, NodeManager::currentNM()->mkConst( Rational( (ak==GT || ak==LEQ) ? 1 : -1 ) ) );
+        t2 = Rewriter::rewrite( t2 );
+        equiv.push_back( NodeManager::currentNM()->mkNode( k, t1, t2 ) );
+      }
+    }
+  }
+
+  //based on eqt cache
+  std::map< Node, Node >::iterator itet = d_eqt_rep.find( n );
+  if( itet!=d_eqt_rep.end() ){
+    Node rn = itet->second;
+    for( unsigned i=0; i<d_eqt_eqc[rn].size(); i++ ){
+      if( d_eqt_eqc[rn][i]!=n && d_eqt_eqc[rn][i].getKind()==k ){
+        if( std::find( equiv.begin(), equiv.end(), d_eqt_eqc[rn][i] )==equiv.end() ){
+          equiv.push_back( d_eqt_eqc[rn][i] );
+        }
+      }
+    }
+  }
+}
+
+void CegConjectureSingleInvSol::registerEquivalentTerms( Node n ) {
+  for( unsigned i=0; i<n.getNumChildren(); i++ ){
+    registerEquivalentTerms( n[i] );
+  }
+  Node rn = Rewriter::rewrite( n );
+  if( rn!=n ){
+    Trace("csi-equiv") << "  eq terms : " << n << " " << rn << std::endl;
+    d_eqt_rep[n] = rn;
+    d_eqt_rep[rn] = rn;
+    if( std::find( d_eqt_eqc[rn].begin(), d_eqt_eqc[rn].end(), rn )==d_eqt_eqc[rn].end() ){
+      d_eqt_eqc[rn].push_back( rn );
+    }
+    if( std::find( d_eqt_eqc[rn].begin(), d_eqt_eqc[rn].end(), n )==d_eqt_eqc[rn].end() ){
+      d_eqt_eqc[rn].push_back( n );
+    }
+  }
+}
+
+Node CegConjectureSingleInvSol::builtinToSygusConst(Node c,
+                                                    TypeNode tn,
+                                                    int rcons_depth)
+{
+  std::map<Node, Node>::iterator it = d_builtin_const_to_sygus[tn].find(c);
+  if (it != d_builtin_const_to_sygus[tn].end())
+  {
+    return it->second;
+  }
+  TermDbSygus* tds = d_qe->getTermDatabaseSygus();
+  NodeManager* nm = NodeManager::currentNM();
+  Node sc;
+  d_builtin_const_to_sygus[tn][c] = sc;
+  Assert(c.isConst());
+  Assert(tn.isDatatype());
+  const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
+  Trace("csi-rcons-debug") << "Try to reconstruct " << c << " in "
+                           << dt.getName() << std::endl;
+  Assert(dt.isSygus());
+  // if we are not interested in reconstructing constants, or the grammar allows
+  // them, return a proxy
+  if (!options::cegqiSingleInvReconstructConst() || dt.getSygusAllowConst())
+  {
+    Node k = nm->mkSkolem("sy", tn, "sygus proxy");
+    SygusPrintProxyAttribute spa;
+    k.setAttribute(spa, c);
+    sc = k;
+  }
+  else
+  {
+    int carg = tds->getOpConsNum(tn, c);
+    if (carg != -1)
+    {
+      sc = nm->mkNode(APPLY_CONSTRUCTOR,
+                      Node::fromExpr(dt[carg].getConstructor()));
+    }
+    else
+    {
+      // identity functions
+      for (unsigned ii : d_id_funcs[tn])
+      {
+        Assert(dt[ii].getNumArgs() == 1);
+        // try to directly reconstruct from single argument
+        TypeNode tnc = tds->getArgType(dt[ii], 0);
+        Trace("csi-rcons-debug")
+            << "Based on id function " << dt[ii].getSygusOp()
+            << ", try reconstructing " << c << " instead in " << tnc
+            << std::endl;
+        Node n = builtinToSygusConst(c, tnc, rcons_depth);
+        if (!n.isNull())
+        {
+          sc = nm->mkNode(
+              APPLY_CONSTRUCTOR, Node::fromExpr(dt[ii].getConstructor()), n);
+          break;
+        }
+      }
+      if (sc.isNull())
+      {
+        if (rcons_depth < 1000)
+        {
+          // accelerated, recursive reconstruction of constants
+          Kind pk = tds->getPlusKind(TypeNode::fromType(dt.getSygusType()));
+          if (pk != UNDEFINED_KIND)
+          {
+            int arg = tds->getKindConsNum(tn, pk);
+            if (arg != -1)
+            {
+              Kind ck =
+                  tds->getComparisonKind(TypeNode::fromType(dt.getSygusType()));
+              Kind pkm =
+                  tds->getPlusKind(TypeNode::fromType(dt.getSygusType()), true);
+              // get types
+              Assert(dt[arg].getNumArgs() == 2);
+              TypeNode tn1 = tds->getArgType(dt[arg], 0);
+              TypeNode tn2 = tds->getArgType(dt[arg], 1);
+              // initialize d_const_list for tn1
+              registerType(tn1);
+              // iterate over all positive constants, largest to smallest
+              int start = d_const_list[tn1].size() - 1;
+              int end = d_const_list[tn1].size() - d_const_list_pos[tn1];
+              for (int i = start; i >= end; --i)
+              {
+                Node c1 = d_const_list[tn1][i];
+                // only consider if smaller than c, and
+                if (doCompare(c1, c, ck))
+                {
+                  Node c2 = nm->mkNode(pkm, c, c1);
+                  c2 = Rewriter::rewrite(c2);
+                  if (c2.isConst())
+                  {
+                    // reconstruct constant on the other side
+                    Node sc2 = builtinToSygusConst(c2, tn2, rcons_depth + 1);
+                    if (!sc2.isNull())
+                    {
+                      Node sc1 = builtinToSygusConst(c1, tn1, rcons_depth);
+                      Assert(!sc1.isNull());
+                      sc = nm->mkNode(APPLY_CONSTRUCTOR,
+                                      Node::fromExpr(dt[arg].getConstructor()),
+                                      sc1,
+                                      sc2);
+                      break;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  d_builtin_const_to_sygus[tn][c] = sc;
+  return sc;
+}
+
+struct sortConstants
+{
+  Kind d_comp_kind;
+  bool operator()(Node i, Node j)
+  {
+    return i != j && doCompare(i, j, d_comp_kind);
+  }
+};
+
+void CegConjectureSingleInvSol::registerType(TypeNode tn)
+{
+  if (d_const_list_pos.find(tn) != d_const_list_pos.end())
+  {
+    return;
+  }
+  d_const_list_pos[tn] = 0;
+  Assert(tn.isDatatype());
+
+  TermDbSygus* tds = d_qe->getTermDatabaseSygus();
+  // ensure it is registered
+  tds->registerSygusType(tn);
+  const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
+  TypeNode btn = TypeNode::fromType(dt.getSygusType());
+  // for constant reconstruction
+  Kind ck = tds->getComparisonKind(btn);
+  Node z = d_qe->getTermUtil()->getTypeValue(btn, 0);
+
+  // iterate over constructors
+  for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
+  {
+    Node n = Node::fromExpr(dt[i].getSygusOp());
+    if (n.getKind() != kind::BUILTIN && n.isConst())
+    {
+      d_const_list[tn].push_back(n);
+      if (ck != UNDEFINED_KIND && doCompare(z, n, ck))
+      {
+        d_const_list_pos[tn]++;
+      }
+    }
+    if (dt[i].isSygusIdFunc())
+    {
+      d_id_funcs[tn].push_back(i);
+    }
+  }
+  // sort the constant list
+  if (!d_const_list[tn].empty())
+  {
+    if (ck != UNDEFINED_KIND)
+    {
+      sortConstants sc;
+      sc.d_comp_kind = ck;
+      std::sort(d_const_list[tn].begin(), d_const_list[tn].end(), sc);
+    }
+    Trace("csi-rcons") << "Type has " << d_const_list[tn].size()
+                       << " constants..." << std::endl
+                       << "  ";
+    for (unsigned i = 0; i < d_const_list[tn].size(); i++)
+    {
+      Trace("csi-rcons") << d_const_list[tn][i] << " ";
+    }
+    Trace("csi-rcons") << std::endl;
+    Trace("csi-rcons") << "Of these, " << d_const_list_pos[tn]
+                       << " are marked as positive." << std::endl;
+  }
+}
+
+bool CegConjectureSingleInvSol::getMatch(Node p,
+                                         Node n,
+                                         std::map<int, Node>& s,
+                                         std::vector<int>& new_s)
+{
+  TermDbSygus* tds = d_qe->getTermDatabaseSygus();
+  if (tds->isFreeVar(p))
+  {
+    unsigned vnum = tds->getVarNum(p);
+    Node prev = s[vnum];
+    s[vnum] = n;
+    if (prev.isNull())
+    {
+      new_s.push_back(vnum);
+    }
+    return prev.isNull() || prev == n;
+  }
+  if (n.getNumChildren() == 0)
+  {
+    return p == n;
+  }
+  if (n.getKind() == p.getKind() && n.getNumChildren() == p.getNumChildren())
+  {
+    // try both ways?
+    unsigned rmax =
+        TermUtil::isComm(n.getKind()) && n.getNumChildren() == 2 ? 2 : 1;
+    std::vector<int> new_tmp;
+    for (unsigned r = 0; r < rmax; r++)
+    {
+      bool success = true;
+      for (unsigned i = 0, size = n.getNumChildren(); i < size; i++)
+      {
+        int io = r == 0 ? i : (i == 0 ? 1 : 0);
+        if (!getMatch(p[i], n[io], s, new_tmp))
+        {
+          success = false;
+          for (unsigned j = 0; j < new_tmp.size(); j++)
+          {
+            s.erase(new_tmp[j]);
+          }
+          new_tmp.clear();
+          break;
+        }
+      }
+      if (success)
+      {
+        new_s.insert(new_s.end(), new_tmp.begin(), new_tmp.end());
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool CegConjectureSingleInvSol::getMatch(Node t,
+                                         TypeNode st,
+                                         int& index_found,
+                                         std::vector<Node>& args,
+                                         int index_exc,
+                                         int index_start)
+{
+  Assert(st.isDatatype());
+  const Datatype& dt = static_cast<DatatypeType>(st.toType()).getDatatype();
+  Assert(dt.isSygus());
+  std::map<Kind, std::vector<Node> > kgens;
+  std::vector<Node> gens;
+  for (unsigned i = index_start, ncons = dt.getNumConstructors(); i < ncons;
+       i++)
+  {
+    if ((int)i != index_exc)
+    {
+      Node g = getGenericBase(st, dt, i);
+      gens.push_back(g);
+      kgens[g.getKind()].push_back(g);
+      Trace("csi-sol-debug") << "Check generic base : " << g << " from "
+                             << dt[i].getName() << std::endl;
+      if (g.getKind() == t.getKind())
+      {
+        Trace("csi-sol-debug") << "Possible match ? " << g << " " << t
+                               << " for " << dt[i].getName() << std::endl;
+        std::map<int, Node> sigma;
+        std::vector<int> new_s;
+        if (getMatch(g, t, sigma, new_s))
+        {
+          // we found an exact match
+          bool msuccess = true;
+          for (unsigned j = 0, nargs = dt[i].getNumArgs(); j < nargs; j++)
+          {
+            if (sigma[j].isNull())
+            {
+              msuccess = false;
+              break;
+            }
+            else
+            {
+              args.push_back(sigma[j]);
+            }
+          }
+          if (msuccess)
+          {
+            index_found = i;
+            return true;
+          }
+        }
+      }
+    }
+  }
+  return false;
+}
+
+Node CegConjectureSingleInvSol::getGenericBase(TypeNode tn,
+                                               const Datatype& dt,
+                                               int c)
+{
+  std::map<int, Node>::iterator it = d_generic_base[tn].find(c);
+  if (it != d_generic_base[tn].end())
+  {
+    return it->second;
+  }
+  TermDbSygus* tds = d_qe->getTermDatabaseSygus();
+  Assert(tds->isRegistered(tn));
+  std::map<TypeNode, int> var_count;
+  std::map<int, Node> pre;
+  Node g = tds->mkGeneric(dt, c, var_count, pre);
+  Trace("csi-sol-debug") << "Generic is " << g << std::endl;
+  Node gr = Rewriter::rewrite(g);
+  Trace("csi-sol-debug") << "Generic rewritten is " << gr << std::endl;
+  d_generic_base[tn][c] = gr;
+  return gr;
+}
+}
+}
+}
diff --git a/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.h b/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.h
new file mode 100644 (file)
index 0000000..7043e1e
--- /dev/null
@@ -0,0 +1,191 @@
+/*********************                                                        */
+/*! \file ce_guided_single_inv_sol.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Paul Meng
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief utility for reconstructing solutions for single invocation synthesis conjectures
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_SINGLE_INV_SOL_H
+#define __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_SINGLE_INV_SOL_H
+
+#include "context/cdhashmap.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+
+class CegConjectureSingleInv;
+
+/** CegConjectureSingleInvSol
+ *
+ * This function implements Figure 5 of "Counterexample-Guided Quantifier
+ * Instantiation for Synthesis in SMT", Reynolds et al CAV 2015.
+ *
+ */
+class CegConjectureSingleInvSol
+{
+  friend class CegConjectureSingleInv;
+private:
+  QuantifiersEngine * d_qe;
+  std::vector< Node > d_varList;
+  std::map< Node, int > d_dterm_size;
+  std::map< Node, int > d_dterm_ite_size;
+//solution simplification
+private:
+  bool debugSolution( Node sol );
+  void debugTermSize( Node sol, int& t_size, int& num_ite );
+  Node pullITEs( Node n );
+  bool pullITECondition( Node root, Node n, std::vector< Node >& conj, Node& t, Node& rem, int depth );
+  Node flattenITEs( Node n, bool rec = true );
+  bool getAssign( bool pol, Node n, std::map< Node, bool >& assign, std::vector< Node >& new_assign,
+                  std::vector< Node >& vars, std::vector< Node >& new_vars, std::vector< Node >& new_subs );
+  bool getAssignEquality( Node eq, std::vector< Node >& vars, std::vector< Node >& new_vars, std::vector< Node >& new_subs );
+  Node simplifySolutionNode( Node sol, TypeNode stn, std::map< Node, bool >& assign,
+                             std::vector< Node >& vars, std::vector< Node >& subs, int status );
+
+ public:
+  CegConjectureSingleInvSol(QuantifiersEngine* qe);
+  /** simplify solution
+   *
+   * Returns the simplified version of node sol whose syntax is restricted by
+   * the grammar corresponding to sygus datatype stn.
+   */
+  Node simplifySolution( Node sol, TypeNode stn );
+  /** reconstruct solution
+   *
+   * Returns (if possible) a node that is equivalent to sol those syntax
+   * matches the grammar corresponding to sygus datatype stn.
+   * The value reconstructed is set to 1 if we successfully return a node,
+   * otherwise it is set to -1.
+   */
+  Node reconstructSolution(Node sol, TypeNode stn, int& reconstructed);
+  /** preregister conjecture
+   *
+   * q : the synthesis conjecture this class is for.
+   * This is used as a heuristic to find terms in the original conjecture which
+   * may be helpful for using during reconstruction.
+   */
+  void preregisterConjecture(Node q);
+
+ private:
+  int d_id_count;
+  int d_root_id;
+  std::map< int, Node > d_id_node;
+  std::map< int, TypeNode > d_id_type;
+  std::map< TypeNode, std::map< Node, int > > d_rcons_to_id;
+  std::map< TypeNode, std::map< Node, int > > d_rcons_to_status;
+
+  std::map< int, std::map< Node, std::vector< int > > > d_reconstruct_op;
+  std::map< int, Node > d_reconstruct;
+  std::map< int, std::vector< int > > d_parents;
+
+  std::map< int, std::vector< int > > d_eqc;
+  std::map< int, int > d_rep;
+  
+  //equivalent terms
+  std::map< Node, Node > d_eqt_rep;
+  std::map< Node, std::vector< Node > > d_eqt_eqc;
+
+  //cache when reconstructing solutions
+  std::vector< int > d_tmp_fail;
+  // get reconstructed solution
+  Node getReconstructedSolution( int id, bool mod_eq = true );
+
+  // allocate node with type
+  int allocate( Node n, TypeNode stn );
+  // term t with sygus type st, returns inducted templated form of t
+  int collectReconstructNodes( Node t, TypeNode stn, int& status );
+  bool collectReconstructNodes( int pid, std::vector< Node >& ts, const DatatypeConstructor& dtc, std::vector< int >& ids, int& status );
+  bool getPathToRoot( int id );
+  void setReconstructed( int id, Node n );
+  //get equivalent terms to n with top symbol k
+  void getEquivalentTerms( Kind k, Node n, std::vector< Node >& equiv );
+  //register equivalent terms
+  void registerEquivalentTerms( Node n );
+  /** builtin to sygus const
+   *
+   * Returns a sygus term of type tn that encodes the builtin constant c.
+   * If the sygus datatype tn allows any constant, this may return a variable
+   * with the attribute SygusPrintProxyAttribute that associates it with c.
+   *
+   * rcons_depth limits the number of recursive calls when doing accelerated
+   * constant reconstruction (currently limited to 1000). Notice this is hacky:
+   * depending upon order of calls, constant rcons may succeed, e.g. 1001, 999
+   * vs. 999, 1001.
+   */
+  Node builtinToSygusConst(Node c, TypeNode tn, int rcons_depth = 0);
+  /** cache for the above function */
+  std::map<TypeNode, std::map<Node, Node> > d_builtin_const_to_sygus;
+  /** sorted list of constants, per type */
+  std::map<TypeNode, std::vector<Node> > d_const_list;
+  /** number of positive constants, per type */
+  std::map<TypeNode, unsigned> d_const_list_pos;
+  /** list of constructor indices whose operators are identity functions */
+  std::map<TypeNode, std::vector<int> > d_id_funcs;
+  /** initialize the above information for sygus type tn */
+  void registerType(TypeNode tn);
+  /** get generic base
+   *
+   * This returns the builtin term that is the analog of an application of the
+   * c^th constructor of dt to fresh variables.
+   */
+  Node getGenericBase(TypeNode tn, const Datatype& dt, int c);
+  /** cache for the above function */
+  std::map<TypeNode, std::map<int, Node> > d_generic_base;
+  /** get match
+   *
+   * This function attempts to find a substitution for which p = n. If
+   * successful, this function returns a substitution in the form of s/new_s,
+   * where:
+   * s : substitution, where the domain are indices of terms in the sygus
+   * term database, and
+   * new_s : the members that were added to s on this call.
+   * Otherwise, this function returns false and s and new_s are unmodified.
+   */
+  bool getMatch(Node p,
+                Node n,
+                std::map<int, Node>& s,
+                std::vector<int>& new_s);
+  /** get match
+   *
+   * This function attempts to find a builtin term that is analog to a value
+   * of the sygus datatype st that is equivalent to n. If this function returns
+   * true, then it has found such a term. Then we set:
+   *   index_found : updated to the constructor index of the sygus term whose
+   *   analog to equivalent to n.
+   *   args : builtin terms corresponding to the match, in order.
+   * Otherwise, this function returns false and index_found and args are
+   * unmodified.
+   * For example, for grammar:
+   *   A -> 0 | 1 | x | +( A, A )
+   * Given input ( 5 + (x+1) ) and A we would return true, where:
+   *   index_found is set to 3 and args is set to { 5, x+1 }.
+   *
+   * index_exc : (if applicable) exclude a constructor index of st
+   * index_start : start index of constructors of st to try
+   */
+  bool getMatch(Node n,
+                TypeNode st,
+                int& index_found,
+                std::vector<Node>& args,
+                int index_exc = -1,
+                int index_start = 0);
+};
+
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/sygus/sygus_explain.cpp b/src/theory/quantifiers/sygus/sygus_explain.cpp
new file mode 100644 (file)
index 0000000..aafaa07
--- /dev/null
@@ -0,0 +1,301 @@
+/*********************                                                        */
+/*! \file sygus_explain.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of techniques for sygus explanations
+ **/
+
+#include "theory/quantifiers/sygus/sygus_explain.h"
+
+#include "theory/datatypes/datatypes_rewriter.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
+
+using namespace CVC4::kind;
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+void TermRecBuild::addTerm(Node n)
+{
+  d_term.push_back(n);
+  std::vector<Node> currc;
+  d_kind.push_back(n.getKind());
+  if (n.getMetaKind() == kind::metakind::PARAMETERIZED)
+  {
+    currc.push_back(n.getOperator());
+    d_has_op.push_back(true);
+  }
+  else
+  {
+    d_has_op.push_back(false);
+  }
+  for (unsigned i = 0; i < n.getNumChildren(); i++)
+  {
+    currc.push_back(n[i]);
+  }
+  d_children.push_back(currc);
+}
+
+void TermRecBuild::init(Node n)
+{
+  Assert(d_term.empty());
+  addTerm(n);
+}
+
+void TermRecBuild::push(unsigned p)
+{
+  Assert(!d_term.empty());
+  unsigned curr = d_term.size() - 1;
+  Assert(d_pos.size() == curr);
+  Assert(d_pos.size() + 1 == d_children.size());
+  Assert(p < d_term[curr].getNumChildren());
+  addTerm(d_term[curr][p]);
+  d_pos.push_back(p);
+}
+
+void TermRecBuild::pop()
+{
+  Assert(!d_pos.empty());
+  d_pos.pop_back();
+  d_kind.pop_back();
+  d_has_op.pop_back();
+  d_children.pop_back();
+  d_term.pop_back();
+}
+
+void TermRecBuild::replaceChild(unsigned i, Node r)
+{
+  Assert(!d_term.empty());
+  unsigned curr = d_term.size() - 1;
+  unsigned o = d_has_op[curr] ? 1 : 0;
+  d_children[curr][i + o] = r;
+}
+
+Node TermRecBuild::getChild(unsigned i)
+{
+  unsigned curr = d_term.size() - 1;
+  unsigned o = d_has_op[curr] ? 1 : 0;
+  return d_children[curr][i + o];
+}
+
+Node TermRecBuild::build(unsigned d)
+{
+  Assert(d_pos.size() + 1 == d_term.size());
+  Assert(d < d_term.size());
+  int p = d < d_pos.size() ? d_pos[d] : -2;
+  std::vector<Node> children;
+  unsigned o = d_has_op[d] ? 1 : 0;
+  for (unsigned i = 0; i < d_children[d].size(); i++)
+  {
+    Node nc;
+    if (p + o == i)
+    {
+      nc = build(d + 1);
+    }
+    else
+    {
+      nc = d_children[d][i];
+    }
+    children.push_back(nc);
+  }
+  return NodeManager::currentNM()->mkNode(d_kind[d], children);
+}
+
+void SygusExplain::getExplanationForConstantEquality(Node n,
+                                                     Node vn,
+                                                     std::vector<Node>& exp)
+{
+  std::map<unsigned, bool> cexc;
+  getExplanationForConstantEquality(n, vn, exp, cexc);
+}
+
+void SygusExplain::getExplanationForConstantEquality(
+    Node n, Node vn, std::vector<Node>& exp, std::map<unsigned, bool>& cexc)
+{
+  Assert(vn.getKind() == kind::APPLY_CONSTRUCTOR);
+  Assert(n.getType() == vn.getType());
+  TypeNode tn = n.getType();
+  Assert(tn.isDatatype());
+  const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
+  int i = Datatype::indexOf(vn.getOperator().toExpr());
+  Node tst = datatypes::DatatypesRewriter::mkTester(n, i, dt);
+  exp.push_back(tst);
+  for (unsigned j = 0; j < vn.getNumChildren(); j++)
+  {
+    if (cexc.find(j) == cexc.end())
+    {
+      Node sel = NodeManager::currentNM()->mkNode(
+          kind::APPLY_SELECTOR_TOTAL,
+          Node::fromExpr(dt[i].getSelectorInternal(tn.toType(), j)),
+          n);
+      getExplanationForConstantEquality(sel, vn[j], exp);
+    }
+  }
+}
+
+Node SygusExplain::getExplanationForConstantEquality(Node n, Node vn)
+{
+  std::map<unsigned, bool> cexc;
+  return getExplanationForConstantEquality(n, vn, cexc);
+}
+
+Node SygusExplain::getExplanationForConstantEquality(
+    Node n, Node vn, std::map<unsigned, bool>& cexc)
+{
+  std::vector<Node> exp;
+  getExplanationForConstantEquality(n, vn, exp, cexc);
+  Assert(!exp.empty());
+  return exp.size() == 1 ? exp[0]
+                         : NodeManager::currentNM()->mkNode(kind::AND, exp);
+}
+
+// we have ( n = vn => eval( n ) = bvr ) ^ vn != vnr , returns exp such that exp
+// => ( eval( n ) = bvr ^ vn != vnr )
+void SygusExplain::getExplanationFor(TermRecBuild& trb,
+                                     Node n,
+                                     Node vn,
+                                     std::vector<Node>& exp,
+                                     std::map<TypeNode, int>& var_count,
+                                     SygusInvarianceTest& et,
+                                     Node vnr,
+                                     Node& vnr_exp,
+                                     int& sz)
+{
+  Assert(vnr.isNull() || vn != vnr);
+  Assert(vn.getKind() == APPLY_CONSTRUCTOR);
+  Assert(vnr.isNull() || vnr.getKind() == APPLY_CONSTRUCTOR);
+  Assert(n.getType() == vn.getType());
+  TypeNode ntn = n.getType();
+  std::map<unsigned, bool> cexc;
+  // for each child, 
+  // check whether replacing that child by a fresh variable
+  // also satisfies the invariance test.
+  for (unsigned i = 0; i < vn.getNumChildren(); i++)
+  {
+    TypeNode xtn = vn[i].getType();
+    Node x = d_tdb->getFreeVarInc(xtn, var_count);
+    trb.replaceChild(i, x);
+    Node nvn = trb.build();
+    Assert(nvn.getKind() == kind::APPLY_CONSTRUCTOR);
+    if (et.is_invariant(d_tdb, nvn, x))
+    {
+      cexc[i] = true;
+      // we are tracking term size if positive
+      if (sz >= 0)
+      {
+        int s = d_tdb->getSygusTermSize(vn[i]);
+        sz = sz - s;
+      }
+    }
+    else
+    {
+      trb.replaceChild(i, vn[i]);
+    }
+  }
+  const Datatype& dt = ((DatatypeType)ntn.toType()).getDatatype();
+  int cindex = Datatype::indexOf(vn.getOperator().toExpr());
+  Assert(cindex >= 0 && cindex < (int)dt.getNumConstructors());
+  Node tst = datatypes::DatatypesRewriter::mkTester(n, cindex, dt);
+  exp.push_back(tst);
+  // if the operator of vn is different than vnr, then disunification obligation
+  // is met
+  if (!vnr.isNull())
+  {
+    if (vnr.getOperator() != vn.getOperator())
+    {
+      vnr = Node::null();
+      vnr_exp = NodeManager::currentNM()->mkConst(true);
+    }
+  }
+  for (unsigned i = 0; i < vn.getNumChildren(); i++)
+  {
+    Node sel = NodeManager::currentNM()->mkNode(
+        kind::APPLY_SELECTOR_TOTAL,
+        Node::fromExpr(dt[cindex].getSelectorInternal(ntn.toType(), i)),
+        n);
+    Node vnr_c = vnr.isNull() ? vnr : (vn[i] == vnr[i] ? Node::null() : vnr[i]);
+    if (cexc.find(i) == cexc.end())
+    {
+      trb.push(i);
+      Node vnr_exp_c;
+      getExplanationFor(
+          trb, sel, vn[i], exp, var_count, et, vnr_c, vnr_exp_c, sz);
+      trb.pop();
+      if (!vnr_c.isNull())
+      {
+        Assert(!vnr_exp_c.isNull());
+        if (vnr_exp_c.isConst() || vnr_exp.isNull())
+        {
+          // recursively satisfied the disunification obligation
+          if (vnr_exp_c.isConst())
+          {
+            // was successful, don't consider further
+            vnr = Node::null();
+          }
+          vnr_exp = vnr_exp_c;
+        }
+      }
+    }
+    else
+    {
+      // if excluded, we may need to add the explanation for this
+      if (vnr_exp.isNull() && !vnr_c.isNull())
+      {
+        vnr_exp = getExplanationForConstantEquality(sel, vnr[i]);
+      }
+    }
+  }
+}
+
+void SygusExplain::getExplanationFor(Node n,
+                                     Node vn,
+                                     std::vector<Node>& exp,
+                                     SygusInvarianceTest& et,
+                                     Node vnr,
+                                     unsigned& sz)
+{
+  // naive :
+  // return getExplanationForConstantEquality( n, vn, exp );
+
+  // set up the recursion object
+  std::map<TypeNode, int> var_count;
+  TermRecBuild trb;
+  trb.init(vn);
+  Node vnr_exp;
+  int sz_use = sz;
+  getExplanationFor(trb, n, vn, exp, var_count, et, vnr, vnr_exp, sz_use);
+  Assert(sz_use >= 0);
+  sz = sz_use;
+  Assert(vnr.isNull() || !vnr_exp.isNull());
+  if (!vnr_exp.isNull() && !vnr_exp.isConst())
+  {
+    exp.push_back(vnr_exp.negate());
+  }
+}
+
+void SygusExplain::getExplanationFor(Node n,
+                                     Node vn,
+                                     std::vector<Node>& exp,
+                                     SygusInvarianceTest& et)
+{
+  int sz = -1;
+  std::map<TypeNode, int> var_count;
+  TermRecBuild trb;
+  trb.init(vn);
+  Node vnr;
+  Node vnr_exp;
+  getExplanationFor(trb, n, vn, exp, var_count, et, vnr, vnr_exp, sz);
+}
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/sygus/sygus_explain.h b/src/theory/quantifiers/sygus/sygus_explain.h
new file mode 100644 (file)
index 0000000..ad26f29
--- /dev/null
@@ -0,0 +1,222 @@
+/*********************                                                        */
+/*! \file sygus_explain.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief sygus explanations
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_EXPLAIN_H
+#define __CVC4__THEORY__QUANTIFIERS__SYGUS_EXPLAIN_H
+
+#include <vector>
+
+#include "expr/node.h"
+#include "theory/quantifiers/sygus/sygus_invariance.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+/** Recursive term builder
+ *
+ * This is a utility used to generate variants
+ * of a term n, where subterms of n can be replaced
+ * by others via calls to replaceChild(...).
+ *
+ * This class maintains a "context", which indicates
+ * a position in term n. Below, we call the subterm of
+ * the initial term n at this position the "active term".
+ *
+ */
+class TermRecBuild
+{
+ public:
+  TermRecBuild() {}
+  /** set the initial term to n
+   *
+   * The context initially empty, that is,
+   * the active term is initially n.
+   */
+  void init(Node n);
+
+  /** push the context
+   *
+   * This updates the context so that the
+   * active term is updated to curr[p], where
+   * curr is the previously active term.
+   */
+  void push(unsigned p);
+
+  /** pop the context */
+  void pop();
+  /** indicates that the i^th child of the active
+   * term should be replaced by r in calls to build().
+   */
+  void replaceChild(unsigned i, Node r);
+  /** get the i^th child of the active term */
+  Node getChild(unsigned i);
+  /** build the (modified) version of the term
+   * we intialized via the call to init().
+   */
+  Node build(unsigned p = 0);
+
+ private:
+  /** stack of active terms */
+  std::vector<Node> d_term;
+  /** stack of children of active terms
+   * Notice that these may be modified with calls to replaceChild(...).
+   */
+  std::vector<std::vector<Node> > d_children;
+  /** stack the kind of active terms */
+  std::vector<Kind> d_kind;
+  /** stack of whether the active terms had an operator */
+  std::vector<bool> d_has_op;
+  /** stack of positions that were pushed via calls to push(...) */
+  std::vector<unsigned> d_pos;
+  /** add term to the context stack */
+  void addTerm(Node n);
+};
+
+/*The SygusExplain utility
+ *
+ * This class is used to produce explanations for refinement lemmas
+ * in the counterexample-guided inductive synthesis (CEGIS) loop.
+ *
+ * When given an invariance test T traverses the AST of a given term,
+ * uses TermRecBuild to replace various subterms by fresh variables and
+ * recheck whether the invariant, as specified by T still holds.
+ * If it does, then we may exclude the explanation for that subterm.
+ *
+ * For example, say we have that the current value of
+ * (datatype) sygus term n is:
+ *  (if (gt x 0) 0 0)
+ * where if, gt, x, 0 are datatype constructors.
+ * The explanation returned by getExplanationForConstantEquality
+ * below for n and the above term is:
+ *   { ((_ is if) n), ((_ is geq) n.0),
+ *     ((_ is x) n.0.0), ((_ is 0) n.0.1),
+ *     ((_ is 0) n.1), ((_ is 0) n.2) }
+ *
+ * This class can also return more precise
+ * explanations based on a property that holds for
+ * variants of n. For instance,
+ * say we find that n's builtin analog rewrites to 0:
+ *  ite( x>0, 0, 0 ) ----> 0
+ * and we would like to find the minimal explanation for
+ * why the builtin analog of n rewrites to 0.
+ * We use the invariance test EquivSygusInvarianceTest
+ * (see sygus_invariance.h) for doing this.
+ * Using the SygusExplain::getExplanationFor method below,
+ * this will invoke the invariant test to check, e.g.
+ *   ite( x>0, 0, y1 ) ----> 0 ? fail
+ *   ite( x>0, y2, 0 ) ----> 0 ? fail
+ *   ite( y3, 0, 0 ) ----> 0 ? success
+ * where y1, y2, y3 are fresh variables.
+ * Hence the explanation for the condition x>0 is irrelevant.
+ * This gives us the explanation:
+ *   { ((_ is if) n), ((_ is 0) n.1), ((_ is 0) n.2) }
+ * indicating that all terms of the form:
+ *   (if _ 0 0) have a builtin equivalent that rewrites to 0.
+ *
+ * For details, see Reynolds et al SYNT 2017.
+ *
+ * Below, we let [[exp]]_n denote the term induced by
+ * the explanation exp for n.
+ * For example:
+ *   exp = { ((_ is plus) n), ((_ is y) n.1) }
+ * is such that:
+ *   [[exp]]_n = (plus w y)
+ * where w is a fresh variable.
+ */
+class SygusExplain
+{
+ public:
+  SygusExplain(TermDbSygus* tdb) : d_tdb(tdb) {}
+  ~SygusExplain() {}
+  /** get explanation for constant equality
+   *
+   * This function constructs an explanation, stored in exp, such that:
+   * - All formulas in exp are of the form ((_ is C) ns), where ns
+   *   is a chain of selectors applied to n, and
+   * - exp => ( n = vn )
+   */
+  void getExplanationForConstantEquality(Node n,
+                                         Node vn,
+                                         std::vector<Node>& exp);
+  /** returns the conjunction of exp computed in the above function */
+  Node getExplanationForConstantEquality(Node n, Node vn);
+
+  /** get explanation for constant equality
+   * This is identical to the above function except that we
+   * take an additional argument cexc, which says which
+   * children of vn should be excluded from the explanation.
+   *
+   * For example, if vn = plus( plus( x, x ), y ) and cexc is { 0 -> true },
+   * then the following is appended to exp :
+   *   { ((_ is plus) n), ((_ is y) n.1) }
+   * where notice that the 0^th argument of vn is excluded.
+   */
+  void getExplanationForConstantEquality(Node n,
+                                         Node vn,
+                                         std::vector<Node>& exp,
+                                         std::map<unsigned, bool>& cexc);
+  /** returns the conjunction of exp computed in the above function */
+  Node getExplanationForConstantEquality(Node n,
+                                         Node vn,
+                                         std::map<unsigned, bool>& cexc);
+
+  /** get explanation for
+   *
+   * This function constructs an explanation, stored in exp, such that:
+   * - All formulas in exp are of the form ((_ is C) ns), where ns
+   *   is a chain of selectors applied to n, and
+   * - The test et holds for [[exp]]_n, and
+   * - (if applicable) exp => ( n != vnr ).
+   *
+   * This function updates sz to be the term size of [[exp]]_n.
+   */
+  void getExplanationFor(Node n,
+                         Node vn,
+                         std::vector<Node>& exp,
+                         SygusInvarianceTest& et,
+                         Node vnr,
+                         unsigned& sz);
+  void getExplanationFor(Node n,
+                         Node vn,
+                         std::vector<Node>& exp,
+                         SygusInvarianceTest& et);
+
+ private:
+  /** sygus term database associated with this utility */
+  TermDbSygus* d_tdb;
+  /** Helper function for getExplanationFor
+   * var_count is the number of free variables we have introduced,
+   *   per type, for the purposes of generalizing subterms of n.
+   * vnr_exp stores the explanation, if one exists, for
+   *   n != vnr.  It is only non-null if vnr is non-null.
+   */
+  void getExplanationFor(TermRecBuild& trb,
+                         Node n,
+                         Node vn,
+                         std::vector<Node>& exp,
+                         std::map<TypeNode, int>& var_count,
+                         SygusInvarianceTest& et,
+                         Node vnr,
+                         Node& vnr_exp,
+                         int& sz);
+};
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__SYGUS_EXPLAIN_H */
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp b/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp
new file mode 100644 (file)
index 0000000..1ca774c
--- /dev/null
@@ -0,0 +1,693 @@
+/*********************                                                        */
+/*! \file sygus_grammar_cons.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief implementation of class for constructing inductive datatypes that correspond to
+ ** grammars that encode syntactic restrictions for SyGuS.
+ **/
+#include "theory/quantifiers/sygus/sygus_grammar_cons.h"
+
+#include <stack>
+
+#include "expr/datatype.h"
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/sygus/ce_guided_conjecture.h"
+#include "theory/quantifiers/sygus/sygus_process_conj.h"
+#include "theory/quantifiers/sygus/sygus_grammar_norm.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
+#include "theory/quantifiers/term_util.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+CegGrammarConstructor::CegGrammarConstructor(QuantifiersEngine* qe,
+                                             CegConjecture* p)
+    : d_qe(qe), d_parent(p), d_is_syntax_restricted(false), d_has_ite(true)
+{
+}
+
+void CegGrammarConstructor::collectTerms( Node n, std::map< TypeNode, std::vector< Node > >& consts ){
+  std::unordered_map<TNode, bool, TNodeHashFunction> visited;
+  std::unordered_map<TNode, bool, TNodeHashFunction>::iterator it;
+  std::stack<TNode> visit;
+  TNode cur;
+  visit.push(n);
+  do {
+    cur = visit.top();
+    visit.pop();
+    it = visited.find(cur);
+    if (it == visited.end()) {
+      visited[cur] = true;
+      // is this a constant?
+      if( cur.isConst() ){
+        TypeNode tn = cur.getType();
+        Node c = cur;
+        if( tn.isReal() ){
+          c = NodeManager::currentNM()->mkConst( c.getConst<Rational>().abs() );
+        }
+        if( std::find( consts[tn].begin(), consts[tn].end(), c )==consts[tn].end() ){
+          Trace("cegqi-debug") << "...consider const : " << c << std::endl;
+          consts[tn].push_back( c );
+        }
+      }
+      // recurse
+      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
+        visit.push(cur[i]);
+      }
+    }
+  } while (!visit.empty());
+}
+
+
+
+Node CegGrammarConstructor::process( Node q, std::map< Node, Node >& templates, std::map< Node, Node >& templates_arg ) {
+  // convert to deep embedding and finalize single invocation here
+  // now, construct the grammar
+  Trace("cegqi") << "CegConjecture : convert to deep embedding..." << std::endl;
+  std::map< TypeNode, std::vector< Node > > extra_cons;
+  if( options::sygusAddConstGrammar() ){
+    Trace("cegqi") << "CegConjecture : collect constants..." << std::endl;
+    collectTerms( q[1], extra_cons );
+  }
+
+  std::vector< Node > qchildren;
+  std::map< Node, Node > synth_fun_vars;
+  std::vector< Node > ebvl;
+  Node qbody_subs = q[1];
+  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+    Node sf = q[0][i];
+    // v encodes the syntactic restrictions (via an inductive datatype) on sf
+    // from the input
+    Node v = sf.getAttribute(SygusSynthGrammarAttribute());
+    Assert(!v.isNull());
+    Node sfvl = sf.getAttribute(SygusSynthFunVarListAttribute());
+    // sfvl may be null for constant synthesis functions
+    Trace("cegqi-debug") << "...sygus var list associated with " << sf << " is " << sfvl << std::endl;
+
+    TypeNode tn;
+    std::stringstream ss;
+    ss << sf;
+    if( v.getType().isDatatype() && ((DatatypeType)v.getType().toType()).getDatatype().isSygus() ){
+      tn = v.getType();
+    }else{
+      // check which arguments are irrelevant
+      std::unordered_set<unsigned> arg_irrelevant;
+      d_parent->getProcess()->getIrrelevantArgs(sf, arg_irrelevant);
+      std::unordered_set<Node, NodeHashFunction> term_irrelevant;
+      // convert to term
+      for (std::unordered_set<unsigned>::iterator ita = arg_irrelevant.begin();
+           ita != arg_irrelevant.end();
+           ++ita)
+      {
+        unsigned arg = *ita;
+        Assert(arg < sfvl.getNumChildren());
+        term_irrelevant.insert(sfvl[arg]);
+      }
+
+      // make the default grammar
+      tn = mkSygusDefaultType(
+          v.getType(), sfvl, ss.str(), extra_cons, term_irrelevant);
+    }
+    // normalize type
+    SygusGrammarNorm sygus_norm(d_qe);
+    tn = sygus_norm.normalizeSygusType(tn, sfvl);
+    // check if there is a template
+    std::map< Node, Node >::iterator itt = templates.find( sf );
+    if( itt!=templates.end() ){
+      Node templ = itt->second;
+      TNode templ_arg = templates_arg[sf];
+      Assert( !templ_arg.isNull() );
+      Trace("cegqi-debug") << "Template for " << sf << " is : " << templ << " with arg " << templ_arg << std::endl;
+      // if there is a template for this argument, make a sygus type on top of it
+      if( options::sygusTemplEmbedGrammar() ){
+        Trace("cegqi-debug") << "  embed this template as a grammar..." << std::endl;
+        tn = mkSygusTemplateType( templ, templ_arg, tn, sfvl, ss.str() );
+      }else{
+        // otherwise, apply it as a preprocessing pass 
+        Trace("cegqi-debug") << "  apply this template as a substituion during preprocess..." << std::endl;
+        std::vector< Node > schildren;
+        std::vector< Node > largs;
+        for( unsigned j=0; j<sfvl.getNumChildren(); j++ ){
+          schildren.push_back( sfvl[j] );
+          largs.push_back( NodeManager::currentNM()->mkBoundVar( sfvl[j].getType() ) );
+        }
+        std::vector< Node > subsfn_children;
+        subsfn_children.push_back( sf );
+        subsfn_children.insert( subsfn_children.end(), schildren.begin(), schildren.end() );
+        Node subsfn = NodeManager::currentNM()->mkNode( kind::APPLY_UF, subsfn_children );
+        TNode subsf = subsfn;
+        Trace("cegqi-debug") << "  substitute arg : " << templ_arg << " -> " << subsf << std::endl;
+        templ = templ.substitute( templ_arg, subsf );
+        // substitute lambda arguments
+        templ = templ.substitute( schildren.begin(), schildren.end(), largs.begin(), largs.end() );
+        Node subsn = NodeManager::currentNM()->mkNode( kind::LAMBDA, NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, largs ), templ );
+        TNode var = sf;
+        TNode subs = subsn;
+        Trace("cegqi-debug") << "  substitute : " << var << " -> " << subs << std::endl;
+        qbody_subs = qbody_subs.substitute( var, subs );
+        Trace("cegqi-debug") << "  body is now : " << qbody_subs << std::endl;
+      }
+    }
+    d_qe->getTermDatabaseSygus()->registerSygusType( tn );
+    // check grammar restrictions
+    if( !d_qe->getTermDatabaseSygus()->sygusToBuiltinType( tn ).isBoolean() ){
+      if( !d_qe->getTermDatabaseSygus()->hasKind( tn, ITE ) ){
+        d_has_ite = false;
+      }
+    }
+    Assert( tn.isDatatype() );
+    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+    Assert( dt.isSygus() );
+    if( !dt.getSygusAllowAll() ){
+      d_is_syntax_restricted = true;
+    }
+
+    // ev is the first-order variable corresponding to this synth fun
+    std::stringstream ssf;
+    ssf << "f" << sf;
+    Node ev = NodeManager::currentNM()->mkBoundVar( ssf.str(), tn );
+    ebvl.push_back( ev );
+    synth_fun_vars[sf] = ev;
+    Trace("cegqi") << "...embedding synth fun : " << sf << " -> " << ev << std::endl;
+  }
+  qchildren.push_back( NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, ebvl ) );
+  if( qbody_subs!=q[1] ){
+    Trace("cegqi") << "...rewriting : " << qbody_subs << std::endl;
+    qbody_subs = Rewriter::rewrite( qbody_subs );
+    Trace("cegqi") << "...got : " << qbody_subs << std::endl;
+  }
+  qchildren.push_back( convertToEmbedding( qbody_subs, synth_fun_vars ) );
+  if( q.getNumChildren()==3 ){
+    qchildren.push_back( q[2] );
+  }
+  return NodeManager::currentNM()->mkNode( kind::FORALL, qchildren );
+}
+  
+Node CegGrammarConstructor::convertToEmbedding( Node n, std::map< Node, Node >& synth_fun_vars ){
+  std::unordered_map<TNode, Node, TNodeHashFunction> visited;
+  std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
+  std::stack<TNode> visit;
+  TNode cur;
+  visit.push(n);
+  do {
+    cur = visit.top();
+    visit.pop();
+    it = visited.find(cur);
+    if (it == visited.end()) {
+      visited[cur] = Node::null();
+      visit.push(cur);
+      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
+        visit.push(cur[i]);
+      }
+    } else if (it->second.isNull()) {
+      Node ret = cur;
+      Kind ret_k = cur.getKind();
+      Node op;
+      bool childChanged = false;
+      std::vector<Node> children;
+      // get the potential operator
+      if( cur.getNumChildren()>0 ){
+        if( cur.getKind()==kind::APPLY_UF ){
+          op = cur.getOperator();
+        }
+      }else{
+        op = cur;
+      }
+      // is the operator a synth function?
+      if( !op.isNull() ){
+        std::map< Node, Node >::iterator its = synth_fun_vars.find( op );
+        if( its!=synth_fun_vars.end() ){
+          Assert( its->second.getType().isDatatype() );
+          // will make into an application of an evaluation function
+          const Datatype& dt = ((DatatypeType)its->second.getType().toType()).getDatatype();
+          Assert( dt.isSygus() );
+          children.push_back( Node::fromExpr( dt.getSygusEvaluationFunc() ) );
+          children.push_back( its->second );
+          childChanged = true;
+          ret_k = kind::APPLY_UF;
+        }
+      }
+      if( !childChanged ){
+        // otherwise, we apply the previous operator
+        if( cur.getMetaKind() == kind::metakind::PARAMETERIZED ){
+          children.push_back( cur.getOperator() );
+        }
+      }
+      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
+        it = visited.find(cur[i]);
+        Assert(it != visited.end());
+        Assert(!it->second.isNull());
+        childChanged = childChanged || cur[i] != it->second;
+        children.push_back(it->second);
+      }
+      if (childChanged) {
+        ret = NodeManager::currentNM()->mkNode(ret_k, children);
+      }
+      visited[cur] = ret;
+    }
+  } while (!visit.empty());
+  Assert(visited.find(n) != visited.end());
+  Assert(!visited.find(n)->second.isNull());
+  return visited[n];
+}
+
+
+TypeNode CegGrammarConstructor::mkUnresolvedType(const std::string& name, std::set<Type>& unres) {
+  TypeNode unresolved = NodeManager::currentNM()->mkSort(name, ExprManager::SORT_FLAG_PLACEHOLDER);
+  unres.insert( unresolved.toType() );
+  return unresolved;
+}
+
+void CegGrammarConstructor::mkSygusConstantsForType( TypeNode type, std::vector<CVC4::Node>& ops ) {
+  if (type.isReal())
+  {
+    ops.push_back(NodeManager::currentNM()->mkConst(Rational(0)));
+    ops.push_back(NodeManager::currentNM()->mkConst(Rational(1)));
+  }else if( type.isBitVector() ){
+    unsigned sz = ((BitVectorType)type.toType()).getSize();
+    BitVector bval0(sz, (unsigned int)0);
+    ops.push_back( NodeManager::currentNM()->mkConst(bval0) );
+    BitVector bval1(sz, (unsigned int)1);
+    ops.push_back( NodeManager::currentNM()->mkConst(bval1) );
+  }else if( type.isBoolean() ){
+    ops.push_back(NodeManager::currentNM()->mkConst(true));
+    ops.push_back(NodeManager::currentNM()->mkConst(false));
+  }
+  //TODO : others?
+}
+
+void CegGrammarConstructor::collectSygusGrammarTypesFor( TypeNode range, std::vector< TypeNode >& types, std::map< TypeNode, std::vector< DatatypeConstructorArg > >& sels ){
+  if( !range.isBoolean() ){
+    if( std::find( types.begin(), types.end(), range )==types.end() ){
+      Trace("sygus-grammar-def") << "...will make grammar for " << range << std::endl;
+      types.push_back( range );
+      if( range.isDatatype() ){
+        const Datatype& dt = ((DatatypeType)range.toType()).getDatatype();
+        for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+          for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
+            TypeNode crange = TypeNode::fromType( ((SelectorType)dt[i][j].getType()).getRangeType() );
+            sels[crange].push_back( dt[i][j] );
+            collectSygusGrammarTypesFor( crange, types, sels );
+          }
+        }
+      }
+    }
+  }
+}
+
+void CegGrammarConstructor::mkSygusDefaultGrammar(
+    TypeNode range,
+    Node bvl,
+    const std::string& fun,
+    std::map<TypeNode, std::vector<Node> >& extra_cons,
+    std::unordered_set<Node, NodeHashFunction>& term_irrelevant,
+    std::vector<CVC4::Datatype>& datatypes,
+    std::set<Type>& unres)
+{
+  Trace("sygus-grammar-def") << "Construct default grammar for " << fun << " "
+                             << range << std::endl;
+  // collect the variables
+  std::vector<Node> sygus_vars;
+  if( !bvl.isNull() ){
+    for( unsigned i=0; i<bvl.getNumChildren(); i++ ){
+      if (term_irrelevant.find(bvl[i]) == term_irrelevant.end())
+      {
+        sygus_vars.push_back(bvl[i]);
+      }
+      else
+      {
+        Trace("sygus-grammar-def") << "...synth var " << bvl[i]
+                                   << " has been marked irrelevant."
+                                   << std::endl;
+      }
+    }
+  }
+  //if( !range.isBoolean() && !range.isInteger() && !range.isBitVector() && !range.isDatatype() ){
+  //  parseError("No default grammar for type.");
+  //}
+  std::vector< std::vector< Expr > > ops;
+  int startIndex = -1;
+  std::map< Type, Type > sygus_to_builtin;
+
+  std::vector< TypeNode > types;
+  std::map< TypeNode, std::vector< DatatypeConstructorArg > > sels;
+  //types for each of the variables of parametric sort
+  for( unsigned i=0; i<sygus_vars.size(); i++ ){
+    collectSygusGrammarTypesFor( sygus_vars[i].getType(), types, sels );
+  }
+  //types connected to range
+  collectSygusGrammarTypesFor( range, types, sels );
+
+  //name of boolean sort
+  std::stringstream ssb;
+  ssb << fun << "_Bool";
+  std::string dbname = ssb.str();
+  Type unres_bt = mkUnresolvedType(ssb.str(), unres).toType();
+
+  std::vector< Type > unres_types;
+  std::map< TypeNode, Type > type_to_unres;
+  for( unsigned i=0; i<types.size(); i++ ){
+    std::stringstream ss;
+    ss << fun << "_" << types[i];
+    std::string dname = ss.str();
+    datatypes.push_back(Datatype(dname));
+    ops.push_back(std::vector< Expr >());
+    //make unresolved type
+    Type unres_t = mkUnresolvedType(dname, unres).toType();
+    unres_types.push_back(unres_t);
+    type_to_unres[types[i]] = unres_t;
+    sygus_to_builtin[unres_t] = types[i].toType();
+  }
+  for( unsigned i=0; i<types.size(); i++ ){
+    Trace("sygus-grammar-def") << "Make grammar for " << types[i] << " " << unres_types[i] << std::endl;
+    std::vector<std::string> cnames;
+    std::vector<std::vector<CVC4::Type> > cargs;
+    Type unres_t = unres_types[i];
+    //add variables
+    for( unsigned j=0; j<sygus_vars.size(); j++ ){
+      if( sygus_vars[j].getType()==types[i] ){
+        std::stringstream ss;
+        ss << sygus_vars[j];
+        Trace("sygus-grammar-def") << "...add for variable " << ss.str() << std::endl;
+        ops[i].push_back( sygus_vars[j].toExpr() );
+        cnames.push_back( ss.str() );
+        cargs.push_back( std::vector< CVC4::Type >() );
+      }
+    }
+    //add constants
+    std::vector< Node > consts;
+    mkSygusConstantsForType( types[i], consts );
+    std::map< TypeNode, std::vector< Node > >::iterator itec = extra_cons.find( types[i] );
+    if( itec!=extra_cons.end() ){
+      //consts.insert( consts.end(), itec->second.begin(), itec->second.end() );
+      for( unsigned j=0; j<itec->second.size(); j++ ){
+        if( std::find( consts.begin(), consts.end(), itec->second[j] )==consts.end() ){
+          consts.push_back( itec->second[j] );
+        }
+      }
+    }
+    for( unsigned j=0; j<consts.size(); j++ ){
+      std::stringstream ss;
+      ss << consts[j];
+      Trace("sygus-grammar-def") << "...add for constant " << ss.str() << std::endl;
+      ops[i].push_back( consts[j].toExpr() );
+      cnames.push_back( ss.str() );
+      cargs.push_back( std::vector< CVC4::Type >() );
+    }
+    //ITE
+    CVC4::Kind k = kind::ITE;
+    Trace("sygus-grammar-def") << "...add for " << k << std::endl;
+    ops[i].push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
+    cnames.push_back( kind::kindToString(k) );
+    cargs.push_back( std::vector< CVC4::Type >() );
+    cargs.back().push_back(unres_bt);
+    cargs.back().push_back(unres_t);
+    cargs.back().push_back(unres_t);
+
+    if (types[i].isReal())
+    {
+      for (unsigned j = 0; j < 2; j++)
+      {
+        Kind k = j == 0 ? PLUS : MINUS;
+        Trace("sygus-grammar-def") << "...add for " << k << std::endl;
+        ops[i].push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
+        cnames.push_back(kind::kindToString(k));
+        cargs.push_back(std::vector<CVC4::Type>());
+        cargs.back().push_back(unres_t);
+        cargs.back().push_back(unres_t);
+      }
+      if (!types[i].isInteger())
+      {
+        Trace("sygus-grammar-def") << "...Dedicate to Real\n";
+        /* Creating type for positive integers */
+        std::stringstream ss;
+        ss << fun << "_PosInt";
+        std::string pos_int_name = ss.str();
+        // make unresolved type
+        Type unres_pos_int_t = mkUnresolvedType(pos_int_name, unres).toType();
+        // make data type
+        datatypes.push_back(Datatype(pos_int_name));
+        /* add placeholders */
+        std::vector<Expr> ops_pos_int;
+        std::vector<std::string> cnames_pos_int;
+        std::vector<std::vector<Type>> cargs_pos_int;
+        /* Add operator 1 */
+        Trace("sygus-grammar-def") << "\t...add for 1 to Pos_Int\n";
+        ops_pos_int.push_back(
+            NodeManager::currentNM()->mkConst(Rational(1)).toExpr());
+        ss << "_1";
+        cnames_pos_int.push_back(ss.str());
+        cargs_pos_int.push_back(std::vector<Type>());
+        /* Add operator PLUS */
+        Kind k = PLUS;
+        Trace("sygus-grammar-def") << "\t...add for PLUS to Pos_Int\n";
+        ops_pos_int.push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
+        cnames_pos_int.push_back(kindToString(k));
+        cargs_pos_int.push_back(std::vector<Type>());
+        cargs_pos_int.back().push_back(unres_pos_int_t);
+        cargs_pos_int.back().push_back(unres_pos_int_t);
+        datatypes.back().setSygus(types[i].toType(), bvl.toExpr(), true, true);
+        for (unsigned j = 0; j < ops_pos_int.size(); j++)
+        {
+          datatypes.back().addSygusConstructor(
+              ops_pos_int[j], cnames_pos_int[j], cargs_pos_int[j]);
+        }
+        Trace("sygus-grammar-def")
+            << "...built datatype " << datatypes.back() << " ";
+        /* Adding division at root */
+        k = DIVISION;
+        Trace("sygus-grammar-def") << "\t...add for " << k << std::endl;
+        ops[i].push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
+        cnames.push_back(kindToString(k));
+        cargs.push_back(std::vector<Type>());
+        cargs.back().push_back(unres_t);
+        cargs.back().push_back(unres_pos_int_t);
+      }
+    }else if( types[i].isDatatype() ){
+      Trace("sygus-grammar-def") << "...add for constructors" << std::endl;
+      const Datatype& dt = ((DatatypeType)types[i].toType()).getDatatype();
+      for( unsigned k=0; k<dt.getNumConstructors(); k++ ){
+        Trace("sygus-grammar-def") << "...for " << dt[k].getName() << std::endl;
+        ops[i].push_back( dt[k].getConstructor() );
+        cnames.push_back( dt[k].getName() );
+        cargs.push_back( std::vector< CVC4::Type >() );
+        for( unsigned j=0; j<dt[k].getNumArgs(); j++ ){
+          TypeNode crange = TypeNode::fromType( ((SelectorType)dt[k][j].getType()).getRangeType() );
+          //Assert( type_to_unres.find(crange)!=type_to_unres.end() );
+          cargs.back().push_back( type_to_unres[crange] );
+        }
+      }
+    }else{
+      std::stringstream sserr;
+      sserr << "No implementation for default Sygus grammar of type " << types[i] << std::endl;
+      //AlwaysAssert( false, sserr.str() );
+      // FIXME
+      AlwaysAssert( false );
+    }
+    //add for all selectors to this type
+    if( !sels[types[i]].empty() ){
+      Trace("sygus-grammar-def") << "...add for selectors" << std::endl;
+      for( unsigned j=0; j<sels[types[i]].size(); j++ ){
+        Trace("sygus-grammar-def") << "...for " << sels[types[i]][j].getName() << std::endl;
+        TypeNode arg_type = TypeNode::fromType( ((SelectorType)sels[types[i]][j].getType()).getDomain() );
+        ops[i].push_back( sels[types[i]][j].getSelector() );
+        cnames.push_back( sels[types[i]][j].getName() );
+        cargs.push_back( std::vector< CVC4::Type >() );
+        //Assert( type_to_unres.find(arg_type)!=type_to_unres.end() );
+        cargs.back().push_back( type_to_unres[arg_type] );
+      }
+    }
+    Trace("sygus-grammar-def") << "...make datatype " << datatypes[i] << std::endl;
+    datatypes[i].setSygus( types[i].toType(), bvl.toExpr(), true, true );
+    for( unsigned j=0; j<ops[i].size(); j++ ){
+      datatypes[i].addSygusConstructor( ops[i][j], cnames[j], cargs[j] );
+    }
+    Trace("sygus-grammar-def")
+        << "...built datatype " << datatypes[i] << " ";
+    //sorts.push_back( types[i] );
+    //set start index if applicable
+    if( types[i]==range ){
+      startIndex = i;
+    }
+  }
+
+  //make Boolean type
+  TypeNode btype = NodeManager::currentNM()->booleanType();
+  datatypes.push_back(Datatype(dbname));
+  ops.push_back(std::vector<Expr>());
+  std::vector<std::string> cnames;
+  std::vector<std::vector< Type > > cargs;
+  Trace("sygus-grammar-def") << "Make grammar for " << btype << " " << datatypes.back() << std::endl;
+  //add variables
+  for( unsigned i=0; i<sygus_vars.size(); i++ ){
+    if( sygus_vars[i].getType().isBoolean() ){
+      std::stringstream ss;
+      ss << sygus_vars[i];
+      Trace("sygus-grammar-def") << "...add for variable " << ss.str() << std::endl;
+      ops.back().push_back( sygus_vars[i].toExpr() );
+      cnames.push_back( ss.str() );
+      cargs.push_back( std::vector< CVC4::Type >() );
+    }
+  }
+  //add constants if no variables and no connected types
+  if( ops.back().empty() && types.empty() ){
+    std::vector< Node > consts;
+    mkSygusConstantsForType( btype, consts );
+    for( unsigned j=0; j<consts.size(); j++ ){
+      std::stringstream ss;
+      ss << consts[j];
+      Trace("sygus-grammar-def") << "...add for constant " << ss.str() << std::endl;
+      ops.back().push_back( consts[j].toExpr() );
+      cnames.push_back( ss.str() );
+      cargs.push_back( std::vector< CVC4::Type >() );
+    }
+  }
+  //add operators
+  for( unsigned i=0; i<3; i++ ){
+    CVC4::Kind k = i==0 ? kind::NOT : ( i==1 ? kind::AND : kind::OR );
+    Trace("sygus-grammar-def") << "...add for " << k << std::endl;
+    ops.back().push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
+    cnames.push_back(kind::kindToString(k));
+    cargs.push_back( std::vector< CVC4::Type >() );
+    if( k==kind::NOT ){
+      cargs.back().push_back(unres_bt);
+    }else if( k==kind::AND || k==kind::OR ){
+      cargs.back().push_back(unres_bt);
+      cargs.back().push_back(unres_bt);
+    }
+  }
+  //add predicates for types
+  for( unsigned i=0; i<types.size(); i++ ){
+    Trace("sygus-grammar-def") << "...add predicates for " << types[i] << std::endl;
+    //add equality per type
+    CVC4::Kind k = kind::EQUAL;
+    Trace("sygus-grammar-def") << "...add for " << k << std::endl;
+    ops.back().push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
+    std::stringstream ss;
+    ss << kind::kindToString(k) << "_" << types[i];
+    cnames.push_back(ss.str());
+    cargs.push_back( std::vector< CVC4::Type >() );
+    cargs.back().push_back(unres_types[i]);
+    cargs.back().push_back(unres_types[i]);
+    //type specific predicates
+    if (types[i].isReal())
+    {
+      CVC4::Kind k = kind::LEQ;
+      Trace("sygus-grammar-def") << "...add for " << k << std::endl;
+      ops.back().push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
+      cnames.push_back(kind::kindToString(k));
+      cargs.push_back( std::vector< CVC4::Type >() );
+      cargs.back().push_back(unres_types[i]);
+      cargs.back().push_back(unres_types[i]);
+    }else if( types[i].isDatatype() ){
+      //add for testers
+      Trace("sygus-grammar-def") << "...add for testers" << std::endl;
+      const Datatype& dt = ((DatatypeType)types[i].toType()).getDatatype();
+      for( unsigned k=0; k<dt.getNumConstructors(); k++ ){
+        Trace("sygus-grammar-def") << "...for " << dt[k].getTesterName() << std::endl;
+        ops.back().push_back(dt[k].getTester());
+        cnames.push_back(dt[k].getTesterName());
+        cargs.push_back( std::vector< CVC4::Type >() );
+        cargs.back().push_back(unres_types[i]);
+      }
+    }
+  }
+  if( range==btype ){
+    startIndex = datatypes.size()-1;
+  }
+  Trace("sygus-grammar-def") << "...make datatype " << datatypes.back() << std::endl;
+  datatypes.back().setSygus( btype.toType(), bvl.toExpr(), true, true );
+  for( unsigned j=0; j<ops.back().size(); j++ ){
+    datatypes.back().addSygusConstructor( ops.back()[j], cnames[j], cargs[j] );
+  }
+  //sorts.push_back( btype );
+  Trace("sygus-grammar-def") << "...finished make default grammar for " << fun << " " << range << std::endl;
+  
+  if( startIndex>0 ){
+    CVC4::Datatype tmp_dt = datatypes[0];
+    datatypes[0] = datatypes[startIndex];
+    datatypes[startIndex] = tmp_dt;
+  }
+}
+
+TypeNode CegGrammarConstructor::mkSygusDefaultType(
+    TypeNode range,
+    Node bvl,
+    const std::string& fun,
+    std::map<TypeNode, std::vector<Node> >& extra_cons,
+    std::unordered_set<Node, NodeHashFunction>& term_irrelevant)
+{
+  Trace("sygus-grammar-def") << "*** Make sygus default type " << range << ", make datatypes..." << std::endl;
+  for( std::map< TypeNode, std::vector< Node > >::iterator it = extra_cons.begin(); it != extra_cons.end(); ++it ){
+    Trace("sygus-grammar-def") << "    ...using " << it->second.size() << " extra constants for " << it->first << std::endl;
+  }
+  std::set<Type> unres;
+  std::vector< CVC4::Datatype > datatypes;
+  mkSygusDefaultGrammar(
+      range, bvl, fun, extra_cons, term_irrelevant, datatypes, unres);
+  Trace("sygus-grammar-def")  << "...made " << datatypes.size() << " datatypes, now make mutual datatype types..." << std::endl;
+  Assert( !datatypes.empty() );
+  std::vector<DatatypeType> types = NodeManager::currentNM()->toExprManager()->mkMutualDatatypeTypes(datatypes, unres);
+  Assert( types.size()==datatypes.size() );
+  return TypeNode::fromType( types[0] );
+}
+
+TypeNode CegGrammarConstructor::mkSygusTemplateTypeRec( Node templ, Node templ_arg, TypeNode templ_arg_sygus_type, Node bvl, 
+                                              const std::string& fun, unsigned& tcount ) {
+  if( templ==templ_arg ){
+    //Assert( templ_arg.getType()==sygusToBuiltinType( templ_arg_sygus_type ) );
+    return templ_arg_sygus_type;
+  }else{
+    tcount++;
+    std::set<Type> unres;
+    std::vector< CVC4::Datatype > datatypes;
+    std::stringstream ssd;
+    ssd << fun << "_templ_" << tcount;
+    std::string dbname = ssd.str();
+    datatypes.push_back(Datatype(dbname));
+    Node op;
+    std::vector< Type > argTypes;
+    if( templ.getNumChildren()==0 ){
+      // TODO : can short circuit to this case when !TermUtil::containsTerm( templ, templ_arg )
+      op = templ;
+    }else{
+      Assert( templ.hasOperator() );
+      op = templ.getOperator();
+      // make constructor taking arguments types from children
+      for( unsigned i=0; i<templ.getNumChildren(); i++ ){
+        //recursion depth bound by the depth of SyGuS template expressions (low)
+        TypeNode tnc = mkSygusTemplateTypeRec( templ[i], templ_arg, templ_arg_sygus_type, bvl, fun, tcount );
+        argTypes.push_back( tnc.toType() );
+      }
+    }
+    std::stringstream ssdc;
+    ssdc << fun << "_templ_cons_" << tcount;
+    std::string cname = ssdc.str();
+    // we have a single sygus constructor that encodes the template
+    datatypes.back().addSygusConstructor( op.toExpr(), cname, argTypes );
+    datatypes.back().setSygus( templ.getType().toType(), bvl.toExpr(), true, true );
+    std::vector<DatatypeType> types = NodeManager::currentNM()->toExprManager()->mkMutualDatatypeTypes(datatypes, unres);
+    Assert( types.size()==1 );
+    return TypeNode::fromType( types[0] );
+  }
+}
+
+TypeNode CegGrammarConstructor::mkSygusTemplateType( Node templ, Node templ_arg, TypeNode templ_arg_sygus_type, Node bvl, 
+                                                     const std::string& fun ) {
+  unsigned tcount = 0;
+  return mkSygusTemplateTypeRec( templ, templ_arg, templ_arg_sygus_type, bvl, fun, tcount );
+}
+
+}/* namespace CVC4::theory::quantifiers */
+}/* namespace CVC4::theory */
+}/* namespace CVC4 */
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_cons.h b/src/theory/quantifiers/sygus/sygus_grammar_cons.h
new file mode 100644 (file)
index 0000000..4e486f8
--- /dev/null
@@ -0,0 +1,131 @@
+/*********************                                                        */
+/*! \file sygus_grammar_cons.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief class for constructing inductive datatypes that correspond to
+ ** grammars that encode syntactic restrictions for SyGuS.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_CONS_H
+#define __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_CONS_H
+
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class CegConjecture;
+
+/** utility for constructing datatypes that correspond to syntactic restrictions,
+* and applying the deep embedding from Section 4 of Reynolds et al CAV 2015.
+*/
+class CegGrammarConstructor
+{
+public:
+ CegGrammarConstructor(QuantifiersEngine* qe, CegConjecture* p);
+ ~CegGrammarConstructor() {}
+ /** process
+  * This converts node q based on its deep embedding
+  * (Section 4 of Reynolds et al CAV 2015).
+  * The syntactic restrictions are associated with
+  * the functions-to-synthesize using the attribute
+  * SygusSynthGrammarAttribute.
+  * The arguments templates and template_args
+  * indicate templates for the function to synthesize,
+  * in particular the solution for the i^th function
+  * to synthesis must be of the form
+  *   templates[i]{ templates_arg[i] -> t }
+  * for some t if !templates[i].isNull().
+  */
+ Node process(Node q,
+              std::map<Node, Node>& templates,
+              std::map<Node, Node>& templates_arg);
+ /** is the syntax restricted? */
+ bool isSyntaxRestricted() { return d_is_syntax_restricted; }
+ /** does the syntax allow ITE expressions? */
+ bool hasSyntaxITE() { return d_has_ite; }
+ /** make the default sygus datatype type corresponding to builtin type range
+ *   bvl is the set of free variables to include in the grammar
+ *   fun is for naming
+ *   extra_cons is a set of extra constant symbols to include in the grammar
+ *   term_irrelevant is a set of terms that should not be included in the
+ *      grammar.
+ */
+ static TypeNode mkSygusDefaultType(
+     TypeNode range,
+     Node bvl,
+     const std::string& fun,
+     std::map<TypeNode, std::vector<Node> >& extra_cons,
+     std::unordered_set<Node, NodeHashFunction>& term_irrelevant);
+ /** make the default sygus datatype type corresponding to builtin type range */
+ static TypeNode mkSygusDefaultType(TypeNode range,
+                                    Node bvl,
+                                    const std::string& fun)
+ {
+   std::map<TypeNode, std::vector<Node> > extra_cons;
+   std::unordered_set<Node, NodeHashFunction> term_irrelevant;
+   return mkSygusDefaultType(range, bvl, fun, extra_cons, term_irrelevant);
+  }
+  /** make the sygus datatype type that encodes the solution space (lambda
+  * templ_arg. templ[templ_arg]) where templ_arg
+  * has syntactic restrictions encoded by sygus type templ_arg_sygus_type
+  *   bvl is the set of free variables to include in the grammar
+  *   fun is for naming
+  */
+  static TypeNode mkSygusTemplateType( Node templ, Node templ_arg, TypeNode templ_arg_sygus_type, Node bvl, const std::string& fun );
+private:
+  /** reference to quantifier engine */
+  QuantifiersEngine * d_qe;
+  /** parent conjecture
+  * This contains global information about the synthesis conjecture.
+  */
+  CegConjecture* d_parent;
+  /** is the syntax restricted? */
+  bool d_is_syntax_restricted;
+  /** does the syntax allow ITE expressions? */
+  bool d_has_ite;
+  /** collect terms */
+  void collectTerms( Node n, std::map< TypeNode, std::vector< Node > >& consts );
+  /** convert node n based on deep embedding (Section 4 of Reynolds et al CAV 2015) */
+  Node convertToEmbedding( Node n, std::map< Node, Node >& synth_fun_vars );
+  //---------------- grammar construction
+  // helper for mkSygusDefaultGrammar (makes unresolved type for mutually recursive datatype construction)
+  static TypeNode mkUnresolvedType(const std::string& name, std::set<Type>& unres);
+  // make the builtin constants for type type that should be included in a sygus grammar
+  static void mkSygusConstantsForType( TypeNode type, std::vector<CVC4::Node>& ops );
+  // collect the list of types that depend on type range
+  static void collectSygusGrammarTypesFor( TypeNode range, std::vector< TypeNode >& types, std::map< TypeNode, std::vector< DatatypeConstructorArg > >& sels );
+  /** helper function for function mkSygusDefaultType
+  * Collects a set of mutually recursive datatypes "datatypes" corresponding to
+  * encoding type "range" to SyGuS.
+  *   unres is used for the resulting call to mkMutualDatatypeTypes
+  */
+  static void mkSygusDefaultGrammar(
+      TypeNode range,
+      Node bvl,
+      const std::string& fun,
+      std::map<TypeNode, std::vector<Node> >& extra_cons,
+      std::unordered_set<Node, NodeHashFunction>& term_irrelevant,
+      std::vector<CVC4::Datatype>& datatypes,
+      std::set<Type>& unres);
+  // helper function for mkSygusTemplateType
+  static TypeNode mkSygusTemplateTypeRec( Node templ, Node templ_arg, TypeNode templ_arg_sygus_type, Node bvl, 
+                                          const std::string& fun, unsigned& tcount );
+  //---------------- end grammar construction
+};
+
+} /* namespace CVC4::theory::quantifiers */
+} /* namespace CVC4::theory */
+} /* namespace CVC4 */
+
+#endif
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_norm.cpp b/src/theory/quantifiers/sygus/sygus_grammar_norm.cpp
new file mode 100644 (file)
index 0000000..73311b0
--- /dev/null
@@ -0,0 +1,492 @@
+/*********************                                                        */
+/*! \file sygus_grammar_norm.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief implementation of class for for simplifying SyGuS grammars after they
+ ** are encoded into datatypes.
+ **/
+
+#include "theory/quantifiers/sygus/sygus_grammar_norm.h"
+
+#include "expr/datatype.h"
+#include "options/quantifiers_options.h"
+#include "printer/sygus_print_callback.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
+#include "theory/quantifiers/sygus/ce_guided_conjecture.h"
+#include "theory/quantifiers/sygus/sygus_grammar_red.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
+#include "theory/quantifiers/term_util.h"
+
+#include <numeric>  // for std::iota
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+bool OpPosTrie::getOrMakeType(TypeNode tn,
+                              TypeNode& unres_tn,
+                              const std::vector<unsigned>& op_pos,
+                              unsigned ind)
+{
+  if (ind == op_pos.size())
+  {
+    /* Found type */
+    if (!d_unres_tn.isNull())
+    {
+      Trace("sygus-grammar-normalize-trie")
+          << "\tFound type " << d_unres_tn << "\n";
+      unres_tn = d_unres_tn;
+      return true;
+    }
+    /* Creating unresolved type */
+    std::stringstream ss;
+    ss << tn << "_";
+    for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
+    {
+      ss << "_" << std::to_string(op_pos[i]);
+    }
+    d_unres_tn = NodeManager::currentNM()->mkSort(
+        ss.str(), ExprManager::SORT_FLAG_PLACEHOLDER);
+    Trace("sygus-grammar-normalize-trie")
+        << "\tCreating type " << d_unres_tn << "\n";
+    unres_tn = d_unres_tn;
+    return false;
+  }
+  /* Go to next node */
+  return d_children[op_pos[ind]].getOrMakeType(tn, unres_tn, op_pos, ind + 1);
+}
+
+void SygusGrammarNorm::TypeObject::addConsInfo(SygusGrammarNorm* sygus_norm,
+                                               const DatatypeConstructor& cons)
+{
+  Trace("sygus-grammar-normalize") << "...for " << cons.getName() << "\n";
+  /* Recover the sygus operator to not lose reference to the original
+   * operator (NOT, ITE, etc) */
+  Node exp_sop_n = Node::fromExpr(
+      smt::currentSmtEngine()->expandDefinitions(cons.getSygusOp()));
+  d_ops.push_back(Rewriter::rewrite(exp_sop_n));
+  Trace("sygus-grammar-normalize-defs")
+      << "\tOriginal op: " << cons.getSygusOp()
+      << "\n\tExpanded one: " << exp_sop_n
+      << "\n\tRewritten one: " << d_ops.back() << "\n\n";
+  d_cons_names.push_back(cons.getName());
+  d_pc.push_back(cons.getSygusPrintCallback());
+  d_weight.push_back(cons.getWeight());
+  d_cons_args_t.push_back(std::vector<Type>());
+  for (const DatatypeConstructorArg& arg : cons)
+  {
+    /* Collect unresolved type nodes corresponding to the typenode of the
+     * arguments */
+    d_cons_args_t.back().push_back(
+        sygus_norm
+            ->normalizeSygusRec(TypeNode::fromType(
+                static_cast<SelectorType>(arg.getType()).getRangeType()))
+            .toType());
+  }
+}
+
+void SygusGrammarNorm::TypeObject::buildDatatype(SygusGrammarNorm* sygus_norm,
+                                                 const Datatype& dt)
+{
+  /* Use the sygus type to not lose reference to the original types (Bool,
+   * Int, etc) */
+  d_dt.setSygus(dt.getSygusType(),
+                sygus_norm->d_sygus_vars.toExpr(),
+                dt.getSygusAllowConst(),
+                dt.getSygusAllowAll());
+  for (unsigned i = 0, size_d_ops = d_ops.size(); i < size_d_ops; ++i)
+  {
+    d_dt.addSygusConstructor(d_ops[i].toExpr(),
+                             d_cons_names[i],
+                             d_cons_args_t[i],
+                             d_pc[i],
+                             d_weight[i]);
+  }
+  Trace("sygus-grammar-normalize") << "...built datatype " << d_dt << " ";
+  /* Add to global accumulators */
+  sygus_norm->d_dt_all.push_back(d_dt);
+  sygus_norm->d_unres_t_all.insert(d_unres_tn.toType());
+  Trace("sygus-grammar-normalize") << "---------------------------------\n";
+}
+
+void SygusGrammarNorm::TransfDrop::buildType(SygusGrammarNorm* sygus_norm,
+                                             TypeObject& to,
+                                             const Datatype& dt,
+                                             std::vector<unsigned>& op_pos)
+{
+  std::vector<unsigned> difference;
+  std::set_difference(op_pos.begin(),
+                      op_pos.end(),
+                      d_drop_indices.begin(),
+                      d_drop_indices.end(),
+                      std::back_inserter(difference));
+  op_pos = difference;
+}
+
+/* TODO #1304: have more operators and types. Moreover, have more general ways
+   of finding kind of operator, e.g. if op is (\lambda xy. x + y) this
+   function should realize that it is chainable for integers */
+bool SygusGrammarNorm::TransfChain::isChainable(TypeNode tn, Node op)
+{
+  /* Checks whether operator occurs chainable for its type */
+  if (tn.isInteger() && NodeManager::currentNM()->operatorToKind(op) == PLUS)
+  {
+    return true;
+  }
+  return false;
+}
+
+/* TODO #1304: have more operators and types. Moreover, have more general ways
+   of finding kind of operator, e.g. if op is (\lambda xy. x + y) this
+   function should realize that it is chainable for integers */
+bool SygusGrammarNorm::TransfChain::isId(TypeNode tn, Node op, Node n)
+{
+  if (tn.isInteger() && NodeManager::currentNM()->operatorToKind(op) == PLUS
+      && n == TermUtil::mkTypeValue(tn, 0))
+  {
+    return true;
+  }
+  return false;
+}
+
+void SygusGrammarNorm::TransfChain::buildType(SygusGrammarNorm* sygus_norm,
+                                              TypeObject& to,
+                                              const Datatype& dt,
+                                              std::vector<unsigned>& op_pos)
+{
+  NodeManager* nm = NodeManager::currentNM();
+  std::vector<unsigned> claimed(d_elem_pos);
+  claimed.push_back(d_chain_op_pos);
+  unsigned nb_op_pos = op_pos.size();
+  /* TODO do this properly */
+  /* Remove from op_pos the positions claimed by the transformation */
+  std::sort(op_pos.begin(), op_pos.end());
+  std::sort(claimed.begin(), claimed.end());
+  std::vector<unsigned> difference;
+  std::set_difference(op_pos.begin(),
+                      op_pos.end(),
+                      claimed.begin(),
+                      claimed.end(),
+                      std::back_inserter(difference));
+  op_pos = difference;
+  if (Trace.isOn("sygus-grammar-normalize-chain"))
+  {
+    Trace("sygus-grammar-normalize-chain")
+        << "OP at " << d_chain_op_pos << "\n"
+        << d_elem_pos.size() << " d_elem_pos: ";
+    for (unsigned i = 0, size = d_elem_pos.size(); i < size; ++i)
+    {
+      Trace("sygus-grammar-normalize-chain") << d_elem_pos[i] << " ";
+    }
+    Trace("sygus-grammar-normalize-chain")
+        << "\n"
+        << op_pos.size() << " remaining op_pos: ";
+    for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
+    {
+      Trace("sygus-grammar-normalize-chain") << op_pos[i] << " ";
+    }
+    Trace("sygus-grammar-normalize-chain") << "\n";
+  }
+  /* Build identity operator and empty callback */
+  Node iden_op =
+      SygusGrammarNorm::getIdOp(TypeNode::fromType(dt.getSygusType()));
+  /* If all operators are claimed, create a monomial */
+  if (nb_op_pos == d_elem_pos.size() + 1)
+  {
+    Trace("sygus-grammar-normalize-chain")
+        << "\tCreating id type for " << d_elem_pos.back() << "\n";
+    /* creates type for element */
+    std::vector<unsigned> tmp;
+    tmp.push_back(d_elem_pos.back());
+    Type t = sygus_norm->normalizeSygusRec(to.d_tn, dt, tmp).toType();
+    /* consumes element */
+    d_elem_pos.pop_back();
+    /* adds to Root: "type" */
+    to.d_ops.push_back(iden_op);
+    to.d_cons_names.push_back("id");
+    to.d_pc.push_back(printer::SygusEmptyPrintCallback::getEmptyPC());
+    /* Identity operators should not increase the size of terms */
+    to.d_weight.push_back(0);
+    to.d_cons_args_t.push_back(std::vector<Type>());
+    to.d_cons_args_t.back().push_back(t);
+    Trace("sygus-grammar-normalize-chain")
+        << "\tAdding  " << t << " to " << to.d_unres_tn << "\n";
+    /* adds to Root: "type + Root" */
+    to.d_ops.push_back(nm->operatorOf(PLUS));
+    to.d_cons_names.push_back(kindToString(PLUS));
+    to.d_pc.push_back(nullptr);
+    to.d_weight.push_back(-1);
+    to.d_cons_args_t.push_back(std::vector<Type>());
+    to.d_cons_args_t.back().push_back(t);
+    to.d_cons_args_t.back().push_back(to.d_unres_tn.toType());
+    Trace("sygus-grammar-normalize-chain")
+        << "\tAdding PLUS to " << to.d_unres_tn << " with arg types "
+        << to.d_unres_tn << " and " << t << "\n";
+  }
+  /* In the initial case if not all operators claimed always creates a next */
+  Assert(nb_op_pos != d_elem_pos.size() + 1 || d_elem_pos.size() > 1);
+  /* TODO #1304: consider case in which CHAIN op has different types than
+     to.d_tn */
+  /* If no more elements to chain, finish */
+  if (d_elem_pos.size() == 0)
+  {
+    return;
+  }
+  /* Creates a type do be added to root representing next step in the chain */
+  /* Add + to elems */
+  d_elem_pos.push_back(d_chain_op_pos);
+  if (Trace.isOn("sygus-grammar-normalize-chain"))
+  {
+    Trace("sygus-grammar-normalize-chain")
+        << "\tCreating type for next entry with sygus_ops ";
+    for (unsigned i = 0, size = d_elem_pos.size(); i < size; ++i)
+    {
+      Trace("sygus-grammar-normalize-chain")
+          << dt[d_elem_pos[i]].getSygusOp() << " ";
+    }
+    Trace("sygus-grammar-normalize-chain") << "\n";
+  }
+  /* adds to Root: (\lambda x. x ) Next */
+  to.d_ops.push_back(iden_op);
+  to.d_cons_names.push_back("id_next");
+  to.d_pc.push_back(printer::SygusEmptyPrintCallback::getEmptyPC());
+  to.d_weight.push_back(0);
+  to.d_cons_args_t.push_back(std::vector<Type>());
+  to.d_cons_args_t.back().push_back(
+      sygus_norm->normalizeSygusRec(to.d_tn, dt, d_elem_pos).toType());
+}
+
+std::map<TypeNode, Node> SygusGrammarNorm::d_tn_to_id = {};
+
+/* Traverse the constructors of dt according to the positions in op_pos. Collect
+ * those that fit the kinds established by to_collect. Remove collected operator
+ * positions from op_pos. Accumulate collected positions in collected
+ *
+ * returns true if collected anything
+ */
+std::unique_ptr<SygusGrammarNorm::Transf> SygusGrammarNorm::inferTransf(
+    TypeNode tn, const Datatype& dt, const std::vector<unsigned>& op_pos)
+{
+  NodeManager* nm = NodeManager::currentNM();
+  TypeNode sygus_tn = TypeNode::fromType(dt.getSygusType());
+  Trace("sygus-gnorm") << "Infer transf for " << dt.getName() << "..."
+                       << std::endl;
+  Trace("sygus-gnorm") << "  #cons = " << op_pos.size() << " / "
+                       << dt.getNumConstructors() << std::endl;
+  // look for redundant constructors to drop
+  if (options::sygusMinGrammar() && dt.getNumConstructors() == op_pos.size())
+  {
+    SygusRedundantCons src;
+    src.initialize(d_qe, tn);
+    std::vector<unsigned> rindices;
+    src.getRedundant(rindices);
+    if (!rindices.empty())
+    {
+      Trace("sygus-gnorm") << "...drop transf, " << rindices.size() << "/"
+                           << op_pos.size() << " constructors." << std::endl;
+      Assert(rindices.size() < op_pos.size());
+      return std::unique_ptr<Transf>(new TransfDrop(rindices));
+    }
+  }
+
+  // if normalization option is not enabled, we do not infer the transformations
+  // below
+  if (!options::sygusGrammarNorm())
+  {
+    return nullptr;
+  }
+
+  /* TODO #1304: step 1: look for singleton */
+  /* step 2: look for chain */
+  unsigned chain_op_pos = dt.getNumConstructors();
+  std::vector<unsigned> elem_pos;
+  for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
+  {
+    Assert(op_pos[i] < dt.getNumConstructors());
+    Expr sop = dt[op_pos[i]].getSygusOp();
+    /* Collects a chainable operator such as PLUS */
+    if (sop.getKind() == BUILTIN
+        && TransfChain::isChainable(sygus_tn, Node::fromExpr(sop)))
+    {
+      Assert(nm->operatorToKind(Node::fromExpr(sop)) == PLUS);
+      /* TODO #1304: be robust for this case */
+      /* For now only transforms applications whose arguments have the same type
+       * as the root */
+      bool same_type_plus = true;
+      for (const DatatypeConstructorArg& arg : dt[op_pos[i]])
+      {
+        if (TypeNode::fromType(
+                static_cast<SelectorType>(arg.getType()).getRangeType())
+            != tn)
+        {
+          same_type_plus = false;
+          break;
+        }
+      }
+      if (!same_type_plus)
+      {
+        Trace("sygus-grammar-normalize-infer")
+            << "\tFor OP " << PLUS << " did not collecting sop " << sop
+            << " in position " << op_pos[i] << "\n";
+        continue;
+      }
+      Assert(chain_op_pos == dt.getNumConstructors());
+      Trace("sygus-grammar-normalize-infer")
+          << "\tCollecting chainable OP " << sop << " in position " << op_pos[i]
+          << "\n";
+      chain_op_pos = op_pos[i];
+      continue;
+    }
+    /* TODO #1304: check this for each operator */
+    /* Collects elements that are not the identity (e.g. 0 is the id of PLUS) */
+    if (!TransfChain::isId(sygus_tn, nm->operatorOf(PLUS), Node::fromExpr(sop)))
+    {
+      Trace("sygus-grammar-normalize-infer")
+          << "\tCollecting for NON_ID_ELEMS the sop " << sop
+          << " in position " << op_pos[i] << "\n";
+      elem_pos.push_back(op_pos[i]);
+    }
+  }
+  /* Typenode admits a chain transformation for normalization */
+  if (chain_op_pos != dt.getNumConstructors() && !elem_pos.empty())
+  {
+    Trace("sygus-gnorm") << "...chain transf." << std::endl;
+    Trace("sygus-grammar-normalize-infer")
+        << "\tInfering chain transformation\n";
+    return std::unique_ptr<Transf>(new TransfChain(chain_op_pos, elem_pos));
+  }
+  return nullptr;
+}
+
+TypeNode SygusGrammarNorm::normalizeSygusRec(TypeNode tn,
+                                             const Datatype& dt,
+                                             std::vector<unsigned>& op_pos)
+{
+  /* Corresponding type node to tn with the given operator positions. To be
+   * retrieved (if cached) or defined (otherwise) */
+  TypeNode unres_tn;
+  if (Trace.isOn("sygus-grammar-normalize-trie"))
+  {
+    Trace("sygus-grammar-normalize-trie")
+        << "\tRecursing on " << tn << " with op_positions ";
+    for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
+    {
+      Trace("sygus-grammar-normalize-trie") << op_pos[i] << " ";
+    }
+    Trace("sygus-grammar-normalize-trie") << "\n";
+  }
+  /* Checks if unresolved type already created (and returns) or creates it
+   * (and then proceeds to definition) */
+  std::sort(op_pos.begin(), op_pos.end());
+  if (d_tries[tn].getOrMakeType(tn, unres_tn, op_pos))
+  {
+    if (Trace.isOn("sygus-grammar-normalize-trie"))
+    {
+      Trace("sygus-grammar-normalize-trie")
+          << "\tTypenode " << tn << " has already been normalized with op_pos ";
+      for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
+      {
+        Trace("sygus-grammar-normalize-trie") << op_pos[i] << " ";
+      }
+      Trace("sygus-grammar-normalize-trie") << " with tn " << unres_tn << "\n";
+    }
+    return unres_tn;
+  }
+  if (Trace.isOn("sygus-grammar-normalize-trie"))
+  {
+    Trace("sygus-grammar-normalize-trie")
+        << "\tTypenode " << tn << " not yet normalized with op_pos ";
+    for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
+    {
+      Trace("sygus-grammar-normalize-trie") << op_pos[i] << " ";
+    }
+    Trace("sygus-grammar-normalize-trie") << "\n";
+  }
+  /* Creates type object for normalization */
+  TypeObject to(tn, unres_tn);
+
+  /* Determine normalization transformation based on sygus type and given
+    * operators */
+  std::unique_ptr<Transf> transformation = inferTransf(tn, dt, op_pos);
+  /* If a transformation was selected, apply it */
+  if (transformation != nullptr)
+  {
+    transformation->buildType(this, to, dt, op_pos);
+  }
+
+  /* Remaining operators are rebuilt as they are */
+  for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
+  {
+    Assert(op_pos[i] < dt.getNumConstructors());
+    to.addConsInfo(this, dt[op_pos[i]]);
+  }
+  /* Build normalize datatype */
+  if (Trace.isOn("sygus-grammar-normalize"))
+  {
+    Trace("sygus-grammar-normalize") << "\nFor positions ";
+    for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
+    {
+      Trace("sygus-grammar-normalize") << op_pos[i] << " ";
+    }
+    Trace("sygus-grammar-normalize") << " and datatype " << dt << " \n";
+  }
+  to.buildDatatype(this, dt);
+  return to.d_unres_tn;
+}
+
+TypeNode SygusGrammarNorm::normalizeSygusRec(TypeNode tn)
+{
+  /* Collect all operators for normalization */
+  const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
+  std::vector<unsigned> op_pos(dt.getNumConstructors());
+  std::iota(op_pos.begin(), op_pos.end(), 0);
+  return normalizeSygusRec(tn, dt, op_pos);
+}
+
+TypeNode SygusGrammarNorm::normalizeSygusType(TypeNode tn, Node sygus_vars)
+{
+  /* Normalize all types in tn */
+  d_sygus_vars = sygus_vars;
+  normalizeSygusRec(tn);
+  /* Resolve created types */
+  Assert(!d_dt_all.empty() && !d_unres_t_all.empty());
+  if (Trace.isOn("sygus-grammar-normalize-build"))
+  {
+    Trace("sygus-grammar-normalize-build")
+        << "making mutual datatyes with datatypes \n";
+    for (unsigned i = 0, size = d_dt_all.size(); i < size; ++i)
+    {
+      Trace("sygus-grammar-normalize-build") << d_dt_all[i];
+    }
+    Trace("sygus-grammar-normalize-build") << " and unresolved types\n";
+    for (const Type& unres_t : d_unres_t_all)
+    {
+      Trace("sygus-grammar-normalize-build") << unres_t << " ";
+    }
+    Trace("sygus-grammar-normalize-build") << "\n";
+  }
+  Assert(d_dt_all.size() == d_unres_t_all.size());
+  std::vector<DatatypeType> types =
+      NodeManager::currentNM()->toExprManager()->mkMutualDatatypeTypes(
+          d_dt_all, d_unres_t_all);
+  Assert(types.size() == d_dt_all.size());
+  /* Clear accumulators */
+  d_dt_all.clear();
+  d_unres_t_all.clear();
+  /* By construction the normalized type node will be the last one considered */
+  return TypeNode::fromType(types.back());
+}
+
+}  // namespace quantifiers
+}  // namespace theory
+}  // namespace CVC4
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_norm.h b/src/theory/quantifiers/sygus/sygus_grammar_norm.h
new file mode 100644 (file)
index 0000000..f72a83e
--- /dev/null
@@ -0,0 +1,455 @@
+/*********************                                                        */
+/*! \file sygus_grammar_norm.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief class for simplifying SyGuS grammars after they are encoded into
+ ** datatypes.
+ **/
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_NORM_H
+#define __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_NORM_H
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "expr/datatype.h"
+#include "expr/node.h"
+#include "expr/node_manager_attributes.h"  // for VarNameAttr
+#include "expr/type.h"
+#include "expr/type_node.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class SygusGrammarNorm;
+
+/** Operator position trie class
+ *
+ * This data structure stores an unresolved type corresponding to the
+ * normalization of a type. This unresolved type is indexed by the positions of
+ * the construtors of the datatype associated with the original type. The list
+ * of positions represent the operators, associated with the respective
+ * considered constructors, that were used for building the unresolved type.
+ *
+ * Example:
+ *
+ * Let A be a type defined by the grammar "A -> x | 0 | 1 | A + A". In its
+ * datatype representation the operator for "x" is in position 0, for "0" in
+ * position "1" and so on. Consider entries (T, [op_1, ..., op_n]) -> T' to
+ * represent that a type T is normalized with operators [op_1, ..., op_n] into
+ * the type T'. For entries
+ *
+ * (A, [x, 0, 1, +]) -> A1
+ * (A, [x, 1, +]) -> A2
+ * (A, [1, +]) -> A3
+ * (A, [0]) -> AZ
+ * (A, [x]) -> AX
+ * (A, [1]) -> AO
+ *
+ * the OpPosTrie T we build for this type is :
+ *
+ * T[A] :
+ *      T[A].d_children[0] : AX
+ *        T[A].d_children[0].d_children[1] :
+ *          T[A].d_children[0].d_children[1].d_children[2] :
+ *            T[A].d_children[0].d_children[1].d_children[2].d_children[3] : A1
+ *        T[A].d_children[0].d_children[2] :
+ *          T[A].d_children[0].d_children[2].d_children[3] : A2
+ *      T[A].d_children[1] : AZ
+ *      T[A].d_children[2] : AO
+ *        T[A].d_children[2].d_children[4] : A3
+ *
+ * Nodes store the types built for the path of positions up to that point, if
+ * any.
+ */
+class OpPosTrie
+{
+ public:
+  /** type retrieval/addition
+   *
+   * if type indexed by the given operator positions is already in the trie then
+   * unres_t becomes the indexed type and true is returned. Otherwise a new type
+   * is created, indexed by the given positions, and assigned to unres_t, with
+   * false being returned.
+   */
+  bool getOrMakeType(TypeNode tn,
+                     TypeNode& unres_tn,
+                     const std::vector<unsigned>& op_pos,
+                     unsigned ind = 0);
+  /** clear all data from this trie */
+  void clear() { d_children.clear(); }
+
+ private:
+  /** the data (only set for the final node of an inserted path) */
+  TypeNode d_unres_tn;
+  /* the children of the trie node */
+  std::map<unsigned, OpPosTrie> d_children;
+}; /* class OpPosTrie */
+
+/** Utility for normalizing SyGuS grammars to avoid spurious enumerations
+ *
+ * Uses the datatype representation of a SyGuS grammar to identify entries that
+ * can normalized in order to have less possible enumerations. An example is
+ * with integer types, e.g.:
+ *
+ * Int -> x | y | Int + Int | 0 | 1 | ite(Bool, Int, Int)
+ *
+ * becomes
+ *
+ * Int0 -> IntZ | Int1
+ * IntZ -> 0
+ * Int1 -> IntX | IntX + Int1 | Int2
+ * IntX -> x
+ * Int2 -> IntY | IntY + Int2 | Int3
+ * IntY -> y
+ * Int3 -> IntO | IntO + Int3 | Int4
+ * IntO -> 1
+ * Int4 -> IntITE | IntITE + Int4
+ * IntITE -> ite(Bool, Int0, Int0)
+ *
+ * TODO: #1304 normalize more complex grammars
+ *
+ * This class also performs more straightforward normalizations, such as
+ * expanding definitions of functions declared with a "define-fun" command.
+ * These lighweight transformations are always applied, independently of the
+ * normalization option being enabled.
+ */
+class SygusGrammarNorm
+{
+ public:
+  SygusGrammarNorm(QuantifiersEngine* qe)
+      : d_qe(qe), d_tds(d_qe->getTermDatabaseSygus())
+  {
+  }
+  ~SygusGrammarNorm() {}
+  /** creates a normalized typenode from a given one.
+   *
+   * In a normalized typenode all typenodes it contains are normalized.
+   * Normalized typenodes can be structurally identicial to their original
+   * counterparts.
+   *
+   * sygus_vars are the input variables for the function to be synthesized,
+   * which are used as input for the built datatypes.
+   *
+   * This is the function that will resolve all types and datatypes built during
+   * normalization. This operation can only be performed after all types
+   * contained in "tn" have been normalized, since the resolution of datatypes
+   * depends on all types involved being defined.
+   */
+  TypeNode normalizeSygusType(TypeNode tn, Node sygus_vars);
+
+  /* Retrives, or, if none, creates, stores and returns, the node for the
+   * identity operator (\lambda x. x) for the given type node */
+  static inline Node getIdOp(TypeNode tn)
+  {
+    auto it = d_tn_to_id.find(tn);
+    if (it == d_tn_to_id.end())
+    {
+      std::vector<Node> vars = {NodeManager::currentNM()->mkBoundVar(tn)};
+      Node n = NodeManager::currentNM()->mkNode(
+          kind::LAMBDA,
+          NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, vars),
+          vars.back());
+      d_tn_to_id[tn] = n;
+      return n;
+    }
+    return it->second;
+  }
+
+ private:
+  /** Keeps the necessary information for bulding a normalized type:
+   *
+   * the original typenode, from which the datatype representation can be
+   * extracted
+   *
+   * the operators, names, print callbacks and list of argument types for each
+   * constructor
+   *
+   * the unresolved type node used as placeholder for references of the yet to
+   * be built normalized type
+   *
+   * a datatype to represent the structure of the type node for the normalized
+   * type
+   */
+  class TypeObject
+  {
+   public:
+    /* Stores the original type node and the unresolved placeholder. The
+     * datatype for the latter is created with the respective name. */
+    TypeObject(TypeNode src_tn, TypeNode unres_tn)
+        : d_tn(src_tn),
+          d_unres_tn(unres_tn),
+          d_dt(Datatype(unres_tn.getAttribute(expr::VarNameAttr())))
+    {
+    }
+    ~TypeObject() {}
+
+    /** adds information in "cons" (operator, name, print callback, argument
+     * types) as it is into "to"
+     *
+     * A side effect of this procedure is to expand the definitions in the sygus
+     * operator of "cons"
+     *
+     * The types of the arguments of "cons" are recursively normalized
+     */
+    void addConsInfo(SygusGrammarNorm* sygus_norm,
+                     const DatatypeConstructor& cons);
+
+    /** builds a datatype with the information in the type object
+     *
+     * "dt" is the datatype of the original typenode. It is necessary for
+     * retrieving ancillary information during the datatype building, such as
+     * its sygus type (e.g. Int)
+     *
+     * The built datatype and its unresolved type are saved in the global
+     * accumulators of "sygus_norm"
+     */
+    void buildDatatype(SygusGrammarNorm* sygus_norm, const Datatype& dt);
+
+    //---------- information stored from original type node
+
+    /* The original typenode this TypeObject is built from */
+    TypeNode d_tn;
+
+    //---------- information to build normalized type node
+
+    /* Operators for each constructor. */
+    std::vector<Node> d_ops;
+    /* Names for each constructor. */
+    std::vector<std::string> d_cons_names;
+    /* Print callbacks for each constructor */
+    std::vector<std::shared_ptr<SygusPrintCallback>> d_pc;
+    /* Weights for each constructor */
+    std::vector<int> d_weight;
+    /* List of argument types for each constructor */
+    std::vector<std::vector<Type>> d_cons_args_t;
+    /* Unresolved type node placeholder */
+    TypeNode d_unres_tn;
+    /* Datatype to represent type's structure */
+    Datatype d_dt;
+  }; /* class TypeObject */
+
+  /** Transformation abstract class
+   *
+   * Classes extending this one will define specif transformationst for building
+   * normalized types based on applications of specific operators
+   */
+  class Transf
+  {
+   public:
+    virtual ~Transf() {}
+
+    /** abstract function for building normalized types
+     *
+     * Builds normalized types for the operators specifed by the positions in
+     * op_pos of constructors from dt. The built types are associated with the
+     * given type object and accumulated in the sygus_norm object, whose
+     * utilities for any extra necessary normalization.
+     */
+    virtual void buildType(SygusGrammarNorm* sygus_norm,
+                           TypeObject& to,
+                           const Datatype& dt,
+                           std::vector<unsigned>& op_pos) = 0;
+  }; /* class Transf */
+
+  /** Drop transformation class
+   *
+   * This class builds a type by dropping a set of redundant constructors,
+   * whose indices are given as input to the constructor of this class.
+   */
+  class TransfDrop : public Transf
+  {
+   public:
+    TransfDrop(const std::vector<unsigned>& indices) : d_drop_indices(indices)
+    {
+    }
+    /** build type */
+    void buildType(SygusGrammarNorm* sygus_norm,
+                   TypeObject& to,
+                   const Datatype& dt,
+                   std::vector<unsigned>& op_pos) override;
+
+   private:
+    std::vector<unsigned> d_drop_indices;
+  };
+
+  /** Chain transformation class
+   *
+   * Determines how to build normalized types by chaining the application of one
+   * of its operators. The resulting type should admit the same terms as the
+   * previous one modulo commutativity, associativity and identity of the
+   * neutral element.
+   *
+   * TODO: #1304:
+   * - define this transformation for more than just PLUS for Int.
+   * - improve the building such that elements that should not be entitled a
+   * "link in the chain" (such as 5 in opposition to variables and 1) do not get
+   * one
+   * - consider the case when operator is applied to different types, e.g.:
+   *   A -> B + B | x; B -> 0 | 1
+   * - consider the case in which in which the operator occurs nested in an
+   *   argument type of itself, e.g.:
+   *   A -> (B + B) + B | x; B -> 0 | 1
+   */
+  class TransfChain : public Transf
+  {
+   public:
+    TransfChain(unsigned chain_op_pos, const std::vector<unsigned>& elem_pos)
+        : d_chain_op_pos(chain_op_pos), d_elem_pos(elem_pos){};
+
+    /** builds types encoding a chain in which each link contains a repetition
+     * of the application of the chain operator over a non-identity element
+     *
+     * Example: when considering, over the integers, the operator "+" and the
+     * elemenst "1", "x" and "y", the built chain is e.g.
+     *
+     * x + ... + x + y + ... + y + 1 + ...+ 1
+     *
+     * whose encoding in types would be e.g.
+     *
+     * A  -> AX | AX + A | B
+     * AX -> x
+     * B  -> BY | BY + B | C
+     * BY -> y
+     * C  -> C1 | C1 + C
+     * C1 -> 1
+     *
+     * ++++++++
+     *
+     * The types composing links in the chain are built recursively by invoking
+     * sygus_norm, which caches results and handles the global normalization, on
+     * the operators not used in a given link, which will lead to recalling this
+     * transformation and so on until all operators originally given are
+     * considered.
+     */
+    void buildType(SygusGrammarNorm* sygus_norm,
+                   TypeObject& to,
+                   const Datatype& dt,
+                   std::vector<unsigned>& op_pos) override;
+
+    /** Whether operator is chainable for the type (e.g. PLUS for Int)
+     *
+     *  Since the map this function depends on cannot be built statically, this
+     *  function first build maps the first time a type is checked. As a
+     *  consequence the list of chainabel operators is hardcoded in the map
+     *  building.
+     *
+     * TODO: #1304: Cover more types and operators, make this robust to more
+     * complex grammars
+     */
+    static bool isChainable(TypeNode tn, Node op);
+    /* Whether n is the identity for the chain operator of the type (e.g. 1 is
+     * not the identity 0 for PLUS for Int)
+     *
+     * TODO: #1304: Cover more types, make this robust to more complex grammars
+     */
+    static bool isId(TypeNode tn, Node op, Node n);
+
+   private:
+    /* TODO #1304: this should admit more than one, as well as which elements
+     * are associated with which operator */
+    /* Position of chain operator */
+    unsigned d_chain_op_pos;
+    /* Positions (of constructors in the datatype whose type is being
+     * normalized) of elements the chain operator is applied to */
+    std::vector<unsigned> d_elem_pos;
+    /** Specifies for each type node which are its chainable operators
+     *
+     * For example, for Int the map is {OP -> [+]}
+     *
+     * TODO #1304: consider more operators
+     */
+    static std::map<TypeNode, std::vector<Kind>> d_chain_ops;
+    /** Specifies for each type node and chainable operator its identity
+     *
+     * For example, for Int and PLUS the map is {Int -> {+ -> 0}}
+     *
+     * TODO #1304: consider more operators
+     */
+    static std::map<TypeNode, std::map<Kind, Node>> d_chain_op_id;
+
+  }; /* class TransfChain */
+
+  /** reference to quantifier engine */
+  QuantifiersEngine* d_qe;
+  /** sygus term database associated with this utility */
+  TermDbSygus* d_tds;
+  /** List of variable inputs of function-to-synthesize.
+   *
+   * This information is needed in the construction of each datatype
+   * representation of type nodes contained in the type node being normalized
+   */
+  TNode d_sygus_vars;
+  /* Datatypes to be resolved */
+  std::vector<Datatype> d_dt_all;
+  /* Types to be resolved */
+  std::set<Type> d_unres_t_all;
+  /* Associates type nodes with OpPosTries */
+  std::map<TypeNode, OpPosTrie> d_tries;
+  /* Map of type nodes into their identity operators (\lambda x. x) */
+  static std::map<TypeNode, Node> d_tn_to_id;
+
+  /** recursively traverses a typenode normalizing all of its elements
+   *
+   * "tn" is the typenode to be normalized
+   * "dt" is its datatype representation
+   * "op_pos" is the list of positions of construtors of dt that are being
+   * considered for the normalization
+   *
+   * The result of normalizing tn with the respective constructors is cached
+   * with an OpPosTrie. New types and datatypes created during normalization are
+   * accumulated grobally to be later resolved.
+   *
+   * The normalization occurs following some inferred transformation based on
+   * the sygus type (e.g. Int) of tn, and the operators being considered.
+   *
+   * Example: Let A be the type node encoding the grammar
+   *
+   * Int -> x | y | Int + Int | 0 | 1 | ite(Bool, Int, Int)
+   *
+   * and assume all its datatype constructors are being used for
+   * normalization. The inferred normalization transformation will consider the
+   * non-zero elements {x, y, 1, ite(...)} and the operator {+} to build a chain
+   * of monomials, as seen above. The operator for "0" is rebuilt as is (the
+   * default behaviour of operators not selected for transformations).
+   *
+   * recursion depth is limited by the height of the types, which is small
+   */
+  TypeNode normalizeSygusRec(TypeNode tn,
+                             const Datatype& dt,
+                             std::vector<unsigned>& op_pos);
+
+  /** wrapper for the above function
+   *
+   * invoked when all operators of "tn" are to be considered for normalization
+   */
+  TypeNode normalizeSygusRec(TypeNode tn);
+
+  /** infers a transformation for normalizing dt when allowed to use the
+   * operators in the positions op_pos.
+   *
+   * TODO: #1304: Infer more complex transformations
+   */
+  std::unique_ptr<Transf> inferTransf(TypeNode tn,
+                                      const Datatype& dt,
+                                      const std::vector<unsigned>& op_pos);
+}; /* class SygusGrammarNorm */
+
+}  // namespace quantifiers
+}  // namespace theory
+}  // namespace CVC4
+
+#endif
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_red.cpp b/src/theory/quantifiers/sygus/sygus_grammar_red.cpp
new file mode 100644 (file)
index 0000000..939788e
--- /dev/null
@@ -0,0 +1,136 @@
+/*********************                                                        */
+/*! \file sygus_grammar_red.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of sygus_grammar_red
+ **/
+
+#include "theory/quantifiers/sygus/sygus_grammar_red.h"
+
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
+#include "theory/quantifiers/term_util.h"
+
+using namespace std;
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+void SygusRedundantCons::initialize(QuantifiersEngine* qe, TypeNode tn)
+{
+  Assert(qe != nullptr);
+  Trace("sygus-red") << "Compute redundant cons for " << tn << std::endl;
+  d_type = tn;
+  Assert(tn.isDatatype());
+  TermDbSygus* tds = qe->getTermDatabaseSygus();
+  tds->registerSygusType(tn);
+  const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
+  Assert(dt.isSygus());
+  TypeNode btn = TypeNode::fromType(dt.getSygusType());
+  for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
+  {
+    Trace("sygus-red") << "  Is " << dt[i].getName() << " a redundant operator?"
+                       << std::endl;
+    std::map<int, Node> pre;
+    Node g = tds->mkGeneric(dt, i, pre);
+    Trace("sygus-red-debug") << "  ...pre-rewrite : " << g << std::endl;
+    Assert(g.getNumChildren() == dt[i].getNumArgs());
+    d_gen_terms[i] = g;
+    for (unsigned j = 0, nargs = dt[i].getNumArgs(); j < nargs; j++)
+    {
+      pre[j] = g[j];
+    }
+    std::vector<Node> glist;
+    getGenericList(tds, dt, i, 0, pre, glist);
+    // call the extended rewriter
+    bool red = false;
+    for (const Node& gr : glist)
+    {
+      Trace("sygus-red-debug") << "  ...variant : " << gr << std::endl;
+      std::map<Node, unsigned>::iterator itg = d_gen_cons.find(gr);
+      if (itg != d_gen_cons.end() && itg->second != i)
+      {
+        red = true;
+        Trace("sygus-red") << "  ......redundant, since a variant of " << g
+                           << " and " << d_gen_terms[itg->second]
+                           << " both rewrite to " << gr << std::endl;
+        break;
+      }
+      else
+      {
+        d_gen_cons[gr] = i;
+        Trace("sygus-red") << "  ......not redundant." << std::endl;
+      }
+    }
+    d_sygus_red_status.push_back(red ? 1 : 0);
+  }
+}
+
+void SygusRedundantCons::getRedundant(std::vector<unsigned>& indices)
+{
+  const Datatype& dt = static_cast<DatatypeType>(d_type.toType()).getDatatype();
+  for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
+  {
+    if (isRedundant(i))
+    {
+      indices.push_back(i);
+    }
+  }
+}
+
+bool SygusRedundantCons::isRedundant(unsigned i)
+{
+  Assert(i < d_sygus_red_status.size());
+  return d_sygus_red_status[i] == 1;
+}
+
+void SygusRedundantCons::getGenericList(TermDbSygus* tds,
+                                        const Datatype& dt,
+                                        unsigned c,
+                                        unsigned index,
+                                        std::map<int, Node>& pre,
+                                        std::vector<Node>& terms)
+{
+  if (index == dt[c].getNumArgs())
+  {
+    Node gt = tds->mkGeneric(dt, c, pre);
+    gt = tds->getExtRewriter()->extendedRewrite(gt);
+    terms.push_back(gt);
+    return;
+  }
+  // with no swap
+  getGenericList(tds, dt, c, index + 1, pre, terms);
+  // swapping is exponential, only use for operators with small # args.
+  if (dt[c].getNumArgs() <= 5)
+  {
+    TypeNode atype = tds->getArgType(dt[c], index);
+    for (unsigned s = index + 1, nargs = dt[c].getNumArgs(); s < nargs; s++)
+    {
+      if (tds->getArgType(dt[c], s) == atype)
+      {
+        // swap s and index
+        Node tmp = pre[s];
+        pre[s] = pre[index];
+        pre[index] = tmp;
+        getGenericList(tds, dt, c, index + 1, pre, terms);
+        // revert
+        tmp = pre[s];
+        pre[s] = pre[index];
+        pre[index] = tmp;
+      }
+    }
+  }
+}
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_red.h b/src/theory/quantifiers/sygus/sygus_grammar_red.h
new file mode 100644 (file)
index 0000000..d0484aa
--- /dev/null
@@ -0,0 +1,119 @@
+/*********************                                                        */
+/*! \file sygus_grammar_red.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief sygus_grammar_red
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_RED_H
+#define __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_RED_H
+
+#include <map>
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+/** SygusRedundantCons
+ *
+ * This class computes the subset of indices of the constructors of a sygus type
+ * that are redundant. To use this class, first call initialize( qe, tn ),
+ * where tn is a sygus tn. Then, use getRedundant and/or isRedundant to get the
+ * indicies of the constructors of tn that are redundant.
+ */
+class SygusRedundantCons
+{
+ public:
+  SygusRedundantCons() {}
+  ~SygusRedundantCons() {}
+  /** register type tn
+   *
+   * qe : pointer to the quantifiers engine,
+   * tn : the (sygus) type to compute redundant constructors for
+   */
+  void initialize(QuantifiersEngine* qe, TypeNode tn);
+  /** Get the indices of the redundant constructors of the register type */
+  void getRedundant(std::vector<unsigned>& indices);
+  /**
+   * This function returns true if the i^th constructor of the registered type
+   * is redundant.
+   */
+  bool isRedundant(unsigned i);
+
+ private:
+  /** the registered type */
+  TypeNode d_type;
+  /** redundant status
+   *
+   * For each constructor, status indicating whether the constructor is
+   * redundant, where:
+   *
+   * 0 : not redundant,
+   * 1 : redundant since another constructor can be used to construct values for
+   * this constructor.
+   *
+   * For example, for grammar:
+   *   A -> C > B | B < C | not D
+   *   B -> x | y
+   *   C -> 0 | 1 | C+C
+   *   D -> B >= C
+   * If A is register with this class, then we store may store { 0, 1, 0 },
+   * noting that the second constructor of A can be simulated with the first.
+   * Notice that the third constructor is not considered redundant.
+   */
+  std::vector<int> d_sygus_red_status;
+  /**
+   * Map from constructor indices to the generic term for that constructor,
+   * where the generic term for a constructor is the (canonical) term returned
+   * by a call to TermDbSygus::mkGeneric.
+   */
+  std::map<unsigned, Node> d_gen_terms;
+  /**
+   * Map from the rewritten form of generic terms for constructors of the
+   * registered type to their corresponding constructor index.
+   */
+  std::map<Node, unsigned> d_gen_cons;
+  /** get generic list
+   *
+   * This function constructs all well-typed variants of a term of the form
+   *    op( x1, ..., xn )
+   * where op is the builtin operator for dt[c], and xi = pre[i] for i=1,...,n.
+   *
+   * It constructs a list of terms of the form g * sigma, where sigma
+   * is an automorphism on { x1...xn } such that for all xi -> xj in sigma,
+   * the type for arguments i and j of dt[c] are the same. We store this
+   * list of terms in terms.
+   *
+   * This function recurses on the arguments of g, index is the current argument
+   * we are processing, and pre stores the current arguments of
+   *
+   * For example, for a sygus grammar
+   *   A -> and( A, A, B )
+   *   B -> false
+   * passing arguments such that g=and( x1, x2, x3 ) to this function will add:
+   *   and( x1, x2, x3 ) and and( x2, x1, x3 )
+   * to terms.
+   */
+  void getGenericList(TermDbSygus* tds,
+                      const Datatype& dt,
+                      unsigned c,
+                      unsigned index,
+                      std::map<int, Node>& pre,
+                      std::vector<Node>& terms);
+};
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_RED_H */
diff --git a/src/theory/quantifiers/sygus/sygus_invariance.cpp b/src/theory/quantifiers/sygus/sygus_invariance.cpp
new file mode 100644 (file)
index 0000000..6b4c648
--- /dev/null
@@ -0,0 +1,229 @@
+/*********************                                                        */
+/*! \file sygus_invariance.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of techniques for sygus invariance tests.
+ **/
+
+#include "theory/quantifiers/sygus/sygus_invariance.h"
+
+#include "theory/quantifiers/sygus/ce_guided_conjecture.h"
+#include "theory/quantifiers/sygus/sygus_pbe.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
+
+using namespace CVC4::kind;
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+void EvalSygusInvarianceTest::init(Node conj, Node var, Node res)
+{
+  d_conj = conj;
+  d_var = var;
+  d_result = res;
+}
+
+Node EvalSygusInvarianceTest::doEvaluateWithUnfolding(TermDbSygus* tds, Node n)
+{
+  return tds->evaluateWithUnfolding(n, d_visited);
+}
+
+bool EvalSygusInvarianceTest::invariant(TermDbSygus* tds, Node nvn, Node x)
+{
+  TNode tnvn = nvn;
+  Node conj_subs = d_conj.substitute(d_var, tnvn);
+  Node conj_subs_unfold = doEvaluateWithUnfolding(tds, conj_subs);
+  Trace("sygus-cref-eval2-debug")
+      << "  ...check unfolding : " << conj_subs_unfold << std::endl;
+  Trace("sygus-cref-eval2-debug") << "  ......from : " << conj_subs
+                                  << std::endl;
+  if (conj_subs_unfold == d_result)
+  {
+    Trace("sygus-cref-eval2") << "Evaluation min explain : " << conj_subs
+                              << " still evaluates to " << d_result
+                              << " regardless of ";
+    Trace("sygus-cref-eval2") << x << std::endl;
+    return true;
+  }
+  return false;
+}
+
+void EquivSygusInvarianceTest::init(
+    TermDbSygus* tds, TypeNode tn, CegConjecture* aconj, Node e, Node bvr)
+{
+  // compute the current examples
+  d_bvr = bvr;
+  if (aconj->getPbe()->hasExamples(e))
+  {
+    d_conj = aconj;
+    d_enum = e;
+    unsigned nex = aconj->getPbe()->getNumExamples(e);
+    for (unsigned i = 0; i < nex; i++)
+    {
+      d_exo.push_back(d_conj->getPbe()->evaluateBuiltin(tn, bvr, e, i));
+    }
+  }
+}
+
+bool EquivSygusInvarianceTest::invariant(TermDbSygus* tds, Node nvn, Node x)
+{
+  TypeNode tn = nvn.getType();
+  Node nbv = tds->sygusToBuiltin(nvn, tn);
+  Node nbvr = tds->getExtRewriter()->extendedRewrite(nbv);
+  Trace("sygus-sb-mexp-debug") << "  min-exp check : " << nbv << " -> " << nbvr
+                               << std::endl;
+  bool exc_arg = false;
+  // equivalent / singular up to normalization
+  if (nbvr == d_bvr)
+  {
+    // gives the same result : then the explanation for the child is irrelevant
+    exc_arg = true;
+    Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin(nvn)
+                           << " is rewritten to " << nbvr;
+    Trace("sygus-sb-mexp") << " regardless of the content of "
+                           << tds->sygusToBuiltin(x) << std::endl;
+  }
+  else
+  {
+    if (nbvr.isVar())
+    {
+      TypeNode xtn = x.getType();
+      if (xtn == tn)
+      {
+        Node bx = tds->sygusToBuiltin(x, xtn);
+        Assert(bx.getType() == nbvr.getType());
+        if (nbvr == bx)
+        {
+          Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin(nvn)
+                                 << " always rewrites to argument " << nbvr
+                                 << std::endl;
+          // rewrites to the variable : then the explanation of this is
+          // irrelevant as well
+          exc_arg = true;
+          d_bvr = nbvr;
+        }
+      }
+    }
+  }
+  // equivalent under examples
+  if (!exc_arg)
+  {
+    if (!d_enum.isNull())
+    {
+      bool ex_equiv = true;
+      for (unsigned j = 0; j < d_exo.size(); j++)
+      {
+        Node nbvr_ex = d_conj->getPbe()->evaluateBuiltin(tn, nbvr, d_enum, j);
+        if (nbvr_ex != d_exo[j])
+        {
+          ex_equiv = false;
+          break;
+        }
+      }
+      if (ex_equiv)
+      {
+        Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin(nvn);
+        Trace("sygus-sb-mexp")
+            << " is the same w.r.t. examples regardless of the content of "
+            << tds->sygusToBuiltin(x) << std::endl;
+        exc_arg = true;
+      }
+    }
+  }
+  return exc_arg;
+}
+
+bool DivByZeroSygusInvarianceTest::invariant(TermDbSygus* tds, Node nvn, Node x)
+{
+  TypeNode tn = nvn.getType();
+  Node nbv = tds->sygusToBuiltin(nvn, tn);
+  Node nbvr = tds->getExtRewriter()->extendedRewrite(nbv);
+  if (tds->involvesDivByZero(nbvr))
+  {
+    Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin(nvn)
+                           << " involves div-by-zero regardless of "
+                           << tds->sygusToBuiltin(x) << std::endl;
+    return true;
+  }
+  return false;
+}
+
+void NegContainsSygusInvarianceTest::init(CegConjecture* conj,
+                                          Node e,
+                                          std::vector<Node>& exo,
+                                          std::vector<unsigned>& ncind)
+{
+  if (conj->getPbe()->hasExamples(e))
+  {
+    Assert(conj->getPbe()->getNumExamples(e) == exo.size());
+    d_enum = e;
+    d_exo.insert(d_exo.end(), exo.begin(), exo.end());
+    d_neg_con_indices.insert(
+        d_neg_con_indices.end(), ncind.begin(), ncind.end());
+    d_conj = conj;
+  }
+}
+
+bool NegContainsSygusInvarianceTest::invariant(TermDbSygus* tds,
+                                               Node nvn,
+                                               Node x)
+{
+  if (!d_enum.isNull())
+  {
+    TypeNode tn = nvn.getType();
+    Node nbv = tds->sygusToBuiltin(nvn, tn);
+    Node nbvr = tds->getExtRewriter()->extendedRewrite(nbv);
+    // if for any of the examples, it is not contained, then we can exclude
+    for (unsigned i = 0; i < d_neg_con_indices.size(); i++)
+    {
+      unsigned ii = d_neg_con_indices[i];
+      Assert(ii < d_exo.size());
+      Node nbvre = d_conj->getPbe()->evaluateBuiltin(tn, nbvr, d_enum, ii);
+      Node out = d_exo[ii];
+      Node cont =
+          NodeManager::currentNM()->mkNode(kind::STRING_STRCTN, out, nbvre);
+      Trace("sygus-pbe-cterm-debug") << "Check: " << cont << std::endl;
+      Node contr = Rewriter::rewrite(cont);
+      if (contr == tds->d_false)
+      {
+        if (Trace.isOn("sygus-pbe-cterm"))
+        {
+          Trace("sygus-pbe-cterm")
+              << "PBE-cterm : enumerator : do not consider ";
+          Trace("sygus-pbe-cterm") << nbv << " for any "
+                                   << tds->sygusToBuiltin(x) << " since "
+                                   << std::endl;
+          Trace("sygus-pbe-cterm") << "   PBE-cterm :    for input example : ";
+          std::vector<Node> ex;
+          d_conj->getPbe()->getExample(d_enum, ii, ex);
+          for (unsigned j = 0; j < ex.size(); j++)
+          {
+            Trace("sygus-pbe-cterm") << ex[j] << " ";
+          }
+          Trace("sygus-pbe-cterm") << std::endl;
+          Trace("sygus-pbe-cterm")
+              << "   PBE-cterm :     this rewrites to : " << nbvre << std::endl;
+          Trace("sygus-pbe-cterm")
+              << "   PBE-cterm : and is not in output : " << out << std::endl;
+        }
+        return true;
+      }
+      Trace("sygus-pbe-cterm-debug2")
+          << "...check failed, rewrites to : " << contr << std::endl;
+    }
+  }
+  return false;
+}
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/sygus/sygus_invariance.h b/src/theory/quantifiers/sygus/sygus_invariance.h
new file mode 100644 (file)
index 0000000..a43e387
--- /dev/null
@@ -0,0 +1,276 @@
+/*********************                                                        */
+/*! \file sygus_invariance.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief sygus invariance tests
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_INVARIANCE_H
+#define __CVC4__THEORY__QUANTIFIERS__SYGUS_INVARIANCE_H
+
+#include <unordered_map>
+#include <vector>
+
+#include "expr/node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class TermDbSygus;
+class CegConjecture;
+
+/* SygusInvarianceTest
+*
+* This class is the standard interface for term generalization
+* in SyGuS. Its interface is a single function is_variant,
+* which is a virtual condition for SyGuS terms.
+*
+* The common use case of invariance tests is when constructing
+* minimal explanations for refinement lemmas in the
+* counterexample-guided inductive synthesis (CEGIS) loop.
+* See sygus_explain.h for more details.
+*/
+class SygusInvarianceTest
+{
+ public:
+  virtual ~SygusInvarianceTest() {}
+
+  /** Is nvn invariant with respect to this test ?
+   *
+   * - nvn is the term to check whether it is invariant.
+   * - x is a variable such that the previous call to
+   *   is_invariant (if any) was with term nvn_prev, and
+   *   nvn is equal to nvn_prev with some subterm
+   *   position replaced by x. This is typically used
+   *   for debugging only.
+   */
+  bool is_invariant(TermDbSygus* tds, Node nvn, Node x)
+  {
+    if (invariant(tds, nvn, x))
+    {
+      d_update_nvn = nvn;
+      return true;
+    }
+    return false;
+  }
+  /** get updated term */
+  Node getUpdatedTerm() { return d_update_nvn; }
+  /** set updated term */
+  void setUpdatedTerm(Node n) { d_update_nvn = n; }
+ protected:
+  /** result of the node that satisfies this invariant */
+  Node d_update_nvn;
+  /** check whether nvn[ x ] is invariant */
+  virtual bool invariant(TermDbSygus* tds, Node nvn, Node x) = 0;
+};
+
+/** EquivSygusInvarianceTest
+*
+* This class tests whether a term evaluates via evaluation
+* operators in the deep embedding (Section 4 of Reynolds
+* et al. CAV 2015) to fixed term d_result.
+*
+* For example, consider a SyGuS evaluation function eval
+* for a synthesis conjecture with arguments x and y.
+* Notice that the term t = (mult x y) is such that:
+*   eval( t, 0, 1 ) ----> 0
+* This test is invariant on the content of the second
+* argument of t, noting that:
+*   eval( (mult x _), 0, 1 ) ----> 0
+* as well, via a call to EvalSygusInvarianceTest::invariant.
+*
+* Another example, t = ite( gt( x, y ), x, y ) is such that:
+*   eval( t, 2, 3 ) ----> 3
+* This test is invariant on the second child of t, noting:
+*   eval( ite( gt( x, y ), _, y ), 2, 3 ) ----> 3
+*/
+class EvalSygusInvarianceTest : public SygusInvarianceTest
+{
+ public:
+  EvalSygusInvarianceTest() {}
+
+  /** initialize this invariance test
+    * This sets d_conj/d_var/d_result, where
+    * we are checking whether:
+    *   d_conj { d_var -> n } ----> d_result.
+    * for terms n.
+    */
+  void init(Node conj, Node var, Node res);
+
+  /** do evaluate with unfolding, using the cache of this class */
+  Node doEvaluateWithUnfolding(TermDbSygus* tds, Node n);
+
+ protected:
+  /** does d_conj{ d_var -> nvn } still rewrite to d_result? */
+  bool invariant(TermDbSygus* tds, Node nvn, Node x);
+
+ private:
+  /** the formula we are evaluating */
+  Node d_conj;
+  /** the variable */
+  TNode d_var;
+  /** the result of the evaluation */
+  Node d_result;
+  /** cache of n -> the simplified form of eval( n ) */
+  std::unordered_map<Node, Node, NodeHashFunction> d_visited;
+};
+
+/** EquivSygusInvarianceTest
+*
+* This class tests whether a builtin version of a
+* sygus term is equivalent up to rewriting to a RHS value bvr.
+*
+* For example,
+*
+* ite( t>0, 0, 0 ) + s*0 ----> 0
+*
+* This test is invariant on the condition t>0 and s, since:
+*
+* ite( _, 0, 0 ) + _*0 ----> 0
+*
+* for any values of _.
+*
+* It also manages the case where the rewriting is invariant
+* wrt a finite set of examples occurring in the conjecture.
+* (EX1) : For example if our input examples are:
+* (x,y,z) = (3,2,4), (5,2,6), (3,2,1)
+* On these examples, we have:
+*
+* ite( x>y, z, 0) ---> 4,6,1
+*
+* which is invariant on the second argument:
+*
+* ite( x>y, z, _) ---> 4,6,1
+*
+* For details, see Reynolds et al SYNT 2017.
+*/
+class EquivSygusInvarianceTest : public SygusInvarianceTest
+{
+ public:
+  EquivSygusInvarianceTest() : d_conj(nullptr) {}
+
+  /** initialize this invariance test
+   * tn is the sygus type for e
+   * aconj/e are used for conjecture-specific symmetry breaking
+   * bvr is the builtin version of the right hand side of the rewrite that we
+   * are checking for invariance
+   */
+  void init(
+      TermDbSygus* tds, TypeNode tn, CegConjecture* aconj, Node e, Node bvr);
+
+ protected:
+  /** checks whether the analog of nvn still rewrites to d_bvr */
+  bool invariant(TermDbSygus* tds, Node nvn, Node x);
+
+ private:
+  /** the conjecture associated with the enumerator d_enum */
+  CegConjecture* d_conj;
+  /** the enumerator associated with the term for which this test is for */
+  Node d_enum;
+  /** the RHS of the evaluation */
+  Node d_bvr;
+  /** the result of the examples
+   * In (EX1), this is (4,6,1)
+   */
+  std::vector<Node> d_exo;
+};
+
+/** DivByZeroSygusInvarianceTest
+ *
+ * This class tests whether a sygus term involves
+ * division by zero.
+ *
+ * For example the test for:
+ *    ( x + ( y/0 )*2 )
+ * is invariant on the contents of _ below:
+ *    ( _ + ( _/0 )*_ )
+ */
+class DivByZeroSygusInvarianceTest : public SygusInvarianceTest
+{
+ public:
+  DivByZeroSygusInvarianceTest() {}
+
+ protected:
+  /** checks whether nvn involves division by zero. */
+  bool invariant(TermDbSygus* tds, Node nvn, Node x);
+};
+
+/** NegContainsSygusInvarianceTest
+*
+* This class is used to construct a minimal shape of a term that cannot
+* be contained in at least one output of an I/O pair.
+*
+* Say our PBE conjecture is:
+*
+* exists f.
+*   f( "abc" ) = "abc abc" ^
+*   f( "de" ) = "de de"
+*
+* Then, this class is used when there is a candidate solution t[x1]
+* such that either:
+*   contains( "abc abc", t["abc"] ) ---> false or
+*   contains( "de de", t["de"] ) ---> false
+*
+* It is used to determine whether certain generalizations of t[x1]
+* are still sufficient to falsify one of the above containments.
+*
+* For example:
+*
+* The test for str.++( x1, "d" ) is invariant on its first argument
+*   ...since contains( "abc abc", str.++( _, "d" ) ) ---> false
+* The test for str.replace( "de", x1, "b" ) is invariant on its third argument
+*   ...since contains( "abc abc", str.replace( "de", "abc", _ ) ) ---> false
+*/
+class NegContainsSygusInvarianceTest : public SygusInvarianceTest
+{
+ public:
+  NegContainsSygusInvarianceTest() : d_conj(nullptr) {}
+
+  /** initialize this invariance test
+   *  cpbe is the conjecture utility.
+   *  e is the enumerator which we are reasoning about (associated with a synth
+   *    fun).
+   *  exo is the list of outputs of the PBE conjecture.
+   *  ncind is the set of possible indices of the PBE conjecture to check
+   *    invariance of non-containment.
+   *    For example, in the above example, when t[x1] = "ab", then this
+   *    has the index 1 since contains("de de", "ab") ---> false but not
+   *    the index 0 since contains("abc abc","ab") ---> true.
+   */
+  void init(CegConjecture* conj,
+            Node e,
+            std::vector<Node>& exo,
+            std::vector<unsigned>& ncind);
+
+ protected:
+  /** checks if contains( out_i, nvn[in_i] ) --> false for some I/O pair i. */
+  bool invariant(TermDbSygus* tds, Node nvn, Node x);
+
+ private:
+  /** The enumerator whose value we are considering in this invariance test */
+  Node d_enum;
+  /** The output examples for the enumerator */
+  std::vector<Node> d_exo;
+  /** The set of I/O pair indices i such that
+   *    contains( out_i, nvn[in_i] ) ---> false
+   */
+  std::vector<unsigned> d_neg_con_indices;
+  /** reference to the conjecture associated with this test */
+  CegConjecture* d_conj;
+};
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__SYGUS_INVARIANCE_H */
diff --git a/src/theory/quantifiers/sygus/sygus_pbe.cpp b/src/theory/quantifiers/sygus/sygus_pbe.cpp
new file mode 100644 (file)
index 0000000..17c4c48
--- /dev/null
@@ -0,0 +1,2460 @@
+/*********************                                                        */
+/*! \file ce_guided_pbe.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief utility for processing programming by examples synthesis conjectures
+ **
+ **/
+#include "theory/quantifiers/sygus/sygus_pbe.h"
+
+#include "expr/datatype.h"
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/datatypes/datatypes_rewriter.h"
+#include "util/random.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+void indent( const char * c, int ind ) {
+  if( Trace.isOn(c) ){
+    for( int i=0; i<ind; i++ ){ 
+      Trace(c) << "  "; 
+    }
+  } 
+}
+
+void print_val( const char * c, std::vector< Node >& vals, bool pol = true ){
+  if( Trace.isOn(c) ){
+    for( unsigned i=0; i<vals.size(); i++ ){
+      //Trace(c) << ( pol ? vals[i] : !vals[i] );
+      Trace(c) << ( ( pol ? vals[i].getConst<bool>() : !vals[i].getConst<bool>() ) ? "1" : "0" );
+    }
+  }
+}
+
+std::ostream& operator<<(std::ostream& os, EnumRole r)
+{
+  switch(r){
+    case enum_invalid: os << "INVALID"; break;
+    case enum_io: os << "IO"; break;
+    case enum_ite_condition: os << "CONDITION"; break;
+    case enum_concat_term: os << "CTERM"; break;
+    default: os << "enum_" << static_cast<unsigned>(r); break;
+  }
+  return os;
+}
+
+std::ostream& operator<<(std::ostream& os, NodeRole r)
+{
+  switch (r)
+  {
+    case role_equal: os << "equal"; break;
+    case role_string_prefix: os << "string_prefix"; break;
+    case role_string_suffix: os << "string_suffix"; break;
+    case role_ite_condition: os << "ite_condition"; break;
+    default: os << "role_" << static_cast<unsigned>(r); break;
+  }
+  return os;
+}
+
+EnumRole getEnumeratorRoleForNodeRole(NodeRole r)
+{
+  switch (r)
+  {
+    case role_equal: return enum_io; break;
+    case role_string_prefix: return enum_concat_term; break;
+    case role_string_suffix: return enum_concat_term; break;
+    case role_ite_condition: return enum_ite_condition; break;
+    default: break;
+  }
+  return enum_invalid;
+}
+
+std::ostream& operator<<(std::ostream& os, StrategyType st)
+{
+  switch (st)
+  {
+    case strat_ITE: os << "ITE"; break;
+    case strat_CONCAT_PREFIX: os << "CONCAT_PREFIX"; break;
+    case strat_CONCAT_SUFFIX: os << "CONCAT_SUFFIX"; break;
+    case strat_ID: os << "ID"; break;
+    default: os << "strat_" << static_cast<unsigned>(st); break;
+  }
+  return os;
+}
+
+CegConjecturePbe::CegConjecturePbe(QuantifiersEngine* qe, CegConjecture* p)
+    : d_qe(qe),
+      d_parent(p){
+  d_tds = d_qe->getTermDatabaseSygus();
+  d_true = NodeManager::currentNM()->mkConst(true);
+  d_false = NodeManager::currentNM()->mkConst(false);
+  d_is_pbe = false;
+}
+
+CegConjecturePbe::~CegConjecturePbe() {
+
+}
+
+//--------------------------------- collecting finite input/output domain information
+
+void CegConjecturePbe::collectExamples( Node n, std::map< Node, bool >& visited, bool hasPol, bool pol ) {
+  if( visited.find( n )==visited.end() ){
+    visited[n] = true;
+    Node neval;
+    Node n_output;
+    if( n.getKind()==APPLY_UF && n.getNumChildren()>0 ){
+      neval = n;
+      if( hasPol ){
+        n_output = !pol ? d_true : d_false;
+      }
+    }else if( n.getKind()==EQUAL && hasPol && !pol ){
+      for( unsigned r=0; r<2; r++ ){
+        if( n[r].getKind()==APPLY_UF && n[r].getNumChildren()>0 ){
+          neval = n[r];
+          if( n[1-r].isConst() ){
+            n_output = n[1-r];
+          }
+        }
+      }
+    }
+    if( !neval.isNull() ){
+      if( neval.getKind()==APPLY_UF && neval.getNumChildren()>0 ){
+        // is it an evaluation function?
+        if( d_examples.find( neval[0] )!=d_examples.end() ){
+          std::map< Node, bool >::iterator itx = d_examples_invalid.find( neval[0] );
+          if( itx==d_examples_invalid.end() ){
+            //collect example
+            bool success = true;
+            std::vector< Node > ex;
+            for( unsigned j=1; j<neval.getNumChildren(); j++ ){
+              if( !neval[j].isConst() ){
+                success = false;
+                break;
+              }else{
+                ex.push_back( neval[j] );
+              }
+            }
+            if( success ){
+              d_examples[neval[0]].push_back( ex );
+              d_examples_out[neval[0]].push_back( n_output );
+              d_examples_term[neval[0]].push_back( neval );
+              if( n_output.isNull() ){
+                d_examples_out_invalid[neval[0]] = true;
+              }else{
+                Assert( n_output.isConst() );
+              }
+              //finished processing this node
+              return;
+            }else{
+              d_examples_invalid[neval[0]] = true;
+              d_examples_out_invalid[neval[0]] = true;
+            }
+          }
+        }
+      }
+    }
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      bool newHasPol;
+      bool newPol;
+      QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
+      collectExamples( n[i], visited, newHasPol, newPol );
+    }
+  }
+}
+
+void CegConjecturePbe::initialize(Node n,
+                                  std::vector<Node>& candidates,
+                                  std::vector<Node>& lemmas)
+{
+  Trace("sygus-pbe") << "Initialize PBE : " << n << std::endl;
+  
+  for( unsigned i=0; i<candidates.size(); i++ ){
+    Node v = candidates[i];
+    d_examples[v].clear();
+    d_examples_out[v].clear();
+    d_examples_term[v].clear();
+  }
+  
+  std::map< Node, bool > visited;
+  collectExamples( n, visited, true, true );
+  
+  for( unsigned i=0; i<candidates.size(); i++ ){
+    Node v = candidates[i];
+    Trace("sygus-pbe") << "  examples for " << v << " : ";
+    if( d_examples_invalid.find( v )!=d_examples_invalid.end() ){
+      Trace("sygus-pbe") << "INVALID" << std::endl;
+    }else{
+      Trace("sygus-pbe") << std::endl;
+      for( unsigned j=0; j<d_examples[v].size(); j++ ){
+        Trace("sygus-pbe") << "    ";
+        for( unsigned k=0; k<d_examples[v][j].size(); k++ ){
+          Trace("sygus-pbe") << d_examples[v][j][k] << " ";
+        }
+        if( !d_examples_out[v][j].isNull() ){
+          Trace("sygus-pbe") << " -> " << d_examples_out[v][j];
+        }
+        Trace("sygus-pbe") << std::endl;
+      }
+    }
+  }
+  
+  //register candidates
+  if( options::sygusUnifCondSol() ){
+    if( candidates.size()==1 ){// conditional solutions for multiple function conjectures TODO?
+      // collect a pool of types over which we will enumerate terms 
+      Node c = candidates[0];
+      //the candidate must be input/output examples
+      if( d_examples_out_invalid.find( c )==d_examples_out_invalid.end() ){
+        Assert( d_examples.find( c )!=d_examples.end() );
+        Trace("sygus-unif") << "It is input/output examples..." << std::endl;
+        TypeNode ctn = c.getType();
+        d_cinfo[c].initialize( c );
+        // collect the enumerator types / form the strategy
+        collectEnumeratorTypes(c, ctn, role_equal);
+        // if we have non-trivial strategies, then use pbe
+        if( d_cinfo[c].isNonTrivial() ){
+          // static learning of redundant constructors
+          staticLearnRedundantOps( c, lemmas );
+          d_is_pbe = true;
+        }
+      }
+    }
+  }
+  if( !d_is_pbe ){
+    Trace("sygus-unif") << "Do not do PBE optimizations, register..." << std::endl;
+    for( unsigned i=0; i<candidates.size(); i++ ){
+      d_qe->getTermDatabaseSygus()->registerEnumerator(
+          candidates[i], candidates[i], d_parent);
+    }
+  }
+}
+
+Node CegConjecturePbe::PbeTrie::addPbeExample(TypeNode etn, Node e, Node b,
+                                              CegConjecturePbe* cpbe,
+                                              unsigned index, unsigned ntotal) {
+  if (index == ntotal) {
+    // lazy child holds the leaf data
+    if (d_lazy_child.isNull()) {
+      d_lazy_child = b;
+    }
+    return d_lazy_child;
+  } else {
+    std::vector<Node> ex;
+    if (d_children.empty()) {
+      if (d_lazy_child.isNull()) {
+        d_lazy_child = b;
+        return d_lazy_child;
+      } else {
+        // evaluate the lazy child
+        Assert(cpbe->d_examples.find(e) != cpbe->d_examples.end());
+        Assert(index < cpbe->d_examples[e].size());
+        ex = cpbe->d_examples[e][index];
+        addPbeExampleEval(etn, e, d_lazy_child, ex, cpbe, index, ntotal);
+        Assert(!d_children.empty());
+        d_lazy_child = Node::null();
+      }
+    } else {
+      Assert(cpbe->d_examples.find(e) != cpbe->d_examples.end());
+      Assert(index < cpbe->d_examples[e].size());
+      ex = cpbe->d_examples[e][index];
+    }
+    return addPbeExampleEval(etn, e, b, ex, cpbe, index, ntotal);
+  }
+}
+
+Node CegConjecturePbe::PbeTrie::addPbeExampleEval(TypeNode etn, Node e, Node b,
+                                                  std::vector<Node>& ex,
+                                                  CegConjecturePbe* cpbe,
+                                                  unsigned index,
+                                                  unsigned ntotal) {
+  Node eb = cpbe->d_tds->evaluateBuiltin(etn, b, ex);
+  return d_children[eb].addPbeExample(etn, e, b, cpbe, index + 1, ntotal);
+}
+
+bool CegConjecturePbe::hasExamples(Node e) {
+  if (isPbe()) {
+    e = d_tds->getSynthFunForEnumerator(e);
+    Assert(!e.isNull());
+    std::map<Node, bool>::iterator itx = d_examples_invalid.find(e);
+    if (itx == d_examples_invalid.end()) {
+      return d_examples.find(e) != d_examples.end();
+    }
+  }
+  return false;
+}
+
+unsigned CegConjecturePbe::getNumExamples(Node e) {
+  e = d_tds->getSynthFunForEnumerator(e);
+  Assert(!e.isNull());
+  std::map<Node, std::vector<std::vector<Node> > >::iterator it =
+      d_examples.find(e);
+  if (it != d_examples.end()) {
+    return it->second.size();
+  } else {
+    return 0;
+  }
+}
+
+void CegConjecturePbe::getExample(Node e, unsigned i, std::vector<Node>& ex) {
+  e = d_tds->getSynthFunForEnumerator(e);
+  Assert(!e.isNull());
+  std::map<Node, std::vector<std::vector<Node> > >::iterator it =
+      d_examples.find(e);
+  if (it != d_examples.end()) {
+    Assert(i < it->second.size());
+    ex.insert(ex.end(), it->second[i].begin(), it->second[i].end());
+  } else {
+    Assert(false);
+  }
+}
+
+Node CegConjecturePbe::getExampleOut(Node e, unsigned i) {
+  e = d_tds->getSynthFunForEnumerator(e);
+  Assert(!e.isNull());
+  std::map<Node, std::vector<Node> >::iterator it = d_examples_out.find(e);
+  if (it != d_examples_out.end()) {
+    Assert(i < it->second.size());
+    return it->second[i];
+  } else {
+    Assert(false);
+    return Node::null();
+  }
+}
+
+Node CegConjecturePbe::addSearchVal(TypeNode tn, Node e, Node bvr) {
+  Assert(isPbe());
+  Assert(!e.isNull());
+  e = d_tds->getSynthFunForEnumerator(e);
+  Assert(!e.isNull());
+  std::map<Node, bool>::iterator itx = d_examples_invalid.find(e);
+  if (itx == d_examples_invalid.end()) {
+    unsigned nex = d_examples[e].size();
+    Node ret = d_pbe_trie[e][tn].addPbeExample(tn, e, bvr, this, 0, nex);
+    Assert(ret.getType() == bvr.getType());
+    return ret;
+  }
+  return Node::null();
+}
+
+Node CegConjecturePbe::evaluateBuiltin(TypeNode tn, Node bn, Node e,
+                                       unsigned i) {
+  e = d_tds->getSynthFunForEnumerator(e);
+  Assert(!e.isNull());
+  std::map<Node, bool>::iterator itx = d_examples_invalid.find(e);
+  if (itx == d_examples_invalid.end()) {
+    std::map<Node, std::vector<std::vector<Node> > >::iterator it =
+        d_examples.find(e);
+    if (it != d_examples.end()) {
+      Assert(i < it->second.size());
+      return d_tds->evaluateBuiltin(tn, bn, it->second[i]);
+    }
+  }
+  return Rewriter::rewrite(bn);
+}
+
+// ----------------------------- establishing enumeration types
+
+void CegConjecturePbe::registerEnumerator(
+    Node et, Node c, TypeNode tn, EnumRole enum_role, bool inSearch)
+{
+  if (d_einfo.find(et) == d_einfo.end())
+  {
+    Trace("sygus-unif-debug")
+        << "...register " << et << " for "
+        << ((DatatypeType)tn.toType()).getDatatype().getName();
+    Trace("sygus-unif-debug") << ", role = " << enum_role
+                              << ", in search = " << inSearch << std::endl;
+    d_einfo[et].initialize(c, enum_role);
+    // if we are actually enumerating this (could be a compound node in the
+    // strategy)
+    if (inSearch)
+    {
+      std::map<TypeNode, Node>::iterator itn =
+          d_cinfo[c].d_search_enum.find(tn);
+      if (itn == d_cinfo[c].d_search_enum.end())
+      {
+        // use this for the search
+        d_cinfo[c].d_search_enum[tn] = et;
+        d_cinfo[c].d_esym_list.push_back(et);
+        d_einfo[et].d_enum_slave.push_back(et);
+        // register measured term with database
+        d_qe->getTermDatabaseSygus()->registerEnumerator(et, c, d_parent, true);
+        d_einfo[et].d_active_guard =
+            d_qe->getTermDatabaseSygus()->getActiveGuardForEnumerator(et);
+      }
+      else
+      {
+        Trace("sygus-unif-debug") << "Make " << et << " a slave of "
+                                  << itn->second << std::endl;
+        d_einfo[itn->second].d_enum_slave.push_back(et);
+      }
+    }
+  }
+}
+
+void CegConjecturePbe::collectEnumeratorTypes(Node e,
+                                              TypeNode tn,
+                                              NodeRole nrole)
+{
+  NodeManager* nm = NodeManager::currentNM();
+  if (d_cinfo[e].d_tinfo.find(tn) == d_cinfo[e].d_tinfo.end())
+  {
+    // register type
+    Trace("sygus-unif") << "Register enumerating type : " << tn << std::endl;
+    d_cinfo[e].initializeType( tn );
+  }
+  EnumTypeInfo& eti = d_cinfo[e].d_tinfo[tn];
+  std::map<NodeRole, StrategyNode>::iterator itsn = eti.d_snodes.find(nrole);
+  if (itsn != eti.d_snodes.end())
+  {
+    // already initialized
+    return;
+  }
+  StrategyNode& snode = eti.d_snodes[nrole];
+
+  // get the enumerator for this
+  EnumRole erole = getEnumeratorRoleForNodeRole(nrole);
+
+  Node ee;
+  std::map<EnumRole, Node>::iterator iten = eti.d_enum.find(erole);
+  if (iten == eti.d_enum.end())
+  {
+    ee = nm->mkSkolem("ee", tn);
+    eti.d_enum[erole] = ee;
+    Trace("sygus-unif-debug")
+        << "...enumerator " << ee << " for "
+        << ((DatatypeType)tn.toType()).getDatatype().getName()
+        << ", role = " << erole << std::endl;
+  }
+  else
+  {
+    ee = iten->second;
+  }
+
+  // roles that we do not recurse on
+  if (nrole == role_ite_condition)
+  {
+    Trace("sygus-unif-debug") << "...this register (non-io)" << std::endl;
+    registerEnumerator(ee, e, tn, erole, true);
+    return;
+  }
+
+  // look at information on how we will construct solutions for this type
+  Assert(tn.isDatatype());
+  const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
+  Assert(dt.isSygus());
+
+  std::map<Node, std::vector<StrategyType> > cop_to_strat;
+  std::map<Node, unsigned> cop_to_cindex;
+  std::map<Node, std::map<unsigned, Node> > cop_to_child_templ;
+  std::map<Node, std::map<unsigned, Node> > cop_to_child_templ_arg;
+  std::map<Node, std::vector<unsigned> > cop_to_carg_list;
+  std::map<Node, std::vector<TypeNode> > cop_to_child_types;
+  std::map<Node, std::vector<Node> > cop_to_sks;
+
+  // whether we will enumerate the current type
+  bool search_this = false;
+  for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++)
+  {
+    Node cop = Node::fromExpr(dt[j].getConstructor());
+    Node op = Node::fromExpr(dt[j].getSygusOp());
+    Trace("sygus-unif-debug") << "--- Infer strategy from " << cop
+                              << " with sygus op " << op << "..." << std::endl;
+
+    // expand the evaluation to see if this constuctor induces a strategy
+    std::vector<Node> utchildren;
+    utchildren.push_back(cop);
+    std::vector<Node> sks;
+    std::vector<TypeNode> sktns;
+    for (unsigned k = 0, nargs = dt[j].getNumArgs(); k < nargs; k++)
+    {
+      Type t = dt[j][k].getRangeType();
+      TypeNode ttn = TypeNode::fromType(t);
+      Node kv = nm->mkSkolem("ut", ttn);
+      sks.push_back(kv);
+      cop_to_sks[cop].push_back(kv);
+      sktns.push_back(ttn);
+      utchildren.push_back(kv);
+    }
+    Node ut = nm->mkNode(APPLY_CONSTRUCTOR, utchildren);
+    std::vector<Node> echildren;
+    echildren.push_back(Node::fromExpr(dt.getSygusEvaluationFunc()));
+    echildren.push_back(ut);
+    Node sbvl = Node::fromExpr(dt.getSygusVarList());
+    for (const Node& sbv : sbvl)
+    {
+      echildren.push_back(sbv);
+    }
+    Node eut = nm->mkNode(APPLY_UF, echildren);
+    Trace("sygus-unif-debug2") << "  Test evaluation of " << eut << "..."
+                               << std::endl;
+    eut = d_qe->getTermDatabaseSygus()->unfold(eut);
+    Trace("sygus-unif-debug2") << "  ...got " << eut;
+    Trace("sygus-unif-debug2") << ", type : " << eut.getType() << std::endl;
+
+    // candidate strategy
+    if (eut.getKind() == ITE)
+    {
+      cop_to_strat[cop].push_back(strat_ITE);
+    }
+    else if (eut.getKind() == STRING_CONCAT)
+    {
+      if (nrole != role_string_suffix)
+      {
+        cop_to_strat[cop].push_back(strat_CONCAT_PREFIX);
+      }
+      if (nrole != role_string_prefix)
+      {
+        cop_to_strat[cop].push_back(strat_CONCAT_SUFFIX);
+      }
+    }
+    else if (dt[j].isSygusIdFunc())
+    {
+      cop_to_strat[cop].push_back(strat_ID);
+    }
+
+    // the kinds for which there is a strategy
+    if (cop_to_strat.find(cop) != cop_to_strat.end())
+    {
+      // infer an injection from the arguments of the datatype
+      std::map<unsigned, unsigned> templ_injection;
+      std::vector<Node> vs;
+      std::vector<Node> ss;
+      std::map<Node, unsigned> templ_var_index;
+      for (unsigned k = 0, sksize = sks.size(); k < sksize; k++)
+      {
+        Assert(sks[k].getType().isDatatype());
+        const Datatype& cdt =
+            static_cast<DatatypeType>(sks[k].getType().toType()).getDatatype();
+        echildren[0] = Node::fromExpr(cdt.getSygusEvaluationFunc());
+        echildren[1] = sks[k];
+        Trace("sygus-unif-debug2") << "...set eval dt to " << sks[k]
+                                   << std::endl;
+        Node esk = nm->mkNode(APPLY_UF, echildren);
+        vs.push_back(esk);
+        Node tvar = nm->mkSkolem("templ", esk.getType());
+        templ_var_index[tvar] = k;
+        Trace("sygus-unif-debug2") << "* template inference : looking for "
+                                   << tvar << " for arg " << k << std::endl;
+        ss.push_back(tvar);
+        Trace("sygus-unif-debug2") << "* substitute : " << esk << " -> " << tvar
+                                   << std::endl;
+      }
+      eut = eut.substitute(vs.begin(), vs.end(), ss.begin(), ss.end());
+      Trace("sygus-unif-debug2") << "Constructor " << j << ", base term is "
+                                 << eut << std::endl;
+      std::map<unsigned, Node> test_args;
+      if (dt[j].isSygusIdFunc())
+      {
+        test_args[0] = eut;
+      }
+      else
+      {
+        for (unsigned k = 0, size = eut.getNumChildren(); k < size; k++)
+        {
+          test_args[k] = eut[k];
+        }
+      }
+
+      // TODO : prefix grouping prefix/suffix
+      bool isAssoc = TermUtil::isAssoc(eut.getKind());
+      Trace("sygus-unif-debug2") << eut.getKind() << " isAssoc = " << isAssoc
+                                 << std::endl;
+      std::map<unsigned, std::vector<unsigned> > assoc_combine;
+      std::vector<unsigned> assoc_waiting;
+      int assoc_last_valid_index = -1;
+      for (std::pair<const unsigned, Node>& ta : test_args)
+      {
+        unsigned k = ta.first;
+        Node eut_c = ta.second;
+        // success if we can find a injection from args to sygus args
+        if (!inferTemplate(k, eut_c, templ_var_index, templ_injection))
+        {
+          Trace("sygus-unif-debug")
+              << "...fail: could not find injection (range)." << std::endl;
+          cop_to_strat.erase(cop);
+          break;
+        }
+        std::map<unsigned, unsigned>::iterator itti = templ_injection.find(k);
+        if (itti != templ_injection.end())
+        {
+          // if associative, combine arguments if it is the same variable
+          if (isAssoc && assoc_last_valid_index >= 0
+              && itti->second == templ_injection[assoc_last_valid_index])
+          {
+            templ_injection.erase(k);
+            assoc_combine[assoc_last_valid_index].push_back(k);
+          }
+          else
+          {
+            assoc_last_valid_index = (int)k;
+            if (!assoc_waiting.empty())
+            {
+              assoc_combine[k].insert(assoc_combine[k].end(),
+                                      assoc_waiting.begin(),
+                                      assoc_waiting.end());
+              assoc_waiting.clear();
+            }
+            assoc_combine[k].push_back(k);
+          }
+        }
+        else
+        {
+          // a ground argument
+          if (!isAssoc)
+          {
+            Trace("sygus-unif-debug")
+                << "...fail: could not find injection (functional)."
+                << std::endl;
+            cop_to_strat.erase(cop);
+            break;
+          }
+          else
+          {
+            if (assoc_last_valid_index >= 0)
+            {
+              assoc_combine[assoc_last_valid_index].push_back(k);
+            }
+            else
+            {
+              assoc_waiting.push_back(k);
+            }
+          }
+        }
+      }
+      if (cop_to_strat.find(cop) != cop_to_strat.end())
+      {
+        // construct the templates
+        if (!assoc_waiting.empty())
+        {
+          // could not find a way to fit some arguments into injection
+          cop_to_strat.erase(cop);
+        }
+        else
+        {
+          for (std::pair<const unsigned, Node>& ta : test_args)
+          {
+            unsigned k = ta.first;
+            Trace("sygus-unif-debug2") << "- processing argument " << k << "..."
+                                       << std::endl;
+            if (templ_injection.find(k) != templ_injection.end())
+            {
+              unsigned sk_index = templ_injection[k];
+              if (std::find(cop_to_carg_list[cop].begin(),
+                            cop_to_carg_list[cop].end(),
+                            sk_index)
+                  == cop_to_carg_list[cop].end())
+              {
+                cop_to_carg_list[cop].push_back(sk_index);
+              }else{
+                Trace("sygus-unif-debug") << "...fail: duplicate argument used"
+                                          << std::endl;
+                cop_to_strat.erase(cop);
+                break;
+              }
+              // also store the template information, if necessary
+              Node teut;
+              if (isAssoc)
+              {
+                std::vector<unsigned>& ac = assoc_combine[k];
+                Assert(!ac.empty());
+                std::vector<Node> children;
+                for (unsigned ack = 0, size_ac = ac.size(); ack < size_ac;
+                     ack++)
+                {
+                  children.push_back(eut[ac[ack]]);
+                }
+                teut = children.size() == 1
+                           ? children[0]
+                           : nm->mkNode(eut.getKind(), children);
+                teut = Rewriter::rewrite(teut);
+              }
+              else
+              {
+                teut = ta.second;
+              }
+
+              if (!teut.isVar())
+              {
+                cop_to_child_templ[cop][k] = teut;
+                cop_to_child_templ_arg[cop][k] = ss[sk_index];
+                Trace("sygus-unif-debug")
+                    << "  Arg " << k << " (template : " << teut << " arg "
+                    << ss[sk_index] << "), index " << sk_index << std::endl;
+              }
+              else
+              {
+                Trace("sygus-unif-debug") << "  Arg " << k << ", index "
+                                          << sk_index << std::endl;
+                Assert(teut == ss[sk_index]);
+              }
+            }
+            else
+            {
+              Assert(isAssoc);
+            }
+          }
+        }
+      }
+    }
+    if (cop_to_strat.find(cop) == cop_to_strat.end())
+    {
+      Trace("sygus-unif") << "...constructor " << cop
+                          << " does not correspond to a strategy." << std::endl;
+      search_this = true;
+    }
+    else
+    {
+      Trace("sygus-unif") << "-> constructor " << cop
+                          << " matches strategy for " << eut.getKind() << "..."
+                          << std::endl;
+      // collect children types
+      for (unsigned k = 0, size = cop_to_carg_list[cop].size(); k < size; k++)
+      {
+        TypeNode tn = sktns[cop_to_carg_list[cop][k]];
+        Trace("sygus-unif-debug")
+            << "   Child type " << k << " : "
+            << static_cast<DatatypeType>(tn.toType()).getDatatype().getName()
+            << std::endl;
+        cop_to_child_types[cop].push_back(tn);
+      }
+    }
+  }
+
+  // check whether we should also enumerate the current type
+  Trace("sygus-unif-debug2") << "  register this enumerator..." << std::endl;
+  registerEnumerator(ee, e, tn, erole, search_this);
+
+  if (cop_to_strat.empty())
+  {
+    Trace("sygus-unif") << "...consider " << dt.getName() << " a basic type"
+                        << std::endl;
+  }
+  else
+  {
+    for (std::pair<const Node, std::vector<StrategyType> >& cstr : cop_to_strat)
+    {
+      Node cop = cstr.first;
+      Trace("sygus-unif-debug") << "Constructor " << cop << " has "
+                                << cstr.second.size() << " strategies..."
+                                << std::endl;
+      for (unsigned s = 0, ssize = cstr.second.size(); s < ssize; s++)
+      {
+        EnumTypeInfoStrat* cons_strat = new EnumTypeInfoStrat;
+        StrategyType strat = cstr.second[s];
+
+        cons_strat->d_this = strat;
+        cons_strat->d_cons = cop;
+        Trace("sygus-unif-debug") << "Process strategy #" << s
+                                  << " for operator : " << cop << " : " << strat
+                                  << std::endl;
+        Assert(cop_to_child_types.find(cop) != cop_to_child_types.end());
+        std::vector<TypeNode>& childTypes = cop_to_child_types[cop];
+        Assert(cop_to_carg_list.find(cop) != cop_to_carg_list.end());
+        std::vector<unsigned>& cargList = cop_to_carg_list[cop];
+
+        std::vector<Node> sol_templ_children;
+        sol_templ_children.resize(cop_to_sks[cop].size());
+
+        for (unsigned j = 0, csize = childTypes.size(); j < csize; j++)
+        {
+          // calculate if we should allocate a new enumerator : should be true
+          // if we have a new role
+          NodeRole nrole_c = nrole;
+          if (strat == strat_ITE)
+          {
+            if (j == 0)
+            {
+              nrole_c = role_ite_condition;
+            }
+          }
+          else if (strat == strat_CONCAT_PREFIX)
+          {
+            if ((j + 1) < childTypes.size())
+            {
+              nrole_c = role_string_prefix;
+            }
+          }
+          else if (strat == strat_CONCAT_SUFFIX)
+          {
+            if (j > 0)
+            {
+              nrole_c = role_string_suffix;
+            }
+          }
+          // in all other cases, role is same as parent
+
+          // register the child type
+          TypeNode ct = childTypes[j];
+          Node csk = cop_to_sks[cop][cargList[j]];
+          cons_strat->d_sol_templ_args.push_back(csk);
+          sol_templ_children[cargList[j]] = csk;
+
+          EnumRole erole_c = getEnumeratorRoleForNodeRole(nrole_c);
+          // make the enumerator
+          Node et;
+          if (cop_to_child_templ[cop].find(j) != cop_to_child_templ[cop].end())
+          {
+            // it is templated, allocate a fresh variable
+            et = nm->mkSkolem("et", ct);
+            Trace("sygus-unif-debug")
+                << "...enumerate " << et << " of type "
+                << ((DatatypeType)ct.toType()).getDatatype().getName();
+            Trace("sygus-unif-debug")
+                << " for arg " << j << " of "
+                << ((DatatypeType)tn.toType()).getDatatype().getName()
+                << std::endl;
+            registerEnumerator(et, e, ct, erole_c, true);
+            d_einfo[et].d_template = cop_to_child_templ[cop][j];
+            d_einfo[et].d_template_arg = cop_to_child_templ_arg[cop][j];
+            Assert(!d_einfo[et].d_template.isNull());
+            Assert(!d_einfo[et].d_template_arg.isNull());
+          }
+          else
+          {
+            Trace("sygus-unif-debug")
+                << "...child type enumerate "
+                << ((DatatypeType)ct.toType()).getDatatype().getName()
+                << ", node role = " << nrole_c << std::endl;
+            collectEnumeratorTypes(e, ct, nrole_c);
+            // otherwise use the previous
+            Assert(d_cinfo[e].d_tinfo[ct].d_enum.find(erole_c)
+                   != d_cinfo[e].d_tinfo[ct].d_enum.end());
+            et = d_cinfo[e].d_tinfo[ct].d_enum[erole_c];
+          }
+          Trace("sygus-unif-debug") << "Register child enumerator " << et
+                                    << ", arg " << j << " of " << cop
+                                    << ", role = " << erole_c << std::endl;
+          Assert(!et.isNull());
+          cons_strat->d_cenum.push_back(std::pair<Node, NodeRole>(et, nrole_c));
+        }
+        // children that are unused in the strategy can be arbitrary
+        for (unsigned j = 0, stsize = sol_templ_children.size(); j < stsize;
+             j++)
+        {
+          if (sol_templ_children[j].isNull())
+          {
+            sol_templ_children[j] = cop_to_sks[cop][j].getType().mkGroundTerm();
+          }
+        }
+        sol_templ_children.insert(sol_templ_children.begin(), cop);
+        cons_strat->d_sol_templ =
+            nm->mkNode(APPLY_CONSTRUCTOR, sol_templ_children);
+        if (strat == strat_CONCAT_SUFFIX)
+        {
+          std::reverse(cons_strat->d_cenum.begin(), cons_strat->d_cenum.end());
+          std::reverse(cons_strat->d_sol_templ_args.begin(),
+                       cons_strat->d_sol_templ_args.end());
+        }
+        if (Trace.isOn("sygus-unif"))
+        {
+          Trace("sygus-unif") << "Initialized strategy " << strat;
+          Trace("sygus-unif") << " for " << ((DatatypeType)tn.toType()).getDatatype().getName() << ", operator " << cop;
+          Trace("sygus-unif") << ", #children = " << cons_strat->d_cenum.size()
+                              << ", solution template = (lambda ( ";
+          for (const Node& targ : cons_strat->d_sol_templ_args)
+          {
+            Trace("sygus-unif") << targ << " ";
+          }
+          Trace("sygus-unif") << ") " << cons_strat->d_sol_templ << ")";
+          Trace("sygus-unif") << std::endl;
+        }
+        // make the strategy
+        snode.d_strats.push_back(cons_strat);
+      }
+    }
+  }
+}
+
+bool CegConjecturePbe::inferTemplate( unsigned k, Node n, std::map< Node, unsigned >& templ_var_index, std::map< unsigned, unsigned >& templ_injection ){
+  if( n.getNumChildren()==0 ){
+    std::map< Node, unsigned >::iterator itt = templ_var_index.find( n );
+    if( itt!=templ_var_index.end() ){
+      unsigned kk = itt->second;
+      std::map< unsigned, unsigned >::iterator itti = templ_injection.find( k );
+      if( itti==templ_injection.end() ){
+        Trace("sygus-unif-debug") << "...set template injection " << k <<  " -> " << kk << std::endl;
+        templ_injection[k] = kk;
+      }else if( itti->second!=kk ){
+        // two distinct variables in this term, we fail
+        return false;
+      }
+    }
+    return true;
+  }else{
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      if( !inferTemplate( k, n[i], templ_var_index, templ_injection ) ){
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+void CegConjecturePbe::staticLearnRedundantOps( Node c, std::vector< Node >& lemmas ) {
+  for( unsigned i=0; i<d_cinfo[c].d_esym_list.size(); i++ ){
+    Node e = d_cinfo[c].d_esym_list[i];
+    std::map< Node, EnumInfo >::iterator itn = d_einfo.find( e );
+    Assert( itn!=d_einfo.end() );
+    // see if there is anything we can eliminate
+    Trace("sygus-unif") << "* Search enumerator #" << i << " : type " << ((DatatypeType)e.getType().toType()).getDatatype().getName() << " : ";
+    Trace("sygus-unif") << e << " has " << itn->second.d_enum_slave.size() << " slaves:" << std::endl;
+    for( unsigned j=0; j<itn->second.d_enum_slave.size(); j++ ){
+      Node es = itn->second.d_enum_slave[j];
+      std::map< Node, EnumInfo >::iterator itns = d_einfo.find( es );
+      Assert( itns!=d_einfo.end() );
+      Trace("sygus-unif") << "  " << es << ", role = " << itns->second.getRole()
+                          << std::endl;
+    }
+  }
+  Trace("sygus-unif") << std::endl;
+  Trace("sygus-unif") << "Strategy for candidate " << c << " is : " << std::endl;
+  std::map<Node, std::map<NodeRole, bool> > visited;
+  std::map<Node, std::map<unsigned, bool> > needs_cons;
+  staticLearnRedundantOps(c,
+                          d_cinfo[c].getRootEnumerator(),
+                          role_equal,
+                          visited,
+                          needs_cons,
+                          0,
+                          false);
+  // now, check the needs_cons map
+  for (std::pair<const Node, std::map<unsigned, bool> >& nce : needs_cons)
+  {
+    Node em = nce.first;
+    const Datatype& dt =
+        static_cast<DatatypeType>(em.getType().toType()).getDatatype();
+    for (std::pair<const unsigned, bool>& nc : nce.second)
+    {
+      Assert(nc.first < dt.getNumConstructors());
+      if (!nc.second)
+      {
+        Node tst =
+            datatypes::DatatypesRewriter::mkTester(em, nc.first, dt).negate();
+        if (std::find(lemmas.begin(), lemmas.end(), tst) == lemmas.end())
+        {
+          Trace("sygus-unif") << "...can exclude based on  : " << tst
+                              << std::endl;
+          lemmas.push_back(tst);
+        }
+      }
+    }
+  }
+}
+
+void CegConjecturePbe::staticLearnRedundantOps(
+    Node c,
+    Node e,
+    NodeRole nrole,
+    std::map<Node, std::map<NodeRole, bool> >& visited,
+    std::map<Node, std::map<unsigned, bool> >& needs_cons,
+    int ind,
+    bool isCond)
+{
+  std::map< Node, EnumInfo >::iterator itn = d_einfo.find( e );
+  Assert( itn!=d_einfo.end() );
+
+  if (visited[e].find(nrole) == visited[e].end()
+      || (isCond && !itn->second.isConditional()))
+  {
+    visited[e][nrole] = true;
+    // if conditional
+    if (isCond)
+    {
+      itn->second.setConditional();
+    }
+    indent("sygus-unif", ind);
+    Trace("sygus-unif") << e << " :: node role : " << nrole;
+    Trace("sygus-unif")
+        << ", type : "
+        << ((DatatypeType)e.getType().toType()).getDatatype().getName();
+    if (isCond)
+    {
+      Trace("sygus-unif") << ", conditional";
+    }
+    Trace("sygus-unif") << ", enum role : " << itn->second.getRole();
+
+    if( itn->second.isTemplated() ){
+      Trace("sygus-unif") << ", templated : (lambda "
+                          << itn->second.d_template_arg << " "
+                          << itn->second.d_template << ")" << std::endl;
+    }else{
+      Trace("sygus-unif") << std::endl;
+      TypeNode etn = e.getType();
+
+      // enumerator type info
+      std::map< TypeNode, EnumTypeInfo >::iterator itt = d_cinfo[c].d_tinfo.find( etn );
+      Assert( itt!=d_cinfo[c].d_tinfo.end() );
+      EnumTypeInfo& tinfo = itt->second;
+
+      // strategy info
+      std::map<NodeRole, StrategyNode>::iterator itsn =
+          tinfo.d_snodes.find(nrole);
+      Assert(itsn != tinfo.d_snodes.end());
+      StrategyNode& snode = itsn->second;
+
+      if (snode.d_strats.empty())
+      {
+        return;
+      }
+      std::map<unsigned, bool> needs_cons_curr;
+      // various strategies
+      for (unsigned j = 0, size = snode.d_strats.size(); j < size; j++)
+      {
+        EnumTypeInfoStrat* etis = snode.d_strats[j];
+        StrategyType strat = etis->d_this;
+        bool newIsCond = isCond || strat == strat_ITE;
+        indent("sygus-unif", ind + 1);
+        Trace("sygus-unif") << "Strategy : " << strat
+                            << ", from cons : " << etis->d_cons << std::endl;
+        int cindex = Datatype::indexOf(etis->d_cons.toExpr());
+        Assert(cindex != -1);
+        needs_cons_curr[static_cast<unsigned>(cindex)] = false;
+        for (std::pair<Node, NodeRole>& cec : etis->d_cenum)
+        {
+          // recurse
+          staticLearnRedundantOps(c,
+                                  cec.first,
+                                  cec.second,
+                                  visited,
+                                  needs_cons,
+                                  ind + 2,
+                                  newIsCond);
+        }
+      }
+      // get the master enumerator for the type of this enumerator
+      std::map<TypeNode, Node>::iterator itse =
+          d_cinfo[c].d_search_enum.find(etn);
+      if (itse == d_cinfo[c].d_search_enum.end())
+      {
+        return;
+      }
+      Node em = itse->second;
+      Assert(!em.isNull());
+      // get the current datatype
+      const Datatype& dt =
+          static_cast<DatatypeType>(etn.toType()).getDatatype();
+      // all constructors that are not a part of a strategy are needed
+      for (unsigned j = 0, size = dt.getNumConstructors(); j < size; j++)
+      {
+        if (needs_cons_curr.find(j) == needs_cons_curr.end())
+        {
+          needs_cons_curr[j] = true;
+        }
+      }
+      // update the constructors that the master enumerator needs
+      if (needs_cons.find(em) == needs_cons.end())
+      {
+        needs_cons[em] = needs_cons_curr;
+      }
+      else
+      {
+        for (unsigned j = 0, size = dt.getNumConstructors(); j < size; j++)
+        {
+          needs_cons[em][j] = needs_cons[em][j] || needs_cons_curr[j];
+        }
+      }
+    }
+  }else{
+    indent("sygus-unif", ind);
+    Trace("sygus-unif") << e << " :: node role : " << nrole << std::endl;
+  }
+}
+
+// ------------------------------------------- solution construction from enumeration
+
+void CegConjecturePbe::getCandidateList( std::vector< Node >& candidates, std::vector< Node >& clist ) {
+  Valuation& valuation = d_qe->getValuation();
+  for( unsigned i=0; i<candidates.size(); i++ ){
+    Node v = candidates[i];
+    std::map< Node, CandidateInfo >::iterator it = d_cinfo.find( v );
+    if( it!=d_cinfo.end() ){
+      for( unsigned j=0; j<it->second.d_esym_list.size(); j++ ){
+        Node e = it->second.d_esym_list[j];
+        std::map< Node, EnumInfo >::iterator it = d_einfo.find( e );
+        Assert( it != d_einfo.end() );
+        Node gstatus = valuation.getSatValue(it->second.d_active_guard);
+        if (!gstatus.isNull() && gstatus.getConst<bool>())
+        {
+          clist.push_back( e );
+        }
+      }
+    }
+  }
+}
+
+bool CegConjecturePbe::constructCandidates( std::vector< Node >& enums, std::vector< Node >& enum_values, 
+                                            std::vector< Node >& candidates, std::vector< Node >& candidate_values, 
+                                            std::vector< Node >& lems ) {
+  Assert( enums.size()==enum_values.size() );
+  if( !enums.empty() ){
+    unsigned min_term_size = 0;
+    std::vector< unsigned > enum_consider;
+    Trace("sygus-pbe-enum") << "Register new enumerated values : " << std::endl;
+    for( unsigned i=0; i<enums.size(); i++ ){
+      Trace("sygus-pbe-enum") << "  " << enums[i] << " -> " << enum_values[i] << std::endl;
+      unsigned sz = d_tds->getSygusTermSize( enum_values[i] );
+      if( i==0 || sz<min_term_size ){
+        enum_consider.clear();
+        min_term_size = sz;
+        enum_consider.push_back( i );
+      }else if( sz==min_term_size ){
+        enum_consider.push_back( i );
+      }
+    }
+    // only consider the enumerators that are at minimum size (for fairness)
+    Trace("sygus-pbe-enum") << "...register " << enum_consider.size() << " / " << enums.size() << std::endl;
+    for( unsigned i=0; i<enum_consider.size(); i++ ){
+      unsigned j = enum_consider[i];
+      addEnumeratedValue( enums[j], enum_values[j], lems );
+    }
+  }
+  for( unsigned i=0; i<candidates.size(); i++ ){
+    Node c = candidates[i];
+    //build decision tree for candidate
+    Node vc = constructSolution( c );
+    if( vc.isNull() ){     
+      return false;
+    }else{
+      candidate_values.push_back( vc );
+    }
+  }
+  return true;
+}
+
+void CegConjecturePbe::addEnumeratedValue( Node x, Node v, std::vector< Node >& lems ) {
+  std::map< Node, EnumInfo >::iterator it = d_einfo.find( x );
+  Assert( it != d_einfo.end() );
+  Node gstatus = d_qe->getValuation().getSatValue(it->second.d_active_guard);
+  if (gstatus.isNull() || !gstatus.getConst<bool>())
+  {
+    Trace("sygus-pbe-enum-debug") << "  ...guard is inactive." << std::endl;
+    return;
+  }
+  Assert(
+      std::find(it->second.d_enum_vals.begin(), it->second.d_enum_vals.end(), v)
+      == it->second.d_enum_vals.end());
+  Node c = it->second.d_parent_candidate;
+  // The explanation for why the current value should be excluded in future
+  // iterations.
+  Node exp_exc;
+  if (d_examples_out_invalid.find(c) == d_examples_out_invalid.end())
+  {
+    std::map<Node, CandidateInfo>::iterator itc = d_cinfo.find(c);
+    Assert(itc != d_cinfo.end());
+    TypeNode xtn = x.getType();
+    Node bv = d_tds->sygusToBuiltin(v, xtn);
+    std::map<Node, std::vector<std::vector<Node> > >::iterator itx =
+        d_examples.find(c);
+    std::map<Node, std::vector<Node> >::iterator itxo = d_examples_out.find(c);
+    Assert(itx != d_examples.end());
+    Assert(itxo != d_examples_out.end());
+    Assert(itx->second.size() == itxo->second.size());
+    std::vector<Node> base_results;
+    // compte the results
+    for (unsigned j = 0, size = itx->second.size(); j < size; j++)
+    {
+      Node res = d_tds->evaluateBuiltin(xtn, bv, itx->second[j]);
+      Trace("sygus-pbe-enum-debug")
+          << "...got res = " << res << " from " << bv << std::endl;
+      base_results.push_back(res);
+    }
+    // is it excluded for domain-specific reason?
+    std::vector<Node> exp_exc_vec;
+    if (getExplanationForEnumeratorExclude(
+            c, x, v, base_results, it->second, exp_exc_vec))
+    {
+      Assert(!exp_exc_vec.empty());
+      exp_exc = exp_exc_vec.size() == 1
+                    ? exp_exc_vec[0]
+                    : NodeManager::currentNM()->mkNode(AND, exp_exc_vec);
+      Trace("sygus-pbe-enum")
+          << "  ...fail : term is excluded (domain-specific)" << std::endl;
+    }
+    else
+    {
+      // notify all slaves
+      Assert( !it->second.d_enum_slave.empty() );
+      //explanation for why this value should be excluded
+      for( unsigned s=0; s<it->second.d_enum_slave.size(); s++ ){
+        Node xs = it->second.d_enum_slave[s];
+        std::map< Node, EnumInfo >::iterator itv = d_einfo.find( xs );
+        Assert( itv!=d_einfo.end() );
+        Trace("sygus-pbe-enum") << "Process " << xs << " from " << s << std::endl;
+        //bool prevIsCover = false;
+        if (itv->second.getRole() == enum_io)
+        {
+          Trace("sygus-pbe-enum") << "   IO-Eval of ";
+          //prevIsCover = itv->second.isFeasible();
+        }else{
+          Trace("sygus-pbe-enum") << "Evaluation of ";
+        }
+        Trace("sygus-pbe-enum")  << xs <<  " : ";
+        //evaluate all input/output examples
+        std::vector< Node > results;
+        Node templ = itv->second.d_template;
+        TNode templ_var = itv->second.d_template_arg;
+        std::map< Node, bool > cond_vals;
+        for (unsigned j = 0, size = base_results.size(); j < size; j++)
+        {
+          Node res = base_results[j];
+          Assert( res.isConst() );
+          if( !templ.isNull() ){
+            TNode tres = res;
+            res = templ.substitute( templ_var, res );
+            res = Rewriter::rewrite( res );
+            Assert( res.isConst() );
+          }
+          Node resb;
+          if (itv->second.getRole() == enum_io)
+          {
+            Node out = itxo->second[j];
+            Assert( out.isConst() );
+            resb = res==out ? d_true : d_false;
+          }else{
+            resb = res;
+          }
+          cond_vals[resb] = true;
+          results.push_back( resb );
+          if( Trace.isOn("sygus-pbe-enum") ){
+            if( resb.getType().isBoolean() ){
+              Trace("sygus-pbe-enum") << ( resb==d_true ? "1" : "0" );
+            }else{
+              Trace("sygus-pbe-enum") << "?";
+            }
+          }
+        }
+        bool keep = false;
+        if (itv->second.getRole() == enum_io)
+        {
+          // latter is the degenerate case of no examples
+          if (cond_vals.find(d_true) != cond_vals.end() || cond_vals.empty())
+          {
+            //check subsumbed/subsuming
+            std::vector< Node > subsume;
+            if( cond_vals.find( d_false )==cond_vals.end() ){
+              // it is the entire solution, we are done
+              Trace("sygus-pbe-enum") << "  ...success, full solution added to PBE pool : " << d_tds->sygusToBuiltin( v ) << std::endl;
+              if( !itv->second.isSolved() ){
+                itv->second.setSolved( v );
+                // it subsumes everything
+                itv->second.d_term_trie.clear();
+                itv->second.d_term_trie.addTerm( this, v, results, true, subsume );
+              }
+              keep = true;
+            }else{
+              Node val = itv->second.d_term_trie.addTerm( this, v, results, true, subsume );
+              if( val==v ){
+                Trace("sygus-pbe-enum") << "  ...success"; 
+                if( !subsume.empty() ){
+                  itv->second.d_enum_subsume.insert( itv->second.d_enum_subsume.end(), subsume.begin(), subsume.end() );
+                  Trace("sygus-pbe-enum") << " and subsumed " << subsume.size() << " terms";
+                }
+                Trace("sygus-pbe-enum") << "!   add to PBE pool : " << d_tds->sygusToBuiltin( v ) << std::endl;
+                keep = true;
+              }else{
+                Assert( subsume.empty() );
+                Trace("sygus-pbe-enum") << "  ...fail : subsumed" << std::endl;
+              }
+            }
+          }else{
+            Trace("sygus-pbe-enum") << "  ...fail : it does not satisfy examples." << std::endl;
+          }
+        }else{
+          // must be unique up to examples
+          Node val = itv->second.d_term_trie.addCond(this, v, results, true);
+          if (val == v)
+          {
+            Trace("sygus-pbe-enum") << "  ...success!   add to PBE pool : "
+                                    << d_tds->sygusToBuiltin(v) << std::endl;
+            keep = true;
+          }else{
+            Trace("sygus-pbe-enum")
+                << "  ...fail : term is not unique" << std::endl;
+          }
+          itc->second.d_cond_count++;
+        }
+        if( keep ){
+          // notify the parent to retry the build of PBE
+          itc->second.d_check_sol = true;
+          itv->second.addEnumValue( this, v, results );
+        }
+      }
+    }
+  }else{
+    Trace("sygus-pbe-enum-debug")
+        << "  ...examples do not have output." << std::endl;
+  }
+  // exclude this value on subsequent iterations
+  Node g = it->second.d_active_guard;
+  if (exp_exc.isNull())
+  {
+    // if we did not already explain why this should be excluded, use default
+    exp_exc = d_tds->getExplain()->getExplanationForConstantEquality(x, v);
+  }
+  Node exlem =
+      NodeManager::currentNM()->mkNode(OR, g.negate(), exp_exc.negate());
+  Trace("sygus-pbe-enum-lemma")
+      << "CegConjecturePbe : enumeration exclude lemma : " << exlem
+      << std::endl;
+  lems.push_back(exlem);
+}
+
+bool CegConjecturePbe::useStrContainsEnumeratorExclude(Node x, EnumInfo& ei)
+{
+  TypeNode xbt = d_tds->sygusToBuiltinType(x.getType());
+  if (xbt.isString())
+  {
+    std::map<Node, bool>::iterator itx = d_use_str_contains_eexc.find(x);
+    if (itx != d_use_str_contains_eexc.end())
+    {
+      return itx->second;
+    }
+    Trace("sygus-pbe-enum-debug")
+        << "Is " << x << " is str.contains exclusion?" << std::endl;
+    d_use_str_contains_eexc[x] = true;
+    for (const Node& sn : ei.d_enum_slave)
+    {
+      std::map<Node, EnumInfo>::iterator itv = d_einfo.find(sn);
+      EnumRole er = itv->second.getRole();
+      if (er != enum_io && er != enum_concat_term)
+      {
+        Trace("sygus-pbe-enum-debug") << "  incompatible slave : " << sn
+                                      << ", role = " << er << std::endl;
+        d_use_str_contains_eexc[x] = false;
+        return false;
+      }
+      if (itv->second.isConditional())
+      {
+        Trace("sygus-pbe-enum-debug")
+            << "  conditional slave : " << sn << std::endl;
+        d_use_str_contains_eexc[x] = false;
+        return false;
+      }
+    }
+    Trace("sygus-pbe-enum-debug")
+        << "...can use str.contains exclusion." << std::endl;
+    return d_use_str_contains_eexc[x];
+  }
+  return false;
+}
+
+bool CegConjecturePbe::getExplanationForEnumeratorExclude(
+    Node c,
+    Node x,
+    Node v,
+    std::vector<Node>& results,
+    EnumInfo& ei,
+    std::vector<Node>& exp)
+{
+  if (useStrContainsEnumeratorExclude(x, ei))
+  {
+    NodeManager* nm = NodeManager::currentNM();
+    // This check whether the example evaluates to something that is larger than
+    // the output for some input/output pair. If so, then this term is never
+    // useful. We generalize its explanation below.
+
+    if (Trace.isOn("sygus-pbe-cterm-debug"))
+    {
+      Trace("sygus-pbe-enum") << std::endl;
+    }
+    // check if all examples had longer length that the output
+    std::map<Node, std::vector<Node> >::iterator itxo = d_examples_out.find(c);
+    Assert(itxo != d_examples_out.end());
+    Assert(itxo->second.size() == results.size());
+    Trace("sygus-pbe-cterm-debug")
+        << "Check enumerator exclusion for " << x << " -> "
+        << d_tds->sygusToBuiltin(v) << " based on str.contains." << std::endl;
+    std::vector<unsigned> cmp_indices;
+    for (unsigned i = 0, size = results.size(); i < size; i++)
+    {
+      Assert(results[i].isConst());
+      Assert(itxo->second[i].isConst());
+      Trace("sygus-pbe-cterm-debug")
+          << "  " << results[i] << " <> " << itxo->second[i];
+      Node cont = nm->mkNode(STRING_STRCTN, itxo->second[i], results[i]);
+      Node contr = Rewriter::rewrite(cont);
+      if (contr == d_false)
+      {
+        cmp_indices.push_back(i);
+        Trace("sygus-pbe-cterm-debug") << "...not contained." << std::endl;
+      }
+      else
+      {
+        Trace("sygus-pbe-cterm-debug") << "...contained." << std::endl;
+      }
+    }
+    if (!cmp_indices.empty())
+    {
+      // we check invariance with respect to a negative contains test
+      NegContainsSygusInvarianceTest ncset;
+      ncset.init(d_parent, x, itxo->second, cmp_indices);
+      // construct the generalized explanation
+      d_tds->getExplain()->getExplanationFor(x, v, exp, ncset);
+      Trace("sygus-pbe-cterm")
+          << "PBE-cterm : enumerator exclude " << d_tds->sygusToBuiltin(v)
+          << " due to negative containment." << std::endl;
+      return true;
+    }
+  }
+  return false;
+}
+
+
+
+void CegConjecturePbe::EnumInfo::addEnumValue( CegConjecturePbe * pbe, Node v, std::vector< Node >& results ) {
+  d_enum_val_to_index[v] = d_enum_vals.size();
+  d_enum_vals.push_back( v );
+  d_enum_vals_res.push_back( results );
+  /*
+  if( getRole()==enum_io ){
+    // compute
+    if( d_enum_total.empty() ){
+      d_enum_total = results;
+    }else if( !d_enum_total_true ){
+      d_enum_total_true = true;
+      Assert( d_enum_total.size()==results.size() );
+      for( unsigned i=0; i<results.size(); i++ ){
+        if( d_enum_total[i]==pbe->d_true || results[i]==pbe->d_true ){
+          d_enum_total[i] = pbe->d_true;
+        }else{
+          d_enum_total[i] = pbe->d_false;
+          d_enum_total_true = false;
+        }
+      }
+    }
+  }
+  */
+}
+
+void CegConjecturePbe::EnumInfo::initialize(Node c, EnumRole role)
+{
+  d_parent_candidate = c;
+  d_role = role;
+}
+
+void CegConjecturePbe::EnumInfo::setSolved( Node slv ) {
+  d_enum_solved = slv;
+  //d_enum_total_true = true;
+}
+    
+void CegConjecturePbe::CandidateInfo::initialize( Node c ) {
+  d_this_candidate = c;
+  d_root = c.getType();
+}
+
+void CegConjecturePbe::CandidateInfo::initializeType( TypeNode tn ) {
+  d_tinfo[tn].d_this_type = tn;
+  d_tinfo[tn].d_parent = this;
+}
+
+Node CegConjecturePbe::CandidateInfo::getRootEnumerator() {
+  std::map<EnumRole, Node>::iterator it = d_tinfo[d_root].d_enum.find(enum_io);
+  Assert( it!=d_tinfo[d_root].d_enum.end() );
+  return it->second;
+}
+
+bool CegConjecturePbe::CandidateInfo::isNonTrivial() {
+  //TODO
+  return true;
+}
+
+// status : 0 : exact, -1 : vals is subset, 1 : vals is superset
+Node CegConjecturePbe::SubsumeTrie::addTermInternal( CegConjecturePbe * pbe, Node t, std::vector< Node >& vals, bool pol, 
+                                                     std::vector< Node >& subsumed, bool spol, IndexFilter * f, 
+                                                     unsigned index, int status, bool checkExistsOnly, bool checkSubsume ) {
+  if( index==vals.size() ){
+    if( status==0 ){
+      // set the term if checkExistsOnly = false
+      if( d_term.isNull() && !checkExistsOnly ){
+        d_term = t;
+      }
+    }else if( status==1 ){
+      Assert( checkSubsume );
+      // found a subsumed term
+      if( !d_term.isNull() ){
+        subsumed.push_back( d_term );
+        if( !checkExistsOnly ){
+          // remove it if checkExistsOnly = false
+          d_term = Node::null();
+        }
+      }
+    }else{
+      Assert( !checkExistsOnly && checkSubsume );
+    }
+    return d_term;
+  }else{
+    // the current value 
+    Assert( pol || ( vals[index].isConst() && vals[index].getType().isBoolean() ) );
+    Node cv = pol ? vals[index] : ( vals[index]==pbe->d_true ? pbe->d_false : pbe->d_true );
+    // if checkExistsOnly = false, check if the current value is subsumed if checkSubsume = true, if so, don't add
+    if( !checkExistsOnly && checkSubsume ){
+      std::vector< bool > check_subsumed_by;
+      if( status==0 ){
+        if( cv==pbe->d_false ){
+          check_subsumed_by.push_back( spol );
+        }
+      }else if( status==-1 ){
+        check_subsumed_by.push_back( spol );
+        if( cv==pbe->d_false ){
+          check_subsumed_by.push_back( !spol );
+        }
+      }
+      // check for subsumed nodes
+      for( unsigned i=0; i<check_subsumed_by.size(); i++ ){
+        Node csval = check_subsumed_by[i] ? pbe->d_true : pbe->d_false;
+        // check if subsumed
+        std::map< Node, SubsumeTrie >::iterator itc = d_children.find( csval );
+        if( itc!=d_children.end() ){
+          unsigned next_index = f ? f->next( index ) : index+1;
+          Node ret = itc->second.addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, -1, checkExistsOnly, checkSubsume );
+          // ret subsumes t
+          if( !ret.isNull() ){
+            return ret;
+          }
+        }
+      }
+    }
+    Node ret;
+    std::vector< bool > check_subsume;
+    if( status==0 ){
+      unsigned next_index = f ? f->next( index ) : index+1;
+      if( checkExistsOnly ){
+        std::map< Node, SubsumeTrie >::iterator itc = d_children.find( cv );
+        if( itc!=d_children.end() ){
+          ret = itc->second.addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, 0, checkExistsOnly, checkSubsume );
+        }
+      }else{
+        Assert( spol );
+        ret = d_children[cv].addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, 0, checkExistsOnly, checkSubsume );
+        if( ret!=t ){
+          // we were subsumed by ret, return
+          return ret;
+        }
+      }
+      if( checkSubsume ){
+        // check for subsuming
+        if( cv==pbe->d_true ){
+          check_subsume.push_back( !spol );
+        }
+      }
+    }else if( status==1 ){
+      Assert( checkSubsume );
+      check_subsume.push_back( !spol );
+      if( cv==pbe->d_true ){
+        check_subsume.push_back( spol );
+      }
+    }
+    if( checkSubsume ){
+      // check for subsumed terms
+      for( unsigned i=0; i<check_subsume.size(); i++ ){
+        Node csval = check_subsume[i] ? pbe->d_true : pbe->d_false;
+        std::map< Node, SubsumeTrie >::iterator itc = d_children.find( csval );
+        if( itc!=d_children.end() ){
+          unsigned next_index = f ? f->next( index ) : index+1;
+          itc->second.addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, 1, checkExistsOnly, checkSubsume );
+          // clean up
+          if( itc->second.isEmpty() ){
+            Assert( !checkExistsOnly );
+            d_children.erase( csval );
+          }
+        }
+      }
+    }
+    return ret;
+  }
+}
+
+Node CegConjecturePbe::SubsumeTrie::addTerm( CegConjecturePbe * pbe, Node t, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f ) {
+  unsigned start_index = f ? f->start() : 0;
+  return addTermInternal( pbe, t, vals, pol, subsumed, true, f, start_index, 0, false, true );
+}
+
+Node CegConjecturePbe::SubsumeTrie::addCond( CegConjecturePbe * pbe, Node c, std::vector< Node >& vals, bool pol, IndexFilter * f ) {
+  unsigned start_index = f ? f->start() : 0;
+  std::vector< Node > subsumed;
+  return addTermInternal( pbe, c, vals, pol, subsumed, true, f, start_index, 0, false, false );
+}
+
+void CegConjecturePbe::SubsumeTrie::getSubsumed( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f ){
+  unsigned start_index = f ? f->start() : 0;
+  addTermInternal( pbe, Node::null(), vals, pol, subsumed, true, f, start_index, 1, true, true );
+}
+
+void CegConjecturePbe::SubsumeTrie::getSubsumedBy( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed_by, IndexFilter * f ){
+  // flip polarities
+  unsigned start_index = f ? f->start() : 0;
+  addTermInternal( pbe, Node::null(), vals, !pol, subsumed_by, false, f, start_index, 1, true, true );
+}
+
+void CegConjecturePbe::SubsumeTrie::getLeavesInternal( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::map< int, std::vector< Node > >& v, 
+                                                       IndexFilter * f, unsigned index, int status ) {
+  if( index==vals.size() ){
+    Assert( !d_term.isNull() );
+    Assert( std::find( v[status].begin(), v[status].end(), d_term )==v[status].end() );
+    v[status].push_back( d_term );
+  }else{
+    Assert( vals[index].isConst() && vals[index].getType().isBoolean() );
+    // filter should be for cv
+    Assert( f==NULL || vals[index]==( pol ? pbe->d_true : pbe->d_false ) );
+    for( std::map< Node, SubsumeTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+      int new_status = status;
+      // if the current value is true
+      if( vals[index]==( pol ? pbe->d_true : pbe->d_false ) ){
+        if( status!=0 ){
+          new_status = ( it->first == pbe->d_true ? 1 : -1 );
+          if( status!=-2 && new_status!=status ){
+            new_status = 0;
+          }
+        }
+      }
+      unsigned next_index = f ? f->next( index ) : index+1;
+      it->second.getLeavesInternal( pbe, vals, pol, v, f, next_index, new_status );
+    }
+  }
+}
+
+void CegConjecturePbe::SubsumeTrie::getLeaves( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::map< int, std::vector< Node > >& v, IndexFilter * f ) {
+  unsigned start_index = f ? f->start() : 0;
+  getLeavesInternal( pbe, vals, pol, v, f, start_index, -2 );
+}
+
+void CegConjecturePbe::IndexFilter::mk( std::vector< Node >& vals, bool pol ) {
+  Trace("sygus-pbe-debug") << "Make for : ";
+  print_val( "sygus-pbe-debug", vals, pol );
+  Trace("sygus-pbe-debug") << std::endl;
+  Node poln = NodeManager::currentNM()->mkConst( pol );
+  
+  unsigned curr_index = 0;
+  while( curr_index<vals.size() && vals[curr_index]!=poln ){
+    curr_index++;
+  }
+  d_next[0] = curr_index;
+  Trace("sygus-pbe-debug") << "0 -> " << curr_index << std::endl;
+  unsigned i = curr_index;
+  while( i<vals.size() ){
+    while( i<vals.size() && vals[i]!=poln ){
+      i++;
+    }
+    i++;
+    d_next[curr_index+1] = i;
+    Trace("sygus-pbe-debug") << curr_index+1 << " -> " << i << std::endl;
+    curr_index = i;
+  }
+  
+  // verify it is correct
+  unsigned j = start();
+  for( unsigned k=0; k<j; k++ ){
+    AlwaysAssert( vals[k]!=poln );
+  }
+  Trace("sygus-pbe-debug") << "...start : " << j << std::endl;
+  unsigned counter = 0;
+  while( j<vals.size() ){
+    Trace("sygus-pbe-debug") << "...at : " << j << std::endl;
+    AlwaysAssert( vals[j]==poln );
+    unsigned jj = next( j );
+    AlwaysAssert( jj>j );
+    for( unsigned k=(j+1); k<jj; k++ ){
+      AlwaysAssert( vals[k]!=poln );
+    }
+    AlwaysAssert( counter<=vals.size() );
+    counter++;
+    j = jj;
+  }
+  
+  
+}
+
+unsigned CegConjecturePbe::IndexFilter::start() {
+  std::map< unsigned, unsigned >::iterator it = d_next.find( 0 );
+  if( it==d_next.end() ){
+    return 0;
+  }else{
+    return it->second;
+  }
+}
+
+unsigned CegConjecturePbe::IndexFilter::next( unsigned i ) {
+  std::map< unsigned, unsigned >::iterator it = d_next.find( i+1 );
+  if( it==d_next.end() ){
+    return i+1;
+  }else{
+    return it->second;
+  }      
+}
+
+bool CegConjecturePbe::IndexFilter::isEq( std::vector< Node >& vals, Node v ) {
+  unsigned index = start();
+  while( index<vals.size() ){
+    if( vals[index]!=v ){
+      return false;
+    }
+    index = next( index );
+  }
+  return true;
+}
+
+Node CegConjecturePbe::constructSolution( Node c ){
+  std::map< Node, CandidateInfo >::iterator itc = d_cinfo.find( c );
+  Assert( itc!=d_cinfo.end() );
+  if( !itc->second.d_solution.isNull() ){
+    // already has a solution
+    return itc->second.d_solution;
+  }else{
+    // only check if an enumerator updated
+    if( itc->second.d_check_sol ){
+      Trace("sygus-pbe") << "Construct solution, #iterations = " << itc->second.d_cond_count << std::endl;
+      itc->second.d_check_sol = false;
+      // try multiple times if we have done multiple conditions, due to non-determinism
+      Node vc;
+      for( unsigned i=0; i<=itc->second.d_cond_count; i++ ){
+        Trace("sygus-pbe-dt") << "ConstructPBE for candidate: " << c << std::endl;
+        Node e = itc->second.getRootEnumerator();
+        UnifContext x;
+        x.initialize( this, c );
+        Node vcc = constructSolution(c, e, role_equal, x, 1);
+        if( !vcc.isNull() ){
+          if( vc.isNull() || ( !vc.isNull() && d_tds->getSygusTermSize( vcc )<d_tds->getSygusTermSize( vc ) ) ){
+            Trace("sygus-pbe") << "**** PBE SOLVED : " << c << " = " << vcc << std::endl;
+            Trace("sygus-pbe") << "...solved at iteration " << i << std::endl;
+            vc = vcc;
+          }
+        }
+      }
+      if( !vc.isNull() ){
+        itc->second.d_solution = vc;
+        return vc;
+      }
+      Trace("sygus-pbe") << "...failed to solve." << std::endl;
+    }
+    return Node::null();
+  }
+}
+
+Node CegConjecturePbe::constructBestSolvedTerm( std::vector< Node >& solved, UnifContext& x ){
+  Assert( !solved.empty() );
+  // TODO
+  return solved[0];
+}
+
+Node CegConjecturePbe::constructBestStringSolvedTerm( std::vector< Node >& solved, UnifContext& x ) {
+  Assert( !solved.empty() );
+  // TODO
+  return solved[0];
+}
+
+Node CegConjecturePbe::constructBestSolvedConditional( std::vector< Node >& solved, UnifContext& x ){
+  Assert( !solved.empty() );
+  // TODO
+  return solved[0];
+}
+
+Node CegConjecturePbe::constructBestConditional( std::vector< Node >& conds, UnifContext& x ) {
+  Assert( !conds.empty() );
+  // TODO
+  double r = Random::getRandom().pickDouble(0.0, 1.0);
+  unsigned cindex = r*conds.size();
+  if( cindex>conds.size() ){
+    cindex = conds.size() - 1;
+  }
+  return conds[cindex];
+}
+
+Node CegConjecturePbe::constructBestStringToConcat( std::vector< Node > strs,
+                                                    std::map< Node, unsigned > total_inc, 
+                                                    std::map< Node, std::vector< unsigned > > incr,
+                                                    UnifContext& x ) {
+  Assert( !strs.empty() );
+  std::random_shuffle(strs.begin(), strs.end());
+  // prefer one that has incremented by more than 0
+  for (const Node& ns : strs)
+  {
+    if (total_inc[ns] > 0)
+    {
+      return ns;
+    }
+  }
+  return strs[0];
+}
+
+Node CegConjecturePbe::constructSolution(
+    Node c, Node e, NodeRole nrole, UnifContext& x, int ind)
+{
+  TypeNode etn = e.getType();
+  if (Trace.isOn("sygus-pbe-dt-debug"))
+  {
+    indent("sygus-pbe-dt-debug", ind);
+    Trace("sygus-pbe-dt-debug") << "ConstructPBE: (" << e << ", " << nrole
+                                << ") for type " << etn << " in context ";
+    print_val("sygus-pbe-dt-debug", x.d_vals);
+    if (x.d_has_string_pos != role_invalid)
+    {
+      Trace("sygus-pbe-dt-debug") << ", string context [" << x.d_has_string_pos;
+      for (unsigned i = 0, size = x.d_str_pos.size(); i < size; i++)
+      {
+        Trace("sygus-pbe-dt-debug") << " " << x.d_str_pos[i];
+      }
+      Trace("sygus-pbe-dt-debug") << "]";
+    }
+    Trace("sygus-pbe-dt-debug") << std::endl;
+  }
+  // enumerator type info
+  std::map<TypeNode, EnumTypeInfo>::iterator itt = d_cinfo[c].d_tinfo.find(etn);
+  Assert(itt != d_cinfo[c].d_tinfo.end());
+  EnumTypeInfo& tinfo = itt->second;
+
+  // get the enumerator information
+  std::map< Node, EnumInfo >::iterator itn = d_einfo.find( e );
+  Assert( itn!=d_einfo.end() );
+  EnumInfo& einfo = itn->second;
+
+  Node ret_dt;
+  if (nrole == role_equal)
+  {
+    if (!x.isReturnValueModified())
+    {
+      if (einfo.isSolved())
+      {
+        // this type has a complete solution
+        ret_dt = einfo.getSolved();
+        indent("sygus-pbe-dt", ind);
+        Trace("sygus-pbe-dt") << "return PBE: success : solved "
+                              << d_tds->sygusToBuiltin(ret_dt) << std::endl;
+        Assert(!ret_dt.isNull());
+      }
+      else
+      {
+        // could be conditionally solved
+        std::vector<Node> subsumed_by;
+        einfo.d_term_trie.getSubsumedBy(this, x.d_vals, true, subsumed_by);
+        if (!subsumed_by.empty())
+        {
+          ret_dt = constructBestSolvedTerm(subsumed_by, x);
+          indent("sygus-pbe-dt", ind);
+          Trace("sygus-pbe-dt") << "return PBE: success : conditionally solved"
+                                << d_tds->sygusToBuiltin(ret_dt) << std::endl;
+        }
+        else
+        {
+          indent("sygus-pbe-dt-debug", ind);
+          Trace("sygus-pbe-dt-debug")
+              << "  ...not currently conditionally solved." << std::endl;
+        }
+      }
+    }
+    if (ret_dt.isNull())
+    {
+      if (d_tds->sygusToBuiltinType(e.getType()).isString())
+      {
+        // check if a current value that closes all examples
+        // get the term enumerator for this type
+        bool success = true;
+        std::map<Node, EnumInfo>::iterator itet;
+        std::map<EnumRole, Node>::iterator itnt =
+            tinfo.d_enum.find(enum_concat_term);
+        if( itnt != itt->second.d_enum.end() ){
+          Node et = itnt->second;
+          itet = d_einfo.find( et );
+          Assert(itet != d_einfo.end());
+        }else{
+          success = false;
+        }
+        if (success)
+        {
+          // get the current examples
+          std::map<Node, std::vector<Node> >::iterator itx =
+              d_examples_out.find(c);
+          Assert(itx != d_examples_out.end());
+          std::vector<String> ex_vals;
+          x.getCurrentStrings(this, itx->second, ex_vals);
+          Assert(itn->second.d_enum_vals.size()
+                 == itn->second.d_enum_vals_res.size());
+
+          // test each example in the term enumerator for the type
+          std::vector<Node> str_solved;
+          for (unsigned i = 0, size = itet->second.d_enum_vals.size(); i < size;
+               i++)
+          {
+            if (x.isStringSolved(
+                    this, ex_vals, itet->second.d_enum_vals_res[i]))
+            {
+              str_solved.push_back(itet->second.d_enum_vals[i]);
+            }
+          }
+          if (!str_solved.empty())
+          {
+            ret_dt = constructBestStringSolvedTerm(str_solved, x);
+            indent("sygus-pbe-dt", ind);
+            Trace("sygus-pbe-dt") << "return PBE: success : string solved "
+                                  << d_tds->sygusToBuiltin(ret_dt) << std::endl;
+          }
+          else
+          {
+            indent("sygus-pbe-dt-debug", ind);
+            Trace("sygus-pbe-dt-debug") << "  ...not currently string solved."
+                                        << std::endl;
+          }
+        }
+      }
+    }
+  }
+  else if (nrole == role_string_prefix || nrole == role_string_suffix)
+  {
+    // check if each return value is a prefix/suffix of all open examples
+    if (!x.isReturnValueModified() || x.d_has_string_pos == nrole)
+    {
+      std::map<Node, std::vector<unsigned> > incr;
+      bool isPrefix = nrole == role_string_prefix;
+      std::map<Node, unsigned> total_inc;
+      std::vector<Node> inc_strs;
+      std::map<Node, std::vector<Node> >::iterator itx = d_examples_out.find(c);
+      Assert(itx != d_examples_out.end());
+      // make the value of the examples
+      std::vector<String> ex_vals;
+      x.getCurrentStrings(this, itx->second, ex_vals);
+      if (Trace.isOn("sygus-pbe-dt-debug"))
+      {
+        indent("sygus-pbe-dt-debug", ind);
+        Trace("sygus-pbe-dt-debug") << "current strings : " << std::endl;
+        for (unsigned i = 0, size = ex_vals.size(); i < size; i++)
+        {
+          indent("sygus-pbe-dt-debug", ind + 1);
+          Trace("sygus-pbe-dt-debug") << ex_vals[i] << std::endl;
+        }
+      }
+
+      // check if there is a value for which is a prefix/suffix of all active
+      // examples
+      Assert(einfo.d_enum_vals.size() == einfo.d_enum_vals_res.size());
+
+      for (unsigned i = 0, size = einfo.d_enum_vals.size(); i < size; i++)
+      {
+        Node val_t = einfo.d_enum_vals[i];
+        indent("sygus-pbe-dt-debug", ind);
+        Trace("sygus-pbe-dt-debug") << "increment string values : " << val_t
+                                    << " : ";
+        Assert(einfo.d_enum_vals_res[i].size() == itx->second.size());
+        unsigned tot = 0;
+        bool exsuccess = x.getStringIncrement(this,
+                                              isPrefix,
+                                              ex_vals,
+                                              einfo.d_enum_vals_res[i],
+                                              incr[val_t],
+                                              tot);
+        if (!exsuccess)
+        {
+          incr.erase(val_t);
+          Trace("sygus-pbe-dt-debug") << "...fail" << std::endl;
+        }
+        else
+        {
+          total_inc[val_t] = tot;
+          inc_strs.push_back(val_t);
+          Trace("sygus-pbe-dt-debug") << "...success, total increment = " << tot
+                                      << std::endl;
+        }
+      }
+
+      if (!incr.empty())
+      {
+        ret_dt = constructBestStringToConcat(inc_strs, total_inc, incr, x);
+        Assert(!ret_dt.isNull());
+        indent("sygus-pbe-dt", ind);
+        Trace("sygus-pbe-dt") << "PBE: CONCAT strategy : choose "
+                              << (isPrefix ? "pre" : "suf") << "fix value "
+                              << d_tds->sygusToBuiltin(ret_dt) << std::endl;
+        // update the context
+        bool ret = x.updateStringPosition(this, incr[ret_dt]);
+        AlwaysAssert(ret == (total_inc[ret_dt] > 0));
+        x.d_has_string_pos = nrole;
+      }else{
+        indent("sygus-pbe-dt", ind);
+        Trace("sygus-pbe-dt") << "PBE: failed CONCAT strategy, no values are "
+                              << (isPrefix ? "pre" : "suf")
+                              << "fix of all examples." << std::endl;
+      }
+    }
+    else
+    {
+      indent("sygus-pbe-dt", ind);
+      Trace("sygus-pbe-dt")
+          << "PBE: failed CONCAT strategy, prefix/suffix mismatch."
+          << std::endl;
+    }
+  }
+  if (ret_dt.isNull() && !einfo.isTemplated())
+  {
+    // we will try a single strategy
+    EnumTypeInfoStrat* etis = nullptr;
+    std::map<NodeRole, StrategyNode>::iterator itsn =
+        tinfo.d_snodes.find(nrole);
+    if (itsn != tinfo.d_snodes.end())
+    {
+      // strategy info
+      StrategyNode& snode = itsn->second;
+      if (x.d_visit_role[e].find(nrole) == x.d_visit_role[e].end())
+      {
+        x.d_visit_role[e][nrole] = true;
+        // try a random strategy
+        if (snode.d_strats.size() > 1)
+        {
+          std::random_shuffle(snode.d_strats.begin(), snode.d_strats.end());
+        }
+        // get an eligible strategy index
+        unsigned sindex = 0;
+        while (sindex < snode.d_strats.size()
+               && !x.isValidStrategy(snode.d_strats[sindex]))
+        {
+          sindex++;
+        }
+        // if we found a eligible strategy
+        if (sindex < snode.d_strats.size())
+        {
+          etis = snode.d_strats[sindex];
+        }
+      }
+    }
+    if (etis != nullptr)
+    {
+      StrategyType strat = etis->d_this;
+      indent("sygus-pbe-dt", ind + 1);
+      Trace("sygus-pbe-dt") << "...try STRATEGY " << strat << "..."
+                            << std::endl;
+
+      std::map<unsigned, Node> look_ahead_solved_children;
+      std::vector<Node> dt_children_cons;
+      bool success = true;
+
+      // for ITE
+      Node split_cond_enum;
+      int split_cond_res_index = -1;
+
+      for (unsigned sc = 0, size = etis->d_cenum.size(); sc < size; sc++)
+      {
+        indent("sygus-pbe-dt", ind + 1);
+        Trace("sygus-pbe-dt") << "construct PBE child #" << sc << "..."
+                              << std::endl;
+        Node rec_c;
+        std::map<unsigned, Node>::iterator itla =
+            look_ahead_solved_children.find(sc);
+        if (itla != look_ahead_solved_children.end())
+        {
+          rec_c = itla->second;
+          indent("sygus-pbe-dt-debug", ind + 1);
+          Trace("sygus-pbe-dt-debug") << "ConstructPBE: look ahead solved : "
+                                      << d_tds->sygusToBuiltin(rec_c)
+                                      << std::endl;
+        }
+        else
+        {
+          std::pair<Node, NodeRole>& cenum = etis->d_cenum[sc];
+
+          // update the context
+          std::vector<Node> prev;
+          if (strat == strat_ITE && sc > 0)
+          {
+            std::map<Node, EnumInfo>::iterator itnc =
+                d_einfo.find(split_cond_enum);
+            Assert(itnc != d_einfo.end());
+            Assert(split_cond_res_index >= 0);
+            Assert(split_cond_res_index
+                   < (int)itnc->second.d_enum_vals_res.size());
+            prev = x.d_vals;
+            bool ret = x.updateContext(
+                this,
+                itnc->second.d_enum_vals_res[split_cond_res_index],
+                sc == 1);
+            AlwaysAssert(ret);
+          }
+
+          // recurse
+          if (strat == strat_ITE && sc == 0)
+          {
+            Node ce = cenum.first;
+
+            // register the condition enumerator
+            std::map<Node, EnumInfo>::iterator itnc = d_einfo.find(ce);
+            Assert(itnc != d_einfo.end());
+            EnumInfo& einfo_child = itnc->second;
+
+            // only used if the return value is not modified
+            if (!x.isReturnValueModified())
+            {
+              if (x.d_uinfo.find(ce) == x.d_uinfo.end())
+              {
+                Trace("sygus-pbe-dt-debug2")
+                    << "  reg : PBE: Look for direct solutions for conditional "
+                       "enumerator "
+                    << ce << " ... " << std::endl;
+                Assert(einfo_child.d_enum_vals.size()
+                       == einfo_child.d_enum_vals_res.size());
+                for (unsigned i = 1; i <= 2; i++)
+                {
+                  std::pair<Node, NodeRole>& te_pair = etis->d_cenum[i];
+                  Node te = te_pair.first;
+                  std::map<Node, EnumInfo>::iterator itnt = d_einfo.find(te);
+                  Assert(itnt != d_einfo.end());
+                  bool branch_pol = (i == 1);
+                  // for each condition, get terms that satisfy it in this
+                  // branch
+                  for (unsigned k = 0, size = einfo_child.d_enum_vals.size();
+                       k < size;
+                       k++)
+                  {
+                    Node cond = einfo_child.d_enum_vals[k];
+                    std::vector<Node> solved;
+                    itnt->second.d_term_trie.getSubsumedBy(
+                        this,
+                        einfo_child.d_enum_vals_res[k],
+                        branch_pol,
+                        solved);
+                    Trace("sygus-pbe-dt-debug2")
+                        << "  reg : PBE: " << d_tds->sygusToBuiltin(cond)
+                        << " has " << solved.size() << " solutions in branch "
+                        << i << std::endl;
+                    if (!solved.empty())
+                    {
+                      Node slv = constructBestSolvedTerm(solved, x);
+                      Trace("sygus-pbe-dt-debug2")
+                          << "  reg : PBE: ..." << d_tds->sygusToBuiltin(slv)
+                          << " is a solution under branch " << i;
+                      Trace("sygus-pbe-dt-debug2")
+                          << " of condition " << d_tds->sygusToBuiltin(cond)
+                          << std::endl;
+                      x.d_uinfo[ce].d_look_ahead_sols[cond][i] = slv;
+                    }
+                  }
+                }
+              }
+            }
+
+            // get the conditionals in the current context : they must be
+            // distinguishable
+            std::map<int, std::vector<Node> > possible_cond;
+            std::map<Node, int> solved_cond;  // stores branch
+            einfo_child.d_term_trie.getLeaves(
+                this, x.d_vals, true, possible_cond);
+
+            std::map<int, std::vector<Node> >::iterator itpc =
+                possible_cond.find(0);
+            if (itpc != possible_cond.end())
+            {
+              if (Trace.isOn("sygus-pbe-dt-debug"))
+              {
+                indent("sygus-pbe-dt-debug", ind + 1);
+                Trace("sygus-pbe-dt-debug")
+                    << "PBE : We have " << itpc->second.size()
+                    << " distinguishable conditionals:" << std::endl;
+                for (Node& cond : itpc->second)
+                {
+                  indent("sygus-pbe-dt-debug", ind + 2);
+                  Trace("sygus-pbe-dt-debug") << d_tds->sygusToBuiltin(cond)
+                                              << std::endl;
+                }
+              }
+
+              // static look ahead conditional : choose conditionals that have
+              // solved terms in at least one branch
+              //    only applicable if we have not modified the return value
+              std::map<int, std::vector<Node> > solved_cond;
+              if (!x.isReturnValueModified())
+              {
+                Assert(x.d_uinfo.find(ce) != x.d_uinfo.end());
+                int solve_max = 0;
+                for (Node& cond : itpc->second)
+                {
+                  std::map<Node, std::map<unsigned, Node> >::iterator itla =
+                      x.d_uinfo[ce].d_look_ahead_sols.find(cond);
+                  if (itla != x.d_uinfo[ce].d_look_ahead_sols.end())
+                  {
+                    int nsolved = itla->second.size();
+                    solve_max = nsolved > solve_max ? nsolved : solve_max;
+                    solved_cond[nsolved].push_back(cond);
+                  }
+                }
+                int n = solve_max;
+                while (n > 0)
+                {
+                  if (!solved_cond[n].empty())
+                  {
+                    rec_c = constructBestSolvedConditional(solved_cond[n], x);
+                    indent("sygus-pbe-dt", ind + 1);
+                    Trace("sygus-pbe-dt")
+                        << "PBE: ITE strategy : choose solved conditional "
+                        << d_tds->sygusToBuiltin(rec_c) << " with " << n
+                        << " solved children..." << std::endl;
+                    std::map<Node, std::map<unsigned, Node> >::iterator itla =
+                        x.d_uinfo[ce].d_look_ahead_sols.find(rec_c);
+                    Assert(itla != x.d_uinfo[ce].d_look_ahead_sols.end());
+                    for (std::pair<const unsigned, Node>& las : itla->second)
+                    {
+                      look_ahead_solved_children[las.first] = las.second;
+                    }
+                    break;
+                  }
+                  n--;
+                }
+              }
+
+              // otherwise, guess a conditional
+              if (rec_c.isNull())
+              {
+                rec_c = constructBestConditional(itpc->second, x);
+                Assert(!rec_c.isNull());
+                indent("sygus-pbe-dt", ind);
+                Trace("sygus-pbe-dt")
+                    << "PBE: ITE strategy : choose random conditional "
+                    << d_tds->sygusToBuiltin(rec_c) << std::endl;
+              }
+            }
+            else
+            {
+              // TODO (#1250) : degenerate case where children have different
+              // types?
+              indent("sygus-pbe-dt", ind);
+              Trace("sygus-pbe-dt") << "return PBE: failed ITE strategy, "
+                                       "cannot find a distinguishable condition"
+                                    << std::endl;
+            }
+            if( !rec_c.isNull() ){
+              Assert(einfo_child.d_enum_val_to_index.find(rec_c)
+                     != einfo_child.d_enum_val_to_index.end());
+              split_cond_res_index = einfo_child.d_enum_val_to_index[rec_c];
+              split_cond_enum = ce;
+              Assert(split_cond_res_index >= 0);
+              Assert(split_cond_res_index
+                     < (int)einfo_child.d_enum_vals_res.size());
+            }
+          }
+          else
+          {
+            rec_c = constructSolution(c, cenum.first, cenum.second, x, ind + 2);
+          }
+
+          // undo update the context
+          if (strat == strat_ITE && sc > 0)
+          {
+            x.d_vals = prev;
+          }
+        }
+        if (!rec_c.isNull())
+        {
+          dt_children_cons.push_back(rec_c);
+        }
+        else
+        {
+          success = false;
+          break;
+        }
+      }
+      if (success)
+      {
+        Assert(dt_children_cons.size() == etis->d_sol_templ_args.size());
+        // ret_dt = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR,
+        // dt_children );
+        ret_dt = etis->d_sol_templ;
+        ret_dt = ret_dt.substitute(etis->d_sol_templ_args.begin(),
+                                   etis->d_sol_templ_args.end(),
+                                   dt_children_cons.begin(),
+                                   dt_children_cons.end());
+        indent("sygus-pbe-dt-debug", ind);
+        Trace("sygus-pbe-dt-debug")
+            << "PBE: success : constructed for strategy " << strat << std::endl;
+      }else{
+        indent("sygus-pbe-dt-debug", ind);
+        Trace("sygus-pbe-dt-debug") << "PBE: failed for strategy " << strat
+                                    << std::endl;
+      }
+    }
+  }
+
+  if( !ret_dt.isNull() ){
+    Assert( ret_dt.getType()==e.getType() );
+  }
+  indent("sygus-pbe-dt", ind);
+  Trace("sygus-pbe-dt") << "ConstructPBE: returned " << ret_dt << std::endl;
+  return ret_dt;
+}
+
+bool CegConjecturePbe::UnifContext::updateContext( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol ) {
+  Assert( d_vals.size()==vals.size() );
+  bool changed = false;
+  Node poln = pol ? pbe->d_true : pbe->d_false;
+  for( unsigned i=0; i<vals.size(); i++ ){
+    if( vals[i]!=poln ){
+      if( d_vals[i]==pbe->d_true ){
+        d_vals[i] = pbe->d_false;
+        changed = true;
+      }
+    }
+  }
+  if (changed)
+  {
+    d_visit_role.clear();
+  }
+  return changed;
+}
+
+bool CegConjecturePbe::UnifContext::updateStringPosition( CegConjecturePbe * pbe, std::vector< unsigned >& pos ) {
+  Assert( pos.size()==d_str_pos.size() );
+  bool changed = false;
+  for( unsigned i=0; i<pos.size(); i++ ){
+    if( pos[i]>0 ){
+      d_str_pos[i] += pos[i];
+      changed = true;
+    }
+  }
+  if (changed)
+  {
+    d_visit_role.clear();
+  }
+  return changed;
+}
+
+bool CegConjecturePbe::UnifContext::isReturnValueModified() {
+  if (d_has_string_pos != role_invalid)
+  {
+    return true;
+  }
+  return false;
+}
+
+bool CegConjecturePbe::UnifContext::isValidStrategy(EnumTypeInfoStrat* etis)
+{
+  StrategyType st = etis->d_this;
+  if (d_has_string_pos == role_string_prefix && st == strat_CONCAT_SUFFIX)
+  {
+    return false;
+  }
+  if (d_has_string_pos == role_string_suffix && st == strat_CONCAT_PREFIX)
+  {
+    return false;
+  }
+  return true;
+}
+
+void CegConjecturePbe::UnifContext::initialize( CegConjecturePbe * pbe, Node c ) {
+  Assert( d_vals.empty() );
+  Assert( d_str_pos.empty() );
+  
+  // initialize with #examples
+  Assert( pbe->d_examples.find( c )!=pbe->d_examples.end() );
+  unsigned sz = pbe->d_examples[c].size();
+  for( unsigned i=0; i<sz; i++ ){
+    d_vals.push_back( pbe->d_true );
+  }
+  
+  if( !pbe->d_examples_out[c].empty() ){
+    // output type of the examples
+    TypeNode exotn = pbe->d_examples_out[c][0].getType();
+    
+    if( exotn.isString() ){
+      for( unsigned i=0; i<sz; i++ ){
+        d_str_pos.push_back( 0 );
+      }
+    }
+  }
+  d_visit_role.clear();
+}
+
+void CegConjecturePbe::UnifContext::getCurrentStrings(
+    CegConjecturePbe* pbe,
+    const std::vector<Node>& vals,
+    std::vector<String>& ex_vals)
+{
+  bool isPrefix = d_has_string_pos == role_string_prefix;
+  String dummy;
+  for( unsigned i=0; i<vals.size(); i++ ){
+    if( d_vals[i]==pbe->d_true ){
+      Assert( vals[i].isConst() );
+      unsigned pos_value = d_str_pos[i];
+      if( pos_value>0 ){
+        Assert(d_has_string_pos != role_invalid);
+        String s = vals[i].getConst<String>();
+        Assert( pos_value<=s.size() );
+        ex_vals.push_back( isPrefix ? s.suffix( s.size()-pos_value ) : 
+                                      s.prefix( s.size()-pos_value ) );
+      }else{
+        ex_vals.push_back( vals[i].getConst<String>() );
+      }
+    }else{
+      // irrelevant, add dummy
+      ex_vals.push_back( dummy );
+    }
+  }
+}
+
+bool CegConjecturePbe::UnifContext::getStringIncrement(
+    CegConjecturePbe* pbe,
+    bool isPrefix,
+    const std::vector<String>& ex_vals,
+    const std::vector<Node>& vals,
+    std::vector<unsigned>& inc,
+    unsigned& tot)
+{
+  for( unsigned j=0; j<vals.size(); j++ ){
+    unsigned ival = 0;
+    if( d_vals[j]==pbe->d_true ){
+      // example is active in this context
+      Assert( vals[j].isConst() );
+      String mystr = vals[j].getConst<String>();
+      ival = mystr.size();
+      if( mystr.size()<=ex_vals[j].size() ){
+        if( !( isPrefix ? ex_vals[j].strncmp(mystr, ival) : ex_vals[j].rstrncmp(mystr, ival) ) ){
+          Trace("sygus-pbe-dt-debug") << "X";
+          return false;
+        }
+      }else{
+        Trace("sygus-pbe-dt-debug") << "X";
+        return false;
+      }
+    }
+    Trace("sygus-pbe-dt-debug") << ival;
+    tot += ival;
+    inc.push_back( ival );
+  }
+  return true;
+}
+bool CegConjecturePbe::UnifContext::isStringSolved(
+    CegConjecturePbe* pbe,
+    const std::vector<String>& ex_vals,
+    const std::vector<Node>& vals)
+{
+  for( unsigned j=0; j<vals.size(); j++ ){
+    if( d_vals[j]==pbe->d_true ){
+      // example is active in this context
+      Assert( vals[j].isConst() );
+      String mystr = vals[j].getConst<String>();
+      if( ex_vals[j]!=mystr ){
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+CegConjecturePbe::StrategyNode::~StrategyNode()
+{
+  for (unsigned j = 0, size = d_strats.size(); j < size; j++)
+  {
+    delete d_strats[j];
+  }
+  d_strats.clear();
+}
+}
+}
+}
diff --git a/src/theory/quantifiers/sygus/sygus_pbe.h b/src/theory/quantifiers/sygus/sygus_pbe.h
new file mode 100644 (file)
index 0000000..ce1f2bf
--- /dev/null
@@ -0,0 +1,802 @@
+/*********************                                                        */
+/*! \file ce_guided_pbe.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief utility for processing programming by examples synthesis conjectures
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_PBE_H
+#define __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_PBE_H
+
+#include "context/cdhashmap.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+/** roles for enumerators
+ *
+ * This indicates the role of an enumerator that is allocated by approaches
+ * for synthesis-by-unification (see details below).
+ *   io : the enumerator should enumerate values that are overall solutions
+ *        for the function-to-synthesize,
+ *   ite_condition : the enumerator should enumerate values that are useful
+ *                   in ite conditions in the ITE strategy,
+ *   concat_term : the enumerator should enumerate values that are used as
+ *                 components of string concatenation solutions.
+ */
+enum EnumRole
+{
+  enum_invalid,
+  enum_io,
+  enum_ite_condition,
+  enum_concat_term,
+};
+std::ostream& operator<<(std::ostream& os, EnumRole r);
+
+/** roles for strategy nodes
+ *
+ * This indicates the role of a strategy node, which is a subprocedure of
+ * CegConjecturePbe::constructSolution (see details below).
+ *   equal : the node constructed must be equal to the overall solution for
+ *           the function-to-synthesize,
+ *   string_prefix/suffix : the node constructed must be a prefix/suffix
+ *                          of the function-to-synthesize,
+ *   ite_condition : the node constructed must be a condition that makes some
+ *                   active input examples true and some input examples false.
+ */
+enum NodeRole
+{
+  role_invalid,
+  role_equal,
+  role_string_prefix,
+  role_string_suffix,
+  role_ite_condition,
+};
+std::ostream& operator<<(std::ostream& os, NodeRole r);
+
+/** enumerator role for node role */
+EnumRole getEnumeratorRoleForNodeRole(NodeRole r);
+
+/** strategy types
+ *
+ * This indicates a strategy for synthesis-by-unification (see details below).
+ *   ITE : strategy for constructing if-then-else solutions via decision
+ *         tree learning techniques,
+ *   CONCAT_PREFIX/SUFFIX : strategy for constructing string concatenation
+ *         solutions via a divide and conquer approach,
+ *   ID : identity strategy used for calling strategies on child type through
+ *        an identity function.
+ */
+enum StrategyType
+{
+  strat_INVALID,
+  strat_ITE,
+  strat_CONCAT_PREFIX,
+  strat_CONCAT_SUFFIX,
+  strat_ID,
+};
+std::ostream& operator<<(std::ostream& os, StrategyType st);
+
+class CegConjecture;
+
+/** CegConjecturePbe
+*
+* This class implements optimizations that target synthesis conjectures
+* that are in Programming-By-Examples (PBE) form.
+*
+* [EX#1] An example of a synthesis conjecture in PBE form is :
+* exists f. forall x.
+* ( x = 0 => f( x ) = 2 ) ^ ( x = 5 => f( x ) = 7 ) ^ ( x = 6 => f( x ) = 8 )
+*
+* We say that the above conjecture has I/O examples (0)->2, (5)->7, (6)->8.
+*
+* Internally, this class does the following for SyGuS inputs:
+*
+* (1) Infers whether the input conjecture is in PBE form or not.
+* (2) Based on this information and on the syntactic restrictions, it
+*     devises a strategy for enumerating terms and construction solutions,
+*     which is inspired by Alur et al. "Scaling Enumerative Program Synthesis
+*     via Divide and Conquer" TACAS 2017. In particular, it may consider
+*     strategies for constructing decision trees when the grammar permits ITEs
+*     and a strategy for divide-and-conquer string synthesis when the grammar
+*     permits string concatenation. This is stored in a set of data structures
+*     within d_cinfo.
+* (3) It makes (possibly multiple) calls to
+*     TermDatabaseSygus::registerMeasuredTerm(...) based
+*     on the strategy, which inform the rest of the system to enumerate values
+*     of particular types in the grammar through use of fresh variables which
+*     we call "enumerators".
+*
+* Points (1)-(3) happen within a call to CegConjecturePbe::initialize(...).
+*
+* Notice that each enumerator is associated with a single
+* function-to-synthesize, but a function-to-sythesize may be mapped to multiple 
+* enumerators. Some public functions of this class expect an enumerator as 
+* input, which we map to a function-to-synthesize via 
+* TermDatabaseSygus::getSynthFunFor(e).
+*
+* An enumerator is initially "active" but may become inactive if the enumeration
+* exhausts all possible values in the datatype corresponding to syntactic
+* restrictions for it. The search may continue unless all enumerators become 
+* inactive.
+*
+* (4) During search, the extension of quantifier-free datatypes procedure for
+*     SyGuS datatypes may ask this class whether current candidates can be
+*     discarded based on
+*     inferring when two candidate solutions are equivalent up to examples.
+*     For example, the candidate solutions:
+*     f = \x ite( x<0, x+1, x ) and f = \x x
+*     are equivalent up to examples on the above conjecture, since they have the
+*     same value on the points x = 0,5,6. Hence, we need only consider one of
+*     them. The interface for querying this is
+*       CegConjecturePbe::addSearchVal(...).
+*     For details, see Reynolds et al. SYNT 2017.
+*
+* (5) When the extension of quantifier-free datatypes procedure for SyGuS
+*     datatypes terminates with a model, the parent of this class calls
+*     CegConjecturePbe::getCandidateList(...), where this class returns the list
+*     of active enumerators.
+* (6) The parent class subsequently calls
+*     CegConjecturePbe::constructValues(...), which
+*     informs this class that new values have been enumerated for active
+*     enumerators, as indicated by the current model. This call also requests
+*     that based on these
+*     newly enumerated values, whether this class is now able to construct a
+*     solution based on the high-level strategy (stored in d_c_info).
+*
+* This class is not designed to work in incremental mode, since there is no way
+* to specify incremental problems in SyguS.
+*/
+class CegConjecturePbe {
+ public:
+  CegConjecturePbe(QuantifiersEngine* qe, CegConjecture* p);
+  ~CegConjecturePbe();
+
+  /** initialize this class
+  *
+  * n is the "base instantiation" of the deep-embedding version of
+  *   the synthesis conjecture under "candidates".
+  *   (see CegConjecture::d_base_inst)
+  *
+  * This function may add lemmas to the vector lemmas corresponding
+  * to initial lemmas regarding static analysis of enumerators it
+  * introduced. For example, we may say that the top-level symbol
+  * of an enumerator is not ITE if it is being used to construct
+  * return values for decision trees.
+  */
+  void initialize(Node n,
+                  std::vector<Node>& candidates,
+                  std::vector<Node>& lemmas);
+  /** get candidate list
+  * Adds all active enumerators associated with functions-to-synthesize in
+  * candidates to clist.
+  */
+  void getCandidateList(std::vector<Node>& candidates,
+                        std::vector<Node>& clist);
+  /** construct candidates
+  * (1) Indicates that the list of enumerators in "enums" currently have model
+  *     values "enum_values".
+  * (2) Asks whether based on these new enumerated values, we can construct a
+  *     solution for
+  *     the functions-to-synthesize in "candidates". If so, this function
+  *     returns "true" and
+  *     adds solutions for candidates into "candidate_values".
+  * During this class, this class may add auxiliary lemmas to "lems", which the
+  * caller should send on the output channel via lemma(...).
+  */
+  bool constructCandidates(std::vector<Node>& enums,
+                           std::vector<Node>& enum_values,
+                           std::vector<Node>& candidates,
+                           std::vector<Node>& candidate_values,
+                           std::vector<Node>& lems);
+  /** is PBE enabled for any enumerator? */
+  bool isPbe() { return d_is_pbe; }
+  /** is the enumerator e associated with I/O example pairs? */
+  bool hasExamples(Node e);
+  /** get number of I/O example pairs for enumerator e */
+  unsigned getNumExamples(Node e);
+  /** get the input arguments for i^th I/O example for e, which is added to the
+   * vector ex */
+  void getExample(Node e, unsigned i, std::vector<Node>& ex);
+  /** get the output value of the i^th I/O example for enumerator e */
+  Node getExampleOut(Node e, unsigned i);
+
+  /** add the search val
+  * This function is called by the extension of quantifier-free datatypes
+  * procedure for SyGuS datatypes when we are considering a value of
+  * enumerator e of sygus type tn whose analog in the signature of builtin
+  * theory is bvr.
+  *
+  * For example, bvr = x + 1 when e is the datatype value Plus( x(), One() ) and
+  * tn is a sygus datatype that encodes a subsignature of the integers.
+  *
+  * This returns either:
+  * - A SyGuS term whose analog is equivalent to bvr up to examples
+  *   In the above example,
+  *   it may return a term t of the form Plus( One(), x() ), such that this
+  *   function was previously called with t as input.
+  * - e, indicating that no previous terms are equivalent to e up to examples.
+  */
+  Node addSearchVal(TypeNode tn, Node e, Node bvr);
+  /** evaluate builtin
+  * This returns the evaluation of bn on the i^th example for the
+  * function-to-synthesis
+  * associated with enumerator e. If there are not at least i examples, it
+  * returns the rewritten form of bn.
+  * For example, if bn = x+5, e is an enumerator for f in the above example
+  * [EX#1], then
+  *   evaluateBuiltin( tn, bn, e, 0 ) = 7
+  *   evaluateBuiltin( tn, bn, e, 1 ) = 9
+  *   evaluateBuiltin( tn, bn, e, 2 ) = 10
+  */
+  Node evaluateBuiltin(TypeNode tn, Node bn, Node e, unsigned i);
+
+ private:
+  /** quantifiers engine associated with this class */
+  QuantifiersEngine* d_qe;
+  /** sygus term database of d_qe */
+  quantifiers::TermDbSygus * d_tds;
+  /** true and false nodes */
+  Node d_true;
+  Node d_false;
+  /** A reference to the conjecture that owns this class. */
+  CegConjecture* d_parent;
+  /** is this a PBE conjecture for any function? */
+  bool d_is_pbe;
+  /** for each candidate variable f (a function-to-synthesize), whether the
+  * conjecture is purely PBE for that variable
+  * In other words, all occurrences of f are guarded by equalities that
+  * constraint its arguments to constants.
+  */
+  std::map< Node, bool > d_examples_invalid;
+  /** for each candidate variable (function-to-synthesize), whether the
+  * conjecture is purely PBE for that variable.
+  * An example of a conjecture for which d_examples_invalid is false but
+  * d_examples_out_invalid is true is:
+  *   exists f. forall x. ( x = 0 => f( x ) > 2 )
+  * another example is:
+  *   exists f. forall x. ( ( x = 0 => f( x ) = 2 ) V ( x = 3 => f( x ) = 3 ) )
+  * since the formula is not a conjunction (the example values are not
+  * entailed).
+  * However, the domain of f in both cases is finite, which can be used for
+  * search space pruning.
+  */
+  std::map< Node, bool > d_examples_out_invalid;
+  /** for each candidate variable (function-to-synthesize), input of I/O
+   * examples */
+  std::map< Node, std::vector< std::vector< Node > > > d_examples;
+  /** for each candidate variable (function-to-synthesize), output of I/O
+   * examples */
+  std::map< Node, std::vector< Node > > d_examples_out;
+  /** the list of example terms
+   * For the example [EX#1] above, this is f( 0 ), f( 5 ), f( 6 )
+   */
+  std::map< Node, std::vector< Node > > d_examples_term;
+  /** collect the PBE examples in n
+  * This is called on the input conjecture, and will populate the above vectors.
+  *   hasPol/pol denote the polarity of n in the conjecture.
+  */
+  void collectExamples( Node n, std::map< Node, bool >& visited, bool hasPol, bool pol );
+
+  //--------------------------------- PBE search values
+  /** this class is an index of candidate solutions for PBE synthesis */
+  class PbeTrie {
+   public:
+    PbeTrie() {}
+    ~PbeTrie() {}
+    Node d_lazy_child;
+    std::map<Node, PbeTrie> d_children;
+    void clear() { d_children.clear(); }
+    Node addPbeExample(TypeNode etn, Node e, Node b, CegConjecturePbe* cpbe,
+                       unsigned index, unsigned ntotal);
+
+   private:
+    Node addPbeExampleEval(TypeNode etn, Node e, Node b, std::vector<Node>& ex,
+                           CegConjecturePbe* cpbe, unsigned index,
+                           unsigned ntotal);
+  };
+  /** trie of candidate solutions tried
+  * This stores information for each (enumerator, type),
+  * where type is a type in the grammar of the space of solutions for a subterm
+  * of e. This is used for symmetry breaking in quantifier-free reasoning
+  * about SyGuS datatypes.
+  */
+  std::map<Node, std::map<TypeNode, PbeTrie> > d_pbe_trie;
+  //--------------------------------- end PBE search values
+
+  // -------------------------------- decision tree learning
+  // index filter
+  class IndexFilter {
+  public:
+    IndexFilter(){}
+    void mk( std::vector< Node >& vals, bool pol = true );
+    std::map< unsigned, unsigned > d_next;
+    unsigned start();
+    unsigned next( unsigned i );
+    void clear() { d_next.clear(); }
+    bool isEq( std::vector< Node >& vs, Node v );
+  };
+  // subsumption trie
+  class SubsumeTrie {
+  public:
+    SubsumeTrie(){}
+    // adds term to the trie, removes based on subsumption
+    Node addTerm( CegConjecturePbe * pbe, Node t, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f = NULL );
+    // adds condition to the trie (does not do subsumption)
+    Node addCond( CegConjecturePbe * pbe, Node c, std::vector< Node >& vals, bool pol, IndexFilter * f = NULL );
+    // returns the set of terms that are subsets of vals
+    void getSubsumed( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f = NULL );
+    // returns the set of terms that are supersets of vals
+    void getSubsumedBy( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed_by, IndexFilter * f = NULL );
+    // v[-1,1,0] -> children always false, always true, both
+    void getLeaves( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::map< int, std::vector< Node > >& v, IndexFilter * f = NULL );
+    /** is this trie empty? */
+    bool isEmpty() { return d_term.isNull() && d_children.empty(); }
+    /** clear this trie */
+    void clear() {
+      d_term = Node::null();
+      d_children.clear(); 
+    }
+
+   private:
+    /** the term at this node */
+    Node d_term;
+    /** the children nodes of this trie */
+    std::map<Node, SubsumeTrie> d_children;
+    /** helper function for above functions */
+    Node addTermInternal(CegConjecturePbe* pbe,
+                         Node t,
+                         std::vector<Node>& vals,
+                         bool pol,
+                         std::vector<Node>& subsumed,
+                         bool spol,
+                         IndexFilter* f,
+                         unsigned index,
+                         int status,
+                         bool checkExistsOnly,
+                         bool checkSubsume);
+    /** helper function for above functions */
+    void getLeavesInternal(CegConjecturePbe* pbe,
+                           std::vector<Node>& vals,
+                           bool pol,
+                           std::map<int, std::vector<Node> >& v,
+                           IndexFilter* f,
+                           unsigned index,
+                           int status);
+  };
+  // -------------------------------- end decision tree learning
+
+  //------------------------------ representation of a enumeration strategy
+
+  /** information about an enumerator
+   *
+   * We say an enumerator is a master enumerator if it is the variable that
+   * we use to enumerate values for its sort. Master enumerators may have
+   * (possibly multiple) slave enumerators, stored in d_enum_slave,
+   */
+  class EnumInfo {
+   public:
+    EnumInfo() : d_role(enum_io), d_is_conditional(false) {}
+    /** initialize this class
+    * c is the parent function-to-synthesize
+    * role is the "role" the enumerator plays in the high-level strategy,
+    *   which is one of enum_* above.
+    */
+    void initialize(Node c, EnumRole role);
+    /** is this enumerator associated with a template? */
+    bool isTemplated() { return !d_template.isNull(); }
+    /** set conditional
+      *
+      * This flag is set to true if this enumerator may not apply to all
+      * input/output examples. For example, if this enumerator is used
+      * as an output value beneath a conditional in an instance of strat_ITE,
+      * then this enumerator is conditional.
+      */
+    void setConditional() { d_is_conditional = true; }
+    /** is conditional */
+    bool isConditional() { return d_is_conditional; }
+    void addEnumValue(CegConjecturePbe* pbe,
+                      Node v,
+                      std::vector<Node>& results);
+    void setSolved(Node slv);
+    bool isSolved() { return !d_enum_solved.isNull(); }
+    Node getSolved() { return d_enum_solved; }
+    EnumRole getRole() { return d_role; }
+    Node d_parent_candidate;
+    // for template
+    Node d_template;
+    Node d_template_arg;
+
+    Node d_active_guard;
+    std::vector<Node> d_enum_slave;
+    /** values we have enumerated */
+    std::vector<Node> d_enum_vals;
+    /**
+      * This either stores the values of f( I ) for inputs
+      * or the value of f( I ) = O if d_role==enum_io
+      */
+    std::vector<std::vector<Node> > d_enum_vals_res;
+    std::vector<Node> d_enum_subsume;
+    std::map<Node, unsigned> d_enum_val_to_index;
+    SubsumeTrie d_term_trie;
+
+   private:
+    /**
+     * Whether an enumerated value for this conjecture has solved the entire
+     * conjecture.
+     */
+    Node d_enum_solved;
+    /** the role of this enumerator (one of enum_* above). */
+    EnumRole d_role;
+    /** is this enumerator conditional */
+    bool d_is_conditional;
+  };
+  /** maps enumerators to the information above */
+  std::map< Node, EnumInfo > d_einfo;
+
+  class CandidateInfo;
+
+  /** represents a strategy for a SyGuS datatype type
+   *
+   * This represents a possible strategy to apply when processing a strategy
+   * node in constructSolution. When applying the strategy represented by this
+   * class, we may make recursive calls to the children of the strategy,
+   * given in d_cenum. If all recursive calls to constructSolution are
+   * successful, say:
+   *   constructSolution( c, d_cenum[1], ... ) = t1,
+   *    ...,
+   *   constructSolution( c, d_cenum[n], ... ) = tn,
+   * Then, the solution returned by this strategy is
+   *   d_sol_templ * { d_sol_templ_args -> (t1,...,tn) }
+   */
+  class EnumTypeInfoStrat {
+   public:
+    /** the type of strategy this represents */
+    StrategyType d_this;
+    /** the sygus datatype constructor that induced this strategy
+     *
+     * For example, this may be a sygus datatype whose sygus operator is ITE,
+     * if the strategy type above is strat_ITE.
+     */
+    Node d_cons;
+    /** children of this strategy */
+    std::vector<std::pair<Node, NodeRole> > d_cenum;
+    /** the arguments for the (templated) solution */
+    std::vector<Node> d_sol_templ_args;
+    /** the template for the solution */
+    Node d_sol_templ;
+  };
+
+  /** represents a node in the strategy graph
+   *
+   * It contains a list of possible strategies which are tried during calls
+   * to constructSolution.
+   */
+  class StrategyNode
+  {
+   public:
+    StrategyNode() {}
+    ~StrategyNode();
+    /** the set of strategies to try at this node in the strategy graph */
+    std::vector<EnumTypeInfoStrat*> d_strats;
+  };
+
+  /** stores enumerators and strategies for a SyGuS datatype type */
+  class EnumTypeInfo {
+  public:
+    EnumTypeInfo() : d_parent( NULL ){}
+    /** the parent candidate info (see below) */
+    CandidateInfo * d_parent;
+    /** the type that this information is for */
+    TypeNode d_this_type;
+    /** map from enum roles to enumerators for this type */
+    std::map<EnumRole, Node> d_enum;
+    /** map from node roles to strategy nodes */
+    std::map<NodeRole, StrategyNode> d_snodes;
+  };
+
+  /** stores strategy and enumeration information for a function-to-synthesize
+   */
+  class CandidateInfo {
+  public:
+    CandidateInfo() : d_check_sol( false ), d_cond_count( 0 ){}
+    Node d_this_candidate;
+    /**
+     * The root sygus datatype for the function-to-synthesize,
+     * which encodes the overall syntactic restrictions on the space
+     * of solutions.
+     */
+    TypeNode d_root;
+    /** Info for sygus datatype type occurring in a field of d_root */
+    std::map< TypeNode, EnumTypeInfo > d_tinfo;
+    /** list of all enumerators for the function-to-synthesize */
+    std::vector< Node > d_esym_list;
+    /**
+     * Maps sygus datatypes to their search enumerator. This is the (single)
+     * enumerator of that type that we enumerate values for.
+     */
+    std::map< TypeNode, Node > d_search_enum;
+    bool d_check_sol;
+    unsigned d_cond_count;
+    Node d_solution;
+    void initialize( Node c );
+    void initializeType( TypeNode tn );
+    Node getRootEnumerator();
+    bool isNonTrivial();
+  };
+  /** maps a function-to-synthesize to the above information */
+  std::map< Node, CandidateInfo > d_cinfo;
+
+  //------------------------------ representation of an enumeration strategy
+  /** add enumerated value
+   *
+   * We have enumerated the value v for x. This function adds x->v to the
+   * relevant data structures that are used for strategy-specific construction
+   * of solutions when necessary, and returns a set of lemmas, which are added
+   * to the input argument lems. These lemmas are used to rule out models where
+   * x = v, to force that a new value is enumerated for x.
+   */
+  void addEnumeratedValue( Node x, Node v, std::vector< Node >& lems );
+  /** domain-specific enumerator exclusion techniques
+   *
+   * Returns true if the value v for x can be excluded based on a
+   * domain-specific exclusion technique like the ones below.
+   *
+   * c : the candidate variable that x is enumerating for,
+   * results : the values of v under the input examples of c,
+   * ei : the enumerator information for x,
+   * exp : if this function returns true, then exp contains a (possibly
+   * generalize) explanation for why v can be excluded.
+   */
+  bool getExplanationForEnumeratorExclude( Node c, Node x, Node v, std::vector< Node >& results, EnumInfo& ei, std::vector< Node >& exp );
+  /** returns true if we can exlude values of x based on negative str.contains
+   *
+   * Values v for x may be excluded if we realize that the value of v under the
+   * substitution for some input example will never be contained in some output
+   * example. For details on this technique, see NegContainsSygusInvarianceTest
+   * in sygus_invariance.h.
+   *
+   * This function depends on whether x is being used to enumerate values
+   * for any node that is conditional in the strategy graph. For example,
+   * nodes that are children of ITE strategy nodes are conditional. If any node
+   * is conditional, then this function returns false.
+   */
+  bool useStrContainsEnumeratorExclude(Node x, EnumInfo& ei);
+  /** cache for the above function */
+  std::map<Node, bool> d_use_str_contains_eexc;
+
+  //------------------------------ strategy registration
+  /** collect enumerator types
+   *
+   * This builds the strategy for enumerated values of type tn for the given
+   * role of nrole, for solutions to function-to-synthesize c.
+   */
+  void collectEnumeratorTypes(Node c, TypeNode tn, NodeRole nrole);
+  /** register enumerator
+   *
+   * This registers that et is an enumerator for function-to-synthesize c
+   * of type tn, having enumerator role enum_role.
+   *
+   * inSearch is whether we will enumerate values based on this enumerator.
+   * A strategy node is represented by a (enumerator, node role) pair. Hence,
+   * we may use enumerators for which this flag is false to represent strategy
+   * nodes that have child strategies.
+   */
+  void registerEnumerator(
+      Node et, Node c, TypeNode tn, EnumRole enum_role, bool inSearch);
+  /** infer template */
+  bool inferTemplate(unsigned k,
+                     Node n,
+                     std::map<Node, unsigned>& templ_var_index,
+                     std::map<unsigned, unsigned>& templ_injection);
+  /** static learn redundant operators
+   *
+   * This learns static lemmas for pruning enumerative space based on the
+   * strategy for the function-to-synthesize c, and stores these into lemmas.
+   */
+  void staticLearnRedundantOps(Node c, std::vector<Node>& lemmas);
+  /** helper for static learn redundant operators
+   *
+   * (e, nrole) specify the strategy node in the graph we are currently
+   * analyzing, visited stores the nodes we have already visited.
+   *
+   * This method builds the mapping needs_cons, which maps (master) enumerators
+   * to a map from the constructors that it needs.
+   *
+   * ind is the depth in the strategy graph we are at (for debugging).
+   *
+   * isCond is whether the current enumerator is conditional (beneath a
+   * conditional of an strat_ITE strategy).
+   */
+  void staticLearnRedundantOps(
+      Node c,
+      Node e,
+      NodeRole nrole,
+      std::map<Node, std::map<NodeRole, bool> >& visited,
+      std::map<Node, std::map<unsigned, bool> >& needs_cons,
+      int ind,
+      bool isCond);
+  //------------------------------ end strategy registration
+
+  //------------------------------ constructing solutions
+  class UnifContext {
+  public:
+   UnifContext() : d_has_string_pos(role_invalid) {}
+   /** this intiializes this context for function-to-synthesize c */
+   void initialize(CegConjecturePbe* pbe, Node c);
+
+   //----------for ITE strategy
+   /** the value of the context conditional
+    *
+    * This stores a list of Boolean constants that is the same length of the
+    * number of input/output example pairs we are considering. For each i,
+    * if d_vals[i] = true, i/o pair #i is active according to this context
+    * if d_vals[i] = false, i/o pair #i is inactive according to this context
+    */
+   std::vector<Node> d_vals;
+   /** update the examples
+    *
+    * if pol=true, this method updates d_vals to d_vals & vals
+    * if pol=false, this method updates d_vals to d_vals & ( ~vals )
+    */
+   bool updateContext(CegConjecturePbe* pbe, std::vector<Node>& vals, bool pol);
+   //----------end for ITE strategy
+
+   //----------for CONCAT strategies
+   /** the position in the strings
+    *
+    * For each i/o example pair, this stores the length of the current solution
+    * for the input of the pair, where the solution for that input is a prefix
+    * or
+    * suffix of the output of the pair. For example, if our i/o pairs are:
+    *   f( "abcd" ) = "abcdcd"
+    *   f( "aa" ) = "aacd"
+    * If the solution we have currently constructed is str.++( x1, "c", ... ),
+    * then d_str_pos = ( 5, 3 ), where notice that
+    *   str.++( "abc", "c" ) is a prefix of "abcdcd" and
+    *   str.++( "aa", "c" ) is a prefix of "aacd".
+    */
+   std::vector<unsigned> d_str_pos;
+   /** has string position
+    *
+    * Whether the solution positions indicate a prefix or suffix of the output
+    * examples. If this is role_invalid, then we have not updated the string
+    * position.
+    */
+   NodeRole d_has_string_pos;
+   /** update the string examples
+    *
+    * This method updates d_str_pos to d_str_pos + pos.
+    */
+   bool updateStringPosition(CegConjecturePbe* pbe, std::vector<unsigned>& pos);
+   /** get current strings
+    *
+    * This returns the prefix/suffix of the string constants stored in vals
+    * of size d_str_pos, and stores the result in ex_vals. For example, if vals
+    * is (abcdcd", "aacde") and d_str_pos = ( 5, 3 ), then we add
+    * "d" and "de" to ex_vals.
+    */
+   void getCurrentStrings(CegConjecturePbe* pbe,
+                          const std::vector<Node>& vals,
+                          std::vector<String>& ex_vals);
+   /** get string increment
+    *
+    * If this method returns true, then inc and tot are updated such that
+    *   for all active indices i,
+    *      vals[i] is a prefix (or suffix if isPrefix=false) of ex_vals[i], and
+    *      inc[i] = str.len(vals[i])
+    *   for all inactive indices i, inc[i] = 0
+    * We set tot to the sum of inc[i] for i=1,...,n. This indicates the total
+    * number of characters incremented across all examples.
+    */
+   bool getStringIncrement(CegConjecturePbe* pbe,
+                           bool isPrefix,
+                           const std::vector<String>& ex_vals,
+                           const std::vector<Node>& vals,
+                           std::vector<unsigned>& inc,
+                           unsigned& tot);
+   /** returns true if ex_vals[i] = vals[i] for all active indices i. */
+   bool isStringSolved(CegConjecturePbe* pbe,
+                       const std::vector<String>& ex_vals,
+                       const std::vector<Node>& vals);
+   //----------end for CONCAT strategies
+
+   /** is return value modified?
+    *
+    * This returns true if we are currently in a state where the return value
+    * of the solution has been modified, e.g. by a previous node that solved
+    * for a prefix.
+    */
+   bool isReturnValueModified();
+   /** returns true if argument is valid strategy in this context */
+   bool isValidStrategy(EnumTypeInfoStrat* etis);
+   /** visited role
+    *
+    * This is the current set of enumerator/node role pairs we are currently
+    * visiting. This set is cleared when the context is updated.
+    */
+   std::map<Node, std::map<NodeRole, bool> > d_visit_role;
+
+   /** unif context enumerator information */
+   class UEnumInfo
+   {
+    public:
+     UEnumInfo() {}
+     /** map from conditions and branch positions to a solved node
+      *
+      * For example, if we have:
+      *   f( 1 ) = 2 ^ f( 3 ) = 4 ^ f( -1 ) = 1
+      * Then, valid entries in this map is:
+      *   d_look_ahead_sols[x>0][1] = x+1
+      *   d_look_ahead_sols[x>0][2] = 1
+      * For the first entry, notice that  for all input examples such that x>0
+      * evaluates to true, which are (1) and (3), we have that their output
+      * values for x+1 under the substitution that maps x to the input value,
+      * resulting in 2 and 4, are equal to the output value for the respective
+      * pairs.
+      */
+     std::map<Node, std::map<unsigned, Node> > d_look_ahead_sols;
+    };
+    /** map from enumerators to the above info class */
+    std::map< Node, UEnumInfo > d_uinfo;
+  };
+
+  /** construct solution
+   *
+   * This method tries to construct a solution for function-to-synthesize c
+   * based on the strategy stored for c in d_cinfo, which may include
+   * synthesis-by-unification approaches for ite and string concatenation terms.
+   * These approaches include the work of Alur et al. TACAS 2017.
+   * If it cannot construct a solution, it returns the null node.
+   */
+  Node constructSolution( Node c );
+  /** helper function for construct solution.
+   *
+   * Construct a solution based on enumerator e for function-to-synthesize c
+   * with node role nrole in context x.
+   *
+   * ind is the term depth of the context (for debugging).
+   */
+  Node constructSolution(
+      Node c, Node e, NodeRole nrole, UnifContext& x, int ind);
+  /** Heuristically choose the best solved term from solved in context x,
+   * currently return the first. */
+  Node constructBestSolvedTerm( std::vector< Node >& solved, UnifContext& x );
+  /** Heuristically choose the best solved string term  from solved in context
+   * x, currently  return the first. */
+  Node constructBestStringSolvedTerm( std::vector< Node >& solved, UnifContext& x );
+  /** Heuristically choose the best solved conditional term  from solved in
+   * context x, currently random */
+  Node constructBestSolvedConditional( std::vector< Node >& solved, UnifContext& x );
+  /** Heuristically choose the best conditional term  from conds in context x,
+   * currently random */
+  Node constructBestConditional( std::vector< Node >& conds, UnifContext& x );
+  /** Heuristically choose the best string to concatenate from strs to the
+  * solution in context x, currently random
+  * incr stores the vector of indices that are incremented by this solution in
+  * example outputs.
+  * total_inc[x] is the sum of incr[x] for each x in strs.
+  */
+  Node constructBestStringToConcat( std::vector< Node > strs,
+                                    std::map< Node, unsigned > total_inc, 
+                                    std::map< Node, std::vector< unsigned > > incr,
+                                    UnifContext& x );
+  //------------------------------ end constructing solutions
+};
+
+}/* namespace CVC4::theory::quantifiers */
+}/* namespace CVC4::theory */
+}/* namespace CVC4 */
+
+#endif
diff --git a/src/theory/quantifiers/sygus/sygus_process_conj.cpp b/src/theory/quantifiers/sygus/sygus_process_conj.cpp
new file mode 100644 (file)
index 0000000..a961c97
--- /dev/null
@@ -0,0 +1,798 @@
+/*********************                                                        */
+/*! \file sygus_process_conj.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of techniqures for static preprocessing and analysis
+ ** of sygus conjectures.
+ **/
+#include "theory/quantifiers/sygus/sygus_process_conj.h"
+
+#include <stack>
+
+#include "expr/datatype.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
+#include "theory/quantifiers/term_util.h"
+
+using namespace CVC4::kind;
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+void CegConjectureProcessFun::init(Node f)
+{
+  d_synth_fun = f;
+  Assert(f.getType().isFunction());
+
+  // initialize the arguments
+  std::unordered_map<TypeNode, unsigned, TypeNodeHashFunction>
+      type_to_init_deq_id;
+  std::vector<Type> argTypes =
+      static_cast<FunctionType>(f.getType().toType()).getArgTypes();
+  for (unsigned j = 0; j < argTypes.size(); j++)
+  {
+    TypeNode atn = TypeNode::fromType(argTypes[j]);
+    std::stringstream ss;
+    ss << "a" << j;
+    Node k = NodeManager::currentNM()->mkBoundVar(ss.str(), atn);
+    d_arg_vars.push_back(k);
+    d_arg_var_num[k] = j;
+    d_arg_props.push_back(CegConjectureProcessArg());
+  }
+}
+
+bool CegConjectureProcessFun::checkMatch(
+    Node cn, Node n, std::unordered_map<unsigned, Node>& n_arg_map)
+{
+  std::vector<Node> vars;
+  std::vector<Node> subs;
+  for (std::unordered_map<unsigned, Node>::iterator it = n_arg_map.begin();
+       it != n_arg_map.end();
+       ++it)
+  {
+    Assert(it->first < d_arg_vars.size());
+    Assert(
+        it->second.getType().isComparableTo(d_arg_vars[it->first].getType()));
+    vars.push_back(d_arg_vars[it->first]);
+    subs.push_back(it->second);
+  }
+  Node cn_subs =
+      cn.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
+  cn_subs = Rewriter::rewrite(cn_subs);
+  Assert(Rewriter::rewrite(n) == n);
+  return cn_subs == n;
+}
+
+bool CegConjectureProcessFun::isArgVar(Node n, unsigned& arg_index)
+{
+  if (n.isVar())
+  {
+    std::unordered_map<Node, unsigned, NodeHashFunction>::iterator ita =
+        d_arg_var_num.find(n);
+    if (ita != d_arg_var_num.end())
+    {
+      arg_index = ita->second;
+      return true;
+    }
+  }
+  return false;
+}
+
+Node CegConjectureProcessFun::inferDefinition(
+    Node n,
+    std::unordered_map<Node, unsigned, NodeHashFunction>& term_to_arg_carry,
+    std::unordered_map<Node,
+                       std::unordered_set<Node, NodeHashFunction>,
+                       NodeHashFunction>& free_vars)
+{
+  std::unordered_map<TNode, Node, TNodeHashFunction> visited;
+  std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
+  std::stack<TNode> visit;
+  TNode cur;
+  visit.push(n);
+  do
+  {
+    cur = visit.top();
+    visit.pop();
+    it = visited.find(cur);
+    if (it == visited.end())
+    {
+      // if it is ground, we can use it
+      if (free_vars[cur].empty())
+      {
+        visited[cur] = cur;
+      }
+      else
+      {
+        // if it is term used by another argument, use it
+        std::unordered_map<Node, unsigned, NodeHashFunction>::iterator itt =
+            term_to_arg_carry.find(cur);
+        if (itt != term_to_arg_carry.end())
+        {
+          visited[cur] = d_arg_vars[itt->second];
+        }
+        else if (cur.getNumChildren() > 0)
+        {
+          // try constructing children
+          visited[cur] = Node::null();
+          visit.push(cur);
+          for (unsigned i = 0; i < cur.getNumChildren(); i++)
+          {
+            visit.push(cur[i]);
+          }
+        }
+        else
+        {
+          return Node::null();
+        }
+      }
+    }
+    else if (it->second.isNull())
+    {
+      Node ret = cur;
+      bool childChanged = false;
+      std::vector<Node> children;
+      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
+      {
+        children.push_back(cur.getOperator());
+      }
+      for (unsigned i = 0; i < cur.getNumChildren(); i++)
+      {
+        it = visited.find(cur[i]);
+        Assert(it != visited.end());
+        Assert(!it->second.isNull());
+        childChanged = childChanged || cur[i] != it->second;
+        children.push_back(it->second);
+      }
+      if (childChanged)
+      {
+        ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
+      }
+      visited[cur] = ret;
+    }
+  } while (!visit.empty());
+  Assert(visited.find(n) != visited.end());
+  Assert(!visited.find(n)->second.isNull());
+  return visited[n];
+}
+
+unsigned CegConjectureProcessFun::assignRelevantDef(Node def,
+                                                    std::vector<unsigned>& args)
+{
+  unsigned id = 0;
+  if (def.isNull())
+  {
+    // prefer one that already has a definition, if one exists
+    for (unsigned j = 0; j < args.size(); j++)
+    {
+      unsigned i = args[j];
+      if (!d_arg_props[i].d_template.isNull())
+      {
+        id = j;
+        break;
+      }
+    }
+  }
+  unsigned rid = args[id];
+  // for merging previously equivalent definitions
+  std::unordered_map<Node, unsigned, NodeHashFunction> prev_defs;
+  for (unsigned j = 0; j < args.size(); j++)
+  {
+    unsigned i = args[j];
+    Trace("sygus-process-arg-deps") << "    ...processed arg #" << i;
+    if (!d_arg_props[i].d_template.isNull())
+    {
+      if (d_arg_props[i].d_template == def)
+      {
+        // definition was consistent
+      }
+      else
+      {
+        Node t = d_arg_props[i].d_template;
+        std::unordered_map<Node, unsigned, NodeHashFunction>::iterator itt =
+            prev_defs.find(t);
+        if (itt != prev_defs.end())
+        {
+          // merge previously equivalent definitions
+          d_arg_props[i].d_template = d_arg_vars[itt->second];
+          Trace("sygus-process-arg-deps")
+              << " (merged equivalent def from argument ";
+          Trace("sygus-process-arg-deps") << itt->second << ")." << std::endl;
+        }
+        else
+        {
+          // store this as previous
+          prev_defs[t] = i;
+          // now must be relevant
+          d_arg_props[i].d_relevant = true;
+          Trace("sygus-process-arg-deps")
+              << " (marked relevant, overwrite definition)." << std::endl;
+        }
+      }
+    }
+    else
+    {
+      if (def.isNull())
+      {
+        if (i != rid)
+        {
+          // marked as relevant, but template can be set equal to master
+          d_arg_props[i].d_template = d_arg_vars[rid];
+          Trace("sygus-process-arg-deps") << " (new definition, map to master "
+                                          << d_arg_vars[rid] << ")."
+                                          << std::endl;
+        }
+        else
+        {
+          d_arg_props[i].d_relevant = true;
+          Trace("sygus-process-arg-deps") << " (marked relevant)." << std::endl;
+        }
+      }
+      else
+      {
+        // has new definition
+        d_arg_props[i].d_template = def;
+        Trace("sygus-process-arg-deps") << " (new definition " << def << ")."
+                                        << std::endl;
+      }
+    }
+  }
+  return rid;
+}
+
+void CegConjectureProcessFun::processTerms(
+    std::vector<Node>& ns,
+    std::vector<Node>& ks,
+    Node nf,
+    std::unordered_set<Node, NodeHashFunction>& synth_fv,
+    std::unordered_map<Node,
+                       std::unordered_set<Node, NodeHashFunction>,
+                       NodeHashFunction>& free_vars)
+{
+  Assert(ns.size() == ks.size());
+  Trace("sygus-process-arg-deps") << "Process " << ns.size()
+                                  << " applications of " << d_synth_fun << "..."
+                                  << std::endl;
+
+  // get the relevant variables
+  // relevant variables are those that appear in the body of the conjunction
+  std::unordered_set<Node, NodeHashFunction> rlv_vars;
+  Assert(free_vars.find(nf) != free_vars.end());
+  rlv_vars = free_vars[nf];
+
+  // get the single occurrence variables
+  // single occurrence variables are those that appear in only one position,
+  // as an argument to the function-to-synthesize.
+  std::unordered_map<Node, bool, NodeHashFunction> single_occ_variables;
+  for (unsigned index = 0; index < ns.size(); index++)
+  {
+    Node n = ns[index];
+    for (unsigned i = 0; i < n.getNumChildren(); i++)
+    {
+      Node nn = n[i];
+      if (nn.isVar())
+      {
+        std::unordered_map<Node, bool, NodeHashFunction>::iterator its =
+            single_occ_variables.find(nn);
+        if (its == single_occ_variables.end())
+        {
+          // only irrelevant variables
+          single_occ_variables[nn] = rlv_vars.find(nn) == rlv_vars.end();
+        }
+        else
+        {
+          single_occ_variables[nn] = false;
+        }
+      }
+      else
+      {
+        std::unordered_map<Node,
+                           std::unordered_set<Node, NodeHashFunction>,
+                           NodeHashFunction>::iterator itf = free_vars.find(nn);
+        Assert(itf != free_vars.end());
+        for (std::unordered_set<Node, NodeHashFunction>::iterator itfv =
+                 itf->second.begin();
+             itfv != itf->second.end();
+             ++itfv)
+        {
+          single_occ_variables[*itfv] = false;
+        }
+      }
+    }
+  }
+
+  // update constant argument information
+  for (unsigned index = 0; index < ns.size(); index++)
+  {
+    Node n = ns[index];
+    Trace("sygus-process-arg-deps")
+        << "  Analyze argument information for application #" << index << ": "
+        << n << std::endl;
+
+    // in the following, we say an argument a "carries" a term t if
+    // the function to synthesize would use argument a to construct
+    // the term t in its definition.
+
+    // map that assumes all arguments carry their respective term
+    std::unordered_map<unsigned, Node> n_arg_map;
+    // terms to the argument that is carrying it.
+    // the arguments in the range of this map must be marked as relevant.
+    std::unordered_map<Node, unsigned, NodeHashFunction> term_to_arg_carry;
+    // map of terms to (unprocessed) arguments where it occurs
+    std::unordered_map<Node, std::vector<unsigned>, NodeHashFunction>
+        term_to_args;
+
+    // initialize
+    for (unsigned a = 0; a < n.getNumChildren(); a++)
+    {
+      n_arg_map[a] = n[a];
+    }
+
+    for (unsigned a = 0; a < n.getNumChildren(); a++)
+    {
+      bool processed = false;
+      if (d_arg_props[a].d_relevant)
+      {
+        // we can assume all relevant arguments carry their terms
+        processed = true;
+        Trace("sygus-process-arg-deps") << "    ...processed arg #" << a
+                                        << " (already relevant)." << std::endl;
+        if (term_to_arg_carry.find(n[a]) == term_to_arg_carry.end())
+        {
+          Trace("sygus-process-arg-deps") << "    carry " << n[a]
+                                          << " by argument #" << a << std::endl;
+          term_to_arg_carry[n[a]] = a;
+        }
+      }
+      else
+      {
+        // first, check if single occurrence variable
+        // check if an irrelevant variable
+        if (n[a].isVar() && synth_fv.find(n[a]) != synth_fv.end())
+        {
+          Assert(single_occ_variables.find(n[a]) != single_occ_variables.end());
+          // may be able to make this more precise?
+          // check if a single-occurrence variable
+          if (single_occ_variables[n[a]])
+          {
+            // if we do not already have a template definition, or the
+            // template is a single occurrence variable
+            if (d_arg_props[a].d_template.isNull()
+                || d_arg_props[a].d_var_single_occ)
+            {
+              processed = true;
+              Trace("sygus-process-arg-deps") << "    ...processed arg #" << a;
+              Trace("sygus-process-arg-deps")
+                  << " (single occurrence variable ";
+              Trace("sygus-process-arg-deps") << n[a] << ")." << std::endl;
+              d_arg_props[a].d_var_single_occ = true;
+              d_arg_props[a].d_template = n[a];
+            }
+          }
+        }
+        if (!processed && !d_arg_props[a].d_template.isNull()
+            && !d_arg_props[a].d_var_single_occ)
+        {
+          // argument already has a definition, see if it is maintained
+          if (checkMatch(d_arg_props[a].d_template, n[a], n_arg_map))
+          {
+            processed = true;
+            Trace("sygus-process-arg-deps") << "    ...processed arg #" << a;
+            Trace("sygus-process-arg-deps") << " (consistent definition "
+                                            << n[a];
+            Trace("sygus-process-arg-deps")
+                << " with " << d_arg_props[a].d_template << ")." << std::endl;
+          }
+        }
+      }
+      if (!processed)
+      {
+        // otherwise, add it to the list of arguments for this term
+        term_to_args[n[a]].push_back(a);
+      }
+    }
+
+    Trace("sygus-process-arg-deps") << "  Look at argument terms..."
+                                    << std::endl;
+
+    // list of all arguments
+    std::vector<Node> arg_list;
+    // now look at the terms for unprocessed arguments
+    for (std::unordered_map<Node, std::vector<unsigned>, NodeHashFunction>::
+             iterator it = term_to_args.begin();
+         it != term_to_args.end();
+         ++it)
+    {
+      Node nn = it->first;
+      arg_list.push_back(nn);
+      if (Trace.isOn("sygus-process-arg-deps"))
+      {
+        Trace("sygus-process-arg-deps") << "    argument " << nn;
+        Trace("sygus-process-arg-deps") << " (" << it->second.size()
+                                        << " positions)";
+        // check the status of this term
+        if (nn.isVar() && synth_fv.find(nn) != synth_fv.end())
+        {
+          // is it relevant?
+          if (rlv_vars.find(nn) != rlv_vars.end())
+          {
+            Trace("sygus-process-arg-deps") << " is a relevant variable."
+                                            << std::endl;
+          }
+          else
+          {
+            Trace("sygus-process-arg-deps") << " is an irrelevant variable."
+                                            << std::endl;
+          }
+        }
+        else
+        {
+          // this can be more precise
+          Trace("sygus-process-arg-deps") << " is a relevant term."
+                                          << std::endl;
+        }
+      }
+    }
+
+    unsigned arg_list_counter = 0;
+    // sort arg_list by term size?
+
+    while (arg_list_counter < arg_list.size())
+    {
+      Node infer_def_t;
+      do
+      {
+        infer_def_t = Node::null();
+        // see if we can infer a definition
+        for (std::unordered_map<Node, std::vector<unsigned>, NodeHashFunction>::
+                 iterator it = term_to_args.begin();
+             it != term_to_args.end();
+             ++it)
+        {
+          Node def = inferDefinition(it->first, term_to_arg_carry, free_vars);
+          if (!def.isNull())
+          {
+            Trace("sygus-process-arg-deps") << "  *** Inferred definition "
+                                            << def << " for " << it->first
+                                            << std::endl;
+            // assign to each argument
+            assignRelevantDef(def, it->second);
+            // term_to_arg_carry[it->first] = rid;
+            infer_def_t = it->first;
+            break;
+          }
+        }
+        if (!infer_def_t.isNull())
+        {
+          term_to_args.erase(infer_def_t);
+        }
+      } while (!infer_def_t.isNull());
+
+      // decide to make an argument relevant
+      bool success = false;
+      while (arg_list_counter < arg_list.size() && !success)
+      {
+        Node curr = arg_list[arg_list_counter];
+        std::unordered_map<Node, std::vector<unsigned>, NodeHashFunction>::
+            iterator it = term_to_args.find(curr);
+        if (it != term_to_args.end())
+        {
+          Trace("sygus-process-arg-deps") << "  *** Decide relevant " << curr
+                                          << std::endl;
+          // assign relevant to each
+          Node null_def;
+          unsigned rid = assignRelevantDef(null_def, it->second);
+          term_to_arg_carry[curr] = rid;
+          Trace("sygus-process-arg-deps")
+              << "    carry " << curr << " by argument #" << rid << std::endl;
+          term_to_args.erase(curr);
+          success = true;
+        }
+        arg_list_counter++;
+      }
+    }
+  }
+}
+
+bool CegConjectureProcessFun::isArgRelevant(unsigned i)
+{
+  return d_arg_props[i].d_relevant;
+}
+
+void CegConjectureProcessFun::getIrrelevantArgs(
+    std::unordered_set<unsigned>& args)
+{
+  for (unsigned i = 0; i < d_arg_vars.size(); i++)
+  {
+    if (!d_arg_props[i].d_relevant)
+    {
+      args.insert(i);
+    }
+  }
+}
+
+CegConjectureProcess::CegConjectureProcess(QuantifiersEngine* qe) {}
+CegConjectureProcess::~CegConjectureProcess() {}
+Node CegConjectureProcess::preSimplify(Node q)
+{
+  Trace("sygus-process") << "Pre-simplify conjecture : " << q << std::endl;
+  return q;
+}
+
+Node CegConjectureProcess::postSimplify(Node q)
+{
+  Trace("sygus-process") << "Post-simplify conjecture : " << q << std::endl;
+  Assert(q.getKind() == FORALL);
+
+  // initialize the information about each function to synthesize
+  for (unsigned i = 0; i < q[0].getNumChildren(); i++)
+  {
+    Node f = q[0][i];
+    if (f.getType().isFunction())
+    {
+      d_sf_info[f].init(f);
+    }
+  }
+
+  // get the base on the conjecture
+  Node base = q[1];
+  std::unordered_set<Node, NodeHashFunction> synth_fv;
+  if (base.getKind() == NOT && base[0].getKind() == FORALL)
+  {
+    for (unsigned j = 0; j < base[0][0].getNumChildren(); j++)
+    {
+      synth_fv.insert(base[0][0][j]);
+    }
+    base = base[0][1];
+  }
+  std::vector<Node> conjuncts;
+  getComponentVector(AND, base, conjuncts);
+
+  // process the conjunctions
+  for (std::map<Node, CegConjectureProcessFun>::iterator it = d_sf_info.begin();
+       it != d_sf_info.end();
+       ++it)
+  {
+    Node f = it->first;
+    for (unsigned i = 0; i < conjuncts.size(); i++)
+    {
+      processConjunct(conjuncts[i], f, synth_fv);
+    }
+  }
+
+  return q;
+}
+
+void CegConjectureProcess::initialize(Node n, std::vector<Node>& candidates)
+{
+  if (Trace.isOn("sygus-process"))
+  {
+    Trace("sygus-process") << "Process conjecture : " << n
+                           << " with candidates: " << std::endl;
+    for (unsigned i = 0; i < candidates.size(); i++)
+    {
+      Trace("sygus-process") << "  " << candidates[i] << std::endl;
+    }
+  }
+}
+
+bool CegConjectureProcess::isArgRelevant(Node f, unsigned i)
+{
+  std::map<Node, CegConjectureProcessFun>::iterator its = d_sf_info.find(f);
+  if (its != d_sf_info.end())
+  {
+    return its->second.isArgRelevant(i);
+  }
+  Assert(false);
+  return true;
+}
+
+bool CegConjectureProcess::getIrrelevantArgs(Node f,
+                                             std::unordered_set<unsigned>& args)
+{
+  std::map<Node, CegConjectureProcessFun>::iterator its = d_sf_info.find(f);
+  if (its != d_sf_info.end())
+  {
+    its->second.getIrrelevantArgs(args);
+    return true;
+  }
+  return false;
+}
+
+void CegConjectureProcess::processConjunct(
+    Node n, Node f, std::unordered_set<Node, NodeHashFunction>& synth_fv)
+{
+  Trace("sygus-process-arg-deps") << "Process conjunct: " << std::endl;
+  Trace("sygus-process-arg-deps") << "  " << n << " for synth fun " << f
+                                  << "..." << std::endl;
+
+  // first, flatten the conjunct
+  // make a copy of free variables since we may add new ones
+  std::unordered_set<Node, NodeHashFunction> synth_fv_n = synth_fv;
+  std::unordered_map<Node, Node, NodeHashFunction> defs;
+  Node nf = flatten(n, f, synth_fv_n, defs);
+
+  Trace("sygus-process-arg-deps") << "Flattened to: " << std::endl;
+  Trace("sygus-process-arg-deps") << "  " << nf << std::endl;
+
+  // get free variables in nf
+  std::unordered_map<Node,
+                     std::unordered_set<Node, NodeHashFunction>,
+                     NodeHashFunction>
+      free_vars;
+  getFreeVariables(nf, synth_fv_n, free_vars);
+  // get free variables in each application
+  std::vector<Node> ns;
+  std::vector<Node> ks;
+  for (std::unordered_map<Node, Node, NodeHashFunction>::iterator it =
+           defs.begin();
+       it != defs.end();
+       ++it)
+  {
+    getFreeVariables(it->second, synth_fv_n, free_vars);
+    ns.push_back(it->second);
+    ks.push_back(it->first);
+  }
+
+  // process the applications of synthesis functions
+  if (!ns.empty())
+  {
+    std::map<Node, CegConjectureProcessFun>::iterator its = d_sf_info.find(f);
+    if (its != d_sf_info.end())
+    {
+      its->second.processTerms(ns, ks, nf, synth_fv_n, free_vars);
+    }
+  }
+}
+
+Node CegConjectureProcess::CegConjectureProcess::flatten(
+    Node n,
+    Node f,
+    std::unordered_set<Node, NodeHashFunction>& synth_fv,
+    std::unordered_map<Node, Node, NodeHashFunction>& defs)
+{
+  std::unordered_map<Node, Node, NodeHashFunction> visited;
+  std::unordered_map<Node, Node, NodeHashFunction>::iterator it;
+  std::stack<Node> visit;
+  Node cur;
+  visit.push(n);
+  do
+  {
+    cur = visit.top();
+    visit.pop();
+    it = visited.find(cur);
+
+    if (it == visited.end())
+    {
+      visited[cur] = Node::null();
+      visit.push(cur);
+      for (unsigned i = 0; i < cur.getNumChildren(); i++)
+      {
+        visit.push(cur[i]);
+      }
+    }
+    else if (it->second.isNull())
+    {
+      Node ret = cur;
+      bool childChanged = false;
+      std::vector<Node> children;
+      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
+      {
+        children.push_back(cur.getOperator());
+      }
+      for (unsigned i = 0; i < cur.getNumChildren(); i++)
+      {
+        it = visited.find(cur[i]);
+        Assert(it != visited.end());
+        Assert(!it->second.isNull());
+        childChanged = childChanged || cur[i] != it->second;
+        children.push_back(it->second);
+      }
+      if (childChanged)
+      {
+        ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
+      }
+      // is it the function to synthesize?
+      if (cur.getKind() == APPLY_UF && cur.getOperator() == f)
+      {
+        // if so, flatten
+        Node k = NodeManager::currentNM()->mkBoundVar("vf", cur.getType());
+        defs[k] = ret;
+        ret = k;
+        synth_fv.insert(k);
+      }
+      // post-rewrite
+      visited[cur] = ret;
+    }
+  } while (!visit.empty());
+  Assert(visited.find(n) != visited.end());
+  Assert(!visited.find(n)->second.isNull());
+  return visited[n];
+}
+
+void CegConjectureProcess::getFreeVariables(
+    Node n,
+    std::unordered_set<Node, NodeHashFunction>& synth_fv,
+    std::unordered_map<Node,
+                       std::unordered_set<Node, NodeHashFunction>,
+                       NodeHashFunction>& free_vars)
+{
+  // first must compute free variables in each subterm of n,
+  // as well as contains_synth_fun
+  std::unordered_map<Node, bool, NodeHashFunction> visited;
+  std::unordered_map<Node, bool, NodeHashFunction>::iterator it;
+  std::stack<Node> visit;
+  Node cur;
+  visit.push(n);
+  do
+  {
+    cur = visit.top();
+    visit.pop();
+    it = visited.find(cur);
+
+    if (it == visited.end())
+    {
+      visited[cur] = false;
+      visit.push(cur);
+      for (unsigned i = 0; i < cur.getNumChildren(); i++)
+      {
+        visit.push(cur[i]);
+      }
+    }
+    else if (!it->second)
+    {
+      free_vars[cur].clear();
+      if (synth_fv.find(cur) != synth_fv.end())
+      {
+        // it is a free variable
+        free_vars[cur].insert(cur);
+      }
+      else
+      {
+        // otherwise, carry the free variables from the children
+        for (unsigned i = 0; i < cur.getNumChildren(); i++)
+        {
+          free_vars[cur].insert(free_vars[cur[i]].begin(),
+                                free_vars[cur[i]].end());
+        }
+      }
+      visited[cur] = true;
+    }
+  } while (!visit.empty());
+}
+
+Node CegConjectureProcess::getSymmetryBreakingPredicate(
+    Node x, Node e, TypeNode tn, unsigned tindex, unsigned depth)
+{
+  return Node::null();
+}
+
+void CegConjectureProcess::debugPrint(const char* c) {}
+void CegConjectureProcess::getComponentVector(Kind k,
+                                              Node n,
+                                              std::vector<Node>& args)
+{
+  if (n.getKind() == k)
+  {
+    for (unsigned i = 0; i < n.getNumChildren(); i++)
+    {
+      args.push_back(n[i]);
+    }
+  }
+  else
+  {
+    args.push_back(n);
+  }
+}
+
+} /* namespace CVC4::theory::quantifiers */
+} /* namespace CVC4::theory */
+} /* namespace CVC4 */
diff --git a/src/theory/quantifiers/sygus/sygus_process_conj.h b/src/theory/quantifiers/sygus/sygus_process_conj.h
new file mode 100644 (file)
index 0000000..0b9a255
--- /dev/null
@@ -0,0 +1,365 @@
+/*********************                                                        */
+/*! \file sygus_process_conj.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Techniqures for static preprocessing and analysis of
+ ** sygus conjectures.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_PROCESS_CONJ_H
+#define __CVC4__THEORY__QUANTIFIERS__SYGUS_PROCESS_CONJ_H
+
+#include <map>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "expr/node.h"
+#include "expr/type_node.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+/** This file contains techniques that compute
+ * argument relevancy for synthesis functions
+ *
+ * Let F be a synthesis conjecture of the form:
+ *   exists f. forall X. P( f, X )
+ *
+ * The classes below compute whether certain arguments of
+ * the function-to-synthesize f are irrelevant.
+ * Assume that f is a binary function, where possible solutions
+ * to the above conjecture are of the form:
+ *   f -> (lambda (xy) t[x,y])
+ * We say e.g. that the 2nd argument of f is irrelevant if we
+ * can determine:
+ *   F has a solution
+ * if and only if
+ *   F has a solution of the form f -> (lambda (xy) t[x] )
+ * We conclude that arguments are irrelevant using the following
+ * techniques.
+ *
+ *
+ * (1) Argument invariance:
+ *
+ * Let s[z] be a term whose free variables are contained in { z }.
+ * If all occurrences of f-applications in F are of the form:
+ *   f(t, s[t])
+ * then:
+ *   f = (lambda (xy) r[x,y])
+ * is a solution to F only if:
+ *   f = (lambda (xy) r[x,s[x]])
+ * is as well.
+ * Hence the second argument of f is not relevant.
+ *
+ *
+ * (2) Variable irrelevance:
+ *
+ * If F is equivalent to:
+ *   exists f. forall w z u1...un. C1 ^...^Cm,
+ * where for i=1...m, Ci is of the form:
+ *   ( w1 = f(tm1[z], u1) ^
+ *     ... ^
+ *     wn = f(tmn[z], un) ) => Pm(w1...wn, z)
+ * then the second argument of f is irrelevant.
+ * We call u1...un single occurrence variables
+ * (in Ci).
+ *
+ *
+ * TODO (#1210) others, generalize (2)?
+ *
+ */
+
+/** This structure stores information regarding
+ * an argument of a function to synthesize.
+ *
+ * It is used to store whether the argument
+ * position in the function to synthesize is
+ * relevant.
+ */
+class CegConjectureProcessArg
+{
+ public:
+  CegConjectureProcessArg() : d_var_single_occ(false), d_relevant(false) {}
+  /** template definition
+   * This is the term s[z] described
+   * under "Argument Invariance" above.
+   */
+  Node d_template;
+  /** single occurrence
+   * Whether we are trying to show this argument
+   * is irrelevant by "Variable irrelevance"
+   * described above.
+   */
+  bool d_var_single_occ;
+  /** whether this argument is relevant
+   * An argument is marked as relevant if:
+   * (A) it is explicitly marked as relevant
+   *     due to a function application containing
+   *     a relevant term at this argument position, or
+   * (B) if it is given conflicting template definitions.
+   */
+  bool d_relevant;
+};
+
+/** This structure stores information regarding conjecture-specific
+* analysis of a single function to synthesize within
+* a conjecture to synthesize.
+*
+* It maintains information about each of the function to
+* synthesize's arguments.
+*/
+struct CegConjectureProcessFun
+{
+ public:
+  CegConjectureProcessFun() {}
+  ~CegConjectureProcessFun() {}
+  /** initialize this class for function f */
+  void init(Node f);
+  /** process terms
+   *
+   * This is called once per conjunction in
+   * the synthesis conjecture.
+   *
+   * ns are the f-applications to process,
+   * ks are the variables we introduced to flatten them,
+   * nf is the flattened form of our conjecture to process,
+   * free_vars maps all subterms of n and nf to the set
+   *   of variables (in set synth_fv) they contain.
+   *
+   * This updates information regarding which arguments
+   * of the function-to-synthesize are relevant.
+   */
+  void processTerms(
+      std::vector<Node>& ns,
+      std::vector<Node>& ks,
+      Node nf,
+      std::unordered_set<Node, NodeHashFunction>& synth_fv,
+      std::unordered_map<Node,
+                         std::unordered_set<Node, NodeHashFunction>,
+                         NodeHashFunction>& free_vars);
+  /** is the i^th argument of the function-to-synthesize of this class relevant?
+   */
+  bool isArgRelevant(unsigned i);
+  /** get irrelevant arguments for the function-to-synthesize of this class */
+  void getIrrelevantArgs(std::unordered_set<unsigned>& args);
+
+ private:
+  /** the synth fun associated with this */
+  Node d_synth_fun;
+  /** properties of each argument */
+  std::vector<CegConjectureProcessArg> d_arg_props;
+  /** variables for each argument type of f
+   *
+   * These are used to express templates for argument
+   * invariance, in the data member
+   * CegConjectureProcessArg::d_template.
+   */
+  std::vector<Node> d_arg_vars;
+  /** map from d_arg_vars to the argument #
+   * they represent.
+   */
+  std::unordered_map<Node, unsigned, NodeHashFunction> d_arg_var_num;
+  /** check match
+   * This function returns true iff we can infer:
+   *   cn * { x -> n_arg_map[d_arg_var_num[x]] | x in d_arg_vars } = n
+   * In other words, cn and n are equivalent
+   * via the substitution mapping argument variables to terms
+   * specified by n_arg_map. The rewriter is used for inferring
+   * this equivalence.
+   *
+   * For example, if n_arg_map contains { 1 -> t, 2 -> s }, then
+   *   checkMatch( x1+x2, t+s, n_arg_map ) returns true,
+   *   checkMatch( x1+1, t+1, n_arg_map ) returns true,
+   *   checkMatch( 0, 0, n_arg_map ) returns true,
+   *   checkMatch( x1+1, s, n_arg_map ) returns false.
+   */
+  bool checkMatch(Node cn,
+                  Node n,
+                  std::unordered_map<unsigned, Node>& n_arg_map);
+  /** infer definition
+   *
+   * In the following, we say a term is a "template
+   * definition" if its free variables are a subset of d_arg_vars.
+   *
+   * If this function returns a non-null node ret, then
+   *   checkMatch( ret, n, term_to_arg_carry^-1 ) returns true.
+   * and ret is a template definition.
+   *
+   * The free variables for all subterms of n are stored in
+   * free_vars. The map term_to_arg_carry is injective.
+   *
+   * For example, if term_to_arg_carry contains { t -> 1, s -> 2 } and
+   * free_vars is { t -> {y}, r -> {y}, s -> {}, q -> {}, ... -> {} }, then
+   *   inferDefinition( 0, term_to_arg_carry, free_vars )
+   *     returns 0
+   *   inferDefinition( t, term_to_arg_carry, free_vars )
+   *     returns x1
+   *   inferDefinition( t+s+q, term_to_arg_carry, free_vars )
+   *     returns x1+x2+q
+   *   inferDefinition( t+r, term_to_arg_carry, free_vars )
+   *     returns null
+   *
+   * Notice that multiple definitions are possible, e.g. above:
+   *  inferDefinition( s, term_to_arg_carry, free_vars )
+   *    may return either s or x2
+   * TODO (#1210) : try multiple definitions?
+   */
+  Node inferDefinition(
+      Node n,
+      std::unordered_map<Node, unsigned, NodeHashFunction>& term_to_arg_carry,
+      std::unordered_map<Node,
+                         std::unordered_set<Node, NodeHashFunction>,
+                         NodeHashFunction>& free_vars);
+  /** Assign relevant definition
+   *
+   * If def is non-null,
+   * this function assigns def as a template definition
+   * for the argument positions in args.
+   * This is called when there exists a term of the form
+   *   f( t1....tn )
+   * in the synthesis conjecture that we are processing,
+   * where t_i = def * sigma for all i \in args,
+   * for some substitution sigma, where def is a template
+   * definition.
+   *
+   * If def is null, then there exists a term of the form
+   *   f( t1....tn )
+   * where t_i = s for for all i \in args, and s is not
+   * a template definition. In this case, at least one
+   * argument in args must be marked as a relevant
+   * argument position.
+   *
+   * Returns a value rid such that:
+   * (1) rid occurs in args,
+   * (2) if def is null, then argument rid was marked
+   *     relevant by this call.
+   */
+  unsigned assignRelevantDef(Node def, std::vector<unsigned>& args);
+  /** returns true if n is in d_arg_vars, updates arg_index
+   * to its position in d_arg_vars.
+   */
+  bool isArgVar(Node n, unsigned& arg_index);
+};
+
+/** Ceg Conjecture Process
+*
+* This class implements static techniques for preprocessing and analysis of
+* sygus conjectures.
+*
+* It is used as a back-end to CegConjecture, which calls it using the following
+* interface:
+* (1) When a sygus conjecture is asserted, we call
+* CegConjectureProcess::simplify( q ),
+*     where q is the sygus conjecture in original form.
+*
+* (2) After a sygus conjecture is simplified and converted to deep
+* embedding form, we call CegConjectureProcess::initialize( n, candidates ).
+*
+* (3) During enumerative SyGuS search, calls may be made by
+* the extension of the quantifier-free datatypes decision procedure for
+* sygus to CegConjectureProcess::getSymmetryBreakingPredicate(...), which are
+* used for pruning search space based on conjecture-specific analysis.
+*/
+class CegConjectureProcess
+{
+ public:
+  CegConjectureProcess(QuantifiersEngine* qe);
+  ~CegConjectureProcess();
+  /** simplify the synthesis conjecture q
+  * Returns a formula that is equivalent to q.
+  * This simplification pass is called before all others
+  * in CegConjecture::assign.
+  *
+  * This function is intended for simplifications that
+  * impact whether or not the synthesis conjecture is
+  * single-invocation.
+  */
+  Node preSimplify(Node q);
+  /** simplify the synthesis conjecture q
+  * Returns a formula that is equivalent to q.
+  * This simplification pass is called after all others
+  * in CegConjecture::assign.
+  */
+  Node postSimplify(Node q);
+  /** initialize
+  *
+  * n is the "base instantiation" of the deep-embedding version of
+  *   the synthesis conjecture under "candidates".
+  *   (see CegConjecture::d_base_inst)
+  */
+  void initialize(Node n, std::vector<Node>& candidates);
+  /** is the i^th argument of the function-to-synthesize f relevant? */
+  bool isArgRelevant(Node f, unsigned i);
+  /** get irrelevant arguments for function-to-synthesize f
+   * returns true if f is a function-to-synthesize.
+   */
+  bool getIrrelevantArgs(Node f, std::unordered_set<unsigned>& args);
+  /** get symmetry breaking predicate
+  *
+  * Returns a formula that restricts the enumerative search space (for a given
+  * depth) for a term x of sygus type tn whose top symbol is the tindex^{th}
+  * constructor, where x is a subterm of enumerator e.
+  */
+  Node getSymmetryBreakingPredicate(
+      Node x, Node e, TypeNode tn, unsigned tindex, unsigned depth);
+  /** print out debug information about this conjecture */
+  void debugPrint(const char* c);
+ private:
+  /** process conjunct
+   *
+   * This sets up initial information about functions to synthesize
+   * where n is a conjunct of the synthesis conjecture, and synth_fv
+   * is the set of (inner) universal variables in the synthesis
+   * conjecture.
+   */
+  void processConjunct(Node n,
+                       Node f,
+                       std::unordered_set<Node, NodeHashFunction>& synth_fv);
+  /** flatten
+   *
+   * Flattens all applications of f in term n.
+   * This may add new variables to synth_fv, which
+   * are introduced at all positions of functions
+   * to synthesize in a bottom-up fashion. For each
+   * variable k introduced for a function application
+   * f(t), we add ( k -> f(t) ) to defs and ( f -> k )
+   * to fun_to_defs.
+   */
+  Node flatten(Node n,
+               Node f,
+               std::unordered_set<Node, NodeHashFunction>& synth_fv,
+               std::unordered_map<Node, Node, NodeHashFunction>& defs);
+  /** get free variables
+   * Constructs a map of all free variables that occur in n
+   * from synth_fv and stores them in the map free_vars.
+   */
+  void getFreeVariables(
+      Node n,
+      std::unordered_set<Node, NodeHashFunction>& synth_fv,
+      std::unordered_map<Node,
+                         std::unordered_set<Node, NodeHashFunction>,
+                         NodeHashFunction>& free_vars);
+  /** for each synth-fun, information that is specific to this conjecture */
+  std::map<Node, CegConjectureProcessFun> d_sf_info;
+
+  /** get component vector */
+  void getComponentVector(Kind k, Node n, std::vector<Node>& args);
+};
+
+} /* namespace CVC4::theory::quantifiers */
+} /* namespace CVC4::theory */
+} /* namespace CVC4 */
+
+#endif
diff --git a/src/theory/quantifiers/sygus/term_database_sygus.cpp b/src/theory/quantifiers/sygus/term_database_sygus.cpp
new file mode 100644 (file)
index 0000000..b12a23c
--- /dev/null
@@ -0,0 +1,1487 @@
+/*********************                                                        */
+/*! \file term_database_sygus.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of term database sygus class
+ **/
+
+#include "theory/quantifiers/sygus/term_database_sygus.h"
+
+#include "options/quantifiers_options.h"
+#include "theory/arith/arith_msum.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+#include "theory/quantifiers_engine.h"
+
+using namespace std;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory::inst;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+TermDbSygus::TermDbSygus(context::Context* c, QuantifiersEngine* qe)
+    : d_quantEngine(qe),
+      d_syexp(new SygusExplain(this)),
+      d_ext_rw(new ExtendedRewriter(true))
+{
+  d_true = NodeManager::currentNM()->mkConst( true );
+  d_false = NodeManager::currentNM()->mkConst( false );
+}
+
+bool TermDbSygus::reset( Theory::Effort e ) { 
+  return true;  
+}
+
+TNode TermDbSygus::getFreeVar( TypeNode tn, int i, bool useSygusType ) {
+  unsigned sindex = 0;
+  TypeNode vtn = tn;
+  if( useSygusType ){
+    if( tn.isDatatype() ){
+      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+      if( !dt.getSygusType().isNull() ){
+        vtn = TypeNode::fromType( dt.getSygusType() );
+        sindex = 1;
+      } 
+    }
+  }
+  while( i>=(int)d_fv[sindex][tn].size() ){
+    std::stringstream ss;
+    if( tn.isDatatype() ){
+      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+      ss << "fv_" << dt.getName() << "_" << i;
+    }else{
+      ss << "fv_" << tn << "_" << i;
+    }
+    Assert( !vtn.isNull() );
+    Node v = NodeManager::currentNM()->mkSkolem( ss.str(), vtn, "for sygus normal form testing" );
+    d_fv_stype[v] = tn;
+    d_fv_num[v] = i;
+    d_fv[sindex][tn].push_back( v );
+  }
+  return d_fv[sindex][tn][i];
+}
+
+TNode TermDbSygus::getFreeVarInc( TypeNode tn, std::map< TypeNode, int >& var_count, bool useSygusType ) {
+  std::map< TypeNode, int >::iterator it = var_count.find( tn );
+  if( it==var_count.end() ){
+    var_count[tn] = 1;
+    return getFreeVar( tn, 0, useSygusType );
+  }else{
+    int index = it->second;
+    var_count[tn]++;
+    return getFreeVar( tn, index, useSygusType );
+  }
+}
+
+bool TermDbSygus::hasFreeVar( Node n, std::map< Node, bool >& visited ){
+  if( visited.find( n )==visited.end() ){
+    visited[n] = true;
+    if( isFreeVar( n ) ){
+      return true;    
+    }
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      if( hasFreeVar( n[i], visited ) ){
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool TermDbSygus::hasFreeVar( Node n ) {
+  std::map< Node, bool > visited;
+  return hasFreeVar( n, visited );
+}
+  
+TypeNode TermDbSygus::getSygusTypeForVar( Node v ) {
+  Assert( d_fv_stype.find( v )!=d_fv_stype.end() );
+  return d_fv_stype[v];
+}
+
+Node TermDbSygus::mkGeneric(const Datatype& dt,
+                            unsigned c,
+                            std::map<TypeNode, int>& var_count,
+                            std::map<int, Node>& pre)
+{
+  Assert(c < dt.getNumConstructors());
+  Assert( dt.isSygus() );
+  Assert( !dt[c].getSygusOp().isNull() );
+  std::vector< Node > children;
+  Node op = Node::fromExpr( dt[c].getSygusOp() );
+  if( op.getKind()!=BUILTIN ){
+    children.push_back( op );
+  }
+  Trace("sygus-db-debug") << "mkGeneric " << dt.getName() << " " << op << " " << op.getKind() << "..." << std::endl;
+  for (unsigned i = 0, nargs = dt[c].getNumArgs(); i < nargs; i++)
+  {
+    TypeNode tna = getArgType( dt[c], i );
+    Node a;
+    std::map< int, Node >::iterator it = pre.find( i );
+    if( it!=pre.end() ){
+      a = it->second;
+    }else{
+      a = getFreeVarInc( tna, var_count, true );
+    }
+    Trace("sygus-db-debug")
+        << "  child " << i << " : " << a << " : " << a.getType() << std::endl;
+    Assert( !a.isNull() );
+    children.push_back( a );
+  }
+  Node ret;
+  if( op.getKind()==BUILTIN ){
+    Trace("sygus-db-debug") << "Make builtin node..." << std::endl;
+    ret = NodeManager::currentNM()->mkNode( op, children );
+  }else{
+    Kind ok = getOperatorKind( op );
+    Trace("sygus-db-debug") << "Operator kind is " << ok << std::endl;
+    if( children.size()==1 && ok==kind::UNDEFINED_KIND ){
+      ret = children[0];
+    }else{
+      ret = NodeManager::currentNM()->mkNode( ok, children );
+    }
+  }
+  Trace("sygus-db-debug") << "...returning " << ret << std::endl;
+  return ret;
+}
+
+Node TermDbSygus::mkGeneric(const Datatype& dt, int c, std::map<int, Node>& pre)
+{
+  std::map<TypeNode, int> var_count;
+  return mkGeneric(dt, c, var_count, pre);
+}
+
+Node TermDbSygus::sygusToBuiltin( Node n, TypeNode tn ) {
+  Assert( n.getType()==tn );
+  Assert( tn.isDatatype() );
+  std::map< Node, Node >::iterator it = d_sygus_to_builtin[tn].find( n );
+  if( it==d_sygus_to_builtin[tn].end() ){
+    Trace("sygus-db-debug") << "SygusToBuiltin : compute for " << n << ", type = " << tn << std::endl;
+    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+    if( n.getKind()==APPLY_CONSTRUCTOR ){
+      unsigned i = Datatype::indexOf( n.getOperator().toExpr() );
+      Assert( n.getNumChildren()==dt[i].getNumArgs() );
+      std::map< TypeNode, int > var_count;
+      std::map< int, Node > pre;
+      for (unsigned j = 0, size = n.getNumChildren(); j < size; j++)
+      {
+        pre[j] = sygusToBuiltin( n[j], getArgType( dt[i], j ) );
+      }
+      Node ret = mkGeneric(dt, i, var_count, pre);
+      Trace("sygus-db-debug") << "SygusToBuiltin : Generic is " << ret << std::endl;
+      d_sygus_to_builtin[tn][n] = ret;
+      return ret;
+    }
+    if (n.hasAttribute(SygusPrintProxyAttribute()))
+    {
+      // this variable was associated by an attribute to a builtin node
+      return n.getAttribute(SygusPrintProxyAttribute());
+    }
+    Assert(isFreeVar(n));
+    // map to builtin variable type
+    int fv_num = getVarNum(n);
+    Assert(!dt.getSygusType().isNull());
+    TypeNode vtn = TypeNode::fromType(dt.getSygusType());
+    Node ret = getFreeVar(vtn, fv_num);
+    return ret;
+  }else{
+    return it->second;
+  }
+}
+
+Node TermDbSygus::sygusSubstituted( TypeNode tn, Node n, std::vector< Node >& args ) {
+  Assert( d_var_list[tn].size()==args.size() );
+  return n.substitute( d_var_list[tn].begin(), d_var_list[tn].end(), args.begin(), args.end() );
+}
+
+unsigned TermDbSygus::getSygusTermSize( Node n ){
+  if( n.getNumChildren()==0 ){
+    return 0;
+  }else{
+    Assert(n.getKind() == APPLY_CONSTRUCTOR);
+    unsigned sum = 0;
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      sum += getSygusTermSize( n[i] );
+    }
+    const Datatype& dt = Datatype::datatypeOf(n.getOperator().toExpr());
+    int cindex = Datatype::indexOf(n.getOperator().toExpr());
+    Assert(cindex >= 0 && cindex < (int)dt.getNumConstructors());
+    unsigned weight = dt[cindex].getWeight();
+    return weight + sum;
+  }
+}
+
+class ReqTrie {
+public:
+  ReqTrie() : d_req_kind( UNDEFINED_KIND ){}
+  std::map< unsigned, ReqTrie > d_children;
+  Kind d_req_kind;
+  TypeNode d_req_type;
+  Node d_req_const;
+  void print( const char * c, int indent = 0 ){
+    if( d_req_kind!=UNDEFINED_KIND ){
+      Trace(c) << d_req_kind << " ";
+    }else if( !d_req_type.isNull() ){
+      Trace(c) << d_req_type;
+    }else if( !d_req_const.isNull() ){
+      Trace(c) << d_req_const;
+    }else{
+      Trace(c) << "_";
+    }
+    Trace(c) << std::endl;
+    for( std::map< unsigned, ReqTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+      for( int i=0; i<=indent; i++ ) { Trace(c) << "  "; }
+      Trace(c) << it->first << " : ";
+      it->second.print( c, indent+1 );
+    }
+  }
+  bool satisfiedBy( quantifiers::TermDbSygus * tdb, TypeNode tn ){
+    if( !d_req_const.isNull() ){
+      if( !tdb->hasConst( tn, d_req_const ) ){
+        return false;
+      }
+    }
+    if( !d_req_type.isNull() ){
+      if( tn!=d_req_type ){
+        return false;
+      }
+    }
+    if( d_req_kind!=UNDEFINED_KIND ){
+      int c = tdb->getKindConsNum( tn, d_req_kind );
+      if( c!=-1 ){
+        bool ret = true;
+        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+        for( std::map< unsigned, ReqTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+          if( it->first<dt[c].getNumArgs() ){
+            TypeNode tnc = tdb->getArgType( dt[c], it->first );
+            if( !it->second.satisfiedBy( tdb, tnc ) ){
+              ret = false;
+              break;
+            }
+          }else{
+            ret = false;
+            break;
+          }
+        }
+        if( !ret ){
+          return false;
+        }
+        // TODO : commutative operators try both?
+      }else{
+        return false;
+      }
+    }
+    return true;
+  }
+  bool empty() {
+    return d_req_kind==UNDEFINED_KIND && d_req_const.isNull() && d_req_type.isNull();
+  }
+};
+
+//this function gets all easy redundant cases, before consulting rewriters
+bool TermDbSygus::considerArgKind( TypeNode tn, TypeNode tnp, Kind k, Kind pk, int arg ) {
+  const Datatype& pdt = ((DatatypeType)(tnp).toType()).getDatatype();
+  const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+  Assert( hasKind( tn, k ) );
+  Assert( hasKind( tnp, pk ) );
+  Trace("sygus-sb-debug") << "Consider sygus arg kind " << k << ", pk = " << pk << ", arg = " << arg << "?" << std::endl;
+  int c = getKindConsNum( tn, k );
+  int pc = getKindConsNum( tnp, pk );
+  if( k==pk ){
+    //check for associativity
+    if( quantifiers::TermUtil::isAssoc( k ) ){
+      //if the operator is associative, then a repeated occurrence should only occur in the leftmost argument position
+      int firstArg = getFirstArgOccurrence( pdt[pc], tn );
+      Assert( firstArg!=-1 );
+      if( arg!=firstArg ){
+        Trace("sygus-sb-simple") << "  sb-simple : do not consider " << k << " at child arg " << arg << " of " << k << " since it is associative, with first arg = " << firstArg << std::endl;
+        return false;
+      }else{
+        return true;
+      }
+    }
+  }
+  //describes the shape of an alternate term to construct
+  //  we check whether this term is in the sygus grammar below
+  ReqTrie rt;
+  Assert( rt.empty() );
+  
+  //construct rt by cases
+  if( pk==NOT || pk==BITVECTOR_NOT || pk==UMINUS || pk==BITVECTOR_NEG ){
+    //negation normal form
+    if( pk==k ){
+      rt.d_req_type = getArgType( dt[c], 0 );
+    }else{
+      Kind reqk = UNDEFINED_KIND;       //required kind for all children
+      std::map< unsigned, Kind > reqkc; //required kind for some children
+      if( pk==NOT ){
+        if( k==AND ) {
+          rt.d_req_kind = OR;reqk = NOT;
+        }else if( k==OR ){
+          rt.d_req_kind = AND;reqk = NOT;
+        //AJR : eliminate this if we eliminate xor
+        }else if( k==EQUAL ) {
+          rt.d_req_kind = XOR;
+        }else if( k==XOR ) {
+          rt.d_req_kind = EQUAL;
+        }else if( k==ITE ){
+          rt.d_req_kind = ITE;reqkc[1] = NOT;reqkc[2] = NOT;
+          rt.d_children[0].d_req_type = getArgType( dt[c], 0 );
+        }else if( k==LEQ || k==GT ){
+          //  (not (~ x y)) ----->  (~ (+ y 1) x)
+          rt.d_req_kind = k;
+          rt.d_children[0].d_req_kind = PLUS;
+          rt.d_children[0].d_children[0].d_req_type = getArgType( dt[c], 1 );
+          rt.d_children[0].d_children[1].d_req_const = NodeManager::currentNM()->mkConst( Rational( 1 ) );
+          rt.d_children[1].d_req_type = getArgType( dt[c], 0 );
+          //TODO: other possibilities?
+        }else if( k==LT || k==GEQ ){
+          //  (not (~ x y)) ----->  (~ y (+ x 1))
+          rt.d_req_kind = k;
+          rt.d_children[0].d_req_type = getArgType( dt[c], 1 );
+          rt.d_children[1].d_req_kind = PLUS;
+          rt.d_children[1].d_children[0].d_req_type = getArgType( dt[c], 0 );
+          rt.d_children[1].d_children[1].d_req_const = NodeManager::currentNM()->mkConst( Rational( 1 ) );
+        }
+      }else if( pk==BITVECTOR_NOT ){
+        if( k==BITVECTOR_AND ) {
+          rt.d_req_kind = BITVECTOR_OR;reqk = BITVECTOR_NOT;
+        }else if( k==BITVECTOR_OR ){
+          rt.d_req_kind = BITVECTOR_AND;reqk = BITVECTOR_NOT;
+        }else if( k==BITVECTOR_XNOR ) {
+          rt.d_req_kind = BITVECTOR_XOR;
+        }else if( k==BITVECTOR_XOR ) {
+          rt.d_req_kind = BITVECTOR_XNOR;
+        }
+      }else if( pk==UMINUS ){
+        if( k==PLUS ){
+          rt.d_req_kind = PLUS;reqk = UMINUS;
+        }
+      }else if( pk==BITVECTOR_NEG ){
+        if( k==PLUS ){
+          rt.d_req_kind = PLUS;reqk = BITVECTOR_NEG;
+        }
+      }
+      if( !rt.empty() && ( reqk!=UNDEFINED_KIND || !reqkc.empty() ) ){
+        int pcr = getKindConsNum( tnp, rt.d_req_kind );
+        if( pcr!=-1 ){
+          Assert( pcr<(int)pdt.getNumConstructors() );
+          //must have same number of arguments
+          if( pdt[pcr].getNumArgs()==dt[c].getNumArgs() ){
+            for( unsigned i=0; i<pdt[pcr].getNumArgs(); i++ ){
+              Kind rk = reqk;
+              if( reqk==UNDEFINED_KIND ){
+                std::map< unsigned, Kind >::iterator itr = reqkc.find( i );
+                if( itr!=reqkc.end() ){
+                  rk = itr->second;
+                }
+              }
+              if( rk!=UNDEFINED_KIND ){
+                rt.d_children[i].d_req_kind = rk;
+                rt.d_children[i].d_children[0].d_req_type = getArgType( dt[c], i );
+              }
+            }
+          }
+        }
+      }
+    }
+  }else if( k==MINUS || k==BITVECTOR_SUB ){
+    if( pk==EQUAL || 
+        pk==MINUS || pk==BITVECTOR_SUB || 
+        pk==LEQ || pk==LT || pk==GEQ || pk==GT ){
+      int oarg = arg==0 ? 1 : 0;
+      //  (~ x (- y z))  ---->  (~ (+ x z) y)
+      //  (~ (- y z) x)  ---->  (~ y (+ x z))
+      rt.d_req_kind = pk;
+      rt.d_children[arg].d_req_type = getArgType( dt[c], 0 );
+      rt.d_children[oarg].d_req_kind = k==MINUS ? PLUS : BITVECTOR_PLUS;
+      rt.d_children[oarg].d_children[0].d_req_type = getArgType( pdt[pc], oarg );
+      rt.d_children[oarg].d_children[1].d_req_type = getArgType( dt[c], 1 );
+    }else if( pk==PLUS || pk==BITVECTOR_PLUS ){
+      //  (+ x (- y z))  -----> (- (+ x y) z)
+      //  (+ (- y z) x)  -----> (- (+ x y) z)
+      rt.d_req_kind = pk==PLUS ? MINUS : BITVECTOR_SUB;
+      int oarg = arg==0 ? 1 : 0;
+      rt.d_children[0].d_req_kind = pk;
+      rt.d_children[0].d_children[0].d_req_type = getArgType( pdt[pc], oarg );
+      rt.d_children[0].d_children[1].d_req_type = getArgType( dt[c], 0 );
+      rt.d_children[1].d_req_type = getArgType( dt[c], 1 );
+      // TODO : this is subsumbed by solving for MINUS
+    }
+  }else if( k==ITE ){
+    if( pk!=ITE ){
+      //  (o X (ite y z w) X')  -----> (ite y (o X z X') (o X w X'))
+      rt.d_req_kind = ITE;
+      rt.d_children[0].d_req_type = getArgType( dt[c], 0 );
+      unsigned n_args = pdt[pc].getNumArgs();
+      for( unsigned r=1; r<=2; r++ ){
+        rt.d_children[r].d_req_kind = pk;
+        for( unsigned q=0; q<n_args; q++ ){
+          if( (int)q==arg ){
+            rt.d_children[r].d_children[q].d_req_type = getArgType( dt[c], r );
+          }else{
+            rt.d_children[r].d_children[q].d_req_type = getArgType( pdt[pc], q );
+          }
+        }
+      }
+      //TODO: this increases term size but is probably a good idea
+    }
+  }else if( k==NOT ){
+    if( pk==ITE ){
+      //  (ite (not y) z w)  -----> (ite y w z)
+      rt.d_req_kind = ITE;
+      rt.d_children[0].d_req_type = getArgType( dt[c], 0 );
+      rt.d_children[1].d_req_type = getArgType( pdt[pc], 2 );
+      rt.d_children[2].d_req_type = getArgType( pdt[pc], 1 );
+    }
+  }
+  Trace("sygus-sb-debug") << "Consider sygus arg kind " << k << ", pk = " << pk << ", arg = " << arg << "?" << std::endl;
+  if( !rt.empty() ){
+    rt.print("sygus-sb-debug");
+    //check if it meets the requirements
+    if( rt.satisfiedBy( this, tnp ) ){
+      Trace("sygus-sb-debug") << "...success!" << std::endl;
+      Trace("sygus-sb-simple") << "  sb-simple : do not consider " << k << " as arg " << arg << " of " << pk << std::endl;
+      //do not need to consider the kind in the search since there are ways to construct equivalent terms
+      return false;
+    }else{
+      Trace("sygus-sb-debug") << "...failed." << std::endl;
+    }
+    Trace("sygus-sb-debug") << std::endl;
+  }
+  //must consider this kind in the search  
+  return true;
+}
+
+bool TermDbSygus::considerConst( TypeNode tn, TypeNode tnp, Node c, Kind pk, int arg ) {
+  const Datatype& pdt = ((DatatypeType)(tnp).toType()).getDatatype();
+  // child grammar-independent
+  if( !considerConst( pdt, tnp, c, pk, arg ) ){
+    return false;
+  }
+  // TODO : this can probably be made child grammar independent
+  int pc = getKindConsNum( tnp, pk );
+  if( pdt[pc].getNumArgs()==2 ){
+    Kind ok;
+    int offset;
+    if (d_quantEngine->getTermUtil()->hasOffsetArg(pk, arg, offset, ok))
+    {
+      Trace("sygus-sb-simple-debug") << pk << " has offset arg " << ok << " " << offset << std::endl;
+      int ok_arg = getKindConsNum( tnp, ok );
+      if( ok_arg!=-1 ){
+        Trace("sygus-sb-simple-debug") << "...at argument " << ok_arg << std::endl;
+        //other operator be the same type
+        if( isTypeMatch( pdt[ok_arg], pdt[arg] ) ){
+          int status;
+          Node co = d_quantEngine->getTermUtil()->getTypeValueOffset(
+              c.getType(), c, offset, status);
+          Trace("sygus-sb-simple-debug") << c << " with offset " << offset << " is " << co << ", status=" << status << std::endl;
+          if( status==0 && !co.isNull() ){
+            if( hasConst( tn, co ) ){
+              Trace("sygus-sb-simple") << "  sb-simple : by offset reasoning, do not consider const " << c;
+              Trace("sygus-sb-simple") << " as arg " << arg << " of " << pk << " since we can use " << co << " under " << ok << " " << std::endl;
+              return false;
+            }
+          }
+        }
+      }
+    }
+  }
+  return true;
+}
+
+bool TermDbSygus::considerConst( const Datatype& pdt, TypeNode tnp, Node c, Kind pk, int arg ) {
+  Assert( hasKind( tnp, pk ) );
+  int pc = getKindConsNum( tnp, pk );
+  bool ret = true;
+  Trace("sygus-sb-debug") << "Consider sygus const " << c << ", parent = " << pk << ", arg = " << arg << "?" << std::endl;
+  if (d_quantEngine->getTermUtil()->isIdempotentArg(c, pk, arg))
+  {
+    if( pdt[pc].getNumArgs()==2 ){
+      int oarg = arg==0 ? 1 : 0;
+      TypeNode otn = TypeNode::fromType( ((SelectorType)pdt[pc][oarg].getType()).getRangeType() );
+      if( otn==tnp ){
+        Trace("sygus-sb-simple") << "  sb-simple : " << c << " is idempotent arg " << arg << " of " << pk << "..." << std::endl;
+        ret = false;
+      }
+    }
+  }else{
+    Node sc = d_quantEngine->getTermUtil()->isSingularArg(c, pk, arg);
+    if( !sc.isNull() ){
+      if( hasConst( tnp, sc ) ){
+        Trace("sygus-sb-simple") << "  sb-simple : " << c << " is singular arg " << arg << " of " << pk << ", evaluating to " << sc << "..." << std::endl;
+        ret = false;
+      }
+    }
+  }
+  if( ret ){
+    ReqTrie rt;
+    Assert( rt.empty() );
+    Node max_c = d_quantEngine->getTermUtil()->getTypeMaxValue(c.getType());
+    Node zero_c = d_quantEngine->getTermUtil()->getTypeValue(c.getType(), 0);
+    Node one_c = d_quantEngine->getTermUtil()->getTypeValue(c.getType(), 1);
+    if( pk==XOR || pk==BITVECTOR_XOR ){
+      if( c==max_c ){
+        rt.d_req_kind = pk==XOR ? NOT : BITVECTOR_NOT;
+      }
+    }else if( pk==ITE ){
+      if( arg==0 ){
+        if( c==max_c ){
+          rt.d_children[2].d_req_type = tnp;
+        }else if( c==zero_c ){
+          rt.d_children[1].d_req_type = tnp;
+        }
+      }
+    }else if( pk==STRING_SUBSTR ){
+      if( c==one_c ){
+        rt.d_req_kind = STRING_CHARAT;
+        rt.d_children[0].d_req_type = getArgType( pdt[pc], 0 );
+        rt.d_children[1].d_req_type = getArgType( pdt[pc], 1 );
+      }
+    }
+    if( !rt.empty() ){
+      //check if satisfied
+      if( rt.satisfiedBy( this, tnp ) ){
+        Trace("sygus-sb-simple") << "  sb-simple : do not consider const " << c << " as arg " << arg << " of " << pk;
+        Trace("sygus-sb-simple") << " in " << ((DatatypeType)tnp.toType()).getDatatype().getName() << std::endl;
+        //do not need to consider the constant in the search since there are ways to construct equivalent terms
+        ret = false;
+      }
+    }
+  }
+  // TODO : cache?
+  return ret;
+}
+
+int TermDbSygus::solveForArgument( TypeNode tn, unsigned cindex, unsigned arg ) {
+  // FIXME
+  return -1;  // TODO : if using, modify considerArgKind above
+  Assert( isRegistered( tn ) );
+  const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+  Assert( cindex<dt.getNumConstructors() );
+  Assert( arg<dt[cindex].getNumArgs() );
+  Kind nk = getConsNumKind( tn, cindex );
+  TypeNode tnc = getArgType( dt[cindex], arg );
+  const Datatype& cdt = ((DatatypeType)(tnc).toType()).getDatatype();
+
+  ReqTrie rt;
+  Assert( rt.empty() );
+  int solve_ret = -1;
+  if( nk==MINUS || nk==BITVECTOR_SUB ){
+    if( dt[cindex].getNumArgs()==2 && arg==0 ){
+      TypeNode tnco = getArgType( dt[cindex], 1 );
+      Node builtin = d_quantEngine->getTermUtil()->getTypeValue(
+          sygusToBuiltinType(tnc), 0);
+      solve_ret = getConstConsNum( tn, builtin );
+      if( solve_ret!=-1 ){
+        // t - s    ----->  ( 0 - s ) + t
+        rt.d_req_kind = nk == MINUS ? PLUS : BITVECTOR_PLUS;
+        rt.d_children[0].d_req_type = tn; // avoid?
+        rt.d_children[0].d_req_kind = nk;
+        rt.d_children[0].d_children[0].d_req_const = builtin;
+        rt.d_children[0].d_children[0].d_req_type = tnco;
+        rt.d_children[1].d_req_type = tnc;
+        // TODO : this can be made more general for multiple type grammars to remove MINUS entirely 
+      }
+    }
+  }
+  
+  if( !rt.empty() ){
+    Assert( solve_ret>=0 );
+    Assert( solve_ret<=(int)cdt.getNumConstructors() );
+    //check if satisfied
+    if( rt.satisfiedBy( this, tn ) ){
+      Trace("sygus-sb-simple") << "  sb-simple : ONLY consider " << cdt[solve_ret].getSygusOp() << " as arg " << arg << " of " << nk;
+      Trace("sygus-sb-simple") << " in " << ((DatatypeType)tn.toType()).getDatatype().getName() << std::endl;
+      return solve_ret;
+    }
+  }
+  
+  return -1;
+}
+
+void TermDbSygus::registerSygusType( TypeNode tn ) {
+  std::map< TypeNode, TypeNode >::iterator itr = d_register.find( tn );
+  if( itr==d_register.end() ){
+    d_register[tn] = TypeNode::null();
+    if( tn.isDatatype() ){
+      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+      Trace("sygus-db") << "Register type " << dt.getName() << "..." << std::endl;
+      TypeNode btn = TypeNode::fromType( dt.getSygusType() );
+      d_register[tn] = btn;
+      if( !d_register[tn].isNull() ){
+        // get the sygus variable list
+        Node var_list = Node::fromExpr( dt.getSygusVarList() );
+        if( !var_list.isNull() ){
+          for( unsigned j=0; j<var_list.getNumChildren(); j++ ){
+            Node sv = var_list[j];
+            SygusVarNumAttribute svna;
+            sv.setAttribute( svna, j );
+            d_var_list[tn].push_back( sv );
+          }
+        }else{
+          // no arguments to synthesis functions
+        }
+        //iterate over constructors
+        for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+          Expr sop = dt[i].getSygusOp();
+          Assert( !sop.isNull() );
+          Node n = Node::fromExpr( sop );
+          Trace("sygus-db") << "  Operator #" << i << " : " << sop;
+          if( sop.getKind() == kind::BUILTIN ){
+            Kind sk = NodeManager::operatorToKind( n );
+            Trace("sygus-db") << ", kind = " << sk;
+            d_kinds[tn][sk] = i;
+            d_arg_kind[tn][i] = sk;
+          }else if( sop.isConst() ){
+            Trace("sygus-db") << ", constant";
+            d_consts[tn][n] = i;
+            d_arg_const[tn][i] = n;
+          }
+          d_ops[tn][n] = i;
+          d_arg_ops[tn][i] = n;
+          Trace("sygus-db") << std::endl;
+        }
+        //register connected types
+        for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+          for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
+            registerSygusType( getArgType( dt[i], j ) );
+          }
+        }
+      }
+    }
+  }
+}
+
+void TermDbSygus::registerEnumerator(Node e,
+                                     Node f,
+                                     CegConjecture* conj,
+                                     bool mkActiveGuard)
+{
+  Assert(d_enum_to_conjecture.find(e) == d_enum_to_conjecture.end());
+  Trace("sygus-db") << "Register measured term : " << e << std::endl;
+  d_enum_to_conjecture[e] = conj;
+  d_enum_to_synth_fun[e] = f;
+  if( mkActiveGuard ){
+    // make the guard
+    Node eg = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "eG", NodeManager::currentNM()->booleanType() ) );
+    eg = d_quantEngine->getValuation().ensureLiteral( eg );
+    AlwaysAssert( !eg.isNull() );
+    d_quantEngine->getOutputChannel().requirePhase( eg, true );
+    //add immediate lemma
+    Node lem = NodeManager::currentNM()->mkNode( OR, eg, eg.negate() );
+    Trace("cegqi-lemma") << "Cegqi::Lemma : enumerator : " << lem << std::endl;
+    d_quantEngine->getOutputChannel().lemma( lem );
+    d_enum_to_active_guard[e] = eg;
+  }
+}
+
+bool TermDbSygus::isEnumerator(Node e) const
+{
+  return d_enum_to_conjecture.find(e) != d_enum_to_conjecture.end();
+}
+
+CegConjecture* TermDbSygus::getConjectureForEnumerator(Node e)
+{
+  std::map<Node, CegConjecture*>::iterator itm = d_enum_to_conjecture.find(e);
+  if (itm != d_enum_to_conjecture.end()) {
+    return itm->second;
+  }else{
+    return NULL;
+  }
+}
+
+Node TermDbSygus::getSynthFunForEnumerator(Node e)
+{
+  std::map<Node, Node>::iterator itsf = d_enum_to_synth_fun.find(e);
+  if (itsf != d_enum_to_synth_fun.end())
+  {
+    return itsf->second;
+  }
+  else
+  {
+    return Node::null();
+  }
+}
+
+Node TermDbSygus::getActiveGuardForEnumerator(Node e)
+{
+  std::map<Node, Node>::iterator itag = d_enum_to_active_guard.find(e);
+  if (itag != d_enum_to_active_guard.end()) {
+    return itag->second;
+  }else{
+    return Node::null();
+  }
+}
+
+void TermDbSygus::getEnumerators(std::vector<Node>& mts)
+{
+  for (std::map<Node, CegConjecture*>::iterator itm =
+           d_enum_to_conjecture.begin();
+       itm != d_enum_to_conjecture.end(); ++itm) {
+    mts.push_back( itm->first );
+  }
+}
+
+bool TermDbSygus::isRegistered( TypeNode tn ) {
+  return d_register.find( tn )!=d_register.end();
+}
+
+TypeNode TermDbSygus::sygusToBuiltinType( TypeNode tn ) {
+  Assert( isRegistered( tn ) );
+  return d_register[tn];
+}
+
+void TermDbSygus::computeMinTypeDepthInternal( TypeNode root_tn, TypeNode tn, unsigned type_depth ) {
+  std::map< TypeNode, unsigned >::iterator it = d_min_type_depth[root_tn].find( tn );
+  if( it==d_min_type_depth[root_tn].end() || type_depth<it->second ){
+    d_min_type_depth[root_tn][tn] = type_depth;
+    Assert( tn.isDatatype() );
+    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+    //compute for connected types
+    for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+      for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
+        computeMinTypeDepthInternal( root_tn, getArgType( dt[i], j ), type_depth+1 );
+      }
+    }
+  }
+}
+  
+unsigned TermDbSygus::getMinTypeDepth( TypeNode root_tn, TypeNode tn ){
+  std::map< TypeNode, unsigned >::iterator it = d_min_type_depth[root_tn].find( tn );
+  if( it==d_min_type_depth[root_tn].end() ){
+    computeMinTypeDepthInternal( root_tn, root_tn, 0 );
+    Assert( d_min_type_depth[root_tn].find( tn )!=d_min_type_depth[root_tn].end() );  
+    return d_min_type_depth[root_tn][tn];
+  }else{
+    return it->second;
+  }
+}
+
+unsigned TermDbSygus::getMinTermSize( TypeNode tn ) {
+  Assert( isRegistered( tn ) );
+  std::map< TypeNode, unsigned >::iterator it = d_min_term_size.find( tn );
+  if( it==d_min_term_size.end() ){
+    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+    for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+      if (dt[i].getNumArgs() == 0)
+      {
+        d_min_term_size[tn] = 0;
+        return 0;
+      }
+    }
+    // TODO : improve
+    d_min_term_size[tn] = 1;
+    return 1;
+  }else{
+    return it->second;
+  }
+}
+
+unsigned TermDbSygus::getMinConsTermSize( TypeNode tn, unsigned cindex ) {
+  Assert( isRegistered( tn ) );
+  std::map< unsigned, unsigned >::iterator it = d_min_cons_term_size[tn].find( cindex );
+  if( it==d_min_cons_term_size[tn].end() ){
+    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+    Assert( cindex<dt.getNumConstructors() );
+    unsigned ret = 0;
+    if( dt[cindex].getNumArgs()>0 ){
+      ret = 1;
+      for( unsigned i=0; i<dt[cindex].getNumArgs(); i++ ){
+        ret += getMinTermSize( getArgType( dt[cindex], i ) );
+      }
+    }
+    d_min_cons_term_size[tn][cindex] = ret;
+    return ret;
+  }else{
+    return it->second;
+  }
+}
+
+unsigned TermDbSygus::getSelectorWeight(TypeNode tn, Node sel)
+{
+  std::map<TypeNode, std::map<Node, unsigned> >::iterator itsw =
+      d_sel_weight.find(tn);
+  if (itsw == d_sel_weight.end())
+  {
+    d_sel_weight[tn].clear();
+    itsw = d_sel_weight.find(tn);
+    Type t = tn.toType();
+    const Datatype& dt = static_cast<DatatypeType>(t).getDatatype();
+    Trace("sygus-db") << "Compute selector weights for " << dt.getName()
+                      << std::endl;
+    for (unsigned i = 0, size = dt.getNumConstructors(); i < size; i++)
+    {
+      unsigned cw = dt[i].getWeight();
+      for (unsigned j = 0, size2 = dt[i].getNumArgs(); j < size2; j++)
+      {
+        Node csel = Node::fromExpr(dt[i].getSelectorInternal(t, j));
+        std::map<Node, unsigned>::iterator its = itsw->second.find(csel);
+        if (its == itsw->second.end() || cw < its->second)
+        {
+          d_sel_weight[tn][csel] = cw;
+          Trace("sygus-db") << "  w(" << csel << ") <= " << cw << std::endl;
+        }
+      }
+    }
+  }
+  Assert(itsw->second.find(sel) != itsw->second.end());
+  return itsw->second[sel];
+}
+
+int TermDbSygus::getKindConsNum( TypeNode tn, Kind k ) {
+  Assert( isRegistered( tn ) );
+  std::map< TypeNode, std::map< Kind, int > >::iterator itt = d_kinds.find( tn );
+  if( itt!=d_kinds.end() ){
+    std::map< Kind, int >::iterator it = itt->second.find( k );
+    if( it!=itt->second.end() ){
+      return it->second;
+    }
+  }
+  return -1;
+}
+
+int TermDbSygus::getConstConsNum( TypeNode tn, Node n ){
+  Assert( isRegistered( tn ) );
+  std::map< TypeNode, std::map< Node, int > >::iterator itt = d_consts.find( tn );
+  if( itt!=d_consts.end() ){
+    std::map< Node, int >::iterator it = itt->second.find( n );
+    if( it!=itt->second.end() ){
+      return it->second;
+    }
+  }
+  return -1;
+}
+
+int TermDbSygus::getOpConsNum( TypeNode tn, Node n ) {
+  std::map< Node, int >::iterator it = d_ops[tn].find( n );
+  if( it!=d_ops[tn].end() ){
+    return it->second;
+  }else{
+    return -1;
+  }
+}
+
+bool TermDbSygus::hasKind( TypeNode tn, Kind k ) {
+  return getKindConsNum( tn, k )!=-1;
+}
+bool TermDbSygus::hasConst( TypeNode tn, Node n ) {
+  return getConstConsNum( tn, n )!=-1;
+}
+bool TermDbSygus::hasOp( TypeNode tn, Node n ) {
+  return getOpConsNum( tn, n )!=-1;
+}
+
+Node TermDbSygus::getConsNumOp( TypeNode tn, int i ) {
+  Assert( isRegistered( tn ) );
+  std::map< TypeNode, std::map< int, Node > >::iterator itt = d_arg_ops.find( tn );
+  if( itt!=d_arg_ops.end() ){
+    std::map< int, Node >::iterator itn = itt->second.find( i );
+    if( itn!=itt->second.end() ){
+      return itn->second;
+    }
+  }
+  return Node::null();
+}
+
+Node TermDbSygus::getConsNumConst( TypeNode tn, int i ) {
+  Assert( isRegistered( tn ) );
+  std::map< TypeNode, std::map< int, Node > >::iterator itt = d_arg_const.find( tn );
+  if( itt!=d_arg_const.end() ){
+    std::map< int, Node >::iterator itn = itt->second.find( i );
+    if( itn!=itt->second.end() ){
+      return itn->second;
+    }
+  }
+  return Node::null();
+}
+
+Kind TermDbSygus::getConsNumKind( TypeNode tn, int i ) {
+  Assert( isRegistered( tn ) );
+  std::map< TypeNode, std::map< int, Kind > >::iterator itt = d_arg_kind.find( tn );
+  if( itt!=d_arg_kind.end() ){
+    std::map< int, Kind >::iterator itk = itt->second.find( i );
+    if( itk!=itt->second.end() ){
+      return itk->second;
+    }
+  }
+  return UNDEFINED_KIND;
+}
+
+bool TermDbSygus::isKindArg( TypeNode tn, int i ) {
+  return getConsNumKind( tn, i )!=UNDEFINED_KIND;
+}
+
+bool TermDbSygus::isConstArg( TypeNode tn, int i ) {
+  Assert( isRegistered( tn ) );
+  std::map< TypeNode, std::map< int, Node > >::iterator itt = d_arg_const.find( tn );
+  if( itt!=d_arg_const.end() ){
+    return itt->second.find( i )!=itt->second.end();
+  }else{
+    return false;
+  }
+}
+
+TypeNode TermDbSygus::getArgType(const DatatypeConstructor& c, unsigned i)
+{
+  Assert(i < c.getNumArgs());
+  return TypeNode::fromType( ((SelectorType)c[i].getType()).getRangeType() );
+}
+
+/** get first occurrence */
+int TermDbSygus::getFirstArgOccurrence( const DatatypeConstructor& c, TypeNode tn ) {
+  for( unsigned i=0; i<c.getNumArgs(); i++ ){
+    TypeNode tni = getArgType( c, i );
+    if( tni==tn ){
+      return i;
+    }
+  }
+  return -1;
+}
+
+bool TermDbSygus::isTypeMatch( const DatatypeConstructor& c1, const DatatypeConstructor& c2 ) {
+  if( c1.getNumArgs()!=c2.getNumArgs() ){
+    return false;
+  }else{
+    for( unsigned i=0; i<c1.getNumArgs(); i++ ){
+      if( getArgType( c1, i )!=getArgType( c2, i ) ){
+        return false;
+      }
+    }
+    return true;
+  }
+}
+
+Node TermDbSygus::minimizeBuiltinTerm( Node n ) {
+  if( ( n.getKind()==EQUAL || n.getKind()==LEQ || n.getKind()==LT || n.getKind()==GEQ || n.getKind()==GT ) &&
+      ( n[0].getType().isInteger() || n[0].getType().isReal() ) ){
+    bool changed = false;
+    std::vector< Node > mon[2];
+    for( unsigned r=0; r<2; r++ ){
+      unsigned ro = r==0 ? 1 : 0;
+      Node c;
+      Node nc;
+      if( n[r].getKind()==PLUS ){
+        for( unsigned i=0; i<n[r].getNumChildren(); i++ ){
+          if (ArithMSum::getMonomial(n[r][i], c, nc)
+              && c.getConst<Rational>().isNegativeOne())
+          {
+            mon[ro].push_back( nc );
+            changed = true;
+          }else{
+            if( !n[r][i].isConst() || !n[r][i].getConst<Rational>().isZero() ){
+              mon[r].push_back( n[r][i] );
+            }
+          }
+        }
+      }else{
+        if (ArithMSum::getMonomial(n[r], c, nc)
+            && c.getConst<Rational>().isNegativeOne())
+        {
+          mon[ro].push_back( nc );
+          changed = true;
+        }else{
+          if( !n[r].isConst() || !n[r].getConst<Rational>().isZero() ){
+            mon[r].push_back( n[r] );
+          }
+        }
+      }
+    }
+    if( changed ){
+      Node nn[2];
+      for( unsigned r=0; r<2; r++ ){
+        nn[r] = mon[r].size()==0 ? NodeManager::currentNM()->mkConst( Rational(0) ) : ( mon[r].size()==1 ? mon[r][0] : NodeManager::currentNM()->mkNode( PLUS, mon[r] ) );
+      }
+      return NodeManager::currentNM()->mkNode( n.getKind(), nn[0], nn[1] );
+    }
+  }
+  return n;
+}
+
+Node TermDbSygus::expandBuiltinTerm( Node t ){
+  if( t.getKind()==EQUAL ){
+    if( t[0].getType().isReal() ){
+      return NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( LEQ, t[0], t[1] ),
+                                                    NodeManager::currentNM()->mkNode( LEQ, t[1], t[0] ) );
+    }else if( t[0].getType().isBoolean() ){
+      return NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, t[0], t[1] ),
+                                                   NodeManager::currentNM()->mkNode( AND, t[0].negate(), t[1].negate() ) );
+    }
+  }else if( t.getKind()==ITE && t.getType().isBoolean() ){
+    return NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, t[0], t[1] ),
+                                                 NodeManager::currentNM()->mkNode( AND, t[0].negate(), t[2] ) );
+  }
+  return Node::null();
+}
+
+
+Kind TermDbSygus::getComparisonKind( TypeNode tn ) {
+  if( tn.isInteger() || tn.isReal() ){
+    return LT;
+  }else if( tn.isBitVector() ){
+    return BITVECTOR_ULT;
+  }else{
+    return UNDEFINED_KIND;
+  }
+}
+
+Kind TermDbSygus::getPlusKind( TypeNode tn, bool is_neg ) {
+  if( tn.isInteger() || tn.isReal() ){
+    return is_neg ? MINUS : PLUS;
+  }else if( tn.isBitVector() ){
+    return is_neg ? BITVECTOR_SUB : BITVECTOR_PLUS;
+  }else{
+    return UNDEFINED_KIND;
+  }
+}
+
+Node TermDbSygus::getSemanticSkolem( TypeNode tn, Node n, bool doMk ){
+  std::map< Node, Node >::iterator its = d_semantic_skolem[tn].find( n );
+  if( its!=d_semantic_skolem[tn].end() ){
+    return its->second;
+  }else if( doMk ){
+    Node ss = NodeManager::currentNM()->mkSkolem( "sem", tn, "semantic skolem for sygus" );
+    d_semantic_skolem[tn][n] = ss;
+    return ss;
+  }else{
+    return Node::null();
+  }
+}
+
+bool TermDbSygus::involvesDivByZero( Node n, std::map< Node, bool >& visited ){
+  if( visited.find( n )==visited.end() ){
+    visited[n] = true;
+    Kind k = n.getKind();
+    if( k==DIVISION || k==DIVISION_TOTAL || k==INTS_DIVISION || k==INTS_DIVISION_TOTAL || 
+        k==INTS_MODULUS || k==INTS_MODULUS_TOTAL ){
+      if( n[1].isConst() ){
+        if (n[1]
+            == d_quantEngine->getTermUtil()->getTypeValue(n[1].getType(), 0))
+        {
+          return true;
+        }
+      }else{
+        // if it has free variables it might be a non-zero constant
+        if( !hasFreeVar( n[1] ) ){
+          return true;
+        }
+      }
+    }
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      if( involvesDivByZero( n[i], visited ) ){
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+bool TermDbSygus::involvesDivByZero( Node n ) {
+  std::map< Node, bool > visited;
+  return involvesDivByZero( n, visited );
+}
+
+void doStrReplace(std::string& str, const std::string& oldStr, const std::string& newStr){
+  size_t pos = 0;
+  while((pos = str.find(oldStr, pos)) != std::string::npos){
+     str.replace(pos, oldStr.length(), newStr);
+     pos += newStr.length();
+  }
+}
+
+Kind TermDbSygus::getOperatorKind( Node op ) {
+  Assert( op.getKind()!=BUILTIN );
+  if (op.getKind() == LAMBDA)
+  {
+    // we use APPLY_UF instead of APPLY, since the rewriter for APPLY_UF
+    // does beta-reduction but does not for APPLY
+    return APPLY_UF;
+  }else{
+    TypeNode tn = op.getType();
+    if( tn.isConstructor() ){
+      return APPLY_CONSTRUCTOR;
+    }
+    else if (tn.isSelector())
+    {
+      return APPLY_SELECTOR;
+    }
+    else if (tn.isTester())
+    {
+      return APPLY_TESTER;
+    }
+    else if (tn.isFunction())
+    {
+      return APPLY_UF;
+    }
+    return NodeManager::operatorToKind(op);
+  }
+}
+
+Node TermDbSygus::getAnchor( Node n ) {
+  if( n.getKind()==APPLY_SELECTOR_TOTAL ){
+    return getAnchor( n[0] );
+  }else{
+    return n;
+  }
+}
+
+unsigned TermDbSygus::getAnchorDepth( Node n ) {
+  if( n.getKind()==APPLY_SELECTOR_TOTAL ){
+    return 1+getAnchorDepth( n[0] );
+  }else{
+    return 0;
+  }
+}
+
+
+void TermDbSygus::registerEvalTerm( Node n ) {
+  if( options::sygusDirectEval() ){
+    if( n.getKind()==APPLY_UF && !n.getType().isBoolean() ){
+      TypeNode tn = n[0].getType();
+      if( tn.isDatatype() ){
+        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+        if( dt.isSygus() ){
+          Node f = n.getOperator();
+          if( n[0].getKind()!=APPLY_CONSTRUCTOR ){
+            if (d_eval_processed.find(n) == d_eval_processed.end())
+            {
+              Trace("sygus-eager")
+                  << "TermDbSygus::eager: Register eval term : " << n
+                  << std::endl;
+              d_eval_processed.insert(n);
+              d_evals[n[0]].push_back(n);
+              TypeNode tn = n[0].getType();
+              Assert(tn.isDatatype());
+              const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+              Node var_list = Node::fromExpr(dt.getSygusVarList());
+              Assert(dt.isSygus());
+              d_eval_args[n[0]].push_back(std::vector<Node>());
+              bool isConst = true;
+              for (unsigned j = 1; j < n.getNumChildren(); j++)
+              {
+                d_eval_args[n[0]].back().push_back(n[j]);
+                if (!n[j].isConst())
+                {
+                  isConst = false;
+                }
+              }
+              d_eval_args_const[n[0]].push_back(isConst);
+              Node a = getAnchor(n[0]);
+              d_subterms[a][n[0]] = true;
+            }
+          }
+        }
+      }    
+    }
+  }
+}
+
+void TermDbSygus::registerModelValue( Node a, Node v, std::vector< Node >& terms, std::vector< Node >& vals, std::vector< Node >& exps ) {
+  std::map< Node, std::map< Node, bool > >::iterator its = d_subterms.find( a );
+  if( its!=d_subterms.end() ){
+    Trace("sygus-eager") << "registerModelValue : " << a << ", has " << its->second.size() << " registered subterms." << std::endl;
+    for( std::map< Node, bool >::iterator itss = its->second.begin(); itss != its->second.end(); ++itss ){
+      Node n = itss->first;
+      Trace("sygus-eager-debug") << "...process : " << n << std::endl;
+      std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_eval_args.find( n );
+      if( it!=d_eval_args.end() && !it->second.empty() ){
+        TNode at = a;
+        TNode vt = v;
+        Node vn = n.substitute( at, vt );
+        vn = Rewriter::rewrite( vn );
+        unsigned start = d_node_mv_args_proc[n][vn];
+        // get explanation in terms of testers
+        std::vector< Node > antec_exp;
+        d_syexp->getExplanationForConstantEquality(n, vn, antec_exp);
+        Node antec = antec_exp.size()==1 ? antec_exp[0] : NodeManager::currentNM()->mkNode( kind::AND, antec_exp );
+        //Node antec = n.eqNode( vn );
+        TypeNode tn = n.getType();
+        Assert( tn.isDatatype() );
+        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+        Assert( dt.isSygus() );
+        Trace("sygus-eager") << "TermDbSygus::eager: Register model value : " << vn << " for " << n << std::endl;
+        Trace("sygus-eager") << "...it has " << it->second.size() << " evaluations, already processed " << start << "." << std::endl;
+        Node bTerm = sygusToBuiltin( vn, tn );
+        Trace("sygus-eager") << "Built-in term : " << bTerm << std::endl;
+        std::vector< Node > vars;
+        Node var_list = Node::fromExpr( dt.getSygusVarList() );
+        for( unsigned j=0; j<var_list.getNumChildren(); j++ ){
+          vars.push_back( var_list[j] );
+        }
+        //evaluation children
+        std::vector< Node > eval_children;
+        eval_children.push_back( Node::fromExpr( dt.getSygusEvaluationFunc() ) );
+        eval_children.push_back( n );
+        //for each evaluation
+        for( unsigned i=start; i<it->second.size(); i++ ){
+          Node res;
+          Node expn;
+          // unfold?
+          bool do_unfold = false;
+          if( options::sygusUnfoldBool() ){
+            if( bTerm.getKind()==ITE || bTerm.getType().isBoolean() ){
+              do_unfold = true;
+            }
+          }
+          if( do_unfold ){
+            // TODO : this is replicated for different values, possibly do better caching
+            std::map< Node, Node > vtm; 
+            std::vector< Node > exp;
+            vtm[n] = vn;
+            eval_children.insert( eval_children.end(), it->second[i].begin(), it->second[i].end() );
+            Node eval_fun = NodeManager::currentNM()->mkNode( kind::APPLY_UF, eval_children );
+            eval_children.resize( 2 );  
+            res = unfold( eval_fun, vtm, exp );
+            expn = exp.size()==1 ? exp[0] : NodeManager::currentNM()->mkNode( kind::AND, exp );
+          }else{
+
+            EvalSygusInvarianceTest esit;
+            eval_children.insert( eval_children.end(), it->second[i].begin(), it->second[i].end() );
+            Node conj =
+                NodeManager::currentNM()->mkNode(kind::APPLY_UF, eval_children);
+            eval_children[1] = vn;
+            Node eval_fun = NodeManager::currentNM()->mkNode( kind::APPLY_UF, eval_children );
+            res = evaluateWithUnfolding(eval_fun);
+            esit.init(conj, n, res);
+            eval_children.resize( 2 );  
+            eval_children[1] = n;
+            
+            //evaluate with minimal explanation
+            std::vector< Node > mexp;
+            d_syexp->getExplanationFor(n, vn, mexp, esit);
+            Assert( !mexp.empty() );
+            expn = mexp.size()==1 ? mexp[0] : NodeManager::currentNM()->mkNode( kind::AND, mexp );
+            
+            //if all constant, we can use evaluation to minimize the explanation
+            //Assert( i<d_eval_args_const[n].size() );
+            //if( d_eval_args_const[n][i] ){
+              /*
+              std::map< Node, Node > vtm; 
+              std::map< Node, Node > visited; 
+              std::map< Node, std::vector< Node > > exp;
+              vtm[n] = vn;
+              res = crefEvaluate( eval_fun, vtm, visited, exp );
+              Assert( !exp[eval_fun].empty() );
+              expn = exp[eval_fun].size()==1 ? exp[eval_fun][0] : NodeManager::currentNM()->mkNode( kind::AND, exp[eval_fun] );
+              */
+              /*
+            //otherwise, just do a substitution
+            }else{
+              Assert( vars.size()==it->second[i].size() );
+              res = bTerm.substitute( vars.begin(), vars.end(), it->second[i].begin(), it->second[i].end() );
+              res = Rewriter::rewrite( res );
+              expn = antec;
+            }
+            */
+          }
+          Assert( !res.isNull() );
+          terms.push_back( d_evals[n][i] );
+          vals.push_back( res );
+          exps.push_back( expn );
+          Trace("sygus-eager") << "Conclude : " << d_evals[n][i] << " == " << res << ", cref eval = " << d_eval_args_const[n][i] << std::endl;
+          Trace("sygus-eager") << "   from " << expn << std::endl;
+        }
+        d_node_mv_args_proc[n][vn] = it->second.size();
+      }
+    }
+  }
+}
+
+Node TermDbSygus::unfold( Node en, std::map< Node, Node >& vtm, std::vector< Node >& exp, bool track_exp ) {
+  if( en.getKind()==kind::APPLY_UF ){
+    Trace("sygus-db-debug") << "Unfold : " << en << std::endl;
+    Node ev = en[0];
+    if( track_exp ){
+      std::map< Node, Node >::iterator itv = vtm.find( en[0] );
+      if( itv!=vtm.end() ){
+        ev = itv->second;
+      }else{
+        Assert( false );
+      }
+      Assert( en[0].getType()==ev.getType() );
+      Assert( ev.isConst() );
+    }
+    Assert( ev.getKind()==kind::APPLY_CONSTRUCTOR );
+    std::vector< Node > args;
+    for( unsigned i=1; i<en.getNumChildren(); i++ ){
+      args.push_back( en[i] );
+    }
+    const Datatype& dt = ((DatatypeType)(ev.getType()).toType()).getDatatype();
+    unsigned i = Datatype::indexOf( ev.getOperator().toExpr() );
+    if( track_exp ){
+      //explanation
+      Node ee = NodeManager::currentNM()->mkNode( kind::APPLY_TESTER, Node::fromExpr( dt[i].getTester() ), en[0] );
+      if( std::find( exp.begin(), exp.end(), ee )==exp.end() ){
+        exp.push_back( ee );
+      }
+    }
+    Assert( !dt.isParametric() );
+    std::map< int, Node > pre;
+    for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
+      std::vector< Node > cc;
+      //get the evaluation argument for the selector
+      Type rt = dt[i][j].getRangeType();
+      const Datatype & ad = ((DatatypeType)dt[i][j].getRangeType()).getDatatype();
+      cc.push_back( Node::fromExpr( ad.getSygusEvaluationFunc() ) );
+      Node s;
+      if( en[0].getKind()==kind::APPLY_CONSTRUCTOR ){
+        s = en[0][j];
+      }else{
+        s = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, dt[i].getSelectorInternal( en[0].getType().toType(), j ), en[0] );
+      }
+      cc.push_back( s );
+      if( track_exp ){
+        //update vtm map
+        vtm[s] = ev[j];
+      }
+      cc.insert( cc.end(), args.begin(), args.end() );
+      pre[j] = NodeManager::currentNM()->mkNode( kind::APPLY_UF, cc );
+    }
+    std::map< TypeNode, int > var_count; 
+    Node ret = mkGeneric( dt, i, var_count, pre );
+    // if it is a variable, apply the substitution
+    if( ret.getKind()==kind::BOUND_VARIABLE ){
+      Assert( ret.hasAttribute(SygusVarNumAttribute()) );
+      int i = ret.getAttribute(SygusVarNumAttribute());
+      Assert( Node::fromExpr( dt.getSygusVarList() )[i]==ret );
+      ret = args[i];
+    }
+    else
+    {
+      ret = Rewriter::rewrite(ret);
+    }
+    return ret;
+  }else{
+    Assert( en.isConst() );
+  }
+  return en;
+}
+
+
+Node TermDbSygus::getEagerUnfold( Node n, std::map< Node, Node >& visited ) {
+  std::map< Node, Node >::iterator itv = visited.find( n );
+  if( itv==visited.end() ){
+    Trace("cegqi-eager-debug") << "getEagerUnfold " << n << std::endl;
+    Node ret;
+    if( n.getKind()==APPLY_UF ){
+      TypeNode tn = n[0].getType();
+      Trace("cegqi-eager-debug") << "check " << n[0].getType() << std::endl;
+      if( tn.isDatatype() ){
+        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+        if( dt.isSygus() ){ 
+          Trace("cegqi-eager") << "Unfold eager : " << n << std::endl;
+          Node bTerm = sygusToBuiltin( n[0], tn );
+          Trace("cegqi-eager") << "Built-in term : " << bTerm << std::endl;
+          std::vector< Node > vars;
+          std::vector< Node > subs;
+          Node var_list = Node::fromExpr( dt.getSygusVarList() );
+          Assert( var_list.getNumChildren()+1==n.getNumChildren() );
+          for( unsigned j=0; j<var_list.getNumChildren(); j++ ){
+            vars.push_back( var_list[j] );
+          }
+          for( unsigned j=1; j<n.getNumChildren(); j++ ){
+            Node nc = getEagerUnfold( n[j], visited );
+            subs.push_back( nc );
+            Assert(subs[j - 1].getType().isComparableTo(
+                var_list[j - 1].getType()));
+          }
+          Assert( vars.size()==subs.size() );
+          bTerm = bTerm.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+          Trace("cegqi-eager") << "Built-in term after subs : " << bTerm << std::endl;
+          Trace("cegqi-eager-debug") << "Types : " << bTerm.getType() << " " << n.getType() << std::endl;
+          Assert(n.getType().isComparableTo(bTerm.getType()));
+          ret = bTerm; 
+        }
+      }
+    }
+    if( ret.isNull() ){
+      if( n.getKind()!=FORALL ){
+        bool childChanged = false;
+        std::vector< Node > children;
+        for( unsigned i=0; i<n.getNumChildren(); i++ ){
+          Node nc = getEagerUnfold( n[i], visited );
+          childChanged = childChanged || n[i]!=nc;
+          children.push_back( nc );
+        }
+        if( childChanged ){
+          if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+            children.insert( children.begin(), n.getOperator() );
+          }
+          ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
+        }
+      }
+      if( ret.isNull() ){
+        ret = n;
+      }
+    }
+    visited[n] = ret;
+    return ret;
+  }else{
+    return itv->second;
+  }
+}
+
+
+Node TermDbSygus::evaluateBuiltin( TypeNode tn, Node bn, std::vector< Node >& args ) {
+  if( !args.empty() ){
+    std::map< TypeNode, std::vector< Node > >::iterator it = d_var_list.find( tn );
+    Assert( it!=d_var_list.end() );
+    Assert( it->second.size()==args.size() );
+    return Rewriter::rewrite( bn.substitute( it->second.begin(), it->second.end(), args.begin(), args.end() ) );
+  }else{
+    return Rewriter::rewrite( bn );
+  }
+}
+
+Node TermDbSygus::evaluateWithUnfolding(
+    Node n, std::unordered_map<Node, Node, NodeHashFunction>& visited)
+{
+  std::unordered_map<Node, Node, NodeHashFunction>::iterator it =
+      visited.find(n);
+  if( it==visited.end() ){
+    Node ret = n;
+    while( ret.getKind()==APPLY_UF && ret[0].getKind()==APPLY_CONSTRUCTOR ){
+      ret = unfold( ret );
+    }    
+    if( ret.getNumChildren()>0 ){
+      std::vector< Node > children;
+      if( ret.getMetaKind() == kind::metakind::PARAMETERIZED ){
+        children.push_back( ret.getOperator() );
+      }
+      bool childChanged = false;
+      for( unsigned i=0; i<ret.getNumChildren(); i++ ){
+        Node nc = evaluateWithUnfolding( ret[i], visited ); 
+        childChanged = childChanged || nc!=ret[i];
+        children.push_back( nc );
+      }
+      if( childChanged ){
+        ret = NodeManager::currentNM()->mkNode( ret.getKind(), children );
+      }
+      ret = getExtRewriter()->extendedRewrite(ret);
+    }
+    visited[n] = ret;
+    return ret;
+  }else{
+    return it->second;
+  }
+}
+
+Node TermDbSygus::evaluateWithUnfolding( Node n ) {
+  std::unordered_map<Node, Node, NodeHashFunction> visited;
+  return evaluateWithUnfolding( n, visited );
+}
+
+}/* CVC4::theory::quantifiers namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
diff --git a/src/theory/quantifiers/sygus/term_database_sygus.h b/src/theory/quantifiers/sygus/term_database_sygus.h
new file mode 100644 (file)
index 0000000..e796a3a
--- /dev/null
@@ -0,0 +1,286 @@
+/*********************                                                        */
+/*! \file term_database_sygus.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief term database sygus class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_SYGUS_H
+#define __CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_SYGUS_H
+
+#include <unordered_set>
+
+#include "theory/quantifiers/extended_rewrite.h"
+#include "theory/quantifiers/sygus/sygus_explain.h"
+#include "theory/quantifiers/term_database.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class CegConjecture;
+
+// TODO :issue #1235 split and document this class
+class TermDbSygus {
+ public:
+  TermDbSygus(context::Context* c, QuantifiersEngine* qe);
+  ~TermDbSygus() {}
+  /** Reset this utility */
+  bool reset(Theory::Effort e);
+  /** Identify this utility */
+  std::string identify() const { return "TermDbSygus"; }
+  /** register the sygus type */
+  void registerSygusType(TypeNode tn);
+  /** register a variable e that we will do enumerative search on
+   * conj is the conjecture that the enumeration of e is for.
+   * f is the synth-fun that the enumeration of e is for.
+   * mkActiveGuard is whether we want to make an active guard for e 
+   * (see d_enum_to_active_guard).
+   *
+   * Notice that enumerator e may not be equivalent
+   * to f in synthesis-through-unification approaches
+   * (e.g. decision tree construction for PBE synthesis).
+   */
+  void registerEnumerator(Node e,
+                          Node f,
+                          CegConjecture* conj,
+                          bool mkActiveGuard = false);
+  /** is e an enumerator? */
+  bool isEnumerator(Node e) const;
+  /** return the conjecture e is associated with */
+  CegConjecture* getConjectureForEnumerator(Node e);
+  /** return the function-to-synthesize e is associated with */
+  Node getSynthFunForEnumerator(Node e);
+  /** get active guard for e */
+  Node getActiveGuardForEnumerator(Node e);
+  /** get all registered enumerators */
+  void getEnumerators(std::vector<Node>& mts);
+  /** get the explanation utility */
+  SygusExplain* getExplain() { return d_syexp.get(); }
+  /** get the extended rewrite utility */
+  ExtendedRewriter* getExtRewriter() { return d_ext_rw.get(); }
+  //-----------------------------conversion from sygus to builtin
+  /** get free variable
+   *
+   * This class caches a list of free variables for each type, which are
+   * used, for instance, for constructing canonical forms of terms with free
+   * variables. This function returns the i^th free variable for type tn.
+   * If useSygusType is true, then this function returns a variable of the
+   * analog type for sygus type tn (see d_fv for details).
+   */
+  TNode getFreeVar(TypeNode tn, int i, bool useSygusType = false);
+  /** get free variable and increment
+   *
+   * This function returns the next free variable for type tn, and increments
+   * the counter in var_count for that type.
+   */
+  TNode getFreeVarInc(TypeNode tn,
+                      std::map<TypeNode, int>& var_count,
+                      bool useSygusType = false);
+  /** returns true if n is a cached free variable (in d_fv). */
+  bool isFreeVar(Node n) { return d_fv_stype.find(n) != d_fv_stype.end(); }
+  /** returns the index of n in the free variable cache (d_fv). */
+  int getVarNum(Node n) { return d_fv_num[n]; }
+  /** returns true if n has a cached free variable (in d_fv). */
+  bool hasFreeVar(Node n);
+  /** make generic
+   *
+   * This function returns a builtin term f( t1, ..., tn ) where f is the
+   * builtin op of the sygus datatype constructor specified by arguments
+   * dt and c. The mapping pre maps child indices to the term for that index
+   * in the term we are constructing. That is, for each i = 1,...,n:
+   *   If i is in the domain of pre, then ti = pre[i].
+   *   If i is not in the domain of pre, then ti = d_fv[1][ var_count[Ti ] ],
+   *     and var_count[Ti] is incremented.
+   */
+  Node mkGeneric(const Datatype& dt,
+                 unsigned c,
+                 std::map<TypeNode, int>& var_count,
+                 std::map<int, Node>& pre);
+  /** same as above, but with empty var_count */
+  Node mkGeneric(const Datatype& dt, int c, std::map<int, Node>& pre);
+  /** sygus to builtin
+   *
+   * Given a sygus datatype term n of type tn, this function returns its analog,
+   * that is, the term that n encodes.
+   */
+  Node sygusToBuiltin(Node n, TypeNode tn);
+  /** same as above, but without tn */
+  Node sygusToBuiltin(Node n) { return sygusToBuiltin(n, n.getType()); }
+  //-----------------------------end conversion from sygus to builtin
+
+ private:
+  /** reference to the quantifiers engine */
+  QuantifiersEngine* d_quantEngine;
+  /** sygus explanation */
+  std::unique_ptr<SygusExplain> d_syexp;
+  /** sygus explanation */
+  std::unique_ptr<ExtendedRewriter> d_ext_rw;
+  /** mapping from enumerator terms to the conjecture they are associated with
+   */
+  std::map<Node, CegConjecture*> d_enum_to_conjecture;
+  /** mapping from enumerator terms to the function-to-synthesize they are
+   * associated with 
+   */
+  std::map<Node, Node> d_enum_to_synth_fun;
+  /** mapping from enumerator terms to the guard they are associated with
+   * The guard G for an enumerator e has the semantics
+   *   if G is true, then there are more values of e to enumerate".
+   */
+  std::map<Node, Node> d_enum_to_active_guard;
+
+  //-----------------------------conversion from sygus to builtin
+  /** cache for sygusToBuiltin */
+  std::map<TypeNode, std::map<Node, Node> > d_sygus_to_builtin;
+  /** a cache of fresh variables for each type
+   *
+   * We store two versions of this list:
+   *   index 0: mapping from builtin types to fresh variables of that type,
+   *   index 1: mapping from sygus types to fresh varaibles of the type they
+   *            encode.
+   */
+  std::map<TypeNode, std::vector<Node> > d_fv[2];
+  /** Maps free variables to the domain type they are associated with in d_fv */
+  std::map<Node, TypeNode> d_fv_stype;
+  /** Maps free variables to their index in d_fv. */
+  std::map<Node, int> d_fv_num;
+  /** recursive helper for hasFreeVar, visited stores nodes we have visited. */
+  bool hasFreeVar(Node n, std::map<Node, bool>& visited);
+  //-----------------------------end conversion from sygus to builtin
+
+  // TODO :issue #1235 : below here needs refactor
+
+ public:
+  Node d_true;
+  Node d_false;
+
+private:
+  void computeMinTypeDepthInternal( TypeNode root_tn, TypeNode tn, unsigned type_depth );
+  bool involvesDivByZero( Node n, std::map< Node, bool >& visited );
+
+ private:
+  // information for sygus types
+  std::map<TypeNode, TypeNode> d_register;  // stores sygus -> builtin type
+  std::map<TypeNode, std::vector<Node> > d_var_list;
+  std::map<TypeNode, std::map<int, Kind> > d_arg_kind;
+  std::map<TypeNode, std::map<Kind, int> > d_kinds;
+  std::map<TypeNode, std::map<int, Node> > d_arg_const;
+  std::map<TypeNode, std::map<Node, int> > d_consts;
+  std::map<TypeNode, std::map<Node, int> > d_ops;
+  std::map<TypeNode, std::map<int, Node> > d_arg_ops;
+  std::map<TypeNode, std::map<Node, Node> > d_semantic_skolem;
+  // grammar information
+  // root -> type -> _
+  std::map<TypeNode, std::map<TypeNode, unsigned> > d_min_type_depth;
+  // std::map< TypeNode, std::map< Node, std::map< std::map< int, bool > > >
+  // d_consider_const;
+  // type -> cons -> _
+  std::map<TypeNode, unsigned> d_min_term_size;
+  std::map<TypeNode, std::map<unsigned, unsigned> > d_min_cons_term_size;
+  /** a cache for getSelectorWeight */
+  std::map<TypeNode, std::map<Node, unsigned> > d_sel_weight;
+
+ public:  // general sygus utilities
+  bool isRegistered( TypeNode tn );
+  // get the minimum depth of type in its parent grammar
+  unsigned getMinTypeDepth( TypeNode root_tn, TypeNode tn );
+  // get the minimum size for a constructor term
+  unsigned getMinTermSize( TypeNode tn );
+  unsigned getMinConsTermSize( TypeNode tn, unsigned cindex );
+  /** get the weight of the selector, where tn is the domain of sel */
+  unsigned getSelectorWeight(TypeNode tn, Node sel);
+
+ public:
+  TypeNode sygusToBuiltinType( TypeNode tn );
+  int getKindConsNum( TypeNode tn, Kind k );
+  int getConstConsNum( TypeNode tn, Node n );
+  int getOpConsNum( TypeNode tn, Node n );
+  bool hasKind( TypeNode tn, Kind k );
+  bool hasConst( TypeNode tn, Node n );
+  bool hasOp( TypeNode tn, Node n );
+  Node getConsNumConst( TypeNode tn, int i );
+  Node getConsNumOp( TypeNode tn, int i );
+  Kind getConsNumKind( TypeNode tn, int i );
+  bool isKindArg( TypeNode tn, int i );
+  bool isConstArg( TypeNode tn, int i );
+  /** get arg type */
+  TypeNode getArgType(const DatatypeConstructor& c, unsigned i);
+  /** get first occurrence */
+  int getFirstArgOccurrence( const DatatypeConstructor& c, TypeNode tn );
+  /** is type match */
+  bool isTypeMatch( const DatatypeConstructor& c1, const DatatypeConstructor& c2 );
+
+  TypeNode getSygusTypeForVar( Node v );
+  Node sygusSubstituted( TypeNode tn, Node n, std::vector< Node >& args );
+  Node getSygusNormalized( Node n, std::map< TypeNode, int >& var_count, std::map< Node, Node >& subs );
+  Node getNormalized(TypeNode t, Node prog);
+  unsigned getSygusTermSize( Node n );
+  /** given a term, construct an equivalent smaller one that respects syntax */
+  Node minimizeBuiltinTerm( Node n );
+  /** given a term, expand it into more basic components */
+  Node expandBuiltinTerm( Node n );
+  /** get comparison kind */
+  Kind getComparisonKind( TypeNode tn );
+  Kind getPlusKind( TypeNode tn, bool is_neg = false );
+  // get semantic skolem for n (a sygus term whose builtin version is n)
+  Node getSemanticSkolem( TypeNode tn, Node n, bool doMk = true );
+  /** involves div-by-zero */
+  bool involvesDivByZero( Node n );
+  
+  /** get operator kind */
+  static Kind getOperatorKind( Node op );
+
+  /** get anchor */
+  static Node getAnchor( Node n );
+  static unsigned getAnchorDepth( Node n );
+  
+public: // for symmetry breaking
+  bool considerArgKind( TypeNode tn, TypeNode tnp, Kind k, Kind pk, int arg );
+  bool considerConst( TypeNode tn, TypeNode tnp, Node c, Kind pk, int arg );
+  bool considerConst( const Datatype& pdt, TypeNode tnp, Node c, Kind pk, int arg );
+  int solveForArgument( TypeNode tnp, unsigned cindex, unsigned arg );
+  
+//for eager instantiation
+  // TODO (as part of #1235) move some of these functions to sygus_explain.h
+ private:
+  /** the set of evaluation terms we have already processed */
+  std::unordered_set<Node, NodeHashFunction> d_eval_processed;
+  std::map< Node, std::map< Node, bool > > d_subterms;
+  std::map< Node, std::vector< Node > > d_evals;
+  std::map< Node, std::vector< std::vector< Node > > > d_eval_args;
+  std::map< Node, std::vector< bool > > d_eval_args_const;
+  std::map< Node, std::map< Node, unsigned > > d_node_mv_args_proc;
+
+public:
+  void registerEvalTerm( Node n );
+  void registerModelValue( Node n, Node v, std::vector< Node >& exps, std::vector< Node >& terms, std::vector< Node >& vals );
+  Node unfold( Node en, std::map< Node, Node >& vtm, std::vector< Node >& exp, bool track_exp = true );
+  Node unfold( Node en ){
+    std::map< Node, Node > vtm;
+    std::vector< Node > exp;
+    return unfold( en, vtm, exp, false );
+  }
+  Node getEagerUnfold( Node n, std::map< Node, Node >& visited );
+
+  // builtin evaluation, returns rewrite( bn [ args / vars(tn) ] )
+  Node evaluateBuiltin( TypeNode tn, Node bn, std::vector< Node >& args );
+  // evaluate with unfolding
+  Node evaluateWithUnfolding(
+      Node n, std::unordered_map<Node, Node, NodeHashFunction>& visited);
+  Node evaluateWithUnfolding( Node n );
+};
+
+}/* CVC4::theory::quantifiers namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_H */
diff --git a/src/theory/quantifiers/sygus_explain.cpp b/src/theory/quantifiers/sygus_explain.cpp
deleted file mode 100644 (file)
index 4ae4d43..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_explain.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of techniques for sygus explanations
- **/
-
-#include "theory/quantifiers/sygus_explain.h"
-
-#include "theory/datatypes/datatypes_rewriter.h"
-#include "theory/quantifiers/term_database_sygus.h"
-
-using namespace CVC4::kind;
-using namespace std;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-void TermRecBuild::addTerm(Node n)
-{
-  d_term.push_back(n);
-  std::vector<Node> currc;
-  d_kind.push_back(n.getKind());
-  if (n.getMetaKind() == kind::metakind::PARAMETERIZED)
-  {
-    currc.push_back(n.getOperator());
-    d_has_op.push_back(true);
-  }
-  else
-  {
-    d_has_op.push_back(false);
-  }
-  for (unsigned i = 0; i < n.getNumChildren(); i++)
-  {
-    currc.push_back(n[i]);
-  }
-  d_children.push_back(currc);
-}
-
-void TermRecBuild::init(Node n)
-{
-  Assert(d_term.empty());
-  addTerm(n);
-}
-
-void TermRecBuild::push(unsigned p)
-{
-  Assert(!d_term.empty());
-  unsigned curr = d_term.size() - 1;
-  Assert(d_pos.size() == curr);
-  Assert(d_pos.size() + 1 == d_children.size());
-  Assert(p < d_term[curr].getNumChildren());
-  addTerm(d_term[curr][p]);
-  d_pos.push_back(p);
-}
-
-void TermRecBuild::pop()
-{
-  Assert(!d_pos.empty());
-  d_pos.pop_back();
-  d_kind.pop_back();
-  d_has_op.pop_back();
-  d_children.pop_back();
-  d_term.pop_back();
-}
-
-void TermRecBuild::replaceChild(unsigned i, Node r)
-{
-  Assert(!d_term.empty());
-  unsigned curr = d_term.size() - 1;
-  unsigned o = d_has_op[curr] ? 1 : 0;
-  d_children[curr][i + o] = r;
-}
-
-Node TermRecBuild::getChild(unsigned i)
-{
-  unsigned curr = d_term.size() - 1;
-  unsigned o = d_has_op[curr] ? 1 : 0;
-  return d_children[curr][i + o];
-}
-
-Node TermRecBuild::build(unsigned d)
-{
-  Assert(d_pos.size() + 1 == d_term.size());
-  Assert(d < d_term.size());
-  int p = d < d_pos.size() ? d_pos[d] : -2;
-  std::vector<Node> children;
-  unsigned o = d_has_op[d] ? 1 : 0;
-  for (unsigned i = 0; i < d_children[d].size(); i++)
-  {
-    Node nc;
-    if (p + o == i)
-    {
-      nc = build(d + 1);
-    }
-    else
-    {
-      nc = d_children[d][i];
-    }
-    children.push_back(nc);
-  }
-  return NodeManager::currentNM()->mkNode(d_kind[d], children);
-}
-
-void SygusExplain::getExplanationForConstantEquality(Node n,
-                                                     Node vn,
-                                                     std::vector<Node>& exp)
-{
-  std::map<unsigned, bool> cexc;
-  getExplanationForConstantEquality(n, vn, exp, cexc);
-}
-
-void SygusExplain::getExplanationForConstantEquality(
-    Node n, Node vn, std::vector<Node>& exp, std::map<unsigned, bool>& cexc)
-{
-  Assert(vn.getKind() == kind::APPLY_CONSTRUCTOR);
-  Assert(n.getType() == vn.getType());
-  TypeNode tn = n.getType();
-  Assert(tn.isDatatype());
-  const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
-  int i = Datatype::indexOf(vn.getOperator().toExpr());
-  Node tst = datatypes::DatatypesRewriter::mkTester(n, i, dt);
-  exp.push_back(tst);
-  for (unsigned j = 0; j < vn.getNumChildren(); j++)
-  {
-    if (cexc.find(j) == cexc.end())
-    {
-      Node sel = NodeManager::currentNM()->mkNode(
-          kind::APPLY_SELECTOR_TOTAL,
-          Node::fromExpr(dt[i].getSelectorInternal(tn.toType(), j)),
-          n);
-      getExplanationForConstantEquality(sel, vn[j], exp);
-    }
-  }
-}
-
-Node SygusExplain::getExplanationForConstantEquality(Node n, Node vn)
-{
-  std::map<unsigned, bool> cexc;
-  return getExplanationForConstantEquality(n, vn, cexc);
-}
-
-Node SygusExplain::getExplanationForConstantEquality(
-    Node n, Node vn, std::map<unsigned, bool>& cexc)
-{
-  std::vector<Node> exp;
-  getExplanationForConstantEquality(n, vn, exp, cexc);
-  Assert(!exp.empty());
-  return exp.size() == 1 ? exp[0]
-                         : NodeManager::currentNM()->mkNode(kind::AND, exp);
-}
-
-// we have ( n = vn => eval( n ) = bvr ) ^ vn != vnr , returns exp such that exp
-// => ( eval( n ) = bvr ^ vn != vnr )
-void SygusExplain::getExplanationFor(TermRecBuild& trb,
-                                     Node n,
-                                     Node vn,
-                                     std::vector<Node>& exp,
-                                     std::map<TypeNode, int>& var_count,
-                                     SygusInvarianceTest& et,
-                                     Node vnr,
-                                     Node& vnr_exp,
-                                     int& sz)
-{
-  Assert(vnr.isNull() || vn != vnr);
-  Assert(vn.getKind() == APPLY_CONSTRUCTOR);
-  Assert(vnr.isNull() || vnr.getKind() == APPLY_CONSTRUCTOR);
-  Assert(n.getType() == vn.getType());
-  TypeNode ntn = n.getType();
-  std::map<unsigned, bool> cexc;
-  // for each child, 
-  // check whether replacing that child by a fresh variable
-  // also satisfies the invariance test.
-  for (unsigned i = 0; i < vn.getNumChildren(); i++)
-  {
-    TypeNode xtn = vn[i].getType();
-    Node x = d_tdb->getFreeVarInc(xtn, var_count);
-    trb.replaceChild(i, x);
-    Node nvn = trb.build();
-    Assert(nvn.getKind() == kind::APPLY_CONSTRUCTOR);
-    if (et.is_invariant(d_tdb, nvn, x))
-    {
-      cexc[i] = true;
-      // we are tracking term size if positive
-      if (sz >= 0)
-      {
-        int s = d_tdb->getSygusTermSize(vn[i]);
-        sz = sz - s;
-      }
-    }
-    else
-    {
-      trb.replaceChild(i, vn[i]);
-    }
-  }
-  const Datatype& dt = ((DatatypeType)ntn.toType()).getDatatype();
-  int cindex = Datatype::indexOf(vn.getOperator().toExpr());
-  Assert(cindex >= 0 && cindex < (int)dt.getNumConstructors());
-  Node tst = datatypes::DatatypesRewriter::mkTester(n, cindex, dt);
-  exp.push_back(tst);
-  // if the operator of vn is different than vnr, then disunification obligation
-  // is met
-  if (!vnr.isNull())
-  {
-    if (vnr.getOperator() != vn.getOperator())
-    {
-      vnr = Node::null();
-      vnr_exp = NodeManager::currentNM()->mkConst(true);
-    }
-  }
-  for (unsigned i = 0; i < vn.getNumChildren(); i++)
-  {
-    Node sel = NodeManager::currentNM()->mkNode(
-        kind::APPLY_SELECTOR_TOTAL,
-        Node::fromExpr(dt[cindex].getSelectorInternal(ntn.toType(), i)),
-        n);
-    Node vnr_c = vnr.isNull() ? vnr : (vn[i] == vnr[i] ? Node::null() : vnr[i]);
-    if (cexc.find(i) == cexc.end())
-    {
-      trb.push(i);
-      Node vnr_exp_c;
-      getExplanationFor(
-          trb, sel, vn[i], exp, var_count, et, vnr_c, vnr_exp_c, sz);
-      trb.pop();
-      if (!vnr_c.isNull())
-      {
-        Assert(!vnr_exp_c.isNull());
-        if (vnr_exp_c.isConst() || vnr_exp.isNull())
-        {
-          // recursively satisfied the disunification obligation
-          if (vnr_exp_c.isConst())
-          {
-            // was successful, don't consider further
-            vnr = Node::null();
-          }
-          vnr_exp = vnr_exp_c;
-        }
-      }
-    }
-    else
-    {
-      // if excluded, we may need to add the explanation for this
-      if (vnr_exp.isNull() && !vnr_c.isNull())
-      {
-        vnr_exp = getExplanationForConstantEquality(sel, vnr[i]);
-      }
-    }
-  }
-}
-
-void SygusExplain::getExplanationFor(Node n,
-                                     Node vn,
-                                     std::vector<Node>& exp,
-                                     SygusInvarianceTest& et,
-                                     Node vnr,
-                                     unsigned& sz)
-{
-  // naive :
-  // return getExplanationForConstantEquality( n, vn, exp );
-
-  // set up the recursion object
-  std::map<TypeNode, int> var_count;
-  TermRecBuild trb;
-  trb.init(vn);
-  Node vnr_exp;
-  int sz_use = sz;
-  getExplanationFor(trb, n, vn, exp, var_count, et, vnr, vnr_exp, sz_use);
-  Assert(sz_use >= 0);
-  sz = sz_use;
-  Assert(vnr.isNull() || !vnr_exp.isNull());
-  if (!vnr_exp.isNull() && !vnr_exp.isConst())
-  {
-    exp.push_back(vnr_exp.negate());
-  }
-}
-
-void SygusExplain::getExplanationFor(Node n,
-                                     Node vn,
-                                     std::vector<Node>& exp,
-                                     SygusInvarianceTest& et)
-{
-  int sz = -1;
-  std::map<TypeNode, int> var_count;
-  TermRecBuild trb;
-  trb.init(vn);
-  Node vnr;
-  Node vnr_exp;
-  getExplanationFor(trb, n, vn, exp, var_count, et, vnr, vnr_exp, sz);
-}
-
-} /* CVC4::theory::quantifiers namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/sygus_explain.h b/src/theory/quantifiers/sygus_explain.h
deleted file mode 100644 (file)
index aa2ca0d..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_explain.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief sygus explanations
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_EXPLAIN_H
-#define __CVC4__THEORY__QUANTIFIERS__SYGUS_EXPLAIN_H
-
-#include <vector>
-
-#include "expr/node.h"
-#include "theory/quantifiers/sygus_invariance.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-/** Recursive term builder
- *
- * This is a utility used to generate variants
- * of a term n, where subterms of n can be replaced
- * by others via calls to replaceChild(...).
- *
- * This class maintains a "context", which indicates
- * a position in term n. Below, we call the subterm of
- * the initial term n at this position the "active term".
- *
- */
-class TermRecBuild
-{
- public:
-  TermRecBuild() {}
-  /** set the initial term to n
-   *
-   * The context initially empty, that is,
-   * the active term is initially n.
-   */
-  void init(Node n);
-
-  /** push the context
-   *
-   * This updates the context so that the
-   * active term is updated to curr[p], where
-   * curr is the previously active term.
-   */
-  void push(unsigned p);
-
-  /** pop the context */
-  void pop();
-  /** indicates that the i^th child of the active
-   * term should be replaced by r in calls to build().
-   */
-  void replaceChild(unsigned i, Node r);
-  /** get the i^th child of the active term */
-  Node getChild(unsigned i);
-  /** build the (modified) version of the term
-   * we intialized via the call to init().
-   */
-  Node build(unsigned p = 0);
-
- private:
-  /** stack of active terms */
-  std::vector<Node> d_term;
-  /** stack of children of active terms
-   * Notice that these may be modified with calls to replaceChild(...).
-   */
-  std::vector<std::vector<Node> > d_children;
-  /** stack the kind of active terms */
-  std::vector<Kind> d_kind;
-  /** stack of whether the active terms had an operator */
-  std::vector<bool> d_has_op;
-  /** stack of positions that were pushed via calls to push(...) */
-  std::vector<unsigned> d_pos;
-  /** add term to the context stack */
-  void addTerm(Node n);
-};
-
-/*The SygusExplain utility
- *
- * This class is used to produce explanations for refinement lemmas
- * in the counterexample-guided inductive synthesis (CEGIS) loop.
- *
- * When given an invariance test T traverses the AST of a given term,
- * uses TermRecBuild to replace various subterms by fresh variables and
- * recheck whether the invariant, as specified by T still holds.
- * If it does, then we may exclude the explanation for that subterm.
- *
- * For example, say we have that the current value of
- * (datatype) sygus term n is:
- *  (if (gt x 0) 0 0)
- * where if, gt, x, 0 are datatype constructors.
- * The explanation returned by getExplanationForConstantEquality
- * below for n and the above term is:
- *   { ((_ is if) n), ((_ is geq) n.0),
- *     ((_ is x) n.0.0), ((_ is 0) n.0.1),
- *     ((_ is 0) n.1), ((_ is 0) n.2) }
- *
- * This class can also return more precise
- * explanations based on a property that holds for
- * variants of n. For instance,
- * say we find that n's builtin analog rewrites to 0:
- *  ite( x>0, 0, 0 ) ----> 0
- * and we would like to find the minimal explanation for
- * why the builtin analog of n rewrites to 0.
- * We use the invariance test EquivSygusInvarianceTest
- * (see sygus_invariance.h) for doing this.
- * Using the SygusExplain::getExplanationFor method below,
- * this will invoke the invariant test to check, e.g.
- *   ite( x>0, 0, y1 ) ----> 0 ? fail
- *   ite( x>0, y2, 0 ) ----> 0 ? fail
- *   ite( y3, 0, 0 ) ----> 0 ? success
- * where y1, y2, y3 are fresh variables.
- * Hence the explanation for the condition x>0 is irrelevant.
- * This gives us the explanation:
- *   { ((_ is if) n), ((_ is 0) n.1), ((_ is 0) n.2) }
- * indicating that all terms of the form:
- *   (if _ 0 0) have a builtin equivalent that rewrites to 0.
- *
- * For details, see Reynolds et al SYNT 2017.
- *
- * Below, we let [[exp]]_n denote the term induced by
- * the explanation exp for n.
- * For example:
- *   exp = { ((_ is plus) n), ((_ is y) n.1) }
- * is such that:
- *   [[exp]]_n = (plus w y)
- * where w is a fresh variable.
- */
-class SygusExplain
-{
- public:
-  SygusExplain(TermDbSygus* tdb) : d_tdb(tdb) {}
-  ~SygusExplain() {}
-  /** get explanation for constant equality
-   *
-   * This function constructs an explanation, stored in exp, such that:
-   * - All formulas in exp are of the form ((_ is C) ns), where ns
-   *   is a chain of selectors applied to n, and
-   * - exp => ( n = vn )
-   */
-  void getExplanationForConstantEquality(Node n,
-                                         Node vn,
-                                         std::vector<Node>& exp);
-  /** returns the conjunction of exp computed in the above function */
-  Node getExplanationForConstantEquality(Node n, Node vn);
-
-  /** get explanation for constant equality
-   * This is identical to the above function except that we
-   * take an additional argument cexc, which says which
-   * children of vn should be excluded from the explanation.
-   *
-   * For example, if vn = plus( plus( x, x ), y ) and cexc is { 0 -> true },
-   * then the following is appended to exp :
-   *   { ((_ is plus) n), ((_ is y) n.1) }
-   * where notice that the 0^th argument of vn is excluded.
-   */
-  void getExplanationForConstantEquality(Node n,
-                                         Node vn,
-                                         std::vector<Node>& exp,
-                                         std::map<unsigned, bool>& cexc);
-  /** returns the conjunction of exp computed in the above function */
-  Node getExplanationForConstantEquality(Node n,
-                                         Node vn,
-                                         std::map<unsigned, bool>& cexc);
-
-  /** get explanation for
-   *
-   * This function constructs an explanation, stored in exp, such that:
-   * - All formulas in exp are of the form ((_ is C) ns), where ns
-   *   is a chain of selectors applied to n, and
-   * - The test et holds for [[exp]]_n, and
-   * - (if applicable) exp => ( n != vnr ).
-   *
-   * This function updates sz to be the term size of [[exp]]_n.
-   */
-  void getExplanationFor(Node n,
-                         Node vn,
-                         std::vector<Node>& exp,
-                         SygusInvarianceTest& et,
-                         Node vnr,
-                         unsigned& sz);
-  void getExplanationFor(Node n,
-                         Node vn,
-                         std::vector<Node>& exp,
-                         SygusInvarianceTest& et);
-
- private:
-  /** sygus term database associated with this utility */
-  TermDbSygus* d_tdb;
-  /** Helper function for getExplanationFor
-   * var_count is the number of free variables we have introduced,
-   *   per type, for the purposes of generalizing subterms of n.
-   * vnr_exp stores the explanation, if one exists, for
-   *   n != vnr.  It is only non-null if vnr is non-null.
-   */
-  void getExplanationFor(TermRecBuild& trb,
-                         Node n,
-                         Node vn,
-                         std::vector<Node>& exp,
-                         std::map<TypeNode, int>& var_count,
-                         SygusInvarianceTest& et,
-                         Node vnr,
-                         Node& vnr_exp,
-                         int& sz);
-};
-
-} /* CVC4::theory::quantifiers namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__SYGUS_EXPLAIN_H */
diff --git a/src/theory/quantifiers/sygus_grammar_cons.cpp b/src/theory/quantifiers/sygus_grammar_cons.cpp
deleted file mode 100644 (file)
index 0928800..0000000
+++ /dev/null
@@ -1,693 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_grammar_cons.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief implementation of class for constructing inductive datatypes that correspond to
- ** grammars that encode syntactic restrictions for SyGuS.
- **/
-#include "theory/quantifiers/sygus_grammar_cons.h"
-
-#include <stack>
-
-#include "expr/datatype.h"
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/ce_guided_conjecture.h"
-#include "theory/quantifiers/sygus_process_conj.h"
-#include "theory/quantifiers/sygus_grammar_norm.h"
-#include "theory/quantifiers/term_database_sygus.h"
-#include "theory/quantifiers/term_util.h"
-
-using namespace CVC4::kind;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-CegGrammarConstructor::CegGrammarConstructor(QuantifiersEngine* qe,
-                                             CegConjecture* p)
-    : d_qe(qe), d_parent(p), d_is_syntax_restricted(false), d_has_ite(true)
-{
-}
-
-void CegGrammarConstructor::collectTerms( Node n, std::map< TypeNode, std::vector< Node > >& consts ){
-  std::unordered_map<TNode, bool, TNodeHashFunction> visited;
-  std::unordered_map<TNode, bool, TNodeHashFunction>::iterator it;
-  std::stack<TNode> visit;
-  TNode cur;
-  visit.push(n);
-  do {
-    cur = visit.top();
-    visit.pop();
-    it = visited.find(cur);
-    if (it == visited.end()) {
-      visited[cur] = true;
-      // is this a constant?
-      if( cur.isConst() ){
-        TypeNode tn = cur.getType();
-        Node c = cur;
-        if( tn.isReal() ){
-          c = NodeManager::currentNM()->mkConst( c.getConst<Rational>().abs() );
-        }
-        if( std::find( consts[tn].begin(), consts[tn].end(), c )==consts[tn].end() ){
-          Trace("cegqi-debug") << "...consider const : " << c << std::endl;
-          consts[tn].push_back( c );
-        }
-      }
-      // recurse
-      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
-        visit.push(cur[i]);
-      }
-    }
-  } while (!visit.empty());
-}
-
-
-
-Node CegGrammarConstructor::process( Node q, std::map< Node, Node >& templates, std::map< Node, Node >& templates_arg ) {
-  // convert to deep embedding and finalize single invocation here
-  // now, construct the grammar
-  Trace("cegqi") << "CegConjecture : convert to deep embedding..." << std::endl;
-  std::map< TypeNode, std::vector< Node > > extra_cons;
-  if( options::sygusAddConstGrammar() ){
-    Trace("cegqi") << "CegConjecture : collect constants..." << std::endl;
-    collectTerms( q[1], extra_cons );
-  }
-
-  std::vector< Node > qchildren;
-  std::map< Node, Node > synth_fun_vars;
-  std::vector< Node > ebvl;
-  Node qbody_subs = q[1];
-  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
-    Node sf = q[0][i];
-    // v encodes the syntactic restrictions (via an inductive datatype) on sf
-    // from the input
-    Node v = sf.getAttribute(SygusSynthGrammarAttribute());
-    Assert(!v.isNull());
-    Node sfvl = sf.getAttribute(SygusSynthFunVarListAttribute());
-    // sfvl may be null for constant synthesis functions
-    Trace("cegqi-debug") << "...sygus var list associated with " << sf << " is " << sfvl << std::endl;
-
-    TypeNode tn;
-    std::stringstream ss;
-    ss << sf;
-    if( v.getType().isDatatype() && ((DatatypeType)v.getType().toType()).getDatatype().isSygus() ){
-      tn = v.getType();
-    }else{
-      // check which arguments are irrelevant
-      std::unordered_set<unsigned> arg_irrelevant;
-      d_parent->getProcess()->getIrrelevantArgs(sf, arg_irrelevant);
-      std::unordered_set<Node, NodeHashFunction> term_irrelevant;
-      // convert to term
-      for (std::unordered_set<unsigned>::iterator ita = arg_irrelevant.begin();
-           ita != arg_irrelevant.end();
-           ++ita)
-      {
-        unsigned arg = *ita;
-        Assert(arg < sfvl.getNumChildren());
-        term_irrelevant.insert(sfvl[arg]);
-      }
-
-      // make the default grammar
-      tn = mkSygusDefaultType(
-          v.getType(), sfvl, ss.str(), extra_cons, term_irrelevant);
-    }
-    // normalize type
-    SygusGrammarNorm sygus_norm(d_qe);
-    tn = sygus_norm.normalizeSygusType(tn, sfvl);
-    // check if there is a template
-    std::map< Node, Node >::iterator itt = templates.find( sf );
-    if( itt!=templates.end() ){
-      Node templ = itt->second;
-      TNode templ_arg = templates_arg[sf];
-      Assert( !templ_arg.isNull() );
-      Trace("cegqi-debug") << "Template for " << sf << " is : " << templ << " with arg " << templ_arg << std::endl;
-      // if there is a template for this argument, make a sygus type on top of it
-      if( options::sygusTemplEmbedGrammar() ){
-        Trace("cegqi-debug") << "  embed this template as a grammar..." << std::endl;
-        tn = mkSygusTemplateType( templ, templ_arg, tn, sfvl, ss.str() );
-      }else{
-        // otherwise, apply it as a preprocessing pass 
-        Trace("cegqi-debug") << "  apply this template as a substituion during preprocess..." << std::endl;
-        std::vector< Node > schildren;
-        std::vector< Node > largs;
-        for( unsigned j=0; j<sfvl.getNumChildren(); j++ ){
-          schildren.push_back( sfvl[j] );
-          largs.push_back( NodeManager::currentNM()->mkBoundVar( sfvl[j].getType() ) );
-        }
-        std::vector< Node > subsfn_children;
-        subsfn_children.push_back( sf );
-        subsfn_children.insert( subsfn_children.end(), schildren.begin(), schildren.end() );
-        Node subsfn = NodeManager::currentNM()->mkNode( kind::APPLY_UF, subsfn_children );
-        TNode subsf = subsfn;
-        Trace("cegqi-debug") << "  substitute arg : " << templ_arg << " -> " << subsf << std::endl;
-        templ = templ.substitute( templ_arg, subsf );
-        // substitute lambda arguments
-        templ = templ.substitute( schildren.begin(), schildren.end(), largs.begin(), largs.end() );
-        Node subsn = NodeManager::currentNM()->mkNode( kind::LAMBDA, NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, largs ), templ );
-        TNode var = sf;
-        TNode subs = subsn;
-        Trace("cegqi-debug") << "  substitute : " << var << " -> " << subs << std::endl;
-        qbody_subs = qbody_subs.substitute( var, subs );
-        Trace("cegqi-debug") << "  body is now : " << qbody_subs << std::endl;
-      }
-    }
-    d_qe->getTermDatabaseSygus()->registerSygusType( tn );
-    // check grammar restrictions
-    if( !d_qe->getTermDatabaseSygus()->sygusToBuiltinType( tn ).isBoolean() ){
-      if( !d_qe->getTermDatabaseSygus()->hasKind( tn, ITE ) ){
-        d_has_ite = false;
-      }
-    }
-    Assert( tn.isDatatype() );
-    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-    Assert( dt.isSygus() );
-    if( !dt.getSygusAllowAll() ){
-      d_is_syntax_restricted = true;
-    }
-
-    // ev is the first-order variable corresponding to this synth fun
-    std::stringstream ssf;
-    ssf << "f" << sf;
-    Node ev = NodeManager::currentNM()->mkBoundVar( ssf.str(), tn );
-    ebvl.push_back( ev );
-    synth_fun_vars[sf] = ev;
-    Trace("cegqi") << "...embedding synth fun : " << sf << " -> " << ev << std::endl;
-  }
-  qchildren.push_back( NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, ebvl ) );
-  if( qbody_subs!=q[1] ){
-    Trace("cegqi") << "...rewriting : " << qbody_subs << std::endl;
-    qbody_subs = Rewriter::rewrite( qbody_subs );
-    Trace("cegqi") << "...got : " << qbody_subs << std::endl;
-  }
-  qchildren.push_back( convertToEmbedding( qbody_subs, synth_fun_vars ) );
-  if( q.getNumChildren()==3 ){
-    qchildren.push_back( q[2] );
-  }
-  return NodeManager::currentNM()->mkNode( kind::FORALL, qchildren );
-}
-  
-Node CegGrammarConstructor::convertToEmbedding( Node n, std::map< Node, Node >& synth_fun_vars ){
-  std::unordered_map<TNode, Node, TNodeHashFunction> visited;
-  std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
-  std::stack<TNode> visit;
-  TNode cur;
-  visit.push(n);
-  do {
-    cur = visit.top();
-    visit.pop();
-    it = visited.find(cur);
-    if (it == visited.end()) {
-      visited[cur] = Node::null();
-      visit.push(cur);
-      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
-        visit.push(cur[i]);
-      }
-    } else if (it->second.isNull()) {
-      Node ret = cur;
-      Kind ret_k = cur.getKind();
-      Node op;
-      bool childChanged = false;
-      std::vector<Node> children;
-      // get the potential operator
-      if( cur.getNumChildren()>0 ){
-        if( cur.getKind()==kind::APPLY_UF ){
-          op = cur.getOperator();
-        }
-      }else{
-        op = cur;
-      }
-      // is the operator a synth function?
-      if( !op.isNull() ){
-        std::map< Node, Node >::iterator its = synth_fun_vars.find( op );
-        if( its!=synth_fun_vars.end() ){
-          Assert( its->second.getType().isDatatype() );
-          // will make into an application of an evaluation function
-          const Datatype& dt = ((DatatypeType)its->second.getType().toType()).getDatatype();
-          Assert( dt.isSygus() );
-          children.push_back( Node::fromExpr( dt.getSygusEvaluationFunc() ) );
-          children.push_back( its->second );
-          childChanged = true;
-          ret_k = kind::APPLY_UF;
-        }
-      }
-      if( !childChanged ){
-        // otherwise, we apply the previous operator
-        if( cur.getMetaKind() == kind::metakind::PARAMETERIZED ){
-          children.push_back( cur.getOperator() );
-        }
-      }
-      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
-        it = visited.find(cur[i]);
-        Assert(it != visited.end());
-        Assert(!it->second.isNull());
-        childChanged = childChanged || cur[i] != it->second;
-        children.push_back(it->second);
-      }
-      if (childChanged) {
-        ret = NodeManager::currentNM()->mkNode(ret_k, children);
-      }
-      visited[cur] = ret;
-    }
-  } while (!visit.empty());
-  Assert(visited.find(n) != visited.end());
-  Assert(!visited.find(n)->second.isNull());
-  return visited[n];
-}
-
-
-TypeNode CegGrammarConstructor::mkUnresolvedType(const std::string& name, std::set<Type>& unres) {
-  TypeNode unresolved = NodeManager::currentNM()->mkSort(name, ExprManager::SORT_FLAG_PLACEHOLDER);
-  unres.insert( unresolved.toType() );
-  return unresolved;
-}
-
-void CegGrammarConstructor::mkSygusConstantsForType( TypeNode type, std::vector<CVC4::Node>& ops ) {
-  if (type.isReal())
-  {
-    ops.push_back(NodeManager::currentNM()->mkConst(Rational(0)));
-    ops.push_back(NodeManager::currentNM()->mkConst(Rational(1)));
-  }else if( type.isBitVector() ){
-    unsigned sz = ((BitVectorType)type.toType()).getSize();
-    BitVector bval0(sz, (unsigned int)0);
-    ops.push_back( NodeManager::currentNM()->mkConst(bval0) );
-    BitVector bval1(sz, (unsigned int)1);
-    ops.push_back( NodeManager::currentNM()->mkConst(bval1) );
-  }else if( type.isBoolean() ){
-    ops.push_back(NodeManager::currentNM()->mkConst(true));
-    ops.push_back(NodeManager::currentNM()->mkConst(false));
-  }
-  //TODO : others?
-}
-
-void CegGrammarConstructor::collectSygusGrammarTypesFor( TypeNode range, std::vector< TypeNode >& types, std::map< TypeNode, std::vector< DatatypeConstructorArg > >& sels ){
-  if( !range.isBoolean() ){
-    if( std::find( types.begin(), types.end(), range )==types.end() ){
-      Trace("sygus-grammar-def") << "...will make grammar for " << range << std::endl;
-      types.push_back( range );
-      if( range.isDatatype() ){
-        const Datatype& dt = ((DatatypeType)range.toType()).getDatatype();
-        for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-          for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
-            TypeNode crange = TypeNode::fromType( ((SelectorType)dt[i][j].getType()).getRangeType() );
-            sels[crange].push_back( dt[i][j] );
-            collectSygusGrammarTypesFor( crange, types, sels );
-          }
-        }
-      }
-    }
-  }
-}
-
-void CegGrammarConstructor::mkSygusDefaultGrammar(
-    TypeNode range,
-    Node bvl,
-    const std::string& fun,
-    std::map<TypeNode, std::vector<Node> >& extra_cons,
-    std::unordered_set<Node, NodeHashFunction>& term_irrelevant,
-    std::vector<CVC4::Datatype>& datatypes,
-    std::set<Type>& unres)
-{
-  Trace("sygus-grammar-def") << "Construct default grammar for " << fun << " "
-                             << range << std::endl;
-  // collect the variables
-  std::vector<Node> sygus_vars;
-  if( !bvl.isNull() ){
-    for( unsigned i=0; i<bvl.getNumChildren(); i++ ){
-      if (term_irrelevant.find(bvl[i]) == term_irrelevant.end())
-      {
-        sygus_vars.push_back(bvl[i]);
-      }
-      else
-      {
-        Trace("sygus-grammar-def") << "...synth var " << bvl[i]
-                                   << " has been marked irrelevant."
-                                   << std::endl;
-      }
-    }
-  }
-  //if( !range.isBoolean() && !range.isInteger() && !range.isBitVector() && !range.isDatatype() ){
-  //  parseError("No default grammar for type.");
-  //}
-  std::vector< std::vector< Expr > > ops;
-  int startIndex = -1;
-  std::map< Type, Type > sygus_to_builtin;
-
-  std::vector< TypeNode > types;
-  std::map< TypeNode, std::vector< DatatypeConstructorArg > > sels;
-  //types for each of the variables of parametric sort
-  for( unsigned i=0; i<sygus_vars.size(); i++ ){
-    collectSygusGrammarTypesFor( sygus_vars[i].getType(), types, sels );
-  }
-  //types connected to range
-  collectSygusGrammarTypesFor( range, types, sels );
-
-  //name of boolean sort
-  std::stringstream ssb;
-  ssb << fun << "_Bool";
-  std::string dbname = ssb.str();
-  Type unres_bt = mkUnresolvedType(ssb.str(), unres).toType();
-
-  std::vector< Type > unres_types;
-  std::map< TypeNode, Type > type_to_unres;
-  for( unsigned i=0; i<types.size(); i++ ){
-    std::stringstream ss;
-    ss << fun << "_" << types[i];
-    std::string dname = ss.str();
-    datatypes.push_back(Datatype(dname));
-    ops.push_back(std::vector< Expr >());
-    //make unresolved type
-    Type unres_t = mkUnresolvedType(dname, unres).toType();
-    unres_types.push_back(unres_t);
-    type_to_unres[types[i]] = unres_t;
-    sygus_to_builtin[unres_t] = types[i].toType();
-  }
-  for( unsigned i=0; i<types.size(); i++ ){
-    Trace("sygus-grammar-def") << "Make grammar for " << types[i] << " " << unres_types[i] << std::endl;
-    std::vector<std::string> cnames;
-    std::vector<std::vector<CVC4::Type> > cargs;
-    Type unres_t = unres_types[i];
-    //add variables
-    for( unsigned j=0; j<sygus_vars.size(); j++ ){
-      if( sygus_vars[j].getType()==types[i] ){
-        std::stringstream ss;
-        ss << sygus_vars[j];
-        Trace("sygus-grammar-def") << "...add for variable " << ss.str() << std::endl;
-        ops[i].push_back( sygus_vars[j].toExpr() );
-        cnames.push_back( ss.str() );
-        cargs.push_back( std::vector< CVC4::Type >() );
-      }
-    }
-    //add constants
-    std::vector< Node > consts;
-    mkSygusConstantsForType( types[i], consts );
-    std::map< TypeNode, std::vector< Node > >::iterator itec = extra_cons.find( types[i] );
-    if( itec!=extra_cons.end() ){
-      //consts.insert( consts.end(), itec->second.begin(), itec->second.end() );
-      for( unsigned j=0; j<itec->second.size(); j++ ){
-        if( std::find( consts.begin(), consts.end(), itec->second[j] )==consts.end() ){
-          consts.push_back( itec->second[j] );
-        }
-      }
-    }
-    for( unsigned j=0; j<consts.size(); j++ ){
-      std::stringstream ss;
-      ss << consts[j];
-      Trace("sygus-grammar-def") << "...add for constant " << ss.str() << std::endl;
-      ops[i].push_back( consts[j].toExpr() );
-      cnames.push_back( ss.str() );
-      cargs.push_back( std::vector< CVC4::Type >() );
-    }
-    //ITE
-    CVC4::Kind k = kind::ITE;
-    Trace("sygus-grammar-def") << "...add for " << k << std::endl;
-    ops[i].push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
-    cnames.push_back( kind::kindToString(k) );
-    cargs.push_back( std::vector< CVC4::Type >() );
-    cargs.back().push_back(unres_bt);
-    cargs.back().push_back(unres_t);
-    cargs.back().push_back(unres_t);
-
-    if (types[i].isReal())
-    {
-      for (unsigned j = 0; j < 2; j++)
-      {
-        Kind k = j == 0 ? PLUS : MINUS;
-        Trace("sygus-grammar-def") << "...add for " << k << std::endl;
-        ops[i].push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
-        cnames.push_back(kind::kindToString(k));
-        cargs.push_back(std::vector<CVC4::Type>());
-        cargs.back().push_back(unres_t);
-        cargs.back().push_back(unres_t);
-      }
-      if (!types[i].isInteger())
-      {
-        Trace("sygus-grammar-def") << "...Dedicate to Real\n";
-        /* Creating type for positive integers */
-        std::stringstream ss;
-        ss << fun << "_PosInt";
-        std::string pos_int_name = ss.str();
-        // make unresolved type
-        Type unres_pos_int_t = mkUnresolvedType(pos_int_name, unres).toType();
-        // make data type
-        datatypes.push_back(Datatype(pos_int_name));
-        /* add placeholders */
-        std::vector<Expr> ops_pos_int;
-        std::vector<std::string> cnames_pos_int;
-        std::vector<std::vector<Type>> cargs_pos_int;
-        /* Add operator 1 */
-        Trace("sygus-grammar-def") << "\t...add for 1 to Pos_Int\n";
-        ops_pos_int.push_back(
-            NodeManager::currentNM()->mkConst(Rational(1)).toExpr());
-        ss << "_1";
-        cnames_pos_int.push_back(ss.str());
-        cargs_pos_int.push_back(std::vector<Type>());
-        /* Add operator PLUS */
-        Kind k = PLUS;
-        Trace("sygus-grammar-def") << "\t...add for PLUS to Pos_Int\n";
-        ops_pos_int.push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
-        cnames_pos_int.push_back(kindToString(k));
-        cargs_pos_int.push_back(std::vector<Type>());
-        cargs_pos_int.back().push_back(unres_pos_int_t);
-        cargs_pos_int.back().push_back(unres_pos_int_t);
-        datatypes.back().setSygus(types[i].toType(), bvl.toExpr(), true, true);
-        for (unsigned j = 0; j < ops_pos_int.size(); j++)
-        {
-          datatypes.back().addSygusConstructor(
-              ops_pos_int[j], cnames_pos_int[j], cargs_pos_int[j]);
-        }
-        Trace("sygus-grammar-def")
-            << "...built datatype " << datatypes.back() << " ";
-        /* Adding division at root */
-        k = DIVISION;
-        Trace("sygus-grammar-def") << "\t...add for " << k << std::endl;
-        ops[i].push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
-        cnames.push_back(kindToString(k));
-        cargs.push_back(std::vector<Type>());
-        cargs.back().push_back(unres_t);
-        cargs.back().push_back(unres_pos_int_t);
-      }
-    }else if( types[i].isDatatype() ){
-      Trace("sygus-grammar-def") << "...add for constructors" << std::endl;
-      const Datatype& dt = ((DatatypeType)types[i].toType()).getDatatype();
-      for( unsigned k=0; k<dt.getNumConstructors(); k++ ){
-        Trace("sygus-grammar-def") << "...for " << dt[k].getName() << std::endl;
-        ops[i].push_back( dt[k].getConstructor() );
-        cnames.push_back( dt[k].getName() );
-        cargs.push_back( std::vector< CVC4::Type >() );
-        for( unsigned j=0; j<dt[k].getNumArgs(); j++ ){
-          TypeNode crange = TypeNode::fromType( ((SelectorType)dt[k][j].getType()).getRangeType() );
-          //Assert( type_to_unres.find(crange)!=type_to_unres.end() );
-          cargs.back().push_back( type_to_unres[crange] );
-        }
-      }
-    }else{
-      std::stringstream sserr;
-      sserr << "No implementation for default Sygus grammar of type " << types[i] << std::endl;
-      //AlwaysAssert( false, sserr.str() );
-      // FIXME
-      AlwaysAssert( false );
-    }
-    //add for all selectors to this type
-    if( !sels[types[i]].empty() ){
-      Trace("sygus-grammar-def") << "...add for selectors" << std::endl;
-      for( unsigned j=0; j<sels[types[i]].size(); j++ ){
-        Trace("sygus-grammar-def") << "...for " << sels[types[i]][j].getName() << std::endl;
-        TypeNode arg_type = TypeNode::fromType( ((SelectorType)sels[types[i]][j].getType()).getDomain() );
-        ops[i].push_back( sels[types[i]][j].getSelector() );
-        cnames.push_back( sels[types[i]][j].getName() );
-        cargs.push_back( std::vector< CVC4::Type >() );
-        //Assert( type_to_unres.find(arg_type)!=type_to_unres.end() );
-        cargs.back().push_back( type_to_unres[arg_type] );
-      }
-    }
-    Trace("sygus-grammar-def") << "...make datatype " << datatypes[i] << std::endl;
-    datatypes[i].setSygus( types[i].toType(), bvl.toExpr(), true, true );
-    for( unsigned j=0; j<ops[i].size(); j++ ){
-      datatypes[i].addSygusConstructor( ops[i][j], cnames[j], cargs[j] );
-    }
-    Trace("sygus-grammar-def")
-        << "...built datatype " << datatypes[i] << " ";
-    //sorts.push_back( types[i] );
-    //set start index if applicable
-    if( types[i]==range ){
-      startIndex = i;
-    }
-  }
-
-  //make Boolean type
-  TypeNode btype = NodeManager::currentNM()->booleanType();
-  datatypes.push_back(Datatype(dbname));
-  ops.push_back(std::vector<Expr>());
-  std::vector<std::string> cnames;
-  std::vector<std::vector< Type > > cargs;
-  Trace("sygus-grammar-def") << "Make grammar for " << btype << " " << datatypes.back() << std::endl;
-  //add variables
-  for( unsigned i=0; i<sygus_vars.size(); i++ ){
-    if( sygus_vars[i].getType().isBoolean() ){
-      std::stringstream ss;
-      ss << sygus_vars[i];
-      Trace("sygus-grammar-def") << "...add for variable " << ss.str() << std::endl;
-      ops.back().push_back( sygus_vars[i].toExpr() );
-      cnames.push_back( ss.str() );
-      cargs.push_back( std::vector< CVC4::Type >() );
-    }
-  }
-  //add constants if no variables and no connected types
-  if( ops.back().empty() && types.empty() ){
-    std::vector< Node > consts;
-    mkSygusConstantsForType( btype, consts );
-    for( unsigned j=0; j<consts.size(); j++ ){
-      std::stringstream ss;
-      ss << consts[j];
-      Trace("sygus-grammar-def") << "...add for constant " << ss.str() << std::endl;
-      ops.back().push_back( consts[j].toExpr() );
-      cnames.push_back( ss.str() );
-      cargs.push_back( std::vector< CVC4::Type >() );
-    }
-  }
-  //add operators
-  for( unsigned i=0; i<3; i++ ){
-    CVC4::Kind k = i==0 ? kind::NOT : ( i==1 ? kind::AND : kind::OR );
-    Trace("sygus-grammar-def") << "...add for " << k << std::endl;
-    ops.back().push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
-    cnames.push_back(kind::kindToString(k));
-    cargs.push_back( std::vector< CVC4::Type >() );
-    if( k==kind::NOT ){
-      cargs.back().push_back(unres_bt);
-    }else if( k==kind::AND || k==kind::OR ){
-      cargs.back().push_back(unres_bt);
-      cargs.back().push_back(unres_bt);
-    }
-  }
-  //add predicates for types
-  for( unsigned i=0; i<types.size(); i++ ){
-    Trace("sygus-grammar-def") << "...add predicates for " << types[i] << std::endl;
-    //add equality per type
-    CVC4::Kind k = kind::EQUAL;
-    Trace("sygus-grammar-def") << "...add for " << k << std::endl;
-    ops.back().push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
-    std::stringstream ss;
-    ss << kind::kindToString(k) << "_" << types[i];
-    cnames.push_back(ss.str());
-    cargs.push_back( std::vector< CVC4::Type >() );
-    cargs.back().push_back(unres_types[i]);
-    cargs.back().push_back(unres_types[i]);
-    //type specific predicates
-    if (types[i].isReal())
-    {
-      CVC4::Kind k = kind::LEQ;
-      Trace("sygus-grammar-def") << "...add for " << k << std::endl;
-      ops.back().push_back(NodeManager::currentNM()->operatorOf(k).toExpr());
-      cnames.push_back(kind::kindToString(k));
-      cargs.push_back( std::vector< CVC4::Type >() );
-      cargs.back().push_back(unres_types[i]);
-      cargs.back().push_back(unres_types[i]);
-    }else if( types[i].isDatatype() ){
-      //add for testers
-      Trace("sygus-grammar-def") << "...add for testers" << std::endl;
-      const Datatype& dt = ((DatatypeType)types[i].toType()).getDatatype();
-      for( unsigned k=0; k<dt.getNumConstructors(); k++ ){
-        Trace("sygus-grammar-def") << "...for " << dt[k].getTesterName() << std::endl;
-        ops.back().push_back(dt[k].getTester());
-        cnames.push_back(dt[k].getTesterName());
-        cargs.push_back( std::vector< CVC4::Type >() );
-        cargs.back().push_back(unres_types[i]);
-      }
-    }
-  }
-  if( range==btype ){
-    startIndex = datatypes.size()-1;
-  }
-  Trace("sygus-grammar-def") << "...make datatype " << datatypes.back() << std::endl;
-  datatypes.back().setSygus( btype.toType(), bvl.toExpr(), true, true );
-  for( unsigned j=0; j<ops.back().size(); j++ ){
-    datatypes.back().addSygusConstructor( ops.back()[j], cnames[j], cargs[j] );
-  }
-  //sorts.push_back( btype );
-  Trace("sygus-grammar-def") << "...finished make default grammar for " << fun << " " << range << std::endl;
-  
-  if( startIndex>0 ){
-    CVC4::Datatype tmp_dt = datatypes[0];
-    datatypes[0] = datatypes[startIndex];
-    datatypes[startIndex] = tmp_dt;
-  }
-}
-
-TypeNode CegGrammarConstructor::mkSygusDefaultType(
-    TypeNode range,
-    Node bvl,
-    const std::string& fun,
-    std::map<TypeNode, std::vector<Node> >& extra_cons,
-    std::unordered_set<Node, NodeHashFunction>& term_irrelevant)
-{
-  Trace("sygus-grammar-def") << "*** Make sygus default type " << range << ", make datatypes..." << std::endl;
-  for( std::map< TypeNode, std::vector< Node > >::iterator it = extra_cons.begin(); it != extra_cons.end(); ++it ){
-    Trace("sygus-grammar-def") << "    ...using " << it->second.size() << " extra constants for " << it->first << std::endl;
-  }
-  std::set<Type> unres;
-  std::vector< CVC4::Datatype > datatypes;
-  mkSygusDefaultGrammar(
-      range, bvl, fun, extra_cons, term_irrelevant, datatypes, unres);
-  Trace("sygus-grammar-def")  << "...made " << datatypes.size() << " datatypes, now make mutual datatype types..." << std::endl;
-  Assert( !datatypes.empty() );
-  std::vector<DatatypeType> types = NodeManager::currentNM()->toExprManager()->mkMutualDatatypeTypes(datatypes, unres);
-  Assert( types.size()==datatypes.size() );
-  return TypeNode::fromType( types[0] );
-}
-
-TypeNode CegGrammarConstructor::mkSygusTemplateTypeRec( Node templ, Node templ_arg, TypeNode templ_arg_sygus_type, Node bvl, 
-                                              const std::string& fun, unsigned& tcount ) {
-  if( templ==templ_arg ){
-    //Assert( templ_arg.getType()==sygusToBuiltinType( templ_arg_sygus_type ) );
-    return templ_arg_sygus_type;
-  }else{
-    tcount++;
-    std::set<Type> unres;
-    std::vector< CVC4::Datatype > datatypes;
-    std::stringstream ssd;
-    ssd << fun << "_templ_" << tcount;
-    std::string dbname = ssd.str();
-    datatypes.push_back(Datatype(dbname));
-    Node op;
-    std::vector< Type > argTypes;
-    if( templ.getNumChildren()==0 ){
-      // TODO : can short circuit to this case when !TermUtil::containsTerm( templ, templ_arg )
-      op = templ;
-    }else{
-      Assert( templ.hasOperator() );
-      op = templ.getOperator();
-      // make constructor taking arguments types from children
-      for( unsigned i=0; i<templ.getNumChildren(); i++ ){
-        //recursion depth bound by the depth of SyGuS template expressions (low)
-        TypeNode tnc = mkSygusTemplateTypeRec( templ[i], templ_arg, templ_arg_sygus_type, bvl, fun, tcount );
-        argTypes.push_back( tnc.toType() );
-      }
-    }
-    std::stringstream ssdc;
-    ssdc << fun << "_templ_cons_" << tcount;
-    std::string cname = ssdc.str();
-    // we have a single sygus constructor that encodes the template
-    datatypes.back().addSygusConstructor( op.toExpr(), cname, argTypes );
-    datatypes.back().setSygus( templ.getType().toType(), bvl.toExpr(), true, true );
-    std::vector<DatatypeType> types = NodeManager::currentNM()->toExprManager()->mkMutualDatatypeTypes(datatypes, unres);
-    Assert( types.size()==1 );
-    return TypeNode::fromType( types[0] );
-  }
-}
-
-TypeNode CegGrammarConstructor::mkSygusTemplateType( Node templ, Node templ_arg, TypeNode templ_arg_sygus_type, Node bvl, 
-                                                     const std::string& fun ) {
-  unsigned tcount = 0;
-  return mkSygusTemplateTypeRec( templ, templ_arg, templ_arg_sygus_type, bvl, fun, tcount );
-}
-
-}/* namespace CVC4::theory::quantifiers */
-}/* namespace CVC4::theory */
-}/* namespace CVC4 */
diff --git a/src/theory/quantifiers/sygus_grammar_cons.h b/src/theory/quantifiers/sygus_grammar_cons.h
deleted file mode 100644 (file)
index 4e486f8..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_grammar_cons.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief class for constructing inductive datatypes that correspond to
- ** grammars that encode syntactic restrictions for SyGuS.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_CONS_H
-#define __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_CONS_H
-
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class CegConjecture;
-
-/** utility for constructing datatypes that correspond to syntactic restrictions,
-* and applying the deep embedding from Section 4 of Reynolds et al CAV 2015.
-*/
-class CegGrammarConstructor
-{
-public:
- CegGrammarConstructor(QuantifiersEngine* qe, CegConjecture* p);
- ~CegGrammarConstructor() {}
- /** process
-  * This converts node q based on its deep embedding
-  * (Section 4 of Reynolds et al CAV 2015).
-  * The syntactic restrictions are associated with
-  * the functions-to-synthesize using the attribute
-  * SygusSynthGrammarAttribute.
-  * The arguments templates and template_args
-  * indicate templates for the function to synthesize,
-  * in particular the solution for the i^th function
-  * to synthesis must be of the form
-  *   templates[i]{ templates_arg[i] -> t }
-  * for some t if !templates[i].isNull().
-  */
- Node process(Node q,
-              std::map<Node, Node>& templates,
-              std::map<Node, Node>& templates_arg);
- /** is the syntax restricted? */
- bool isSyntaxRestricted() { return d_is_syntax_restricted; }
- /** does the syntax allow ITE expressions? */
- bool hasSyntaxITE() { return d_has_ite; }
- /** make the default sygus datatype type corresponding to builtin type range
- *   bvl is the set of free variables to include in the grammar
- *   fun is for naming
- *   extra_cons is a set of extra constant symbols to include in the grammar
- *   term_irrelevant is a set of terms that should not be included in the
- *      grammar.
- */
- static TypeNode mkSygusDefaultType(
-     TypeNode range,
-     Node bvl,
-     const std::string& fun,
-     std::map<TypeNode, std::vector<Node> >& extra_cons,
-     std::unordered_set<Node, NodeHashFunction>& term_irrelevant);
- /** make the default sygus datatype type corresponding to builtin type range */
- static TypeNode mkSygusDefaultType(TypeNode range,
-                                    Node bvl,
-                                    const std::string& fun)
- {
-   std::map<TypeNode, std::vector<Node> > extra_cons;
-   std::unordered_set<Node, NodeHashFunction> term_irrelevant;
-   return mkSygusDefaultType(range, bvl, fun, extra_cons, term_irrelevant);
-  }
-  /** make the sygus datatype type that encodes the solution space (lambda
-  * templ_arg. templ[templ_arg]) where templ_arg
-  * has syntactic restrictions encoded by sygus type templ_arg_sygus_type
-  *   bvl is the set of free variables to include in the grammar
-  *   fun is for naming
-  */
-  static TypeNode mkSygusTemplateType( Node templ, Node templ_arg, TypeNode templ_arg_sygus_type, Node bvl, const std::string& fun );
-private:
-  /** reference to quantifier engine */
-  QuantifiersEngine * d_qe;
-  /** parent conjecture
-  * This contains global information about the synthesis conjecture.
-  */
-  CegConjecture* d_parent;
-  /** is the syntax restricted? */
-  bool d_is_syntax_restricted;
-  /** does the syntax allow ITE expressions? */
-  bool d_has_ite;
-  /** collect terms */
-  void collectTerms( Node n, std::map< TypeNode, std::vector< Node > >& consts );
-  /** convert node n based on deep embedding (Section 4 of Reynolds et al CAV 2015) */
-  Node convertToEmbedding( Node n, std::map< Node, Node >& synth_fun_vars );
-  //---------------- grammar construction
-  // helper for mkSygusDefaultGrammar (makes unresolved type for mutually recursive datatype construction)
-  static TypeNode mkUnresolvedType(const std::string& name, std::set<Type>& unres);
-  // make the builtin constants for type type that should be included in a sygus grammar
-  static void mkSygusConstantsForType( TypeNode type, std::vector<CVC4::Node>& ops );
-  // collect the list of types that depend on type range
-  static void collectSygusGrammarTypesFor( TypeNode range, std::vector< TypeNode >& types, std::map< TypeNode, std::vector< DatatypeConstructorArg > >& sels );
-  /** helper function for function mkSygusDefaultType
-  * Collects a set of mutually recursive datatypes "datatypes" corresponding to
-  * encoding type "range" to SyGuS.
-  *   unres is used for the resulting call to mkMutualDatatypeTypes
-  */
-  static void mkSygusDefaultGrammar(
-      TypeNode range,
-      Node bvl,
-      const std::string& fun,
-      std::map<TypeNode, std::vector<Node> >& extra_cons,
-      std::unordered_set<Node, NodeHashFunction>& term_irrelevant,
-      std::vector<CVC4::Datatype>& datatypes,
-      std::set<Type>& unres);
-  // helper function for mkSygusTemplateType
-  static TypeNode mkSygusTemplateTypeRec( Node templ, Node templ_arg, TypeNode templ_arg_sygus_type, Node bvl, 
-                                          const std::string& fun, unsigned& tcount );
-  //---------------- end grammar construction
-};
-
-} /* namespace CVC4::theory::quantifiers */
-} /* namespace CVC4::theory */
-} /* namespace CVC4 */
-
-#endif
diff --git a/src/theory/quantifiers/sygus_grammar_norm.cpp b/src/theory/quantifiers/sygus_grammar_norm.cpp
deleted file mode 100644 (file)
index 6776aca..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_grammar_norm.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Haniel Barbosa
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief implementation of class for for simplifying SyGuS grammars after they
- ** are encoded into datatypes.
- **/
-
-#include "theory/quantifiers/sygus_grammar_norm.h"
-
-#include "expr/datatype.h"
-#include "options/quantifiers_options.h"
-#include "printer/sygus_print_callback.h"
-#include "smt/smt_engine.h"
-#include "smt/smt_engine_scope.h"
-#include "theory/quantifiers/ce_guided_conjecture.h"
-#include "theory/quantifiers/sygus_grammar_red.h"
-#include "theory/quantifiers/term_database_sygus.h"
-#include "theory/quantifiers/term_util.h"
-
-#include <numeric>  // for std::iota
-
-using namespace CVC4::kind;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-bool OpPosTrie::getOrMakeType(TypeNode tn,
-                              TypeNode& unres_tn,
-                              const std::vector<unsigned>& op_pos,
-                              unsigned ind)
-{
-  if (ind == op_pos.size())
-  {
-    /* Found type */
-    if (!d_unres_tn.isNull())
-    {
-      Trace("sygus-grammar-normalize-trie")
-          << "\tFound type " << d_unres_tn << "\n";
-      unres_tn = d_unres_tn;
-      return true;
-    }
-    /* Creating unresolved type */
-    std::stringstream ss;
-    ss << tn << "_";
-    for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
-    {
-      ss << "_" << std::to_string(op_pos[i]);
-    }
-    d_unres_tn = NodeManager::currentNM()->mkSort(
-        ss.str(), ExprManager::SORT_FLAG_PLACEHOLDER);
-    Trace("sygus-grammar-normalize-trie")
-        << "\tCreating type " << d_unres_tn << "\n";
-    unres_tn = d_unres_tn;
-    return false;
-  }
-  /* Go to next node */
-  return d_children[op_pos[ind]].getOrMakeType(tn, unres_tn, op_pos, ind + 1);
-}
-
-void SygusGrammarNorm::TypeObject::addConsInfo(SygusGrammarNorm* sygus_norm,
-                                               const DatatypeConstructor& cons)
-{
-  Trace("sygus-grammar-normalize") << "...for " << cons.getName() << "\n";
-  /* Recover the sygus operator to not lose reference to the original
-   * operator (NOT, ITE, etc) */
-  Node exp_sop_n = Node::fromExpr(
-      smt::currentSmtEngine()->expandDefinitions(cons.getSygusOp()));
-  d_ops.push_back(Rewriter::rewrite(exp_sop_n));
-  Trace("sygus-grammar-normalize-defs")
-      << "\tOriginal op: " << cons.getSygusOp()
-      << "\n\tExpanded one: " << exp_sop_n
-      << "\n\tRewritten one: " << d_ops.back() << "\n\n";
-  d_cons_names.push_back(cons.getName());
-  d_pc.push_back(cons.getSygusPrintCallback());
-  d_weight.push_back(cons.getWeight());
-  d_cons_args_t.push_back(std::vector<Type>());
-  for (const DatatypeConstructorArg& arg : cons)
-  {
-    /* Collect unresolved type nodes corresponding to the typenode of the
-     * arguments */
-    d_cons_args_t.back().push_back(
-        sygus_norm
-            ->normalizeSygusRec(TypeNode::fromType(
-                static_cast<SelectorType>(arg.getType()).getRangeType()))
-            .toType());
-  }
-}
-
-void SygusGrammarNorm::TypeObject::buildDatatype(SygusGrammarNorm* sygus_norm,
-                                                 const Datatype& dt)
-{
-  /* Use the sygus type to not lose reference to the original types (Bool,
-   * Int, etc) */
-  d_dt.setSygus(dt.getSygusType(),
-                sygus_norm->d_sygus_vars.toExpr(),
-                dt.getSygusAllowConst(),
-                dt.getSygusAllowAll());
-  for (unsigned i = 0, size_d_ops = d_ops.size(); i < size_d_ops; ++i)
-  {
-    d_dt.addSygusConstructor(d_ops[i].toExpr(),
-                             d_cons_names[i],
-                             d_cons_args_t[i],
-                             d_pc[i],
-                             d_weight[i]);
-  }
-  Trace("sygus-grammar-normalize") << "...built datatype " << d_dt << " ";
-  /* Add to global accumulators */
-  sygus_norm->d_dt_all.push_back(d_dt);
-  sygus_norm->d_unres_t_all.insert(d_unres_tn.toType());
-  Trace("sygus-grammar-normalize") << "---------------------------------\n";
-}
-
-void SygusGrammarNorm::TransfDrop::buildType(SygusGrammarNorm* sygus_norm,
-                                             TypeObject& to,
-                                             const Datatype& dt,
-                                             std::vector<unsigned>& op_pos)
-{
-  std::vector<unsigned> difference;
-  std::set_difference(op_pos.begin(),
-                      op_pos.end(),
-                      d_drop_indices.begin(),
-                      d_drop_indices.end(),
-                      std::back_inserter(difference));
-  op_pos = difference;
-}
-
-/* TODO #1304: have more operators and types. Moreover, have more general ways
-   of finding kind of operator, e.g. if op is (\lambda xy. x + y) this
-   function should realize that it is chainable for integers */
-bool SygusGrammarNorm::TransfChain::isChainable(TypeNode tn, Node op)
-{
-  /* Checks whether operator occurs chainable for its type */
-  if (tn.isInteger() && NodeManager::currentNM()->operatorToKind(op) == PLUS)
-  {
-    return true;
-  }
-  return false;
-}
-
-/* TODO #1304: have more operators and types. Moreover, have more general ways
-   of finding kind of operator, e.g. if op is (\lambda xy. x + y) this
-   function should realize that it is chainable for integers */
-bool SygusGrammarNorm::TransfChain::isId(TypeNode tn, Node op, Node n)
-{
-  if (tn.isInteger() && NodeManager::currentNM()->operatorToKind(op) == PLUS
-      && n == TermUtil::mkTypeValue(tn, 0))
-  {
-    return true;
-  }
-  return false;
-}
-
-void SygusGrammarNorm::TransfChain::buildType(SygusGrammarNorm* sygus_norm,
-                                              TypeObject& to,
-                                              const Datatype& dt,
-                                              std::vector<unsigned>& op_pos)
-{
-  NodeManager* nm = NodeManager::currentNM();
-  std::vector<unsigned> claimed(d_elem_pos);
-  claimed.push_back(d_chain_op_pos);
-  unsigned nb_op_pos = op_pos.size();
-  /* TODO do this properly */
-  /* Remove from op_pos the positions claimed by the transformation */
-  std::sort(op_pos.begin(), op_pos.end());
-  std::sort(claimed.begin(), claimed.end());
-  std::vector<unsigned> difference;
-  std::set_difference(op_pos.begin(),
-                      op_pos.end(),
-                      claimed.begin(),
-                      claimed.end(),
-                      std::back_inserter(difference));
-  op_pos = difference;
-  if (Trace.isOn("sygus-grammar-normalize-chain"))
-  {
-    Trace("sygus-grammar-normalize-chain")
-        << "OP at " << d_chain_op_pos << "\n"
-        << d_elem_pos.size() << " d_elem_pos: ";
-    for (unsigned i = 0, size = d_elem_pos.size(); i < size; ++i)
-    {
-      Trace("sygus-grammar-normalize-chain") << d_elem_pos[i] << " ";
-    }
-    Trace("sygus-grammar-normalize-chain")
-        << "\n"
-        << op_pos.size() << " remaining op_pos: ";
-    for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
-    {
-      Trace("sygus-grammar-normalize-chain") << op_pos[i] << " ";
-    }
-    Trace("sygus-grammar-normalize-chain") << "\n";
-  }
-  /* Build identity operator and empty callback */
-  Node iden_op =
-      SygusGrammarNorm::getIdOp(TypeNode::fromType(dt.getSygusType()));
-  /* If all operators are claimed, create a monomial */
-  if (nb_op_pos == d_elem_pos.size() + 1)
-  {
-    Trace("sygus-grammar-normalize-chain")
-        << "\tCreating id type for " << d_elem_pos.back() << "\n";
-    /* creates type for element */
-    std::vector<unsigned> tmp;
-    tmp.push_back(d_elem_pos.back());
-    Type t = sygus_norm->normalizeSygusRec(to.d_tn, dt, tmp).toType();
-    /* consumes element */
-    d_elem_pos.pop_back();
-    /* adds to Root: "type" */
-    to.d_ops.push_back(iden_op);
-    to.d_cons_names.push_back("id");
-    to.d_pc.push_back(printer::SygusEmptyPrintCallback::getEmptyPC());
-    /* Identity operators should not increase the size of terms */
-    to.d_weight.push_back(0);
-    to.d_cons_args_t.push_back(std::vector<Type>());
-    to.d_cons_args_t.back().push_back(t);
-    Trace("sygus-grammar-normalize-chain")
-        << "\tAdding  " << t << " to " << to.d_unres_tn << "\n";
-    /* adds to Root: "type + Root" */
-    to.d_ops.push_back(nm->operatorOf(PLUS));
-    to.d_cons_names.push_back(kindToString(PLUS));
-    to.d_pc.push_back(nullptr);
-    to.d_weight.push_back(-1);
-    to.d_cons_args_t.push_back(std::vector<Type>());
-    to.d_cons_args_t.back().push_back(t);
-    to.d_cons_args_t.back().push_back(to.d_unres_tn.toType());
-    Trace("sygus-grammar-normalize-chain")
-        << "\tAdding PLUS to " << to.d_unres_tn << " with arg types "
-        << to.d_unres_tn << " and " << t << "\n";
-  }
-  /* In the initial case if not all operators claimed always creates a next */
-  Assert(nb_op_pos != d_elem_pos.size() + 1 || d_elem_pos.size() > 1);
-  /* TODO #1304: consider case in which CHAIN op has different types than
-     to.d_tn */
-  /* If no more elements to chain, finish */
-  if (d_elem_pos.size() == 0)
-  {
-    return;
-  }
-  /* Creates a type do be added to root representing next step in the chain */
-  /* Add + to elems */
-  d_elem_pos.push_back(d_chain_op_pos);
-  if (Trace.isOn("sygus-grammar-normalize-chain"))
-  {
-    Trace("sygus-grammar-normalize-chain")
-        << "\tCreating type for next entry with sygus_ops ";
-    for (unsigned i = 0, size = d_elem_pos.size(); i < size; ++i)
-    {
-      Trace("sygus-grammar-normalize-chain")
-          << dt[d_elem_pos[i]].getSygusOp() << " ";
-    }
-    Trace("sygus-grammar-normalize-chain") << "\n";
-  }
-  /* adds to Root: (\lambda x. x ) Next */
-  to.d_ops.push_back(iden_op);
-  to.d_cons_names.push_back("id_next");
-  to.d_pc.push_back(printer::SygusEmptyPrintCallback::getEmptyPC());
-  to.d_weight.push_back(0);
-  to.d_cons_args_t.push_back(std::vector<Type>());
-  to.d_cons_args_t.back().push_back(
-      sygus_norm->normalizeSygusRec(to.d_tn, dt, d_elem_pos).toType());
-}
-
-std::map<TypeNode, Node> SygusGrammarNorm::d_tn_to_id = {};
-
-/* Traverse the constructors of dt according to the positions in op_pos. Collect
- * those that fit the kinds established by to_collect. Remove collected operator
- * positions from op_pos. Accumulate collected positions in collected
- *
- * returns true if collected anything
- */
-std::unique_ptr<SygusGrammarNorm::Transf> SygusGrammarNorm::inferTransf(
-    TypeNode tn, const Datatype& dt, const std::vector<unsigned>& op_pos)
-{
-  NodeManager* nm = NodeManager::currentNM();
-  TypeNode sygus_tn = TypeNode::fromType(dt.getSygusType());
-  Trace("sygus-gnorm") << "Infer transf for " << dt.getName() << "..."
-                       << std::endl;
-  Trace("sygus-gnorm") << "  #cons = " << op_pos.size() << " / "
-                       << dt.getNumConstructors() << std::endl;
-  // look for redundant constructors to drop
-  if (options::sygusMinGrammar() && dt.getNumConstructors() == op_pos.size())
-  {
-    SygusRedundantCons src;
-    src.initialize(d_qe, tn);
-    std::vector<unsigned> rindices;
-    src.getRedundant(rindices);
-    if (!rindices.empty())
-    {
-      Trace("sygus-gnorm") << "...drop transf, " << rindices.size() << "/"
-                           << op_pos.size() << " constructors." << std::endl;
-      Assert(rindices.size() < op_pos.size());
-      return std::unique_ptr<Transf>(new TransfDrop(rindices));
-    }
-  }
-
-  // if normalization option is not enabled, we do not infer the transformations
-  // below
-  if (!options::sygusGrammarNorm())
-  {
-    return nullptr;
-  }
-
-  /* TODO #1304: step 1: look for singleton */
-  /* step 2: look for chain */
-  unsigned chain_op_pos = dt.getNumConstructors();
-  std::vector<unsigned> elem_pos;
-  for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
-  {
-    Assert(op_pos[i] < dt.getNumConstructors());
-    Expr sop = dt[op_pos[i]].getSygusOp();
-    /* Collects a chainable operator such as PLUS */
-    if (sop.getKind() == BUILTIN
-        && TransfChain::isChainable(sygus_tn, Node::fromExpr(sop)))
-    {
-      Assert(nm->operatorToKind(Node::fromExpr(sop)) == PLUS);
-      /* TODO #1304: be robust for this case */
-      /* For now only transforms applications whose arguments have the same type
-       * as the root */
-      bool same_type_plus = true;
-      for (const DatatypeConstructorArg& arg : dt[op_pos[i]])
-      {
-        if (TypeNode::fromType(
-                static_cast<SelectorType>(arg.getType()).getRangeType())
-            != tn)
-        {
-          same_type_plus = false;
-          break;
-        }
-      }
-      if (!same_type_plus)
-      {
-        Trace("sygus-grammar-normalize-infer")
-            << "\tFor OP " << PLUS << " did not collecting sop " << sop
-            << " in position " << op_pos[i] << "\n";
-        continue;
-      }
-      Assert(chain_op_pos == dt.getNumConstructors());
-      Trace("sygus-grammar-normalize-infer")
-          << "\tCollecting chainable OP " << sop << " in position " << op_pos[i]
-          << "\n";
-      chain_op_pos = op_pos[i];
-      continue;
-    }
-    /* TODO #1304: check this for each operator */
-    /* Collects elements that are not the identity (e.g. 0 is the id of PLUS) */
-    if (!TransfChain::isId(sygus_tn, nm->operatorOf(PLUS), Node::fromExpr(sop)))
-    {
-      Trace("sygus-grammar-normalize-infer")
-          << "\tCollecting for NON_ID_ELEMS the sop " << sop
-          << " in position " << op_pos[i] << "\n";
-      elem_pos.push_back(op_pos[i]);
-    }
-  }
-  /* Typenode admits a chain transformation for normalization */
-  if (chain_op_pos != dt.getNumConstructors() && !elem_pos.empty())
-  {
-    Trace("sygus-gnorm") << "...chain transf." << std::endl;
-    Trace("sygus-grammar-normalize-infer")
-        << "\tInfering chain transformation\n";
-    return std::unique_ptr<Transf>(new TransfChain(chain_op_pos, elem_pos));
-  }
-  return nullptr;
-}
-
-TypeNode SygusGrammarNorm::normalizeSygusRec(TypeNode tn,
-                                             const Datatype& dt,
-                                             std::vector<unsigned>& op_pos)
-{
-  /* Corresponding type node to tn with the given operator positions. To be
-   * retrieved (if cached) or defined (otherwise) */
-  TypeNode unres_tn;
-  if (Trace.isOn("sygus-grammar-normalize-trie"))
-  {
-    Trace("sygus-grammar-normalize-trie")
-        << "\tRecursing on " << tn << " with op_positions ";
-    for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
-    {
-      Trace("sygus-grammar-normalize-trie") << op_pos[i] << " ";
-    }
-    Trace("sygus-grammar-normalize-trie") << "\n";
-  }
-  /* Checks if unresolved type already created (and returns) or creates it
-   * (and then proceeds to definition) */
-  std::sort(op_pos.begin(), op_pos.end());
-  if (d_tries[tn].getOrMakeType(tn, unres_tn, op_pos))
-  {
-    if (Trace.isOn("sygus-grammar-normalize-trie"))
-    {
-      Trace("sygus-grammar-normalize-trie")
-          << "\tTypenode " << tn << " has already been normalized with op_pos ";
-      for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
-      {
-        Trace("sygus-grammar-normalize-trie") << op_pos[i] << " ";
-      }
-      Trace("sygus-grammar-normalize-trie") << " with tn " << unres_tn << "\n";
-    }
-    return unres_tn;
-  }
-  if (Trace.isOn("sygus-grammar-normalize-trie"))
-  {
-    Trace("sygus-grammar-normalize-trie")
-        << "\tTypenode " << tn << " not yet normalized with op_pos ";
-    for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
-    {
-      Trace("sygus-grammar-normalize-trie") << op_pos[i] << " ";
-    }
-    Trace("sygus-grammar-normalize-trie") << "\n";
-  }
-  /* Creates type object for normalization */
-  TypeObject to(tn, unres_tn);
-
-  /* Determine normalization transformation based on sygus type and given
-    * operators */
-  std::unique_ptr<Transf> transformation = inferTransf(tn, dt, op_pos);
-  /* If a transformation was selected, apply it */
-  if (transformation != nullptr)
-  {
-    transformation->buildType(this, to, dt, op_pos);
-  }
-
-  /* Remaining operators are rebuilt as they are */
-  for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
-  {
-    Assert(op_pos[i] < dt.getNumConstructors());
-    to.addConsInfo(this, dt[op_pos[i]]);
-  }
-  /* Build normalize datatype */
-  if (Trace.isOn("sygus-grammar-normalize"))
-  {
-    Trace("sygus-grammar-normalize") << "\nFor positions ";
-    for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
-    {
-      Trace("sygus-grammar-normalize") << op_pos[i] << " ";
-    }
-    Trace("sygus-grammar-normalize") << " and datatype " << dt << " \n";
-  }
-  to.buildDatatype(this, dt);
-  return to.d_unres_tn;
-}
-
-TypeNode SygusGrammarNorm::normalizeSygusRec(TypeNode tn)
-{
-  /* Collect all operators for normalization */
-  const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
-  std::vector<unsigned> op_pos(dt.getNumConstructors());
-  std::iota(op_pos.begin(), op_pos.end(), 0);
-  return normalizeSygusRec(tn, dt, op_pos);
-}
-
-TypeNode SygusGrammarNorm::normalizeSygusType(TypeNode tn, Node sygus_vars)
-{
-  /* Normalize all types in tn */
-  d_sygus_vars = sygus_vars;
-  normalizeSygusRec(tn);
-  /* Resolve created types */
-  Assert(!d_dt_all.empty() && !d_unres_t_all.empty());
-  if (Trace.isOn("sygus-grammar-normalize-build"))
-  {
-    Trace("sygus-grammar-normalize-build")
-        << "making mutual datatyes with datatypes \n";
-    for (unsigned i = 0, size = d_dt_all.size(); i < size; ++i)
-    {
-      Trace("sygus-grammar-normalize-build") << d_dt_all[i];
-    }
-    Trace("sygus-grammar-normalize-build") << " and unresolved types\n";
-    for (const Type& unres_t : d_unres_t_all)
-    {
-      Trace("sygus-grammar-normalize-build") << unres_t << " ";
-    }
-    Trace("sygus-grammar-normalize-build") << "\n";
-  }
-  Assert(d_dt_all.size() == d_unres_t_all.size());
-  std::vector<DatatypeType> types =
-      NodeManager::currentNM()->toExprManager()->mkMutualDatatypeTypes(
-          d_dt_all, d_unres_t_all);
-  Assert(types.size() == d_dt_all.size());
-  /* Clear accumulators */
-  d_dt_all.clear();
-  d_unres_t_all.clear();
-  /* By construction the normalized type node will be the last one considered */
-  return TypeNode::fromType(types.back());
-}
-
-}  // namespace quantifiers
-}  // namespace theory
-}  // namespace CVC4
diff --git a/src/theory/quantifiers/sygus_grammar_norm.h b/src/theory/quantifiers/sygus_grammar_norm.h
deleted file mode 100644 (file)
index f72a83e..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_grammar_norm.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Haniel Barbosa
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief class for simplifying SyGuS grammars after they are encoded into
- ** datatypes.
- **/
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_NORM_H
-#define __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_NORM_H
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "expr/datatype.h"
-#include "expr/node.h"
-#include "expr/node_manager_attributes.h"  // for VarNameAttr
-#include "expr/type.h"
-#include "expr/type_node.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class SygusGrammarNorm;
-
-/** Operator position trie class
- *
- * This data structure stores an unresolved type corresponding to the
- * normalization of a type. This unresolved type is indexed by the positions of
- * the construtors of the datatype associated with the original type. The list
- * of positions represent the operators, associated with the respective
- * considered constructors, that were used for building the unresolved type.
- *
- * Example:
- *
- * Let A be a type defined by the grammar "A -> x | 0 | 1 | A + A". In its
- * datatype representation the operator for "x" is in position 0, for "0" in
- * position "1" and so on. Consider entries (T, [op_1, ..., op_n]) -> T' to
- * represent that a type T is normalized with operators [op_1, ..., op_n] into
- * the type T'. For entries
- *
- * (A, [x, 0, 1, +]) -> A1
- * (A, [x, 1, +]) -> A2
- * (A, [1, +]) -> A3
- * (A, [0]) -> AZ
- * (A, [x]) -> AX
- * (A, [1]) -> AO
- *
- * the OpPosTrie T we build for this type is :
- *
- * T[A] :
- *      T[A].d_children[0] : AX
- *        T[A].d_children[0].d_children[1] :
- *          T[A].d_children[0].d_children[1].d_children[2] :
- *            T[A].d_children[0].d_children[1].d_children[2].d_children[3] : A1
- *        T[A].d_children[0].d_children[2] :
- *          T[A].d_children[0].d_children[2].d_children[3] : A2
- *      T[A].d_children[1] : AZ
- *      T[A].d_children[2] : AO
- *        T[A].d_children[2].d_children[4] : A3
- *
- * Nodes store the types built for the path of positions up to that point, if
- * any.
- */
-class OpPosTrie
-{
- public:
-  /** type retrieval/addition
-   *
-   * if type indexed by the given operator positions is already in the trie then
-   * unres_t becomes the indexed type and true is returned. Otherwise a new type
-   * is created, indexed by the given positions, and assigned to unres_t, with
-   * false being returned.
-   */
-  bool getOrMakeType(TypeNode tn,
-                     TypeNode& unres_tn,
-                     const std::vector<unsigned>& op_pos,
-                     unsigned ind = 0);
-  /** clear all data from this trie */
-  void clear() { d_children.clear(); }
-
- private:
-  /** the data (only set for the final node of an inserted path) */
-  TypeNode d_unres_tn;
-  /* the children of the trie node */
-  std::map<unsigned, OpPosTrie> d_children;
-}; /* class OpPosTrie */
-
-/** Utility for normalizing SyGuS grammars to avoid spurious enumerations
- *
- * Uses the datatype representation of a SyGuS grammar to identify entries that
- * can normalized in order to have less possible enumerations. An example is
- * with integer types, e.g.:
- *
- * Int -> x | y | Int + Int | 0 | 1 | ite(Bool, Int, Int)
- *
- * becomes
- *
- * Int0 -> IntZ | Int1
- * IntZ -> 0
- * Int1 -> IntX | IntX + Int1 | Int2
- * IntX -> x
- * Int2 -> IntY | IntY + Int2 | Int3
- * IntY -> y
- * Int3 -> IntO | IntO + Int3 | Int4
- * IntO -> 1
- * Int4 -> IntITE | IntITE + Int4
- * IntITE -> ite(Bool, Int0, Int0)
- *
- * TODO: #1304 normalize more complex grammars
- *
- * This class also performs more straightforward normalizations, such as
- * expanding definitions of functions declared with a "define-fun" command.
- * These lighweight transformations are always applied, independently of the
- * normalization option being enabled.
- */
-class SygusGrammarNorm
-{
- public:
-  SygusGrammarNorm(QuantifiersEngine* qe)
-      : d_qe(qe), d_tds(d_qe->getTermDatabaseSygus())
-  {
-  }
-  ~SygusGrammarNorm() {}
-  /** creates a normalized typenode from a given one.
-   *
-   * In a normalized typenode all typenodes it contains are normalized.
-   * Normalized typenodes can be structurally identicial to their original
-   * counterparts.
-   *
-   * sygus_vars are the input variables for the function to be synthesized,
-   * which are used as input for the built datatypes.
-   *
-   * This is the function that will resolve all types and datatypes built during
-   * normalization. This operation can only be performed after all types
-   * contained in "tn" have been normalized, since the resolution of datatypes
-   * depends on all types involved being defined.
-   */
-  TypeNode normalizeSygusType(TypeNode tn, Node sygus_vars);
-
-  /* Retrives, or, if none, creates, stores and returns, the node for the
-   * identity operator (\lambda x. x) for the given type node */
-  static inline Node getIdOp(TypeNode tn)
-  {
-    auto it = d_tn_to_id.find(tn);
-    if (it == d_tn_to_id.end())
-    {
-      std::vector<Node> vars = {NodeManager::currentNM()->mkBoundVar(tn)};
-      Node n = NodeManager::currentNM()->mkNode(
-          kind::LAMBDA,
-          NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, vars),
-          vars.back());
-      d_tn_to_id[tn] = n;
-      return n;
-    }
-    return it->second;
-  }
-
- private:
-  /** Keeps the necessary information for bulding a normalized type:
-   *
-   * the original typenode, from which the datatype representation can be
-   * extracted
-   *
-   * the operators, names, print callbacks and list of argument types for each
-   * constructor
-   *
-   * the unresolved type node used as placeholder for references of the yet to
-   * be built normalized type
-   *
-   * a datatype to represent the structure of the type node for the normalized
-   * type
-   */
-  class TypeObject
-  {
-   public:
-    /* Stores the original type node and the unresolved placeholder. The
-     * datatype for the latter is created with the respective name. */
-    TypeObject(TypeNode src_tn, TypeNode unres_tn)
-        : d_tn(src_tn),
-          d_unres_tn(unres_tn),
-          d_dt(Datatype(unres_tn.getAttribute(expr::VarNameAttr())))
-    {
-    }
-    ~TypeObject() {}
-
-    /** adds information in "cons" (operator, name, print callback, argument
-     * types) as it is into "to"
-     *
-     * A side effect of this procedure is to expand the definitions in the sygus
-     * operator of "cons"
-     *
-     * The types of the arguments of "cons" are recursively normalized
-     */
-    void addConsInfo(SygusGrammarNorm* sygus_norm,
-                     const DatatypeConstructor& cons);
-
-    /** builds a datatype with the information in the type object
-     *
-     * "dt" is the datatype of the original typenode. It is necessary for
-     * retrieving ancillary information during the datatype building, such as
-     * its sygus type (e.g. Int)
-     *
-     * The built datatype and its unresolved type are saved in the global
-     * accumulators of "sygus_norm"
-     */
-    void buildDatatype(SygusGrammarNorm* sygus_norm, const Datatype& dt);
-
-    //---------- information stored from original type node
-
-    /* The original typenode this TypeObject is built from */
-    TypeNode d_tn;
-
-    //---------- information to build normalized type node
-
-    /* Operators for each constructor. */
-    std::vector<Node> d_ops;
-    /* Names for each constructor. */
-    std::vector<std::string> d_cons_names;
-    /* Print callbacks for each constructor */
-    std::vector<std::shared_ptr<SygusPrintCallback>> d_pc;
-    /* Weights for each constructor */
-    std::vector<int> d_weight;
-    /* List of argument types for each constructor */
-    std::vector<std::vector<Type>> d_cons_args_t;
-    /* Unresolved type node placeholder */
-    TypeNode d_unres_tn;
-    /* Datatype to represent type's structure */
-    Datatype d_dt;
-  }; /* class TypeObject */
-
-  /** Transformation abstract class
-   *
-   * Classes extending this one will define specif transformationst for building
-   * normalized types based on applications of specific operators
-   */
-  class Transf
-  {
-   public:
-    virtual ~Transf() {}
-
-    /** abstract function for building normalized types
-     *
-     * Builds normalized types for the operators specifed by the positions in
-     * op_pos of constructors from dt. The built types are associated with the
-     * given type object and accumulated in the sygus_norm object, whose
-     * utilities for any extra necessary normalization.
-     */
-    virtual void buildType(SygusGrammarNorm* sygus_norm,
-                           TypeObject& to,
-                           const Datatype& dt,
-                           std::vector<unsigned>& op_pos) = 0;
-  }; /* class Transf */
-
-  /** Drop transformation class
-   *
-   * This class builds a type by dropping a set of redundant constructors,
-   * whose indices are given as input to the constructor of this class.
-   */
-  class TransfDrop : public Transf
-  {
-   public:
-    TransfDrop(const std::vector<unsigned>& indices) : d_drop_indices(indices)
-    {
-    }
-    /** build type */
-    void buildType(SygusGrammarNorm* sygus_norm,
-                   TypeObject& to,
-                   const Datatype& dt,
-                   std::vector<unsigned>& op_pos) override;
-
-   private:
-    std::vector<unsigned> d_drop_indices;
-  };
-
-  /** Chain transformation class
-   *
-   * Determines how to build normalized types by chaining the application of one
-   * of its operators. The resulting type should admit the same terms as the
-   * previous one modulo commutativity, associativity and identity of the
-   * neutral element.
-   *
-   * TODO: #1304:
-   * - define this transformation for more than just PLUS for Int.
-   * - improve the building such that elements that should not be entitled a
-   * "link in the chain" (such as 5 in opposition to variables and 1) do not get
-   * one
-   * - consider the case when operator is applied to different types, e.g.:
-   *   A -> B + B | x; B -> 0 | 1
-   * - consider the case in which in which the operator occurs nested in an
-   *   argument type of itself, e.g.:
-   *   A -> (B + B) + B | x; B -> 0 | 1
-   */
-  class TransfChain : public Transf
-  {
-   public:
-    TransfChain(unsigned chain_op_pos, const std::vector<unsigned>& elem_pos)
-        : d_chain_op_pos(chain_op_pos), d_elem_pos(elem_pos){};
-
-    /** builds types encoding a chain in which each link contains a repetition
-     * of the application of the chain operator over a non-identity element
-     *
-     * Example: when considering, over the integers, the operator "+" and the
-     * elemenst "1", "x" and "y", the built chain is e.g.
-     *
-     * x + ... + x + y + ... + y + 1 + ...+ 1
-     *
-     * whose encoding in types would be e.g.
-     *
-     * A  -> AX | AX + A | B
-     * AX -> x
-     * B  -> BY | BY + B | C
-     * BY -> y
-     * C  -> C1 | C1 + C
-     * C1 -> 1
-     *
-     * ++++++++
-     *
-     * The types composing links in the chain are built recursively by invoking
-     * sygus_norm, which caches results and handles the global normalization, on
-     * the operators not used in a given link, which will lead to recalling this
-     * transformation and so on until all operators originally given are
-     * considered.
-     */
-    void buildType(SygusGrammarNorm* sygus_norm,
-                   TypeObject& to,
-                   const Datatype& dt,
-                   std::vector<unsigned>& op_pos) override;
-
-    /** Whether operator is chainable for the type (e.g. PLUS for Int)
-     *
-     *  Since the map this function depends on cannot be built statically, this
-     *  function first build maps the first time a type is checked. As a
-     *  consequence the list of chainabel operators is hardcoded in the map
-     *  building.
-     *
-     * TODO: #1304: Cover more types and operators, make this robust to more
-     * complex grammars
-     */
-    static bool isChainable(TypeNode tn, Node op);
-    /* Whether n is the identity for the chain operator of the type (e.g. 1 is
-     * not the identity 0 for PLUS for Int)
-     *
-     * TODO: #1304: Cover more types, make this robust to more complex grammars
-     */
-    static bool isId(TypeNode tn, Node op, Node n);
-
-   private:
-    /* TODO #1304: this should admit more than one, as well as which elements
-     * are associated with which operator */
-    /* Position of chain operator */
-    unsigned d_chain_op_pos;
-    /* Positions (of constructors in the datatype whose type is being
-     * normalized) of elements the chain operator is applied to */
-    std::vector<unsigned> d_elem_pos;
-    /** Specifies for each type node which are its chainable operators
-     *
-     * For example, for Int the map is {OP -> [+]}
-     *
-     * TODO #1304: consider more operators
-     */
-    static std::map<TypeNode, std::vector<Kind>> d_chain_ops;
-    /** Specifies for each type node and chainable operator its identity
-     *
-     * For example, for Int and PLUS the map is {Int -> {+ -> 0}}
-     *
-     * TODO #1304: consider more operators
-     */
-    static std::map<TypeNode, std::map<Kind, Node>> d_chain_op_id;
-
-  }; /* class TransfChain */
-
-  /** reference to quantifier engine */
-  QuantifiersEngine* d_qe;
-  /** sygus term database associated with this utility */
-  TermDbSygus* d_tds;
-  /** List of variable inputs of function-to-synthesize.
-   *
-   * This information is needed in the construction of each datatype
-   * representation of type nodes contained in the type node being normalized
-   */
-  TNode d_sygus_vars;
-  /* Datatypes to be resolved */
-  std::vector<Datatype> d_dt_all;
-  /* Types to be resolved */
-  std::set<Type> d_unres_t_all;
-  /* Associates type nodes with OpPosTries */
-  std::map<TypeNode, OpPosTrie> d_tries;
-  /* Map of type nodes into their identity operators (\lambda x. x) */
-  static std::map<TypeNode, Node> d_tn_to_id;
-
-  /** recursively traverses a typenode normalizing all of its elements
-   *
-   * "tn" is the typenode to be normalized
-   * "dt" is its datatype representation
-   * "op_pos" is the list of positions of construtors of dt that are being
-   * considered for the normalization
-   *
-   * The result of normalizing tn with the respective constructors is cached
-   * with an OpPosTrie. New types and datatypes created during normalization are
-   * accumulated grobally to be later resolved.
-   *
-   * The normalization occurs following some inferred transformation based on
-   * the sygus type (e.g. Int) of tn, and the operators being considered.
-   *
-   * Example: Let A be the type node encoding the grammar
-   *
-   * Int -> x | y | Int + Int | 0 | 1 | ite(Bool, Int, Int)
-   *
-   * and assume all its datatype constructors are being used for
-   * normalization. The inferred normalization transformation will consider the
-   * non-zero elements {x, y, 1, ite(...)} and the operator {+} to build a chain
-   * of monomials, as seen above. The operator for "0" is rebuilt as is (the
-   * default behaviour of operators not selected for transformations).
-   *
-   * recursion depth is limited by the height of the types, which is small
-   */
-  TypeNode normalizeSygusRec(TypeNode tn,
-                             const Datatype& dt,
-                             std::vector<unsigned>& op_pos);
-
-  /** wrapper for the above function
-   *
-   * invoked when all operators of "tn" are to be considered for normalization
-   */
-  TypeNode normalizeSygusRec(TypeNode tn);
-
-  /** infers a transformation for normalizing dt when allowed to use the
-   * operators in the positions op_pos.
-   *
-   * TODO: #1304: Infer more complex transformations
-   */
-  std::unique_ptr<Transf> inferTransf(TypeNode tn,
-                                      const Datatype& dt,
-                                      const std::vector<unsigned>& op_pos);
-}; /* class SygusGrammarNorm */
-
-}  // namespace quantifiers
-}  // namespace theory
-}  // namespace CVC4
-
-#endif
diff --git a/src/theory/quantifiers/sygus_grammar_red.cpp b/src/theory/quantifiers/sygus_grammar_red.cpp
deleted file mode 100644 (file)
index 056fc45..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_grammar_red.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of sygus_grammar_red
- **/
-
-#include "theory/quantifiers/sygus_grammar_red.h"
-
-#include "options/quantifiers_options.h"
-#include "theory/quantifiers/term_database_sygus.h"
-#include "theory/quantifiers/term_util.h"
-
-using namespace std;
-using namespace CVC4::kind;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-void SygusRedundantCons::initialize(QuantifiersEngine* qe, TypeNode tn)
-{
-  Assert(qe != nullptr);
-  Trace("sygus-red") << "Compute redundant cons for " << tn << std::endl;
-  d_type = tn;
-  Assert(tn.isDatatype());
-  TermDbSygus* tds = qe->getTermDatabaseSygus();
-  tds->registerSygusType(tn);
-  const Datatype& dt = static_cast<DatatypeType>(tn.toType()).getDatatype();
-  Assert(dt.isSygus());
-  TypeNode btn = TypeNode::fromType(dt.getSygusType());
-  for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
-  {
-    Trace("sygus-red") << "  Is " << dt[i].getName() << " a redundant operator?"
-                       << std::endl;
-    std::map<int, Node> pre;
-    Node g = tds->mkGeneric(dt, i, pre);
-    Trace("sygus-red-debug") << "  ...pre-rewrite : " << g << std::endl;
-    Assert(g.getNumChildren() == dt[i].getNumArgs());
-    d_gen_terms[i] = g;
-    for (unsigned j = 0, nargs = dt[i].getNumArgs(); j < nargs; j++)
-    {
-      pre[j] = g[j];
-    }
-    std::vector<Node> glist;
-    getGenericList(tds, dt, i, 0, pre, glist);
-    // call the extended rewriter
-    bool red = false;
-    for (const Node& gr : glist)
-    {
-      Trace("sygus-red-debug") << "  ...variant : " << gr << std::endl;
-      std::map<Node, unsigned>::iterator itg = d_gen_cons.find(gr);
-      if (itg != d_gen_cons.end() && itg->second != i)
-      {
-        red = true;
-        Trace("sygus-red") << "  ......redundant, since a variant of " << g
-                           << " and " << d_gen_terms[itg->second]
-                           << " both rewrite to " << gr << std::endl;
-        break;
-      }
-      else
-      {
-        d_gen_cons[gr] = i;
-        Trace("sygus-red") << "  ......not redundant." << std::endl;
-      }
-    }
-    d_sygus_red_status.push_back(red ? 1 : 0);
-  }
-}
-
-void SygusRedundantCons::getRedundant(std::vector<unsigned>& indices)
-{
-  const Datatype& dt = static_cast<DatatypeType>(d_type.toType()).getDatatype();
-  for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
-  {
-    if (isRedundant(i))
-    {
-      indices.push_back(i);
-    }
-  }
-}
-
-bool SygusRedundantCons::isRedundant(unsigned i)
-{
-  Assert(i < d_sygus_red_status.size());
-  return d_sygus_red_status[i] == 1;
-}
-
-void SygusRedundantCons::getGenericList(TermDbSygus* tds,
-                                        const Datatype& dt,
-                                        unsigned c,
-                                        unsigned index,
-                                        std::map<int, Node>& pre,
-                                        std::vector<Node>& terms)
-{
-  if (index == dt[c].getNumArgs())
-  {
-    Node gt = tds->mkGeneric(dt, c, pre);
-    gt = tds->getExtRewriter()->extendedRewrite(gt);
-    terms.push_back(gt);
-    return;
-  }
-  // with no swap
-  getGenericList(tds, dt, c, index + 1, pre, terms);
-  // swapping is exponential, only use for operators with small # args.
-  if (dt[c].getNumArgs() <= 5)
-  {
-    TypeNode atype = tds->getArgType(dt[c], index);
-    for (unsigned s = index + 1, nargs = dt[c].getNumArgs(); s < nargs; s++)
-    {
-      if (tds->getArgType(dt[c], s) == atype)
-      {
-        // swap s and index
-        Node tmp = pre[s];
-        pre[s] = pre[index];
-        pre[index] = tmp;
-        getGenericList(tds, dt, c, index + 1, pre, terms);
-        // revert
-        tmp = pre[s];
-        pre[s] = pre[index];
-        pre[index] = tmp;
-      }
-    }
-  }
-}
-
-} /* CVC4::theory::quantifiers namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/sygus_grammar_red.h b/src/theory/quantifiers/sygus_grammar_red.h
deleted file mode 100644 (file)
index d0484aa..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_grammar_red.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief sygus_grammar_red
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_RED_H
-#define __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_RED_H
-
-#include <map>
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-/** SygusRedundantCons
- *
- * This class computes the subset of indices of the constructors of a sygus type
- * that are redundant. To use this class, first call initialize( qe, tn ),
- * where tn is a sygus tn. Then, use getRedundant and/or isRedundant to get the
- * indicies of the constructors of tn that are redundant.
- */
-class SygusRedundantCons
-{
- public:
-  SygusRedundantCons() {}
-  ~SygusRedundantCons() {}
-  /** register type tn
-   *
-   * qe : pointer to the quantifiers engine,
-   * tn : the (sygus) type to compute redundant constructors for
-   */
-  void initialize(QuantifiersEngine* qe, TypeNode tn);
-  /** Get the indices of the redundant constructors of the register type */
-  void getRedundant(std::vector<unsigned>& indices);
-  /**
-   * This function returns true if the i^th constructor of the registered type
-   * is redundant.
-   */
-  bool isRedundant(unsigned i);
-
- private:
-  /** the registered type */
-  TypeNode d_type;
-  /** redundant status
-   *
-   * For each constructor, status indicating whether the constructor is
-   * redundant, where:
-   *
-   * 0 : not redundant,
-   * 1 : redundant since another constructor can be used to construct values for
-   * this constructor.
-   *
-   * For example, for grammar:
-   *   A -> C > B | B < C | not D
-   *   B -> x | y
-   *   C -> 0 | 1 | C+C
-   *   D -> B >= C
-   * If A is register with this class, then we store may store { 0, 1, 0 },
-   * noting that the second constructor of A can be simulated with the first.
-   * Notice that the third constructor is not considered redundant.
-   */
-  std::vector<int> d_sygus_red_status;
-  /**
-   * Map from constructor indices to the generic term for that constructor,
-   * where the generic term for a constructor is the (canonical) term returned
-   * by a call to TermDbSygus::mkGeneric.
-   */
-  std::map<unsigned, Node> d_gen_terms;
-  /**
-   * Map from the rewritten form of generic terms for constructors of the
-   * registered type to their corresponding constructor index.
-   */
-  std::map<Node, unsigned> d_gen_cons;
-  /** get generic list
-   *
-   * This function constructs all well-typed variants of a term of the form
-   *    op( x1, ..., xn )
-   * where op is the builtin operator for dt[c], and xi = pre[i] for i=1,...,n.
-   *
-   * It constructs a list of terms of the form g * sigma, where sigma
-   * is an automorphism on { x1...xn } such that for all xi -> xj in sigma,
-   * the type for arguments i and j of dt[c] are the same. We store this
-   * list of terms in terms.
-   *
-   * This function recurses on the arguments of g, index is the current argument
-   * we are processing, and pre stores the current arguments of
-   *
-   * For example, for a sygus grammar
-   *   A -> and( A, A, B )
-   *   B -> false
-   * passing arguments such that g=and( x1, x2, x3 ) to this function will add:
-   *   and( x1, x2, x3 ) and and( x2, x1, x3 )
-   * to terms.
-   */
-  void getGenericList(TermDbSygus* tds,
-                      const Datatype& dt,
-                      unsigned c,
-                      unsigned index,
-                      std::map<int, Node>& pre,
-                      std::vector<Node>& terms);
-};
-
-} /* CVC4::theory::quantifiers namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__SYGUS_GRAMMAR_RED_H */
diff --git a/src/theory/quantifiers/sygus_invariance.cpp b/src/theory/quantifiers/sygus_invariance.cpp
deleted file mode 100644 (file)
index 1fd6bc7..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_invariance.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of techniques for sygus invariance tests.
- **/
-
-#include "theory/quantifiers/sygus_invariance.h"
-
-#include "theory/quantifiers/ce_guided_conjecture.h"
-#include "theory/quantifiers/ce_guided_pbe.h"
-#include "theory/quantifiers/term_database_sygus.h"
-
-using namespace CVC4::kind;
-using namespace std;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-void EvalSygusInvarianceTest::init(Node conj, Node var, Node res)
-{
-  d_conj = conj;
-  d_var = var;
-  d_result = res;
-}
-
-Node EvalSygusInvarianceTest::doEvaluateWithUnfolding(TermDbSygus* tds, Node n)
-{
-  return tds->evaluateWithUnfolding(n, d_visited);
-}
-
-bool EvalSygusInvarianceTest::invariant(TermDbSygus* tds, Node nvn, Node x)
-{
-  TNode tnvn = nvn;
-  Node conj_subs = d_conj.substitute(d_var, tnvn);
-  Node conj_subs_unfold = doEvaluateWithUnfolding(tds, conj_subs);
-  Trace("sygus-cref-eval2-debug")
-      << "  ...check unfolding : " << conj_subs_unfold << std::endl;
-  Trace("sygus-cref-eval2-debug") << "  ......from : " << conj_subs
-                                  << std::endl;
-  if (conj_subs_unfold == d_result)
-  {
-    Trace("sygus-cref-eval2") << "Evaluation min explain : " << conj_subs
-                              << " still evaluates to " << d_result
-                              << " regardless of ";
-    Trace("sygus-cref-eval2") << x << std::endl;
-    return true;
-  }
-  return false;
-}
-
-void EquivSygusInvarianceTest::init(
-    TermDbSygus* tds, TypeNode tn, CegConjecture* aconj, Node e, Node bvr)
-{
-  // compute the current examples
-  d_bvr = bvr;
-  if (aconj->getPbe()->hasExamples(e))
-  {
-    d_conj = aconj;
-    d_enum = e;
-    unsigned nex = aconj->getPbe()->getNumExamples(e);
-    for (unsigned i = 0; i < nex; i++)
-    {
-      d_exo.push_back(d_conj->getPbe()->evaluateBuiltin(tn, bvr, e, i));
-    }
-  }
-}
-
-bool EquivSygusInvarianceTest::invariant(TermDbSygus* tds, Node nvn, Node x)
-{
-  TypeNode tn = nvn.getType();
-  Node nbv = tds->sygusToBuiltin(nvn, tn);
-  Node nbvr = tds->getExtRewriter()->extendedRewrite(nbv);
-  Trace("sygus-sb-mexp-debug") << "  min-exp check : " << nbv << " -> " << nbvr
-                               << std::endl;
-  bool exc_arg = false;
-  // equivalent / singular up to normalization
-  if (nbvr == d_bvr)
-  {
-    // gives the same result : then the explanation for the child is irrelevant
-    exc_arg = true;
-    Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin(nvn)
-                           << " is rewritten to " << nbvr;
-    Trace("sygus-sb-mexp") << " regardless of the content of "
-                           << tds->sygusToBuiltin(x) << std::endl;
-  }
-  else
-  {
-    if (nbvr.isVar())
-    {
-      TypeNode xtn = x.getType();
-      if (xtn == tn)
-      {
-        Node bx = tds->sygusToBuiltin(x, xtn);
-        Assert(bx.getType() == nbvr.getType());
-        if (nbvr == bx)
-        {
-          Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin(nvn)
-                                 << " always rewrites to argument " << nbvr
-                                 << std::endl;
-          // rewrites to the variable : then the explanation of this is
-          // irrelevant as well
-          exc_arg = true;
-          d_bvr = nbvr;
-        }
-      }
-    }
-  }
-  // equivalent under examples
-  if (!exc_arg)
-  {
-    if (!d_enum.isNull())
-    {
-      bool ex_equiv = true;
-      for (unsigned j = 0; j < d_exo.size(); j++)
-      {
-        Node nbvr_ex = d_conj->getPbe()->evaluateBuiltin(tn, nbvr, d_enum, j);
-        if (nbvr_ex != d_exo[j])
-        {
-          ex_equiv = false;
-          break;
-        }
-      }
-      if (ex_equiv)
-      {
-        Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin(nvn);
-        Trace("sygus-sb-mexp")
-            << " is the same w.r.t. examples regardless of the content of "
-            << tds->sygusToBuiltin(x) << std::endl;
-        exc_arg = true;
-      }
-    }
-  }
-  return exc_arg;
-}
-
-bool DivByZeroSygusInvarianceTest::invariant(TermDbSygus* tds, Node nvn, Node x)
-{
-  TypeNode tn = nvn.getType();
-  Node nbv = tds->sygusToBuiltin(nvn, tn);
-  Node nbvr = tds->getExtRewriter()->extendedRewrite(nbv);
-  if (tds->involvesDivByZero(nbvr))
-  {
-    Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin(nvn)
-                           << " involves div-by-zero regardless of "
-                           << tds->sygusToBuiltin(x) << std::endl;
-    return true;
-  }
-  return false;
-}
-
-void NegContainsSygusInvarianceTest::init(CegConjecture* conj,
-                                          Node e,
-                                          std::vector<Node>& exo,
-                                          std::vector<unsigned>& ncind)
-{
-  if (conj->getPbe()->hasExamples(e))
-  {
-    Assert(conj->getPbe()->getNumExamples(e) == exo.size());
-    d_enum = e;
-    d_exo.insert(d_exo.end(), exo.begin(), exo.end());
-    d_neg_con_indices.insert(
-        d_neg_con_indices.end(), ncind.begin(), ncind.end());
-    d_conj = conj;
-  }
-}
-
-bool NegContainsSygusInvarianceTest::invariant(TermDbSygus* tds,
-                                               Node nvn,
-                                               Node x)
-{
-  if (!d_enum.isNull())
-  {
-    TypeNode tn = nvn.getType();
-    Node nbv = tds->sygusToBuiltin(nvn, tn);
-    Node nbvr = tds->getExtRewriter()->extendedRewrite(nbv);
-    // if for any of the examples, it is not contained, then we can exclude
-    for (unsigned i = 0; i < d_neg_con_indices.size(); i++)
-    {
-      unsigned ii = d_neg_con_indices[i];
-      Assert(ii < d_exo.size());
-      Node nbvre = d_conj->getPbe()->evaluateBuiltin(tn, nbvr, d_enum, ii);
-      Node out = d_exo[ii];
-      Node cont =
-          NodeManager::currentNM()->mkNode(kind::STRING_STRCTN, out, nbvre);
-      Trace("sygus-pbe-cterm-debug") << "Check: " << cont << std::endl;
-      Node contr = Rewriter::rewrite(cont);
-      if (contr == tds->d_false)
-      {
-        if (Trace.isOn("sygus-pbe-cterm"))
-        {
-          Trace("sygus-pbe-cterm")
-              << "PBE-cterm : enumerator : do not consider ";
-          Trace("sygus-pbe-cterm") << nbv << " for any "
-                                   << tds->sygusToBuiltin(x) << " since "
-                                   << std::endl;
-          Trace("sygus-pbe-cterm") << "   PBE-cterm :    for input example : ";
-          std::vector<Node> ex;
-          d_conj->getPbe()->getExample(d_enum, ii, ex);
-          for (unsigned j = 0; j < ex.size(); j++)
-          {
-            Trace("sygus-pbe-cterm") << ex[j] << " ";
-          }
-          Trace("sygus-pbe-cterm") << std::endl;
-          Trace("sygus-pbe-cterm")
-              << "   PBE-cterm :     this rewrites to : " << nbvre << std::endl;
-          Trace("sygus-pbe-cterm")
-              << "   PBE-cterm : and is not in output : " << out << std::endl;
-        }
-        return true;
-      }
-      Trace("sygus-pbe-cterm-debug2")
-          << "...check failed, rewrites to : " << contr << std::endl;
-    }
-  }
-  return false;
-}
-
-} /* CVC4::theory::quantifiers namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/sygus_invariance.h b/src/theory/quantifiers/sygus_invariance.h
deleted file mode 100644 (file)
index a43e387..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_invariance.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief sygus invariance tests
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_INVARIANCE_H
-#define __CVC4__THEORY__QUANTIFIERS__SYGUS_INVARIANCE_H
-
-#include <unordered_map>
-#include <vector>
-
-#include "expr/node.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class TermDbSygus;
-class CegConjecture;
-
-/* SygusInvarianceTest
-*
-* This class is the standard interface for term generalization
-* in SyGuS. Its interface is a single function is_variant,
-* which is a virtual condition for SyGuS terms.
-*
-* The common use case of invariance tests is when constructing
-* minimal explanations for refinement lemmas in the
-* counterexample-guided inductive synthesis (CEGIS) loop.
-* See sygus_explain.h for more details.
-*/
-class SygusInvarianceTest
-{
- public:
-  virtual ~SygusInvarianceTest() {}
-
-  /** Is nvn invariant with respect to this test ?
-   *
-   * - nvn is the term to check whether it is invariant.
-   * - x is a variable such that the previous call to
-   *   is_invariant (if any) was with term nvn_prev, and
-   *   nvn is equal to nvn_prev with some subterm
-   *   position replaced by x. This is typically used
-   *   for debugging only.
-   */
-  bool is_invariant(TermDbSygus* tds, Node nvn, Node x)
-  {
-    if (invariant(tds, nvn, x))
-    {
-      d_update_nvn = nvn;
-      return true;
-    }
-    return false;
-  }
-  /** get updated term */
-  Node getUpdatedTerm() { return d_update_nvn; }
-  /** set updated term */
-  void setUpdatedTerm(Node n) { d_update_nvn = n; }
- protected:
-  /** result of the node that satisfies this invariant */
-  Node d_update_nvn;
-  /** check whether nvn[ x ] is invariant */
-  virtual bool invariant(TermDbSygus* tds, Node nvn, Node x) = 0;
-};
-
-/** EquivSygusInvarianceTest
-*
-* This class tests whether a term evaluates via evaluation
-* operators in the deep embedding (Section 4 of Reynolds
-* et al. CAV 2015) to fixed term d_result.
-*
-* For example, consider a SyGuS evaluation function eval
-* for a synthesis conjecture with arguments x and y.
-* Notice that the term t = (mult x y) is such that:
-*   eval( t, 0, 1 ) ----> 0
-* This test is invariant on the content of the second
-* argument of t, noting that:
-*   eval( (mult x _), 0, 1 ) ----> 0
-* as well, via a call to EvalSygusInvarianceTest::invariant.
-*
-* Another example, t = ite( gt( x, y ), x, y ) is such that:
-*   eval( t, 2, 3 ) ----> 3
-* This test is invariant on the second child of t, noting:
-*   eval( ite( gt( x, y ), _, y ), 2, 3 ) ----> 3
-*/
-class EvalSygusInvarianceTest : public SygusInvarianceTest
-{
- public:
-  EvalSygusInvarianceTest() {}
-
-  /** initialize this invariance test
-    * This sets d_conj/d_var/d_result, where
-    * we are checking whether:
-    *   d_conj { d_var -> n } ----> d_result.
-    * for terms n.
-    */
-  void init(Node conj, Node var, Node res);
-
-  /** do evaluate with unfolding, using the cache of this class */
-  Node doEvaluateWithUnfolding(TermDbSygus* tds, Node n);
-
- protected:
-  /** does d_conj{ d_var -> nvn } still rewrite to d_result? */
-  bool invariant(TermDbSygus* tds, Node nvn, Node x);
-
- private:
-  /** the formula we are evaluating */
-  Node d_conj;
-  /** the variable */
-  TNode d_var;
-  /** the result of the evaluation */
-  Node d_result;
-  /** cache of n -> the simplified form of eval( n ) */
-  std::unordered_map<Node, Node, NodeHashFunction> d_visited;
-};
-
-/** EquivSygusInvarianceTest
-*
-* This class tests whether a builtin version of a
-* sygus term is equivalent up to rewriting to a RHS value bvr.
-*
-* For example,
-*
-* ite( t>0, 0, 0 ) + s*0 ----> 0
-*
-* This test is invariant on the condition t>0 and s, since:
-*
-* ite( _, 0, 0 ) + _*0 ----> 0
-*
-* for any values of _.
-*
-* It also manages the case where the rewriting is invariant
-* wrt a finite set of examples occurring in the conjecture.
-* (EX1) : For example if our input examples are:
-* (x,y,z) = (3,2,4), (5,2,6), (3,2,1)
-* On these examples, we have:
-*
-* ite( x>y, z, 0) ---> 4,6,1
-*
-* which is invariant on the second argument:
-*
-* ite( x>y, z, _) ---> 4,6,1
-*
-* For details, see Reynolds et al SYNT 2017.
-*/
-class EquivSygusInvarianceTest : public SygusInvarianceTest
-{
- public:
-  EquivSygusInvarianceTest() : d_conj(nullptr) {}
-
-  /** initialize this invariance test
-   * tn is the sygus type for e
-   * aconj/e are used for conjecture-specific symmetry breaking
-   * bvr is the builtin version of the right hand side of the rewrite that we
-   * are checking for invariance
-   */
-  void init(
-      TermDbSygus* tds, TypeNode tn, CegConjecture* aconj, Node e, Node bvr);
-
- protected:
-  /** checks whether the analog of nvn still rewrites to d_bvr */
-  bool invariant(TermDbSygus* tds, Node nvn, Node x);
-
- private:
-  /** the conjecture associated with the enumerator d_enum */
-  CegConjecture* d_conj;
-  /** the enumerator associated with the term for which this test is for */
-  Node d_enum;
-  /** the RHS of the evaluation */
-  Node d_bvr;
-  /** the result of the examples
-   * In (EX1), this is (4,6,1)
-   */
-  std::vector<Node> d_exo;
-};
-
-/** DivByZeroSygusInvarianceTest
- *
- * This class tests whether a sygus term involves
- * division by zero.
- *
- * For example the test for:
- *    ( x + ( y/0 )*2 )
- * is invariant on the contents of _ below:
- *    ( _ + ( _/0 )*_ )
- */
-class DivByZeroSygusInvarianceTest : public SygusInvarianceTest
-{
- public:
-  DivByZeroSygusInvarianceTest() {}
-
- protected:
-  /** checks whether nvn involves division by zero. */
-  bool invariant(TermDbSygus* tds, Node nvn, Node x);
-};
-
-/** NegContainsSygusInvarianceTest
-*
-* This class is used to construct a minimal shape of a term that cannot
-* be contained in at least one output of an I/O pair.
-*
-* Say our PBE conjecture is:
-*
-* exists f.
-*   f( "abc" ) = "abc abc" ^
-*   f( "de" ) = "de de"
-*
-* Then, this class is used when there is a candidate solution t[x1]
-* such that either:
-*   contains( "abc abc", t["abc"] ) ---> false or
-*   contains( "de de", t["de"] ) ---> false
-*
-* It is used to determine whether certain generalizations of t[x1]
-* are still sufficient to falsify one of the above containments.
-*
-* For example:
-*
-* The test for str.++( x1, "d" ) is invariant on its first argument
-*   ...since contains( "abc abc", str.++( _, "d" ) ) ---> false
-* The test for str.replace( "de", x1, "b" ) is invariant on its third argument
-*   ...since contains( "abc abc", str.replace( "de", "abc", _ ) ) ---> false
-*/
-class NegContainsSygusInvarianceTest : public SygusInvarianceTest
-{
- public:
-  NegContainsSygusInvarianceTest() : d_conj(nullptr) {}
-
-  /** initialize this invariance test
-   *  cpbe is the conjecture utility.
-   *  e is the enumerator which we are reasoning about (associated with a synth
-   *    fun).
-   *  exo is the list of outputs of the PBE conjecture.
-   *  ncind is the set of possible indices of the PBE conjecture to check
-   *    invariance of non-containment.
-   *    For example, in the above example, when t[x1] = "ab", then this
-   *    has the index 1 since contains("de de", "ab") ---> false but not
-   *    the index 0 since contains("abc abc","ab") ---> true.
-   */
-  void init(CegConjecture* conj,
-            Node e,
-            std::vector<Node>& exo,
-            std::vector<unsigned>& ncind);
-
- protected:
-  /** checks if contains( out_i, nvn[in_i] ) --> false for some I/O pair i. */
-  bool invariant(TermDbSygus* tds, Node nvn, Node x);
-
- private:
-  /** The enumerator whose value we are considering in this invariance test */
-  Node d_enum;
-  /** The output examples for the enumerator */
-  std::vector<Node> d_exo;
-  /** The set of I/O pair indices i such that
-   *    contains( out_i, nvn[in_i] ) ---> false
-   */
-  std::vector<unsigned> d_neg_con_indices;
-  /** reference to the conjecture associated with this test */
-  CegConjecture* d_conj;
-};
-
-} /* CVC4::theory::quantifiers namespace */
-} /* CVC4::theory namespace */
-} /* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__SYGUS_INVARIANCE_H */
diff --git a/src/theory/quantifiers/sygus_process_conj.cpp b/src/theory/quantifiers/sygus_process_conj.cpp
deleted file mode 100644 (file)
index 4c0e992..0000000
+++ /dev/null
@@ -1,798 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_process_conj.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of techniqures for static preprocessing and analysis
- ** of sygus conjectures.
- **/
-#include "theory/quantifiers/sygus_process_conj.h"
-
-#include <stack>
-
-#include "expr/datatype.h"
-#include "theory/quantifiers/term_database_sygus.h"
-#include "theory/quantifiers/term_util.h"
-
-using namespace CVC4::kind;
-using namespace std;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-void CegConjectureProcessFun::init(Node f)
-{
-  d_synth_fun = f;
-  Assert(f.getType().isFunction());
-
-  // initialize the arguments
-  std::unordered_map<TypeNode, unsigned, TypeNodeHashFunction>
-      type_to_init_deq_id;
-  std::vector<Type> argTypes =
-      static_cast<FunctionType>(f.getType().toType()).getArgTypes();
-  for (unsigned j = 0; j < argTypes.size(); j++)
-  {
-    TypeNode atn = TypeNode::fromType(argTypes[j]);
-    std::stringstream ss;
-    ss << "a" << j;
-    Node k = NodeManager::currentNM()->mkBoundVar(ss.str(), atn);
-    d_arg_vars.push_back(k);
-    d_arg_var_num[k] = j;
-    d_arg_props.push_back(CegConjectureProcessArg());
-  }
-}
-
-bool CegConjectureProcessFun::checkMatch(
-    Node cn, Node n, std::unordered_map<unsigned, Node>& n_arg_map)
-{
-  std::vector<Node> vars;
-  std::vector<Node> subs;
-  for (std::unordered_map<unsigned, Node>::iterator it = n_arg_map.begin();
-       it != n_arg_map.end();
-       ++it)
-  {
-    Assert(it->first < d_arg_vars.size());
-    Assert(
-        it->second.getType().isComparableTo(d_arg_vars[it->first].getType()));
-    vars.push_back(d_arg_vars[it->first]);
-    subs.push_back(it->second);
-  }
-  Node cn_subs =
-      cn.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
-  cn_subs = Rewriter::rewrite(cn_subs);
-  Assert(Rewriter::rewrite(n) == n);
-  return cn_subs == n;
-}
-
-bool CegConjectureProcessFun::isArgVar(Node n, unsigned& arg_index)
-{
-  if (n.isVar())
-  {
-    std::unordered_map<Node, unsigned, NodeHashFunction>::iterator ita =
-        d_arg_var_num.find(n);
-    if (ita != d_arg_var_num.end())
-    {
-      arg_index = ita->second;
-      return true;
-    }
-  }
-  return false;
-}
-
-Node CegConjectureProcessFun::inferDefinition(
-    Node n,
-    std::unordered_map<Node, unsigned, NodeHashFunction>& term_to_arg_carry,
-    std::unordered_map<Node,
-                       std::unordered_set<Node, NodeHashFunction>,
-                       NodeHashFunction>& free_vars)
-{
-  std::unordered_map<TNode, Node, TNodeHashFunction> visited;
-  std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
-  std::stack<TNode> visit;
-  TNode cur;
-  visit.push(n);
-  do
-  {
-    cur = visit.top();
-    visit.pop();
-    it = visited.find(cur);
-    if (it == visited.end())
-    {
-      // if it is ground, we can use it
-      if (free_vars[cur].empty())
-      {
-        visited[cur] = cur;
-      }
-      else
-      {
-        // if it is term used by another argument, use it
-        std::unordered_map<Node, unsigned, NodeHashFunction>::iterator itt =
-            term_to_arg_carry.find(cur);
-        if (itt != term_to_arg_carry.end())
-        {
-          visited[cur] = d_arg_vars[itt->second];
-        }
-        else if (cur.getNumChildren() > 0)
-        {
-          // try constructing children
-          visited[cur] = Node::null();
-          visit.push(cur);
-          for (unsigned i = 0; i < cur.getNumChildren(); i++)
-          {
-            visit.push(cur[i]);
-          }
-        }
-        else
-        {
-          return Node::null();
-        }
-      }
-    }
-    else if (it->second.isNull())
-    {
-      Node ret = cur;
-      bool childChanged = false;
-      std::vector<Node> children;
-      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
-      {
-        children.push_back(cur.getOperator());
-      }
-      for (unsigned i = 0; i < cur.getNumChildren(); i++)
-      {
-        it = visited.find(cur[i]);
-        Assert(it != visited.end());
-        Assert(!it->second.isNull());
-        childChanged = childChanged || cur[i] != it->second;
-        children.push_back(it->second);
-      }
-      if (childChanged)
-      {
-        ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
-      }
-      visited[cur] = ret;
-    }
-  } while (!visit.empty());
-  Assert(visited.find(n) != visited.end());
-  Assert(!visited.find(n)->second.isNull());
-  return visited[n];
-}
-
-unsigned CegConjectureProcessFun::assignRelevantDef(Node def,
-                                                    std::vector<unsigned>& args)
-{
-  unsigned id = 0;
-  if (def.isNull())
-  {
-    // prefer one that already has a definition, if one exists
-    for (unsigned j = 0; j < args.size(); j++)
-    {
-      unsigned i = args[j];
-      if (!d_arg_props[i].d_template.isNull())
-      {
-        id = j;
-        break;
-      }
-    }
-  }
-  unsigned rid = args[id];
-  // for merging previously equivalent definitions
-  std::unordered_map<Node, unsigned, NodeHashFunction> prev_defs;
-  for (unsigned j = 0; j < args.size(); j++)
-  {
-    unsigned i = args[j];
-    Trace("sygus-process-arg-deps") << "    ...processed arg #" << i;
-    if (!d_arg_props[i].d_template.isNull())
-    {
-      if (d_arg_props[i].d_template == def)
-      {
-        // definition was consistent
-      }
-      else
-      {
-        Node t = d_arg_props[i].d_template;
-        std::unordered_map<Node, unsigned, NodeHashFunction>::iterator itt =
-            prev_defs.find(t);
-        if (itt != prev_defs.end())
-        {
-          // merge previously equivalent definitions
-          d_arg_props[i].d_template = d_arg_vars[itt->second];
-          Trace("sygus-process-arg-deps")
-              << " (merged equivalent def from argument ";
-          Trace("sygus-process-arg-deps") << itt->second << ")." << std::endl;
-        }
-        else
-        {
-          // store this as previous
-          prev_defs[t] = i;
-          // now must be relevant
-          d_arg_props[i].d_relevant = true;
-          Trace("sygus-process-arg-deps")
-              << " (marked relevant, overwrite definition)." << std::endl;
-        }
-      }
-    }
-    else
-    {
-      if (def.isNull())
-      {
-        if (i != rid)
-        {
-          // marked as relevant, but template can be set equal to master
-          d_arg_props[i].d_template = d_arg_vars[rid];
-          Trace("sygus-process-arg-deps") << " (new definition, map to master "
-                                          << d_arg_vars[rid] << ")."
-                                          << std::endl;
-        }
-        else
-        {
-          d_arg_props[i].d_relevant = true;
-          Trace("sygus-process-arg-deps") << " (marked relevant)." << std::endl;
-        }
-      }
-      else
-      {
-        // has new definition
-        d_arg_props[i].d_template = def;
-        Trace("sygus-process-arg-deps") << " (new definition " << def << ")."
-                                        << std::endl;
-      }
-    }
-  }
-  return rid;
-}
-
-void CegConjectureProcessFun::processTerms(
-    std::vector<Node>& ns,
-    std::vector<Node>& ks,
-    Node nf,
-    std::unordered_set<Node, NodeHashFunction>& synth_fv,
-    std::unordered_map<Node,
-                       std::unordered_set<Node, NodeHashFunction>,
-                       NodeHashFunction>& free_vars)
-{
-  Assert(ns.size() == ks.size());
-  Trace("sygus-process-arg-deps") << "Process " << ns.size()
-                                  << " applications of " << d_synth_fun << "..."
-                                  << std::endl;
-
-  // get the relevant variables
-  // relevant variables are those that appear in the body of the conjunction
-  std::unordered_set<Node, NodeHashFunction> rlv_vars;
-  Assert(free_vars.find(nf) != free_vars.end());
-  rlv_vars = free_vars[nf];
-
-  // get the single occurrence variables
-  // single occurrence variables are those that appear in only one position,
-  // as an argument to the function-to-synthesize.
-  std::unordered_map<Node, bool, NodeHashFunction> single_occ_variables;
-  for (unsigned index = 0; index < ns.size(); index++)
-  {
-    Node n = ns[index];
-    for (unsigned i = 0; i < n.getNumChildren(); i++)
-    {
-      Node nn = n[i];
-      if (nn.isVar())
-      {
-        std::unordered_map<Node, bool, NodeHashFunction>::iterator its =
-            single_occ_variables.find(nn);
-        if (its == single_occ_variables.end())
-        {
-          // only irrelevant variables
-          single_occ_variables[nn] = rlv_vars.find(nn) == rlv_vars.end();
-        }
-        else
-        {
-          single_occ_variables[nn] = false;
-        }
-      }
-      else
-      {
-        std::unordered_map<Node,
-                           std::unordered_set<Node, NodeHashFunction>,
-                           NodeHashFunction>::iterator itf = free_vars.find(nn);
-        Assert(itf != free_vars.end());
-        for (std::unordered_set<Node, NodeHashFunction>::iterator itfv =
-                 itf->second.begin();
-             itfv != itf->second.end();
-             ++itfv)
-        {
-          single_occ_variables[*itfv] = false;
-        }
-      }
-    }
-  }
-
-  // update constant argument information
-  for (unsigned index = 0; index < ns.size(); index++)
-  {
-    Node n = ns[index];
-    Trace("sygus-process-arg-deps")
-        << "  Analyze argument information for application #" << index << ": "
-        << n << std::endl;
-
-    // in the following, we say an argument a "carries" a term t if
-    // the function to synthesize would use argument a to construct
-    // the term t in its definition.
-
-    // map that assumes all arguments carry their respective term
-    std::unordered_map<unsigned, Node> n_arg_map;
-    // terms to the argument that is carrying it.
-    // the arguments in the range of this map must be marked as relevant.
-    std::unordered_map<Node, unsigned, NodeHashFunction> term_to_arg_carry;
-    // map of terms to (unprocessed) arguments where it occurs
-    std::unordered_map<Node, std::vector<unsigned>, NodeHashFunction>
-        term_to_args;
-
-    // initialize
-    for (unsigned a = 0; a < n.getNumChildren(); a++)
-    {
-      n_arg_map[a] = n[a];
-    }
-
-    for (unsigned a = 0; a < n.getNumChildren(); a++)
-    {
-      bool processed = false;
-      if (d_arg_props[a].d_relevant)
-      {
-        // we can assume all relevant arguments carry their terms
-        processed = true;
-        Trace("sygus-process-arg-deps") << "    ...processed arg #" << a
-                                        << " (already relevant)." << std::endl;
-        if (term_to_arg_carry.find(n[a]) == term_to_arg_carry.end())
-        {
-          Trace("sygus-process-arg-deps") << "    carry " << n[a]
-                                          << " by argument #" << a << std::endl;
-          term_to_arg_carry[n[a]] = a;
-        }
-      }
-      else
-      {
-        // first, check if single occurrence variable
-        // check if an irrelevant variable
-        if (n[a].isVar() && synth_fv.find(n[a]) != synth_fv.end())
-        {
-          Assert(single_occ_variables.find(n[a]) != single_occ_variables.end());
-          // may be able to make this more precise?
-          // check if a single-occurrence variable
-          if (single_occ_variables[n[a]])
-          {
-            // if we do not already have a template definition, or the
-            // template is a single occurrence variable
-            if (d_arg_props[a].d_template.isNull()
-                || d_arg_props[a].d_var_single_occ)
-            {
-              processed = true;
-              Trace("sygus-process-arg-deps") << "    ...processed arg #" << a;
-              Trace("sygus-process-arg-deps")
-                  << " (single occurrence variable ";
-              Trace("sygus-process-arg-deps") << n[a] << ")." << std::endl;
-              d_arg_props[a].d_var_single_occ = true;
-              d_arg_props[a].d_template = n[a];
-            }
-          }
-        }
-        if (!processed && !d_arg_props[a].d_template.isNull()
-            && !d_arg_props[a].d_var_single_occ)
-        {
-          // argument already has a definition, see if it is maintained
-          if (checkMatch(d_arg_props[a].d_template, n[a], n_arg_map))
-          {
-            processed = true;
-            Trace("sygus-process-arg-deps") << "    ...processed arg #" << a;
-            Trace("sygus-process-arg-deps") << " (consistent definition "
-                                            << n[a];
-            Trace("sygus-process-arg-deps")
-                << " with " << d_arg_props[a].d_template << ")." << std::endl;
-          }
-        }
-      }
-      if (!processed)
-      {
-        // otherwise, add it to the list of arguments for this term
-        term_to_args[n[a]].push_back(a);
-      }
-    }
-
-    Trace("sygus-process-arg-deps") << "  Look at argument terms..."
-                                    << std::endl;
-
-    // list of all arguments
-    std::vector<Node> arg_list;
-    // now look at the terms for unprocessed arguments
-    for (std::unordered_map<Node, std::vector<unsigned>, NodeHashFunction>::
-             iterator it = term_to_args.begin();
-         it != term_to_args.end();
-         ++it)
-    {
-      Node nn = it->first;
-      arg_list.push_back(nn);
-      if (Trace.isOn("sygus-process-arg-deps"))
-      {
-        Trace("sygus-process-arg-deps") << "    argument " << nn;
-        Trace("sygus-process-arg-deps") << " (" << it->second.size()
-                                        << " positions)";
-        // check the status of this term
-        if (nn.isVar() && synth_fv.find(nn) != synth_fv.end())
-        {
-          // is it relevant?
-          if (rlv_vars.find(nn) != rlv_vars.end())
-          {
-            Trace("sygus-process-arg-deps") << " is a relevant variable."
-                                            << std::endl;
-          }
-          else
-          {
-            Trace("sygus-process-arg-deps") << " is an irrelevant variable."
-                                            << std::endl;
-          }
-        }
-        else
-        {
-          // this can be more precise
-          Trace("sygus-process-arg-deps") << " is a relevant term."
-                                          << std::endl;
-        }
-      }
-    }
-
-    unsigned arg_list_counter = 0;
-    // sort arg_list by term size?
-
-    while (arg_list_counter < arg_list.size())
-    {
-      Node infer_def_t;
-      do
-      {
-        infer_def_t = Node::null();
-        // see if we can infer a definition
-        for (std::unordered_map<Node, std::vector<unsigned>, NodeHashFunction>::
-                 iterator it = term_to_args.begin();
-             it != term_to_args.end();
-             ++it)
-        {
-          Node def = inferDefinition(it->first, term_to_arg_carry, free_vars);
-          if (!def.isNull())
-          {
-            Trace("sygus-process-arg-deps") << "  *** Inferred definition "
-                                            << def << " for " << it->first
-                                            << std::endl;
-            // assign to each argument
-            assignRelevantDef(def, it->second);
-            // term_to_arg_carry[it->first] = rid;
-            infer_def_t = it->first;
-            break;
-          }
-        }
-        if (!infer_def_t.isNull())
-        {
-          term_to_args.erase(infer_def_t);
-        }
-      } while (!infer_def_t.isNull());
-
-      // decide to make an argument relevant
-      bool success = false;
-      while (arg_list_counter < arg_list.size() && !success)
-      {
-        Node curr = arg_list[arg_list_counter];
-        std::unordered_map<Node, std::vector<unsigned>, NodeHashFunction>::
-            iterator it = term_to_args.find(curr);
-        if (it != term_to_args.end())
-        {
-          Trace("sygus-process-arg-deps") << "  *** Decide relevant " << curr
-                                          << std::endl;
-          // assign relevant to each
-          Node null_def;
-          unsigned rid = assignRelevantDef(null_def, it->second);
-          term_to_arg_carry[curr] = rid;
-          Trace("sygus-process-arg-deps")
-              << "    carry " << curr << " by argument #" << rid << std::endl;
-          term_to_args.erase(curr);
-          success = true;
-        }
-        arg_list_counter++;
-      }
-    }
-  }
-}
-
-bool CegConjectureProcessFun::isArgRelevant(unsigned i)
-{
-  return d_arg_props[i].d_relevant;
-}
-
-void CegConjectureProcessFun::getIrrelevantArgs(
-    std::unordered_set<unsigned>& args)
-{
-  for (unsigned i = 0; i < d_arg_vars.size(); i++)
-  {
-    if (!d_arg_props[i].d_relevant)
-    {
-      args.insert(i);
-    }
-  }
-}
-
-CegConjectureProcess::CegConjectureProcess(QuantifiersEngine* qe) {}
-CegConjectureProcess::~CegConjectureProcess() {}
-Node CegConjectureProcess::preSimplify(Node q)
-{
-  Trace("sygus-process") << "Pre-simplify conjecture : " << q << std::endl;
-  return q;
-}
-
-Node CegConjectureProcess::postSimplify(Node q)
-{
-  Trace("sygus-process") << "Post-simplify conjecture : " << q << std::endl;
-  Assert(q.getKind() == FORALL);
-
-  // initialize the information about each function to synthesize
-  for (unsigned i = 0; i < q[0].getNumChildren(); i++)
-  {
-    Node f = q[0][i];
-    if (f.getType().isFunction())
-    {
-      d_sf_info[f].init(f);
-    }
-  }
-
-  // get the base on the conjecture
-  Node base = q[1];
-  std::unordered_set<Node, NodeHashFunction> synth_fv;
-  if (base.getKind() == NOT && base[0].getKind() == FORALL)
-  {
-    for (unsigned j = 0; j < base[0][0].getNumChildren(); j++)
-    {
-      synth_fv.insert(base[0][0][j]);
-    }
-    base = base[0][1];
-  }
-  std::vector<Node> conjuncts;
-  getComponentVector(AND, base, conjuncts);
-
-  // process the conjunctions
-  for (std::map<Node, CegConjectureProcessFun>::iterator it = d_sf_info.begin();
-       it != d_sf_info.end();
-       ++it)
-  {
-    Node f = it->first;
-    for (unsigned i = 0; i < conjuncts.size(); i++)
-    {
-      processConjunct(conjuncts[i], f, synth_fv);
-    }
-  }
-
-  return q;
-}
-
-void CegConjectureProcess::initialize(Node n, std::vector<Node>& candidates)
-{
-  if (Trace.isOn("sygus-process"))
-  {
-    Trace("sygus-process") << "Process conjecture : " << n
-                           << " with candidates: " << std::endl;
-    for (unsigned i = 0; i < candidates.size(); i++)
-    {
-      Trace("sygus-process") << "  " << candidates[i] << std::endl;
-    }
-  }
-}
-
-bool CegConjectureProcess::isArgRelevant(Node f, unsigned i)
-{
-  std::map<Node, CegConjectureProcessFun>::iterator its = d_sf_info.find(f);
-  if (its != d_sf_info.end())
-  {
-    return its->second.isArgRelevant(i);
-  }
-  Assert(false);
-  return true;
-}
-
-bool CegConjectureProcess::getIrrelevantArgs(Node f,
-                                             std::unordered_set<unsigned>& args)
-{
-  std::map<Node, CegConjectureProcessFun>::iterator its = d_sf_info.find(f);
-  if (its != d_sf_info.end())
-  {
-    its->second.getIrrelevantArgs(args);
-    return true;
-  }
-  return false;
-}
-
-void CegConjectureProcess::processConjunct(
-    Node n, Node f, std::unordered_set<Node, NodeHashFunction>& synth_fv)
-{
-  Trace("sygus-process-arg-deps") << "Process conjunct: " << std::endl;
-  Trace("sygus-process-arg-deps") << "  " << n << " for synth fun " << f
-                                  << "..." << std::endl;
-
-  // first, flatten the conjunct
-  // make a copy of free variables since we may add new ones
-  std::unordered_set<Node, NodeHashFunction> synth_fv_n = synth_fv;
-  std::unordered_map<Node, Node, NodeHashFunction> defs;
-  Node nf = flatten(n, f, synth_fv_n, defs);
-
-  Trace("sygus-process-arg-deps") << "Flattened to: " << std::endl;
-  Trace("sygus-process-arg-deps") << "  " << nf << std::endl;
-
-  // get free variables in nf
-  std::unordered_map<Node,
-                     std::unordered_set<Node, NodeHashFunction>,
-                     NodeHashFunction>
-      free_vars;
-  getFreeVariables(nf, synth_fv_n, free_vars);
-  // get free variables in each application
-  std::vector<Node> ns;
-  std::vector<Node> ks;
-  for (std::unordered_map<Node, Node, NodeHashFunction>::iterator it =
-           defs.begin();
-       it != defs.end();
-       ++it)
-  {
-    getFreeVariables(it->second, synth_fv_n, free_vars);
-    ns.push_back(it->second);
-    ks.push_back(it->first);
-  }
-
-  // process the applications of synthesis functions
-  if (!ns.empty())
-  {
-    std::map<Node, CegConjectureProcessFun>::iterator its = d_sf_info.find(f);
-    if (its != d_sf_info.end())
-    {
-      its->second.processTerms(ns, ks, nf, synth_fv_n, free_vars);
-    }
-  }
-}
-
-Node CegConjectureProcess::CegConjectureProcess::flatten(
-    Node n,
-    Node f,
-    std::unordered_set<Node, NodeHashFunction>& synth_fv,
-    std::unordered_map<Node, Node, NodeHashFunction>& defs)
-{
-  std::unordered_map<Node, Node, NodeHashFunction> visited;
-  std::unordered_map<Node, Node, NodeHashFunction>::iterator it;
-  std::stack<Node> visit;
-  Node cur;
-  visit.push(n);
-  do
-  {
-    cur = visit.top();
-    visit.pop();
-    it = visited.find(cur);
-
-    if (it == visited.end())
-    {
-      visited[cur] = Node::null();
-      visit.push(cur);
-      for (unsigned i = 0; i < cur.getNumChildren(); i++)
-      {
-        visit.push(cur[i]);
-      }
-    }
-    else if (it->second.isNull())
-    {
-      Node ret = cur;
-      bool childChanged = false;
-      std::vector<Node> children;
-      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
-      {
-        children.push_back(cur.getOperator());
-      }
-      for (unsigned i = 0; i < cur.getNumChildren(); i++)
-      {
-        it = visited.find(cur[i]);
-        Assert(it != visited.end());
-        Assert(!it->second.isNull());
-        childChanged = childChanged || cur[i] != it->second;
-        children.push_back(it->second);
-      }
-      if (childChanged)
-      {
-        ret = NodeManager::currentNM()->mkNode(cur.getKind(), children);
-      }
-      // is it the function to synthesize?
-      if (cur.getKind() == APPLY_UF && cur.getOperator() == f)
-      {
-        // if so, flatten
-        Node k = NodeManager::currentNM()->mkBoundVar("vf", cur.getType());
-        defs[k] = ret;
-        ret = k;
-        synth_fv.insert(k);
-      }
-      // post-rewrite
-      visited[cur] = ret;
-    }
-  } while (!visit.empty());
-  Assert(visited.find(n) != visited.end());
-  Assert(!visited.find(n)->second.isNull());
-  return visited[n];
-}
-
-void CegConjectureProcess::getFreeVariables(
-    Node n,
-    std::unordered_set<Node, NodeHashFunction>& synth_fv,
-    std::unordered_map<Node,
-                       std::unordered_set<Node, NodeHashFunction>,
-                       NodeHashFunction>& free_vars)
-{
-  // first must compute free variables in each subterm of n,
-  // as well as contains_synth_fun
-  std::unordered_map<Node, bool, NodeHashFunction> visited;
-  std::unordered_map<Node, bool, NodeHashFunction>::iterator it;
-  std::stack<Node> visit;
-  Node cur;
-  visit.push(n);
-  do
-  {
-    cur = visit.top();
-    visit.pop();
-    it = visited.find(cur);
-
-    if (it == visited.end())
-    {
-      visited[cur] = false;
-      visit.push(cur);
-      for (unsigned i = 0; i < cur.getNumChildren(); i++)
-      {
-        visit.push(cur[i]);
-      }
-    }
-    else if (!it->second)
-    {
-      free_vars[cur].clear();
-      if (synth_fv.find(cur) != synth_fv.end())
-      {
-        // it is a free variable
-        free_vars[cur].insert(cur);
-      }
-      else
-      {
-        // otherwise, carry the free variables from the children
-        for (unsigned i = 0; i < cur.getNumChildren(); i++)
-        {
-          free_vars[cur].insert(free_vars[cur[i]].begin(),
-                                free_vars[cur[i]].end());
-        }
-      }
-      visited[cur] = true;
-    }
-  } while (!visit.empty());
-}
-
-Node CegConjectureProcess::getSymmetryBreakingPredicate(
-    Node x, Node e, TypeNode tn, unsigned tindex, unsigned depth)
-{
-  return Node::null();
-}
-
-void CegConjectureProcess::debugPrint(const char* c) {}
-void CegConjectureProcess::getComponentVector(Kind k,
-                                              Node n,
-                                              std::vector<Node>& args)
-{
-  if (n.getKind() == k)
-  {
-    for (unsigned i = 0; i < n.getNumChildren(); i++)
-    {
-      args.push_back(n[i]);
-    }
-  }
-  else
-  {
-    args.push_back(n);
-  }
-}
-
-} /* namespace CVC4::theory::quantifiers */
-} /* namespace CVC4::theory */
-} /* namespace CVC4 */
diff --git a/src/theory/quantifiers/sygus_process_conj.h b/src/theory/quantifiers/sygus_process_conj.h
deleted file mode 100644 (file)
index 0b9a255..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-/*********************                                                        */
-/*! \file sygus_process_conj.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Techniqures for static preprocessing and analysis of
- ** sygus conjectures.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__SYGUS_PROCESS_CONJ_H
-#define __CVC4__THEORY__QUANTIFIERS__SYGUS_PROCESS_CONJ_H
-
-#include <map>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#include "expr/node.h"
-#include "expr/type_node.h"
-#include "theory/quantifiers_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-/** This file contains techniques that compute
- * argument relevancy for synthesis functions
- *
- * Let F be a synthesis conjecture of the form:
- *   exists f. forall X. P( f, X )
- *
- * The classes below compute whether certain arguments of
- * the function-to-synthesize f are irrelevant.
- * Assume that f is a binary function, where possible solutions
- * to the above conjecture are of the form:
- *   f -> (lambda (xy) t[x,y])
- * We say e.g. that the 2nd argument of f is irrelevant if we
- * can determine:
- *   F has a solution
- * if and only if
- *   F has a solution of the form f -> (lambda (xy) t[x] )
- * We conclude that arguments are irrelevant using the following
- * techniques.
- *
- *
- * (1) Argument invariance:
- *
- * Let s[z] be a term whose free variables are contained in { z }.
- * If all occurrences of f-applications in F are of the form:
- *   f(t, s[t])
- * then:
- *   f = (lambda (xy) r[x,y])
- * is a solution to F only if:
- *   f = (lambda (xy) r[x,s[x]])
- * is as well.
- * Hence the second argument of f is not relevant.
- *
- *
- * (2) Variable irrelevance:
- *
- * If F is equivalent to:
- *   exists f. forall w z u1...un. C1 ^...^Cm,
- * where for i=1...m, Ci is of the form:
- *   ( w1 = f(tm1[z], u1) ^
- *     ... ^
- *     wn = f(tmn[z], un) ) => Pm(w1...wn, z)
- * then the second argument of f is irrelevant.
- * We call u1...un single occurrence variables
- * (in Ci).
- *
- *
- * TODO (#1210) others, generalize (2)?
- *
- */
-
-/** This structure stores information regarding
- * an argument of a function to synthesize.
- *
- * It is used to store whether the argument
- * position in the function to synthesize is
- * relevant.
- */
-class CegConjectureProcessArg
-{
- public:
-  CegConjectureProcessArg() : d_var_single_occ(false), d_relevant(false) {}
-  /** template definition
-   * This is the term s[z] described
-   * under "Argument Invariance" above.
-   */
-  Node d_template;
-  /** single occurrence
-   * Whether we are trying to show this argument
-   * is irrelevant by "Variable irrelevance"
-   * described above.
-   */
-  bool d_var_single_occ;
-  /** whether this argument is relevant
-   * An argument is marked as relevant if:
-   * (A) it is explicitly marked as relevant
-   *     due to a function application containing
-   *     a relevant term at this argument position, or
-   * (B) if it is given conflicting template definitions.
-   */
-  bool d_relevant;
-};
-
-/** This structure stores information regarding conjecture-specific
-* analysis of a single function to synthesize within
-* a conjecture to synthesize.
-*
-* It maintains information about each of the function to
-* synthesize's arguments.
-*/
-struct CegConjectureProcessFun
-{
- public:
-  CegConjectureProcessFun() {}
-  ~CegConjectureProcessFun() {}
-  /** initialize this class for function f */
-  void init(Node f);
-  /** process terms
-   *
-   * This is called once per conjunction in
-   * the synthesis conjecture.
-   *
-   * ns are the f-applications to process,
-   * ks are the variables we introduced to flatten them,
-   * nf is the flattened form of our conjecture to process,
-   * free_vars maps all subterms of n and nf to the set
-   *   of variables (in set synth_fv) they contain.
-   *
-   * This updates information regarding which arguments
-   * of the function-to-synthesize are relevant.
-   */
-  void processTerms(
-      std::vector<Node>& ns,
-      std::vector<Node>& ks,
-      Node nf,
-      std::unordered_set<Node, NodeHashFunction>& synth_fv,
-      std::unordered_map<Node,
-                         std::unordered_set<Node, NodeHashFunction>,
-                         NodeHashFunction>& free_vars);
-  /** is the i^th argument of the function-to-synthesize of this class relevant?
-   */
-  bool isArgRelevant(unsigned i);
-  /** get irrelevant arguments for the function-to-synthesize of this class */
-  void getIrrelevantArgs(std::unordered_set<unsigned>& args);
-
- private:
-  /** the synth fun associated with this */
-  Node d_synth_fun;
-  /** properties of each argument */
-  std::vector<CegConjectureProcessArg> d_arg_props;
-  /** variables for each argument type of f
-   *
-   * These are used to express templates for argument
-   * invariance, in the data member
-   * CegConjectureProcessArg::d_template.
-   */
-  std::vector<Node> d_arg_vars;
-  /** map from d_arg_vars to the argument #
-   * they represent.
-   */
-  std::unordered_map<Node, unsigned, NodeHashFunction> d_arg_var_num;
-  /** check match
-   * This function returns true iff we can infer:
-   *   cn * { x -> n_arg_map[d_arg_var_num[x]] | x in d_arg_vars } = n
-   * In other words, cn and n are equivalent
-   * via the substitution mapping argument variables to terms
-   * specified by n_arg_map. The rewriter is used for inferring
-   * this equivalence.
-   *
-   * For example, if n_arg_map contains { 1 -> t, 2 -> s }, then
-   *   checkMatch( x1+x2, t+s, n_arg_map ) returns true,
-   *   checkMatch( x1+1, t+1, n_arg_map ) returns true,
-   *   checkMatch( 0, 0, n_arg_map ) returns true,
-   *   checkMatch( x1+1, s, n_arg_map ) returns false.
-   */
-  bool checkMatch(Node cn,
-                  Node n,
-                  std::unordered_map<unsigned, Node>& n_arg_map);
-  /** infer definition
-   *
-   * In the following, we say a term is a "template
-   * definition" if its free variables are a subset of d_arg_vars.
-   *
-   * If this function returns a non-null node ret, then
-   *   checkMatch( ret, n, term_to_arg_carry^-1 ) returns true.
-   * and ret is a template definition.
-   *
-   * The free variables for all subterms of n are stored in
-   * free_vars. The map term_to_arg_carry is injective.
-   *
-   * For example, if term_to_arg_carry contains { t -> 1, s -> 2 } and
-   * free_vars is { t -> {y}, r -> {y}, s -> {}, q -> {}, ... -> {} }, then
-   *   inferDefinition( 0, term_to_arg_carry, free_vars )
-   *     returns 0
-   *   inferDefinition( t, term_to_arg_carry, free_vars )
-   *     returns x1
-   *   inferDefinition( t+s+q, term_to_arg_carry, free_vars )
-   *     returns x1+x2+q
-   *   inferDefinition( t+r, term_to_arg_carry, free_vars )
-   *     returns null
-   *
-   * Notice that multiple definitions are possible, e.g. above:
-   *  inferDefinition( s, term_to_arg_carry, free_vars )
-   *    may return either s or x2
-   * TODO (#1210) : try multiple definitions?
-   */
-  Node inferDefinition(
-      Node n,
-      std::unordered_map<Node, unsigned, NodeHashFunction>& term_to_arg_carry,
-      std::unordered_map<Node,
-                         std::unordered_set<Node, NodeHashFunction>,
-                         NodeHashFunction>& free_vars);
-  /** Assign relevant definition
-   *
-   * If def is non-null,
-   * this function assigns def as a template definition
-   * for the argument positions in args.
-   * This is called when there exists a term of the form
-   *   f( t1....tn )
-   * in the synthesis conjecture that we are processing,
-   * where t_i = def * sigma for all i \in args,
-   * for some substitution sigma, where def is a template
-   * definition.
-   *
-   * If def is null, then there exists a term of the form
-   *   f( t1....tn )
-   * where t_i = s for for all i \in args, and s is not
-   * a template definition. In this case, at least one
-   * argument in args must be marked as a relevant
-   * argument position.
-   *
-   * Returns a value rid such that:
-   * (1) rid occurs in args,
-   * (2) if def is null, then argument rid was marked
-   *     relevant by this call.
-   */
-  unsigned assignRelevantDef(Node def, std::vector<unsigned>& args);
-  /** returns true if n is in d_arg_vars, updates arg_index
-   * to its position in d_arg_vars.
-   */
-  bool isArgVar(Node n, unsigned& arg_index);
-};
-
-/** Ceg Conjecture Process
-*
-* This class implements static techniques for preprocessing and analysis of
-* sygus conjectures.
-*
-* It is used as a back-end to CegConjecture, which calls it using the following
-* interface:
-* (1) When a sygus conjecture is asserted, we call
-* CegConjectureProcess::simplify( q ),
-*     where q is the sygus conjecture in original form.
-*
-* (2) After a sygus conjecture is simplified and converted to deep
-* embedding form, we call CegConjectureProcess::initialize( n, candidates ).
-*
-* (3) During enumerative SyGuS search, calls may be made by
-* the extension of the quantifier-free datatypes decision procedure for
-* sygus to CegConjectureProcess::getSymmetryBreakingPredicate(...), which are
-* used for pruning search space based on conjecture-specific analysis.
-*/
-class CegConjectureProcess
-{
- public:
-  CegConjectureProcess(QuantifiersEngine* qe);
-  ~CegConjectureProcess();
-  /** simplify the synthesis conjecture q
-  * Returns a formula that is equivalent to q.
-  * This simplification pass is called before all others
-  * in CegConjecture::assign.
-  *
-  * This function is intended for simplifications that
-  * impact whether or not the synthesis conjecture is
-  * single-invocation.
-  */
-  Node preSimplify(Node q);
-  /** simplify the synthesis conjecture q
-  * Returns a formula that is equivalent to q.
-  * This simplification pass is called after all others
-  * in CegConjecture::assign.
-  */
-  Node postSimplify(Node q);
-  /** initialize
-  *
-  * n is the "base instantiation" of the deep-embedding version of
-  *   the synthesis conjecture under "candidates".
-  *   (see CegConjecture::d_base_inst)
-  */
-  void initialize(Node n, std::vector<Node>& candidates);
-  /** is the i^th argument of the function-to-synthesize f relevant? */
-  bool isArgRelevant(Node f, unsigned i);
-  /** get irrelevant arguments for function-to-synthesize f
-   * returns true if f is a function-to-synthesize.
-   */
-  bool getIrrelevantArgs(Node f, std::unordered_set<unsigned>& args);
-  /** get symmetry breaking predicate
-  *
-  * Returns a formula that restricts the enumerative search space (for a given
-  * depth) for a term x of sygus type tn whose top symbol is the tindex^{th}
-  * constructor, where x is a subterm of enumerator e.
-  */
-  Node getSymmetryBreakingPredicate(
-      Node x, Node e, TypeNode tn, unsigned tindex, unsigned depth);
-  /** print out debug information about this conjecture */
-  void debugPrint(const char* c);
- private:
-  /** process conjunct
-   *
-   * This sets up initial information about functions to synthesize
-   * where n is a conjunct of the synthesis conjecture, and synth_fv
-   * is the set of (inner) universal variables in the synthesis
-   * conjecture.
-   */
-  void processConjunct(Node n,
-                       Node f,
-                       std::unordered_set<Node, NodeHashFunction>& synth_fv);
-  /** flatten
-   *
-   * Flattens all applications of f in term n.
-   * This may add new variables to synth_fv, which
-   * are introduced at all positions of functions
-   * to synthesize in a bottom-up fashion. For each
-   * variable k introduced for a function application
-   * f(t), we add ( k -> f(t) ) to defs and ( f -> k )
-   * to fun_to_defs.
-   */
-  Node flatten(Node n,
-               Node f,
-               std::unordered_set<Node, NodeHashFunction>& synth_fv,
-               std::unordered_map<Node, Node, NodeHashFunction>& defs);
-  /** get free variables
-   * Constructs a map of all free variables that occur in n
-   * from synth_fv and stores them in the map free_vars.
-   */
-  void getFreeVariables(
-      Node n,
-      std::unordered_set<Node, NodeHashFunction>& synth_fv,
-      std::unordered_map<Node,
-                         std::unordered_set<Node, NodeHashFunction>,
-                         NodeHashFunction>& free_vars);
-  /** for each synth-fun, information that is specific to this conjecture */
-  std::map<Node, CegConjectureProcessFun> d_sf_info;
-
-  /** get component vector */
-  void getComponentVector(Kind k, Node n, std::vector<Node>& args);
-};
-
-} /* namespace CVC4::theory::quantifiers */
-} /* namespace CVC4::theory */
-} /* namespace CVC4 */
-
-#endif
index 60c2af22a575b196aa4fa62c09be3587592d1787..abc9232af6b46d540a10eaa75157ad87a8812e56 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <map>
 #include "theory/quantifiers/dynamic_rewrite.h"
-#include "theory/quantifiers/term_database_sygus.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
 
 namespace CVC4 {
 namespace theory {
index 19cdc68e560739d80b2cd84edb509ccd0ec23782..8e22b2ced8b4dba88f2e1a3535fae2d7fa258cbb 100644 (file)
@@ -19,7 +19,7 @@
 #include "options/uf_options.h"
 #include "theory/quantifiers/quantifiers_attributes.h"
 #include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/ematching/trigger.h"
 #include "theory/quantifiers_engine.h"
 #include "theory/theory_engine.h"
 
diff --git a/src/theory/quantifiers/term_database_sygus.cpp b/src/theory/quantifiers/term_database_sygus.cpp
deleted file mode 100644 (file)
index 4c80108..0000000
+++ /dev/null
@@ -1,1487 +0,0 @@
-/*********************                                                        */
-/*! \file term_database_sygus.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of term database sygus class
- **/
-
-#include "theory/quantifiers/term_database_sygus.h"
-
-#include "options/quantifiers_options.h"
-#include "theory/arith/arith_msum.h"
-#include "theory/quantifiers/quantifiers_attributes.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers_engine.h"
-
-using namespace std;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory::inst;
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-TermDbSygus::TermDbSygus(context::Context* c, QuantifiersEngine* qe)
-    : d_quantEngine(qe),
-      d_syexp(new SygusExplain(this)),
-      d_ext_rw(new ExtendedRewriter(true))
-{
-  d_true = NodeManager::currentNM()->mkConst( true );
-  d_false = NodeManager::currentNM()->mkConst( false );
-}
-
-bool TermDbSygus::reset( Theory::Effort e ) { 
-  return true;  
-}
-
-TNode TermDbSygus::getFreeVar( TypeNode tn, int i, bool useSygusType ) {
-  unsigned sindex = 0;
-  TypeNode vtn = tn;
-  if( useSygusType ){
-    if( tn.isDatatype() ){
-      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-      if( !dt.getSygusType().isNull() ){
-        vtn = TypeNode::fromType( dt.getSygusType() );
-        sindex = 1;
-      } 
-    }
-  }
-  while( i>=(int)d_fv[sindex][tn].size() ){
-    std::stringstream ss;
-    if( tn.isDatatype() ){
-      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-      ss << "fv_" << dt.getName() << "_" << i;
-    }else{
-      ss << "fv_" << tn << "_" << i;
-    }
-    Assert( !vtn.isNull() );
-    Node v = NodeManager::currentNM()->mkSkolem( ss.str(), vtn, "for sygus normal form testing" );
-    d_fv_stype[v] = tn;
-    d_fv_num[v] = i;
-    d_fv[sindex][tn].push_back( v );
-  }
-  return d_fv[sindex][tn][i];
-}
-
-TNode TermDbSygus::getFreeVarInc( TypeNode tn, std::map< TypeNode, int >& var_count, bool useSygusType ) {
-  std::map< TypeNode, int >::iterator it = var_count.find( tn );
-  if( it==var_count.end() ){
-    var_count[tn] = 1;
-    return getFreeVar( tn, 0, useSygusType );
-  }else{
-    int index = it->second;
-    var_count[tn]++;
-    return getFreeVar( tn, index, useSygusType );
-  }
-}
-
-bool TermDbSygus::hasFreeVar( Node n, std::map< Node, bool >& visited ){
-  if( visited.find( n )==visited.end() ){
-    visited[n] = true;
-    if( isFreeVar( n ) ){
-      return true;    
-    }
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      if( hasFreeVar( n[i], visited ) ){
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
-bool TermDbSygus::hasFreeVar( Node n ) {
-  std::map< Node, bool > visited;
-  return hasFreeVar( n, visited );
-}
-  
-TypeNode TermDbSygus::getSygusTypeForVar( Node v ) {
-  Assert( d_fv_stype.find( v )!=d_fv_stype.end() );
-  return d_fv_stype[v];
-}
-
-Node TermDbSygus::mkGeneric(const Datatype& dt,
-                            unsigned c,
-                            std::map<TypeNode, int>& var_count,
-                            std::map<int, Node>& pre)
-{
-  Assert(c < dt.getNumConstructors());
-  Assert( dt.isSygus() );
-  Assert( !dt[c].getSygusOp().isNull() );
-  std::vector< Node > children;
-  Node op = Node::fromExpr( dt[c].getSygusOp() );
-  if( op.getKind()!=BUILTIN ){
-    children.push_back( op );
-  }
-  Trace("sygus-db-debug") << "mkGeneric " << dt.getName() << " " << op << " " << op.getKind() << "..." << std::endl;
-  for (unsigned i = 0, nargs = dt[c].getNumArgs(); i < nargs; i++)
-  {
-    TypeNode tna = getArgType( dt[c], i );
-    Node a;
-    std::map< int, Node >::iterator it = pre.find( i );
-    if( it!=pre.end() ){
-      a = it->second;
-    }else{
-      a = getFreeVarInc( tna, var_count, true );
-    }
-    Trace("sygus-db-debug")
-        << "  child " << i << " : " << a << " : " << a.getType() << std::endl;
-    Assert( !a.isNull() );
-    children.push_back( a );
-  }
-  Node ret;
-  if( op.getKind()==BUILTIN ){
-    Trace("sygus-db-debug") << "Make builtin node..." << std::endl;
-    ret = NodeManager::currentNM()->mkNode( op, children );
-  }else{
-    Kind ok = getOperatorKind( op );
-    Trace("sygus-db-debug") << "Operator kind is " << ok << std::endl;
-    if( children.size()==1 && ok==kind::UNDEFINED_KIND ){
-      ret = children[0];
-    }else{
-      ret = NodeManager::currentNM()->mkNode( ok, children );
-    }
-  }
-  Trace("sygus-db-debug") << "...returning " << ret << std::endl;
-  return ret;
-}
-
-Node TermDbSygus::mkGeneric(const Datatype& dt, int c, std::map<int, Node>& pre)
-{
-  std::map<TypeNode, int> var_count;
-  return mkGeneric(dt, c, var_count, pre);
-}
-
-Node TermDbSygus::sygusToBuiltin( Node n, TypeNode tn ) {
-  Assert( n.getType()==tn );
-  Assert( tn.isDatatype() );
-  std::map< Node, Node >::iterator it = d_sygus_to_builtin[tn].find( n );
-  if( it==d_sygus_to_builtin[tn].end() ){
-    Trace("sygus-db-debug") << "SygusToBuiltin : compute for " << n << ", type = " << tn << std::endl;
-    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-    if( n.getKind()==APPLY_CONSTRUCTOR ){
-      unsigned i = Datatype::indexOf( n.getOperator().toExpr() );
-      Assert( n.getNumChildren()==dt[i].getNumArgs() );
-      std::map< TypeNode, int > var_count;
-      std::map< int, Node > pre;
-      for (unsigned j = 0, size = n.getNumChildren(); j < size; j++)
-      {
-        pre[j] = sygusToBuiltin( n[j], getArgType( dt[i], j ) );
-      }
-      Node ret = mkGeneric(dt, i, var_count, pre);
-      Trace("sygus-db-debug") << "SygusToBuiltin : Generic is " << ret << std::endl;
-      d_sygus_to_builtin[tn][n] = ret;
-      return ret;
-    }
-    if (n.hasAttribute(SygusPrintProxyAttribute()))
-    {
-      // this variable was associated by an attribute to a builtin node
-      return n.getAttribute(SygusPrintProxyAttribute());
-    }
-    Assert(isFreeVar(n));
-    // map to builtin variable type
-    int fv_num = getVarNum(n);
-    Assert(!dt.getSygusType().isNull());
-    TypeNode vtn = TypeNode::fromType(dt.getSygusType());
-    Node ret = getFreeVar(vtn, fv_num);
-    return ret;
-  }else{
-    return it->second;
-  }
-}
-
-Node TermDbSygus::sygusSubstituted( TypeNode tn, Node n, std::vector< Node >& args ) {
-  Assert( d_var_list[tn].size()==args.size() );
-  return n.substitute( d_var_list[tn].begin(), d_var_list[tn].end(), args.begin(), args.end() );
-}
-
-unsigned TermDbSygus::getSygusTermSize( Node n ){
-  if( n.getNumChildren()==0 ){
-    return 0;
-  }else{
-    Assert(n.getKind() == APPLY_CONSTRUCTOR);
-    unsigned sum = 0;
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      sum += getSygusTermSize( n[i] );
-    }
-    const Datatype& dt = Datatype::datatypeOf(n.getOperator().toExpr());
-    int cindex = Datatype::indexOf(n.getOperator().toExpr());
-    Assert(cindex >= 0 && cindex < (int)dt.getNumConstructors());
-    unsigned weight = dt[cindex].getWeight();
-    return weight + sum;
-  }
-}
-
-class ReqTrie {
-public:
-  ReqTrie() : d_req_kind( UNDEFINED_KIND ){}
-  std::map< unsigned, ReqTrie > d_children;
-  Kind d_req_kind;
-  TypeNode d_req_type;
-  Node d_req_const;
-  void print( const char * c, int indent = 0 ){
-    if( d_req_kind!=UNDEFINED_KIND ){
-      Trace(c) << d_req_kind << " ";
-    }else if( !d_req_type.isNull() ){
-      Trace(c) << d_req_type;
-    }else if( !d_req_const.isNull() ){
-      Trace(c) << d_req_const;
-    }else{
-      Trace(c) << "_";
-    }
-    Trace(c) << std::endl;
-    for( std::map< unsigned, ReqTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
-      for( int i=0; i<=indent; i++ ) { Trace(c) << "  "; }
-      Trace(c) << it->first << " : ";
-      it->second.print( c, indent+1 );
-    }
-  }
-  bool satisfiedBy( quantifiers::TermDbSygus * tdb, TypeNode tn ){
-    if( !d_req_const.isNull() ){
-      if( !tdb->hasConst( tn, d_req_const ) ){
-        return false;
-      }
-    }
-    if( !d_req_type.isNull() ){
-      if( tn!=d_req_type ){
-        return false;
-      }
-    }
-    if( d_req_kind!=UNDEFINED_KIND ){
-      int c = tdb->getKindConsNum( tn, d_req_kind );
-      if( c!=-1 ){
-        bool ret = true;
-        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-        for( std::map< unsigned, ReqTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
-          if( it->first<dt[c].getNumArgs() ){
-            TypeNode tnc = tdb->getArgType( dt[c], it->first );
-            if( !it->second.satisfiedBy( tdb, tnc ) ){
-              ret = false;
-              break;
-            }
-          }else{
-            ret = false;
-            break;
-          }
-        }
-        if( !ret ){
-          return false;
-        }
-        // TODO : commutative operators try both?
-      }else{
-        return false;
-      }
-    }
-    return true;
-  }
-  bool empty() {
-    return d_req_kind==UNDEFINED_KIND && d_req_const.isNull() && d_req_type.isNull();
-  }
-};
-
-//this function gets all easy redundant cases, before consulting rewriters
-bool TermDbSygus::considerArgKind( TypeNode tn, TypeNode tnp, Kind k, Kind pk, int arg ) {
-  const Datatype& pdt = ((DatatypeType)(tnp).toType()).getDatatype();
-  const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-  Assert( hasKind( tn, k ) );
-  Assert( hasKind( tnp, pk ) );
-  Trace("sygus-sb-debug") << "Consider sygus arg kind " << k << ", pk = " << pk << ", arg = " << arg << "?" << std::endl;
-  int c = getKindConsNum( tn, k );
-  int pc = getKindConsNum( tnp, pk );
-  if( k==pk ){
-    //check for associativity
-    if( quantifiers::TermUtil::isAssoc( k ) ){
-      //if the operator is associative, then a repeated occurrence should only occur in the leftmost argument position
-      int firstArg = getFirstArgOccurrence( pdt[pc], tn );
-      Assert( firstArg!=-1 );
-      if( arg!=firstArg ){
-        Trace("sygus-sb-simple") << "  sb-simple : do not consider " << k << " at child arg " << arg << " of " << k << " since it is associative, with first arg = " << firstArg << std::endl;
-        return false;
-      }else{
-        return true;
-      }
-    }
-  }
-  //describes the shape of an alternate term to construct
-  //  we check whether this term is in the sygus grammar below
-  ReqTrie rt;
-  Assert( rt.empty() );
-  
-  //construct rt by cases
-  if( pk==NOT || pk==BITVECTOR_NOT || pk==UMINUS || pk==BITVECTOR_NEG ){
-    //negation normal form
-    if( pk==k ){
-      rt.d_req_type = getArgType( dt[c], 0 );
-    }else{
-      Kind reqk = UNDEFINED_KIND;       //required kind for all children
-      std::map< unsigned, Kind > reqkc; //required kind for some children
-      if( pk==NOT ){
-        if( k==AND ) {
-          rt.d_req_kind = OR;reqk = NOT;
-        }else if( k==OR ){
-          rt.d_req_kind = AND;reqk = NOT;
-        //AJR : eliminate this if we eliminate xor
-        }else if( k==EQUAL ) {
-          rt.d_req_kind = XOR;
-        }else if( k==XOR ) {
-          rt.d_req_kind = EQUAL;
-        }else if( k==ITE ){
-          rt.d_req_kind = ITE;reqkc[1] = NOT;reqkc[2] = NOT;
-          rt.d_children[0].d_req_type = getArgType( dt[c], 0 );
-        }else if( k==LEQ || k==GT ){
-          //  (not (~ x y)) ----->  (~ (+ y 1) x)
-          rt.d_req_kind = k;
-          rt.d_children[0].d_req_kind = PLUS;
-          rt.d_children[0].d_children[0].d_req_type = getArgType( dt[c], 1 );
-          rt.d_children[0].d_children[1].d_req_const = NodeManager::currentNM()->mkConst( Rational( 1 ) );
-          rt.d_children[1].d_req_type = getArgType( dt[c], 0 );
-          //TODO: other possibilities?
-        }else if( k==LT || k==GEQ ){
-          //  (not (~ x y)) ----->  (~ y (+ x 1))
-          rt.d_req_kind = k;
-          rt.d_children[0].d_req_type = getArgType( dt[c], 1 );
-          rt.d_children[1].d_req_kind = PLUS;
-          rt.d_children[1].d_children[0].d_req_type = getArgType( dt[c], 0 );
-          rt.d_children[1].d_children[1].d_req_const = NodeManager::currentNM()->mkConst( Rational( 1 ) );
-        }
-      }else if( pk==BITVECTOR_NOT ){
-        if( k==BITVECTOR_AND ) {
-          rt.d_req_kind = BITVECTOR_OR;reqk = BITVECTOR_NOT;
-        }else if( k==BITVECTOR_OR ){
-          rt.d_req_kind = BITVECTOR_AND;reqk = BITVECTOR_NOT;
-        }else if( k==BITVECTOR_XNOR ) {
-          rt.d_req_kind = BITVECTOR_XOR;
-        }else if( k==BITVECTOR_XOR ) {
-          rt.d_req_kind = BITVECTOR_XNOR;
-        }
-      }else if( pk==UMINUS ){
-        if( k==PLUS ){
-          rt.d_req_kind = PLUS;reqk = UMINUS;
-        }
-      }else if( pk==BITVECTOR_NEG ){
-        if( k==PLUS ){
-          rt.d_req_kind = PLUS;reqk = BITVECTOR_NEG;
-        }
-      }
-      if( !rt.empty() && ( reqk!=UNDEFINED_KIND || !reqkc.empty() ) ){
-        int pcr = getKindConsNum( tnp, rt.d_req_kind );
-        if( pcr!=-1 ){
-          Assert( pcr<(int)pdt.getNumConstructors() );
-          //must have same number of arguments
-          if( pdt[pcr].getNumArgs()==dt[c].getNumArgs() ){
-            for( unsigned i=0; i<pdt[pcr].getNumArgs(); i++ ){
-              Kind rk = reqk;
-              if( reqk==UNDEFINED_KIND ){
-                std::map< unsigned, Kind >::iterator itr = reqkc.find( i );
-                if( itr!=reqkc.end() ){
-                  rk = itr->second;
-                }
-              }
-              if( rk!=UNDEFINED_KIND ){
-                rt.d_children[i].d_req_kind = rk;
-                rt.d_children[i].d_children[0].d_req_type = getArgType( dt[c], i );
-              }
-            }
-          }
-        }
-      }
-    }
-  }else if( k==MINUS || k==BITVECTOR_SUB ){
-    if( pk==EQUAL || 
-        pk==MINUS || pk==BITVECTOR_SUB || 
-        pk==LEQ || pk==LT || pk==GEQ || pk==GT ){
-      int oarg = arg==0 ? 1 : 0;
-      //  (~ x (- y z))  ---->  (~ (+ x z) y)
-      //  (~ (- y z) x)  ---->  (~ y (+ x z))
-      rt.d_req_kind = pk;
-      rt.d_children[arg].d_req_type = getArgType( dt[c], 0 );
-      rt.d_children[oarg].d_req_kind = k==MINUS ? PLUS : BITVECTOR_PLUS;
-      rt.d_children[oarg].d_children[0].d_req_type = getArgType( pdt[pc], oarg );
-      rt.d_children[oarg].d_children[1].d_req_type = getArgType( dt[c], 1 );
-    }else if( pk==PLUS || pk==BITVECTOR_PLUS ){
-      //  (+ x (- y z))  -----> (- (+ x y) z)
-      //  (+ (- y z) x)  -----> (- (+ x y) z)
-      rt.d_req_kind = pk==PLUS ? MINUS : BITVECTOR_SUB;
-      int oarg = arg==0 ? 1 : 0;
-      rt.d_children[0].d_req_kind = pk;
-      rt.d_children[0].d_children[0].d_req_type = getArgType( pdt[pc], oarg );
-      rt.d_children[0].d_children[1].d_req_type = getArgType( dt[c], 0 );
-      rt.d_children[1].d_req_type = getArgType( dt[c], 1 );
-      // TODO : this is subsumbed by solving for MINUS
-    }
-  }else if( k==ITE ){
-    if( pk!=ITE ){
-      //  (o X (ite y z w) X')  -----> (ite y (o X z X') (o X w X'))
-      rt.d_req_kind = ITE;
-      rt.d_children[0].d_req_type = getArgType( dt[c], 0 );
-      unsigned n_args = pdt[pc].getNumArgs();
-      for( unsigned r=1; r<=2; r++ ){
-        rt.d_children[r].d_req_kind = pk;
-        for( unsigned q=0; q<n_args; q++ ){
-          if( (int)q==arg ){
-            rt.d_children[r].d_children[q].d_req_type = getArgType( dt[c], r );
-          }else{
-            rt.d_children[r].d_children[q].d_req_type = getArgType( pdt[pc], q );
-          }
-        }
-      }
-      //TODO: this increases term size but is probably a good idea
-    }
-  }else if( k==NOT ){
-    if( pk==ITE ){
-      //  (ite (not y) z w)  -----> (ite y w z)
-      rt.d_req_kind = ITE;
-      rt.d_children[0].d_req_type = getArgType( dt[c], 0 );
-      rt.d_children[1].d_req_type = getArgType( pdt[pc], 2 );
-      rt.d_children[2].d_req_type = getArgType( pdt[pc], 1 );
-    }
-  }
-  Trace("sygus-sb-debug") << "Consider sygus arg kind " << k << ", pk = " << pk << ", arg = " << arg << "?" << std::endl;
-  if( !rt.empty() ){
-    rt.print("sygus-sb-debug");
-    //check if it meets the requirements
-    if( rt.satisfiedBy( this, tnp ) ){
-      Trace("sygus-sb-debug") << "...success!" << std::endl;
-      Trace("sygus-sb-simple") << "  sb-simple : do not consider " << k << " as arg " << arg << " of " << pk << std::endl;
-      //do not need to consider the kind in the search since there are ways to construct equivalent terms
-      return false;
-    }else{
-      Trace("sygus-sb-debug") << "...failed." << std::endl;
-    }
-    Trace("sygus-sb-debug") << std::endl;
-  }
-  //must consider this kind in the search  
-  return true;
-}
-
-bool TermDbSygus::considerConst( TypeNode tn, TypeNode tnp, Node c, Kind pk, int arg ) {
-  const Datatype& pdt = ((DatatypeType)(tnp).toType()).getDatatype();
-  // child grammar-independent
-  if( !considerConst( pdt, tnp, c, pk, arg ) ){
-    return false;
-  }
-  // TODO : this can probably be made child grammar independent
-  int pc = getKindConsNum( tnp, pk );
-  if( pdt[pc].getNumArgs()==2 ){
-    Kind ok;
-    int offset;
-    if (d_quantEngine->getTermUtil()->hasOffsetArg(pk, arg, offset, ok))
-    {
-      Trace("sygus-sb-simple-debug") << pk << " has offset arg " << ok << " " << offset << std::endl;
-      int ok_arg = getKindConsNum( tnp, ok );
-      if( ok_arg!=-1 ){
-        Trace("sygus-sb-simple-debug") << "...at argument " << ok_arg << std::endl;
-        //other operator be the same type
-        if( isTypeMatch( pdt[ok_arg], pdt[arg] ) ){
-          int status;
-          Node co = d_quantEngine->getTermUtil()->getTypeValueOffset(
-              c.getType(), c, offset, status);
-          Trace("sygus-sb-simple-debug") << c << " with offset " << offset << " is " << co << ", status=" << status << std::endl;
-          if( status==0 && !co.isNull() ){
-            if( hasConst( tn, co ) ){
-              Trace("sygus-sb-simple") << "  sb-simple : by offset reasoning, do not consider const " << c;
-              Trace("sygus-sb-simple") << " as arg " << arg << " of " << pk << " since we can use " << co << " under " << ok << " " << std::endl;
-              return false;
-            }
-          }
-        }
-      }
-    }
-  }
-  return true;
-}
-
-bool TermDbSygus::considerConst( const Datatype& pdt, TypeNode tnp, Node c, Kind pk, int arg ) {
-  Assert( hasKind( tnp, pk ) );
-  int pc = getKindConsNum( tnp, pk );
-  bool ret = true;
-  Trace("sygus-sb-debug") << "Consider sygus const " << c << ", parent = " << pk << ", arg = " << arg << "?" << std::endl;
-  if (d_quantEngine->getTermUtil()->isIdempotentArg(c, pk, arg))
-  {
-    if( pdt[pc].getNumArgs()==2 ){
-      int oarg = arg==0 ? 1 : 0;
-      TypeNode otn = TypeNode::fromType( ((SelectorType)pdt[pc][oarg].getType()).getRangeType() );
-      if( otn==tnp ){
-        Trace("sygus-sb-simple") << "  sb-simple : " << c << " is idempotent arg " << arg << " of " << pk << "..." << std::endl;
-        ret = false;
-      }
-    }
-  }else{
-    Node sc = d_quantEngine->getTermUtil()->isSingularArg(c, pk, arg);
-    if( !sc.isNull() ){
-      if( hasConst( tnp, sc ) ){
-        Trace("sygus-sb-simple") << "  sb-simple : " << c << " is singular arg " << arg << " of " << pk << ", evaluating to " << sc << "..." << std::endl;
-        ret = false;
-      }
-    }
-  }
-  if( ret ){
-    ReqTrie rt;
-    Assert( rt.empty() );
-    Node max_c = d_quantEngine->getTermUtil()->getTypeMaxValue(c.getType());
-    Node zero_c = d_quantEngine->getTermUtil()->getTypeValue(c.getType(), 0);
-    Node one_c = d_quantEngine->getTermUtil()->getTypeValue(c.getType(), 1);
-    if( pk==XOR || pk==BITVECTOR_XOR ){
-      if( c==max_c ){
-        rt.d_req_kind = pk==XOR ? NOT : BITVECTOR_NOT;
-      }
-    }else if( pk==ITE ){
-      if( arg==0 ){
-        if( c==max_c ){
-          rt.d_children[2].d_req_type = tnp;
-        }else if( c==zero_c ){
-          rt.d_children[1].d_req_type = tnp;
-        }
-      }
-    }else if( pk==STRING_SUBSTR ){
-      if( c==one_c ){
-        rt.d_req_kind = STRING_CHARAT;
-        rt.d_children[0].d_req_type = getArgType( pdt[pc], 0 );
-        rt.d_children[1].d_req_type = getArgType( pdt[pc], 1 );
-      }
-    }
-    if( !rt.empty() ){
-      //check if satisfied
-      if( rt.satisfiedBy( this, tnp ) ){
-        Trace("sygus-sb-simple") << "  sb-simple : do not consider const " << c << " as arg " << arg << " of " << pk;
-        Trace("sygus-sb-simple") << " in " << ((DatatypeType)tnp.toType()).getDatatype().getName() << std::endl;
-        //do not need to consider the constant in the search since there are ways to construct equivalent terms
-        ret = false;
-      }
-    }
-  }
-  // TODO : cache?
-  return ret;
-}
-
-int TermDbSygus::solveForArgument( TypeNode tn, unsigned cindex, unsigned arg ) {
-  // FIXME
-  return -1;  // TODO : if using, modify considerArgKind above
-  Assert( isRegistered( tn ) );
-  const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-  Assert( cindex<dt.getNumConstructors() );
-  Assert( arg<dt[cindex].getNumArgs() );
-  Kind nk = getConsNumKind( tn, cindex );
-  TypeNode tnc = getArgType( dt[cindex], arg );
-  const Datatype& cdt = ((DatatypeType)(tnc).toType()).getDatatype();
-
-  ReqTrie rt;
-  Assert( rt.empty() );
-  int solve_ret = -1;
-  if( nk==MINUS || nk==BITVECTOR_SUB ){
-    if( dt[cindex].getNumArgs()==2 && arg==0 ){
-      TypeNode tnco = getArgType( dt[cindex], 1 );
-      Node builtin = d_quantEngine->getTermUtil()->getTypeValue(
-          sygusToBuiltinType(tnc), 0);
-      solve_ret = getConstConsNum( tn, builtin );
-      if( solve_ret!=-1 ){
-        // t - s    ----->  ( 0 - s ) + t
-        rt.d_req_kind = nk == MINUS ? PLUS : BITVECTOR_PLUS;
-        rt.d_children[0].d_req_type = tn; // avoid?
-        rt.d_children[0].d_req_kind = nk;
-        rt.d_children[0].d_children[0].d_req_const = builtin;
-        rt.d_children[0].d_children[0].d_req_type = tnco;
-        rt.d_children[1].d_req_type = tnc;
-        // TODO : this can be made more general for multiple type grammars to remove MINUS entirely 
-      }
-    }
-  }
-  
-  if( !rt.empty() ){
-    Assert( solve_ret>=0 );
-    Assert( solve_ret<=(int)cdt.getNumConstructors() );
-    //check if satisfied
-    if( rt.satisfiedBy( this, tn ) ){
-      Trace("sygus-sb-simple") << "  sb-simple : ONLY consider " << cdt[solve_ret].getSygusOp() << " as arg " << arg << " of " << nk;
-      Trace("sygus-sb-simple") << " in " << ((DatatypeType)tn.toType()).getDatatype().getName() << std::endl;
-      return solve_ret;
-    }
-  }
-  
-  return -1;
-}
-
-void TermDbSygus::registerSygusType( TypeNode tn ) {
-  std::map< TypeNode, TypeNode >::iterator itr = d_register.find( tn );
-  if( itr==d_register.end() ){
-    d_register[tn] = TypeNode::null();
-    if( tn.isDatatype() ){
-      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-      Trace("sygus-db") << "Register type " << dt.getName() << "..." << std::endl;
-      TypeNode btn = TypeNode::fromType( dt.getSygusType() );
-      d_register[tn] = btn;
-      if( !d_register[tn].isNull() ){
-        // get the sygus variable list
-        Node var_list = Node::fromExpr( dt.getSygusVarList() );
-        if( !var_list.isNull() ){
-          for( unsigned j=0; j<var_list.getNumChildren(); j++ ){
-            Node sv = var_list[j];
-            SygusVarNumAttribute svna;
-            sv.setAttribute( svna, j );
-            d_var_list[tn].push_back( sv );
-          }
-        }else{
-          // no arguments to synthesis functions
-        }
-        //iterate over constructors
-        for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-          Expr sop = dt[i].getSygusOp();
-          Assert( !sop.isNull() );
-          Node n = Node::fromExpr( sop );
-          Trace("sygus-db") << "  Operator #" << i << " : " << sop;
-          if( sop.getKind() == kind::BUILTIN ){
-            Kind sk = NodeManager::operatorToKind( n );
-            Trace("sygus-db") << ", kind = " << sk;
-            d_kinds[tn][sk] = i;
-            d_arg_kind[tn][i] = sk;
-          }else if( sop.isConst() ){
-            Trace("sygus-db") << ", constant";
-            d_consts[tn][n] = i;
-            d_arg_const[tn][i] = n;
-          }
-          d_ops[tn][n] = i;
-          d_arg_ops[tn][i] = n;
-          Trace("sygus-db") << std::endl;
-        }
-        //register connected types
-        for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-          for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
-            registerSygusType( getArgType( dt[i], j ) );
-          }
-        }
-      }
-    }
-  }
-}
-
-void TermDbSygus::registerEnumerator(Node e,
-                                     Node f,
-                                     CegConjecture* conj,
-                                     bool mkActiveGuard)
-{
-  Assert(d_enum_to_conjecture.find(e) == d_enum_to_conjecture.end());
-  Trace("sygus-db") << "Register measured term : " << e << std::endl;
-  d_enum_to_conjecture[e] = conj;
-  d_enum_to_synth_fun[e] = f;
-  if( mkActiveGuard ){
-    // make the guard
-    Node eg = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "eG", NodeManager::currentNM()->booleanType() ) );
-    eg = d_quantEngine->getValuation().ensureLiteral( eg );
-    AlwaysAssert( !eg.isNull() );
-    d_quantEngine->getOutputChannel().requirePhase( eg, true );
-    //add immediate lemma
-    Node lem = NodeManager::currentNM()->mkNode( OR, eg, eg.negate() );
-    Trace("cegqi-lemma") << "Cegqi::Lemma : enumerator : " << lem << std::endl;
-    d_quantEngine->getOutputChannel().lemma( lem );
-    d_enum_to_active_guard[e] = eg;
-  }
-}
-
-bool TermDbSygus::isEnumerator(Node e) const
-{
-  return d_enum_to_conjecture.find(e) != d_enum_to_conjecture.end();
-}
-
-CegConjecture* TermDbSygus::getConjectureForEnumerator(Node e)
-{
-  std::map<Node, CegConjecture*>::iterator itm = d_enum_to_conjecture.find(e);
-  if (itm != d_enum_to_conjecture.end()) {
-    return itm->second;
-  }else{
-    return NULL;
-  }
-}
-
-Node TermDbSygus::getSynthFunForEnumerator(Node e)
-{
-  std::map<Node, Node>::iterator itsf = d_enum_to_synth_fun.find(e);
-  if (itsf != d_enum_to_synth_fun.end())
-  {
-    return itsf->second;
-  }
-  else
-  {
-    return Node::null();
-  }
-}
-
-Node TermDbSygus::getActiveGuardForEnumerator(Node e)
-{
-  std::map<Node, Node>::iterator itag = d_enum_to_active_guard.find(e);
-  if (itag != d_enum_to_active_guard.end()) {
-    return itag->second;
-  }else{
-    return Node::null();
-  }
-}
-
-void TermDbSygus::getEnumerators(std::vector<Node>& mts)
-{
-  for (std::map<Node, CegConjecture*>::iterator itm =
-           d_enum_to_conjecture.begin();
-       itm != d_enum_to_conjecture.end(); ++itm) {
-    mts.push_back( itm->first );
-  }
-}
-
-bool TermDbSygus::isRegistered( TypeNode tn ) {
-  return d_register.find( tn )!=d_register.end();
-}
-
-TypeNode TermDbSygus::sygusToBuiltinType( TypeNode tn ) {
-  Assert( isRegistered( tn ) );
-  return d_register[tn];
-}
-
-void TermDbSygus::computeMinTypeDepthInternal( TypeNode root_tn, TypeNode tn, unsigned type_depth ) {
-  std::map< TypeNode, unsigned >::iterator it = d_min_type_depth[root_tn].find( tn );
-  if( it==d_min_type_depth[root_tn].end() || type_depth<it->second ){
-    d_min_type_depth[root_tn][tn] = type_depth;
-    Assert( tn.isDatatype() );
-    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-    //compute for connected types
-    for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-      for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
-        computeMinTypeDepthInternal( root_tn, getArgType( dt[i], j ), type_depth+1 );
-      }
-    }
-  }
-}
-  
-unsigned TermDbSygus::getMinTypeDepth( TypeNode root_tn, TypeNode tn ){
-  std::map< TypeNode, unsigned >::iterator it = d_min_type_depth[root_tn].find( tn );
-  if( it==d_min_type_depth[root_tn].end() ){
-    computeMinTypeDepthInternal( root_tn, root_tn, 0 );
-    Assert( d_min_type_depth[root_tn].find( tn )!=d_min_type_depth[root_tn].end() );  
-    return d_min_type_depth[root_tn][tn];
-  }else{
-    return it->second;
-  }
-}
-
-unsigned TermDbSygus::getMinTermSize( TypeNode tn ) {
-  Assert( isRegistered( tn ) );
-  std::map< TypeNode, unsigned >::iterator it = d_min_term_size.find( tn );
-  if( it==d_min_term_size.end() ){
-    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-    for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-      if (dt[i].getNumArgs() == 0)
-      {
-        d_min_term_size[tn] = 0;
-        return 0;
-      }
-    }
-    // TODO : improve
-    d_min_term_size[tn] = 1;
-    return 1;
-  }else{
-    return it->second;
-  }
-}
-
-unsigned TermDbSygus::getMinConsTermSize( TypeNode tn, unsigned cindex ) {
-  Assert( isRegistered( tn ) );
-  std::map< unsigned, unsigned >::iterator it = d_min_cons_term_size[tn].find( cindex );
-  if( it==d_min_cons_term_size[tn].end() ){
-    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-    Assert( cindex<dt.getNumConstructors() );
-    unsigned ret = 0;
-    if( dt[cindex].getNumArgs()>0 ){
-      ret = 1;
-      for( unsigned i=0; i<dt[cindex].getNumArgs(); i++ ){
-        ret += getMinTermSize( getArgType( dt[cindex], i ) );
-      }
-    }
-    d_min_cons_term_size[tn][cindex] = ret;
-    return ret;
-  }else{
-    return it->second;
-  }
-}
-
-unsigned TermDbSygus::getSelectorWeight(TypeNode tn, Node sel)
-{
-  std::map<TypeNode, std::map<Node, unsigned> >::iterator itsw =
-      d_sel_weight.find(tn);
-  if (itsw == d_sel_weight.end())
-  {
-    d_sel_weight[tn].clear();
-    itsw = d_sel_weight.find(tn);
-    Type t = tn.toType();
-    const Datatype& dt = static_cast<DatatypeType>(t).getDatatype();
-    Trace("sygus-db") << "Compute selector weights for " << dt.getName()
-                      << std::endl;
-    for (unsigned i = 0, size = dt.getNumConstructors(); i < size; i++)
-    {
-      unsigned cw = dt[i].getWeight();
-      for (unsigned j = 0, size2 = dt[i].getNumArgs(); j < size2; j++)
-      {
-        Node csel = Node::fromExpr(dt[i].getSelectorInternal(t, j));
-        std::map<Node, unsigned>::iterator its = itsw->second.find(csel);
-        if (its == itsw->second.end() || cw < its->second)
-        {
-          d_sel_weight[tn][csel] = cw;
-          Trace("sygus-db") << "  w(" << csel << ") <= " << cw << std::endl;
-        }
-      }
-    }
-  }
-  Assert(itsw->second.find(sel) != itsw->second.end());
-  return itsw->second[sel];
-}
-
-int TermDbSygus::getKindConsNum( TypeNode tn, Kind k ) {
-  Assert( isRegistered( tn ) );
-  std::map< TypeNode, std::map< Kind, int > >::iterator itt = d_kinds.find( tn );
-  if( itt!=d_kinds.end() ){
-    std::map< Kind, int >::iterator it = itt->second.find( k );
-    if( it!=itt->second.end() ){
-      return it->second;
-    }
-  }
-  return -1;
-}
-
-int TermDbSygus::getConstConsNum( TypeNode tn, Node n ){
-  Assert( isRegistered( tn ) );
-  std::map< TypeNode, std::map< Node, int > >::iterator itt = d_consts.find( tn );
-  if( itt!=d_consts.end() ){
-    std::map< Node, int >::iterator it = itt->second.find( n );
-    if( it!=itt->second.end() ){
-      return it->second;
-    }
-  }
-  return -1;
-}
-
-int TermDbSygus::getOpConsNum( TypeNode tn, Node n ) {
-  std::map< Node, int >::iterator it = d_ops[tn].find( n );
-  if( it!=d_ops[tn].end() ){
-    return it->second;
-  }else{
-    return -1;
-  }
-}
-
-bool TermDbSygus::hasKind( TypeNode tn, Kind k ) {
-  return getKindConsNum( tn, k )!=-1;
-}
-bool TermDbSygus::hasConst( TypeNode tn, Node n ) {
-  return getConstConsNum( tn, n )!=-1;
-}
-bool TermDbSygus::hasOp( TypeNode tn, Node n ) {
-  return getOpConsNum( tn, n )!=-1;
-}
-
-Node TermDbSygus::getConsNumOp( TypeNode tn, int i ) {
-  Assert( isRegistered( tn ) );
-  std::map< TypeNode, std::map< int, Node > >::iterator itt = d_arg_ops.find( tn );
-  if( itt!=d_arg_ops.end() ){
-    std::map< int, Node >::iterator itn = itt->second.find( i );
-    if( itn!=itt->second.end() ){
-      return itn->second;
-    }
-  }
-  return Node::null();
-}
-
-Node TermDbSygus::getConsNumConst( TypeNode tn, int i ) {
-  Assert( isRegistered( tn ) );
-  std::map< TypeNode, std::map< int, Node > >::iterator itt = d_arg_const.find( tn );
-  if( itt!=d_arg_const.end() ){
-    std::map< int, Node >::iterator itn = itt->second.find( i );
-    if( itn!=itt->second.end() ){
-      return itn->second;
-    }
-  }
-  return Node::null();
-}
-
-Kind TermDbSygus::getConsNumKind( TypeNode tn, int i ) {
-  Assert( isRegistered( tn ) );
-  std::map< TypeNode, std::map< int, Kind > >::iterator itt = d_arg_kind.find( tn );
-  if( itt!=d_arg_kind.end() ){
-    std::map< int, Kind >::iterator itk = itt->second.find( i );
-    if( itk!=itt->second.end() ){
-      return itk->second;
-    }
-  }
-  return UNDEFINED_KIND;
-}
-
-bool TermDbSygus::isKindArg( TypeNode tn, int i ) {
-  return getConsNumKind( tn, i )!=UNDEFINED_KIND;
-}
-
-bool TermDbSygus::isConstArg( TypeNode tn, int i ) {
-  Assert( isRegistered( tn ) );
-  std::map< TypeNode, std::map< int, Node > >::iterator itt = d_arg_const.find( tn );
-  if( itt!=d_arg_const.end() ){
-    return itt->second.find( i )!=itt->second.end();
-  }else{
-    return false;
-  }
-}
-
-TypeNode TermDbSygus::getArgType(const DatatypeConstructor& c, unsigned i)
-{
-  Assert(i < c.getNumArgs());
-  return TypeNode::fromType( ((SelectorType)c[i].getType()).getRangeType() );
-}
-
-/** get first occurrence */
-int TermDbSygus::getFirstArgOccurrence( const DatatypeConstructor& c, TypeNode tn ) {
-  for( unsigned i=0; i<c.getNumArgs(); i++ ){
-    TypeNode tni = getArgType( c, i );
-    if( tni==tn ){
-      return i;
-    }
-  }
-  return -1;
-}
-
-bool TermDbSygus::isTypeMatch( const DatatypeConstructor& c1, const DatatypeConstructor& c2 ) {
-  if( c1.getNumArgs()!=c2.getNumArgs() ){
-    return false;
-  }else{
-    for( unsigned i=0; i<c1.getNumArgs(); i++ ){
-      if( getArgType( c1, i )!=getArgType( c2, i ) ){
-        return false;
-      }
-    }
-    return true;
-  }
-}
-
-Node TermDbSygus::minimizeBuiltinTerm( Node n ) {
-  if( ( n.getKind()==EQUAL || n.getKind()==LEQ || n.getKind()==LT || n.getKind()==GEQ || n.getKind()==GT ) &&
-      ( n[0].getType().isInteger() || n[0].getType().isReal() ) ){
-    bool changed = false;
-    std::vector< Node > mon[2];
-    for( unsigned r=0; r<2; r++ ){
-      unsigned ro = r==0 ? 1 : 0;
-      Node c;
-      Node nc;
-      if( n[r].getKind()==PLUS ){
-        for( unsigned i=0; i<n[r].getNumChildren(); i++ ){
-          if (ArithMSum::getMonomial(n[r][i], c, nc)
-              && c.getConst<Rational>().isNegativeOne())
-          {
-            mon[ro].push_back( nc );
-            changed = true;
-          }else{
-            if( !n[r][i].isConst() || !n[r][i].getConst<Rational>().isZero() ){
-              mon[r].push_back( n[r][i] );
-            }
-          }
-        }
-      }else{
-        if (ArithMSum::getMonomial(n[r], c, nc)
-            && c.getConst<Rational>().isNegativeOne())
-        {
-          mon[ro].push_back( nc );
-          changed = true;
-        }else{
-          if( !n[r].isConst() || !n[r].getConst<Rational>().isZero() ){
-            mon[r].push_back( n[r] );
-          }
-        }
-      }
-    }
-    if( changed ){
-      Node nn[2];
-      for( unsigned r=0; r<2; r++ ){
-        nn[r] = mon[r].size()==0 ? NodeManager::currentNM()->mkConst( Rational(0) ) : ( mon[r].size()==1 ? mon[r][0] : NodeManager::currentNM()->mkNode( PLUS, mon[r] ) );
-      }
-      return NodeManager::currentNM()->mkNode( n.getKind(), nn[0], nn[1] );
-    }
-  }
-  return n;
-}
-
-Node TermDbSygus::expandBuiltinTerm( Node t ){
-  if( t.getKind()==EQUAL ){
-    if( t[0].getType().isReal() ){
-      return NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( LEQ, t[0], t[1] ),
-                                                    NodeManager::currentNM()->mkNode( LEQ, t[1], t[0] ) );
-    }else if( t[0].getType().isBoolean() ){
-      return NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, t[0], t[1] ),
-                                                   NodeManager::currentNM()->mkNode( AND, t[0].negate(), t[1].negate() ) );
-    }
-  }else if( t.getKind()==ITE && t.getType().isBoolean() ){
-    return NodeManager::currentNM()->mkNode( OR, NodeManager::currentNM()->mkNode( AND, t[0], t[1] ),
-                                                 NodeManager::currentNM()->mkNode( AND, t[0].negate(), t[2] ) );
-  }
-  return Node::null();
-}
-
-
-Kind TermDbSygus::getComparisonKind( TypeNode tn ) {
-  if( tn.isInteger() || tn.isReal() ){
-    return LT;
-  }else if( tn.isBitVector() ){
-    return BITVECTOR_ULT;
-  }else{
-    return UNDEFINED_KIND;
-  }
-}
-
-Kind TermDbSygus::getPlusKind( TypeNode tn, bool is_neg ) {
-  if( tn.isInteger() || tn.isReal() ){
-    return is_neg ? MINUS : PLUS;
-  }else if( tn.isBitVector() ){
-    return is_neg ? BITVECTOR_SUB : BITVECTOR_PLUS;
-  }else{
-    return UNDEFINED_KIND;
-  }
-}
-
-Node TermDbSygus::getSemanticSkolem( TypeNode tn, Node n, bool doMk ){
-  std::map< Node, Node >::iterator its = d_semantic_skolem[tn].find( n );
-  if( its!=d_semantic_skolem[tn].end() ){
-    return its->second;
-  }else if( doMk ){
-    Node ss = NodeManager::currentNM()->mkSkolem( "sem", tn, "semantic skolem for sygus" );
-    d_semantic_skolem[tn][n] = ss;
-    return ss;
-  }else{
-    return Node::null();
-  }
-}
-
-bool TermDbSygus::involvesDivByZero( Node n, std::map< Node, bool >& visited ){
-  if( visited.find( n )==visited.end() ){
-    visited[n] = true;
-    Kind k = n.getKind();
-    if( k==DIVISION || k==DIVISION_TOTAL || k==INTS_DIVISION || k==INTS_DIVISION_TOTAL || 
-        k==INTS_MODULUS || k==INTS_MODULUS_TOTAL ){
-      if( n[1].isConst() ){
-        if (n[1]
-            == d_quantEngine->getTermUtil()->getTypeValue(n[1].getType(), 0))
-        {
-          return true;
-        }
-      }else{
-        // if it has free variables it might be a non-zero constant
-        if( !hasFreeVar( n[1] ) ){
-          return true;
-        }
-      }
-    }
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      if( involvesDivByZero( n[i], visited ) ){
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
-bool TermDbSygus::involvesDivByZero( Node n ) {
-  std::map< Node, bool > visited;
-  return involvesDivByZero( n, visited );
-}
-
-void doStrReplace(std::string& str, const std::string& oldStr, const std::string& newStr){
-  size_t pos = 0;
-  while((pos = str.find(oldStr, pos)) != std::string::npos){
-     str.replace(pos, oldStr.length(), newStr);
-     pos += newStr.length();
-  }
-}
-
-Kind TermDbSygus::getOperatorKind( Node op ) {
-  Assert( op.getKind()!=BUILTIN );
-  if (op.getKind() == LAMBDA)
-  {
-    // we use APPLY_UF instead of APPLY, since the rewriter for APPLY_UF
-    // does beta-reduction but does not for APPLY
-    return APPLY_UF;
-  }else{
-    TypeNode tn = op.getType();
-    if( tn.isConstructor() ){
-      return APPLY_CONSTRUCTOR;
-    }
-    else if (tn.isSelector())
-    {
-      return APPLY_SELECTOR;
-    }
-    else if (tn.isTester())
-    {
-      return APPLY_TESTER;
-    }
-    else if (tn.isFunction())
-    {
-      return APPLY_UF;
-    }
-    return NodeManager::operatorToKind(op);
-  }
-}
-
-Node TermDbSygus::getAnchor( Node n ) {
-  if( n.getKind()==APPLY_SELECTOR_TOTAL ){
-    return getAnchor( n[0] );
-  }else{
-    return n;
-  }
-}
-
-unsigned TermDbSygus::getAnchorDepth( Node n ) {
-  if( n.getKind()==APPLY_SELECTOR_TOTAL ){
-    return 1+getAnchorDepth( n[0] );
-  }else{
-    return 0;
-  }
-}
-
-
-void TermDbSygus::registerEvalTerm( Node n ) {
-  if( options::sygusDirectEval() ){
-    if( n.getKind()==APPLY_UF && !n.getType().isBoolean() ){
-      TypeNode tn = n[0].getType();
-      if( tn.isDatatype() ){
-        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-        if( dt.isSygus() ){
-          Node f = n.getOperator();
-          if( n[0].getKind()!=APPLY_CONSTRUCTOR ){
-            if (d_eval_processed.find(n) == d_eval_processed.end())
-            {
-              Trace("sygus-eager")
-                  << "TermDbSygus::eager: Register eval term : " << n
-                  << std::endl;
-              d_eval_processed.insert(n);
-              d_evals[n[0]].push_back(n);
-              TypeNode tn = n[0].getType();
-              Assert(tn.isDatatype());
-              const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-              Node var_list = Node::fromExpr(dt.getSygusVarList());
-              Assert(dt.isSygus());
-              d_eval_args[n[0]].push_back(std::vector<Node>());
-              bool isConst = true;
-              for (unsigned j = 1; j < n.getNumChildren(); j++)
-              {
-                d_eval_args[n[0]].back().push_back(n[j]);
-                if (!n[j].isConst())
-                {
-                  isConst = false;
-                }
-              }
-              d_eval_args_const[n[0]].push_back(isConst);
-              Node a = getAnchor(n[0]);
-              d_subterms[a][n[0]] = true;
-            }
-          }
-        }
-      }    
-    }
-  }
-}
-
-void TermDbSygus::registerModelValue( Node a, Node v, std::vector< Node >& terms, std::vector< Node >& vals, std::vector< Node >& exps ) {
-  std::map< Node, std::map< Node, bool > >::iterator its = d_subterms.find( a );
-  if( its!=d_subterms.end() ){
-    Trace("sygus-eager") << "registerModelValue : " << a << ", has " << its->second.size() << " registered subterms." << std::endl;
-    for( std::map< Node, bool >::iterator itss = its->second.begin(); itss != its->second.end(); ++itss ){
-      Node n = itss->first;
-      Trace("sygus-eager-debug") << "...process : " << n << std::endl;
-      std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_eval_args.find( n );
-      if( it!=d_eval_args.end() && !it->second.empty() ){
-        TNode at = a;
-        TNode vt = v;
-        Node vn = n.substitute( at, vt );
-        vn = Rewriter::rewrite( vn );
-        unsigned start = d_node_mv_args_proc[n][vn];
-        // get explanation in terms of testers
-        std::vector< Node > antec_exp;
-        d_syexp->getExplanationForConstantEquality(n, vn, antec_exp);
-        Node antec = antec_exp.size()==1 ? antec_exp[0] : NodeManager::currentNM()->mkNode( kind::AND, antec_exp );
-        //Node antec = n.eqNode( vn );
-        TypeNode tn = n.getType();
-        Assert( tn.isDatatype() );
-        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-        Assert( dt.isSygus() );
-        Trace("sygus-eager") << "TermDbSygus::eager: Register model value : " << vn << " for " << n << std::endl;
-        Trace("sygus-eager") << "...it has " << it->second.size() << " evaluations, already processed " << start << "." << std::endl;
-        Node bTerm = sygusToBuiltin( vn, tn );
-        Trace("sygus-eager") << "Built-in term : " << bTerm << std::endl;
-        std::vector< Node > vars;
-        Node var_list = Node::fromExpr( dt.getSygusVarList() );
-        for( unsigned j=0; j<var_list.getNumChildren(); j++ ){
-          vars.push_back( var_list[j] );
-        }
-        //evaluation children
-        std::vector< Node > eval_children;
-        eval_children.push_back( Node::fromExpr( dt.getSygusEvaluationFunc() ) );
-        eval_children.push_back( n );
-        //for each evaluation
-        for( unsigned i=start; i<it->second.size(); i++ ){
-          Node res;
-          Node expn;
-          // unfold?
-          bool do_unfold = false;
-          if( options::sygusUnfoldBool() ){
-            if( bTerm.getKind()==ITE || bTerm.getType().isBoolean() ){
-              do_unfold = true;
-            }
-          }
-          if( do_unfold ){
-            // TODO : this is replicated for different values, possibly do better caching
-            std::map< Node, Node > vtm; 
-            std::vector< Node > exp;
-            vtm[n] = vn;
-            eval_children.insert( eval_children.end(), it->second[i].begin(), it->second[i].end() );
-            Node eval_fun = NodeManager::currentNM()->mkNode( kind::APPLY_UF, eval_children );
-            eval_children.resize( 2 );  
-            res = unfold( eval_fun, vtm, exp );
-            expn = exp.size()==1 ? exp[0] : NodeManager::currentNM()->mkNode( kind::AND, exp );
-          }else{
-
-            EvalSygusInvarianceTest esit;
-            eval_children.insert( eval_children.end(), it->second[i].begin(), it->second[i].end() );
-            Node conj =
-                NodeManager::currentNM()->mkNode(kind::APPLY_UF, eval_children);
-            eval_children[1] = vn;
-            Node eval_fun = NodeManager::currentNM()->mkNode( kind::APPLY_UF, eval_children );
-            res = evaluateWithUnfolding(eval_fun);
-            esit.init(conj, n, res);
-            eval_children.resize( 2 );  
-            eval_children[1] = n;
-            
-            //evaluate with minimal explanation
-            std::vector< Node > mexp;
-            d_syexp->getExplanationFor(n, vn, mexp, esit);
-            Assert( !mexp.empty() );
-            expn = mexp.size()==1 ? mexp[0] : NodeManager::currentNM()->mkNode( kind::AND, mexp );
-            
-            //if all constant, we can use evaluation to minimize the explanation
-            //Assert( i<d_eval_args_const[n].size() );
-            //if( d_eval_args_const[n][i] ){
-              /*
-              std::map< Node, Node > vtm; 
-              std::map< Node, Node > visited; 
-              std::map< Node, std::vector< Node > > exp;
-              vtm[n] = vn;
-              res = crefEvaluate( eval_fun, vtm, visited, exp );
-              Assert( !exp[eval_fun].empty() );
-              expn = exp[eval_fun].size()==1 ? exp[eval_fun][0] : NodeManager::currentNM()->mkNode( kind::AND, exp[eval_fun] );
-              */
-              /*
-            //otherwise, just do a substitution
-            }else{
-              Assert( vars.size()==it->second[i].size() );
-              res = bTerm.substitute( vars.begin(), vars.end(), it->second[i].begin(), it->second[i].end() );
-              res = Rewriter::rewrite( res );
-              expn = antec;
-            }
-            */
-          }
-          Assert( !res.isNull() );
-          terms.push_back( d_evals[n][i] );
-          vals.push_back( res );
-          exps.push_back( expn );
-          Trace("sygus-eager") << "Conclude : " << d_evals[n][i] << " == " << res << ", cref eval = " << d_eval_args_const[n][i] << std::endl;
-          Trace("sygus-eager") << "   from " << expn << std::endl;
-        }
-        d_node_mv_args_proc[n][vn] = it->second.size();
-      }
-    }
-  }
-}
-
-Node TermDbSygus::unfold( Node en, std::map< Node, Node >& vtm, std::vector< Node >& exp, bool track_exp ) {
-  if( en.getKind()==kind::APPLY_UF ){
-    Trace("sygus-db-debug") << "Unfold : " << en << std::endl;
-    Node ev = en[0];
-    if( track_exp ){
-      std::map< Node, Node >::iterator itv = vtm.find( en[0] );
-      if( itv!=vtm.end() ){
-        ev = itv->second;
-      }else{
-        Assert( false );
-      }
-      Assert( en[0].getType()==ev.getType() );
-      Assert( ev.isConst() );
-    }
-    Assert( ev.getKind()==kind::APPLY_CONSTRUCTOR );
-    std::vector< Node > args;
-    for( unsigned i=1; i<en.getNumChildren(); i++ ){
-      args.push_back( en[i] );
-    }
-    const Datatype& dt = ((DatatypeType)(ev.getType()).toType()).getDatatype();
-    unsigned i = Datatype::indexOf( ev.getOperator().toExpr() );
-    if( track_exp ){
-      //explanation
-      Node ee = NodeManager::currentNM()->mkNode( kind::APPLY_TESTER, Node::fromExpr( dt[i].getTester() ), en[0] );
-      if( std::find( exp.begin(), exp.end(), ee )==exp.end() ){
-        exp.push_back( ee );
-      }
-    }
-    Assert( !dt.isParametric() );
-    std::map< int, Node > pre;
-    for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
-      std::vector< Node > cc;
-      //get the evaluation argument for the selector
-      Type rt = dt[i][j].getRangeType();
-      const Datatype & ad = ((DatatypeType)dt[i][j].getRangeType()).getDatatype();
-      cc.push_back( Node::fromExpr( ad.getSygusEvaluationFunc() ) );
-      Node s;
-      if( en[0].getKind()==kind::APPLY_CONSTRUCTOR ){
-        s = en[0][j];
-      }else{
-        s = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, dt[i].getSelectorInternal( en[0].getType().toType(), j ), en[0] );
-      }
-      cc.push_back( s );
-      if( track_exp ){
-        //update vtm map
-        vtm[s] = ev[j];
-      }
-      cc.insert( cc.end(), args.begin(), args.end() );
-      pre[j] = NodeManager::currentNM()->mkNode( kind::APPLY_UF, cc );
-    }
-    std::map< TypeNode, int > var_count; 
-    Node ret = mkGeneric( dt, i, var_count, pre );
-    // if it is a variable, apply the substitution
-    if( ret.getKind()==kind::BOUND_VARIABLE ){
-      Assert( ret.hasAttribute(SygusVarNumAttribute()) );
-      int i = ret.getAttribute(SygusVarNumAttribute());
-      Assert( Node::fromExpr( dt.getSygusVarList() )[i]==ret );
-      ret = args[i];
-    }
-    else
-    {
-      ret = Rewriter::rewrite(ret);
-    }
-    return ret;
-  }else{
-    Assert( en.isConst() );
-  }
-  return en;
-}
-
-
-Node TermDbSygus::getEagerUnfold( Node n, std::map< Node, Node >& visited ) {
-  std::map< Node, Node >::iterator itv = visited.find( n );
-  if( itv==visited.end() ){
-    Trace("cegqi-eager-debug") << "getEagerUnfold " << n << std::endl;
-    Node ret;
-    if( n.getKind()==APPLY_UF ){
-      TypeNode tn = n[0].getType();
-      Trace("cegqi-eager-debug") << "check " << n[0].getType() << std::endl;
-      if( tn.isDatatype() ){
-        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-        if( dt.isSygus() ){ 
-          Trace("cegqi-eager") << "Unfold eager : " << n << std::endl;
-          Node bTerm = sygusToBuiltin( n[0], tn );
-          Trace("cegqi-eager") << "Built-in term : " << bTerm << std::endl;
-          std::vector< Node > vars;
-          std::vector< Node > subs;
-          Node var_list = Node::fromExpr( dt.getSygusVarList() );
-          Assert( var_list.getNumChildren()+1==n.getNumChildren() );
-          for( unsigned j=0; j<var_list.getNumChildren(); j++ ){
-            vars.push_back( var_list[j] );
-          }
-          for( unsigned j=1; j<n.getNumChildren(); j++ ){
-            Node nc = getEagerUnfold( n[j], visited );
-            subs.push_back( nc );
-            Assert(subs[j - 1].getType().isComparableTo(
-                var_list[j - 1].getType()));
-          }
-          Assert( vars.size()==subs.size() );
-          bTerm = bTerm.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
-          Trace("cegqi-eager") << "Built-in term after subs : " << bTerm << std::endl;
-          Trace("cegqi-eager-debug") << "Types : " << bTerm.getType() << " " << n.getType() << std::endl;
-          Assert(n.getType().isComparableTo(bTerm.getType()));
-          ret = bTerm; 
-        }
-      }
-    }
-    if( ret.isNull() ){
-      if( n.getKind()!=FORALL ){
-        bool childChanged = false;
-        std::vector< Node > children;
-        for( unsigned i=0; i<n.getNumChildren(); i++ ){
-          Node nc = getEagerUnfold( n[i], visited );
-          childChanged = childChanged || n[i]!=nc;
-          children.push_back( nc );
-        }
-        if( childChanged ){
-          if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
-            children.insert( children.begin(), n.getOperator() );
-          }
-          ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
-        }
-      }
-      if( ret.isNull() ){
-        ret = n;
-      }
-    }
-    visited[n] = ret;
-    return ret;
-  }else{
-    return itv->second;
-  }
-}
-
-
-Node TermDbSygus::evaluateBuiltin( TypeNode tn, Node bn, std::vector< Node >& args ) {
-  if( !args.empty() ){
-    std::map< TypeNode, std::vector< Node > >::iterator it = d_var_list.find( tn );
-    Assert( it!=d_var_list.end() );
-    Assert( it->second.size()==args.size() );
-    return Rewriter::rewrite( bn.substitute( it->second.begin(), it->second.end(), args.begin(), args.end() ) );
-  }else{
-    return Rewriter::rewrite( bn );
-  }
-}
-
-Node TermDbSygus::evaluateWithUnfolding(
-    Node n, std::unordered_map<Node, Node, NodeHashFunction>& visited)
-{
-  std::unordered_map<Node, Node, NodeHashFunction>::iterator it =
-      visited.find(n);
-  if( it==visited.end() ){
-    Node ret = n;
-    while( ret.getKind()==APPLY_UF && ret[0].getKind()==APPLY_CONSTRUCTOR ){
-      ret = unfold( ret );
-    }    
-    if( ret.getNumChildren()>0 ){
-      std::vector< Node > children;
-      if( ret.getMetaKind() == kind::metakind::PARAMETERIZED ){
-        children.push_back( ret.getOperator() );
-      }
-      bool childChanged = false;
-      for( unsigned i=0; i<ret.getNumChildren(); i++ ){
-        Node nc = evaluateWithUnfolding( ret[i], visited ); 
-        childChanged = childChanged || nc!=ret[i];
-        children.push_back( nc );
-      }
-      if( childChanged ){
-        ret = NodeManager::currentNM()->mkNode( ret.getKind(), children );
-      }
-      ret = getExtRewriter()->extendedRewrite(ret);
-    }
-    visited[n] = ret;
-    return ret;
-  }else{
-    return it->second;
-  }
-}
-
-Node TermDbSygus::evaluateWithUnfolding( Node n ) {
-  std::unordered_map<Node, Node, NodeHashFunction> visited;
-  return evaluateWithUnfolding( n, visited );
-}
-
-}/* CVC4::theory::quantifiers namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
diff --git a/src/theory/quantifiers/term_database_sygus.h b/src/theory/quantifiers/term_database_sygus.h
deleted file mode 100644 (file)
index b9af26b..0000000
+++ /dev/null
@@ -1,286 +0,0 @@
-/*********************                                                        */
-/*! \file term_database_sygus.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief term database sygus class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_SYGUS_H
-#define __CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_SYGUS_H
-
-#include <unordered_set>
-
-#include "theory/quantifiers/extended_rewrite.h"
-#include "theory/quantifiers/sygus_explain.h"
-#include "theory/quantifiers/term_database.h"
-
-namespace CVC4 {
-namespace theory {
-namespace quantifiers {
-
-class CegConjecture;
-
-// TODO :issue #1235 split and document this class
-class TermDbSygus {
- public:
-  TermDbSygus(context::Context* c, QuantifiersEngine* qe);
-  ~TermDbSygus() {}
-  /** Reset this utility */
-  bool reset(Theory::Effort e);
-  /** Identify this utility */
-  std::string identify() const { return "TermDbSygus"; }
-  /** register the sygus type */
-  void registerSygusType(TypeNode tn);
-  /** register a variable e that we will do enumerative search on
-   * conj is the conjecture that the enumeration of e is for.
-   * f is the synth-fun that the enumeration of e is for.
-   * mkActiveGuard is whether we want to make an active guard for e 
-   * (see d_enum_to_active_guard).
-   *
-   * Notice that enumerator e may not be equivalent
-   * to f in synthesis-through-unification approaches
-   * (e.g. decision tree construction for PBE synthesis).
-   */
-  void registerEnumerator(Node e,
-                          Node f,
-                          CegConjecture* conj,
-                          bool mkActiveGuard = false);
-  /** is e an enumerator? */
-  bool isEnumerator(Node e) const;
-  /** return the conjecture e is associated with */
-  CegConjecture* getConjectureForEnumerator(Node e);
-  /** return the function-to-synthesize e is associated with */
-  Node getSynthFunForEnumerator(Node e);
-  /** get active guard for e */
-  Node getActiveGuardForEnumerator(Node e);
-  /** get all registered enumerators */
-  void getEnumerators(std::vector<Node>& mts);
-  /** get the explanation utility */
-  SygusExplain* getExplain() { return d_syexp.get(); }
-  /** get the extended rewrite utility */
-  ExtendedRewriter* getExtRewriter() { return d_ext_rw.get(); }
-  //-----------------------------conversion from sygus to builtin
-  /** get free variable
-   *
-   * This class caches a list of free variables for each type, which are
-   * used, for instance, for constructing canonical forms of terms with free
-   * variables. This function returns the i^th free variable for type tn.
-   * If useSygusType is true, then this function returns a variable of the
-   * analog type for sygus type tn (see d_fv for details).
-   */
-  TNode getFreeVar(TypeNode tn, int i, bool useSygusType = false);
-  /** get free variable and increment
-   *
-   * This function returns the next free variable for type tn, and increments
-   * the counter in var_count for that type.
-   */
-  TNode getFreeVarInc(TypeNode tn,
-                      std::map<TypeNode, int>& var_count,
-                      bool useSygusType = false);
-  /** returns true if n is a cached free variable (in d_fv). */
-  bool isFreeVar(Node n) { return d_fv_stype.find(n) != d_fv_stype.end(); }
-  /** returns the index of n in the free variable cache (d_fv). */
-  int getVarNum(Node n) { return d_fv_num[n]; }
-  /** returns true if n has a cached free variable (in d_fv). */
-  bool hasFreeVar(Node n);
-  /** make generic
-   *
-   * This function returns a builtin term f( t1, ..., tn ) where f is the
-   * builtin op of the sygus datatype constructor specified by arguments
-   * dt and c. The mapping pre maps child indices to the term for that index
-   * in the term we are constructing. That is, for each i = 1,...,n:
-   *   If i is in the domain of pre, then ti = pre[i].
-   *   If i is not in the domain of pre, then ti = d_fv[1][ var_count[Ti ] ],
-   *     and var_count[Ti] is incremented.
-   */
-  Node mkGeneric(const Datatype& dt,
-                 unsigned c,
-                 std::map<TypeNode, int>& var_count,
-                 std::map<int, Node>& pre);
-  /** same as above, but with empty var_count */
-  Node mkGeneric(const Datatype& dt, int c, std::map<int, Node>& pre);
-  /** sygus to builtin
-   *
-   * Given a sygus datatype term n of type tn, this function returns its analog,
-   * that is, the term that n encodes.
-   */
-  Node sygusToBuiltin(Node n, TypeNode tn);
-  /** same as above, but without tn */
-  Node sygusToBuiltin(Node n) { return sygusToBuiltin(n, n.getType()); }
-  //-----------------------------end conversion from sygus to builtin
-
- private:
-  /** reference to the quantifiers engine */
-  QuantifiersEngine* d_quantEngine;
-  /** sygus explanation */
-  std::unique_ptr<SygusExplain> d_syexp;
-  /** sygus explanation */
-  std::unique_ptr<ExtendedRewriter> d_ext_rw;
-  /** mapping from enumerator terms to the conjecture they are associated with
-   */
-  std::map<Node, CegConjecture*> d_enum_to_conjecture;
-  /** mapping from enumerator terms to the function-to-synthesize they are
-   * associated with 
-   */
-  std::map<Node, Node> d_enum_to_synth_fun;
-  /** mapping from enumerator terms to the guard they are associated with
-   * The guard G for an enumerator e has the semantics
-   *   if G is true, then there are more values of e to enumerate".
-   */
-  std::map<Node, Node> d_enum_to_active_guard;
-
-  //-----------------------------conversion from sygus to builtin
-  /** cache for sygusToBuiltin */
-  std::map<TypeNode, std::map<Node, Node> > d_sygus_to_builtin;
-  /** a cache of fresh variables for each type
-   *
-   * We store two versions of this list:
-   *   index 0: mapping from builtin types to fresh variables of that type,
-   *   index 1: mapping from sygus types to fresh varaibles of the type they
-   *            encode.
-   */
-  std::map<TypeNode, std::vector<Node> > d_fv[2];
-  /** Maps free variables to the domain type they are associated with in d_fv */
-  std::map<Node, TypeNode> d_fv_stype;
-  /** Maps free variables to their index in d_fv. */
-  std::map<Node, int> d_fv_num;
-  /** recursive helper for hasFreeVar, visited stores nodes we have visited. */
-  bool hasFreeVar(Node n, std::map<Node, bool>& visited);
-  //-----------------------------end conversion from sygus to builtin
-
-  // TODO :issue #1235 : below here needs refactor
-
- public:
-  Node d_true;
-  Node d_false;
-
-private:
-  void computeMinTypeDepthInternal( TypeNode root_tn, TypeNode tn, unsigned type_depth );
-  bool involvesDivByZero( Node n, std::map< Node, bool >& visited );
-
- private:
-  // information for sygus types
-  std::map<TypeNode, TypeNode> d_register;  // stores sygus -> builtin type
-  std::map<TypeNode, std::vector<Node> > d_var_list;
-  std::map<TypeNode, std::map<int, Kind> > d_arg_kind;
-  std::map<TypeNode, std::map<Kind, int> > d_kinds;
-  std::map<TypeNode, std::map<int, Node> > d_arg_const;
-  std::map<TypeNode, std::map<Node, int> > d_consts;
-  std::map<TypeNode, std::map<Node, int> > d_ops;
-  std::map<TypeNode, std::map<int, Node> > d_arg_ops;
-  std::map<TypeNode, std::map<Node, Node> > d_semantic_skolem;
-  // grammar information
-  // root -> type -> _
-  std::map<TypeNode, std::map<TypeNode, unsigned> > d_min_type_depth;
-  // std::map< TypeNode, std::map< Node, std::map< std::map< int, bool > > >
-  // d_consider_const;
-  // type -> cons -> _
-  std::map<TypeNode, unsigned> d_min_term_size;
-  std::map<TypeNode, std::map<unsigned, unsigned> > d_min_cons_term_size;
-  /** a cache for getSelectorWeight */
-  std::map<TypeNode, std::map<Node, unsigned> > d_sel_weight;
-
- public:  // general sygus utilities
-  bool isRegistered( TypeNode tn );
-  // get the minimum depth of type in its parent grammar
-  unsigned getMinTypeDepth( TypeNode root_tn, TypeNode tn );
-  // get the minimum size for a constructor term
-  unsigned getMinTermSize( TypeNode tn );
-  unsigned getMinConsTermSize( TypeNode tn, unsigned cindex );
-  /** get the weight of the selector, where tn is the domain of sel */
-  unsigned getSelectorWeight(TypeNode tn, Node sel);
-
- public:
-  TypeNode sygusToBuiltinType( TypeNode tn );
-  int getKindConsNum( TypeNode tn, Kind k );
-  int getConstConsNum( TypeNode tn, Node n );
-  int getOpConsNum( TypeNode tn, Node n );
-  bool hasKind( TypeNode tn, Kind k );
-  bool hasConst( TypeNode tn, Node n );
-  bool hasOp( TypeNode tn, Node n );
-  Node getConsNumConst( TypeNode tn, int i );
-  Node getConsNumOp( TypeNode tn, int i );
-  Kind getConsNumKind( TypeNode tn, int i );
-  bool isKindArg( TypeNode tn, int i );
-  bool isConstArg( TypeNode tn, int i );
-  /** get arg type */
-  TypeNode getArgType(const DatatypeConstructor& c, unsigned i);
-  /** get first occurrence */
-  int getFirstArgOccurrence( const DatatypeConstructor& c, TypeNode tn );
-  /** is type match */
-  bool isTypeMatch( const DatatypeConstructor& c1, const DatatypeConstructor& c2 );
-
-  TypeNode getSygusTypeForVar( Node v );
-  Node sygusSubstituted( TypeNode tn, Node n, std::vector< Node >& args );
-  Node getSygusNormalized( Node n, std::map< TypeNode, int >& var_count, std::map< Node, Node >& subs );
-  Node getNormalized(TypeNode t, Node prog);
-  unsigned getSygusTermSize( Node n );
-  /** given a term, construct an equivalent smaller one that respects syntax */
-  Node minimizeBuiltinTerm( Node n );
-  /** given a term, expand it into more basic components */
-  Node expandBuiltinTerm( Node n );
-  /** get comparison kind */
-  Kind getComparisonKind( TypeNode tn );
-  Kind getPlusKind( TypeNode tn, bool is_neg = false );
-  // get semantic skolem for n (a sygus term whose builtin version is n)
-  Node getSemanticSkolem( TypeNode tn, Node n, bool doMk = true );
-  /** involves div-by-zero */
-  bool involvesDivByZero( Node n );
-  
-  /** get operator kind */
-  static Kind getOperatorKind( Node op );
-
-  /** get anchor */
-  static Node getAnchor( Node n );
-  static unsigned getAnchorDepth( Node n );
-  
-public: // for symmetry breaking
-  bool considerArgKind( TypeNode tn, TypeNode tnp, Kind k, Kind pk, int arg );
-  bool considerConst( TypeNode tn, TypeNode tnp, Node c, Kind pk, int arg );
-  bool considerConst( const Datatype& pdt, TypeNode tnp, Node c, Kind pk, int arg );
-  int solveForArgument( TypeNode tnp, unsigned cindex, unsigned arg );
-  
-//for eager instantiation
-  // TODO (as part of #1235) move some of these functions to sygus_explain.h
- private:
-  /** the set of evaluation terms we have already processed */
-  std::unordered_set<Node, NodeHashFunction> d_eval_processed;
-  std::map< Node, std::map< Node, bool > > d_subterms;
-  std::map< Node, std::vector< Node > > d_evals;
-  std::map< Node, std::vector< std::vector< Node > > > d_eval_args;
-  std::map< Node, std::vector< bool > > d_eval_args_const;
-  std::map< Node, std::map< Node, unsigned > > d_node_mv_args_proc;
-
-public:
-  void registerEvalTerm( Node n );
-  void registerModelValue( Node n, Node v, std::vector< Node >& exps, std::vector< Node >& terms, std::vector< Node >& vals );
-  Node unfold( Node en, std::map< Node, Node >& vtm, std::vector< Node >& exp, bool track_exp = true );
-  Node unfold( Node en ){
-    std::map< Node, Node > vtm;
-    std::vector< Node > exp;
-    return unfold( en, vtm, exp, false );
-  }
-  Node getEagerUnfold( Node n, std::map< Node, Node >& visited );
-
-  // builtin evaluation, returns rewrite( bn [ args / vars(tn) ] )
-  Node evaluateBuiltin( TypeNode tn, Node bn, std::vector< Node >& args );
-  // evaluate with unfolding
-  Node evaluateWithUnfolding(
-      Node n, std::unordered_map<Node, Node, NodeHashFunction>& visited);
-  Node evaluateWithUnfolding( Node n );
-};
-
-}/* CVC4::theory::quantifiers namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_H */
index a278274c378fb6c6d5447da6ac1de65da529e513..f4e44ff2f67f3728371badf38acceb088a81c87e 100644 (file)
@@ -20,8 +20,8 @@
 #include "base/cvc4_assert.h"
 #include "expr/kind.h"
 #include "options/quantifiers_options.h"
-#include "theory/quantifiers/instantiation_engine.h"
-#include "theory/quantifiers/model_engine.h"
+#include "theory/quantifiers/ematching/instantiation_engine.h"
+#include "theory/quantifiers/fmf/model_engine.h"
 #include "theory/quantifiers/quantifiers_attributes.h"
 #include "theory/quantifiers/term_database.h"
 #include "theory/quantifiers/term_util.h"
diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp
deleted file mode 100644 (file)
index 609b6e4..0000000
+++ /dev/null
@@ -1,969 +0,0 @@
-/*********************                                                        */
-/*! \file trigger.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Morgan Deters, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of trigger class
- **/
-
-#include "theory/quantifiers/trigger.h"
-
-#include "theory/arith/arith_msum.h"
-#include "theory/quantifiers/candidate_generator.h"
-#include "theory/quantifiers/ho_trigger.h"
-#include "theory/quantifiers/inst_match_generator.h"
-#include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers_engine.h"
-#include "theory/theory_engine.h"
-#include "theory/uf/equality_engine.h"
-#include "util/hash.h"
-
-using namespace std;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-
-namespace CVC4 {
-namespace theory {
-namespace inst {
-
-void TriggerTermInfo::init( Node q, Node n, int reqPol, Node reqPolEq ){
-  if( d_fv.empty() ){
-    quantifiers::TermUtil::getVarContainsNode( q, n, d_fv );
-  }
-  if( d_reqPol==0 ){
-    d_reqPol = reqPol;
-    d_reqPolEq = reqPolEq;
-  }else{
-    //determined a ground (dis)equality must hold or else q is a tautology?
-  }
-  d_weight = Trigger::getTriggerWeight(n);
-}
-
-/** trigger class constructor */
-Trigger::Trigger(QuantifiersEngine* qe, Node q, std::vector<Node>& nodes)
-    : d_quantEngine(qe), d_quant(q)
-{
-  d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() );
-  Trace("trigger") << "Trigger for " << q << ": " << std::endl;
-  for( unsigned i=0; i<d_nodes.size(); i++ ){
-    Trace("trigger") << "   " << d_nodes[i] << std::endl;
-  }
-  if( d_nodes.size()==1 ){
-    if( isSimpleTrigger( d_nodes[0] ) ){
-      d_mg = new InstMatchGeneratorSimple(q, d_nodes[0], qe);
-    }else{
-      d_mg = InstMatchGenerator::mkInstMatchGenerator(q, d_nodes[0], qe);
-    }
-  }else{
-    if( options::multiTriggerCache() ){
-      d_mg = new InstMatchGeneratorMulti(q, d_nodes, qe);
-    }else{
-      d_mg = InstMatchGenerator::mkInstMatchGeneratorMulti(q, d_nodes, qe);
-    }
-  }
-  if( d_nodes.size()==1 ){
-    if( isSimpleTrigger( d_nodes[0] ) ){
-      ++(qe->d_statistics.d_triggers);
-    }else{
-      ++(qe->d_statistics.d_simple_triggers);
-    }
-  }else{
-    Trace("multi-trigger") << "Trigger for " << q << ": " << std::endl;
-    for( unsigned i=0; i<d_nodes.size(); i++ ){
-      Trace("multi-trigger") << "   " << d_nodes[i] << std::endl;
-    }
-    ++(qe->d_statistics.d_multi_triggers);
-  }
-
-  // Notice() << "Trigger : " << (*this) << "  for " << q << std::endl;
-  Trace("trigger-debug") << "Finished making trigger." << std::endl;
-}
-
-Trigger::~Trigger() {
-  delete d_mg;
-}
-
-void Trigger::resetInstantiationRound(){
-  d_mg->resetInstantiationRound( d_quantEngine );
-}
-
-void Trigger::reset( Node eqc ){
-  d_mg->reset( eqc, d_quantEngine );
-}
-
-Node Trigger::getInstPattern(){
-  return NodeManager::currentNM()->mkNode( INST_PATTERN, d_nodes );
-}
-
-int Trigger::addInstantiations()
-{
-  int addedLemmas = d_mg->addInstantiations(d_quant, d_quantEngine, this);
-  if( addedLemmas>0 ){
-    if (Debug.isOn("inst-trigger"))
-    {
-      Debug("inst-trigger") << "Added " << addedLemmas
-                            << " lemmas, trigger was ";
-      for (unsigned i = 0; i < d_nodes.size(); i++)
-      {
-        Debug("inst-trigger") << d_nodes[i] << " ";
-      }
-      Debug("inst-trigger") << std::endl;
-    }
-  }
-  return addedLemmas;
-}
-
-bool Trigger::sendInstantiation(InstMatch& m)
-{
-  return d_quantEngine->getInstantiate()->addInstantiation(d_quant, m);
-}
-
-bool Trigger::mkTriggerTerms( Node q, std::vector< Node >& nodes, unsigned n_vars, std::vector< Node >& trNodes ) {
-  //only take nodes that contribute variables to the trigger when added
-  std::vector< Node > temp;
-  temp.insert( temp.begin(), nodes.begin(), nodes.end() );
-  std::map< Node, bool > vars;
-  std::map< Node, std::vector< Node > > patterns;
-  size_t varCount = 0;
-  std::map< Node, std::vector< Node > > varContains;
-  quantifiers::TermUtil::getVarContains( q, temp, varContains );
-  for( unsigned i=0; i<temp.size(); i++ ){
-    bool foundVar = false;
-    for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){
-      Node v = varContains[ temp[i] ][j];
-      Assert( quantifiers::TermUtil::getInstConstAttr(v)==q );
-      if( vars.find( v )==vars.end() ){
-        varCount++;
-        vars[ v ] = true;
-        foundVar = true;
-      }
-    }
-    if( foundVar ){
-      trNodes.push_back( temp[i] );
-      for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){
-        Node v = varContains[ temp[i] ][j];
-        patterns[ v ].push_back( temp[i] );
-      }
-    }
-    if( varCount==n_vars ){
-      break;
-    }
-  }
-  if( varCount<n_vars ){
-    Trace("trigger-debug") << "Don't consider trigger since it does not contain specified number of variables." << std::endl;
-    for( unsigned i=0; i<nodes.size(); i++) {
-      Trace("trigger-debug") << nodes[i] << " ";
-    }
-    Trace("trigger-debug") << std::endl;
-
-    //do not generate multi-trigger if it does not contain all variables
-    return false;
-  }else{
-    //now, minimize the trigger
-    for( unsigned i=0; i<trNodes.size(); i++ ){
-      bool keepPattern = false;
-      Node n = trNodes[i];
-      for( unsigned j=0; j<varContains[ n ].size(); j++ ){
-        Node v = varContains[ n ][j];
-        if( patterns[v].size()==1 ){
-          keepPattern = true;
-          break;
-        }
-      }
-      if( !keepPattern ){
-        //remove from pattern vector
-        for( unsigned j=0; j<varContains[ n ].size(); j++ ){
-          Node v = varContains[ n ][j];
-          for( unsigned k=0; k<patterns[v].size(); k++ ){
-            if( patterns[v][k]==n ){
-              patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 );
-              break;
-            }
-          }
-        }
-        //remove from trigger nodes
-        trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 );
-        i--;
-      }
-    }
-  }
-  return true;
-}
-
-Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, bool keepAll, int trOption, unsigned use_n_vars ){
-  std::vector< Node > trNodes;
-  if( !keepAll ){
-    unsigned n_vars = use_n_vars==0 ? f[0].getNumChildren() : use_n_vars;
-    if( !mkTriggerTerms( f, nodes, n_vars, trNodes ) ){
-      return NULL;
-    }
-  }else{
-    trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() );
-  }
-
-  //check for duplicate?
-  if( trOption!=TR_MAKE_NEW ){
-    Trigger* t = qe->getTriggerDatabase()->getTrigger( trNodes );
-    if( t ){
-      if( trOption==TR_GET_OLD ){
-        //just return old trigger
-        return t;
-      }else{
-        return NULL;
-      }
-    }
-  }
-
-  // check if higher-order
-  Trace("trigger-debug") << "Collect higher-order variable triggers..."
-                         << std::endl;
-  std::map<Node, std::vector<Node> > ho_apps;
-  HigherOrderTrigger::collectHoVarApplyTerms(f, trNodes, ho_apps);
-  Trace("trigger") << "...got " << ho_apps.size()
-                   << " higher-order applications." << std::endl;
-  Trigger* t;
-  if (!ho_apps.empty())
-  {
-    t = new HigherOrderTrigger(qe, f, trNodes, ho_apps);
-  }
-  else
-  {
-    t = new Trigger(qe, f, trNodes);
-  }
-
-  qe->getTriggerDatabase()->addTrigger( trNodes, t );
-  return t;
-}
-
-Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, bool keepAll, int trOption, unsigned use_n_vars ){
-  std::vector< Node > nodes;
-  nodes.push_back( n );
-  return mkTrigger( qe, f, nodes, keepAll, trOption, use_n_vars );
-}
-
-bool Trigger::isUsable( Node n, Node q ){
-  if( quantifiers::TermUtil::getInstConstAttr(n)==q ){
-    if( isAtomicTrigger( n ) ){
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        if( !isUsable( n[i], q ) ){
-          return false;
-        }
-      }
-      return true;
-    }else if( n.getKind()==INST_CONSTANT ){
-      return true;
-    }else{
-      std::map< Node, Node > coeffs;
-      if( isBooleanTermTrigger( n ) ){
-        return true;
-      }else if( options::purifyTriggers() ){
-        Node x = getInversionVariable( n );
-        if( !x.isNull() ){
-          return true;
-        }
-      }
-    }
-    return false;
-  }else{
-    return true;
-  }
-}
-
-Node Trigger::getIsUsableEq( Node q, Node n ) {
-  Assert( isRelationalTrigger( n ) );
-  for( unsigned i=0; i<2; i++) {
-    if( isUsableEqTerms( q, n[i], n[1-i] ) ){
-      if( i==1 && n.getKind()==EQUAL && !quantifiers::TermUtil::hasInstConstAttr(n[0]) ){
-        return NodeManager::currentNM()->mkNode( n.getKind(), n[1], n[0] );  
-      }else{
-        return n;
-      }
-    }
-  }
-  return Node::null();
-}
-
-bool Trigger::isUsableEqTerms( Node q, Node n1, Node n2 ) {
-  if( n1.getKind()==INST_CONSTANT ){
-    if( options::relationalTriggers() ){
-      if( !quantifiers::TermUtil::hasInstConstAttr(n2) ){
-        return true;
-      }else if( n2.getKind()==INST_CONSTANT ){
-        return true;
-      }
-    }
-  }else if( isUsableAtomicTrigger( n1, q ) ){
-    if( options::relationalTriggers() && n2.getKind()==INST_CONSTANT && !quantifiers::TermUtil::containsTerm( n1, n2 ) ){
-      return true;
-    }else if( !quantifiers::TermUtil::hasInstConstAttr(n2) ){
-      return true;
-    }
-  }
-  return false;
-}
-
-Node Trigger::getIsUsableTrigger( Node n, Node q ) {
-  bool pol = true;
-  Trace("trigger-debug") << "Is " << n << " a usable trigger?" << std::endl;
-  if( n.getKind()==NOT ){
-    pol = !pol;
-    n = n[0];
-  }
-  if( n.getKind()==INST_CONSTANT ){
-    return pol ? n : NodeManager::currentNM()->mkNode( EQUAL, n, NodeManager::currentNM()->mkConst( true ) ).notNode();
-  }else if( isRelationalTrigger( n ) ){
-    Node rtr = getIsUsableEq( q, n );
-    if( rtr.isNull() && n[0].getType().isReal() ){
-      //try to solve relation
-      std::map< Node, Node > m;
-      if (ArithMSum::getMonomialSumLit(n, m))
-      {
-        for( std::map< Node, Node >::iterator it = m.begin(); it!=m.end(); ++it ){
-          bool trySolve = false;
-          if( !it->first.isNull() ){
-            if( it->first.getKind()==INST_CONSTANT ){
-              trySolve = options::relationalTriggers();
-            }else if( isUsableTrigger( it->first, q ) ){
-              trySolve = true;
-            }
-          }
-          if( trySolve ){
-            Trace("trigger-debug") << "Try to solve for " << it->first << std::endl;
-            Node veq;
-            if (ArithMSum::isolate(it->first, m, veq, n.getKind()) != 0)
-            {
-              rtr = getIsUsableEq( q, veq );
-            }
-            //either all solves will succeed or all solves will fail
-            break;
-          }
-        }
-      }
-    }
-    if( !rtr.isNull() ){
-      Trace("relational-trigger") << "Relational trigger : " << std::endl;
-      Trace("relational-trigger") << "    " << rtr << " (from " << n << ")" << std::endl;
-      Trace("relational-trigger") << "    in quantifier " << q << std::endl;
-      Node rtr2 = pol ? rtr : rtr.negate();
-      Trace("relational-trigger") << "    return : " << rtr2 << std::endl;
-      return rtr2;
-    }
-  }else{
-    Trace("trigger-debug") << n << " usable : " << ( quantifiers::TermUtil::getInstConstAttr(n)==q ) << " " << isAtomicTrigger( n ) << " " << isUsable( n, q ) << std::endl;
-    if( isUsableAtomicTrigger( n, q ) ){
-      return pol ? n : NodeManager::currentNM()->mkNode( EQUAL, n, NodeManager::currentNM()->mkConst( true ) ).notNode();
-    }
-  }
-  return Node::null();
-}
-
-bool Trigger::isUsableAtomicTrigger( Node n, Node q ) {
-  return quantifiers::TermUtil::getInstConstAttr( n )==q && isAtomicTrigger( n ) && isUsable( n, q );
-}
-
-bool Trigger::isUsableTrigger( Node n, Node q ){
-  Node nu = getIsUsableTrigger( n, q );
-  return !nu.isNull();
-}
-
-bool Trigger::isAtomicTrigger( Node n ){
-  return isAtomicTriggerKind( n.getKind() );
-}
-
-bool Trigger::isAtomicTriggerKind( Kind k ) {
-  return k == APPLY_UF || k == SELECT || k == STORE || k == APPLY_CONSTRUCTOR
-         || k == APPLY_SELECTOR_TOTAL || k == APPLY_TESTER || k == UNION
-         || k == INTERSECTION || k == SUBSET || k == SETMINUS || k == MEMBER
-         || k == SINGLETON || k == SEP_PTO || k == BITVECTOR_TO_NAT
-         || k == INT_TO_BITVECTOR || k == HO_APPLY;
-}
-
-bool Trigger::isRelationalTrigger( Node n ) {
-  return isRelationalTriggerKind( n.getKind() );
-}
-
-bool Trigger::isRelationalTriggerKind( Kind k ) {
-  return k==EQUAL || k==GEQ;
-}
-  
-bool Trigger::isCbqiKind( Kind k ) {
-  if( quantifiers::TermUtil::isBoolConnective( k ) || k==PLUS || k==GEQ || k==EQUAL || k==MULT ){
-    return true;
-  }else{
-    //CBQI typically works for satisfaction-complete theories
-    TheoryId t = kindToTheoryId( k );
-    return t == THEORY_BV || t == THEORY_DATATYPES || t == THEORY_BOOL;
-  }
-}
-
-bool Trigger::isSimpleTrigger( Node n ){
-  Node t = n.getKind()==NOT ? n[0] : n;
-  if( t.getKind()==EQUAL ){
-    if( !quantifiers::TermUtil::hasInstConstAttr( t[1] ) ){
-      t = t[0];
-    }
-  }
-  if( isAtomicTrigger( t ) ){
-    for( unsigned i=0; i<t.getNumChildren(); i++ ){
-      if( t[i].getKind()!=INST_CONSTANT && quantifiers::TermUtil::hasInstConstAttr(t[i]) ){
-        return false;
-      }
-    }
-    if( options::purifyDtTriggers() && t.getKind()==APPLY_SELECTOR_TOTAL ){
-      return false;
-    }
-    if (t.getKind() == HO_APPLY && t[0].getKind() == INST_CONSTANT)
-    {
-      return false;
-    }
-    return true;
-  }else{
-    return false;
-  }
-}
-
-//store triggers in reqPol, indicating their polarity (if any) they must appear to falsify the quantified formula
-void Trigger::collectPatTerms2( Node q, Node n, std::map< Node, std::vector< Node > >& visited, std::map< Node, TriggerTermInfo >& tinfo, 
-                                quantifiers::TriggerSelMode tstrt, std::vector< Node >& exclude, std::vector< Node >& added,
-                                bool pol, bool hasPol, bool epol, bool hasEPol, bool knowIsUsable ){
-  std::map< Node, std::vector< Node > >::iterator itv = visited.find( n );
-  if( itv==visited.end() ){
-    visited[ n ].clear();
-    Trace("auto-gen-trigger-debug2") << "Collect pat terms " << n << " " << pol << " " << hasPol << " " << epol << " " << hasEPol << std::endl;
-    if( n.getKind()!=FORALL && n.getKind()!=INST_CONSTANT ){
-      Node nu;
-      bool nu_single = false;
-      if( knowIsUsable ){
-        nu = n;
-      }else if( n.getKind()!=NOT && std::find( exclude.begin(), exclude.end(), n )==exclude.end() ){
-        nu = getIsUsableTrigger( n, q );
-        if( !nu.isNull() && nu!=n ){
-          collectPatTerms2( q, nu, visited, tinfo, tstrt, exclude, added, pol, hasPol, epol, hasEPol, true );
-          // copy to n
-          visited[n].insert( visited[n].end(), added.begin(), added.end() );
-          return;
-        }
-      }
-      if( !nu.isNull() ){
-        Assert( nu==n );
-        Assert( nu.getKind()!=NOT );
-        Trace("auto-gen-trigger-debug2") << "...found usable trigger : " << nu << std::endl;
-        Node reqEq;
-        if( nu.getKind()==EQUAL ){
-          if( isAtomicTrigger( nu[0] ) && !quantifiers::TermUtil::hasInstConstAttr(nu[1]) ){
-            if( hasPol ){
-              reqEq = nu[1];
-            }
-            nu = nu[0];
-          }
-        }
-        Assert( reqEq.isNull() || !quantifiers::TermUtil::hasInstConstAttr( reqEq ) );
-        Assert( isUsableTrigger( nu, q ) );
-        //tinfo.find( nu )==tinfo.end()
-        Trace("auto-gen-trigger-debug2") << "...add usable trigger : " << nu << std::endl;
-        tinfo[ nu ].init( q, nu, hasEPol ? ( epol ? 1 : -1 ) : 0, reqEq );
-        nu_single = tinfo[ nu ].d_fv.size()==q[0].getNumChildren();
-      }
-      Node nrec = nu.isNull() ? n : nu;
-      std::vector< Node > added2;
-      for( unsigned i=0; i<nrec.getNumChildren(); i++ ){
-        bool newHasPol, newPol;
-        bool newHasEPol, newEPol;
-        QuantPhaseReq::getPolarity( nrec, i, hasPol, pol, newHasPol, newPol );
-        QuantPhaseReq::getEntailPolarity( nrec, i, hasEPol, epol, newHasEPol, newEPol );
-        collectPatTerms2( q, nrec[i], visited, tinfo, tstrt, exclude, added2, newPol, newHasPol, newEPol, newHasEPol );
-      }
-      // if this is not a usable trigger, don't worry about caching the results, since triggers do not contain non-usable subterms
-      if( !nu.isNull() ){
-        bool rm_nu = false;
-        for( unsigned i=0; i<added2.size(); i++ ){
-          Trace("auto-gen-trigger-debug2") << "..." << nu << " added child " << i << " : " << added2[i] << std::endl;
-          Assert( added2[i]!=nu );
-          // if child was not already removed
-          if( tinfo.find( added2[i] )!=tinfo.end() ){
-            if( tstrt==quantifiers::TRIGGER_SEL_MAX || ( tstrt==quantifiers::TRIGGER_SEL_MIN_SINGLE_MAX && !nu_single ) ){
-              //discard all subterms
-              Trace("auto-gen-trigger-debug2") << "......remove it." << std::endl;
-              visited[ added2[i] ].clear();
-              tinfo.erase( added2[i] );
-            }else{
-              if( tinfo[ nu ].d_fv.size()==tinfo[ added2[i] ].d_fv.size() ){
-                if (tinfo[nu].d_weight >= tinfo[added2[i]].d_weight)
-                {
-                  // discard if we added a subterm as a trigger with all
-                  // variables that nu has
-                  Trace("auto-gen-trigger-debug2")
-                      << "......subsumes parent " << tinfo[nu].d_weight << " "
-                      << tinfo[added2[i]].d_weight << "." << std::endl;
-                  rm_nu = true;
-                }
-              }
-              if( std::find( added.begin(), added.end(), added2[i] )==added.end() ){
-                added.push_back( added2[i] );
-              }
-            }
-          }
-        }
-        if( rm_nu && ( tstrt==quantifiers::TRIGGER_SEL_MIN || ( tstrt==quantifiers::TRIGGER_SEL_MIN_SINGLE_ALL && nu_single ) ) ){
-          tinfo.erase( nu );
-        }else{
-          if( std::find( added.begin(), added.end(), nu )==added.end() ){
-            added.push_back( nu );
-          }
-        }
-        visited[n].insert( visited[n].end(), added.begin(), added.end() );
-      }
-    }
-  }else{
-    for( unsigned i=0; i<itv->second.size(); ++i ){
-      Node t = itv->second[i];
-      if( std::find( added.begin(), added.end(), t )==added.end() ){
-        added.push_back( t );
-      }
-    }
-  }
-}
-
-bool Trigger::isBooleanTermTrigger( Node n ) {
-  if( n.getKind()==ITE ){
-    //check for boolean term converted to ITE
-    if( n[0].getKind()==INST_CONSTANT &&
-        n[1].getKind()==CONST_BITVECTOR &&
-        n[2].getKind()==CONST_BITVECTOR ){
-      if( ((BitVectorType)n[1].getType().toType()).getSize()==1 &&
-          n[1].getConst<BitVector>().toInteger()==1 &&
-          n[2].getConst<BitVector>().toInteger()==0 ){
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
-bool Trigger::isPureTheoryTrigger( Node n ) {
-  if( n.getKind()==APPLY_UF || n.getKind()==VARIABLE || n.getKind()==SKOLEM ){  //|| !quantifiers::TermUtil::hasInstConstAttr( n ) ){
-    return false;
-  }else{
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      if( !isPureTheoryTrigger( n[i] ) ){
-        return false;
-      }
-    }
-    return true;
-  }
-}
-
-int Trigger::getTriggerWeight( Node n ) {
-  if (n.getKind() == APPLY_UF)
-  {
-    return 0;
-  }
-  else if (isAtomicTrigger(n))
-  {
-    return 1;
-  }else{
-    if( options::relationalTriggers() ){
-      if( isRelationalTrigger( n ) ){
-        for( unsigned i=0; i<2; i++ ){
-          if( n[i].getKind()==INST_CONSTANT && !quantifiers::TermUtil::hasInstConstAttr( n[1-i] ) ){
-            return 0;
-          }
-        }
-      }
-    }
-    return 2;
-  }
-}
-
-bool Trigger::isLocalTheoryExt( Node n, std::vector< Node >& vars, std::vector< Node >& patTerms ) {
-  if( !n.getType().isBoolean() && n.getKind()==APPLY_UF ){
-    if( std::find( patTerms.begin(), patTerms.end(), n )==patTerms.end() ){
-      bool hasVar = false;
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        if( n[i].getKind()==INST_CONSTANT ){
-          hasVar = true;
-          if( std::find( vars.begin(), vars.end(), n[i] )==vars.end() ){
-            vars.push_back( n[i] );
-          }else{
-            //do not allow duplicate variables
-            return false;
-          }
-        }else{
-          //do not allow nested function applications
-          return false;
-        }
-      }
-      if( hasVar ){
-        patTerms.push_back( n );
-      }
-    }
-  }else{
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      if( !isLocalTheoryExt( n[i], vars, patTerms ) ){
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-void Trigger::collectPatTerms( Node q, Node n, std::vector< Node >& patTerms, quantifiers::TriggerSelMode tstrt, std::vector< Node >& exclude, 
-                               std::map< Node, TriggerTermInfo >& tinfo, bool filterInst ){
-  std::map< Node, std::vector< Node > > visited;
-  if( filterInst ){
-    //immediately do not consider any term t for which another term is an instance of t
-    std::vector< Node > patTerms2;
-    std::map< Node, TriggerTermInfo > tinfo2;
-    collectPatTerms( q, n, patTerms2, quantifiers::TRIGGER_SEL_ALL, exclude, tinfo2, false );
-    std::vector< Node > temp;
-    temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() );
-    filterTriggerInstances(temp);
-    if (Trace.isOn("trigger-filter-instance"))
-    {
-      if (temp.size() != patTerms2.size())
-      {
-        Trace("trigger-filter-instance") << "Filtered an instance: "
-                                         << std::endl;
-        Trace("trigger-filter-instance") << "Old: ";
-        for (unsigned i = 0; i < patTerms2.size(); i++)
-        {
-          Trace("trigger-filter-instance") << patTerms2[i] << " ";
-        }
-        Trace("trigger-filter-instance") << std::endl << "New: ";
-        for (unsigned i = 0; i < temp.size(); i++)
-        {
-          Trace("trigger-filter-instance") << temp[i] << " ";
-        }
-        Trace("trigger-filter-instance") << std::endl;
-      }
-    }
-    if( tstrt==quantifiers::TRIGGER_SEL_ALL ){
-      for( unsigned i=0; i<temp.size(); i++ ){
-        //copy information
-        tinfo[temp[i]].d_fv.insert( tinfo[temp[i]].d_fv.end(), tinfo2[temp[i]].d_fv.begin(), tinfo2[temp[i]].d_fv.end() );
-        tinfo[temp[i]].d_reqPol = tinfo2[temp[i]].d_reqPol;
-        tinfo[temp[i]].d_reqPolEq = tinfo2[temp[i]].d_reqPolEq;
-        patTerms.push_back( temp[i] );
-      }
-      return;
-    }else{
-      //do not consider terms that have instances
-      for( unsigned i=0; i<patTerms2.size(); i++ ){
-        if( std::find( temp.begin(), temp.end(), patTerms2[i] )==temp.end() ){
-          visited[ patTerms2[i] ].clear();
-        }
-      }
-    }
-  }
-  std::vector< Node > added;
-  collectPatTerms2( q, n, visited, tinfo, tstrt, exclude, added, true, true, false, true );
-  for( std::map< Node, TriggerTermInfo >::iterator it = tinfo.begin(); it != tinfo.end(); ++it ){
-    patTerms.push_back( it->first );
-  }
-}
-
-int Trigger::isTriggerInstanceOf(Node n1,
-                                 Node n2,
-                                 std::vector<Node>& fv1,
-                                 std::vector<Node>& fv2)
-{
-  Assert(n1 != n2);
-  int status = 0;
-  std::unordered_set<TNode, TNodeHashFunction> subs_vars;
-  std::unordered_set<std::pair<TNode, TNode>,
-                     PairHashFunction<TNode,
-                                      TNode,
-                                      TNodeHashFunction,
-                                      TNodeHashFunction> >
-      visited;
-  std::vector<std::pair<TNode, TNode> > visit;
-  std::pair<TNode, TNode> cur;
-  TNode cur1;
-  TNode cur2;
-  visit.push_back(std::pair<TNode, TNode>(n1, n2));
-  do
-  {
-    cur = visit.back();
-    visit.pop_back();
-    if (visited.find(cur) == visited.end())
-    {
-      visited.insert(cur);
-      cur1 = cur.first;
-      cur2 = cur.second;
-      Assert(cur1 != cur2);
-      // recurse if they have the same operator
-      if (cur1.hasOperator() && cur2.hasOperator()
-          && cur1.getNumChildren() == cur2.getNumChildren()
-          && cur1.getOperator() == cur2.getOperator()
-          && cur1.getOperator().getKind()!=INST_CONSTANT)
-      {
-        visit.push_back(std::pair<TNode, TNode>(cur1, cur2));
-        for (unsigned i = 0, size = cur1.getNumChildren(); i < size; i++)
-        {
-          if (cur1[i] != cur2[i])
-          {
-            visit.push_back(std::pair<TNode, TNode>(cur1[i], cur2[i]));
-          }
-          else if (cur1[i].getKind() == INST_CONSTANT)
-          {
-            if (subs_vars.find(cur1[i]) != subs_vars.end())
-            {
-              return 0;
-            }
-            // the variable must map to itself in the substitution
-            subs_vars.insert(cur1[i]);
-          }
-        }
-      }
-      else
-      {
-        bool success = false;
-        // check if we are in a unifiable instance case
-        // must be only this case
-        for (unsigned r = 0; r < 2; r++)
-        {
-          if (status == 0 || ((status == 1) == (r == 0)))
-          {
-            TNode curi = r == 0 ? cur1 : cur2;
-            if (curi.getKind() == INST_CONSTANT
-                && subs_vars.find(curi) == subs_vars.end())
-            {
-              TNode curj = r == 0 ? cur2 : cur1;
-              // RHS must be a simple trigger
-              if (getTriggerWeight(curj) == 0)
-              {
-                // must occur in the free variables in the other
-                std::vector<Node>& free_vars = r == 0 ? fv2 : fv1;
-                if (std::find(free_vars.begin(), free_vars.end(), curi)
-                    != free_vars.end())
-                {
-                  status = r == 0 ? 1 : -1;
-                  subs_vars.insert(curi);
-                  success = true;
-                  break;
-                }
-              }
-            }
-          }
-        }
-        if (!success)
-        {
-          return 0;
-        }
-      }
-    }
-  } while (!visit.empty());
-  return status;
-}
-
-void Trigger::filterTriggerInstances(std::vector<Node>& nodes)
-{
-  std::map<unsigned, std::vector<Node> > fvs;
-  for (unsigned i = 0, size = nodes.size(); i < size; i++)
-  {
-    quantifiers::TermUtil::computeVarContains(nodes[i], fvs[i]);
-  }
-  std::vector<bool> active;
-  active.resize(nodes.size(), true);
-  for (unsigned i = 0, size = nodes.size(); i < size; i++)
-  {
-    std::vector<Node>& fvsi = fvs[i];
-    if (active[i])
-    {
-      for (unsigned j = i + 1, size2 = nodes.size(); j < size2; j++)
-      {
-        if (active[j])
-        {
-          int result = isTriggerInstanceOf(nodes[i], nodes[j], fvsi, fvs[j]);
-          if (result == 1)
-          {
-            Trace("filter-instances") << nodes[j] << " is an instance of "
-                                      << nodes[i] << std::endl;
-            active[i] = false;
-            break;
-          }
-          else if (result == -1)
-          {
-            Trace("filter-instances") << nodes[i] << " is an instance of "
-                                      << nodes[j] << std::endl;
-            active[j] = false;
-          }
-        }
-      }
-    }
-  }
-  std::vector<Node> temp;
-  for (unsigned i = 0; i < nodes.size(); i++)
-  {
-    if (active[i])
-    {
-      temp.push_back(nodes[i]);
-    }
-  }
-  nodes.clear();
-  nodes.insert(nodes.begin(), temp.begin(), temp.end());
-}
-
-Node Trigger::getInversionVariable( Node n ) {
-  if( n.getKind()==INST_CONSTANT ){
-    return n;
-  }else if( n.getKind()==PLUS || n.getKind()==MULT ){
-    Node ret;
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      if( quantifiers::TermUtil::hasInstConstAttr(n[i]) ){
-        if( ret.isNull() ){
-          ret = getInversionVariable( n[i] );
-          if( ret.isNull() ){
-            Trace("var-trigger-debug") << "No : multiple variables " << n << std::endl;
-            return Node::null();
-          }
-        }else{
-          return Node::null();
-        }
-      }else if( n.getKind()==MULT ){
-        if( !n[i].isConst() ){
-          Trace("var-trigger-debug") << "No : non-linear coefficient " << n << std::endl;
-          return Node::null();
-        }
-        /*
-        else if( n.getType().isInteger() ){
-          Rational r = n[i].getConst<Rational>();
-          if( r!=Rational(-1) && r!=Rational(1) ){
-            Trace("var-trigger-debug") << "No : not integer coefficient " << n << std::endl;
-            return Node::null();
-          }
-        }
-        */
-      }
-    }
-    return ret;
-  }else{
-    Trace("var-trigger-debug") << "No : unsupported operator " << n << "." << std::endl;
-  }
-  return Node::null();
-}
-
-Node Trigger::getInversion( Node n, Node x ) {
-  if( n.getKind()==INST_CONSTANT ){
-    return x;
-  }else if( n.getKind()==PLUS || n.getKind()==MULT ){
-    int cindex = -1;
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      if( !quantifiers::TermUtil::hasInstConstAttr(n[i]) ){
-        if( n.getKind()==PLUS ){
-          x = NodeManager::currentNM()->mkNode( MINUS, x, n[i] );
-        }else if( n.getKind()==MULT ){
-          Assert( n[i].isConst() );
-          if( x.getType().isInteger() ){
-            Node coeff = NodeManager::currentNM()->mkConst( n[i].getConst<Rational>().abs() );
-            if( !n[i].getConst<Rational>().abs().isOne() ){
-              x = NodeManager::currentNM()->mkNode( INTS_DIVISION_TOTAL, x, coeff );
-            }
-            if( n[i].getConst<Rational>().sgn()<0 ){
-              x = NodeManager::currentNM()->mkNode( UMINUS, x );
-            }
-          }else{
-            Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / n[i].getConst<Rational>() );
-            x = NodeManager::currentNM()->mkNode( MULT, x, coeff );
-          }
-        }
-        x = Rewriter::rewrite( x );
-      }else{
-        Assert( cindex==-1 );
-        cindex = i;
-      }
-    }
-    Assert( cindex!=-1 );
-    return getInversion( n[cindex], x );
-  }
-  return Node::null();
-}
-
-void Trigger::getTriggerVariables(Node n, Node q, std::vector<Node>& t_vars)
-{
-  std::vector< Node > patTerms;
-  std::map< Node, TriggerTermInfo > tinfo;
-  // collect all patterns from n
-  std::vector< Node > exclude;
-  collectPatTerms(q, n, patTerms, quantifiers::TRIGGER_SEL_ALL, exclude, tinfo);
-  //collect all variables from all patterns in patTerms, add to t_vars
-  for( unsigned i=0; i<patTerms.size(); i++ ){
-    quantifiers::TermUtil::getVarContainsNode( q, patTerms[i], t_vars );
-  }
-}
-
-int Trigger::getActiveScore() {
-  return d_mg->getActiveScore( d_quantEngine );
-}
-
-TriggerTrie::TriggerTrie()
-{}
-
-TriggerTrie::~TriggerTrie() {
-  for(std::map< TNode, TriggerTrie* >::iterator i = d_children.begin(), iend = d_children.end();
-      i != iend; ++i) {
-    TriggerTrie* current = (*i).second;
-    delete current;
-  }
-  d_children.clear();
-
-  for( unsigned i=0; i<d_tr.size(); i++ ){
-    delete d_tr[i];
-  }
-}
-
-inst::Trigger* TriggerTrie::getTrigger(std::vector<Node>& nodes)
-{
-  std::vector<Node> temp;
-  temp.insert(temp.begin(), nodes.begin(), nodes.end());
-  std::sort(temp.begin(), temp.end());
-  TriggerTrie* tt = this;
-  for (const Node& n : temp)
-  {
-    std::map<TNode, TriggerTrie*>::iterator itt = tt->d_children.find(n);
-    if (itt == tt->d_children.end())
-    {
-      return NULL;
-    }
-    else
-    {
-      tt = itt->second;
-    }
-  }
-  return tt->d_tr.empty() ? NULL : tt->d_tr[0];
-}
-
-void TriggerTrie::addTrigger(std::vector<Node>& nodes, inst::Trigger* t)
-{
-  std::vector<Node> temp;
-  temp.insert(temp.begin(), nodes.begin(), nodes.end());
-  std::sort(temp.begin(), temp.end());
-  TriggerTrie* tt = this;
-  for (const Node& n : temp)
-  {
-    std::map<TNode, TriggerTrie*>::iterator itt = tt->d_children.find(n);
-    if (itt == tt->d_children.end())
-    {
-      TriggerTrie* ttn = new TriggerTrie;
-      tt->d_children[n] = ttn;
-      tt = ttn;
-    }
-    else
-    {
-      tt = itt->second;
-    }
-  }
-  tt->d_tr.push_back(t);
-}
-
-}/* CVC4::theory::inst namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h
deleted file mode 100644 (file)
index e897c0b..0000000
+++ /dev/null
@@ -1,476 +0,0 @@
-/*********************                                                        */
-/*! \file trigger.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Andrew Reynolds, Tim King, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief trigger class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__QUANTIFIERS__TRIGGER_H
-#define __CVC4__THEORY__QUANTIFIERS__TRIGGER_H
-
-#include <map>
-
-#include "expr/node.h"
-#include "theory/quantifiers/inst_match.h"
-#include "options/quantifiers_options.h"
-
-namespace CVC4 {
-namespace theory {
-
-class QuantifiersEngine;
-
-namespace inst {
-
-class IMGenerator;
-class InstMatchGenerator;
-
-/** Information about a node used in a trigger.
-*
-* This information includes:
-* 1. the free variables of the node, and
-* 2. information about which terms are useful for matching.
-*
-* As an example, consider the trigger
-*   { f( x ), g( y ), P( y, z ) }
-* for quantified formula
-*   forall xy. ( f( x ) != b => ( P( x, g( y ) ) V P( y, z ) ) )
-*
-* Notice that it is only useful to match f( x ) to f-applications not in the
-* equivalence class of b, and P( y, z ) to P-applications not in the equivalence
-* class of true, as such instances will always be entailed by the ground
-* equalities and disequalities the current context. Entailed instances are
-* typically not helpful, and are discarded in Instantiate::addInstantiation(...)
-* unless the option --no-inst-no-entail is enabled. For more details, see page
-* 10 of "Congruence Closure with Free Variables", Barbosa et al., TACAS 2017.
-*
-* This example is referenced for each of the functions below.
-*/
-class TriggerTermInfo {
- public:
-  TriggerTermInfo() : d_reqPol(0), d_weight(0) {}
-  ~TriggerTermInfo() {}
-  /** The free variables in the node
-  *
-  * In the trigger term info for f( x ) in the above example, d_fv = { x }
-  * In the trigger term info for g( y ) in the above example, d_fv = { y }
-  * In the trigger term info for P( y, z ) in the above example, d_fv = { y, z }
-  */
-  std::vector<Node> d_fv;
-  /** Required polarity:  1 for equality, -1 for disequality, 0 for none
-  *
-  * In the trigger term info for f( x ) in the above example, d_reqPol = -1
-  * In the trigger term info for g( y ) in the above example, d_reqPol = 0
-  * In the trigger term info for P( y, z ) in the above example,  d_reqPol = 1
-  */
-  int d_reqPol;
-  /** Required polarity equal term
-  *
-  * If d_reqPolEq is not null,
-  *   if d_reqPol = 1, then this trigger term must be matched to terms in the
-  *                    equivalence class of d_reqPolEq,
-  *   if d_reqPol = -1, then this trigger term must be matched to terms *not* in
-  *                     the equivalence class of d_reqPolEq.
-  *
-  * This information is typically chosen by analyzing the entailed equalities
-  * and disequalities of quantified formulas.
-  * In the trigger term info for f( x ) in the above example, d_reqPolEq = b
-  * In the trigger term info for g( y ) in the above example,
-  *   d_reqPolEq = Node::null()
-  * In the trigger term info for P( y, z ) in the above example,
-  *   d_reqPolEq = false
-  */
-  Node d_reqPolEq;
-  /** the weight of the trigger (see Trigger::getTriggerWeight). */
-  int d_weight;
-  /** Initialize this information class (can be called more than once).
-  * q is the quantified formula that n is a trigger term for
-  * n is the trigger term
-  * reqPol/reqPolEq are described above
-  */
-  void init(Node q, Node n, int reqPol = 0, Node reqPolEq = Node::null());
-};
-
-/** A collection of nodes representing a trigger.
-*
-* This class encapsulates all implementations of E-matching in CVC4.
-* Its primary use is as a utility of the quantifiers module InstantiationEngine
-* (see theory/quantifiers/instantiation_engine.h) which uses Trigger to make
-* appropriate calls to Instantiate::addInstantiation(...)
-* (see theory/instantiate.h) for the instantiate utility of the quantifiers
-* engine (d_quantEngine) associated with this trigger.  These calls
-* queue instantiation lemmas to the output channel of TheoryQuantifiers during
-* a full effort check.
-*
-* Concretely, a Trigger* t is used in the following way during a full effort
-* check. Assume that t is associated with quantified formula q (see field d_f).
-* We call :
-*
-* // setup initial information
-* t->resetInstantiationRound();
-* // will produce instantiations based on matching with all terms
-* t->reset( Node::null() );
-* // add all instantiations based on E-matching with this trigger and the
-* // current context
-* t->addInstantiations();
-*
-* This will result in (a set of) calls to
-* Instantiate::addInstantiation(q, m1)...Instantiate::addInstantiation(q, mn),
-* where m1...mn are InstMatch objects. These calls add the corresponding
-* instantiation lemma for (q,mi) on the output channel associated with
-* d_quantEngine.
-*
-* The Trigger class is wrapper around an underlying IMGenerator class, which
-* implements various forms of E-matching for its set of nodes (d_nodes), which
-* is refered to in the literature as a "trigger". A trigger is a set of terms
-* whose free variables are the bound variables of a quantified formula q,
-* and that is used to guide instantiations for q (for example, see "Efficient
-* E-Matching for SMT Solvers" by de Moura et al).
-*
-* For example of an instantiation lemma produced by E-matching :
-*
-* quantified formula : forall x. P( x )
-*            trigger : P( x )
-*     ground context : ~P( a )
-*
-* Then E-matching matches P( x ) and P( a ), resulting in the match { x -> a }
-* which is used to generate the instantiation lemma :
-*   (forall x. P( x )) => P( a )
-*
-* Terms that are provided as input to a Trigger class via mkTrigger
-* should be in "instantiation constant form", see TermUtil::getInstConstantNode.
-* Say we have quantified formula q whose AST is the Node
-*   (FORALL
-*     (BOUND_VAR_LIST x)
-*     (NOT (P x))
-*     (INST_PATTERN_LIST (INST_PATTERN (P x))))
-* then TermUtil::getInstConstantNode( q, (P x) ) = (P IC) where
-* IC = TermUtil::getInstantiationConstant( q, i ).
-* Trigger expects as input (P IC) to represent the Trigger (P x). This form
-* ensures that references to bound variables are unique to quantified formulas,
-* which is required to ensure the correctness of instantiation lemmas we
-* generate.
-*
-*/
-class Trigger {
-  friend class IMGenerator;
-
- public:
-  virtual ~Trigger();
-  /** get the generator associated with this trigger */
-  IMGenerator* getGenerator() { return d_mg; }
-  /** Reset instantiation round.
-   *
-  * Called once at beginning of an instantiation round.
-  */
-  void resetInstantiationRound();
-  /** Reset the trigger.
-   *
-  * eqc is the equivalence class from which to match ground terms. If eqc is
-  * Node::null(), then we match ground terms from all equivalence classes.
-  */
-  void reset( Node eqc );
-  /** add all available instantiations, based on the current context
-  *
-  * This function makes the appropriate calls to d_qe->addInstantiation(...)
-  * based on the current ground terms and equalities in the current context,
-  * via queries to functions in d_qe. This calls the addInstantiations function
-  * of the underlying match generator. It can be extended to
-  * produce instantiations beyond what is produced by the match generator
-  * (for example, see theory/quantifiers/ho_trigger.h).
-  */
-  virtual int addInstantiations();
-  /** Return whether this is a multi-trigger. */
-  bool isMultiTrigger() { return d_nodes.size()>1; }
-  /** Get instantiation pattern list associated with this trigger.
-   *
-  * An instantiation pattern list is the node representation of a trigger, in
-  * particular, it is the third argument of quantified formulas which have user
-  * (! ... :pattern) attributes.
-  */
-  Node getInstPattern();
-  /* A heuristic value indicating how active this generator is.
-   *
-  * This returns the number of ground terms for the match operators in terms
-  * from d_nodes. This score is only used with the experimental option
-  *   --trigger-active-sel.
-  */
-  int getActiveScore();
-  /** print debug information for the trigger */
-  void debugPrint(const char* c)
-  {
-    Trace(c) << "TRIGGER( ";
-    for (int i = 0; i < (int)d_nodes.size(); i++)
-    {
-      if (i > 0)
-      {
-        Trace(c) << ", ";
-      }
-      Trace(c) << d_nodes[i];
-    }
-    Trace(c) << " )";
-  }
-  /** mkTrigger method
-   *
-   * This makes an instance of a trigger object.
-   *  qe     : pointer to the quantifier engine;
-   *  q      : the quantified formula we are making a trigger for
-   *  nodes  : the nodes comprising the (multi-)trigger
-   *  keepAll: don't remove unneeded patterns;
-   *  trOption : policy for dealing with triggers that already exist
-   *             (see below)
-   *  use_n_vars : number of variables that should be bound by the trigger
-   *               typically, the number of quantified variables in q.
-   */
-  enum{
-    TR_MAKE_NEW,    //make new trigger even if it already may exist
-    TR_GET_OLD,     //return a previous trigger if it had already been created
-    TR_RETURN_NULL  //return null if a duplicate is found
-  };
-  static Trigger* mkTrigger(QuantifiersEngine* qe,
-                            Node q,
-                            std::vector<Node>& nodes,
-                            bool keepAll = true,
-                            int trOption = TR_MAKE_NEW,
-                            unsigned use_n_vars = 0);
-  /** single trigger version that calls the above function */
-  static Trigger* mkTrigger(QuantifiersEngine* qe,
-                            Node q,
-                            Node n,
-                            bool keepAll = true,
-                            int trOption = TR_MAKE_NEW,
-                            unsigned use_n_vars = 0);
-  /** make trigger terms
-   *
-   * This takes a set of eligible trigger terms and stores a subset of them in
-   * trNodes, such that :
-   *   (1) the terms in trNodes contain at least n_vars of the quantified
-   *       variables in quantified formula q, and
-   *   (2) the set trNodes is minimal, i.e. removing one term from trNodes
-   *       always violates (1).
-   */
-  static bool mkTriggerTerms(Node q,
-                             std::vector<Node>& nodes,
-                             unsigned n_vars,
-                             std::vector<Node>& trNodes);
-  /** collect pattern terms
-   *
-   * This collects all terms that are eligible for triggers for quantified
-   * formula q in term n and adds them to patTerms.
-   *   tstrt : the selection strategy (see options/quantifiers_mode.h),
-   *   exclude :  a set of terms that *cannot* be selected as triggers,
-   *   tinfo : stores the result of the collection, mapping terms to the
-   *           information they are associated with,
-   *   filterInst : flag that when true, we discard terms that have instances
-   *     in the vector we are returning, e.g. we do not return f( x ) if we are
-   *     also returning f( f( x ) ). TODO: revisit this (issue #1211)
-   */
-  static void collectPatTerms( Node q, Node n, std::vector< Node >& patTerms, quantifiers::TriggerSelMode tstrt,
-                               std::vector< Node >& exclude, std::map< Node, TriggerTermInfo >& tinfo,
-                               bool filterInst = false );
-
-  /** Is n a usable trigger in quantified formula q?
-   *
-   * A usable trigger is one that is matchable and contains free variables only
-   * from q.
-   */
-  static bool isUsableTrigger( Node n, Node q );
-  /** get is usable trigger
-   *
-   * Return the associated node of n that is a usable trigger in quantified
-   * formula q. This may be different than n in several cases :
-   * (1) Polarity information is explicitly converted to equalities, e.g.
-   *      getIsUsableTrigger( (not (P x )), q ) may return (= (P x) false)
-   * (2) Relational triggers are put into solved form, e.g.
-   *      getIsUsableTrigger( (= (+ x a) 5), q ) may return (= x (- 5 a)).
-   */
-  static Node getIsUsableTrigger( Node n, Node q );
-  /** Is n a usable atomic trigger?
-   *
-   * A usable atomic trigger is a term that is both a useable trigger and an
-   * atomic trigger.
-   */
-  static bool isUsableAtomicTrigger( Node n, Node q );
-  /** is n an atomic trigger?
-  *
-  * An atomic trigger is one whose kind is an atomic trigger kind.
-  */
-  static bool isAtomicTrigger( Node n );
-  /** Is k an atomic trigger kind?
-   *
-  * An atomic trigger kind is one for which term indexing/matching is possible.
-  */
-  static bool isAtomicTriggerKind( Kind k );
-  /** is n a relational trigger, e.g. like x >= a ? */
-  static bool isRelationalTrigger( Node n );
-  /** Is k a relational trigger kind? */
-  static bool isRelationalTriggerKind( Kind k );
-  /** Is k a kind for which counterexample-guided instantiation is possible?
-   *
-  * This typically corresponds to kinds that correspond to operators that
-  * have total interpretations and are a part of the signature of
-  * satisfaction complete theories (see Reynolds et al., CAV 2015).
-  */
-  static bool isCbqiKind( Kind k );
-  /** is n a simple trigger (see inst_match_generator.h)? */
-  static bool isSimpleTrigger( Node n );
-  /** is n a Boolean term trigger, e.g. ite( x, BV1, BV0 )? */
-  static bool isBooleanTermTrigger( Node n );
-  /** is n a pure theory trigger, e.g. head( x )? */
-  static bool isPureTheoryTrigger( Node n );
-  /** get trigger weight
-   *
-   * Returns 0 for triggers that are easy to process and 1 otherwise.
-   * A trigger is easy to process if it is an atomic trigger, or a relational
-   * trigger of the form x ~ g for ~ \in { =, >=, > }.
-   */
-  static int getTriggerWeight( Node n );
-  /** Returns whether n is a trigger term with a local theory extension
-  * property from Bansal et al., CAV 2015.
-  */
-  static bool isLocalTheoryExt( Node n, std::vector< Node >& vars,
-                                std::vector< Node >& patTerms );
-  /** get the variable associated with an inversion for n
-   *
-   * A term n with an inversion variable x has the following property :
-   *   There exists a closed function f such that for all terms t
-   *   |= (n = t) <=> (x = f(t))
-   * For example, getInversionVariable( x+1 ) returns x since for all terms t,
-   *   |= x+1 = t <=> x = (\y. y-1)(t)
-   * We call f the inversion function for n.
-   */
-  static Node getInversionVariable( Node n );
-  /** Get the body of the inversion function for n whose argument is y.
-   * e.g. getInversion( x+1, y ) returns y-1
-   */
-  static Node getInversion(Node n, Node y);
-  /** get all variables that E-matching can instantiate from a subterm n.
-   *
-   * This returns the union of all free variables in usable triggers that are
-   * subterms of n.
-   */
-  static void getTriggerVariables(Node n, Node f, std::vector<Node>& t_vars);
-
- protected:
-  /** trigger constructor, intentionally protected (use Trigger::mkTrigger). */
-  Trigger(QuantifiersEngine* ie, Node q, std::vector<Node>& nodes);
-  /** is subterm of trigger usable (helper function for isUsableTrigger) */
-  static bool isUsable( Node n, Node q );
-  /** returns an equality that is equivalent to the equality eq and
-  * is a usable trigger for q if one exists, otherwise returns Node::null().
-  */
-  static Node getIsUsableEq( Node q, Node eq );
-  /** returns whether n1 == n2 is a usable (relational) trigger for q. */
-  static bool isUsableEqTerms( Node q, Node n1, Node n2 );
-  /** recursive helper function for collectPatTerms
-   *
-   * This collects the usable trigger terms in the subterm n of the body of
-   * quantified formula q.
-   *   visited : cache of the trigger terms collected for each visited node,
-   *   tinfo : cache of trigger term info for each visited node,
-   *   tstrat : the selection strategy (see options/quantifiers_mode.h)
-   *   exclude :  a set of terms that *cannot* be selected as triggers
-   *   pol/hasPol : the polarity of node n in q
-   *                (see QuantPhaseReq theory/quantifiers/quant_util.h)
-   *   epol/hasEPol : the entailed polarity of node n in q
-   *                  (see QuantPhaseReq theory/quantifiers/quant_util.h)
-   *   knowIsUsable : whether we know that n is a usable trigger.
-   *
-   * We add the triggers we collected recursively in n into added.
-   */
-  static void collectPatTerms2( Node q, Node n, std::map< Node, std::vector< Node > >& visited, std::map< Node, TriggerTermInfo >& tinfo, 
-                                quantifiers::TriggerSelMode tstrt, std::vector< Node >& exclude, std::vector< Node >& added,
-                                bool pol, bool hasPol, bool epol, bool hasEPol, bool knowIsUsable = false );
-
-  /** filter all nodes that have trigger instances
-   *
-   * This is used during collectModelInfo to filter certain trigger terms,
-   * stored in nodes. This updates nodes so that no pairs of distinct nodes
-   * (i,j) is such that i is a trigger instance of j or vice versa (see below).
-   */
-  static void filterTriggerInstances(std::vector<Node>& nodes);
-
-  /** is instance of
-   *
-   * We say a term t is an trigger instance of term s if
-   * (1) t = s * { x1 -> t1 ... xn -> tn }
-   * (2) { x1, ..., xn } are a subset of FV( t ).
-   * For example, f( g( h( x, x ) ) ) and f( g( x ) ) are instances of f( x ),
-   * but f( g( y ) ) and g( x ) are not instances of f( x ).
-   *
-   * When this method returns -1, n1 is an instance of n2,
-   * When this method returns 1, n1 is an instance of n2.
-   *
-   * The motivation for this method is to discard triggers s that are less
-   * restrictive (criteria (1)) and serve to bind the same variables (criteria
-   * (2)) as another trigger t. This often helps avoiding matching loops.
-   */
-  static int isTriggerInstanceOf(Node n1,
-                                 Node n2,
-                                 std::vector<Node>& fv1,
-                                 std::vector<Node>& fv2);
-
-  /** add an instantiation (called by InstMatchGenerator)
-   *
-   * This calls Instantiate::addInstantiation(...) for instantiations
-   * associated with m. Typically, m is associated with a single instantiation,
-   * but in some cases (e.g. higher-order) we may modify m before calling
-   * Instantiate::addInstantiation(...).
-   */
-  virtual bool sendInstantiation(InstMatch& m);
-  /** The nodes comprising this trigger. */
-  std::vector< Node > d_nodes;
-  /** The quantifiers engine associated with this trigger. */
-  QuantifiersEngine* d_quantEngine;
-  /** The quantified formula this trigger is for. */
-  Node d_quant;
-  /** match generator
-   *
-  * This is the back-end utility that implements the underlying matching
-  * algorithm associated with this trigger.
-  */
-  IMGenerator* d_mg;
-}; /* class Trigger */
-
-/** A trie of triggers.
-*
-* This class is used to cache all Trigger objects that are generated in the
-* current context. We index Triggers in this data structure based on the
-* value of Trigger::d_nodes. When a Trigger is added to this data structure,
-* this Trie assumes responsibility for deleting it.
-*/
-class TriggerTrie {
-public:
-  TriggerTrie();
-  ~TriggerTrie();
-  /** get trigger
-  * This returns a Trigger t that is indexed by nodes,
-  * or NULL otherwise.
-  */
-  Trigger* getTrigger(std::vector<Node>& nodes);
-  /** add trigger
-  * This adds t to the trie, indexed by nodes.
-  * In typical use cases, nodes is t->d_nodes.
-  */
-  void addTrigger(std::vector<Node>& nodes, Trigger* t);
-
- private:
-  /** The trigger at this node in the trie. */
-  std::vector<Trigger*> d_tr;
-  /** The children of this node in the trie. */
-  std::map< TNode, TriggerTrie* > d_children;
-};/* class inst::Trigger::TriggerTrie */
-
-}/* CVC4::theory::inst namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__QUANTIFIERS__TRIGGER_H */
index a0efe80f9aeb1954c2e53c9bf080394ce142eedc..60f44c256ff3b40eed6d660aa47637b25eced81d 100644 (file)
 #include "theory/arrays/theory_arrays.h"
 #include "theory/datatypes/theory_datatypes.h"
 #include "theory/quantifiers/alpha_equivalence.h"
-#include "theory/quantifiers/ambqi_builder.h"
+#include "theory/quantifiers/fmf/ambqi_builder.h"
 #include "theory/quantifiers/anti_skolem.h"
-#include "theory/quantifiers/bounded_integers.h"
-#include "theory/quantifiers/ce_guided_instantiation.h"
-#include "theory/quantifiers/ceg_t_instantiator.h"
+#include "theory/quantifiers/fmf/bounded_integers.h"
+#include "theory/quantifiers/sygus/ce_guided_instantiation.h"
+#include "theory/quantifiers/cegqi/ceg_t_instantiator.h"
 #include "theory/quantifiers/conjecture_generator.h"
 #include "theory/quantifiers/equality_infer.h"
 #include "theory/quantifiers/equality_query.h"
 #include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/full_model_check.h"
+#include "theory/quantifiers/fmf/full_model_check.h"
 #include "theory/quantifiers/fun_def_engine.h"
 #include "theory/quantifiers/inst_propagator.h"
-#include "theory/quantifiers/inst_strategy_cbqi.h"
-#include "theory/quantifiers/inst_strategy_e_matching.h"
+#include "theory/quantifiers/cegqi/inst_strategy_cbqi.h"
+#include "theory/quantifiers/ematching/inst_strategy_e_matching.h"
 #include "theory/quantifiers/inst_strategy_enumerative.h"
 #include "theory/quantifiers/instantiate.h"
-#include "theory/quantifiers/instantiation_engine.h"
+#include "theory/quantifiers/ematching/instantiation_engine.h"
 #include "theory/quantifiers/local_theory_ext.h"
-#include "theory/quantifiers/model_engine.h"
+#include "theory/quantifiers/fmf/model_engine.h"
 #include "theory/quantifiers/quant_conflict_find.h"
 #include "theory/quantifiers/quant_epr.h"
 #include "theory/quantifiers/quant_equality_engine.h"
 #include "theory/quantifiers/rewrite_engine.h"
 #include "theory/quantifiers/skolemize.h"
 #include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_database_sygus.h"
+#include "theory/quantifiers/sygus/term_database_sygus.h"
 #include "theory/quantifiers/term_enumeration.h"
 #include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/ematching/trigger.h"
 #include "theory/sep/theory_sep.h"
 #include "theory/theory_engine.h"
 #include "theory/uf/equality_engine.h"
index edbd768d7375c3e181caa5a81c73eae6165e44c2..c6299693124fc7eb827d65fdc1d3e941e2b211fc 100644 (file)
@@ -40,7 +40,7 @@
 #include "theory/care_graph.h"
 #include "theory/ite_utilities.h"
 #include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/model_engine.h"
+#include "theory/quantifiers/fmf/model_engine.h"
 #include "theory/quantifiers/theory_quantifiers.h"
 #include "theory/quantifiers_engine.h"
 #include "theory/rewriter.h"
index 1e6578b275c89a44a4539cc3809c8e1294612aa4..27a676066c7c784f442e81f3e0ed76d40005d9b7 100644 (file)
@@ -22,7 +22,7 @@
 #include "theory/rewriter.h"
 #include "util/bitvector.h"
 
-#include "theory/quantifiers/ceg_t_instantiator.cpp"
+#include "theory/quantifiers/cegqi/ceg_t_instantiator.cpp"
 
 #include <cxxtest/TestSuite.h>
 #include <iostream>