Separate sygus term utilities to new file, minor cleanup from last commit.
authorajreynol <andrew.j.reynolds@gmail.com>
Mon, 10 Jul 2017 19:35:47 +0000 (14:35 -0500)
committerajreynol <andrew.j.reynolds@gmail.com>
Mon, 10 Jul 2017 19:35:47 +0000 (14:35 -0500)
src/Makefile.am
src/expr/node.cpp
src/theory/datatypes/datatypes_sygus.cpp
src/theory/quantifiers/ce_guided_instantiation.cpp
src/theory/quantifiers/ce_guided_pbe.cpp
src/theory/quantifiers/ce_guided_single_inv.cpp
src/theory/quantifiers/ce_guided_single_inv_sol.cpp
src/theory/quantifiers/term_database.cpp
src/theory/quantifiers/term_database.h
src/theory/quantifiers/term_database_sygus.cpp [new file with mode: 0644]
src/theory/quantifiers/term_database_sygus.h [new file with mode: 0644]

index 6cbed6fda76918dec52a954f515ffdfb5e9816ed..847eecedceb067ed68fe5e726f04137cdbc7b170 100644 (file)
@@ -413,6 +413,8 @@ libcvc4_la_SOURCES = \
        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/theory_quantifiers.cpp \
        theory/quantifiers/theory_quantifiers.h \
        theory/quantifiers/theory_quantifiers_type_rules.h \
index e45ca49e02af02d42ed9ad35735038367a6a5efb..0c844f92d6e3c1f38b9a1288d5548c441ddd5a12 100644 (file)
@@ -114,6 +114,10 @@ bool NodeTemplate<ref_count>::hasBoundVar() {
         hasBv = (*i).hasBoundVar();
       }
       if( !hasBv ){
+        //FIXME : this is a hack to handle synthesis conjectures
+        // the issue is that we represent second-order quantification in synthesis conjectures via a Node:
+        //  exists x forall y P[f,y], where x is a dummy variable that maps to f through attribute SygusSynthFunVarListAttributeId
+        //  when asked whether a node has a bound variable, we want to treat f as if it were a bound (second-order) variable. -AJR
         if( getKind()==kind::APPLY_UF && getOperator().hasAttribute(theory::SygusSynthFunVarListAttribute()) ){
           hasBv = true;
         }
index 8a8660303a5834437efa5f83551801348504ec57..0652ebe10f16c7a326f005f7d625e82e3f6b17bf 100644 (file)
@@ -19,7 +19,7 @@
 #include "options/quantifiers_options.h"
 #include "theory/datatypes/datatypes_rewriter.h"
 #include "theory/datatypes/datatypes_sygus.h"
-#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_database_sygus.h"
 #include "theory/datatypes/theory_datatypes.h"
 #include "theory/theory_model.h"
 
index 63e8aa365b930c682e5719cc905b481f646aed87..a635568fe1cc7022f3cf2d77e68666d80a55e5ff 100644 (file)
@@ -19,7 +19,7 @@
 #include "options/datatypes_options.h"
 #include "smt/smt_statistics_registry.h"
 #include "theory/quantifiers/first_order_model.h"
-#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_database_sygus.h"
 #include "theory/theory_engine.h"
 #include "prop/prop_engine.h"
 #include "theory/bv/theory_bv_rewriter.h"
index 38b5af85f9894e66e305334154c95e9f315998fd..501e839db6c5a1a39af3dae0dfab11d93f5da4b2 100644 (file)
@@ -16,7 +16,7 @@
 
 #include "expr/datatype.h"
 #include "options/quantifiers_options.h"
-#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_database_sygus.h"
 #include "theory/datatypes/datatypes_rewriter.h"
 
 using namespace CVC4;
index 4db6df1552d7f388ae88ddc59dae64dc3127d8e6..a8dcd588791f00732e8073b9b9e07a05b80795ca 100644 (file)
@@ -20,7 +20,7 @@
 #include "theory/quantifiers/ce_guided_single_inv_ei.h"
 #include "theory/quantifiers/first_order_model.h"
 #include "theory/quantifiers/quant_util.h"
-#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_database_sygus.h"
 #include "theory/quantifiers/trigger.h"
 #include "theory/theory_engine.h"
 
@@ -731,36 +731,36 @@ struct sortSiInstanceIndices {
 
 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;
+  //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;
   }
+  //}
 }
 
 
index aea1e4efc5d0e04f7ff94a0a3bb24326508f2ee0..9e65be20242f3600e856713a1f561bfb1408225d 100644 (file)
@@ -20,7 +20,7 @@
 #include "theory/quantifiers/ce_guided_single_inv.h"
 #include "theory/quantifiers/first_order_model.h"
 #include "theory/quantifiers/quant_util.h"
-#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_database_sygus.h"
 #include "theory/quantifiers/trigger.h"
 #include "theory/theory_engine.h"
 
index 9e7f174c1f8534463b67db0e02014c16ecfc51f9..93390facb0191a92b0d5281421a86a28b19ab078 100644 (file)
 #include "theory/quantifiers/rewrite_engine.h"
 #include "theory/quantifiers/theory_quantifiers.h"
 #include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/term_database_sygus.h"
 #include "theory/quantifiers_engine.h"
 #include "theory/theory_engine.h"
 
-//for sygus
-#include "smt/smt_engine_scope.h"
-#include "theory/bv/theory_bv_utils.h"
-#include "util/bitvector.h"
-#include "theory/datatypes/datatypes_rewriter.h"
-#include "theory/strings/theory_strings_rewriter.h"
-
 using namespace std;
 using namespace CVC4::kind;
 using namespace CVC4::context;
@@ -2291,2966 +2285,6 @@ Node TermDb::getQAttrQuantIdNumNode( Node q ) {
   }
 }
 
-
-bool EvalSygusInvarianceTest::invariant( quantifiers::TermDbSygus * tds, Node nvn, Node x ){
-  TNode tnvn = nvn;
-  Node conj_subs = d_conj.substitute( d_var, tnvn );
-  Node conj_subs_unfold = tds->evaluateWithUnfolding( conj_subs, d_visited );
-  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;
-  }else{
-    return false;
-  }
-}
-
-TermDbSygus::TermDbSygus( context::Context* c, QuantifiersEngine* qe ) : d_quantEngine( qe ){
-  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];
-}
-
-bool TermDbSygus::getMatch( Node p, Node n, std::map< int, Node >& s ) {
-  std::vector< int > new_s;
-  return getMatch2( p, n, s, new_s );
-}
-
-bool TermDbSygus::getMatch2( Node p, Node n, std::map< int, Node >& s, std::vector< int >& new_s ) {
-  std::map< Node, int >::iterator it = d_fv_num.find( p );
-  if( it!=d_fv_num.end() ){
-    Node prev = s[it->second];
-    s[it->second] = n;
-    if( prev.isNull() ){
-      new_s.push_back( it->second );
-    }
-    return prev.isNull() || prev==n;
-  }else if( n.getNumChildren()==0 ){
-    return p==n;
-  }else if( n.getKind()==p.getKind() && n.getNumChildren()==p.getNumChildren() ){
-    //try both ways?
-    unsigned rmax = TermDb::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; i<n.getNumChildren(); i++ ){
-        int io = r==0 ? i : ( i==0 ? 1 : 0 );
-        if( !getMatch2( 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 TermDbSygus::getMatch( Node t, TypeNode st, int& index_found, std::vector< Node >& args, int index_exc, int index_start ) {
-  Assert( st.isDatatype() );
-  const Datatype& dt = ((DatatypeType)(st).toType()).getDatatype();
-  Assert( dt.isSygus() );
-  std::map< Kind, std::vector< Node > > kgens;
-  std::vector< Node > gens;
-  for( unsigned i=index_start; i<dt.getNumConstructors(); i++ ){
-    if( (int)i!=index_exc ){
-      Node g = getGenericBase( st, dt, i );
-      gens.push_back( g );
-      kgens[g.getKind()].push_back( g );
-      Trace("sygus-db-debug") << "Check generic base : " << g << " from " << dt[i].getName() << std::endl;
-      if( g.getKind()==t.getKind() ){
-        Trace("sygus-db-debug") << "Possible match ? " << g << " " << t << " for " << dt[i].getName() << std::endl;
-        std::map< int, Node > sigma;
-        if( getMatch( g, t, sigma ) ){
-          //we found an exact match
-          bool msuccess = true;
-          for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
-            if( sigma[j].isNull() ){
-              msuccess = false;
-              break;
-            }else{
-              args.push_back( sigma[j] );
-            }
-          }
-          if( msuccess ){
-            index_found = i;
-            return true;
-          }
-          //we found an exact match
-          //std::map< TypeNode, int > var_count;
-          //Node new_t = mkGeneric( dt, i, var_count, args );
-          //Trace("sygus-db-debug") << "Rewrote to : " << new_t << std::endl;
-          //return new_t;
-        }
-      }
-    }
-  }
-  /*
-  //otherwise, try to modulate based on kinds
-  for( std::map< Kind, std::vector< Node > >::iterator it = kgens.begin(); it != kgens.end(); ++it ){
-    if( it->second.size()>1 ){
-      for( unsigned i=0; i<it->second.size(); i++ ){
-        for( unsigned j=0; j<it->second.size(); j++ ){
-          if( i!=j ){
-            std::map< int, Node > sigma;
-            if( getMatch( it->second[i], it->second[j], sigma ) ){
-              if( sigma.size()==1 ){
-                //Node mod_pat = sigma.begin().second;
-                //Trace("cegqi-si-rcons-debug") << "Modulated pattern " << mod_pat << " from " << it->second[i] << " and " << it->second[j] << std::endl;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-  */
-  return false;
-}
-
-Node TermDbSygus::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() ){
-    Assert( isRegistered( tn ) );
-    std::map< TypeNode, int > var_count;
-    std::map< int, Node > pre;
-    Node g = mkGeneric( dt, c, var_count, pre );
-    Trace("sygus-db-debug") << "Sygus DB : Generic is " << g << std::endl;
-    Node gr = Rewriter::rewrite( g );
-    Trace("sygus-db-debug") << "Sygus DB : Generic rewritten is " << gr << std::endl;
-    gr = Node::fromExpr( smt::currentSmtEngine()->expandDefinitions( gr.toExpr() ) );
-    Trace("sygus-db-debug") << "Sygus DB : Generic base " << dt[c].getName() << " : " << gr << std::endl;
-    d_generic_base[tn][c] = gr;
-    return gr;
-  }else{
-    return it->second;
-  }
-}
-
-Node TermDbSygus::mkGeneric( const Datatype& dt, int c, std::map< TypeNode, int >& var_count, std::map< int, Node >& pre ) {
-  Assert( c>=0 && c<(int)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( int i=0; i<(int)dt[c].getNumArgs(); 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 );
-    }
-    Assert( !a.isNull() );
-    children.push_back( a );
-  }
-  Node ret;
-  if( op.getKind()==BUILTIN ){
-    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 );
-      /*
-      Node n = NodeManager::currentNM()->mkNode( APPLY, children );
-      //must expand definitions
-      Node ne = Node::fromExpr( smt::currentSmtEngine()->expandDefinitions( n.toExpr() ) );
-      Trace("sygus-db-debug") << "Expanded definitions in " << n << " to " << ne << std::endl;
-      return ne;
-      */
-    }
-  }
-  Trace("sygus-db-debug") << "...returning " << ret << std::endl;
-  return ret;
-}
-
-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;
-    Node ret;
-    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; j<n.getNumChildren(); j++ ){
-        pre[j] = sygusToBuiltin( n[j], getArgType( dt[i], j ) );
-      }
-      ret = mkGeneric( dt, i, var_count, pre );
-      Trace("sygus-db-debug") << "SygusToBuiltin : Generic is " << ret << std::endl;
-      ret = Node::fromExpr( smt::currentSmtEngine()->expandDefinitions( ret.toExpr() ) );
-      Trace("sygus-db-debug") << "SygusToBuiltin : After expand definitions " << ret << std::endl;
-      d_sygus_to_builtin[tn][n] = ret;
-    }else{
-      Assert( isFreeVar( n ) );
-      //map to builtin variable type
-      int fv_num = getVarNum( n );
-      Assert( !dt.getSygusType().isNull() );
-      TypeNode vtn = TypeNode::fromType( dt.getSygusType() );
-      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() );
-}
-  
-//rcons_depth limits the number of recursive calls when doing accelerated constant reconstruction (currently limited to 1000)
-//this is hacky : depending upon order of calls, constant rcons may succeed, e.g. 1001, 999 vs. 999, 1001
-Node TermDbSygus::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() ){
-    Node sc;
-    d_builtin_const_to_sygus[tn][c] = sc;
-    Assert( c.isConst() );
-    Assert( tn.isDatatype() );
-    const Datatype& dt = ((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 = NodeManager::currentNM()->mkSkolem( "sy", tn, "sygus proxy" );
-      SygusProxyAttribute spa;
-      k.setAttribute(spa,c);
-      sc = k;
-    }else{
-      int carg = getOpConsNum( tn, c );
-      if( carg!=-1 ){
-        //sc = Node::fromExpr( dt[carg].getSygusOp() );
-        sc = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, Node::fromExpr( dt[carg].getConstructor() ) );
-      }else{
-        //identity functions
-        for( unsigned i=0; i<getNumIdFuncs( tn ); i++ ){
-          unsigned ii = getIdFuncIndex( tn, i );
-          Assert( dt[ii].getNumArgs()==1 );
-          //try to directly reconstruct from single argument
-          TypeNode tnc = 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 = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, Node::fromExpr( dt[ii].getConstructor() ), n );
-            break;
-          }
-        }
-        if( sc.isNull() ){
-          if( rcons_depth<1000 ){
-            //accelerated, recursive reconstruction of constants
-            Kind pk = getPlusKind( TypeNode::fromType( dt.getSygusType() ) );
-            if( pk!=UNDEFINED_KIND ){
-              int arg = getKindConsNum( tn, pk );
-              if( arg!=-1 ){
-                Kind ck = getComparisonKind( TypeNode::fromType( dt.getSygusType() ) );
-                Kind pkm = getPlusKind( TypeNode::fromType( dt.getSygusType() ), true );
-                //get types
-                Assert( dt[arg].getNumArgs()==2 );
-                TypeNode tn1 = getArgType( dt[arg], 0 );
-                TypeNode tn2 = getArgType( dt[arg], 1 );
-                //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 = NodeManager::currentNM()->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 = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, Node::fromExpr( dt[arg].getConstructor() ), sc1, sc2 );
-                        break;
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-    d_builtin_const_to_sygus[tn][c] = sc;
-    return sc;
-  }else{
-    return it->second;
-  }
-}
-
-Node TermDbSygus::getSygusNormalized( Node n, std::map< TypeNode, int >& var_count, std::map< Node, Node >& subs ) {
-  return n;
-  /*  TODO?
-  if( n.getKind()==SKOLEM ){
-    std::map< Node, Node >::iterator its = subs.find( n );
-    if( its!=subs.end() ){
-      return its->second;
-    }else{
-      std::map< Node, TypeNode >::iterator it = d_fv_stype.find( n );
-      if( it!=d_fv_stype.end() ){
-        Node v = getVarInc( it->second, var_count );
-        subs[n] = v;
-        return v;
-      }else{
-        return n;
-      }
-    }
-  }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 = getSygusNormalized( n[i], var_count, subs );
-        childChanged = childChanged || nc!=n[i];
-        children.push_back( nc );
-      }
-      if( childChanged ){
-        return NodeManager::currentNM()->mkNode( n.getKind(), children );
-      }
-    }
-    return n;
-  }
-  */
-}
-
-Node TermDbSygus::getNormalized( TypeNode t, Node prog, bool do_pre_norm, bool do_post_norm ) {
-  if( do_pre_norm ){
-    std::map< TypeNode, int > var_count;
-    std::map< Node, Node > subs;
-    prog = getSygusNormalized( prog, var_count, subs );
-  }
-  std::map< Node, Node >::iterator itn = d_normalized[t].find( prog );
-  if( itn==d_normalized[t].end() ){
-    Node progr = Node::fromExpr( smt::currentSmtEngine()->expandDefinitions( prog.toExpr() ) );
-    progr = Rewriter::rewrite( progr );
-    if( do_post_norm ){
-      std::map< TypeNode, int > var_count;
-      std::map< Node, Node > subs;
-      progr = getSygusNormalized( progr, var_count, subs );
-    }
-    Trace("sygus-sym-break2") << "...rewrites to " << progr << std::endl;
-    d_normalized[t][prog] = progr;
-    return progr;
-  }else{
-    return itn->second;
-  }
-}
-
-unsigned TermDbSygus::getSygusTermSize( Node n ){
-  if( n.getNumChildren()==0 ){
-    return 0;
-  }else{
-    unsigned sum = 0;
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      sum += getSygusTermSize( n[i] );
-    }
-    return 1+sum;
-  }
-}
-
-unsigned TermDbSygus::getSygusConstructors( Node n, std::vector< Node >& cons ) {
-  Assert( n.getKind()==APPLY_CONSTRUCTOR );
-  Node op = n.getOperator();
-  if( std::find( cons.begin(), cons.end(), op )==cons.end() ){
-    cons.push_back( op );
-  }
-  if( n.getNumChildren()==0 ){
-    return 0;
-  }else{
-    unsigned sum = 0;
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      sum += getSygusConstructors( n[i], cons );
-    }
-    return 1+sum;
-  }
-}
-  
-bool TermDbSygus::isAntisymmetric( Kind k, Kind& dk ) {
-  if( k==GT ){
-    dk = LT;
-    return true;
-  }else if( k==GEQ ){
-    dk = LEQ;
-    return true;
-  }else if( k==BITVECTOR_UGT ){
-    dk = BITVECTOR_ULT;
-    return true;
-  }else if( k==BITVECTOR_UGE ){
-    dk = BITVECTOR_ULE;
-    return true;
-  }else if( k==BITVECTOR_SGT ){
-    dk = BITVECTOR_SLT;
-    return true;
-  }else if( k==BITVECTOR_SGE ){
-    dk = BITVECTOR_SLE;
-    return true;
-  }else{
-    return false;
-  }
-}
-
-bool TermDbSygus::isIdempotentArg( Node n, Kind ik, int arg ) {
-  // these should all be binary operators
-  //Assert( ik!=DIVISION && ik!=INTS_DIVISION && ik!=INTS_MODULUS && ik!=BITVECTOR_UDIV );
-  TypeNode tn = n.getType();
-  if( n==getTypeValue( tn, 0 ) ){
-    if( ik==PLUS || ik==OR || ik==XOR || ik==BITVECTOR_PLUS || ik==BITVECTOR_OR || ik==BITVECTOR_XOR || ik==STRING_CONCAT ){
-      return true;
-    }else if( ik==MINUS || ik==BITVECTOR_SHL || ik==BITVECTOR_LSHR || ik==BITVECTOR_ASHR || ik==BITVECTOR_SUB || 
-              ik==BITVECTOR_UREM || ik==BITVECTOR_UREM_TOTAL ){
-      return arg==1;
-    }
-  }else if( n==getTypeValue( tn, 1 ) ){
-    if( ik==MULT || ik==BITVECTOR_MULT ){
-      return true;
-    }else if( ik==DIVISION || ik==DIVISION_TOTAL || ik==INTS_DIVISION || ik==INTS_DIVISION_TOTAL || 
-              ik==INTS_MODULUS || ik==INTS_MODULUS_TOTAL || 
-              ik==BITVECTOR_UDIV_TOTAL || ik==BITVECTOR_UDIV || ik==BITVECTOR_SDIV ){
-      return arg==1;
-    }
-  }else if( n==getTypeMaxValue( tn ) ){
-    if( ik==EQUAL || ik==BITVECTOR_AND || ik==BITVECTOR_XNOR ){
-      return true;
-    }
-  }
-  return false;
-}
-
-
-Node TermDbSygus::isSingularArg( Node n, Kind ik, int arg ) {
-  TypeNode tn = n.getType();
-  if( n==getTypeValue( tn, 0 ) ){
-    if( ik==AND || ik==MULT || ik==BITVECTOR_AND || ik==BITVECTOR_MULT ){
-      return n;
-    }else if( ik==BITVECTOR_SHL || ik==BITVECTOR_LSHR || ik==BITVECTOR_ASHR || 
-              ik==BITVECTOR_UREM || ik==BITVECTOR_UREM_TOTAL ){
-      if( arg==0 ){
-        return n;
-      }
-    }else if( ik==BITVECTOR_UDIV_TOTAL || ik==BITVECTOR_UDIV || ik==BITVECTOR_SDIV ){
-      if( arg==0 ){
-        return n;
-      }else if( arg==1 ){
-        return getTypeMaxValue( tn );
-      }
-    }else if( ik==DIVISION || ik==DIVISION_TOTAL || ik==INTS_DIVISION || ik==INTS_DIVISION_TOTAL || 
-              ik==INTS_MODULUS || ik==INTS_MODULUS_TOTAL  ){
-      if( arg==0 ){
-        return n;
-      }else{
-        //TODO?
-      }
-    }else if( ik==STRING_SUBSTR ){
-      if( arg==0 ){
-        return n;
-      }else if( arg==2 ){
-        return getTypeValue( NodeManager::currentNM()->stringType(), 0 );
-      }
-    }else if( ik==STRING_STRIDOF ){
-      if( arg==0 || arg==1 ){
-        return getTypeValue( NodeManager::currentNM()->integerType(), -1 );
-      }
-    }
-  }else if( n==getTypeValue( tn, 1 ) ){
-    if( ik==BITVECTOR_UREM_TOTAL ){
-      return getTypeValue( tn, 0 );
-    }
-  }else if( n==getTypeMaxValue( tn ) ){
-    if( ik==OR || ik==BITVECTOR_OR ){
-      return n;
-    }
-  }else{
-    if( n.getType().isReal() && n.getConst<Rational>().sgn()<0 ){
-      // negative arguments
-      if( ik==STRING_SUBSTR || ik==STRING_CHARAT ){
-        return getTypeValue( NodeManager::currentNM()->stringType(), 0 );
-      }else if( ik==STRING_STRIDOF ){
-        Assert( arg==2 );
-        return getTypeValue( NodeManager::currentNM()->integerType(), -1 );
-      }
-    }
-  }
-  return Node::null();
-}
-
-bool TermDbSygus::hasOffsetArg( Kind ik, int arg, int& offset, Kind& ok ) {
-  if( ik==LT ){
-    Assert( arg==0 || arg==1 );
-    offset = arg==0 ? 1 : -1;
-    ok = LEQ;
-    return true;
-  }else if( ik==BITVECTOR_ULT ){
-    Assert( arg==0 || arg==1 );
-    offset = arg==0 ? 1 : -1;
-    ok = BITVECTOR_ULE;
-    return true;
-  }else if( ik==BITVECTOR_SLT ){
-    Assert( arg==0 || arg==1 );
-    offset = arg==0 ? 1 : -1;
-    ok = BITVECTOR_SLE;
-    return true;
-  }
-  return false;
-}
-
-
-
-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::TermDb::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( 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 = 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( 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 = 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 = getTypeMaxValue( c.getType() );
-    Node zero_c = getTypeValue( c.getType(), 0 );
-    Node one_c = 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 = getTypeValue( sygusToBuiltinType( tnc ), 0 );
-      solve_ret = getConstConsNum( tn, builtin );
-      if( solve_ret!=-1 ){
-        // t - s    ----->  ( 0 - s ) + t
-        rt.d_req_kind = 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;
-}
-
-Node TermDbSygus::getTypeValue( TypeNode tn, int val ) {
-  std::map< int, Node >::iterator it = d_type_value[tn].find( val );
-  if( it==d_type_value[tn].end() ){
-    Node n;
-    if( tn.isInteger() || tn.isReal() ){
-      Rational c(val);
-      n = NodeManager::currentNM()->mkConst( c );
-    }else if( tn.isBitVector() ){
-      unsigned int uv = val;
-      BitVector bval(tn.getConst<BitVectorSize>(), uv);
-      n = NodeManager::currentNM()->mkConst<BitVector>(bval);
-    }else if( tn.isBoolean() ){
-      if( val==0 ){
-        n = d_false;
-      }
-    }else if( tn.isString() ){
-      if( val==0 ){
-        n = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
-      }
-    }
-    d_type_value[tn][val] = n;
-    return n;
-  }else{
-    return it->second;
-  }
-}
-
-Node TermDbSygus::getTypeMaxValue( TypeNode tn ) {
-  std::map< TypeNode, Node >::iterator it = d_type_max_value.find( tn );
-  if( it==d_type_max_value.end() ){
-    Node n;
-    if( tn.isBitVector() ){
-      n = bv::utils::mkOnes(tn.getConst<BitVectorSize>());
-    }else if( tn.isBoolean() ){
-      n = d_true;
-    }
-    d_type_max_value[tn] = n;
-    return n;
-  }else{
-    return it->second;
-  }
-}
-
-Node TermDbSygus::getTypeValueOffset( TypeNode tn, Node val, int offset, int& status ) {
-  std::map< int, Node >::iterator it = d_type_value_offset[tn][val].find( offset );
-  if( it==d_type_value_offset[tn][val].end() ){
-    Node val_o;
-    Node offset_val = getTypeValue( tn, offset );
-    status = -1;
-    if( !offset_val.isNull() ){
-      if( tn.isInteger() || tn.isReal() ){
-        val_o = Rewriter::rewrite( NodeManager::currentNM()->mkNode( PLUS, val, offset_val ) );
-        status = 0;
-      }else if( tn.isBitVector() ){
-        val_o = Rewriter::rewrite( NodeManager::currentNM()->mkNode( BITVECTOR_PLUS, val, offset_val ) );
-        // TODO : enable?  watch for overflows
-      }
-    }
-    d_type_value_offset[tn][val][offset] = val_o;
-    d_type_value_offset_status[tn][val][offset] = status;
-    return val_o;
-  }else{
-    status = d_type_value_offset_status[tn][val][offset];
-    return it->second;
-  }
-}
-
-struct sortConstants {
-  TermDbSygus * d_tds;
-  Kind d_comp_kind;
-  bool operator() (Node i, Node j) {
-    if( i!=j ){
-      return d_tds->doCompare( i, j, d_comp_kind );
-    }else{
-      return false;
-    }
-  }
-};
-
-class ReconstructTrie {
-public:
-  std::map< Node, ReconstructTrie > d_children;
-  std::vector< Node > d_reconstruct;
-  void add( std::vector< Node >& cons, Node r, unsigned index = 0 ){
-    if( index==cons.size() ){
-      d_reconstruct.push_back( r );
-    }else{
-      d_children[cons[index]].add( cons, r, index+1 );
-    }
-  }
-  Node getReconstruct( std::map< Node, int >& rcons, unsigned depth ) {
-    if( !d_reconstruct.empty() ){
-      for( unsigned i=0; i<d_reconstruct.size(); i++ ){
-        Node r = d_reconstruct[i];
-        if( rcons[r]==0 ){
-          Trace("sygus-static-enum") << "...eliminate constructor " << r << std::endl;
-          rcons[r] = 1;
-          return r;
-        }
-      }
-    }
-    if( depth>0 ){
-      for( unsigned w=0; w<2; w++ ){
-        for( std::map< Node, ReconstructTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
-          Node n = it->first;
-          if( ( w==0 && rcons[n]!=0 ) || ( w==1 && rcons[n]==0 ) ){
-            Node r = it->second.getReconstruct( rcons, depth - w );
-            if( !r.isNull() ){
-              if( w==1 ){
-                Trace("sygus-static-enum") << "...use " << n << " to eliminate constructor " << r << std::endl;
-                rcons[n] = -1;
-              }
-              return r;
-            }
-          }
-        }
-      }
-    }
-    return Node::null();
-  }
-};
-
-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
-        }
-        //for constant reconstruction
-        Kind ck = getComparisonKind( TypeNode::fromType( dt.getSygusType() ) );
-        Node z = getTypeValue( TypeNode::fromType( dt.getSygusType() ), 0 );
-        d_const_list_pos[tn] = 0;
-        //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_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 );
-          }
-          d_ops[tn][n] = i;
-          d_arg_ops[tn][i] = n;
-          Trace("sygus-db") << std::endl;
-        }
-        //sort the constant list
-        if( !d_const_list[tn].empty() ){
-          if( ck!=UNDEFINED_KIND ){
-            sortConstants sc;
-            sc.d_comp_kind = ck;
-            sc.d_tds = this;
-            std::sort( d_const_list[tn].begin(), d_const_list[tn].end(), sc );
-          }
-          Trace("sygus-db") << "Type has " << d_const_list[tn].size() << " constants..." << std::endl << "  ";
-          for( unsigned i=0; i<d_const_list[tn].size(); i++ ){
-            Trace("sygus-db") << d_const_list[tn][i] << " ";
-          }
-          Trace("sygus-db") << std::endl;
-          Trace("sygus-db") << "Of these, " << d_const_list_pos[tn] << " are marked as positive." << 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 ) );
-          }
-        }
-        
-        //compute the redundant operators
-        if( options::sygusMinGrammar() ){
-          for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-            bool nred = true;
-            Trace("sygus-split-debug") << "Is " << dt[i].getName() << " a redundant operator?" << std::endl;
-            Kind ck = getConsNumKind( tn, i );
-            if( ck!=UNDEFINED_KIND ){
-              Kind dk;
-              if( isAntisymmetric( ck, dk ) ){
-                int j = getKindConsNum( tn, dk );
-                if( j!=-1 ){
-                  Trace("sygus-split-debug") << "Possible redundant operator : " << ck << " with " << dk << std::endl;
-                  //check for type mismatches
-                  bool success = true;
-                  for( unsigned k=0; k<2; k++ ){
-                    unsigned ko = k==0 ? 1 : 0;
-                    TypeNode tni = TypeNode::fromType( ((SelectorType)dt[i][k].getType()).getRangeType() );
-                    TypeNode tnj = TypeNode::fromType( ((SelectorType)dt[j][ko].getType()).getRangeType() );
-                    if( tni!=tnj ){
-                      Trace("sygus-split-debug") << "Argument types " << tni << " and " << tnj << " are not equal." << std::endl;
-                      success = false;
-                      break;
-                    }
-                  }
-                  if( success ){
-                    Trace("sygus-nf") << "* Sygus norm " << dt.getName() << " : do not consider any " << ck << " terms." << std::endl;
-                    nred = false;
-                  }
-                }
-              }
-            }
-            if( nred ){
-              Trace("sygus-split-debug") << "Check " << dt[i].getName() << " based on generic rewriting" << std::endl;
-              std::map< TypeNode, int > var_count;
-              std::map< int, Node > pre;
-              Node g = mkGeneric( dt, i, var_count, pre );
-              nred = !computeGenericRedundant( tn, g );
-              Trace("sygus-split-debug") << "...done check " << dt[i].getName() << " based on generic rewriting" << std::endl;
-            }
-            d_sygus_red_status[tn].push_back( nred ? 0 : 1 );
-          }
-          // run an enumerator for this type
-          if( options::sygusMinGrammarAgg() ){
-            TypeEnumerator te(tn);
-            unsigned count = 0;
-            std::map< Node, std::vector< Node > > builtin_to_orig;
-            Trace("sygus-static-enum") << "Static enumerate " << dt.getName() << "..." << std::endl;
-            while( !te.isFinished() && count<1000 ){
-              Node n = *te;
-              Node bn = sygusToBuiltin( n, tn );
-              Trace("sygus-static-enum") << "  " << bn;
-              Node bnr = Rewriter::rewrite( bn );
-              Trace("sygus-static-enum") << "  ..." << bnr << std::endl;
-              builtin_to_orig[bnr].push_back( n );
-              ++te;
-              count++;
-            }
-            std::map< Node, bool > reserved;
-            for( unsigned i=0; i<=2; i++ ){
-              Node rsv = i==2 ? getTypeMaxValue( btn ) : getTypeValue( btn, i );
-              if( !rsv.isNull() ){
-                reserved[ rsv ] = true;
-              }
-            }
-            Trace("sygus-static-enum") << "...make the reconstruct index data structure..." << std::endl;
-            ReconstructTrie rt;
-            std::map< Node, int > rcons;
-            unsigned max_depth = 0;
-            for( std::map< Node, std::vector< Node > >::iterator itb = builtin_to_orig.begin(); itb != builtin_to_orig.end(); ++itb ){
-              if( itb->second.size()>0 ){
-                std::map< Node, std::vector< Node > > clist;
-                Node single_cons;
-                for( unsigned j=0; j<itb->second.size(); j++ ){
-                  Node e = itb->second[j];
-                  getSygusConstructors( e, clist[e] );
-                  if( clist[e].size()>max_depth ){
-                    max_depth = clist[e].size();
-                  }
-                  for( unsigned k=0; k<clist[e].size(); k++ ){
-                    /*
-                    unsigned cindex = Datatype::indexOf( clist[e][k].toExpr() );
-                    if( isGenericRedundant( tn, cindex ) ){
-                      is_gen_redundant = true;
-                      break;
-                    }else{
-                    */
-                    rcons[clist[e][k]] = 0;
-                  }
-                  //if( is_gen_redundant ){
-                  //  clist.erase( e );
-                  //}else{
-                  if( clist[e].size()==1 ){
-                    Trace("sygus-static-enum") << "...single constructor term : " << e << ", builtin is " << itb->first << ", cons is " << clist[e][0] << std::endl;
-                    if( single_cons.isNull() ){
-                      single_cons = clist[e][0];
-                    }else{
-                      Trace("sygus-static-enum") << "*** already can eliminate constructor " << clist[e][0] << std::endl;
-                      unsigned cindex =  Datatype::indexOf( clist[e][0].toExpr() );
-                      d_sygus_red_status[tn][cindex] = 1;
-                    }
-                  }
-                  //}
-                }
-                // do not eliminate 0, 1, or max
-                if( !single_cons.isNull() && reserved.find( itb->first )==reserved.end() ){
-                  Trace("sygus-static-enum") << "...possibly elim " << single_cons << std::endl;
-                  for( std::map< Node, std::vector< Node > >::iterator itc = clist.begin(); itc != clist.end(); ++itc ){
-                    if( std::find( itc->second.begin(), itc->second.end(), single_cons )==itc->second.end() ){
-                      rt.add( itc->second, single_cons );
-                    }
-                  }
-                }
-              }
-            }
-            Trace("sygus-static-enum") << "...compute reconstructions..." << std::endl;
-            Node next_rcons;
-            do {
-              unsigned depth = 0;
-              do{
-                next_rcons = rt.getReconstruct( rcons, depth );
-                depth++;
-              }while( next_rcons.isNull() && depth<=max_depth );
-              // if we found a constructor to eliminate
-              if( !next_rcons.isNull() ){
-                Trace("sygus-static-enum") << "*** eliminate constructor " << next_rcons << std::endl;
-                unsigned cindex =  Datatype::indexOf( next_rcons.toExpr() );
-                d_sygus_red_status[tn][cindex] = 2;
-              }
-            }while( !next_rcons.isNull() );
-            Trace("sygus-static-enum") << "...finished..." << std::endl;
-          }
-        }else{
-          // assume all are non-redundant
-          for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-            d_sygus_red_status[tn].push_back( 0 );
-          }
-        }
-      }
-    }
-  }
-}
-
-void TermDbSygus::registerMeasuredTerm( Node e, Node root, bool mkActiveGuard ) {
-  Assert( d_measured_term.find( e )==d_measured_term.end() );
-  Trace("sygus-db") << "Register measured term : " << e << " with root " << root << std::endl;
-  d_measured_term[e] = root;
-  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_measured_term_active_guard[e] = eg;
-  }
-}
-
-void TermDbSygus::registerPbeExamples( Node e, std::vector< std::vector< Node > >& exs, 
-                                       std::vector< Node >& exos, std::vector< Node >& exts  ) {
-  Trace("sygus-db") << "Register " << exs.size() << " PBE examples with " << e << std::endl;
-  Assert( d_measured_term.find( e )==d_measured_term.end() || isMeasuredTerm( e )==e );
-  Assert( d_pbe_exs.find( e )==d_pbe_exs.end() );
-  Assert( exs.size()==exos.size() );
-  d_pbe_exs[e] = exs;
-  d_pbe_exos[e] = exos;
-  for( unsigned i=0; i<exts.size(); i++ ){
-    Trace("sygus-db-debug") << "  # " << i << " : " << exts[i] << std::endl;
-    Assert( exts[i].getKind()==APPLY_UF );
-    Assert( exts[i][0]==e );
-    d_pbe_term_id[exts[i]] = i;
-  }
-}
-
-Node TermDbSygus::isMeasuredTerm( Node e ) {
-  std::map< Node, Node >::iterator itm = d_measured_term.find( e );
-  if( itm!=d_measured_term.end() ){
-    return itm->second;
-  }else{
-    return Node::null();
-  }
-}
-
-Node TermDbSygus::getActiveGuardForMeasureTerm( Node e ) {
-  std::map< Node, Node >::iterator itag = d_measured_term_active_guard.find( e );
-  if( itag!=d_measured_term_active_guard.end() ){
-    return itag->second;
-  }else{
-    return Node::null();
-  }
-}
-
-void TermDbSygus::getMeasuredTerms( std::vector< Node >& mts ) {
-  for( std::map< Node, Node >::iterator itm = d_measured_term.begin(); itm != d_measured_term.end(); ++itm ){
-    mts.push_back( itm->first );
-  }
-}
-
-bool TermDbSygus::hasPbeExamples( Node e ) {
-  return d_pbe_exs.find( e )!=d_pbe_exs.end();
-}
-
-unsigned TermDbSygus::getNumPbeExamples( Node e ) {
-  std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_pbe_exs.find( e );
-  if( it!=d_pbe_exs.end() ){
-    return it->second.size();
-  }else{
-    return 0;
-  }
-}
-
-void TermDbSygus::getPbeExample( Node e, unsigned i, std::vector< Node >& ex ) {
-  std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_pbe_exs.find( e );
-  if( it!=d_pbe_exs.end() ){
-    Assert( i<it->second.size() );
-    Assert( i<d_pbe_exos[e].size() );
-    ex.insert( ex.end(), it->second[i].begin(), it->second[i].end() );
-  }else{
-    Assert( false );
-  }
-}
-Node TermDbSygus::getPbeExampleOut( Node e, unsigned i ) {
-  std::map< Node, std::vector< Node > >::iterator it = d_pbe_exos.find( e );
-  if( it!=d_pbe_exos.end() ){
-    Assert( i<it->second.size() );
-    return it->second[i];
-  }else{
-    Assert( false );
-    return Node::null();
-  }
-}
-
-int TermDbSygus::getPbeExampleId( Node n ) {
-  std::map< Node, unsigned >::iterator it = d_pbe_term_id.find( n );
-  if( it!=d_pbe_term_id.end() ){
-    return it->second;
-  }else{
-    return -1;
-  }
-}
-
-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( !isGenericRedundant( tn, 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 ) );
-  Assert( !isGenericRedundant( tn, cindex ) );
-  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;
-  }
-}
-
-
-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;
-  }
-}
-
-unsigned TermDbSygus::getNumIdFuncs( TypeNode tn ) {
-  return d_id_funcs[tn].size();
-}
-
-unsigned TermDbSygus::getIdFuncIndex( TypeNode tn, unsigned i ) {
-  return d_id_funcs[tn][i];
-}
-
-TypeNode TermDbSygus::getArgType( const DatatypeConstructor& c, int i ) {
-  Assert( i>=0 && i<(int)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( QuantArith::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( QuantArith::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;
-  }
-}
-
-bool TermDbSygus::doCompare( Node a, Node b, Kind k ) {
-  Node com = NodeManager::currentNM()->mkNode( k, a, b );
-  com = Rewriter::rewrite( com );
-  return com==d_true;
-}
-
-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]==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( smt::currentSmtEngine()->isDefinedFunction( op.toExpr() ) ){
-    return APPLY;
-  }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{
-      return NodeManager::operatorToKind( op );
-    }
-  }
-}
-
-void TermDbSygus::printSygusTerm( std::ostream& out, Node n, std::vector< Node >& lvs ) {
-  if( n.getKind()==APPLY_CONSTRUCTOR ){
-    TypeNode tn = n.getType();
-    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-    if( dt.isSygus() ){
-      int cIndex = Datatype::indexOf( n.getOperator().toExpr() );
-      Assert( !dt[cIndex].getSygusOp().isNull() );
-      if( dt[cIndex].getSygusLetBody().isNull() ){
-        if( n.getNumChildren()>0 ){
-          out << "(";
-        }
-        Node op = dt[cIndex].getSygusOp();
-        if( op.getType().isBitVector() && op.isConst() ){
-          //print in the style it was given
-          Trace("sygus-print-bvc") << "[Print " << op << " " << dt[cIndex].getName() << "]" << std::endl;
-          std::stringstream ss;
-          ss << dt[cIndex].getName();
-          std::string str = ss.str();
-          std::size_t found = str.find_last_of("_");
-          Assert( found!=std::string::npos );
-          std::string name = std::string( str.begin() + found +1, str.end() );
-          out << name;
-        }else{
-          out << op;
-        }
-        if( n.getNumChildren()>0 ){
-          for( unsigned i=0; i<n.getNumChildren(); i++ ){
-            out << " ";
-            printSygusTerm( out, n[i], lvs );
-          }
-          out << ")";
-        }
-      }else{
-        std::stringstream let_out;
-        //print as let term
-        if( dt[cIndex].getNumSygusLetInputArgs()>0 ){
-          let_out << "(let (";
-        }
-        std::vector< Node > subs_lvs;
-        std::vector< Node > new_lvs;
-        for( unsigned i=0; i<dt[cIndex].getNumSygusLetArgs(); i++ ){
-          Node v = Node::fromExpr( dt[cIndex].getSygusLetArg( i ) );
-          subs_lvs.push_back( v );
-          std::stringstream ss;
-          ss << "_l_" << new_lvs.size();
-          Node lv = NodeManager::currentNM()->mkBoundVar( ss.str(), v.getType() );
-          new_lvs.push_back( lv );
-          //map free variables to proper terms
-          if( i<dt[cIndex].getNumSygusLetInputArgs() ){
-            //it should be printed as a let argument
-            let_out << "(";
-            let_out << lv << " " << lv.getType() << " ";
-            printSygusTerm( let_out, n[i], lvs );
-            let_out << ")";
-          }
-        }
-        if( dt[cIndex].getNumSygusLetInputArgs()>0 ){
-          let_out << ") ";
-        }
-        //print the body
-        Node let_body = Node::fromExpr( dt[cIndex].getSygusLetBody() );
-        let_body = let_body.substitute( subs_lvs.begin(), subs_lvs.end(), new_lvs.begin(), new_lvs.end() );
-        new_lvs.insert( new_lvs.end(), lvs.begin(), lvs.end() );
-        printSygusTerm( let_out, let_body, new_lvs );
-        if( dt[cIndex].getNumSygusLetInputArgs()>0 ){
-          let_out << ")";
-        }
-        //do variable substitutions since ASSUMING : let_vars are interpreted literally and do not represent a class of variables
-        std::string lbody = let_out.str();
-        for( unsigned i=0; i<dt[cIndex].getNumSygusLetArgs(); i++ ){
-          std::stringstream old_str;
-          old_str << new_lvs[i];
-          std::stringstream new_str;
-          if( i>=dt[cIndex].getNumSygusLetInputArgs() ){
-            printSygusTerm( new_str, n[i], lvs );
-          }else{
-            new_str << Node::fromExpr( dt[cIndex].getSygusLetArg( i ) );
-          }
-          doStrReplace( lbody, old_str.str().c_str(), new_str.str().c_str() );
-        }
-        out << lbody;
-      }
-      return;
-    }
-  }else if( !n.getAttribute(SygusProxyAttribute()).isNull() ){
-    out << n.getAttribute(SygusProxyAttribute());
-  }else{
-    out << n;
-  }
-}
-
-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() ){
-      Trace("sygus-eager") << "TermDbSygus::eager: Register eval term : " << n << std::endl;
-      TypeNode tn = n[0].getType();
-      if( tn.isDatatype() ){
-        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-        if( dt.isSygus() ){
-          Node f = n.getOperator();
-          Trace("sygus-eager") << "...the evaluation function is : " << f << std::endl;
-          if( n[0].getKind()!=APPLY_CONSTRUCTOR ){
-            // check if it directly occurs in an input/ouput example
-            int pbe_id = getPbeExampleId( n );
-            if( pbe_id!=-1 ){
-              Node n_res = getPbeExampleOut( n[0], pbe_id );
-              if( !n_res.isNull() ){
-                Trace("sygus-eager") << "......do not evaluate " << n << " since it is an input/output example : " << n_res << std::endl;
-                return;
-              }
-            }
-            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;
-        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 = d_quantEngine->getTermDatabaseSygus()->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() );
-            esit.d_conj = NodeManager::currentNM()->mkNode( kind::APPLY_UF, eval_children );
-            esit.d_var = n;
-            eval_children[1] = vn;
-            Node eval_fun = NodeManager::currentNM()->mkNode( kind::APPLY_UF, eval_children );
-            esit.d_result = evaluateWithUnfolding( eval_fun );
-            res = esit.d_result;
-            eval_children.resize( 2 );  
-            eval_children[1] = n;
-            
-            //evaluate with minimal explanation
-            std::vector< Node > mexp;
-            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();
-      }
-    }
-  }
-}
-
-void TermDbSygus::getExplanationForConstantEquality( Node n, Node vn, std::vector< Node >& exp ) {
-  std::map< unsigned, bool > cexc;
-  getExplanationForConstantEquality( n, vn, exp, cexc );
-}
-
-void TermDbSygus::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 TermDbSygus::getExplanationForConstantEquality( Node n, Node vn ) {
-  std::map< unsigned, bool > cexc;
-  return getExplanationForConstantEquality( n, vn, cexc );
-}
-
-Node TermDbSygus::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 TermDbSygus::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 by a fresh variable and rewriting again
-  for( unsigned i=0; i<vn.getNumChildren(); i++ ){
-    TypeNode xtn = vn[i].getType();
-    Node x = getFreeVarInc( xtn, var_count );
-    trb.replaceChild( i, x );
-    Node nvn = trb.build();
-    Assert( nvn.getKind()==kind::APPLY_CONSTRUCTOR );
-    if( et.is_invariant( this, nvn, x ) ){
-      cexc[i] = true;
-      // we are tracking term size if positive
-      if( sz>=0 ){
-        int s = 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 = d_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 TermDbSygus::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 TermDbSygus::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 );
-}
-
-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 if( ret.getKind()==APPLY ){
-      //must expand definitions to account for defined functions in sygus grammars
-      ret = Node::fromExpr( smt::currentSmtEngine()->expandDefinitions( ret.toExpr() ) );
-    }
-    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()==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()==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::evaluateBuiltin( TypeNode tn, Node bn, Node ar, unsigned i ) {
-  std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_pbe_exs.find( ar );
-  if( it!=d_pbe_exs.end() ){
-    Assert( i<it->second.size() );
-    return evaluateBuiltin( tn, bn, it->second[i] );
-  }else{
-    return Rewriter::rewrite( bn );
-  }
-}
-
-Node TermDbSygus::evaluateWithUnfolding( Node n, std::map< Node, Node >& visited ) {
-  std::map< Node, Node >::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 );
-      }
-      // TODO : extended rewrite?
-      ret = extendedRewrite( ret );
-    }
-    visited[n] = ret;
-    return ret;
-  }else{
-    return it->second;
-  }
-}
-
-Node TermDbSygus::evaluateWithUnfolding( Node n ) {
-  std::map< Node, Node > visited;
-  return evaluateWithUnfolding( n, visited );
-}
-
-bool TermDbSygus::computeGenericRedundant( TypeNode tn, Node g ) {
-  //everything added to this cache should be mutually exclusive cases
-  std::map< Node, bool >::iterator it = d_gen_redundant[tn].find( g );
-  if( it==d_gen_redundant[tn].end() ){
-    Trace("sygus-gnf") << "Register generic for " << tn << " : " << g << std::endl;
-    Node gr = getNormalized( tn, g, false );
-    Trace("sygus-gnf-debug") << "Generic " << g << " rewrites to " << gr << std::endl;
-    std::map< Node, Node >::iterator itg = d_gen_terms[tn].find( gr );
-    bool red = true;
-    if( itg==d_gen_terms[tn].end() ){
-      red = false;
-      d_gen_terms[tn][gr] = g;
-      Trace("sygus-gnf-debug") << "...not redundant." << std::endl;
-      Trace("sygus-nf-reg") << "*** Sygus (generic) normal form : normal form of " << g << " is " << gr << std::endl;
-    }else{
-      Trace("sygus-gnf-debug") << "...redundant." << std::endl;
-      Trace("sygus-nf") << "* Sygus normal form : simplify since " << g << " and " << itg->second << " both rewrite to " << gr << std::endl;
-    }
-    d_gen_redundant[tn][g] = red;
-    return red;
-  }else{
-    return it->second;
-  }
-}
-
-bool TermDbSygus::isGenericRedundant( TypeNode tn, unsigned i ) {
-  Assert( i<d_sygus_red_status[tn].size() );
-  if( options::sygusMinGrammarAgg() ){
-    return d_sygus_red_status[tn][i]!=0;
-  }else{
-    return d_sygus_red_status[tn][i]==1;
-  }
-}
-
-Node TermDbSygus::PbeTrie::addPbeExample( TypeNode etn, Node e, Node b, quantifiers::TermDbSygus * tds, unsigned index, unsigned ntotal ) {
-  Assert( tds->getNumPbeExamples( e )==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    
-        tds->getPbeExample( e, index, ex );
-        addPbeExampleEval( etn, e, d_lazy_child, ex, tds, index, ntotal );
-        Assert( !d_children.empty() );
-        d_lazy_child = Node::null();
-      }
-    }else{
-      tds->getPbeExample( e, index, ex );
-    }
-    return addPbeExampleEval( etn, e, b, ex, tds, index, ntotal );
-  }
-}
-
-Node TermDbSygus::PbeTrie::addPbeExampleEval( TypeNode etn, Node e, Node b, std::vector< Node >& ex, quantifiers::TermDbSygus * tds, unsigned index, unsigned ntotal ) {
-  Node eb = tds->evaluateBuiltin( etn, b, ex );
-  return d_children[eb].addPbeExample( etn, e, b, tds, index+1, ntotal );
-}
-
-Node TermDbSygus::addPbeSearchVal( TypeNode tn, Node e, Node bvr ){
-  Assert( !e.isNull() );
-  if( hasPbeExamples( e ) ){
-    unsigned nex = getNumPbeExamples( e );
-    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 TermDbSygus::extendedRewritePullIte( Node n ) {
-  // generalize this?
-  Assert( n.getNumChildren()==2 );
-  Assert( n.getType().isBoolean() );
-  Assert( n.getMetaKind() != kind::metakind::PARAMETERIZED );
-  std::vector< Node > children;
-  for( unsigned i=0; i<n.getNumChildren(); i++ ){
-    children.push_back( n[i] );
-  }
-  for( unsigned i=0; i<2; i++ ){
-    if( n[i].getKind()==kind::ITE ){
-      for( unsigned j=0; j<2; j++ ){
-        children[i] = n[i][j+1];
-        Node eqr = extendedRewrite( NodeManager::currentNM()->mkNode( n.getKind(), children ) );
-        children[i] = n[i];
-        if( eqr.isConst() ){
-          std::vector< Node > new_children;
-          Kind new_k;
-          if( eqr==d_true ){
-            new_k = kind::OR;
-            new_children.push_back( j==0 ? n[i][0] : n[i][0].negate() );
-          }else{
-            Assert( eqr==d_false );
-            new_k = kind::AND;
-            new_children.push_back( j==0 ? n[i][0].negate() : n[i][0] );
-          }
-          children[i] = n[i][2-j];
-          Node rem_eq = NodeManager::currentNM()->mkNode( n.getKind(), children );
-          children[i] = n[i];
-          new_children.push_back( rem_eq );
-          Node nc = NodeManager::currentNM()->mkNode( new_k, new_children );
-          Trace("sygus-ext-rewrite") << "sygus-extr : " << n << " rewrites to " << nc << " by simple ITE pulling." << std::endl;
-          //recurse
-          return extendedRewrite( nc );
-        }
-      }
-    }
-  }
-  return Node::null();
-}
-
-Node TermDbSygus::extendedRewrite( Node n ) {
-  std::map< Node, Node >::iterator it = d_ext_rewrite_cache.find( n );
-  if( it == d_ext_rewrite_cache.end() ){
-    Node ret = n;
-    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 = extendedRewrite( n[i] );
-        childChanged = nc!=n[i] || childChanged;
-        children.push_back( nc );
-      }
-      Node ret;
-      if( childChanged ){
-        ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
-      }
-    }
-    ret = Rewriter::rewrite( n );
-    Trace("sygus-ext-rewrite-debug") << "Do extended rewrite on : " << ret << " (from " << n << ")" << std::endl; 
-
-    Node new_ret;
-    if( ret.getKind()==kind::EQUAL ){
-      // string equalities with disequal prefix or suffix
-      if( ret[0].getType().isString() ){
-        std::vector< Node > c[2];
-        for( unsigned i=0; i<2; i++ ){
-          strings::TheoryStringsRewriter::getConcat( ret[i], c[i] );
-        }
-        if( c[0].empty()==c[1].empty() ){
-          if( !c[0].empty() ){
-            for( unsigned i=0; i<2; i++ ){
-              unsigned index1 = i==0 ? 0 : c[0].size()-1;
-              unsigned index2 = i==0 ? 0 : c[1].size()-1;
-              if( c[0][index1].isConst() && c[1][index2].isConst() ){
-                CVC4::String s = c[0][index1].getConst<String>();
-                CVC4::String t = c[1][index2].getConst<String>();
-                unsigned len_short = s.size() <= t.size() ? s.size() : t.size();
-                bool isSameFix = i==1 ? s.rstrncmp(t, len_short): s.strncmp(t, len_short);
-                if( !isSameFix ){
-                  Trace("sygus-ext-rewrite") << "sygus-extr : " << ret << " rewrites to false due to disequal string prefix/suffix." << std::endl;
-                  new_ret = d_false;
-                  break;
-                }
-              }
-            }
-          }
-        }else{
-          new_ret = d_false;
-        }
-      }
-      if( new_ret.isNull() ){
-        // simple ITE pulling
-        new_ret = extendedRewritePullIte( ret );
-      }
-      // TODO : ( ~contains( x, y ) --> false ) => ( ~x=y --> false )
-    }else if( ret.getKind()==kind::ITE ){
-      Assert( ret[1]!=ret[2] );
-      if( ret[0].getKind()==NOT ){
-        ret = NodeManager::currentNM()->mkNode( kind::ITE, ret[0][0], ret[2], ret[1] );
-      }
-      if( ret[0].getKind()==kind::EQUAL ){
-        // simple invariant ITE
-        for( unsigned i=0; i<2; i++ ){
-          if( ret[1]==ret[0][i] && ret[2]==ret[0][1-i] ){
-            Trace("sygus-ext-rewrite") << "sygus-extr : " << ret << " rewrites to " << ret[2] << " due to simple invariant ITE." << std::endl;
-            new_ret = ret[2];
-            break;
-          }
-        }
-        // notice this is strictly more general that the above
-        if( new_ret.isNull() ){
-          // simple substitution
-          for( unsigned i=0; i<2; i++ ){
-            if( ret[0][i].isVar() && ( ( ret[0][1-i].isVar() && ret[0][i]<ret[0][1-i] ) || ret[0][1-i].isConst() ) ){
-              TNode r1 = ret[0][i];
-              TNode r2 = ret[0][1-i];
-              Node retn = ret[1].substitute( r1, r2 );
-              if( retn!=ret[1] ){
-                new_ret = NodeManager::currentNM()->mkNode( kind::ITE, ret[0], retn, ret[2] );
-                Trace("sygus-ext-rewrite") << "sygus-extr : " << ret << " rewrites to " << new_ret << " due to simple ITE substitution." << std::endl;
-              }
-            }
-          }
-        }
-      }
-    }else if( ret.getKind()==DIVISION || ret.getKind()==INTS_DIVISION || ret.getKind()==INTS_MODULUS ){
-      // rewrite as though total
-      std::vector< Node > children;
-      bool all_const = true;
-      for( unsigned i=0; i<ret.getNumChildren(); i++ ){
-        if( ret[i].isConst() ){
-          children.push_back( ret[i] );
-        }else{
-          all_const = false;
-          break;
-        }
-      }
-      if( all_const ){
-        Kind new_k = ( ret.getKind()==DIVISION ? DIVISION_TOTAL : ( ret.getKind()==INTS_DIVISION ? INTS_DIVISION_TOTAL : INTS_MODULUS_TOTAL ) ); 
-        new_ret = NodeManager::currentNM()->mkNode( new_k, children );
-        Trace("sygus-ext-rewrite") << "sygus-extr : " << ret << " rewrites to " << new_ret << " due to total interpretation." << std::endl;
-      }
-    }
-    // more expensive rewrites 
-    if( new_ret.isNull() ){
-      Trace("sygus-ext-rewrite-debug2")  << "Do expensive rewrites on " << ret << std::endl;
-      bool polarity = ret.getKind()!=NOT;
-      Node ret_atom = ret.getKind()==NOT ? ret[0] : ret;
-      if( ( ret_atom.getKind()==EQUAL && ret_atom[0].getType().isReal() ) || ret_atom.getKind()==GEQ ){
-        Trace("sygus-ext-rewrite-debug2")  << "Compute monomial sum " << ret_atom << std::endl;
-        //compute monomial sum
-        std::map< Node, Node > msum;
-        if( QuantArith::getMonomialSumLit( ret_atom, msum ) ){
-          for( std::map< Node, Node >::iterator itm = msum.begin(); itm != msum.end(); ++itm ){
-            Node v = itm->first;
-            Trace("sygus-ext-rewrite-debug2") << itm->first << " * " << itm->second << std::endl;
-            if( v.getKind()==ITE ){
-              Node veq;
-              int res = QuantArith::isolate( v, msum, veq, ret_atom.getKind() );
-              if( res!=0 ){
-                Trace("sygus-ext-rewrite-debug") << "  have ITE relation, solved form : " << veq << std::endl;
-                // try pulling ITE
-                new_ret = extendedRewritePullIte( veq );
-                if( !new_ret.isNull() ){
-                  if( !polarity ){
-                    new_ret = new_ret.negate();
-                  }
-                  break;
-                }
-              }else{
-                Trace("sygus-ext-rewrite-debug") << "  failed to isolate " << v << " in " << ret << std::endl;
-              }
-            }
-          }
-        }else{
-          Trace("sygus-ext-rewrite-debug") << "  failed to get monomial sum of " << ret << std::endl;
-        }
-      }else if( ret_atom.getKind()==ITE ){
-        // TODO : conditional rewriting
-      }else if( ret.getKind()==kind::AND || ret.getKind()==kind::OR ){
-        // TODO condition merging
-      }
-    }
-    
-    if( !new_ret.isNull() ){
-      ret = Rewriter::rewrite( new_ret );
-    }
-    d_ext_rewrite_cache[n] = ret;
-    return ret;
-  }else{
-    return it->second;
-  }
-}
-
-
-
-
-
-
-TypeNode TermDbSygus::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 TermDbSygus::mkSygusConstantsForType( TypeNode type, std::vector<CVC4::Node>& ops ) {
-  if( type.isInteger() ){
-    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 TermDbSygus::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 TermDbSygus::mkSygusDefaultGrammar( TypeNode range, Node bvl, const std::string& fun, std::map< TypeNode, std::vector< Node > >& extra_cons, 
-                                         std::vector< CVC4::Datatype >& datatypes, std::set<Type>& unres ) {
-  // collect the variables
-  std::vector<Node> sygus_vars;
-  if( !bvl.isNull() ){
-    for( unsigned i=0; i<bvl.getNumChildren(); i++ ){
-      sygus_vars.push_back( bvl[i] );
-    }
-  }
-  //if( !range.isBoolean() && !range.isInteger() && !range.isBitVector() && !range.isDatatype() ){
-  //  parseError("No default grammar for type.");
-  //}
-  std::vector< std::vector< Expr > > ops;
-  int startIndex = -1;
-  Trace("sygus-grammar-def") << "Construct default grammar for " << fun << " " << range << std::endl;
-  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].isInteger() ){
-      for( unsigned j=0; j<2; j++ ){
-        CVC4::Kind k = j==0 ? kind::PLUS : kind::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);
-      }
-    }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.back() << 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] );
-    }
-    //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].isInteger() ){
-      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 TermDbSygus::mkSygusDefaultType( TypeNode range, Node bvl, const std::string& fun, 
-                                          std::map< TypeNode, std::vector< Node > >& extra_cons ) {
-  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, 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] );
-}
-
 }/* CVC4::theory::quantifiers namespace */
 }/* CVC4::theory namespace */
 }/* CVC4 namespace */
index b1d4f7f2b336826f47ff8b1fb68ffb6a5e343091..f187e5989ab796998bb730e9c89c019fe78f0d1e 100644 (file)
@@ -574,293 +574,6 @@ public:
   static void computeQuantAttributes( Node q, QAttributes& qa );
 };/* class TermDb */
 
-class SygusInvarianceTest {
-protected:
-  // check whether nvn[ x ] should be excluded
-  virtual bool invariant( TermDbSygus * tds, Node nvn, Node x ) = 0;
-public:
-  bool is_invariant( TermDbSygus * tds, Node nvn, Node x ){
-    if( invariant( tds, nvn, x ) ){
-      d_update_nvn = nvn;
-      return true;
-    }else{
-      return false;
-    }
-  }
-  // result of the node after invariant replacements
-  Node d_update_nvn;
-};
-
-class EvalSygusInvarianceTest : public SygusInvarianceTest {
-public:
-  Node d_conj;
-  TNode d_var;
-  std::map< Node, Node > d_visited;
-  Node d_result;
-protected:
-  bool invariant( quantifiers::TermDbSygus * tds, Node nvn, Node x );
-};
-
-class TermDbSygus {
-private:
-  /** reference to the quantifiers engine */
-  QuantifiersEngine* d_quantEngine;
-  std::map< TypeNode, std::vector< Node > > d_fv[2];
-  std::map< Node, TypeNode > d_fv_stype;
-  std::map< Node, int > d_fv_num;
-  bool hasFreeVar( Node n, std::map< Node, bool >& visited );
-public:
-  Node d_true;
-  Node d_false;
-public:
-  TNode getFreeVar( TypeNode tn, int i, bool useSygusType = false );
-  TNode getFreeVarInc( TypeNode tn, std::map< TypeNode, int >& var_count, bool useSygusType = false );
-  bool isFreeVar( Node n ) { return d_fv_stype.find( n )!=d_fv_stype.end(); }
-  int getVarNum( Node n ) { return d_fv_num[n]; }
-  bool hasFreeVar( Node n );
-private:
-  std::map< TypeNode, std::map< int, Node > > d_generic_base;
-  std::map< TypeNode, std::vector< Node > > d_generic_templ;
-  bool getMatch( Node p, Node n, std::map< int, Node >& s );
-  bool getMatch2( Node p, Node n, std::map< int, Node >& s, std::vector< int >& new_s );
-public:
-  bool getMatch( Node n, TypeNode st, int& index_found, std::vector< Node >& args, int index_exc = -1, int index_start = 0 );
-private:
-  void computeMinTypeDepthInternal( TypeNode root_tn, TypeNode tn, unsigned type_depth );
-  bool involvesDivByZero( Node n, std::map< Node, bool >& visited );
-private:
-  // stores root
-  std::map< Node, Node > d_measured_term;
-  std::map< Node, Node > d_measured_term_active_guard;
-  //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::vector< int > > d_id_funcs;
-  std::map< TypeNode, std::vector< Node > > d_const_list; //sorted list of constants for type
-  std::map< TypeNode, unsigned > d_const_list_pos;
-  std::map< TypeNode, std::map< Node, Node > > d_semantic_skolem;
-  //information for builtin types
-  std::map< TypeNode, std::map< int, Node > > d_type_value;
-  std::map< TypeNode, Node > d_type_max_value;
-  std::map< TypeNode, std::map< Node, std::map< int, Node > > > d_type_value_offset;
-  std::map< TypeNode, std::map< Node, std::map< int, int > > > d_type_value_offset_status;
-  //normalized map
-  std::map< TypeNode, std::map< Node, Node > > d_normalized;
-  std::map< TypeNode, std::map< Node, Node > > d_sygus_to_builtin;
-  std::map< TypeNode, std::map< Node, Node > > d_builtin_const_to_sygus;
-  // 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;
-public:
-  TermDbSygus( context::Context* c, QuantifiersEngine* qe );
-  ~TermDbSygus(){}
-  bool reset( Theory::Effort e );
-  std::string identify() const { return "TermDbSygus"; }
-public:
-  /** register the sygus type */
-  void registerSygusType( TypeNode tn );
-  /** register a term that we will do enumerative search on */
-  void registerMeasuredTerm( Node e, Node root, bool mkActiveGuard = false );
-  /** is measured term */
-  Node isMeasuredTerm( Node e );
-  /** get active guard */
-  Node getActiveGuardForMeasureTerm( Node e );
-  /** get measured terms */
-  void getMeasuredTerms( std::vector< Node >& mts );
-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 );
-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 );
-  unsigned getNumIdFuncs( TypeNode tn );
-  unsigned getIdFuncIndex( TypeNode tn, unsigned i );
-  /** get arg type */
-  TypeNode getArgType( const DatatypeConstructor& c, int i );
-  /** get first occurrence */
-  int getFirstArgOccurrence( const DatatypeConstructor& c, TypeNode tn );
-  /** is type match */
-  bool isTypeMatch( const DatatypeConstructor& c1, const DatatypeConstructor& c2 );
-  /** isAntisymmetric */
-  bool isAntisymmetric( Kind k, Kind& dk );
-  /** is idempotent arg */
-  bool isIdempotentArg( Node n, Kind ik, int arg );
-  /** is singular arg */
-  Node isSingularArg( Node n, Kind ik, int arg );
-  /** get offset arg */
-  bool hasOffsetArg( Kind ik, int arg, int& offset, Kind& ok );
-  /** get value */
-  Node getTypeValue( TypeNode tn, int val );
-  /** get value */
-  Node getTypeValueOffset( TypeNode tn, Node val, int offset, int& status );
-  /** get value */
-  Node getTypeMaxValue( TypeNode tn );
-  TypeNode getSygusTypeForVar( Node v );
-  Node getGenericBase( TypeNode tn, const Datatype& dt, int c );
-  Node mkGeneric( const Datatype& dt, int c, std::map< TypeNode, int >& var_count, std::map< int, Node >& pre );
-  Node sygusToBuiltin( Node n, TypeNode tn );
-  Node sygusToBuiltin( Node n ) { return sygusToBuiltin( n, n.getType() ); }
-  Node sygusSubstituted( TypeNode tn, Node n, std::vector< Node >& args );
-  Node builtinToSygusConst( Node c, TypeNode tn, int rcons_depth = 0 );
-  Node getSygusNormalized( Node n, std::map< TypeNode, int >& var_count, std::map< Node, Node >& subs );
-  Node getNormalized( TypeNode t, Node prog, bool do_pre_norm = false, bool do_post_norm = true );
-  unsigned getSygusTermSize( Node n );
-  // returns size
-  unsigned getSygusConstructors( Node n, std::vector< Node >& cons );
-  /** 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 );
-  bool doCompare( Node a, Node b, Kind k );
-  // 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 );
-  /** print sygus term */
-  static void printSygusTerm( std::ostream& out, Node n, std::vector< Node >& lvs );
-
-  /** 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
-private:
-  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;
-
-  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 );
-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 );
-  // returns straightforward exp => n = vn
-  void getExplanationForConstantEquality( Node n, Node vn, std::vector< Node >& exp );
-  void getExplanationForConstantEquality( Node n, Node vn, std::vector< Node >& exp, std::map< unsigned, bool >& cexc );
-  Node getExplanationForConstantEquality( Node n, Node vn );
-  Node getExplanationForConstantEquality( Node n, Node vn, std::map< unsigned, bool >& cexc );
-  // we have n = vn => eval( n ) = bvr, returns exp => eval( n ) = bvr
-  //   ensures the explanation still allows for vnr
-  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 );
-  // builtin evaluation, returns rewrite( bn [ args / vars(tn) ] )
-  Node evaluateBuiltin( TypeNode tn, Node bn, std::vector< Node >& args );
-  Node evaluateBuiltin( TypeNode tn, Node bn, Node ar, unsigned i );
-  // evaluate with unfolding
-  Node evaluateWithUnfolding( Node n, std::map< Node, Node >& visited );
-  Node evaluateWithUnfolding( Node n );
-//for calculating redundant operators
-private:
-  //whether each constructor is redundant
-  // 0 : not redundant, 1 : redundant, 2 : partially redundant
-  std::map< TypeNode, std::vector< int > > d_sygus_red_status;
-  // type to (rewritten) to original
-  std::map< TypeNode, std::map< Node, Node > > d_gen_terms;
-  std::map< TypeNode, std::map< Node, bool > > d_gen_redundant;
-  //compute generic redundant
-  bool computeGenericRedundant( TypeNode tn, Node g );
-public:
-  bool isGenericRedundant( TypeNode tn, unsigned i );
-  
-//sygus pbe
-private:
-  std::map< Node, std::vector< std::vector< Node > > > d_pbe_exs;
-  std::map< Node, std::vector< Node > > d_pbe_exos;
-  std::map< Node, unsigned > d_pbe_term_id;
-private:
-  class PbeTrie {
-  private:
-    Node addPbeExampleEval( TypeNode etn, Node e, Node b, std::vector< Node >& ex, quantifiers::TermDbSygus * tds, unsigned index, unsigned ntotal );
-  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, TermDbSygus * tds, unsigned index, unsigned ntotal );
-  };
-  std::map< Node, std::map< TypeNode, PbeTrie > > d_pbe_trie;
-public:
-  /** register examples for an enumerative search term. 
-      This should be a comprehensive set of examples. */
-  void registerPbeExamples( Node e, std::vector< std::vector< Node > >& exs, 
-                            std::vector< Node >& exos, std::vector< Node >& exts );
-  /** get examples */
-  bool hasPbeExamples( Node e );
-  unsigned getNumPbeExamples( Node e );
-  /** return value is the required value for the example */
-  void getPbeExample( Node e, unsigned i, std::vector< Node >& ex );
-  Node getPbeExampleOut( Node e, unsigned i );
-  int getPbeExampleId( Node n );
-  /** add the search val, returns an equivalent value (possibly the same) */
-  Node addPbeSearchVal( TypeNode tn, Node e, Node bvr );
-
-// extended rewriting
-private:
-  std::map< Node, Node > d_ext_rewrite_cache;
-  Node extendedRewritePullIte( Node n );
-public:
-  Node extendedRewrite( Node n );
-  
-// for default grammar construction
-private:
-  TypeNode mkUnresolvedType(const std::string& name, std::set<Type>& unres);
-  void mkSygusConstantsForType( TypeNode type, std::vector<CVC4::Node>& ops );
-  void collectSygusGrammarTypesFor( TypeNode range, std::vector< TypeNode >& types, std::map< TypeNode, std::vector< DatatypeConstructorArg > >& sels );
-  void mkSygusDefaultGrammar( TypeNode range, Node bvl, const std::string& fun, std::map< TypeNode, std::vector< Node > >& extra_cons, std::vector< CVC4::Datatype >& datatypes, std::set<Type>& unres );
-public:
-  TypeNode mkSygusDefaultType( TypeNode range, Node bvl, const std::string& fun, std::map< TypeNode, std::vector< Node > >& extra_cons );
-  TypeNode mkSygusDefaultType( TypeNode range, Node bvl, const std::string& fun ){
-    std::map< TypeNode, std::vector< Node > > extra_cons;
-    return mkSygusDefaultType( range, bvl, fun, extra_cons );
-  }
-};
-
 }/* CVC4::theory::quantifiers namespace */
 }/* CVC4::theory namespace */
 }/* CVC4 namespace */
diff --git a/src/theory/quantifiers/term_database_sygus.cpp b/src/theory/quantifiers/term_database_sygus.cpp
new file mode 100644 (file)
index 0000000..d8913da
--- /dev/null
@@ -0,0 +1,3008 @@
+/*********************                                                        */
+/*! \file term_database_sygus.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynoldsg
+ ** 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 databse class
+ **/
+
+#include "theory/quantifiers/term_database_sygus.h"
+
+#include "expr/datatype.h"
+#include "options/base_options.h"
+#include "options/quantifiers_options.h"
+#include "options/datatypes_options.h"
+#include "theory/quantifiers/ce_guided_instantiation.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/fun_def_engine.h"
+#include "theory/quantifiers/rewrite_engine.h"
+#include "theory/quantifiers/theory_quantifiers.h"
+#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/theory_engine.h"
+
+//for sygus
+#include "smt/smt_engine_scope.h"
+#include "theory/bv/theory_bv_utils.h"
+#include "util/bitvector.h"
+#include "theory/datatypes/datatypes_rewriter.h"
+#include "theory/strings/theory_strings_rewriter.h"
+
+using namespace std;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory::inst;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+bool EvalSygusInvarianceTest::invariant( quantifiers::TermDbSygus * tds, Node nvn, Node x ){
+  TNode tnvn = nvn;
+  Node conj_subs = d_conj.substitute( d_var, tnvn );
+  Node conj_subs_unfold = tds->evaluateWithUnfolding( conj_subs, d_visited );
+  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;
+  }else{
+    return false;
+  }
+}
+
+TermDbSygus::TermDbSygus( context::Context* c, QuantifiersEngine* qe ) : d_quantEngine( qe ){
+  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];
+}
+
+bool TermDbSygus::getMatch( Node p, Node n, std::map< int, Node >& s ) {
+  std::vector< int > new_s;
+  return getMatch2( p, n, s, new_s );
+}
+
+bool TermDbSygus::getMatch2( Node p, Node n, std::map< int, Node >& s, std::vector< int >& new_s ) {
+  std::map< Node, int >::iterator it = d_fv_num.find( p );
+  if( it!=d_fv_num.end() ){
+    Node prev = s[it->second];
+    s[it->second] = n;
+    if( prev.isNull() ){
+      new_s.push_back( it->second );
+    }
+    return prev.isNull() || prev==n;
+  }else if( n.getNumChildren()==0 ){
+    return p==n;
+  }else if( n.getKind()==p.getKind() && n.getNumChildren()==p.getNumChildren() ){
+    //try both ways?
+    unsigned rmax = TermDb::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; i<n.getNumChildren(); i++ ){
+        int io = r==0 ? i : ( i==0 ? 1 : 0 );
+        if( !getMatch2( 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 TermDbSygus::getMatch( Node t, TypeNode st, int& index_found, std::vector< Node >& args, int index_exc, int index_start ) {
+  Assert( st.isDatatype() );
+  const Datatype& dt = ((DatatypeType)(st).toType()).getDatatype();
+  Assert( dt.isSygus() );
+  std::map< Kind, std::vector< Node > > kgens;
+  std::vector< Node > gens;
+  for( unsigned i=index_start; i<dt.getNumConstructors(); i++ ){
+    if( (int)i!=index_exc ){
+      Node g = getGenericBase( st, dt, i );
+      gens.push_back( g );
+      kgens[g.getKind()].push_back( g );
+      Trace("sygus-db-debug") << "Check generic base : " << g << " from " << dt[i].getName() << std::endl;
+      if( g.getKind()==t.getKind() ){
+        Trace("sygus-db-debug") << "Possible match ? " << g << " " << t << " for " << dt[i].getName() << std::endl;
+        std::map< int, Node > sigma;
+        if( getMatch( g, t, sigma ) ){
+          //we found an exact match
+          bool msuccess = true;
+          for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
+            if( sigma[j].isNull() ){
+              msuccess = false;
+              break;
+            }else{
+              args.push_back( sigma[j] );
+            }
+          }
+          if( msuccess ){
+            index_found = i;
+            return true;
+          }
+          //we found an exact match
+          //std::map< TypeNode, int > var_count;
+          //Node new_t = mkGeneric( dt, i, var_count, args );
+          //Trace("sygus-db-debug") << "Rewrote to : " << new_t << std::endl;
+          //return new_t;
+        }
+      }
+    }
+  }
+  /*
+  //otherwise, try to modulate based on kinds
+  for( std::map< Kind, std::vector< Node > >::iterator it = kgens.begin(); it != kgens.end(); ++it ){
+    if( it->second.size()>1 ){
+      for( unsigned i=0; i<it->second.size(); i++ ){
+        for( unsigned j=0; j<it->second.size(); j++ ){
+          if( i!=j ){
+            std::map< int, Node > sigma;
+            if( getMatch( it->second[i], it->second[j], sigma ) ){
+              if( sigma.size()==1 ){
+                //Node mod_pat = sigma.begin().second;
+                //Trace("cegqi-si-rcons-debug") << "Modulated pattern " << mod_pat << " from " << it->second[i] << " and " << it->second[j] << std::endl;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  */
+  return false;
+}
+
+Node TermDbSygus::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() ){
+    Assert( isRegistered( tn ) );
+    std::map< TypeNode, int > var_count;
+    std::map< int, Node > pre;
+    Node g = mkGeneric( dt, c, var_count, pre );
+    Trace("sygus-db-debug") << "Sygus DB : Generic is " << g << std::endl;
+    Node gr = Rewriter::rewrite( g );
+    Trace("sygus-db-debug") << "Sygus DB : Generic rewritten is " << gr << std::endl;
+    gr = Node::fromExpr( smt::currentSmtEngine()->expandDefinitions( gr.toExpr() ) );
+    Trace("sygus-db-debug") << "Sygus DB : Generic base " << dt[c].getName() << " : " << gr << std::endl;
+    d_generic_base[tn][c] = gr;
+    return gr;
+  }else{
+    return it->second;
+  }
+}
+
+Node TermDbSygus::mkGeneric( const Datatype& dt, int c, std::map< TypeNode, int >& var_count, std::map< int, Node >& pre ) {
+  Assert( c>=0 && c<(int)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( int i=0; i<(int)dt[c].getNumArgs(); 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 );
+    }
+    Assert( !a.isNull() );
+    children.push_back( a );
+  }
+  Node ret;
+  if( op.getKind()==BUILTIN ){
+    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 );
+      /*
+      Node n = NodeManager::currentNM()->mkNode( APPLY, children );
+      //must expand definitions
+      Node ne = Node::fromExpr( smt::currentSmtEngine()->expandDefinitions( n.toExpr() ) );
+      Trace("sygus-db-debug") << "Expanded definitions in " << n << " to " << ne << std::endl;
+      return ne;
+      */
+    }
+  }
+  Trace("sygus-db-debug") << "...returning " << ret << std::endl;
+  return ret;
+}
+
+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;
+    Node ret;
+    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; j<n.getNumChildren(); j++ ){
+        pre[j] = sygusToBuiltin( n[j], getArgType( dt[i], j ) );
+      }
+      ret = mkGeneric( dt, i, var_count, pre );
+      Trace("sygus-db-debug") << "SygusToBuiltin : Generic is " << ret << std::endl;
+      ret = Node::fromExpr( smt::currentSmtEngine()->expandDefinitions( ret.toExpr() ) );
+      Trace("sygus-db-debug") << "SygusToBuiltin : After expand definitions " << ret << std::endl;
+      d_sygus_to_builtin[tn][n] = ret;
+    }else{
+      Assert( isFreeVar( n ) );
+      //map to builtin variable type
+      int fv_num = getVarNum( n );
+      Assert( !dt.getSygusType().isNull() );
+      TypeNode vtn = TypeNode::fromType( dt.getSygusType() );
+      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() );
+}
+  
+//rcons_depth limits the number of recursive calls when doing accelerated constant reconstruction (currently limited to 1000)
+//this is hacky : depending upon order of calls, constant rcons may succeed, e.g. 1001, 999 vs. 999, 1001
+Node TermDbSygus::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() ){
+    Node sc;
+    d_builtin_const_to_sygus[tn][c] = sc;
+    Assert( c.isConst() );
+    Assert( tn.isDatatype() );
+    const Datatype& dt = ((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 = NodeManager::currentNM()->mkSkolem( "sy", tn, "sygus proxy" );
+      SygusProxyAttribute spa;
+      k.setAttribute(spa,c);
+      sc = k;
+    }else{
+      int carg = getOpConsNum( tn, c );
+      if( carg!=-1 ){
+        //sc = Node::fromExpr( dt[carg].getSygusOp() );
+        sc = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, Node::fromExpr( dt[carg].getConstructor() ) );
+      }else{
+        //identity functions
+        for( unsigned i=0; i<getNumIdFuncs( tn ); i++ ){
+          unsigned ii = getIdFuncIndex( tn, i );
+          Assert( dt[ii].getNumArgs()==1 );
+          //try to directly reconstruct from single argument
+          TypeNode tnc = 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 = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, Node::fromExpr( dt[ii].getConstructor() ), n );
+            break;
+          }
+        }
+        if( sc.isNull() ){
+          if( rcons_depth<1000 ){
+            //accelerated, recursive reconstruction of constants
+            Kind pk = getPlusKind( TypeNode::fromType( dt.getSygusType() ) );
+            if( pk!=UNDEFINED_KIND ){
+              int arg = getKindConsNum( tn, pk );
+              if( arg!=-1 ){
+                Kind ck = getComparisonKind( TypeNode::fromType( dt.getSygusType() ) );
+                Kind pkm = getPlusKind( TypeNode::fromType( dt.getSygusType() ), true );
+                //get types
+                Assert( dt[arg].getNumArgs()==2 );
+                TypeNode tn1 = getArgType( dt[arg], 0 );
+                TypeNode tn2 = getArgType( dt[arg], 1 );
+                //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 = NodeManager::currentNM()->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 = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, Node::fromExpr( dt[arg].getConstructor() ), sc1, sc2 );
+                        break;
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    d_builtin_const_to_sygus[tn][c] = sc;
+    return sc;
+  }else{
+    return it->second;
+  }
+}
+
+Node TermDbSygus::getSygusNormalized( Node n, std::map< TypeNode, int >& var_count, std::map< Node, Node >& subs ) {
+  return n;
+  /*  TODO?
+  if( n.getKind()==SKOLEM ){
+    std::map< Node, Node >::iterator its = subs.find( n );
+    if( its!=subs.end() ){
+      return its->second;
+    }else{
+      std::map< Node, TypeNode >::iterator it = d_fv_stype.find( n );
+      if( it!=d_fv_stype.end() ){
+        Node v = getVarInc( it->second, var_count );
+        subs[n] = v;
+        return v;
+      }else{
+        return n;
+      }
+    }
+  }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 = getSygusNormalized( n[i], var_count, subs );
+        childChanged = childChanged || nc!=n[i];
+        children.push_back( nc );
+      }
+      if( childChanged ){
+        return NodeManager::currentNM()->mkNode( n.getKind(), children );
+      }
+    }
+    return n;
+  }
+  */
+}
+
+Node TermDbSygus::getNormalized( TypeNode t, Node prog, bool do_pre_norm, bool do_post_norm ) {
+  if( do_pre_norm ){
+    std::map< TypeNode, int > var_count;
+    std::map< Node, Node > subs;
+    prog = getSygusNormalized( prog, var_count, subs );
+  }
+  std::map< Node, Node >::iterator itn = d_normalized[t].find( prog );
+  if( itn==d_normalized[t].end() ){
+    Node progr = Node::fromExpr( smt::currentSmtEngine()->expandDefinitions( prog.toExpr() ) );
+    progr = Rewriter::rewrite( progr );
+    if( do_post_norm ){
+      std::map< TypeNode, int > var_count;
+      std::map< Node, Node > subs;
+      progr = getSygusNormalized( progr, var_count, subs );
+    }
+    Trace("sygus-sym-break2") << "...rewrites to " << progr << std::endl;
+    d_normalized[t][prog] = progr;
+    return progr;
+  }else{
+    return itn->second;
+  }
+}
+
+unsigned TermDbSygus::getSygusTermSize( Node n ){
+  if( n.getNumChildren()==0 ){
+    return 0;
+  }else{
+    unsigned sum = 0;
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      sum += getSygusTermSize( n[i] );
+    }
+    return 1+sum;
+  }
+}
+
+unsigned TermDbSygus::getSygusConstructors( Node n, std::vector< Node >& cons ) {
+  Assert( n.getKind()==APPLY_CONSTRUCTOR );
+  Node op = n.getOperator();
+  if( std::find( cons.begin(), cons.end(), op )==cons.end() ){
+    cons.push_back( op );
+  }
+  if( n.getNumChildren()==0 ){
+    return 0;
+  }else{
+    unsigned sum = 0;
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      sum += getSygusConstructors( n[i], cons );
+    }
+    return 1+sum;
+  }
+}
+  
+bool TermDbSygus::isAntisymmetric( Kind k, Kind& dk ) {
+  if( k==GT ){
+    dk = LT;
+    return true;
+  }else if( k==GEQ ){
+    dk = LEQ;
+    return true;
+  }else if( k==BITVECTOR_UGT ){
+    dk = BITVECTOR_ULT;
+    return true;
+  }else if( k==BITVECTOR_UGE ){
+    dk = BITVECTOR_ULE;
+    return true;
+  }else if( k==BITVECTOR_SGT ){
+    dk = BITVECTOR_SLT;
+    return true;
+  }else if( k==BITVECTOR_SGE ){
+    dk = BITVECTOR_SLE;
+    return true;
+  }else{
+    return false;
+  }
+}
+
+bool TermDbSygus::isIdempotentArg( Node n, Kind ik, int arg ) {
+  // these should all be binary operators
+  //Assert( ik!=DIVISION && ik!=INTS_DIVISION && ik!=INTS_MODULUS && ik!=BITVECTOR_UDIV );
+  TypeNode tn = n.getType();
+  if( n==getTypeValue( tn, 0 ) ){
+    if( ik==PLUS || ik==OR || ik==XOR || ik==BITVECTOR_PLUS || ik==BITVECTOR_OR || ik==BITVECTOR_XOR || ik==STRING_CONCAT ){
+      return true;
+    }else if( ik==MINUS || ik==BITVECTOR_SHL || ik==BITVECTOR_LSHR || ik==BITVECTOR_ASHR || ik==BITVECTOR_SUB || 
+              ik==BITVECTOR_UREM || ik==BITVECTOR_UREM_TOTAL ){
+      return arg==1;
+    }
+  }else if( n==getTypeValue( tn, 1 ) ){
+    if( ik==MULT || ik==BITVECTOR_MULT ){
+      return true;
+    }else if( ik==DIVISION || ik==DIVISION_TOTAL || ik==INTS_DIVISION || ik==INTS_DIVISION_TOTAL || 
+              ik==INTS_MODULUS || ik==INTS_MODULUS_TOTAL || 
+              ik==BITVECTOR_UDIV_TOTAL || ik==BITVECTOR_UDIV || ik==BITVECTOR_SDIV ){
+      return arg==1;
+    }
+  }else if( n==getTypeMaxValue( tn ) ){
+    if( ik==EQUAL || ik==BITVECTOR_AND || ik==BITVECTOR_XNOR ){
+      return true;
+    }
+  }
+  return false;
+}
+
+
+Node TermDbSygus::isSingularArg( Node n, Kind ik, int arg ) {
+  TypeNode tn = n.getType();
+  if( n==getTypeValue( tn, 0 ) ){
+    if( ik==AND || ik==MULT || ik==BITVECTOR_AND || ik==BITVECTOR_MULT ){
+      return n;
+    }else if( ik==BITVECTOR_SHL || ik==BITVECTOR_LSHR || ik==BITVECTOR_ASHR || 
+              ik==BITVECTOR_UREM || ik==BITVECTOR_UREM_TOTAL ){
+      if( arg==0 ){
+        return n;
+      }
+    }else if( ik==BITVECTOR_UDIV_TOTAL || ik==BITVECTOR_UDIV || ik==BITVECTOR_SDIV ){
+      if( arg==0 ){
+        return n;
+      }else if( arg==1 ){
+        return getTypeMaxValue( tn );
+      }
+    }else if( ik==DIVISION || ik==DIVISION_TOTAL || ik==INTS_DIVISION || ik==INTS_DIVISION_TOTAL || 
+              ik==INTS_MODULUS || ik==INTS_MODULUS_TOTAL  ){
+      if( arg==0 ){
+        return n;
+      }else{
+        //TODO?
+      }
+    }else if( ik==STRING_SUBSTR ){
+      if( arg==0 ){
+        return n;
+      }else if( arg==2 ){
+        return getTypeValue( NodeManager::currentNM()->stringType(), 0 );
+      }
+    }else if( ik==STRING_STRIDOF ){
+      if( arg==0 || arg==1 ){
+        return getTypeValue( NodeManager::currentNM()->integerType(), -1 );
+      }
+    }
+  }else if( n==getTypeValue( tn, 1 ) ){
+    if( ik==BITVECTOR_UREM_TOTAL ){
+      return getTypeValue( tn, 0 );
+    }
+  }else if( n==getTypeMaxValue( tn ) ){
+    if( ik==OR || ik==BITVECTOR_OR ){
+      return n;
+    }
+  }else{
+    if( n.getType().isReal() && n.getConst<Rational>().sgn()<0 ){
+      // negative arguments
+      if( ik==STRING_SUBSTR || ik==STRING_CHARAT ){
+        return getTypeValue( NodeManager::currentNM()->stringType(), 0 );
+      }else if( ik==STRING_STRIDOF ){
+        Assert( arg==2 );
+        return getTypeValue( NodeManager::currentNM()->integerType(), -1 );
+      }
+    }
+  }
+  return Node::null();
+}
+
+bool TermDbSygus::hasOffsetArg( Kind ik, int arg, int& offset, Kind& ok ) {
+  if( ik==LT ){
+    Assert( arg==0 || arg==1 );
+    offset = arg==0 ? 1 : -1;
+    ok = LEQ;
+    return true;
+  }else if( ik==BITVECTOR_ULT ){
+    Assert( arg==0 || arg==1 );
+    offset = arg==0 ? 1 : -1;
+    ok = BITVECTOR_ULE;
+    return true;
+  }else if( ik==BITVECTOR_SLT ){
+    Assert( arg==0 || arg==1 );
+    offset = arg==0 ? 1 : -1;
+    ok = BITVECTOR_SLE;
+    return true;
+  }
+  return false;
+}
+
+
+
+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::TermDb::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( 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 = 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( 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 = 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 = getTypeMaxValue( c.getType() );
+    Node zero_c = getTypeValue( c.getType(), 0 );
+    Node one_c = 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 = getTypeValue( sygusToBuiltinType( tnc ), 0 );
+      solve_ret = getConstConsNum( tn, builtin );
+      if( solve_ret!=-1 ){
+        // t - s    ----->  ( 0 - s ) + t
+        rt.d_req_kind = 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;
+}
+
+Node TermDbSygus::getTypeValue( TypeNode tn, int val ) {
+  std::map< int, Node >::iterator it = d_type_value[tn].find( val );
+  if( it==d_type_value[tn].end() ){
+    Node n;
+    if( tn.isInteger() || tn.isReal() ){
+      Rational c(val);
+      n = NodeManager::currentNM()->mkConst( c );
+    }else if( tn.isBitVector() ){
+      unsigned int uv = val;
+      BitVector bval(tn.getConst<BitVectorSize>(), uv);
+      n = NodeManager::currentNM()->mkConst<BitVector>(bval);
+    }else if( tn.isBoolean() ){
+      if( val==0 ){
+        n = d_false;
+      }
+    }else if( tn.isString() ){
+      if( val==0 ){
+        n = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
+      }
+    }
+    d_type_value[tn][val] = n;
+    return n;
+  }else{
+    return it->second;
+  }
+}
+
+Node TermDbSygus::getTypeMaxValue( TypeNode tn ) {
+  std::map< TypeNode, Node >::iterator it = d_type_max_value.find( tn );
+  if( it==d_type_max_value.end() ){
+    Node n;
+    if( tn.isBitVector() ){
+      n = bv::utils::mkOnes(tn.getConst<BitVectorSize>());
+    }else if( tn.isBoolean() ){
+      n = d_true;
+    }
+    d_type_max_value[tn] = n;
+    return n;
+  }else{
+    return it->second;
+  }
+}
+
+Node TermDbSygus::getTypeValueOffset( TypeNode tn, Node val, int offset, int& status ) {
+  std::map< int, Node >::iterator it = d_type_value_offset[tn][val].find( offset );
+  if( it==d_type_value_offset[tn][val].end() ){
+    Node val_o;
+    Node offset_val = getTypeValue( tn, offset );
+    status = -1;
+    if( !offset_val.isNull() ){
+      if( tn.isInteger() || tn.isReal() ){
+        val_o = Rewriter::rewrite( NodeManager::currentNM()->mkNode( PLUS, val, offset_val ) );
+        status = 0;
+      }else if( tn.isBitVector() ){
+        val_o = Rewriter::rewrite( NodeManager::currentNM()->mkNode( BITVECTOR_PLUS, val, offset_val ) );
+        // TODO : enable?  watch for overflows
+      }
+    }
+    d_type_value_offset[tn][val][offset] = val_o;
+    d_type_value_offset_status[tn][val][offset] = status;
+    return val_o;
+  }else{
+    status = d_type_value_offset_status[tn][val][offset];
+    return it->second;
+  }
+}
+
+struct sortConstants {
+  TermDbSygus * d_tds;
+  Kind d_comp_kind;
+  bool operator() (Node i, Node j) {
+    if( i!=j ){
+      return d_tds->doCompare( i, j, d_comp_kind );
+    }else{
+      return false;
+    }
+  }
+};
+
+class ReconstructTrie {
+public:
+  std::map< Node, ReconstructTrie > d_children;
+  std::vector< Node > d_reconstruct;
+  void add( std::vector< Node >& cons, Node r, unsigned index = 0 ){
+    if( index==cons.size() ){
+      d_reconstruct.push_back( r );
+    }else{
+      d_children[cons[index]].add( cons, r, index+1 );
+    }
+  }
+  Node getReconstruct( std::map< Node, int >& rcons, unsigned depth ) {
+    if( !d_reconstruct.empty() ){
+      for( unsigned i=0; i<d_reconstruct.size(); i++ ){
+        Node r = d_reconstruct[i];
+        if( rcons[r]==0 ){
+          Trace("sygus-static-enum") << "...eliminate constructor " << r << std::endl;
+          rcons[r] = 1;
+          return r;
+        }
+      }
+    }
+    if( depth>0 ){
+      for( unsigned w=0; w<2; w++ ){
+        for( std::map< Node, ReconstructTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+          Node n = it->first;
+          if( ( w==0 && rcons[n]!=0 ) || ( w==1 && rcons[n]==0 ) ){
+            Node r = it->second.getReconstruct( rcons, depth - w );
+            if( !r.isNull() ){
+              if( w==1 ){
+                Trace("sygus-static-enum") << "...use " << n << " to eliminate constructor " << r << std::endl;
+                rcons[n] = -1;
+              }
+              return r;
+            }
+          }
+        }
+      }
+    }
+    return Node::null();
+  }
+};
+
+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
+        }
+        //for constant reconstruction
+        Kind ck = getComparisonKind( TypeNode::fromType( dt.getSygusType() ) );
+        Node z = getTypeValue( TypeNode::fromType( dt.getSygusType() ), 0 );
+        d_const_list_pos[tn] = 0;
+        //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_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 );
+          }
+          d_ops[tn][n] = i;
+          d_arg_ops[tn][i] = n;
+          Trace("sygus-db") << std::endl;
+        }
+        //sort the constant list
+        if( !d_const_list[tn].empty() ){
+          if( ck!=UNDEFINED_KIND ){
+            sortConstants sc;
+            sc.d_comp_kind = ck;
+            sc.d_tds = this;
+            std::sort( d_const_list[tn].begin(), d_const_list[tn].end(), sc );
+          }
+          Trace("sygus-db") << "Type has " << d_const_list[tn].size() << " constants..." << std::endl << "  ";
+          for( unsigned i=0; i<d_const_list[tn].size(); i++ ){
+            Trace("sygus-db") << d_const_list[tn][i] << " ";
+          }
+          Trace("sygus-db") << std::endl;
+          Trace("sygus-db") << "Of these, " << d_const_list_pos[tn] << " are marked as positive." << 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 ) );
+          }
+        }
+        
+        //compute the redundant operators
+        if( options::sygusMinGrammar() ){
+          for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+            bool nred = true;
+            Trace("sygus-split-debug") << "Is " << dt[i].getName() << " a redundant operator?" << std::endl;
+            Kind ck = getConsNumKind( tn, i );
+            if( ck!=UNDEFINED_KIND ){
+              Kind dk;
+              if( isAntisymmetric( ck, dk ) ){
+                int j = getKindConsNum( tn, dk );
+                if( j!=-1 ){
+                  Trace("sygus-split-debug") << "Possible redundant operator : " << ck << " with " << dk << std::endl;
+                  //check for type mismatches
+                  bool success = true;
+                  for( unsigned k=0; k<2; k++ ){
+                    unsigned ko = k==0 ? 1 : 0;
+                    TypeNode tni = TypeNode::fromType( ((SelectorType)dt[i][k].getType()).getRangeType() );
+                    TypeNode tnj = TypeNode::fromType( ((SelectorType)dt[j][ko].getType()).getRangeType() );
+                    if( tni!=tnj ){
+                      Trace("sygus-split-debug") << "Argument types " << tni << " and " << tnj << " are not equal." << std::endl;
+                      success = false;
+                      break;
+                    }
+                  }
+                  if( success ){
+                    Trace("sygus-nf") << "* Sygus norm " << dt.getName() << " : do not consider any " << ck << " terms." << std::endl;
+                    nred = false;
+                  }
+                }
+              }
+            }
+            if( nred ){
+              Trace("sygus-split-debug") << "Check " << dt[i].getName() << " based on generic rewriting" << std::endl;
+              std::map< TypeNode, int > var_count;
+              std::map< int, Node > pre;
+              Node g = mkGeneric( dt, i, var_count, pre );
+              nred = !computeGenericRedundant( tn, g );
+              Trace("sygus-split-debug") << "...done check " << dt[i].getName() << " based on generic rewriting" << std::endl;
+            }
+            d_sygus_red_status[tn].push_back( nred ? 0 : 1 );
+          }
+          // run an enumerator for this type
+          if( options::sygusMinGrammarAgg() ){
+            TypeEnumerator te(tn);
+            unsigned count = 0;
+            std::map< Node, std::vector< Node > > builtin_to_orig;
+            Trace("sygus-static-enum") << "Static enumerate " << dt.getName() << "..." << std::endl;
+            while( !te.isFinished() && count<1000 ){
+              Node n = *te;
+              Node bn = sygusToBuiltin( n, tn );
+              Trace("sygus-static-enum") << "  " << bn;
+              Node bnr = Rewriter::rewrite( bn );
+              Trace("sygus-static-enum") << "  ..." << bnr << std::endl;
+              builtin_to_orig[bnr].push_back( n );
+              ++te;
+              count++;
+            }
+            std::map< Node, bool > reserved;
+            for( unsigned i=0; i<=2; i++ ){
+              Node rsv = i==2 ? getTypeMaxValue( btn ) : getTypeValue( btn, i );
+              if( !rsv.isNull() ){
+                reserved[ rsv ] = true;
+              }
+            }
+            Trace("sygus-static-enum") << "...make the reconstruct index data structure..." << std::endl;
+            ReconstructTrie rt;
+            std::map< Node, int > rcons;
+            unsigned max_depth = 0;
+            for( std::map< Node, std::vector< Node > >::iterator itb = builtin_to_orig.begin(); itb != builtin_to_orig.end(); ++itb ){
+              if( itb->second.size()>0 ){
+                std::map< Node, std::vector< Node > > clist;
+                Node single_cons;
+                for( unsigned j=0; j<itb->second.size(); j++ ){
+                  Node e = itb->second[j];
+                  getSygusConstructors( e, clist[e] );
+                  if( clist[e].size()>max_depth ){
+                    max_depth = clist[e].size();
+                  }
+                  for( unsigned k=0; k<clist[e].size(); k++ ){
+                    /*
+                    unsigned cindex = Datatype::indexOf( clist[e][k].toExpr() );
+                    if( isGenericRedundant( tn, cindex ) ){
+                      is_gen_redundant = true;
+                      break;
+                    }else{
+                    */
+                    rcons[clist[e][k]] = 0;
+                  }
+                  //if( is_gen_redundant ){
+                  //  clist.erase( e );
+                  //}else{
+                  if( clist[e].size()==1 ){
+                    Trace("sygus-static-enum") << "...single constructor term : " << e << ", builtin is " << itb->first << ", cons is " << clist[e][0] << std::endl;
+                    if( single_cons.isNull() ){
+                      single_cons = clist[e][0];
+                    }else{
+                      Trace("sygus-static-enum") << "*** already can eliminate constructor " << clist[e][0] << std::endl;
+                      unsigned cindex =  Datatype::indexOf( clist[e][0].toExpr() );
+                      d_sygus_red_status[tn][cindex] = 1;
+                    }
+                  }
+                  //}
+                }
+                // do not eliminate 0, 1, or max
+                if( !single_cons.isNull() && reserved.find( itb->first )==reserved.end() ){
+                  Trace("sygus-static-enum") << "...possibly elim " << single_cons << std::endl;
+                  for( std::map< Node, std::vector< Node > >::iterator itc = clist.begin(); itc != clist.end(); ++itc ){
+                    if( std::find( itc->second.begin(), itc->second.end(), single_cons )==itc->second.end() ){
+                      rt.add( itc->second, single_cons );
+                    }
+                  }
+                }
+              }
+            }
+            Trace("sygus-static-enum") << "...compute reconstructions..." << std::endl;
+            Node next_rcons;
+            do {
+              unsigned depth = 0;
+              do{
+                next_rcons = rt.getReconstruct( rcons, depth );
+                depth++;
+              }while( next_rcons.isNull() && depth<=max_depth );
+              // if we found a constructor to eliminate
+              if( !next_rcons.isNull() ){
+                Trace("sygus-static-enum") << "*** eliminate constructor " << next_rcons << std::endl;
+                unsigned cindex =  Datatype::indexOf( next_rcons.toExpr() );
+                d_sygus_red_status[tn][cindex] = 2;
+              }
+            }while( !next_rcons.isNull() );
+            Trace("sygus-static-enum") << "...finished..." << std::endl;
+          }
+        }else{
+          // assume all are non-redundant
+          for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+            d_sygus_red_status[tn].push_back( 0 );
+          }
+        }
+      }
+    }
+  }
+}
+
+void TermDbSygus::registerMeasuredTerm( Node e, Node root, bool mkActiveGuard ) {
+  Assert( d_measured_term.find( e )==d_measured_term.end() );
+  Trace("sygus-db") << "Register measured term : " << e << " with root " << root << std::endl;
+  d_measured_term[e] = root;
+  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_measured_term_active_guard[e] = eg;
+  }
+}
+
+void TermDbSygus::registerPbeExamples( Node e, std::vector< std::vector< Node > >& exs, 
+                                       std::vector< Node >& exos, std::vector< Node >& exts  ) {
+  Trace("sygus-db") << "Register " << exs.size() << " PBE examples with " << e << std::endl;
+  Assert( d_measured_term.find( e )==d_measured_term.end() || isMeasuredTerm( e )==e );
+  Assert( d_pbe_exs.find( e )==d_pbe_exs.end() );
+  Assert( exs.size()==exos.size() );
+  d_pbe_exs[e] = exs;
+  d_pbe_exos[e] = exos;
+  for( unsigned i=0; i<exts.size(); i++ ){
+    Trace("sygus-db-debug") << "  # " << i << " : " << exts[i] << std::endl;
+    Assert( exts[i].getKind()==APPLY_UF );
+    Assert( exts[i][0]==e );
+    d_pbe_term_id[exts[i]] = i;
+  }
+}
+
+Node TermDbSygus::isMeasuredTerm( Node e ) {
+  std::map< Node, Node >::iterator itm = d_measured_term.find( e );
+  if( itm!=d_measured_term.end() ){
+    return itm->second;
+  }else{
+    return Node::null();
+  }
+}
+
+Node TermDbSygus::getActiveGuardForMeasureTerm( Node e ) {
+  std::map< Node, Node >::iterator itag = d_measured_term_active_guard.find( e );
+  if( itag!=d_measured_term_active_guard.end() ){
+    return itag->second;
+  }else{
+    return Node::null();
+  }
+}
+
+void TermDbSygus::getMeasuredTerms( std::vector< Node >& mts ) {
+  for( std::map< Node, Node >::iterator itm = d_measured_term.begin(); itm != d_measured_term.end(); ++itm ){
+    mts.push_back( itm->first );
+  }
+}
+
+bool TermDbSygus::hasPbeExamples( Node e ) {
+  return d_pbe_exs.find( e )!=d_pbe_exs.end();
+}
+
+unsigned TermDbSygus::getNumPbeExamples( Node e ) {
+  std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_pbe_exs.find( e );
+  if( it!=d_pbe_exs.end() ){
+    return it->second.size();
+  }else{
+    return 0;
+  }
+}
+
+void TermDbSygus::getPbeExample( Node e, unsigned i, std::vector< Node >& ex ) {
+  std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_pbe_exs.find( e );
+  if( it!=d_pbe_exs.end() ){
+    Assert( i<it->second.size() );
+    Assert( i<d_pbe_exos[e].size() );
+    ex.insert( ex.end(), it->second[i].begin(), it->second[i].end() );
+  }else{
+    Assert( false );
+  }
+}
+Node TermDbSygus::getPbeExampleOut( Node e, unsigned i ) {
+  std::map< Node, std::vector< Node > >::iterator it = d_pbe_exos.find( e );
+  if( it!=d_pbe_exos.end() ){
+    Assert( i<it->second.size() );
+    return it->second[i];
+  }else{
+    Assert( false );
+    return Node::null();
+  }
+}
+
+int TermDbSygus::getPbeExampleId( Node n ) {
+  std::map< Node, unsigned >::iterator it = d_pbe_term_id.find( n );
+  if( it!=d_pbe_term_id.end() ){
+    return it->second;
+  }else{
+    return -1;
+  }
+}
+
+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( !isGenericRedundant( tn, 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 ) );
+  Assert( !isGenericRedundant( tn, cindex ) );
+  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;
+  }
+}
+
+
+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;
+  }
+}
+
+unsigned TermDbSygus::getNumIdFuncs( TypeNode tn ) {
+  return d_id_funcs[tn].size();
+}
+
+unsigned TermDbSygus::getIdFuncIndex( TypeNode tn, unsigned i ) {
+  return d_id_funcs[tn][i];
+}
+
+TypeNode TermDbSygus::getArgType( const DatatypeConstructor& c, int i ) {
+  Assert( i>=0 && i<(int)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( QuantArith::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( QuantArith::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;
+  }
+}
+
+bool TermDbSygus::doCompare( Node a, Node b, Kind k ) {
+  Node com = NodeManager::currentNM()->mkNode( k, a, b );
+  com = Rewriter::rewrite( com );
+  return com==d_true;
+}
+
+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]==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( smt::currentSmtEngine()->isDefinedFunction( op.toExpr() ) ){
+    return APPLY;
+  }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{
+      return NodeManager::operatorToKind( op );
+    }
+  }
+}
+
+void TermDbSygus::printSygusTerm( std::ostream& out, Node n, std::vector< Node >& lvs ) {
+  if( n.getKind()==APPLY_CONSTRUCTOR ){
+    TypeNode tn = n.getType();
+    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+    if( dt.isSygus() ){
+      int cIndex = Datatype::indexOf( n.getOperator().toExpr() );
+      Assert( !dt[cIndex].getSygusOp().isNull() );
+      if( dt[cIndex].getSygusLetBody().isNull() ){
+        if( n.getNumChildren()>0 ){
+          out << "(";
+        }
+        Node op = dt[cIndex].getSygusOp();
+        if( op.getType().isBitVector() && op.isConst() ){
+          //print in the style it was given
+          Trace("sygus-print-bvc") << "[Print " << op << " " << dt[cIndex].getName() << "]" << std::endl;
+          std::stringstream ss;
+          ss << dt[cIndex].getName();
+          std::string str = ss.str();
+          std::size_t found = str.find_last_of("_");
+          Assert( found!=std::string::npos );
+          std::string name = std::string( str.begin() + found +1, str.end() );
+          out << name;
+        }else{
+          out << op;
+        }
+        if( n.getNumChildren()>0 ){
+          for( unsigned i=0; i<n.getNumChildren(); i++ ){
+            out << " ";
+            printSygusTerm( out, n[i], lvs );
+          }
+          out << ")";
+        }
+      }else{
+        std::stringstream let_out;
+        //print as let term
+        if( dt[cIndex].getNumSygusLetInputArgs()>0 ){
+          let_out << "(let (";
+        }
+        std::vector< Node > subs_lvs;
+        std::vector< Node > new_lvs;
+        for( unsigned i=0; i<dt[cIndex].getNumSygusLetArgs(); i++ ){
+          Node v = Node::fromExpr( dt[cIndex].getSygusLetArg( i ) );
+          subs_lvs.push_back( v );
+          std::stringstream ss;
+          ss << "_l_" << new_lvs.size();
+          Node lv = NodeManager::currentNM()->mkBoundVar( ss.str(), v.getType() );
+          new_lvs.push_back( lv );
+          //map free variables to proper terms
+          if( i<dt[cIndex].getNumSygusLetInputArgs() ){
+            //it should be printed as a let argument
+            let_out << "(";
+            let_out << lv << " " << lv.getType() << " ";
+            printSygusTerm( let_out, n[i], lvs );
+            let_out << ")";
+          }
+        }
+        if( dt[cIndex].getNumSygusLetInputArgs()>0 ){
+          let_out << ") ";
+        }
+        //print the body
+        Node let_body = Node::fromExpr( dt[cIndex].getSygusLetBody() );
+        let_body = let_body.substitute( subs_lvs.begin(), subs_lvs.end(), new_lvs.begin(), new_lvs.end() );
+        new_lvs.insert( new_lvs.end(), lvs.begin(), lvs.end() );
+        printSygusTerm( let_out, let_body, new_lvs );
+        if( dt[cIndex].getNumSygusLetInputArgs()>0 ){
+          let_out << ")";
+        }
+        //do variable substitutions since ASSUMING : let_vars are interpreted literally and do not represent a class of variables
+        std::string lbody = let_out.str();
+        for( unsigned i=0; i<dt[cIndex].getNumSygusLetArgs(); i++ ){
+          std::stringstream old_str;
+          old_str << new_lvs[i];
+          std::stringstream new_str;
+          if( i>=dt[cIndex].getNumSygusLetInputArgs() ){
+            printSygusTerm( new_str, n[i], lvs );
+          }else{
+            new_str << Node::fromExpr( dt[cIndex].getSygusLetArg( i ) );
+          }
+          doStrReplace( lbody, old_str.str().c_str(), new_str.str().c_str() );
+        }
+        out << lbody;
+      }
+      return;
+    }
+  }else if( !n.getAttribute(SygusProxyAttribute()).isNull() ){
+    out << n.getAttribute(SygusProxyAttribute());
+  }else{
+    out << n;
+  }
+}
+
+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() ){
+      Trace("sygus-eager") << "TermDbSygus::eager: Register eval term : " << n << std::endl;
+      TypeNode tn = n[0].getType();
+      if( tn.isDatatype() ){
+        const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+        if( dt.isSygus() ){
+          Node f = n.getOperator();
+          Trace("sygus-eager") << "...the evaluation function is : " << f << std::endl;
+          if( n[0].getKind()!=APPLY_CONSTRUCTOR ){
+            // check if it directly occurs in an input/ouput example
+            int pbe_id = getPbeExampleId( n );
+            if( pbe_id!=-1 ){
+              Node n_res = getPbeExampleOut( n[0], pbe_id );
+              if( !n_res.isNull() ){
+                Trace("sygus-eager") << "......do not evaluate " << n << " since it is an input/output example : " << n_res << std::endl;
+                return;
+              }
+            }
+            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;
+        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 = d_quantEngine->getTermDatabaseSygus()->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() );
+            esit.d_conj = NodeManager::currentNM()->mkNode( kind::APPLY_UF, eval_children );
+            esit.d_var = n;
+            eval_children[1] = vn;
+            Node eval_fun = NodeManager::currentNM()->mkNode( kind::APPLY_UF, eval_children );
+            esit.d_result = evaluateWithUnfolding( eval_fun );
+            res = esit.d_result;
+            eval_children.resize( 2 );  
+            eval_children[1] = n;
+            
+            //evaluate with minimal explanation
+            std::vector< Node > mexp;
+            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();
+      }
+    }
+  }
+}
+
+void TermDbSygus::getExplanationForConstantEquality( Node n, Node vn, std::vector< Node >& exp ) {
+  std::map< unsigned, bool > cexc;
+  getExplanationForConstantEquality( n, vn, exp, cexc );
+}
+
+void TermDbSygus::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 TermDbSygus::getExplanationForConstantEquality( Node n, Node vn ) {
+  std::map< unsigned, bool > cexc;
+  return getExplanationForConstantEquality( n, vn, cexc );
+}
+
+Node TermDbSygus::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 TermDbSygus::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 by a fresh variable and rewriting again
+  for( unsigned i=0; i<vn.getNumChildren(); i++ ){
+    TypeNode xtn = vn[i].getType();
+    Node x = getFreeVarInc( xtn, var_count );
+    trb.replaceChild( i, x );
+    Node nvn = trb.build();
+    Assert( nvn.getKind()==kind::APPLY_CONSTRUCTOR );
+    if( et.is_invariant( this, nvn, x ) ){
+      cexc[i] = true;
+      // we are tracking term size if positive
+      if( sz>=0 ){
+        int s = 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 = d_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 TermDbSygus::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 TermDbSygus::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 );
+}
+
+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 if( ret.getKind()==APPLY ){
+      //must expand definitions to account for defined functions in sygus grammars
+      ret = Node::fromExpr( smt::currentSmtEngine()->expandDefinitions( ret.toExpr() ) );
+    }
+    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()==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()==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::evaluateBuiltin( TypeNode tn, Node bn, Node ar, unsigned i ) {
+  std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_pbe_exs.find( ar );
+  if( it!=d_pbe_exs.end() ){
+    Assert( i<it->second.size() );
+    return evaluateBuiltin( tn, bn, it->second[i] );
+  }else{
+    return Rewriter::rewrite( bn );
+  }
+}
+
+Node TermDbSygus::evaluateWithUnfolding( Node n, std::map< Node, Node >& visited ) {
+  std::map< Node, Node >::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 );
+      }
+      // TODO : extended rewrite?
+      ret = extendedRewrite( ret );
+    }
+    visited[n] = ret;
+    return ret;
+  }else{
+    return it->second;
+  }
+}
+
+Node TermDbSygus::evaluateWithUnfolding( Node n ) {
+  std::map< Node, Node > visited;
+  return evaluateWithUnfolding( n, visited );
+}
+
+bool TermDbSygus::computeGenericRedundant( TypeNode tn, Node g ) {
+  //everything added to this cache should be mutually exclusive cases
+  std::map< Node, bool >::iterator it = d_gen_redundant[tn].find( g );
+  if( it==d_gen_redundant[tn].end() ){
+    Trace("sygus-gnf") << "Register generic for " << tn << " : " << g << std::endl;
+    Node gr = getNormalized( tn, g, false );
+    Trace("sygus-gnf-debug") << "Generic " << g << " rewrites to " << gr << std::endl;
+    std::map< Node, Node >::iterator itg = d_gen_terms[tn].find( gr );
+    bool red = true;
+    if( itg==d_gen_terms[tn].end() ){
+      red = false;
+      d_gen_terms[tn][gr] = g;
+      Trace("sygus-gnf-debug") << "...not redundant." << std::endl;
+      Trace("sygus-nf-reg") << "*** Sygus (generic) normal form : normal form of " << g << " is " << gr << std::endl;
+    }else{
+      Trace("sygus-gnf-debug") << "...redundant." << std::endl;
+      Trace("sygus-nf") << "* Sygus normal form : simplify since " << g << " and " << itg->second << " both rewrite to " << gr << std::endl;
+    }
+    d_gen_redundant[tn][g] = red;
+    return red;
+  }else{
+    return it->second;
+  }
+}
+
+bool TermDbSygus::isGenericRedundant( TypeNode tn, unsigned i ) {
+  Assert( i<d_sygus_red_status[tn].size() );
+  if( options::sygusMinGrammarAgg() ){
+    return d_sygus_red_status[tn][i]!=0;
+  }else{
+    return d_sygus_red_status[tn][i]==1;
+  }
+}
+
+Node TermDbSygus::PbeTrie::addPbeExample( TypeNode etn, Node e, Node b, quantifiers::TermDbSygus * tds, unsigned index, unsigned ntotal ) {
+  Assert( tds->getNumPbeExamples( e )==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    
+        tds->getPbeExample( e, index, ex );
+        addPbeExampleEval( etn, e, d_lazy_child, ex, tds, index, ntotal );
+        Assert( !d_children.empty() );
+        d_lazy_child = Node::null();
+      }
+    }else{
+      tds->getPbeExample( e, index, ex );
+    }
+    return addPbeExampleEval( etn, e, b, ex, tds, index, ntotal );
+  }
+}
+
+Node TermDbSygus::PbeTrie::addPbeExampleEval( TypeNode etn, Node e, Node b, std::vector< Node >& ex, quantifiers::TermDbSygus * tds, unsigned index, unsigned ntotal ) {
+  Node eb = tds->evaluateBuiltin( etn, b, ex );
+  return d_children[eb].addPbeExample( etn, e, b, tds, index+1, ntotal );
+}
+
+Node TermDbSygus::addPbeSearchVal( TypeNode tn, Node e, Node bvr ){
+  Assert( !e.isNull() );
+  if( hasPbeExamples( e ) ){
+    unsigned nex = getNumPbeExamples( e );
+    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 TermDbSygus::extendedRewritePullIte( Node n ) {
+  // generalize this?
+  Assert( n.getNumChildren()==2 );
+  Assert( n.getType().isBoolean() );
+  Assert( n.getMetaKind() != kind::metakind::PARAMETERIZED );
+  std::vector< Node > children;
+  for( unsigned i=0; i<n.getNumChildren(); i++ ){
+    children.push_back( n[i] );
+  }
+  for( unsigned i=0; i<2; i++ ){
+    if( n[i].getKind()==kind::ITE ){
+      for( unsigned j=0; j<2; j++ ){
+        children[i] = n[i][j+1];
+        Node eqr = extendedRewrite( NodeManager::currentNM()->mkNode( n.getKind(), children ) );
+        children[i] = n[i];
+        if( eqr.isConst() ){
+          std::vector< Node > new_children;
+          Kind new_k;
+          if( eqr==d_true ){
+            new_k = kind::OR;
+            new_children.push_back( j==0 ? n[i][0] : n[i][0].negate() );
+          }else{
+            Assert( eqr==d_false );
+            new_k = kind::AND;
+            new_children.push_back( j==0 ? n[i][0].negate() : n[i][0] );
+          }
+          children[i] = n[i][2-j];
+          Node rem_eq = NodeManager::currentNM()->mkNode( n.getKind(), children );
+          children[i] = n[i];
+          new_children.push_back( rem_eq );
+          Node nc = NodeManager::currentNM()->mkNode( new_k, new_children );
+          Trace("sygus-ext-rewrite") << "sygus-extr : " << n << " rewrites to " << nc << " by simple ITE pulling." << std::endl;
+          //recurse
+          return extendedRewrite( nc );
+        }
+      }
+    }
+  }
+  return Node::null();
+}
+
+Node TermDbSygus::extendedRewrite( Node n ) {
+  std::map< Node, Node >::iterator it = d_ext_rewrite_cache.find( n );
+  if( it == d_ext_rewrite_cache.end() ){
+    Node ret = n;
+    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 = extendedRewrite( n[i] );
+        childChanged = nc!=n[i] || childChanged;
+        children.push_back( nc );
+      }
+      Node ret;
+      if( childChanged ){
+        ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
+      }
+    }
+    ret = Rewriter::rewrite( n );
+    Trace("sygus-ext-rewrite-debug") << "Do extended rewrite on : " << ret << " (from " << n << ")" << std::endl; 
+
+    Node new_ret;
+    if( ret.getKind()==kind::EQUAL ){
+      // string equalities with disequal prefix or suffix
+      if( ret[0].getType().isString() ){
+        std::vector< Node > c[2];
+        for( unsigned i=0; i<2; i++ ){
+          strings::TheoryStringsRewriter::getConcat( ret[i], c[i] );
+        }
+        if( c[0].empty()==c[1].empty() ){
+          if( !c[0].empty() ){
+            for( unsigned i=0; i<2; i++ ){
+              unsigned index1 = i==0 ? 0 : c[0].size()-1;
+              unsigned index2 = i==0 ? 0 : c[1].size()-1;
+              if( c[0][index1].isConst() && c[1][index2].isConst() ){
+                CVC4::String s = c[0][index1].getConst<String>();
+                CVC4::String t = c[1][index2].getConst<String>();
+                unsigned len_short = s.size() <= t.size() ? s.size() : t.size();
+                bool isSameFix = i==1 ? s.rstrncmp(t, len_short): s.strncmp(t, len_short);
+                if( !isSameFix ){
+                  Trace("sygus-ext-rewrite") << "sygus-extr : " << ret << " rewrites to false due to disequal string prefix/suffix." << std::endl;
+                  new_ret = d_false;
+                  break;
+                }
+              }
+            }
+          }
+        }else{
+          new_ret = d_false;
+        }
+      }
+      if( new_ret.isNull() ){
+        // simple ITE pulling
+        new_ret = extendedRewritePullIte( ret );
+      }
+      // TODO : ( ~contains( x, y ) --> false ) => ( ~x=y --> false )
+    }else if( ret.getKind()==kind::ITE ){
+      Assert( ret[1]!=ret[2] );
+      if( ret[0].getKind()==NOT ){
+        ret = NodeManager::currentNM()->mkNode( kind::ITE, ret[0][0], ret[2], ret[1] );
+      }
+      if( ret[0].getKind()==kind::EQUAL ){
+        // simple invariant ITE
+        for( unsigned i=0; i<2; i++ ){
+          if( ret[1]==ret[0][i] && ret[2]==ret[0][1-i] ){
+            Trace("sygus-ext-rewrite") << "sygus-extr : " << ret << " rewrites to " << ret[2] << " due to simple invariant ITE." << std::endl;
+            new_ret = ret[2];
+            break;
+          }
+        }
+        // notice this is strictly more general that the above
+        if( new_ret.isNull() ){
+          // simple substitution
+          for( unsigned i=0; i<2; i++ ){
+            if( ret[0][i].isVar() && ( ( ret[0][1-i].isVar() && ret[0][i]<ret[0][1-i] ) || ret[0][1-i].isConst() ) ){
+              TNode r1 = ret[0][i];
+              TNode r2 = ret[0][1-i];
+              Node retn = ret[1].substitute( r1, r2 );
+              if( retn!=ret[1] ){
+                new_ret = NodeManager::currentNM()->mkNode( kind::ITE, ret[0], retn, ret[2] );
+                Trace("sygus-ext-rewrite") << "sygus-extr : " << ret << " rewrites to " << new_ret << " due to simple ITE substitution." << std::endl;
+              }
+            }
+          }
+        }
+      }
+    }else if( ret.getKind()==DIVISION || ret.getKind()==INTS_DIVISION || ret.getKind()==INTS_MODULUS ){
+      // rewrite as though total
+      std::vector< Node > children;
+      bool all_const = true;
+      for( unsigned i=0; i<ret.getNumChildren(); i++ ){
+        if( ret[i].isConst() ){
+          children.push_back( ret[i] );
+        }else{
+          all_const = false;
+          break;
+        }
+      }
+      if( all_const ){
+        Kind new_k = ( ret.getKind()==DIVISION ? DIVISION_TOTAL : ( ret.getKind()==INTS_DIVISION ? INTS_DIVISION_TOTAL : INTS_MODULUS_TOTAL ) ); 
+        new_ret = NodeManager::currentNM()->mkNode( new_k, children );
+        Trace("sygus-ext-rewrite") << "sygus-extr : " << ret << " rewrites to " << new_ret << " due to total interpretation." << std::endl;
+      }
+    }
+    // more expensive rewrites 
+    if( new_ret.isNull() ){
+      Trace("sygus-ext-rewrite-debug2")  << "Do expensive rewrites on " << ret << std::endl;
+      bool polarity = ret.getKind()!=NOT;
+      Node ret_atom = ret.getKind()==NOT ? ret[0] : ret;
+      if( ( ret_atom.getKind()==EQUAL && ret_atom[0].getType().isReal() ) || ret_atom.getKind()==GEQ ){
+        Trace("sygus-ext-rewrite-debug2")  << "Compute monomial sum " << ret_atom << std::endl;
+        //compute monomial sum
+        std::map< Node, Node > msum;
+        if( QuantArith::getMonomialSumLit( ret_atom, msum ) ){
+          for( std::map< Node, Node >::iterator itm = msum.begin(); itm != msum.end(); ++itm ){
+            Node v = itm->first;
+            Trace("sygus-ext-rewrite-debug2") << itm->first << " * " << itm->second << std::endl;
+            if( v.getKind()==ITE ){
+              Node veq;
+              int res = QuantArith::isolate( v, msum, veq, ret_atom.getKind() );
+              if( res!=0 ){
+                Trace("sygus-ext-rewrite-debug") << "  have ITE relation, solved form : " << veq << std::endl;
+                // try pulling ITE
+                new_ret = extendedRewritePullIte( veq );
+                if( !new_ret.isNull() ){
+                  if( !polarity ){
+                    new_ret = new_ret.negate();
+                  }
+                  break;
+                }
+              }else{
+                Trace("sygus-ext-rewrite-debug") << "  failed to isolate " << v << " in " << ret << std::endl;
+              }
+            }
+          }
+        }else{
+          Trace("sygus-ext-rewrite-debug") << "  failed to get monomial sum of " << ret << std::endl;
+        }
+      }else if( ret_atom.getKind()==ITE ){
+        // TODO : conditional rewriting
+      }else if( ret.getKind()==kind::AND || ret.getKind()==kind::OR ){
+        // TODO condition merging
+      }
+    }
+    
+    if( !new_ret.isNull() ){
+      ret = Rewriter::rewrite( new_ret );
+    }
+    d_ext_rewrite_cache[n] = ret;
+    return ret;
+  }else{
+    return it->second;
+  }
+}
+
+
+
+
+
+
+TypeNode TermDbSygus::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 TermDbSygus::mkSygusConstantsForType( TypeNode type, std::vector<CVC4::Node>& ops ) {
+  if( type.isInteger() ){
+    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 TermDbSygus::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 TermDbSygus::mkSygusDefaultGrammar( TypeNode range, Node bvl, const std::string& fun, std::map< TypeNode, std::vector< Node > >& extra_cons, 
+                                         std::vector< CVC4::Datatype >& datatypes, std::set<Type>& unres ) {
+  // collect the variables
+  std::vector<Node> sygus_vars;
+  if( !bvl.isNull() ){
+    for( unsigned i=0; i<bvl.getNumChildren(); i++ ){
+      sygus_vars.push_back( bvl[i] );
+    }
+  }
+  //if( !range.isBoolean() && !range.isInteger() && !range.isBitVector() && !range.isDatatype() ){
+  //  parseError("No default grammar for type.");
+  //}
+  std::vector< std::vector< Expr > > ops;
+  int startIndex = -1;
+  Trace("sygus-grammar-def") << "Construct default grammar for " << fun << " " << range << std::endl;
+  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].isInteger() ){
+      for( unsigned j=0; j<2; j++ ){
+        CVC4::Kind k = j==0 ? kind::PLUS : kind::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);
+      }
+    }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.back() << 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] );
+    }
+    //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].isInteger() ){
+      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 TermDbSygus::mkSygusDefaultType( TypeNode range, Node bvl, const std::string& fun, 
+                                          std::map< TypeNode, std::vector< Node > >& extra_cons ) {
+  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, 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] );
+}
+
+}/* 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
new file mode 100644 (file)
index 0000000..70f27db
--- /dev/null
@@ -0,0 +1,317 @@
+/*********************                                                        */
+/*! \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 "theory/quantifiers/term_database.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class SygusInvarianceTest {
+protected:
+  // check whether nvn[ x ] should be excluded
+  virtual bool invariant( TermDbSygus * tds, Node nvn, Node x ) = 0;
+public:
+  bool is_invariant( TermDbSygus * tds, Node nvn, Node x ){
+    if( invariant( tds, nvn, x ) ){
+      d_update_nvn = nvn;
+      return true;
+    }else{
+      return false;
+    }
+  }
+  // result of the node after invariant replacements
+  Node d_update_nvn;
+};
+
+class EvalSygusInvarianceTest : public SygusInvarianceTest {
+public:
+  Node d_conj;
+  TNode d_var;
+  std::map< Node, Node > d_visited;
+  Node d_result;
+protected:
+  bool invariant( quantifiers::TermDbSygus * tds, Node nvn, Node x );
+};
+
+class TermDbSygus {
+private:
+  /** reference to the quantifiers engine */
+  QuantifiersEngine* d_quantEngine;
+  std::map< TypeNode, std::vector< Node > > d_fv[2];
+  std::map< Node, TypeNode > d_fv_stype;
+  std::map< Node, int > d_fv_num;
+  bool hasFreeVar( Node n, std::map< Node, bool >& visited );
+public:
+  Node d_true;
+  Node d_false;
+public:
+  TNode getFreeVar( TypeNode tn, int i, bool useSygusType = false );
+  TNode getFreeVarInc( TypeNode tn, std::map< TypeNode, int >& var_count, bool useSygusType = false );
+  bool isFreeVar( Node n ) { return d_fv_stype.find( n )!=d_fv_stype.end(); }
+  int getVarNum( Node n ) { return d_fv_num[n]; }
+  bool hasFreeVar( Node n );
+private:
+  std::map< TypeNode, std::map< int, Node > > d_generic_base;
+  std::map< TypeNode, std::vector< Node > > d_generic_templ;
+  bool getMatch( Node p, Node n, std::map< int, Node >& s );
+  bool getMatch2( Node p, Node n, std::map< int, Node >& s, std::vector< int >& new_s );
+public:
+  bool getMatch( Node n, TypeNode st, int& index_found, std::vector< Node >& args, int index_exc = -1, int index_start = 0 );
+private:
+  void computeMinTypeDepthInternal( TypeNode root_tn, TypeNode tn, unsigned type_depth );
+  bool involvesDivByZero( Node n, std::map< Node, bool >& visited );
+private:
+  // stores root
+  std::map< Node, Node > d_measured_term;
+  std::map< Node, Node > d_measured_term_active_guard;
+  //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::vector< int > > d_id_funcs;
+  std::map< TypeNode, std::vector< Node > > d_const_list; //sorted list of constants for type
+  std::map< TypeNode, unsigned > d_const_list_pos;
+  std::map< TypeNode, std::map< Node, Node > > d_semantic_skolem;
+  //information for builtin types
+  std::map< TypeNode, std::map< int, Node > > d_type_value;
+  std::map< TypeNode, Node > d_type_max_value;
+  std::map< TypeNode, std::map< Node, std::map< int, Node > > > d_type_value_offset;
+  std::map< TypeNode, std::map< Node, std::map< int, int > > > d_type_value_offset_status;
+  //normalized map
+  std::map< TypeNode, std::map< Node, Node > > d_normalized;
+  std::map< TypeNode, std::map< Node, Node > > d_sygus_to_builtin;
+  std::map< TypeNode, std::map< Node, Node > > d_builtin_const_to_sygus;
+  // 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;
+public:
+  TermDbSygus( context::Context* c, QuantifiersEngine* qe );
+  ~TermDbSygus(){}
+  bool reset( Theory::Effort e );
+  std::string identify() const { return "TermDbSygus"; }
+public:
+  /** register the sygus type */
+  void registerSygusType( TypeNode tn );
+  /** register a term that we will do enumerative search on */
+  void registerMeasuredTerm( Node e, Node root, bool mkActiveGuard = false );
+  /** is measured term */
+  Node isMeasuredTerm( Node e );
+  /** get active guard */
+  Node getActiveGuardForMeasureTerm( Node e );
+  /** get measured terms */
+  void getMeasuredTerms( std::vector< Node >& mts );
+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 );
+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 );
+  unsigned getNumIdFuncs( TypeNode tn );
+  unsigned getIdFuncIndex( TypeNode tn, unsigned i );
+  /** get arg type */
+  TypeNode getArgType( const DatatypeConstructor& c, int i );
+  /** get first occurrence */
+  int getFirstArgOccurrence( const DatatypeConstructor& c, TypeNode tn );
+  /** is type match */
+  bool isTypeMatch( const DatatypeConstructor& c1, const DatatypeConstructor& c2 );
+  /** isAntisymmetric */
+  bool isAntisymmetric( Kind k, Kind& dk );
+  /** is idempotent arg */
+  bool isIdempotentArg( Node n, Kind ik, int arg );
+  /** is singular arg */
+  Node isSingularArg( Node n, Kind ik, int arg );
+  /** get offset arg */
+  bool hasOffsetArg( Kind ik, int arg, int& offset, Kind& ok );
+  /** get value */
+  Node getTypeValue( TypeNode tn, int val );
+  /** get value */
+  Node getTypeValueOffset( TypeNode tn, Node val, int offset, int& status );
+  /** get value */
+  Node getTypeMaxValue( TypeNode tn );
+  TypeNode getSygusTypeForVar( Node v );
+  Node getGenericBase( TypeNode tn, const Datatype& dt, int c );
+  Node mkGeneric( const Datatype& dt, int c, std::map< TypeNode, int >& var_count, std::map< int, Node >& pre );
+  Node sygusToBuiltin( Node n, TypeNode tn );
+  Node sygusToBuiltin( Node n ) { return sygusToBuiltin( n, n.getType() ); }
+  Node sygusSubstituted( TypeNode tn, Node n, std::vector< Node >& args );
+  Node builtinToSygusConst( Node c, TypeNode tn, int rcons_depth = 0 );
+  Node getSygusNormalized( Node n, std::map< TypeNode, int >& var_count, std::map< Node, Node >& subs );
+  Node getNormalized( TypeNode t, Node prog, bool do_pre_norm = false, bool do_post_norm = true );
+  unsigned getSygusTermSize( Node n );
+  // returns size
+  unsigned getSygusConstructors( Node n, std::vector< Node >& cons );
+  /** 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 );
+  bool doCompare( Node a, Node b, Kind k );
+  // 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 );
+  /** print sygus term */
+  static void printSygusTerm( std::ostream& out, Node n, std::vector< Node >& lvs );
+
+  /** 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
+private:
+  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;
+
+  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 );
+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 );
+  // returns straightforward exp => n = vn
+  void getExplanationForConstantEquality( Node n, Node vn, std::vector< Node >& exp );
+  void getExplanationForConstantEquality( Node n, Node vn, std::vector< Node >& exp, std::map< unsigned, bool >& cexc );
+  Node getExplanationForConstantEquality( Node n, Node vn );
+  Node getExplanationForConstantEquality( Node n, Node vn, std::map< unsigned, bool >& cexc );
+  // we have n = vn => eval( n ) = bvr, returns exp => eval( n ) = bvr
+  //   ensures the explanation still allows for vnr
+  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 );
+  // builtin evaluation, returns rewrite( bn [ args / vars(tn) ] )
+  Node evaluateBuiltin( TypeNode tn, Node bn, std::vector< Node >& args );
+  Node evaluateBuiltin( TypeNode tn, Node bn, Node ar, unsigned i );
+  // evaluate with unfolding
+  Node evaluateWithUnfolding( Node n, std::map< Node, Node >& visited );
+  Node evaluateWithUnfolding( Node n );
+//for calculating redundant operators
+private:
+  //whether each constructor is redundant
+  // 0 : not redundant, 1 : redundant, 2 : partially redundant
+  std::map< TypeNode, std::vector< int > > d_sygus_red_status;
+  // type to (rewritten) to original
+  std::map< TypeNode, std::map< Node, Node > > d_gen_terms;
+  std::map< TypeNode, std::map< Node, bool > > d_gen_redundant;
+  //compute generic redundant
+  bool computeGenericRedundant( TypeNode tn, Node g );
+public:
+  bool isGenericRedundant( TypeNode tn, unsigned i );
+  
+//sygus pbe
+private:
+  std::map< Node, std::vector< std::vector< Node > > > d_pbe_exs;
+  std::map< Node, std::vector< Node > > d_pbe_exos;
+  std::map< Node, unsigned > d_pbe_term_id;
+private:
+  class PbeTrie {
+  private:
+    Node addPbeExampleEval( TypeNode etn, Node e, Node b, std::vector< Node >& ex, quantifiers::TermDbSygus * tds, unsigned index, unsigned ntotal );
+  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, TermDbSygus * tds, unsigned index, unsigned ntotal );
+  };
+  std::map< Node, std::map< TypeNode, PbeTrie > > d_pbe_trie;
+public:
+  /** register examples for an enumerative search term. 
+      This should be a comprehensive set of examples. */
+  void registerPbeExamples( Node e, std::vector< std::vector< Node > >& exs, 
+                            std::vector< Node >& exos, std::vector< Node >& exts );
+  /** get examples */
+  bool hasPbeExamples( Node e );
+  unsigned getNumPbeExamples( Node e );
+  /** return value is the required value for the example */
+  void getPbeExample( Node e, unsigned i, std::vector< Node >& ex );
+  Node getPbeExampleOut( Node e, unsigned i );
+  int getPbeExampleId( Node n );
+  /** add the search val, returns an equivalent value (possibly the same) */
+  Node addPbeSearchVal( TypeNode tn, Node e, Node bvr );
+
+// extended rewriting
+private:
+  std::map< Node, Node > d_ext_rewrite_cache;
+  Node extendedRewritePullIte( Node n );
+public:
+  Node extendedRewrite( Node n );
+  
+// for default grammar construction
+private:
+  TypeNode mkUnresolvedType(const std::string& name, std::set<Type>& unres);
+  void mkSygusConstantsForType( TypeNode type, std::vector<CVC4::Node>& ops );
+  void collectSygusGrammarTypesFor( TypeNode range, std::vector< TypeNode >& types, std::map< TypeNode, std::vector< DatatypeConstructorArg > >& sels );
+  void mkSygusDefaultGrammar( TypeNode range, Node bvl, const std::string& fun, std::map< TypeNode, std::vector< Node > >& extra_cons, std::vector< CVC4::Datatype >& datatypes, std::set<Type>& unres );
+public:
+  TypeNode mkSygusDefaultType( TypeNode range, Node bvl, const std::string& fun, std::map< TypeNode, std::vector< Node > >& extra_cons );
+  TypeNode mkSygusDefaultType( TypeNode range, Node bvl, const std::string& fun ){
+    std::map< TypeNode, std::vector< Node > > extra_cons;
+    return mkSygusDefaultType( range, bvl, fun, extra_cons );
+  }
+};
+
+}/* CVC4::theory::quantifiers namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_H */